Compare commits
214 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 255d5add29 | |||
| 032f1aa1a3 | |||
| ba71f2ae4a | |||
| 84a375c1be | |||
| 9a58332bf6 | |||
| 62efc4cb02 | |||
| d6f9352940 | |||
| 643ab1a1be | |||
| f499fcaeff | |||
| 80886c11ce | |||
| 39f8d0ee7e | |||
| bbe4634535 | |||
| e7b8f7681c | |||
| 64168d103d | |||
| 600a321f49 | |||
| e753f4df32 | |||
| cbe7353122 | |||
| de5682a960 | |||
| b451399323 | |||
| e547aa32ca | |||
| 3fe9d762da | |||
| 20b53596e2 | |||
| c04a9fd37b | |||
| fe59a3c377 | |||
| fc9c6bc7e4 | |||
| e3fa7a5eed | |||
| de135a8528 | |||
| 5ac053ddd9 | |||
| f817f06dbe | |||
| 5d5acf253b | |||
| bb4faf8ec9 | |||
| 7f9edcfaef | |||
| 1c1e6d1e00 | |||
| 550b600424 | |||
| 9673a6c0f6 | |||
| 20b56cfcbd | |||
| 947af8727d | |||
| 23b950d5b8 | |||
| 2eaa9b445c | |||
| c166bac323 | |||
| 074a429c6a | |||
| 3fab85e134 | |||
| 5aec954061 | |||
| 094a5f615f | |||
| 65ed0e8a22 | |||
| 936601cbad | |||
| f9cf1b39db | |||
| 3fb3c1c039 | |||
| e8bc6ca725 | |||
| df531d3724 | |||
| 2728012f33 | |||
| 853df2eb42 | |||
| 0cb2165ddf | |||
| ca7e9034ed | |||
| 1322c920f5 | |||
| e5c00e3882 | |||
| c030629bab | |||
| 165d079251 | |||
| 7cc9200adf | |||
| 01a9d8c075 | |||
| 0a0a08d220 | |||
| 410768e6f3 | |||
| bbbe024bb3 | |||
| 93112d5192 | |||
| 112a562b2d | |||
| 85ca4fd100 | |||
| 136b1cc924 | |||
| e4b7d528f5 | |||
| 2903ebfbac | |||
| 931ca1b2c0 | |||
| 85e724d88a | |||
| e41f83a2dd | |||
| 69b52cfe88 | |||
| 7591821e57 | |||
| 0ce0dcf2e9 | |||
| 73811c3a6b | |||
| 2a887b7794 | |||
| ad9f482e76 | |||
| 6eaef94459 | |||
| 4f5c616240 | |||
| f5947dded9 | |||
| 77e0acc16b | |||
| e48646c5ff | |||
| 5e48fe51ea | |||
| 6b30dbef65 | |||
| d6508a2be4 | |||
| dfcadfb3bd | |||
| 7888b92129 | |||
| 5b48dffa77 | |||
| 5bf4650da1 | |||
| 8e9c270b77 | |||
| 00080331df | |||
| 27e40e2069 | |||
| 3a93877de3 | |||
| 7f70784cd3 | |||
| ed6e3df66e | |||
| eb5becbbd4 | |||
| 9599316fbc | |||
| cc1c951ef8 | |||
| d23c4cba18 | |||
| 3d30b0b96f | |||
| ad1e5d555a | |||
| 14ea5f1c72 | |||
| 709d44e4d9 | |||
| 8df00e9c41 | |||
| 8dbb0ec058 | |||
| b8310eedae | |||
| c04754afe1 | |||
| 3155aa6815 | |||
| ea27b1a081 | |||
| 4d078f9597 | |||
| 67459cbbbd | |||
| 932de4e969 | |||
| 41e28291ad | |||
| 6ae6324368 | |||
| 4858716f05 | |||
| 24fb4cfe4a | |||
| 186138d0c0 | |||
| 6690564017 | |||
| 89a0a900cc | |||
| 391a24db3f | |||
| 4b546af642 | |||
| ee8aabbf97 | |||
| 45994e2b94 | |||
| 13bdc69da8 | |||
| c0184fde8e | |||
| cbd297e59d | |||
| c6cf7c950e | |||
| fe5d80e017 | |||
| e985a8f15b | |||
| 615767f758 | |||
| 65a24b2295 | |||
| 94c2afe67a | |||
| 9bbca37ecd | |||
| 58241a0f5c | |||
| a960a01ca1 | |||
| 67d8ee773c | |||
| c6f2675278 | |||
| 2380be230e | |||
| 833276b7b3 | |||
| 9b32835720 | |||
| 61634a9cc3 | |||
| 408a35db8d | |||
| 9695a85131 | |||
| d027cf4f2a | |||
| c2f8bfc5b4 | |||
| 486425a62c | |||
| f9681d4c66 | |||
| cd0671dc59 | |||
| 7ebca16948 | |||
| e8cbdde518 | |||
| 7ca6f05151 | |||
| f4f17e90e5 | |||
| 3ea48efb1d | |||
| ffc3533688 | |||
| bd309855a2 | |||
| 1473c7e9b7 | |||
| 15cc7b6d18 | |||
| 1c89c5f779 | |||
| ca7f1cc8ca | |||
| 8fd1de84e4 | |||
| 95d9168b6b | |||
| c1db827132 | |||
| d10b78ab46 | |||
| 2d70523f43 | |||
| 42fb7ad3df | |||
| e90d0950d4 | |||
| 888d4190d1 | |||
| 57696b2538 | |||
| 1440537f6b | |||
| a16ff88c8d | |||
| 041de12ea7 | |||
| 5e36f66c4e | |||
| a6a5a6104d | |||
| 6f7b225ce8 | |||
| 81a85883d2 | |||
| 3f06d2fea4 | |||
| 26b390268a | |||
| 486d55f349 | |||
| 5948090d63 | |||
| 32340191de | |||
| 0b09875bb3 | |||
| 078a36d304 | |||
| 3ef4ec522b | |||
| cd6fa03990 | |||
| bba9fb68e6 | |||
| dcb7038833 | |||
| f8a058259d | |||
| 1696d5daeb | |||
| ac69af012a | |||
| 692546a232 | |||
| b0478b627f | |||
| 2cdca4b990 | |||
| 4c0b2adef4 | |||
| 191dd078b8 | |||
| 2de7807bec | |||
| 9d4f1dd370 | |||
| 6f769150b1 | |||
| 155dc0b621 | |||
| 07acea53e3 | |||
| 1fcb3a2b1b | |||
| 16eabc8deb | |||
| e0efd8d407 | |||
| 969f0b96fd | |||
| 8a9d88c9ac | |||
| 3b55728c75 | |||
| 240bffa7ed | |||
| c313236eec | |||
| 21f7928b9c | |||
| 1304c11381 | |||
| 79932e15ab | |||
| 25ee166e41 | |||
| 299510e663 | |||
| d3d76cae16 |
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"homepage": "https://www.curseforge.com/minecraft/mc-mods/electroblobs-wizardry",
|
||||||
|
"promos": {
|
||||||
|
"1.12.2-latest": "4.3.18",
|
||||||
|
"1.12.2-recommended": "4.3.18"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Report a crash or something that isn't working as it should
|
|
||||||
title: "[Give a brief, relevant title here]"
|
|
||||||
labels: bug
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting.
|
|
||||||
|
|
||||||
Minecraft version: 1.12.2 [change as necessary]
|
|
||||||
Wizardry version: 4.3.2 [change as necessary]
|
|
||||||
Environment: Singleplayer/LAN game/Server [delete as necessary]
|
|
||||||
|
|
||||||
Issue details: [describe what you were doing when the issue occurred, what went wrong, what you expected to happen, etc.]
|
|
||||||
|
|
||||||
Other mods involved: [only list mods that are relevant to the problem]
|
|
||||||
|
|
||||||
Link to crash report (if applicable): [give a link to the crash report on gist, pastebin, etc.]
|
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
name: 🐛 Bug Report
|
||||||
|
description: Something is not working as expected
|
||||||
|
title: "[Bug] <write the title here>"
|
||||||
|
labels: [ "bug", "Needs Triage" ]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting. You may also find the [troubleshooting page](https://github.com/Electroblob77/Wizardry/wiki/Troubleshooting) helpful.
|
||||||
|
Please try the latest version of the mod and check if the issue persist before submitting a report.
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Is there an existing issue for this?
|
||||||
|
description: Please search to see if an issue already exists for the bug you encountered.
|
||||||
|
options:
|
||||||
|
- label: I have searched the existing issues
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: observed
|
||||||
|
attributes:
|
||||||
|
label: Observed behaviour
|
||||||
|
description: Describe what happened and when this happened
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: expected
|
||||||
|
attributes:
|
||||||
|
label: Expected behaviour
|
||||||
|
description: Describe what you expected to happen
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: reproduction
|
||||||
|
attributes:
|
||||||
|
label: Steps to reproduce
|
||||||
|
description: Step by step instructions on how to reproduce the observed behaviour
|
||||||
|
placeholder: |
|
||||||
|
1. Join a server
|
||||||
|
2. Cast the [spell]
|
||||||
|
3. ...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: crashlog
|
||||||
|
attributes:
|
||||||
|
label: Crashlog
|
||||||
|
description: If this was a crash, grab [minecraft instance]/logs/debug.log, upload it as a [gist](https://gist.github.com/) and paste the link here. Alternatively, give a link to the crash report on gist, pastebin if you already have one there.
|
||||||
|
placeholder: https://gist.github.com/<your-user>/abcdef124
|
||||||
|
- type: dropdown
|
||||||
|
id: environment
|
||||||
|
attributes:
|
||||||
|
label: Environment (Singleplayer/Server, etc.)
|
||||||
|
options:
|
||||||
|
- Singleplayer
|
||||||
|
- LAN game/Server
|
||||||
|
- Issue present on both sides
|
||||||
|
- Not sure
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: mod-version
|
||||||
|
attributes:
|
||||||
|
label: Mod version
|
||||||
|
placeholder: 1.0.0
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: minecraft-version
|
||||||
|
attributes:
|
||||||
|
label: Minecraft version
|
||||||
|
placeholder: 12.2.2
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: forge-version
|
||||||
|
attributes:
|
||||||
|
label: Forge version
|
||||||
|
placeholder: 1.12.2 - 14.23.5.2860
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: other-mods
|
||||||
|
attributes:
|
||||||
|
label: Other mods
|
||||||
|
description: List any other mods present when the bug was encountered, include the mod versions. You only have to fill this if no crash log was attached
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: 📖 Mod Wiki Page
|
||||||
|
url: https://github.com/Electroblob77/Wizardry/wiki
|
||||||
|
about: Most features are documented in the mod's wiki page --- Link --->
|
||||||
|
- name: 💬 Electroblob's Wizardry discord
|
||||||
|
url: https://discord.gg/hs8yJP2
|
||||||
|
about: Ask for help or get more info on Discord. --- Discord Server link --->
|
||||||
|
- name: 💡 Feature requests / suggestions
|
||||||
|
url: https://discord.gg/hs8yJP2
|
||||||
|
about: Please use the discord server to suggest stuff. --- Discord Server link --->
|
||||||
|
- name: ❓ Question
|
||||||
|
url: https://discord.gg/hs8yJP2
|
||||||
|
about: Ask a question about the mod or the code. --- Discord Server link --->
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature request
|
|
||||||
about: Make a suggestion for improving the mod
|
|
||||||
title: "[Give a brief, relevant title here]"
|
|
||||||
labels: enhancement
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting.
|
|
||||||
|
|
||||||
Minecraft versions: [if this suggestion only applies to some versions, list them here]
|
|
||||||
|
|
||||||
Suggestion details: [describe what you would like to see added to the mod and why]
|
|
||||||
|
|
||||||
Other mods involved: [if this suggestion involves integration with other mods, list them here]
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
---
|
|
||||||
name: Question
|
|
||||||
about: Ask a question about the mod or the code
|
|
||||||
title: "[Give a brief, relevant title here]"
|
|
||||||
labels: question
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/CONTRIBUTING.md) before posting.
|
|
||||||
|
|
||||||
Minecraft version: 1.12.2 [change as necessary]
|
|
||||||
Wizardry version: 4.3.2 [change as necessary]
|
|
||||||
|
|
||||||
Question details: [explain your question here]
|
|
||||||
|
|
||||||
Other mods involved: [if this question involves other mods, list them here]
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
name: Gradle Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "**" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v6
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Set up JDK 8
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
java-version: '8'
|
||||||
|
distribution: 'temurin'
|
||||||
|
|
||||||
|
- name: Load Cache
|
||||||
|
uses: actions/cache@v5
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
~/.gradle/caches
|
||||||
|
~/.gradle/wrapper
|
||||||
|
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-gradle-
|
||||||
|
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/actions/setup-gradle@v4
|
||||||
|
with:
|
||||||
|
cache-read-only: ${{ github.ref != 'refs/heads/1.12.2' }}
|
||||||
|
|
||||||
|
- name: Grant execute permission for gradlew
|
||||||
|
run: chmod +x gradlew
|
||||||
|
|
||||||
|
- name: Build with Gradle
|
||||||
|
run: ./gradlew build --max-workers=1 --no-daemon
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
if: success()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: build-artifacts
|
||||||
|
path: build/libs/*.jar
|
||||||
|
retention-days: 30
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
name: Potential Duplicates
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [opened, edited]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
run:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: bubkoo/potential-duplicates@v1
|
||||||
|
with:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
label: potential duplicate
|
||||||
|
exclude: |
|
||||||
|
adding
|
||||||
|
add
|
||||||
|
creating
|
||||||
|
create
|
||||||
|
icons
|
||||||
|
icon
|
||||||
|
logos
|
||||||
|
logo
|
||||||
|
missing
|
||||||
|
miss
|
||||||
|
needing
|
||||||
|
need
|
||||||
|
please
|
||||||
|
requesting
|
||||||
|
request
|
||||||
|
1.12.2
|
||||||
|
wizardry
|
||||||
|
state: all
|
||||||
|
threshold: 0.7
|
||||||
|
comment: |
|
||||||
|
This issue is potentially a duplicate of one of the following issues:
|
||||||
|
{{#issues}}
|
||||||
|
- [#{{ number }}] {{ title }} ({{ accuracy }}% match)
|
||||||
|
{{/issues}}
|
||||||
+8
-2
@@ -1,7 +1,7 @@
|
|||||||
# Credits
|
# Credits
|
||||||
|
|
||||||
Electroblob's Wizardry
|
Electroblob's Wizardry
|
||||||
Version 4.3.2
|
Version 4.3.7
|
||||||
For Minecraft 1.12.2
|
For Minecraft 1.12.2
|
||||||
|
|
||||||
Designed, coded and textured by Electroblob
|
Designed, coded and textured by Electroblob
|
||||||
@@ -12,6 +12,11 @@ Thanks also to the Minecraft modding community, which always has an answer to my
|
|||||||
|
|
||||||
In addition, I'd like to thank the following individuals for their contributions to the mod:
|
In addition, I'd like to thank the following individuals for their contributions to the mod:
|
||||||
|
|
||||||
|
#### Discord Moderators (and all-round awesome people)
|
||||||
|
|
||||||
|
- FavouriteDragon
|
||||||
|
- WinDanesz
|
||||||
|
|
||||||
#### Code
|
#### Code
|
||||||
|
|
||||||
- Corail31
|
- Corail31
|
||||||
@@ -27,13 +32,14 @@ In addition, I'd like to thank the following individuals for their contributions
|
|||||||
- rafasoares
|
- rafasoares
|
||||||
- xinyuan-liu
|
- xinyuan-liu
|
||||||
- SettingDust
|
- SettingDust
|
||||||
|
- Aralu115
|
||||||
|
|
||||||
#### Translations
|
#### Translations
|
||||||
|
|
||||||
- Spanish: MadWrist, Alsentar
|
- Spanish: MadWrist, Alsentar
|
||||||
- Mexican Spanish: MadWrist
|
- Mexican Spanish: MadWrist
|
||||||
- Russian: VilagVil, kellixon, bigenergy, MugGod2, DrHesperus
|
- Russian: VilagVil, kellixon, bigenergy, MugGod2, DrHesperus
|
||||||
- French: Hahdrim
|
- French: Hahdrim, Crowller
|
||||||
- Brazilian Portuguese: lorrampi
|
- Brazilian Portuguese: lorrampi
|
||||||
- Chinese (Simplified): ZHENGLOC, dragon-evol, Hokorizero, TUsama, Determancer
|
- Chinese (Simplified): ZHENGLOC, dragon-evol, Hokorizero, TUsama, Determancer
|
||||||
- Korean: shejery, rewi_wire, 방통, red1854th
|
- Korean: shejery, rewi_wire, 방통, red1854th
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting.
|
Please read the [guide for contributing](https://github.com/Electroblob77/Wizardry/blob/1.12.2/guide_for_contributing.md) before posting. You may also find the [troubleshooting page](https://github.com/Electroblob77/Wizardry/wiki/Troubleshooting) helpful.
|
||||||
|
|
||||||
Minecraft version: 1.12.2 [change as necessary]
|
Minecraft version: 1.12.2 [change as necessary]
|
||||||
Wizardry version: 4.3.2 [change as necessary]
|
Wizardry version: [change as necessary]
|
||||||
Environment: Singleplayer/LAN game/Server [delete 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.]
|
Issue details: [describe what you were doing when the issue occurred, what went wrong, what you expected to happen, etc.]
|
||||||
|
|||||||
+115
-50
@@ -1,64 +1,130 @@
|
|||||||
|
import groovy.json.JsonOutput
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
gradlePluginPortal()
|
||||||
maven { url = "http://files.minecraftforge.net/maven" }
|
maven {
|
||||||
|
name 'MinecraftForge'
|
||||||
|
url 'https://maven.minecraftforge.net/'
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
name 'Garden of Fancy'
|
||||||
|
url 'https://maven.gofancy.wtf/releases'
|
||||||
|
}
|
||||||
|
//fallback for fancygradle maven
|
||||||
|
//mavenLocal()
|
||||||
|
maven {
|
||||||
|
name 'Sponge'
|
||||||
|
url 'https://repo.spongepowered.org/repository/maven-public/'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
|
classpath 'net.minecraftforge.gradle:ForgeGradle:5.+'
|
||||||
|
classpath 'org.ajoberstar.grgit:grgit-gradle:3.1.1'
|
||||||
|
classpath group: 'wtf.gofancy.fancygradle', name: 'wtf.gofancy.fancygradle.gradle.plugin', version: '1.1.+'
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories.each {
|
||||||
|
if (it instanceof MavenArtifactRepository && it.url.toString() == "https://files.minecraftforge.net/maven") {
|
||||||
|
it.url = "https://maven.minecraftforge.net"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
apply plugin: 'net.minecraftforge.gradle.forge'
|
|
||||||
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
|
apply plugin: 'net.minecraftforge.gradle'
|
||||||
|
apply plugin: 'idea'
|
||||||
|
apply plugin: 'maven-publish'
|
||||||
|
apply plugin: org.ajoberstar.grgit.gradle.GrgitPlugin
|
||||||
|
apply plugin: 'wtf.gofancy.fancygradle'
|
||||||
|
|
||||||
|
|
||||||
version = "4.3.2" // There, it matches semver, happy now?
|
version = "4.3.18"
|
||||||
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
|
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||||
archivesBaseName = "ElectroblobsWizardry"
|
archivesBaseName = "ElectroblobsWizardry"
|
||||||
|
|
||||||
sourceCompatibility = targetCompatibility = "1.8" // Need this here so eclipse task generates correctly.
|
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
|
||||||
compileJava {
|
|
||||||
sourceCompatibility = targetCompatibility = "1.8"
|
|
||||||
|
minecraft {
|
||||||
|
// The mappings can be changed at any time, and must be in the following format.
|
||||||
|
// snapshot_YYYYMMDD Snapshot are built nightly.
|
||||||
|
// stable_# Stables are built at the discretion of the MCP team.
|
||||||
|
// Use non-default mappings at your own risk. they may not always work.
|
||||||
|
// Simply re-run your setup task after changing the mappings to update your workspace.
|
||||||
|
//mappings channel: 'snapshot', version: '20171003-1.12'
|
||||||
|
mappings channel: "stable", version: "39-1.12"
|
||||||
|
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
|
||||||
|
|
||||||
|
// accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
|
||||||
|
|
||||||
|
// Default run configurations.
|
||||||
|
// These can be tweaked, removed, or duplicated as needed.
|
||||||
|
|
||||||
|
def argsz = ['--username', 'WinDanesz', '--user', 'WinDanesz', '--uuid', '7faee354-8c60-4f5c-9862-fc0ce5f7f575']
|
||||||
|
runs {
|
||||||
|
client {
|
||||||
|
workingDirectory project.file('run')
|
||||||
|
|
||||||
|
// Recommended logging data for a userdev environment
|
||||||
|
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
|
||||||
|
|
||||||
|
// Recommended logging level for the console
|
||||||
|
property 'forge.logging.console.level', 'info'
|
||||||
|
args argsz
|
||||||
|
}
|
||||||
|
|
||||||
|
server {
|
||||||
|
|
||||||
|
// Recommended logging data for a userdev environment
|
||||||
|
property 'forge.logging.markers', 'SCAN,REGISTRIES,REGISTRYDUMP'
|
||||||
|
|
||||||
|
// Recommended logging level for the console
|
||||||
|
property 'forge.logging.console.level', 'info'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
maven {
|
maven {
|
||||||
// location of the maven that hosts JEI files
|
url = uri('https://www.cursemaven.com')
|
||||||
name = "Progwml6 maven"
|
content {
|
||||||
url = "http://dvs1.progwml6.com/files/maven"
|
includeGroup 'curse.maven'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
maven {
|
maven {
|
||||||
// location of a maven mirror for JEI files, as a fallback
|
name = 'Modrinth'
|
||||||
name = "ModMaven"
|
url = uri('https://api.modrinth.com/maven')
|
||||||
url = "modmaven.k-4u.nl"
|
content {
|
||||||
|
includeGroup 'maven.modrinth'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
maven {
|
maven {
|
||||||
name = "Curseforge Maven"
|
name = 'Sponge'
|
||||||
url = "https://minecraft.curseforge.com/api/maven/"
|
url = uri('https://repo.spongepowered.org/maven')
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url = uri('https://maven.blamejared.com')
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url = uri('https://m2.dv8tion.net/releases')
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url = uri('https://jitpack.io')
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
minecraft {
|
|
||||||
version = "1.12.2-14.23.5.2847"
|
|
||||||
runDir = "run"
|
|
||||||
|
|
||||||
// the mappings can be changed at any time, and must be in the following format.
|
|
||||||
// snapshot_YYYYMMDD snapshot are built nightly.
|
|
||||||
// stable_# stables are built at the discretion of the MCP team.
|
|
||||||
// Use non-default mappings at your own risk. they may not always work.
|
|
||||||
// simply re-run your setup task after changing the mappings to update your workspace.
|
|
||||||
mappings = "stable_39"
|
|
||||||
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
//// MC version ////
|
||||||
// Compile against the JEI API but do not include it at runtime
|
// Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed
|
||||||
deobfProvided "mezz.jei:jei_${mc_version}:${jei_version}:api"
|
// that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied.
|
||||||
// At runtime, use the full JEI jar
|
// The userdev artifact is a special name and will get all sorts of transformations applied to it.
|
||||||
runtime "mezz.jei:jei_${mc_version}:${jei_version}"
|
minecraft "net.minecraftforge:forge:${project.mc_version}-${project.forge_version}"
|
||||||
|
//// MC version ////
|
||||||
deobfCompile "baubles:Baubles:${mc_version_short}:${baubles_version}"
|
implementation fg.deobf("curse.maven:baubles-${baubles_projectid}:${baubles_fileid}")
|
||||||
deobfCompile "antique-atlas:antiqueatlas:${mc_version}:${antique_atlas_version}"
|
implementation fg.deobf("mezz.jei:jei_${mc_version}:${jei_version}")
|
||||||
|
implementation fg.deobf("curse.maven:antique-atlas-${antiqueatlas_projectid}:${antiqueatlas_fileid}")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,20 +134,19 @@ task deobfJar(type: Jar) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
// this will ensure that this task is redone when the versions change.
|
// replace tokens in mcmod.info, and pack.mcmeta
|
||||||
inputs.property "version", project.version
|
|
||||||
inputs.property "mcversion", project.minecraft.version
|
|
||||||
|
|
||||||
// replace stuff in mcmod.info, nothing else
|
|
||||||
from(sourceSets.main.resources.srcDirs) {
|
from(sourceSets.main.resources.srcDirs) {
|
||||||
|
include 'pack.mcmeta'
|
||||||
include 'mcmod.info'
|
include 'mcmod.info'
|
||||||
|
|
||||||
// replace version and mcversion
|
|
||||||
expand 'version':project.version, 'mcversion':project.minecraft.version
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy everything else except the mcmod.info
|
duplicatesStrategy = 'include'
|
||||||
from(sourceSets.main.resources.srcDirs) {
|
}
|
||||||
exclude 'mcmod.info'
|
|
||||||
|
fancyGradle {
|
||||||
|
patches {
|
||||||
|
resources
|
||||||
|
coremods
|
||||||
|
asm
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-1
@@ -1,8 +1,22 @@
|
|||||||
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
|
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
|
||||||
# This is required to provide enough memory for the Minecraft decompilation process.
|
# This is required to provide enough memory for the Minecraft decompilation process.
|
||||||
org.gradle.jvmargs=-Xmx3G
|
org.gradle.jvmargs=-Xmx3G
|
||||||
|
mod_id=ebwizardry
|
||||||
mc_version=1.12.2
|
mc_version=1.12.2
|
||||||
mc_version_short=1.12
|
mc_version_short=1.12
|
||||||
jei_version=4.15.0.291
|
jei_version=4.15.0.291
|
||||||
baubles_version=1.5.2
|
baubles_version=1.5.2
|
||||||
antique_atlas_version=4.6.3
|
antique_atlas_version=4.6.3
|
||||||
|
forge_version=14.23.5.2860
|
||||||
|
mappings_version=39
|
||||||
|
mappings_channel=stable
|
||||||
|
mappings_mc_version=1.12
|
||||||
|
baubles_projectid=227083
|
||||||
|
baubles_fileid=2518667
|
||||||
|
jei_projectid=238222
|
||||||
|
artemislib_projectid=313590
|
||||||
|
artemislib_version=1.0.6
|
||||||
|
artemislib_fileid=2741812
|
||||||
|
antiqueatlas_projectid=227795
|
||||||
|
antiqueatlas_fileid=2823030
|
||||||
|
org.gradle.daemon=false
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
+2
-3
@@ -1,6 +1,5 @@
|
|||||||
#Mon Sep 14 12:28:28 PDT 2015
|
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14-bin.zip
|
|
||||||
@@ -1,164 +1,232 @@
|
|||||||
#!/usr/bin/env bash
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
##
|
#
|
||||||
## Gradle start up script for UN*X
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
##
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
# Attempt to set APP_HOME
|
||||||
DEFAULT_JVM_OPTS=""
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||||
|
|
||||||
APP_NAME="Gradle"
|
APP_NAME="Gradle"
|
||||||
APP_BASE_NAME=`basename "$0"`
|
APP_BASE_NAME=${0##*/}
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD="maximum"
|
MAX_FD=maximum
|
||||||
|
|
||||||
warn ( ) {
|
warn () {
|
||||||
echo "$*"
|
echo "$*"
|
||||||
}
|
} >&2
|
||||||
|
|
||||||
die ( ) {
|
die () {
|
||||||
echo
|
echo
|
||||||
echo "$*"
|
echo "$*"
|
||||||
echo
|
echo
|
||||||
exit 1
|
exit 1
|
||||||
}
|
} >&2
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
# OS specific support (must be 'true' or 'false').
|
||||||
cygwin=false
|
cygwin=false
|
||||||
msys=false
|
msys=false
|
||||||
darwin=false
|
darwin=false
|
||||||
case "`uname`" in
|
nonstop=false
|
||||||
CYGWIN* )
|
case "$( uname )" in #(
|
||||||
cygwin=true
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
;;
|
Darwin* ) darwin=true ;; #(
|
||||||
Darwin* )
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
darwin=true
|
NONSTOP* ) nonstop=true ;;
|
||||||
;;
|
|
||||||
MINGW* )
|
|
||||||
msys=true
|
|
||||||
;;
|
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
|
||||||
if $cygwin ; then
|
|
||||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
|
||||||
# Resolve links: $0 may be a link
|
|
||||||
PRG="$0"
|
|
||||||
# Need this for relative symlinks.
|
|
||||||
while [ -h "$PRG" ] ; do
|
|
||||||
ls=`ls -ld "$PRG"`
|
|
||||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
|
||||||
if expr "$link" : '/.*' > /dev/null; then
|
|
||||||
PRG="$link"
|
|
||||||
else
|
|
||||||
PRG=`dirname "$PRG"`"/$link"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
SAVED="`pwd`"
|
|
||||||
cd "`dirname \"$PRG\"`/" >&-
|
|
||||||
APP_HOME="`pwd -P`"
|
|
||||||
cd "$SAVED" >&-
|
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
else
|
else
|
||||||
JAVACMD="$JAVA_HOME/bin/java"
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
fi
|
fi
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
locations of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD="java"
|
JAVACMD=java
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
locations of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
MAX_FD_LIMIT=`ulimit -H -n`
|
case $MAX_FD in #(
|
||||||
if [ $? -eq 0 ] ; then
|
max*)
|
||||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
MAX_FD="$MAX_FD_LIMIT"
|
warn "Could not query maximum file descriptor limit"
|
||||||
fi
|
esac
|
||||||
ulimit -n $MAX_FD
|
case $MAX_FD in #(
|
||||||
if [ $? -ne 0 ] ; then
|
'' | soft) :;; #(
|
||||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
*)
|
||||||
fi
|
ulimit -n "$MAX_FD" ||
|
||||||
else
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Darwin, add options to specify how the application appears in the dock
|
|
||||||
if $darwin; then
|
|
||||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
|
||||||
fi
|
|
||||||
|
|
||||||
# For Cygwin, switch paths to Windows format before running java
|
|
||||||
if $cygwin ; then
|
|
||||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
|
||||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
|
||||||
|
|
||||||
# We build the pattern for arguments to be converted via cygpath
|
|
||||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
|
||||||
SEP=""
|
|
||||||
for dir in $ROOTDIRSRAW ; do
|
|
||||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
|
||||||
SEP="|"
|
|
||||||
done
|
|
||||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
|
||||||
# Add a user-defined pattern to the cygpath arguments
|
|
||||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
|
||||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
|
||||||
fi
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
i=0
|
|
||||||
for arg in "$@" ; do
|
|
||||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
|
||||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
|
||||||
|
|
||||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
|
||||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
|
||||||
else
|
|
||||||
eval `echo args$i`="\"$arg\""
|
|
||||||
fi
|
|
||||||
i=$((i+1))
|
|
||||||
done
|
|
||||||
case $i in
|
|
||||||
(0) set -- ;;
|
|
||||||
(1) set -- "$args0" ;;
|
|
||||||
(2) set -- "$args0" "$args1" ;;
|
|
||||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
|
||||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
|
||||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
|
||||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
|
||||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
|
||||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
|
||||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
function splitJvmOpts() {
|
# * args from the command line
|
||||||
JVM_OPTS=("$@")
|
# * the main class name
|
||||||
}
|
# * -classpath
|
||||||
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
|
# * -D...appname settings
|
||||||
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command;
|
||||||
|
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||||
|
# shell script including quotes and variable substitutions, so put them in
|
||||||
|
# double quotes to make sure that they get re-expanded; and
|
||||||
|
# * put everything else in single quotes, so that it's not re-expanded.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
Vendored
+29
-30
@@ -1,3 +1,19 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%" == "" @echo off
|
@if "%DEBUG%" == "" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@@ -8,26 +24,29 @@
|
|||||||
@rem Set local scope for the variables with windows NT shell
|
@rem Set local scope for the variables with windows NT shell
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
set DEFAULT_JVM_OPTS=
|
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%" == "" set DIRNAME=.
|
if "%DIRNAME%" == "" set DIRNAME=.
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
@rem Find java.exe
|
@rem Find java.exe
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if "%ERRORLEVEL%" == "0" goto init
|
if "%ERRORLEVEL%" == "0" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
echo.
|
echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo locations of your Java installation.
|
echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@@ -35,44 +54,24 @@ goto fail
|
|||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto init
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||||
echo.
|
echo.
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the
|
||||||
echo locations of your Java installation.
|
echo location of your Java installation.
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:init
|
|
||||||
@rem Get command-line arguments, handling Windowz variants
|
|
||||||
|
|
||||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
|
||||||
if "%@eval[2+2]" == "4" goto 4NT_args
|
|
||||||
|
|
||||||
:win9xME_args
|
|
||||||
@rem Slurp the command line arguments.
|
|
||||||
set CMD_LINE_ARGS=
|
|
||||||
set _SKIP=2
|
|
||||||
|
|
||||||
:win9xME_args_slurp
|
|
||||||
if "x%~1" == "x" goto execute
|
|
||||||
|
|
||||||
set CMD_LINE_ARGS=%*
|
|
||||||
goto execute
|
|
||||||
|
|
||||||
:4NT_args
|
|
||||||
@rem Get arguments from the 4NT Shell from JP Software
|
|
||||||
set CMD_LINE_ARGS=%$
|
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
@@ -87,4 +86,4 @@ exit /b 1
|
|||||||
:mainEnd
|
:mainEnd
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
:omega
|
:omega
|
||||||
@@ -10,6 +10,7 @@ import net.minecraft.block.state.IBlockState;
|
|||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.EntityLivingBase;
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.item.ItemArmor.ArmorMaterial;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
import net.minecraft.util.SoundCategory;
|
import net.minecraft.util.SoundCategory;
|
||||||
@@ -42,13 +43,17 @@ public class CommonProxy {
|
|||||||
|
|
||||||
public void registerRenderers(){}
|
public void registerRenderers(){}
|
||||||
|
|
||||||
|
public void registerItemColorHandlers(){}
|
||||||
|
|
||||||
|
public void registerModelProperties(){}
|
||||||
|
|
||||||
public void initialiseLayers(){}
|
public void initialiseLayers(){}
|
||||||
|
|
||||||
public void initialiseAnimations(){}
|
public void initialiseAnimations(){}
|
||||||
|
|
||||||
public void registerKeyBindings(){}
|
public void registerKeyBindings(){}
|
||||||
|
|
||||||
public net.minecraft.client.model.ModelBiped getWizardArmourModel(){
|
public net.minecraft.client.model.ModelBiped getWizardArmourModel(ArmorMaterial material){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,6 +179,8 @@ public class CommonProxy {
|
|||||||
|
|
||||||
public void handleConquerShrinePacket(PacketConquerShrine.Message message){}
|
public void handleConquerShrinePacket(PacketConquerShrine.Message message){}
|
||||||
|
|
||||||
|
public void handleBombExplosionPacket(PacketBombExplosion.Message message){}
|
||||||
|
|
||||||
// SECTION Misc
|
// SECTION Misc
|
||||||
// ===============================================================================================================
|
// ===============================================================================================================
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import net.minecraft.entity.EntityList;
|
|||||||
import net.minecraft.entity.player.EntityPlayerMP;
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.nbt.JsonToNBT;
|
||||||
|
import net.minecraft.nbt.NBTException;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
import net.minecraftforge.common.config.ConfigCategory;
|
import net.minecraftforge.common.config.ConfigCategory;
|
||||||
import net.minecraftforge.common.config.Configuration;
|
import net.minecraftforge.common.config.Configuration;
|
||||||
@@ -93,6 +96,8 @@ public final class Settings {
|
|||||||
/** The wizardry config file. */
|
/** The wizardry config file. */
|
||||||
private Configuration config;
|
private Configuration config;
|
||||||
|
|
||||||
|
private List<String> redundantKeys = new ArrayList<>();
|
||||||
|
|
||||||
// Server-only settings. These only affect server-side code and hence are not synced. Changing these locally only
|
// Server-only settings. These only affect server-side code and hence are not synced. Changing these locally only
|
||||||
// has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world.
|
// has an effect if the local game is the host, i.e. a dedicated server, a LAN host or a singleplayer world.
|
||||||
|
|
||||||
@@ -136,6 +141,12 @@ public final class Settings {
|
|||||||
new ResourceLocation(Wizardry.MODID, "shrine_5"),
|
new ResourceLocation(Wizardry.MODID, "shrine_5"),
|
||||||
new ResourceLocation(Wizardry.MODID, "shrine_6"),
|
new ResourceLocation(Wizardry.MODID, "shrine_6"),
|
||||||
new ResourceLocation(Wizardry.MODID, "shrine_7")};
|
new ResourceLocation(Wizardry.MODID, "shrine_7")};
|
||||||
|
/** <b>[Server-only]</b> Whether conquered shrines should regenerate after a period of time. */
|
||||||
|
public boolean shrineRegenerationEnabled = true;
|
||||||
|
/** <b>[Server-only]</b> Time in minutes for a conquered shrine to regenerate. */
|
||||||
|
public int shrineRegenerationTime = 1;
|
||||||
|
/** <b>[Server-only]</b> Whether players can loot shrines multiple times. If false, each player can only loot each shrine once. */
|
||||||
|
public boolean shrineAllowMultipleLoot = false;
|
||||||
/** <b>[Server-only]</b> List of dimension ids in which to generate library ruins. */
|
/** <b>[Server-only]</b> List of dimension ids in which to generate library ruins. */
|
||||||
public int[] libraryDimensions = {0};
|
public int[] libraryDimensions = {0};
|
||||||
/** <b>[Server-only]</b> The rarity of library ruins, used by the world generator. Larger numbers are rarer. */
|
/** <b>[Server-only]</b> The rarity of library ruins, used by the world generator. Larger numbers are rarer. */
|
||||||
@@ -154,6 +165,12 @@ public final class Settings {
|
|||||||
public Pair<ResourceLocation, Short>[] treeBlocks = parseItemMetaStrings(DEFAULT_TREE_BLOCKS);
|
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. */
|
/** <b>[Server-only]</b> The chance for wizard towers to generate with an evil wizard and chest inside. */
|
||||||
public double evilWizardChance = 0.2;
|
public double evilWizardChance = 0.2;
|
||||||
|
public double cooldownReductionPerLevel = 0.15;
|
||||||
|
public double potencyIncreasePerTier = 0.15;
|
||||||
|
public double durationIncreasePerLevel = 0.25;
|
||||||
|
public double rangeIncreasePerLevel = 0.25;
|
||||||
|
public double blastIncreasePerLevel = 0.25;
|
||||||
|
public double frostSlownessIncreasePerLevel = 0.5;
|
||||||
/** <b>[Server-only]</b> List of dimension ids in which to generate crystal ore. */
|
/** <b>[Server-only]</b> List of dimension ids in which to generate crystal ore. */
|
||||||
public int[] oreDimensions = {0};
|
public int[] oreDimensions = {0};
|
||||||
/** <b>[Server-only]</b> List of dimension ids in which to generate crystal flowers. */
|
/** <b>[Server-only]</b> List of dimension ids in which to generate crystal flowers. */
|
||||||
@@ -190,12 +207,25 @@ public final class Settings {
|
|||||||
public boolean playerBlockDamage = true;
|
public boolean playerBlockDamage = true;
|
||||||
/** <b>[Server-only]</b> Whether spells cast by dispensers can destroy blocks in the world. */
|
/** <b>[Server-only]</b> Whether spells cast by dispensers can destroy blocks in the world. */
|
||||||
public boolean dispenserBlockDamage = true;
|
public boolean dispenserBlockDamage = true;
|
||||||
|
/** <b>[Server-only]</b> Whether damage should be registered with the old system (wizardry_magic/indirect_wizardry_magic) prefixed damage with the elements like
|
||||||
|
* necromancy_indirect_wizardry_magic, necromancy_wizardry_magic*/
|
||||||
|
public boolean damageTypePerElement = false;
|
||||||
|
/** <b>[Server-only]</b> Whether spell books are consumed when they are bound to a wand.*/
|
||||||
|
public boolean singleUseSpellBooks = false;
|
||||||
|
/** <b>[Server-only]</b> Whether to prevent binding the same spell to a wand multiple times*/
|
||||||
|
public boolean preventBindingSameSpellTwiceToWands = false;
|
||||||
/** <b>[Server-only]</b> Whether to revert to the old wand upgrade system, which only requires tomes of arcana. */
|
/** <b>[Server-only]</b> Whether to revert to the old wand upgrade system, which only requires tomes of arcana. */
|
||||||
public boolean legacyWandLevelling = false;
|
public boolean legacyWandLevelling = false;
|
||||||
/** <b>[Server-only]</b> Whether to tweak the blindness effect to reduce follow distance when used on non-players. */
|
/** <b>[Server-only]</b> Whether to tweak the blindness effect to reduce follow distance when used on non-players. */
|
||||||
public boolean blindnessTweak = true;
|
public boolean blindnessTweak = true;
|
||||||
/** <b>[Server-only]</b> Whether using bonemeal on grass blocks has a chance to grow crystal flowers. */
|
/** <b>[Server-only]</b> Whether using bonemeal on grass blocks has a chance to grow crystal flowers. */
|
||||||
public boolean bonemealGrowsCrystalFlowers = true;
|
public boolean bonemealGrowsCrystalFlowers = true;
|
||||||
|
/** <b>[Server-only]</b> Whether wands only decrement their cooldowns if a player holds them. */
|
||||||
|
public boolean wandsMustBeHeldToDecrementCooldown = false;
|
||||||
|
/** <b>[Server-only]</b> Whether to enable Wizardry mob loot injection. Allows an easier switch instead of blacklisting all entities. */
|
||||||
|
public boolean injectMobDrops = true;
|
||||||
|
/** <b>[Server-only]</b> The time in ticks after which recent spell casts expire and no longer count toward progression penalties. */
|
||||||
|
public int recentSpellExpiryTime = 1200;
|
||||||
/**
|
/**
|
||||||
* <b>[Server-only]</b> List of registry names of entities which summoned creatures are allowed to attack, in addition
|
* <b>[Server-only]</b> List of registry names of entities which summoned creatures are allowed to attack, in addition
|
||||||
* to the defaults.
|
* to the defaults.
|
||||||
@@ -224,6 +254,8 @@ public final class Settings {
|
|||||||
public Pair<ResourceLocation, Short>[] bowItemWhitelist = parseItemMetaStrings();
|
public Pair<ResourceLocation, Short>[] bowItemWhitelist = parseItemMetaStrings();
|
||||||
/** <b>[Server-only]</b> Map of items to values which wizard trades may use as currency. */
|
/** <b>[Server-only]</b> Map of items to values which wizard trades may use as currency. */
|
||||||
public Map<Pair<ResourceLocation, Short>, Integer> currencyItems = new HashMap<>();
|
public Map<Pair<ResourceLocation, Short>, Integer> currencyItems = new HashMap<>();
|
||||||
|
/** <b>[Server-only]</b> Map of optional NBT tags for currency items, keyed the same as {@link #currencyItems}. */
|
||||||
|
public Map<Pair<ResourceLocation, Short>, NBTTagCompound> currencyItemNbt = new HashMap<>();
|
||||||
/** <b>[Server-only]</b> Global damage scaling factor for all player magic damage. */
|
/** <b>[Server-only]</b> Global damage scaling factor for all player magic damage. */
|
||||||
public double playerDamageScale = 1.0;
|
public double playerDamageScale = 1.0;
|
||||||
/** <b>[Server-only]</b> Global damage scaling factor for all npc magic damage. */
|
/** <b>[Server-only]</b> Global damage scaling factor for all npc magic damage. */
|
||||||
@@ -239,6 +271,26 @@ public final class Settings {
|
|||||||
/** <b>[Server-only]</b> List of registry names of biomes in which wizardry's hostile mobs cannot spawn. */
|
/** <b>[Server-only]</b> List of registry names of biomes in which wizardry's hostile mobs cannot spawn. */
|
||||||
public ResourceLocation[] mobSpawnBiomeBlacklist = toResourceLocations("mushroom_island", "mushroom_island_shore");
|
public ResourceLocation[] mobSpawnBiomeBlacklist = toResourceLocations("mushroom_island", "mushroom_island_shore");
|
||||||
|
|
||||||
|
// Mana and upgrade constants
|
||||||
|
/** <b>[Server-only]</b> The amount of mana a crystal shard is worth */
|
||||||
|
public int manaPerShard = 10;
|
||||||
|
/** <b>[Server-only]</b> The amount of mana each magic crystal is worth */
|
||||||
|
public int manaPerCrystal = 100;
|
||||||
|
/** <b>[Server-only]</b> The amount of mana a grand magic crystal is worth */
|
||||||
|
public int grandCrystalMana = 400;
|
||||||
|
/** <b>[Server-only]</b> The maximum number of one type of wand upgrade which can be applied to a wand. */
|
||||||
|
public int upgradeStackLimit = 3;
|
||||||
|
/** <b>[Server-only]</b> The bonus amount of wand upgrades that can be applied to a non-elemental wand. */
|
||||||
|
public int nonElementalUpgradeBonus = 3;
|
||||||
|
/** <b>[Server-only]</b> The fraction by which maximum charge is increased for each level of storage upgrade. */
|
||||||
|
public float storageIncreasePerLevel = 0.15f;
|
||||||
|
/** <b>[Server-only]</b> The amount of mana given for a kill for each level of siphon upgrade. */
|
||||||
|
public int siphonManaPerLevel = 5;
|
||||||
|
/** <b>[Server-only]</b> The number of ticks between each mana increase for wands with the condenser upgrade. */
|
||||||
|
public int condenserTickInterval = 50;
|
||||||
|
/** <b>[Server-only]</b> The number of spell slots a wand has with no attunement upgrades applied. */
|
||||||
|
public int baseSpellSlots = 5;
|
||||||
|
|
||||||
// Commands (these don't need synchronising since typing a command always queries the server).
|
// Commands (these don't need synchronising since typing a command always queries the server).
|
||||||
/**
|
/**
|
||||||
* <b>[Server-only]</b> The maximum allowed multiplier for the /cast command. This limit is here to stop people from
|
* <b>[Server-only]</b> The maximum allowed multiplier for the /cast command. This limit is here to stop people from
|
||||||
@@ -308,10 +360,40 @@ public final class Settings {
|
|||||||
* velocity-based one.
|
* velocity-based one.
|
||||||
*/
|
*/
|
||||||
public boolean replaceVanillaFallDamage = true;
|
public boolean replaceVanillaFallDamage = true;
|
||||||
|
/** <b>[Synchronised]</b> Whether spell book colors are only shown when the player has the Archivist's Eyeglass equipped. */
|
||||||
|
public boolean spellBookColorsRequireArchivistsEyeglass = false;
|
||||||
/** <b>[Synchronised]</b> Chance of 'misreading' an undiscovered spell and triggering a forfeit instead. */
|
/** <b>[Synchronised]</b> Chance of 'misreading' an undiscovered spell and triggering a forfeit instead. */
|
||||||
public double forfeitChance = 0.2;
|
public double forfeitChance = 0.2;
|
||||||
/** <b>[Synchronised]</b> Progression requirements for upgrading a wand to each tier. */
|
/** <b>[Synchronised]</b> Progression requirements for upgrading a wand to each tier. */
|
||||||
public int[] progressionRequirements = {1500, 3500, 6000};
|
public int[] progressionRequirements = {1500, 3500, 6000};
|
||||||
|
|
||||||
|
// Integer wrappers for tier values
|
||||||
|
public Integer noviceMaxCharge = 700;
|
||||||
|
public Integer apprenticeMaxCharge = 1000;
|
||||||
|
public Integer advancedMaxCharge = 1500;
|
||||||
|
public Integer masterMaxCharge = 2500;
|
||||||
|
|
||||||
|
public Integer noviceUpgradeLimit = 3;
|
||||||
|
public Integer apprenticeUpgradeLimit = 5;
|
||||||
|
public Integer advancedUpgradeLimit = 7;
|
||||||
|
public Integer masterUpgradeLimit = 9;
|
||||||
|
|
||||||
|
/** <b>[Synchronised]</b> Multiplier for condenser upgrade mana regeneration amount */
|
||||||
|
public double condenserAmountMultiplier = 1.0;
|
||||||
|
/** <b>[Synchronised]</b> Whether flesh spells (DiamondFlesh, IronFlesh, OakFlesh) apply slowness */
|
||||||
|
public boolean fleshSpellsCauseSlowness = true;
|
||||||
|
|
||||||
|
/** <b>[Synchronised]</b> Armor bonus for DiamondFlesh spell */
|
||||||
|
public double diamondFleshArmorBonus = 4.0;
|
||||||
|
/** <b>[Synchronised]</b> Armor toughness bonus for DiamondFlesh spell */
|
||||||
|
public double diamondFleshArmorToughnessBonus = 3.0;
|
||||||
|
/** <b>[Synchronised]</b> Armor bonus for IronFlesh spell */
|
||||||
|
public double ironFleshArmorBonus = 4.0;
|
||||||
|
/** <b>[Synchronised]</b> Armor bonus for OakFlesh spell */
|
||||||
|
public double oakFleshArmorBonus = 3.0;
|
||||||
|
/** <b>[Synchronised]</b> Health bonus for OakFlesh spell */
|
||||||
|
public double oakFleshHealthBonus = 0.2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>[Synchronised]</b> The maximum number of blocks a bookshelf can be from an arcane workbench or lectern to be
|
* <b>[Synchronised]</b> The maximum number of blocks a bookshelf can be from an arcane workbench or lectern to be
|
||||||
* able to link to it.
|
* able to link to it.
|
||||||
@@ -375,12 +457,19 @@ public final class Settings {
|
|||||||
public boolean showSpellHUD = true;
|
public boolean showSpellHUD = true;
|
||||||
/** <b>[Client-only]</b> Whether to show the charge meter when charging up a spell. */
|
/** <b>[Client-only]</b> Whether to show the charge meter when charging up a spell. */
|
||||||
public boolean showChargeMeter = true;
|
public boolean showChargeMeter = true;
|
||||||
|
/** <b>[Client-only]</b> Whether to initialise the handbook's data. Setting this to false will break the in-game handbook, but might help with some
|
||||||
|
* startup crashes */
|
||||||
|
public boolean loadHandbook = true;
|
||||||
|
/** <b>[Client-only]</b> Whether to allow the Arcane Workbench and lectern search field to lose focus and start unfocused. */
|
||||||
|
public boolean unfocusedSearchBars = false;
|
||||||
/** <b>[Client-only]</b> The position of the spell HUD. */
|
/** <b>[Client-only]</b> The position of the spell HUD. */
|
||||||
public GuiPosition spellHUDPosition = GuiPosition.BOTTOM_LEFT;
|
public GuiPosition spellHUDPosition = GuiPosition.BOTTOM_LEFT;
|
||||||
|
|
||||||
public static final String DEFAULT_HUD_SKIN_KEY = "default"; // Defined here so it's not in a client-only class.
|
public static final String DEFAULT_HUD_SKIN_KEY = "default"; // Defined here so it's not in a client-only class.
|
||||||
/** <b>[Client-only]</b> The string identifier of the skin used for the spell HUD. */
|
/** <b>[Client-only]</b> The string identifier of the skin used for the spell HUD. */
|
||||||
public String spellHUDSkin = DEFAULT_HUD_SKIN_KEY;
|
public String spellHUDSkin = DEFAULT_HUD_SKIN_KEY;
|
||||||
|
/** <b>[Client-only]</b> Whether to show elemental colors on spell books for discovered spells. */
|
||||||
|
public boolean spellBookColors = true;
|
||||||
|
|
||||||
/** Set of constants for each of the eight positions that the spell HUD can be in. */
|
/** Set of constants for each of the eight positions that the spell HUD can be in. */
|
||||||
public enum GuiPosition {
|
public enum GuiPosition {
|
||||||
@@ -446,6 +535,8 @@ public final class Settings {
|
|||||||
*/
|
*/
|
||||||
void initConfig(FMLPreInitializationEvent event){
|
void initConfig(FMLPreInitializationEvent event){
|
||||||
|
|
||||||
|
redundantKeys.clear();
|
||||||
|
|
||||||
config = new Configuration(new File(Wizardry.configDirectory, Wizardry.MODID + ".cfg"));
|
config = new Configuration(new File(Wizardry.configDirectory, Wizardry.MODID + ".cfg"));
|
||||||
config.load();
|
config.load();
|
||||||
|
|
||||||
@@ -484,6 +575,8 @@ public final class Settings {
|
|||||||
/** Called to save changes to the config file after it has been edited in game from the menus. */
|
/** Called to save changes to the config file after it has been edited in game from the menus. */
|
||||||
void saveConfigChanges(){
|
void saveConfigChanges(){
|
||||||
|
|
||||||
|
redundantKeys.clear();
|
||||||
|
|
||||||
Wizardry.logger.info("Saving in-game config changes");
|
Wizardry.logger.info("Saving in-game config changes");
|
||||||
|
|
||||||
setupGameplayConfig();
|
setupGameplayConfig();
|
||||||
@@ -497,9 +590,58 @@ public final class Settings {
|
|||||||
setupArtefactsConfig();
|
setupArtefactsConfig();
|
||||||
setupResistancesConfig();
|
setupResistancesConfig();
|
||||||
|
|
||||||
|
// Update the constants with new values
|
||||||
|
updateConstantsFromSettings();
|
||||||
|
|
||||||
config.save();
|
config.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Updates the Constants class with the current settings values */
|
||||||
|
public void updateConstantsFromSettings(){
|
||||||
|
electroblob.wizardry.constants.Constants.MANA_PER_SHARD = this.manaPerShard;
|
||||||
|
electroblob.wizardry.constants.Constants.MANA_PER_CRYSTAL = this.manaPerCrystal;
|
||||||
|
electroblob.wizardry.constants.Constants.GRAND_CRYSTAL_MANA = this.grandCrystalMana;
|
||||||
|
electroblob.wizardry.constants.Constants.UPGRADE_STACK_LIMIT = this.upgradeStackLimit;
|
||||||
|
electroblob.wizardry.constants.Constants.NON_ELEMENTAL_UPGRADE_BONUS = this.nonElementalUpgradeBonus;
|
||||||
|
electroblob.wizardry.constants.Constants.COOLDOWN_REDUCTION_PER_LEVEL = (float) this.cooldownReductionPerLevel;
|
||||||
|
electroblob.wizardry.constants.Constants.STORAGE_INCREASE_PER_LEVEL = this.storageIncreasePerLevel;
|
||||||
|
electroblob.wizardry.constants.Constants.POTENCY_INCREASE_PER_TIER = (float) this.potencyIncreasePerTier;
|
||||||
|
electroblob.wizardry.constants.Constants.DURATION_INCREASE_PER_LEVEL = (float) this.durationIncreasePerLevel;
|
||||||
|
electroblob.wizardry.constants.Constants.RANGE_INCREASE_PER_LEVEL = (float) this.rangeIncreasePerLevel;
|
||||||
|
electroblob.wizardry.constants.Constants.BLAST_RADIUS_INCREASE_PER_LEVEL = (float) this.blastIncreasePerLevel;
|
||||||
|
electroblob.wizardry.constants.Constants.FROST_SLOWNESS_PER_LEVEL = (float) this.frostSlownessIncreasePerLevel;
|
||||||
|
electroblob.wizardry.constants.Constants.SIPHON_MANA_PER_LEVEL = this.siphonManaPerLevel;
|
||||||
|
electroblob.wizardry.constants.Constants.CONDENSER_TICK_INTERVAL = this.condenserTickInterval;
|
||||||
|
electroblob.wizardry.item.ItemWand.BASE_SPELL_SLOTS = this.baseSpellSlots;
|
||||||
|
electroblob.wizardry.data.WizardData.MAX_RECENT_SPELLS = this.baseSpellSlots;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkForRedundantOptions(String categoryName, Collection<String> validKeys){
|
||||||
|
|
||||||
|
ConfigCategory category = config.getCategory(categoryName);
|
||||||
|
boolean redundantKeysFound = false;
|
||||||
|
|
||||||
|
for(String key : category.keySet()){
|
||||||
|
if(!validKeys.contains(key)){
|
||||||
|
redundantKeys.add(key);
|
||||||
|
if(!redundantKeysFound){
|
||||||
|
redundantKeysFound = true;
|
||||||
|
Wizardry.logger.info("Config category {} contains redundant options:", categoryName);
|
||||||
|
}
|
||||||
|
Wizardry.logger.info(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(redundantKeysFound){
|
||||||
|
Wizardry.logger.info("These options will have no effect (they are probably left over from an older version of wizardry). It is recommended to either remove them manually, or delete ebwizardry.cfg and allow a fresh config to be generated.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if the config file contains keys that are not valid options (usually because of updates). */
|
||||||
|
public boolean hasRedundantKeys(){
|
||||||
|
return !redundantKeys.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
/** Sends a packet to the specified player's client containing all the <b>synchronised</b> settings. */
|
/** Sends a packet to the specified player's client containing all the <b>synchronised</b> settings. */
|
||||||
public void sync(EntityPlayerMP player){
|
public void sync(EntityPlayerMP player){
|
||||||
Wizardry.logger.info("Synchronising config settings for " + player.getName());
|
Wizardry.logger.info("Synchronising config settings for " + player.getName());
|
||||||
@@ -518,7 +660,10 @@ public final class Settings {
|
|||||||
|
|
||||||
Property property;
|
Property property;
|
||||||
|
|
||||||
|
List<String> keys = new ArrayList<>();
|
||||||
|
|
||||||
for(Spell spell : Spell.getAllSpells()){
|
for(Spell spell : Spell.getAllSpells()){
|
||||||
|
keys.add(spell.getRegistryName().toString());
|
||||||
property = config.get(SPELLS_CATEGORY, spell.getRegistryName().toString(), true,
|
property = config.get(SPELLS_CATEGORY, spell.getRegistryName().toString(), true,
|
||||||
"Set to false to disable this spell");
|
"Set to false to disable this spell");
|
||||||
// Uses the same config key as the spell name, because - well, that's what it's called!
|
// Uses the same config key as the spell name, because - well, that's what it's called!
|
||||||
@@ -527,6 +672,7 @@ public final class Settings {
|
|||||||
spell.setEnabled(property.getBoolean(true));
|
spell.setEnabled(property.getBoolean(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkForRedundantOptions(SPELLS_CATEGORY, keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupArtefactsConfig(){
|
private void setupArtefactsConfig(){
|
||||||
@@ -536,8 +682,11 @@ public final class Settings {
|
|||||||
|
|
||||||
Property property;
|
Property property;
|
||||||
|
|
||||||
|
List<String> keys = new ArrayList<>();
|
||||||
|
|
||||||
for(Item item : Item.REGISTRY){
|
for(Item item : Item.REGISTRY){
|
||||||
if(item instanceof ItemArtefact){
|
if(item instanceof ItemArtefact){
|
||||||
|
keys.add(item.getRegistryName().toString());
|
||||||
property = config.get(ARTEFACTS_CATEGORY, item.getRegistryName().toString(), true,
|
property = config.get(ARTEFACTS_CATEGORY, item.getRegistryName().toString(), true,
|
||||||
"Set to false to disable this item");
|
"Set to false to disable this item");
|
||||||
// Uses the same config key as the item name, because - well, that's what it's called!
|
// Uses the same config key as the item name, because - well, that's what it's called!
|
||||||
@@ -547,6 +696,7 @@ public final class Settings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkForRedundantOptions(ARTEFACTS_CATEGORY, keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupGameplayConfig(){
|
private void setupGameplayConfig(){
|
||||||
@@ -572,6 +722,85 @@ public final class Settings {
|
|||||||
dispenserBlockDamage = property.getBoolean();
|
dispenserBlockDamage = property.getBoolean();
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(GAMEPLAY_CATEGORY, "damageTypePerElement", false,
|
||||||
|
"Whether damage should be registered with the old system (wizardry_magic/indirect_wizardry_magic) prefixed damage with the elements like "
|
||||||
|
+ "necromancy_indirect_wizardry_magic, necromancy_wizardry_magic. This is disabled by default to not break existing modpacks."
|
||||||
|
+ "The intention of this setting is to allow differentiating various damage types for e.g. the Distinct Damage Descriptions mod");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".damage_type_per_element");
|
||||||
|
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||||
|
damageTypePerElement = property.getBoolean();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(GAMEPLAY_CATEGORY, "singleUseSpellBooks", false,
|
||||||
|
"Whether spell books are consumed when they are bound to a wand.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".single_use_spell_books");
|
||||||
|
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||||
|
singleUseSpellBooks = property.getBoolean();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(GAMEPLAY_CATEGORY, "preventBindingSameSpellTwiceToWands", false,
|
||||||
|
"Whether to prevent binding the same spell to a wand multiple times");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".prevent_binding_same_spell_twice_to_wands");
|
||||||
|
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||||
|
preventBindingSameSpellTwiceToWands = property.getBoolean();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(GAMEPLAY_CATEGORY, "manaPerShard", 10,
|
||||||
|
"The amount of mana a crystal shard is worth.", 1, 1000);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".mana_per_shard");
|
||||||
|
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||||
|
manaPerShard = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(GAMEPLAY_CATEGORY, "manaPerCrystal", 100,
|
||||||
|
"The amount of mana each magic crystal is worth.", 1, 10000);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".mana_per_crystal");
|
||||||
|
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||||
|
manaPerCrystal = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(GAMEPLAY_CATEGORY, "grandCrystalMana", 400,
|
||||||
|
"The amount of mana a grand magic crystal is worth.", 1, 10000);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".grand_crystal_mana");
|
||||||
|
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||||
|
grandCrystalMana = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(GAMEPLAY_CATEGORY, "upgradeStackLimit", 3,
|
||||||
|
"The maximum number of one type of wand upgrade which can be applied to a wand.", 1, 10);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".upgrade_stack_limit");
|
||||||
|
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||||
|
upgradeStackLimit = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(GAMEPLAY_CATEGORY, "nonElementalUpgradeBonus", 3,
|
||||||
|
"The bonus amount of wand upgrades that can be applied to a non-elemental wand.", 0, 10);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".non_elemental_upgrade_bonus");
|
||||||
|
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||||
|
nonElementalUpgradeBonus = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(GAMEPLAY_CATEGORY, "siphonManaPerLevel", 5,
|
||||||
|
"The amount of mana given for a kill for each level of siphon upgrade.", 0, 100);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".siphon_mana_per_level");
|
||||||
|
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||||
|
siphonManaPerLevel = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(GAMEPLAY_CATEGORY, "condenserTickInterval", 50,
|
||||||
|
"The number of ticks between each mana increase for wands with the condenser upgrade.", 1, 1000);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".condenser_tick_interval");
|
||||||
|
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||||
|
condenserTickInterval = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(GAMEPLAY_CATEGORY, "baseSpellSlots", 5,
|
||||||
|
"The number of spell slots a wand has with no attunement upgrades applied.", 1, 5);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".base_spell_slots");
|
||||||
|
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||||
|
baseSpellSlots = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
property = config.get(GAMEPLAY_CATEGORY, "playersMoveEachOther", true,
|
property = config.get(GAMEPLAY_CATEGORY, "playersMoveEachOther", true,
|
||||||
"Whether to allow players to move other players around using magic.");
|
"Whether to allow players to move other players around using magic.");
|
||||||
property.setLanguageKey("config." + Wizardry.MODID + ".players_move_each_other");
|
property.setLanguageKey("config." + Wizardry.MODID + ".players_move_each_other");
|
||||||
@@ -623,6 +852,14 @@ public final class Settings {
|
|||||||
bonemealGrowsCrystalFlowers = property.getBoolean();
|
bonemealGrowsCrystalFlowers = property.getBoolean();
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(GAMEPLAY_CATEGORY, "wandsMustBeHeldToDecrementCooldown", false,
|
||||||
|
"Whether wands only decrement their cooldowns if a player holds them.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".wands_must_be_held_to_decrement_cooldown");
|
||||||
|
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||||
|
wandsMustBeHeldToDecrementCooldown = property.getBoolean();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
checkForRedundantOptions(GAMEPLAY_CATEGORY, propOrder); // Must be before the order is set!
|
||||||
config.setCategoryPropertyOrder(GAMEPLAY_CATEGORY, propOrder);
|
config.setCategoryPropertyOrder(GAMEPLAY_CATEGORY, propOrder);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -688,6 +925,122 @@ public final class Settings {
|
|||||||
progressionRequirements = property.getIntList();
|
progressionRequirements = property.getIntList();
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "tierMaxCharges", new int[]{700, 1000, 1500, 2500},
|
||||||
|
"Maximum mana each tier can store (novice, apprentice, advanced, master respectively).");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".tier_max_charges");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
//tierMaxCharges = property.getIntList();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
// Individual tier configuration
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "noviceMaxCharge", 700,
|
||||||
|
"Maximum mana a novice wand can store.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".novice_max_charge");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
noviceMaxCharge = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "apprenticeMaxCharge", 1000,
|
||||||
|
"Maximum mana an apprentice wand can store.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".apprentice_max_charge");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
apprenticeMaxCharge = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "advancedMaxCharge", 1500,
|
||||||
|
"Maximum mana an advanced wand can store.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".advanced_max_charge");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
advancedMaxCharge = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "masterMaxCharge", 2500,
|
||||||
|
"Maximum mana a master wand can store.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".master_max_charge");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
masterMaxCharge = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "noviceUpgradeLimit", 3,
|
||||||
|
"Maximum number of upgrades a novice wand can have.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".novice_upgrade_limit");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
noviceUpgradeLimit = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "apprenticeUpgradeLimit", 5,
|
||||||
|
"Maximum number of upgrades an apprentice wand can have.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".apprentice_upgrade_limit");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
apprenticeUpgradeLimit = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "advancedUpgradeLimit", 7,
|
||||||
|
"Maximum number of upgrades an advanced wand can have.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".advanced_upgrade_limit");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
advancedUpgradeLimit = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "masterUpgradeLimit", 9,
|
||||||
|
"Maximum number of upgrades a master wand can have.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".master_upgrade_limit");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
masterUpgradeLimit = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "condenserAmountMultiplier", 1.0,
|
||||||
|
"Multiplier for condenser upgrade mana regeneration amount. Higher values make condensers more effective.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".condenser_amount_multiplier");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
condenserAmountMultiplier = property.getDouble();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "fleshSpellsCauseSlowness", true,
|
||||||
|
"Whether flesh spells (DiamondFlesh, IronFlesh, OakFlesh) apply slowness. When disabled, these spells only provide their defensive benefits without movement penalty.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".flesh_spells_cause_slowness");
|
||||||
|
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||||
|
property.requiresMcRestart();
|
||||||
|
fleshSpellsCauseSlowness = property.getBoolean();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "diamondFleshArmorBonus", 4.0,
|
||||||
|
"Armor bonus provided by the DiamondFlesh spell.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".diamond_flesh_armor_bonus");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
diamondFleshArmorBonus = property.getDouble();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "diamondFleshArmorToughnessBonus", 3.0,
|
||||||
|
"Armor toughness bonus provided by the DiamondFlesh spell.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".diamond_flesh_armor_toughness_bonus");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
diamondFleshArmorToughnessBonus = property.getDouble();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "ironFleshArmorBonus", 4.0,
|
||||||
|
"Armor bonus provided by the IronFlesh spell.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".iron_flesh_armor_bonus");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
ironFleshArmorBonus = property.getDouble();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "oakFleshArmorBonus", 3.0,
|
||||||
|
"Armor bonus provided by the OakFlesh spell.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".oak_flesh_armor_bonus");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
oakFleshArmorBonus = property.getDouble();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(DIFFICULTY_CATEGORY, "oakFleshHealthBonus", 0.2,
|
||||||
|
"Health bonus provided by the OakFlesh spell (as a multiplier, e.g., 0.2 = 20% increase).");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".oak_flesh_health_bonus");
|
||||||
|
property.setRequiresWorldRestart(true);
|
||||||
|
oakFleshHealthBonus = property.getDouble();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// These two aren't sliders because using a slider makes it difficult to fine-tune the numbers; the nature of a
|
// These two aren't sliders because using a slider makes it difficult to fine-tune the numbers; the nature of a
|
||||||
// scaling factor means that 0.5 is as big a change as 2.0, so whilst a slider is fine for increasing the
|
// scaling factor means that 0.5 is as big a change as 2.0, so whilst a slider is fine for increasing the
|
||||||
// damage, it doesn't give fine enough control for values less than 1.
|
// damage, it doesn't give fine enough control for values less than 1.
|
||||||
@@ -730,6 +1083,7 @@ public final class Settings {
|
|||||||
lightningWraithSpawnRate = property.getInt();
|
lightningWraithSpawnRate = property.getInt();
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
checkForRedundantOptions(DIFFICULTY_CATEGORY, propOrder); // Must be before the order is set!
|
||||||
config.setCategoryPropertyOrder(DIFFICULTY_CATEGORY, propOrder);
|
config.setCategoryPropertyOrder(DIFFICULTY_CATEGORY, propOrder);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -758,6 +1112,13 @@ public final class Settings {
|
|||||||
replaceVanillaFallDamage = property.getBoolean();
|
replaceVanillaFallDamage = property.getBoolean();
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(TWEAKS_CATEGORY, "spellBookColorsRequireArchivistsEyeglass", false,
|
||||||
|
"If true, spell book colors are only shown when the player has the charm of spell discovery equipped.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".spell_book_colors_require_charm");
|
||||||
|
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||||
|
spellBookColorsRequireArchivistsEyeglass = property.getBoolean();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
property = config.get(TWEAKS_CATEGORY, "blindnessTweak", true,
|
property = config.get(TWEAKS_CATEGORY, "blindnessTweak", true,
|
||||||
"Whether to tweak the blindness effect to reduce follow distance when used on non-players. This automatically disables itself in favour of Potion Core's implementation if installed.");
|
"Whether to tweak the blindness effect to reduce follow distance when used on non-players. This automatically disables itself in favour of Potion Core's implementation if installed.");
|
||||||
property.setLanguageKey("config." + Wizardry.MODID + ".blindness_tweak");
|
property.setLanguageKey("config." + Wizardry.MODID + ".blindness_tweak");
|
||||||
@@ -765,6 +1126,21 @@ public final class Settings {
|
|||||||
blindnessTweak = property.getBoolean();
|
blindnessTweak = property.getBoolean();
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(TWEAKS_CATEGORY, "injectMobDrops", true,
|
||||||
|
"Whether to inject Wizardry loot to mobs, based on the loot table 'Mob Loot Table Whitelist' / 'Mob Loot Table Blacklist' settings. If disabled, the lists won't have any effect!");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".inject_mob_drops");
|
||||||
|
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||||
|
injectMobDrops = property.getBoolean();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(TWEAKS_CATEGORY, "recentSpellExpiryTime", 1200,
|
||||||
|
"The time in ticks after which recent spell casts expire and no longer count toward progression penalties. Default is 1200 ticks (1 minute). Lower values make progression penalties shorter-lived, higher values make them last longer.",
|
||||||
|
60, 72000); // Between 3 seconds and 1 hour
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".recent_spell_expiry_time");
|
||||||
|
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||||
|
recentSpellExpiryTime = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
property = config.get(TWEAKS_CATEGORY, "mobLootTableWhitelist", new String[0], "Whitelist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually include them.");
|
property = config.get(TWEAKS_CATEGORY, "mobLootTableWhitelist", new String[0], "Whitelist for loot tables to inject additional mob drops (as specified in loot_tables/entities/mob_additions.json) into. Wizardry makes a best guess as to which loot tables belong to hostile mobs, but this may not always be correct or appropriate; add loot table locations (not entity IDs) to this list to manually include them.");
|
||||||
property.setLanguageKey("config." + Wizardry.MODID + ".mob_loot_table_whitelist");
|
property.setLanguageKey("config." + Wizardry.MODID + ".mob_loot_table_whitelist");
|
||||||
property.setRequiresMcRestart(true);
|
property.setRequiresMcRestart(true);
|
||||||
@@ -853,25 +1229,98 @@ public final class Settings {
|
|||||||
bookshelfSearchRadius = property.getInt();
|
bookshelfSearchRadius = property.getInt();
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
property = config.get(TWEAKS_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.",
|
property = config.get(TWEAKS_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. To specify metadata, use the format 'modid:item:meta value'. For example, 'minecraft:wool:1 5'. If no metadata is given, any metadata will be accepted. NBT tags may optionally be specified in SNBT format immediately after the item/metadata, e.g. 'minecraft:potion{Potion:\"minecraft:strength\"} 3'.",
|
||||||
Pattern.compile("[A-Za-z0-9:_]+ [0-9]+"));
|
Pattern.compile(".+ [0-9]+"));
|
||||||
property.setLanguageKey("config." + Wizardry.MODID + ".currency_items");
|
property.setLanguageKey("config." + Wizardry.MODID + ".currency_items");
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
currencyItems = new HashMap<>();
|
currencyItems = new HashMap<>();
|
||||||
|
currencyItemNbt = new HashMap<>();
|
||||||
for(String string : property.getStringList()){
|
for(String string : property.getStringList()){
|
||||||
string = string.toLowerCase(Locale.ROOT).trim();
|
string = string.trim();
|
||||||
String[] args = string.split(" ");
|
// Split on the last space to separate the item spec from the integer value; this correctly
|
||||||
if(args.length != 2){
|
// handles NBT strings that contain spaces inside quoted values.
|
||||||
|
int lastSpace = string.lastIndexOf(' ');
|
||||||
|
if(lastSpace < 0){
|
||||||
Wizardry.logger.warn("Invalid entry in currency items: {}", string);
|
Wizardry.logger.warn("Invalid entry in currency items: {}", string);
|
||||||
continue; // Ignore invalid entries, the pattern above should ensure this never happens
|
continue;
|
||||||
|
}
|
||||||
|
String itemSpec = string.substring(0, lastSpace).toLowerCase(Locale.ROOT);
|
||||||
|
String valueStr = string.substring(lastSpace + 1);
|
||||||
|
// Check for an optional NBT tag (do NOT lowercase the raw NBT string - it is case-sensitive)
|
||||||
|
int nbtStart = itemSpec.indexOf('{');
|
||||||
|
NBTTagCompound nbt = null;
|
||||||
|
if(nbtStart >= 0){
|
||||||
|
// Re-extract the NBT portion from the original (non-lowercased) string to preserve case
|
||||||
|
String rawNbt = string.substring(nbtStart, lastSpace);
|
||||||
|
itemSpec = itemSpec.substring(0, nbtStart);
|
||||||
|
try{
|
||||||
|
nbt = JsonToNBT.getTagFromJson(rawNbt);
|
||||||
|
}catch(NBTException e){
|
||||||
|
Wizardry.logger.warn("Invalid NBT in currency items '{}': {}", string, e.getMessage());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try{
|
try{
|
||||||
currencyItems.put(parseItemMetaString(args[0]), Integer.parseInt(args[1]));
|
Pair<ResourceLocation, Short> key = parseItemMetaString(itemSpec);
|
||||||
|
currencyItems.put(key, Integer.parseInt(valueStr));
|
||||||
|
if(nbt != null) currencyItemNbt.put(key, nbt);
|
||||||
}catch(NumberFormatException e){
|
}catch(NumberFormatException e){
|
||||||
Wizardry.logger.warn("Invalid integer in currency items: {}", args[1]);
|
Wizardry.logger.warn("Invalid integer in currency items: {}", valueStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property = config.get(TWEAKS_CATEGORY, "cooldown_reduction_per_level", 0.15,
|
||||||
|
"The fraction by which cooldowns are reduced for each level of cooldown upgrade.",
|
||||||
|
0.05, Integer.MAX_VALUE); // Sure, I mean you COULD set it to 2^31-1... what could possibly go wrong?
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".cooldown_reduction_per_level");
|
||||||
|
cooldownReductionPerLevel = property.getDouble();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(TWEAKS_CATEGORY, "storage_increase_per_level", 0.15,
|
||||||
|
"The fraction by which maximum charge is increased for each level of storage upgrade.",
|
||||||
|
0.05, Integer.MAX_VALUE);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".storage_increase_per_level");
|
||||||
|
storageIncreasePerLevel = (float) property.getDouble();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(TWEAKS_CATEGORY, "potency_increase_per_tier", 0.15,
|
||||||
|
"The fraction by which potency is increased for each tier of matching wand. May cause extreme lag with high values!",
|
||||||
|
0.05, Integer.MAX_VALUE);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".potency_increase_per_tier");
|
||||||
|
potencyIncreasePerTier = property.getDouble();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(TWEAKS_CATEGORY, "duration_increase_per_level", 0.25,
|
||||||
|
"The fraction by which spell duration is increased for each level of duration upgrade.",
|
||||||
|
0.05, Integer.MAX_VALUE);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".duration_increase_per_level");
|
||||||
|
durationIncreasePerLevel = property.getDouble();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(TWEAKS_CATEGORY, "range_increase_per_level", 0.25,
|
||||||
|
"The fraction by which spell range is increased for each level of range upgrade. May cause extreme lag with high values!",
|
||||||
|
0.05, Integer.MAX_VALUE);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".range_increase_per_level");
|
||||||
|
rangeIncreasePerLevel = property.getDouble();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(TWEAKS_CATEGORY, "blast_increase_per_level", 0.25,
|
||||||
|
"The fraction by which spell blast is increased for each level of blast upgrade. May cause extreme lag with high values!",
|
||||||
|
0.05, Integer.MAX_VALUE);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".blast_increase_per_level");
|
||||||
|
blastIncreasePerLevel = property.getDouble();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
|
||||||
|
property = config.get(TWEAKS_CATEGORY, "frost_slowness_increase_per_level", 0.5,
|
||||||
|
"The fraction by which movement speed is reduced per level of frost effect.",
|
||||||
|
0.05, Integer.MAX_VALUE);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".frost_slowness_increase_per_level");
|
||||||
|
frostSlownessIncreasePerLevel = property.getDouble();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
|
||||||
|
checkForRedundantOptions(TWEAKS_CATEGORY, propOrder); // Must be before the order is set!
|
||||||
config.setCategoryPropertyOrder(TWEAKS_CATEGORY, propOrder);
|
config.setCategoryPropertyOrder(TWEAKS_CATEGORY, propOrder);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -968,6 +1417,22 @@ public final class Settings {
|
|||||||
shrineFiles = getResourceLocationList(property);
|
shrineFiles = getResourceLocationList(property);
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(WORLDGEN_CATEGORY, "shrineRegenerationEnabled", false, "Whether conquered shrines should regenerate after a period of time. When disabled, shrines remain conquered permanently.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".shrine_regeneration_enabled");
|
||||||
|
shrineRegenerationEnabled = property.getBoolean();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(WORLDGEN_CATEGORY, "shrineRegenerationTime", 20, "Time in minutes for a conquered shrine to regenerate. Minimum 1 minute, maximum 1440 minutes (24 hours).", 1, 1440);
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".shrine_regeneration_time");
|
||||||
|
Wizardry.proxy.setToNumberSliderEntry(property);
|
||||||
|
shrineRegenerationTime = property.getInt();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(WORLDGEN_CATEGORY, "shrineAllowMultipleLoot", false, "Whether players can loot shrines multiple times. If false, each player can only loot each shrine once until it regenerates.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".shrine_allow_multiple_loot");
|
||||||
|
shrineAllowMultipleLoot = property.getBoolean();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
property = config.get(WORLDGEN_CATEGORY, "libraryDimensions", new int[]{0}, "List of dimension ids in which library ruins will generate. Remove all dimensions to disable library ruins completely.");
|
property = config.get(WORLDGEN_CATEGORY, "libraryDimensions", new int[]{0}, "List of dimension ids in which library ruins will generate. Remove all dimensions to disable library ruins completely.");
|
||||||
property.setLanguageKey("config." + Wizardry.MODID + ".library_dimensions");
|
property.setLanguageKey("config." + Wizardry.MODID + ".library_dimensions");
|
||||||
property.setRequiresWorldRestart(true);
|
property.setRequiresWorldRestart(true);
|
||||||
@@ -1019,6 +1484,7 @@ public final class Settings {
|
|||||||
lootInjectionLocations = getResourceLocationList(property);
|
lootInjectionLocations = getResourceLocationList(property);
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
checkForRedundantOptions(WORLDGEN_CATEGORY, propOrder); // Must be before the order is set!
|
||||||
config.setCategoryPropertyOrder(WORLDGEN_CATEGORY, propOrder);
|
config.setCategoryPropertyOrder(WORLDGEN_CATEGORY, propOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1059,6 +1525,27 @@ public final class Settings {
|
|||||||
showChargeMeter = property.getBoolean();
|
showChargeMeter = property.getBoolean();
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(CLIENT_CATEGORY, "spellBookColors", true, "Whether to show elemental colors on spell books for discovered spells.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".spell_book_colors");
|
||||||
|
property.setRequiresWorldRestart(false);
|
||||||
|
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||||
|
spellBookColors = property.getBoolean();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(CLIENT_CATEGORY, "loadHandbook", true, "Whether to initialise the in-game handbook. Setting this to false will brick the in-game handbook, but it might help if you have startup crashes.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".load_handbook");
|
||||||
|
property.setRequiresWorldRestart(false);
|
||||||
|
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||||
|
loadHandbook = property.getBoolean();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(CLIENT_CATEGORY, "unfocusedSearchBars", false, "Whether to allow the Arcane Workbench and lectern search field to lose focus and start unfocused. If true, the search field won't automatically capture keyboard input.");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".unfocused_search_bars");
|
||||||
|
property.setRequiresWorldRestart(false);
|
||||||
|
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||||
|
unfocusedSearchBars = property.getBoolean();
|
||||||
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
property = config.get(CLIENT_CATEGORY, "spellHUDPosition", GuiPosition.BOTTOM_LEFT.name, "The position of the spell HUD.", GuiPosition.names);
|
property = config.get(CLIENT_CATEGORY, "spellHUDPosition", GuiPosition.BOTTOM_LEFT.name, "The position of the spell HUD.", GuiPosition.names);
|
||||||
property.setLanguageKey("config." + Wizardry.MODID + ".spell_hud_position");
|
property.setLanguageKey("config." + Wizardry.MODID + ".spell_hud_position");
|
||||||
spellHUDPosition = GuiPosition.fromName(property.getString());
|
spellHUDPosition = GuiPosition.fromName(property.getString());
|
||||||
@@ -1120,6 +1607,7 @@ public final class Settings {
|
|||||||
donationPerkElement = Element.fromName(property.getString(), null); // Fallback to null for no element
|
donationPerkElement = Element.fromName(property.getString(), null); // Fallback to null for no element
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
checkForRedundantOptions(CLIENT_CATEGORY, propOrder); // Must be before the order is set!
|
||||||
config.setCategoryPropertyOrder(CLIENT_CATEGORY, propOrder);
|
config.setCategoryPropertyOrder(CLIENT_CATEGORY, propOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1166,6 +1654,7 @@ public final class Settings {
|
|||||||
alliesCommandName = property.getString();
|
alliesCommandName = property.getString();
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
checkForRedundantOptions(COMMANDS_CATEGORY, propOrder); // Must be before the order is set!
|
||||||
config.setCategoryPropertyOrder(COMMANDS_CATEGORY, propOrder);
|
config.setCategoryPropertyOrder(COMMANDS_CATEGORY, propOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1217,6 +1706,18 @@ public final class Settings {
|
|||||||
}
|
}
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToMagic", new String[]{},
|
||||||
|
"List of names of entities that are immune to magic, in addition to the defaults. Add mod creatures to this list if you want them to be immune to magic damage and they aren't already. SoundLoopSpellEntity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard).");
|
||||||
|
property.setLanguageKey("config." + Wizardry.MODID + ".mobs_immune_to_magic");
|
||||||
|
property.setRequiresMcRestart(true);
|
||||||
|
// Wizardry.proxy.setToEntityNameEntry(property);
|
||||||
|
// Converts all strings in the list to lower case, to ignore case sensitivity, and trims them.
|
||||||
|
for(int i = 0; i < property.getStringList().length; i++){
|
||||||
|
property.getStringList()[i] = property.getStringList()[i].toLowerCase(Locale.ROOT).trim();
|
||||||
|
MagicDamage.addEntityImmunity(EntityList.getClass(new ResourceLocation(property.getStringList()[i])),
|
||||||
|
DamageType.MAGIC);
|
||||||
|
}
|
||||||
|
propOrder.add(property.getName());
|
||||||
property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToWither", new String[]{},
|
property = config.get(RESISTANCES_CATEGORY, "mobsImmuneToWither", new String[]{},
|
||||||
"List of names of entities that are immune to wither effects, in addition to the defaults. Add mod creatures to this list if you want them to be immune to withering magic and they aren't already. SoundLoopSpellEntity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard).");
|
"List of names of entities that are immune to wither effects, in addition to the defaults. Add mod creatures to this list if you want them to be immune to withering magic and they aren't already. SoundLoopSpellEntity names are not case sensitive. For mod entities, prefix with the mod ID (e.g. " + Wizardry.MODID + ":wizard).");
|
||||||
property.setLanguageKey("config." + Wizardry.MODID + ".mobs_immune_to_wither");
|
property.setLanguageKey("config." + Wizardry.MODID + ".mobs_immune_to_wither");
|
||||||
@@ -1243,6 +1744,7 @@ public final class Settings {
|
|||||||
}
|
}
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
checkForRedundantOptions(RESISTANCES_CATEGORY, propOrder); // Must be before the order is set!
|
||||||
config.setCategoryPropertyOrder(RESISTANCES_CATEGORY, propOrder);
|
config.setCategoryPropertyOrder(RESISTANCES_CATEGORY, propOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1332,6 +1834,7 @@ public final class Settings {
|
|||||||
autoUndergroundLibraryMarkers = property.getBoolean();
|
autoUndergroundLibraryMarkers = property.getBoolean();
|
||||||
propOrder.add(property.getName());
|
propOrder.add(property.getName());
|
||||||
|
|
||||||
|
checkForRedundantOptions(COMPATIBILITY_CATEGORY, propOrder); // Must be before the order is set!
|
||||||
config.setCategoryPropertyOrder(COMPATIBILITY_CATEGORY, propOrder);
|
config.setCategoryPropertyOrder(COMPATIBILITY_CATEGORY, propOrder);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1359,16 +1862,46 @@ public final class Settings {
|
|||||||
|
|
||||||
string = string.toLowerCase(Locale.ROOT).trim();
|
string = string.toLowerCase(Locale.ROOT).trim();
|
||||||
|
|
||||||
String[] itemArgs = string.split(":");
|
|
||||||
String item;
|
String item;
|
||||||
short meta;
|
short meta;
|
||||||
|
|
||||||
try {
|
int lastColon = string.lastIndexOf(':');
|
||||||
meta = Short.parseShort(itemArgs[itemArgs.length-1]);
|
|
||||||
item = String.join(":", Arrays.copyOfRange(itemArgs, 0, itemArgs.length-1));
|
if (lastColon > -1 && lastColon < string.length() - 1) { // if there is a colon and it's not the last char
|
||||||
}catch(NumberFormatException e){ // If no metadata is specified
|
String metaString = string.substring(lastColon + 1);
|
||||||
meta = OreDictionary.WILDCARD_VALUE;
|
try {
|
||||||
|
short parsedMeta = Short.parseShort(metaString);
|
||||||
|
String itemString = string.substring(0, lastColon);
|
||||||
|
|
||||||
|
// If itemString has no colon, it could be 'item:meta' or 'namespace:numeric_path'.
|
||||||
|
// e.g., 'wool:1' vs 'mod:123'. We want to support 'wool:1' as item 'wool' with meta 1.
|
||||||
|
// We can't reliably distinguish the two cases without knowing all namespaces, so we have to use
|
||||||
|
// a heuristic. The original code favoured the 'item:meta' interpretation, let's stick with that.
|
||||||
|
// The issue was with 'namespace:numeric_path' which this logic now handles.
|
||||||
|
if (itemString.indexOf(':') == -1) {
|
||||||
|
item = itemString;
|
||||||
|
meta = parsedMeta;
|
||||||
|
} else {
|
||||||
|
// Disambiguate things like 'mod:123:4' (item 'mod:123' with meta 4) vs 'mod:item:123' (item 'mod:item' with meta 123)
|
||||||
|
// If the bit before the last colon is a valid resource location, it's probably item:meta
|
||||||
|
try {
|
||||||
|
new ResourceLocation(itemString);
|
||||||
|
item = itemString;
|
||||||
|
meta = parsedMeta;
|
||||||
|
} catch (Exception e) {
|
||||||
|
item = string;
|
||||||
|
meta = OreDictionary.WILDCARD_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// The part after colon is not a number, so it's part of the name
|
||||||
|
item = string;
|
||||||
|
meta = OreDictionary.WILDCARD_VALUE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
item = string;
|
item = string;
|
||||||
|
meta = OreDictionary.WILDCARD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Pair.of(new ResourceLocation(item), meta);
|
return Pair.of(new ResourceLocation(item), meta);
|
||||||
|
|||||||
@@ -13,11 +13,23 @@ import electroblob.wizardry.inventory.ContainerBookshelf;
|
|||||||
import electroblob.wizardry.misc.DonationPerksHandler;
|
import electroblob.wizardry.misc.DonationPerksHandler;
|
||||||
import electroblob.wizardry.misc.Forfeit;
|
import electroblob.wizardry.misc.Forfeit;
|
||||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||||
import electroblob.wizardry.registry.*;
|
import electroblob.wizardry.registry.Spells;
|
||||||
|
import electroblob.wizardry.registry.WizardryAdvancementTriggers;
|
||||||
|
import electroblob.wizardry.registry.WizardryBlocks;
|
||||||
|
import electroblob.wizardry.registry.WizardryItems;
|
||||||
|
import electroblob.wizardry.registry.WizardryLoot;
|
||||||
|
import electroblob.wizardry.registry.WizardrySounds;
|
||||||
import electroblob.wizardry.spell.Spell;
|
import electroblob.wizardry.spell.Spell;
|
||||||
|
import electroblob.wizardry.util.SpellNetworkIDSorter;
|
||||||
import electroblob.wizardry.util.SpellProperties;
|
import electroblob.wizardry.util.SpellProperties;
|
||||||
import electroblob.wizardry.util.WandHelper;
|
import electroblob.wizardry.util.WandHelper;
|
||||||
import electroblob.wizardry.worldgen.*;
|
import electroblob.wizardry.worldgen.WorldGenCrystalFlower;
|
||||||
|
import electroblob.wizardry.worldgen.WorldGenCrystalOre;
|
||||||
|
import electroblob.wizardry.worldgen.WorldGenLibraryRuins;
|
||||||
|
import electroblob.wizardry.worldgen.WorldGenObelisk;
|
||||||
|
import electroblob.wizardry.worldgen.WorldGenShrine;
|
||||||
|
import electroblob.wizardry.worldgen.WorldGenUndergroundLibraryRuins;
|
||||||
|
import electroblob.wizardry.worldgen.WorldGenWizardTower;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.util.SoundCategory;
|
import net.minecraft.util.SoundCategory;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
@@ -51,6 +63,7 @@ import java.util.Calendar;
|
|||||||
|
|
||||||
@Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, acceptedMinecraftVersions = "[1.12.2]",
|
@Mod(modid = Wizardry.MODID, name = Wizardry.NAME, version = Wizardry.VERSION, acceptedMinecraftVersions = "[1.12.2]",
|
||||||
guiFactory = "electroblob.wizardry.WizardryGuiFactory",
|
guiFactory = "electroblob.wizardry.WizardryGuiFactory",
|
||||||
|
updateJSON = Wizardry.updateJSON,
|
||||||
dependencies = "required-after:forge@[14.23.5.2847,);after:jei@[4.15.0,);after:baubles@[1.5.2,);after:antiqueatlas@[4.6,)")
|
dependencies = "required-after:forge@[14.23.5.2847,);after:jei@[4.15.0,);after:baubles@[1.5.2,);after:antiqueatlas@[4.6,)")
|
||||||
|
|
||||||
public class Wizardry {
|
public class Wizardry {
|
||||||
@@ -69,7 +82,13 @@ public class Wizardry {
|
|||||||
* 1.x.x represents Minecraft 1.7.x versions, 2.x.x represents Minecraft 1.10.x versions, 3.x.x represents Minecraft
|
* 1.x.x represents Minecraft 1.7.x versions, 2.x.x represents Minecraft 1.10.x versions, 3.x.x represents Minecraft
|
||||||
* 1.11.x versions, and so on.
|
* 1.11.x versions, and so on.
|
||||||
*/
|
*/
|
||||||
public static final String VERSION = "4.3.2";
|
public static final String VERSION = "4.3.18";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Json file used by Forge's built-in <a href="https://mcforge.readthedocs.io/en/1.12.x/gettingstarted/autoupdate/">update checker</a>.
|
||||||
|
* Used by the in-game mod menu to show that green icon whenever a newer version is available of the mod.
|
||||||
|
*/
|
||||||
|
public static final String updateJSON = "https://github.com/Electroblob77/Wizardry/blob/1.12.2/.forge/update.json";
|
||||||
|
|
||||||
// IDEA: Triggering of inbuilt Forge events in relevant places?
|
// IDEA: Triggering of inbuilt Forge events in relevant places?
|
||||||
// IDEA: Abstract the vanilla particles behind the particle builder
|
// IDEA: Abstract the vanilla particles behind the particle builder
|
||||||
@@ -108,8 +127,6 @@ public class Wizardry {
|
|||||||
public void preInit(FMLPreInitializationEvent event){
|
public void preInit(FMLPreInitializationEvent event){
|
||||||
|
|
||||||
logger = event.getModLog();
|
logger = event.getModLog();
|
||||||
|
|
||||||
proxy.registerResourceReloadListeners();
|
|
||||||
|
|
||||||
configDirectory = new File(event.getModConfigurationDirectory(), Wizardry.MODID);
|
configDirectory = new File(event.getModConfigurationDirectory(), Wizardry.MODID);
|
||||||
settings.initConfig(event);
|
settings.initConfig(event);
|
||||||
@@ -143,9 +160,13 @@ public class Wizardry {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void init(FMLInitializationEvent event){
|
public void init(FMLInitializationEvent event){
|
||||||
|
proxy.registerResourceReloadListeners();
|
||||||
|
|
||||||
settings.initConfigExtras();
|
settings.initConfigExtras();
|
||||||
|
|
||||||
|
// Update constants with configured values
|
||||||
|
settings.updateConstantsFromSettings();
|
||||||
|
|
||||||
// World generators
|
// World generators
|
||||||
// Weight is a misnomer, it's actually the priority (where lower numbers get generated first)
|
// Weight is a misnomer, it's actually the priority (where lower numbers get generated first)
|
||||||
// Literally nothing on typical 'weight' values here, there isn't even an upper limit
|
// Literally nothing on typical 'weight' values here, there isn't even an upper limit
|
||||||
@@ -168,8 +189,6 @@ public class Wizardry {
|
|||||||
// Post-registry extras
|
// Post-registry extras
|
||||||
BlockBookshelf.compileBookModelTextures();
|
BlockBookshelf.compileBookModelTextures();
|
||||||
ContainerBookshelf.initDefaultBookItems();
|
ContainerBookshelf.initDefaultBookItems();
|
||||||
WizardryItems.populateWandMap();
|
|
||||||
WizardryItems.populateArmourMap();
|
|
||||||
WizardryItems.registerDispenseBehaviours();
|
WizardryItems.registerDispenseBehaviours();
|
||||||
WizardryItems.registerBannerPatterns();
|
WizardryItems.registerBannerPatterns();
|
||||||
WandHelper.populateUpgradeMap();
|
WandHelper.populateUpgradeMap();
|
||||||
@@ -179,6 +198,8 @@ public class Wizardry {
|
|||||||
// Client-side stuff (via proxies)
|
// Client-side stuff (via proxies)
|
||||||
proxy.initGuiBits();
|
proxy.initGuiBits();
|
||||||
proxy.registerParticles();
|
proxy.registerParticles();
|
||||||
|
proxy.registerItemColorHandlers();
|
||||||
|
proxy.registerModelProperties();
|
||||||
proxy.registerSoundEventListener();
|
proxy.registerSoundEventListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,6 +207,8 @@ public class Wizardry {
|
|||||||
public void postInit(FMLPostInitializationEvent event){
|
public void postInit(FMLPostInitializationEvent event){
|
||||||
proxy.initialiseLayers();
|
proxy.initialiseLayers();
|
||||||
proxy.initialiseAnimations();
|
proxy.initialiseAnimations();
|
||||||
|
|
||||||
|
SpellNetworkIDSorter.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
|
|||||||
@@ -203,7 +203,6 @@ public final class WizardryEventHandler {
|
|||||||
// Find the angle between the direction the mob is looking and the direction the player is in
|
// Find the angle between the direction the mob is looking and the direction the player is in
|
||||||
// Angle between a and b = acos((a.b) / (|a|*|b|))
|
// Angle between a and b = acos((a.b) / (|a|*|b|))
|
||||||
double angle = Math.acos(vec.dotProduct(event.getEntity().getLookVec()) / vec.length());
|
double angle = Math.acos(vec.dotProduct(event.getEntity().getLookVec()) / vec.length());
|
||||||
System.out.println(angle);
|
|
||||||
// If the player is not within the 144-degree arc in front of the mob, it won't detect them
|
// If the player is not within the 144-degree arc in front of the mob, it won't detect them
|
||||||
if(angle > 0.4 * Math.PI){
|
if(angle > 0.4 * Math.PI){
|
||||||
((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
|
((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
|
||||||
@@ -269,7 +268,7 @@ public final class WizardryEventHandler {
|
|||||||
// Fireskin
|
// Fireskin
|
||||||
if(event.getEntityLiving().isPotionActive(WizardryPotions.fireskin)
|
if(event.getEntityLiving().isPotionActive(WizardryPotions.fireskin)
|
||||||
&& !MagicDamage.isEntityImmune(DamageType.FIRE, event.getEntityLiving()))
|
&& !MagicDamage.isEntityImmune(DamageType.FIRE, event.getEntityLiving()))
|
||||||
attacker.setFire(Spells.fire_breath.getProperty(Spell.BURN_DURATION).intValue());
|
attacker.setFire(Spells.fire_breath.getProperty(Spell.BURN_DURATION).intValue() * 20);
|
||||||
|
|
||||||
// Ice Shroud
|
// Ice Shroud
|
||||||
if(event.getEntityLiving().isPotionActive(WizardryPotions.ice_shroud)
|
if(event.getEntityLiving().isPotionActive(WizardryPotions.ice_shroud)
|
||||||
@@ -307,7 +306,7 @@ public final class WizardryEventHandler {
|
|||||||
PotionEffect effect = event.getEntityLiving().getActivePotionEffect(WizardryPotions.ward);
|
PotionEffect effect = event.getEntityLiving().getActivePotionEffect(WizardryPotions.ward);
|
||||||
|
|
||||||
if(effect != null && event.getSource().isMagicDamage()){
|
if(effect != null && event.getSource().isMagicDamage()){
|
||||||
event.setAmount(event.getAmount() * Math.max(0, 1 - 0.4f * effect.getAmplifier())); // Resistance is 20%
|
event.setAmount(event.getAmount() * Math.max(0, 1 - 0.2f * (1 + effect.getAmplifier()))); // Resistance is 20%
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flaming and freezing swords
|
// Flaming and freezing swords
|
||||||
@@ -491,4 +490,4 @@ public final class WizardryEventHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
|
|||||||
import electroblob.wizardry.Settings;
|
import electroblob.wizardry.Settings;
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
import electroblob.wizardry.WizardryGuiHandler;
|
import electroblob.wizardry.WizardryGuiHandler;
|
||||||
|
import electroblob.wizardry.inventory.ContainerBookshelf;
|
||||||
import electroblob.wizardry.registry.WizardryItems;
|
import electroblob.wizardry.registry.WizardryItems;
|
||||||
import electroblob.wizardry.registry.WizardryTabs;
|
import electroblob.wizardry.registry.WizardryTabs;
|
||||||
import electroblob.wizardry.tileentity.TileEntityBookshelf;
|
import electroblob.wizardry.tileentity.TileEntityBookshelf;
|
||||||
@@ -22,6 +23,7 @@ import net.minecraft.init.Items;
|
|||||||
import net.minecraft.inventory.IInventory;
|
import net.minecraft.inventory.IInventory;
|
||||||
import net.minecraft.inventory.InventoryHelper;
|
import net.minecraft.inventory.InventoryHelper;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.util.*;
|
import net.minecraft.util.*;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
@@ -162,7 +164,37 @@ public class BlockBookshelf extends BlockHorizontal implements ITileEntityProvid
|
|||||||
|
|
||||||
TileEntity tileEntity = world.getTileEntity(pos);
|
TileEntity tileEntity = world.getTileEntity(pos);
|
||||||
|
|
||||||
if(tileEntity == null || player.isSneaking()){
|
if(tileEntity == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(player.isSneaking()){
|
||||||
|
ItemStack heldItem = player.getHeldItem(hand);
|
||||||
|
if(heldItem.isEmpty() && tileEntity instanceof TileEntityBookshelf){
|
||||||
|
if(!world.isRemote){
|
||||||
|
TileEntityBookshelf bookshelf = (TileEntityBookshelf)tileEntity;
|
||||||
|
for(int i = 0; i < bookshelf.getSizeInventory(); i++){
|
||||||
|
ItemStack stack = bookshelf.getStackInSlot(i);
|
||||||
|
if(!stack.isEmpty()){
|
||||||
|
player.addItemStackToInventory(stack.copy());
|
||||||
|
bookshelf.setInventorySlotContents(i, ItemStack.EMPTY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}else if(!heldItem.isEmpty() && ContainerBookshelf.isBook(heldItem) && tileEntity instanceof TileEntityBookshelf){
|
||||||
|
if(!world.isRemote){
|
||||||
|
TileEntityBookshelf bookshelf = (TileEntityBookshelf)tileEntity;
|
||||||
|
for(int i = 0; i < bookshelf.getSizeInventory(); i++){
|
||||||
|
if(bookshelf.getStackInSlot(i).isEmpty()){
|
||||||
|
bookshelf.setInventorySlotContents(i, heldItem.splitStack(1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,7 +293,6 @@ public class BlockBookshelf extends BlockHorizontal implements ITileEntityProvid
|
|||||||
registerBookModelTexture(() -> WizardryItems.scroll, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_blue"));
|
registerBookModelTexture(() -> WizardryItems.scroll, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_blue"));
|
||||||
registerBookModelTexture(() -> WizardryItems.blank_scroll, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_blue"));
|
registerBookModelTexture(() -> WizardryItems.blank_scroll, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_blue"));
|
||||||
registerBookModelTexture(() -> WizardryItems.identification_scroll, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_purple"));
|
registerBookModelTexture(() -> WizardryItems.identification_scroll, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_purple"));
|
||||||
registerBookModelTexture(() -> WizardryItems.armour_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_red"));
|
|
||||||
// Can't use the map in WandHelper because this is called from preInit (addons will have to add theirs manually)
|
// Can't use the map in WandHelper because this is called from preInit (addons will have to add theirs manually)
|
||||||
registerBookModelTexture(() -> WizardryItems.storage_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
|
registerBookModelTexture(() -> WizardryItems.storage_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
|
||||||
registerBookModelTexture(() -> WizardryItems.siphon_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
|
registerBookModelTexture(() -> WizardryItems.siphon_upgrade, new ResourceLocation(Wizardry.MODID, "blocks/scrolls_wooden"));
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public class BlockCrystalFlower extends BlockBush {
|
|||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onBonemealEvent(BonemealEvent event){
|
public static void onBonemealEvent(BonemealEvent event){
|
||||||
// Grows crystal flowers when bonemeal is used on grass
|
// Grows crystal flowers when bonemeal is used on grass
|
||||||
if(Wizardry.settings.bonemealGrowsCrystalFlowers && event.getBlock().getBlock() == Blocks.GRASS){
|
if(!event.getWorld().isRemote && Wizardry.settings.bonemealGrowsCrystalFlowers && event.getBlock().getBlock() == Blocks.GRASS){
|
||||||
|
|
||||||
BlockPos pos = event.getPos().add(event.getWorld().rand.nextInt(8) - event.getWorld().rand.nextInt(8),
|
BlockPos pos = event.getPos().add(event.getWorld().rand.nextInt(8) - event.getWorld().rand.nextInt(8),
|
||||||
event.getWorld().rand.nextInt(4) - event.getWorld().rand.nextInt(4),
|
event.getWorld().rand.nextInt(4) - event.getWorld().rand.nextInt(4),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package electroblob.wizardry.block;
|
package electroblob.wizardry.block;
|
||||||
|
|
||||||
|
import electroblob.wizardry.Wizardry;
|
||||||
import electroblob.wizardry.constants.Element;
|
import electroblob.wizardry.constants.Element;
|
||||||
import electroblob.wizardry.registry.WizardryTabs;
|
import electroblob.wizardry.registry.WizardryTabs;
|
||||||
import electroblob.wizardry.tileentity.TileEntityShrineCore;
|
import electroblob.wizardry.tileentity.TileEntityShrineCore;
|
||||||
@@ -81,11 +82,25 @@ public class BlockPedestal extends Block implements ITileEntityProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getBlockHardness(IBlockState state, World world, BlockPos pos){
|
public float getBlockHardness(IBlockState state, World world, BlockPos pos){
|
||||||
|
// If shrine regeneration is enabled, make pedestal blocks with shrine cores unbreakable to prevent exploitation
|
||||||
|
if(!world.isRemote && Wizardry.settings != null && Wizardry.settings.shrineRegenerationEnabled){
|
||||||
|
TileEntity tileEntity = world.getTileEntity(pos);
|
||||||
|
if(tileEntity instanceof TileEntityShrineCore){
|
||||||
|
return -1; // Unbreakable if it has a shrine core
|
||||||
|
}
|
||||||
|
}
|
||||||
return state.getValue(NATURAL) ? -1 : super.getBlockHardness(state, world, pos);
|
return state.getValue(NATURAL) ? -1 : super.getBlockHardness(state, world, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float getExplosionResistance(World world, BlockPos pos, @Nullable Entity exploder, Explosion explosion){
|
public float getExplosionResistance(World world, BlockPos pos, @Nullable Entity exploder, Explosion explosion){
|
||||||
|
// If shrine regeneration is enabled, make pedestal blocks with shrine cores unbreakable to prevent exploitation
|
||||||
|
if(!world.isRemote && Wizardry.settings != null && Wizardry.settings.shrineRegenerationEnabled){
|
||||||
|
TileEntity tileEntity = world.getTileEntity(pos);
|
||||||
|
if(tileEntity instanceof TileEntityShrineCore){
|
||||||
|
return 6000000.0F; // Unbreakable if it has a shrine core
|
||||||
|
}
|
||||||
|
}
|
||||||
return world.getBlockState(pos).getValue(NATURAL) ? 6000000.0F : super.getExplosionResistance(world, pos, exploder, explosion);
|
return world.getBlockState(pos).getValue(NATURAL) ? 6000000.0F : super.getExplosionResistance(world, pos, exploder, explosion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ public class BlockStatue extends Block implements ITileEntityProvider {
|
|||||||
// Making this an instance method means it works equally well for both types of statue
|
// Making this an instance method means it works equally well for both types of statue
|
||||||
public boolean convertToStatue(EntityLiving target, @Nullable EntityLivingBase caster, int duration){
|
public boolean convertToStatue(EntityLiving target, @Nullable EntityLivingBase caster, int duration){
|
||||||
|
|
||||||
if(target.deathTime > 0) return false;
|
if(target.deathTime > 0 || target.world.isRemote) return false;
|
||||||
|
|
||||||
BlockPos pos = new BlockPos(target);
|
BlockPos pos = new BlockPos(target);
|
||||||
World world = target.world;
|
World world = target.world;
|
||||||
|
|||||||
@@ -14,9 +14,14 @@ import electroblob.wizardry.client.gui.GuiSpellDisplay;
|
|||||||
import electroblob.wizardry.client.gui.config.NamedBooleanEntry;
|
import electroblob.wizardry.client.gui.config.NamedBooleanEntry;
|
||||||
import electroblob.wizardry.client.gui.config.SpellHUDSkinChooserEntry;
|
import electroblob.wizardry.client.gui.config.SpellHUDSkinChooserEntry;
|
||||||
import electroblob.wizardry.client.gui.handbook.GuiWizardHandbook;
|
import electroblob.wizardry.client.gui.handbook.GuiWizardHandbook;
|
||||||
|
import electroblob.wizardry.client.model.ModelRobeArmour;
|
||||||
|
import electroblob.wizardry.client.model.ModelSageArmour;
|
||||||
import electroblob.wizardry.client.model.ModelWizardArmour;
|
import electroblob.wizardry.client.model.ModelWizardArmour;
|
||||||
import electroblob.wizardry.client.particle.*;
|
import electroblob.wizardry.client.particle.*;
|
||||||
|
import electroblob.wizardry.constants.Element;
|
||||||
|
import electroblob.wizardry.registry.WizardryItems;
|
||||||
import electroblob.wizardry.client.particle.ParticleWizardry.IWizardryParticleFactory;
|
import electroblob.wizardry.client.particle.ParticleWizardry.IWizardryParticleFactory;
|
||||||
|
import electroblob.wizardry.client.renderer.RenderSpectralGolem;
|
||||||
import electroblob.wizardry.client.renderer.entity.*;
|
import electroblob.wizardry.client.renderer.entity.*;
|
||||||
import electroblob.wizardry.client.renderer.entity.layers.*;
|
import electroblob.wizardry.client.renderer.entity.layers.*;
|
||||||
import electroblob.wizardry.client.renderer.overlay.RenderBlinkEffect;
|
import electroblob.wizardry.client.renderer.overlay.RenderBlinkEffect;
|
||||||
@@ -34,11 +39,13 @@ import electroblob.wizardry.entity.projectile.*;
|
|||||||
import electroblob.wizardry.event.SpellCastEvent;
|
import electroblob.wizardry.event.SpellCastEvent;
|
||||||
import electroblob.wizardry.event.SpellCastEvent.Source;
|
import electroblob.wizardry.event.SpellCastEvent.Source;
|
||||||
import electroblob.wizardry.integration.antiqueatlas.WizardryAntiqueAtlasIntegration;
|
import electroblob.wizardry.integration.antiqueatlas.WizardryAntiqueAtlasIntegration;
|
||||||
|
import electroblob.wizardry.item.ItemArtefact;
|
||||||
import electroblob.wizardry.item.ItemScroll;
|
import electroblob.wizardry.item.ItemScroll;
|
||||||
import electroblob.wizardry.item.ItemSpellBook;
|
import electroblob.wizardry.item.ItemSpellBook;
|
||||||
import electroblob.wizardry.item.ItemWand;
|
import electroblob.wizardry.item.ItemWand;
|
||||||
import electroblob.wizardry.packet.*;
|
import electroblob.wizardry.packet.*;
|
||||||
import electroblob.wizardry.registry.Spells;
|
import electroblob.wizardry.registry.Spells;
|
||||||
|
import electroblob.wizardry.registry.WizardryItems.Materials;
|
||||||
import electroblob.wizardry.registry.WizardrySounds;
|
import electroblob.wizardry.registry.WizardrySounds;
|
||||||
import electroblob.wizardry.spell.*;
|
import electroblob.wizardry.spell.*;
|
||||||
import electroblob.wizardry.tileentity.*;
|
import electroblob.wizardry.tileentity.*;
|
||||||
@@ -65,6 +72,7 @@ import net.minecraft.entity.monster.EntityBlaze;
|
|||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.inventory.ContainerMerchant;
|
import net.minecraft.inventory.ContainerMerchant;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemArmor.ArmorMaterial;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.tileentity.TileEntity;
|
import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.tileentity.TileEntityDispenser;
|
import net.minecraft.tileentity.TileEntityDispenser;
|
||||||
@@ -120,8 +128,16 @@ public class ClientProxy extends CommonProxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Armour Model
|
// Armour Models
|
||||||
public static final ModelBiped WIZARD_ARMOUR_MODEL = new ModelWizardArmour(0.75f);
|
// Can't use an EnumMap here because our additional values aren't really part of the enum
|
||||||
|
public static final Map<ArmorMaterial, ModelBiped> wizard_armour_models = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
wizard_armour_models.put(Materials.SILK, new ModelWizardArmour(0.75f));
|
||||||
|
wizard_armour_models.put(Materials.SAGE, new ModelSageArmour(0.75f));
|
||||||
|
wizard_armour_models.put(Materials.BATTLEMAGE, new ModelRobeArmour(0.75f, true));
|
||||||
|
wizard_armour_models.put(Materials.WARLOCK, new ModelRobeArmour(0.75f, false));
|
||||||
|
}
|
||||||
|
|
||||||
/** The wrap width for standard multi-line descriptions (see {@link ClientProxy#addMultiLineDescription(List, String, Style, Object...)}). */
|
/** The wrap width for standard multi-line descriptions (see {@link ClientProxy#addMultiLineDescription(List, String, Style, Object...)}). */
|
||||||
private static final int TOOLTIP_WRAP_WIDTH = 140;
|
private static final int TOOLTIP_WRAP_WIDTH = 140;
|
||||||
@@ -130,8 +146,8 @@ public class ClientProxy extends CommonProxy {
|
|||||||
// ===============================================================================================================
|
// ===============================================================================================================
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModelBiped getWizardArmourModel(){
|
public ModelBiped getWizardArmourModel(ArmorMaterial material){
|
||||||
return WIZARD_ARMOUR_MODEL;
|
return wizard_armour_models.get(material);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -152,7 +168,8 @@ public class ClientProxy extends CommonProxy {
|
|||||||
IResourceManager manager = Minecraft.getMinecraft().getResourceManager();
|
IResourceManager manager = Minecraft.getMinecraft().getResourceManager();
|
||||||
if(manager instanceof IReloadableResourceManager){
|
if(manager instanceof IReloadableResourceManager){
|
||||||
((IReloadableResourceManager)manager).registerReloadListener(GuiSpellDisplay::loadSkins);
|
((IReloadableResourceManager)manager).registerReloadListener(GuiSpellDisplay::loadSkins);
|
||||||
((IReloadableResourceManager)manager).registerReloadListener(GuiWizardHandbook::loadHandbookFile);
|
if (Wizardry.settings.loadHandbook)
|
||||||
|
((IReloadableResourceManager)manager).registerReloadListener(GuiWizardHandbook::loadHandbookFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -700,6 +717,65 @@ public class ClientProxy extends CommonProxy {
|
|||||||
}else Wizardry.logger.warn("Received a PacketConquerShrine, but there was no shrine core at the position sent");
|
}else Wizardry.logger.warn("Received a PacketConquerShrine, but there was no shrine core at the position sent");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleBombExplosionPacket(PacketBombExplosion.Message message){
|
||||||
|
|
||||||
|
net.minecraft.world.World world = Minecraft.getMinecraft().world;
|
||||||
|
double x = message.x, y = message.y, z = message.z;
|
||||||
|
float blastMultiplier = message.blastMultiplier;
|
||||||
|
|
||||||
|
switch(message.bombType){
|
||||||
|
|
||||||
|
case PacketBombExplosion.FIREBOMB:
|
||||||
|
ParticleBuilder.create(Type.FLASH).pos(x, y, z).scale(5 * blastMultiplier).clr(1, 0.6f, 0).spawn(world);
|
||||||
|
for(int i = 0; i < 60 * blastMultiplier; i++){
|
||||||
|
ParticleBuilder.create(Type.MAGIC_FIRE, world.rand, x, y, z, 2 * blastMultiplier, false)
|
||||||
|
.time(10 + world.rand.nextInt(4)).scale(2 + world.rand.nextFloat()).spawn(world);
|
||||||
|
ParticleBuilder.create(Type.DARK_MAGIC, world.rand, x, y, z, 2 * blastMultiplier, false)
|
||||||
|
.clr(1.0f, 0.2f + world.rand.nextFloat() * 0.4f, 0.0f).spawn(world);
|
||||||
|
}
|
||||||
|
world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, x, y, z, 0, 0, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PacketBombExplosion.POISON_BOMB:
|
||||||
|
ParticleBuilder.create(Type.FLASH).pos(x, y, z).scale(5 * blastMultiplier)
|
||||||
|
.clr(0.2f + world.rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world);
|
||||||
|
for(int i = 0; i < 60 * blastMultiplier; i++){
|
||||||
|
ParticleBuilder.create(Type.SPARKLE, world.rand, x, y, z, 2 * blastMultiplier, false).time(35)
|
||||||
|
.scale(2).clr(0.2f + world.rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world);
|
||||||
|
ParticleBuilder.create(Type.DARK_MAGIC, world.rand, x, y, z, 2 * blastMultiplier, false)
|
||||||
|
.clr(0.2f + world.rand.nextFloat() * 0.2f, 0.8f, 0.0f).spawn(world);
|
||||||
|
}
|
||||||
|
world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, x, y, z, 0, 0, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PacketBombExplosion.SMOKE_BOMB:
|
||||||
|
ParticleBuilder.create(Type.FLASH).pos(x, y, z).scale(5 * blastMultiplier).clr(0, 0, 0).spawn(world);
|
||||||
|
world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, x, y, z, 0, 0, 0);
|
||||||
|
for(int i = 0; i < 60 * blastMultiplier; i++){
|
||||||
|
float brightness = world.rand.nextFloat() * 0.1f + 0.1f;
|
||||||
|
ParticleBuilder.create(Type.CLOUD, world.rand, x, y, z, 2 * blastMultiplier, false)
|
||||||
|
.clr(brightness, brightness, brightness).time(80 + world.rand.nextInt(12)).shaded(true).spawn(world);
|
||||||
|
brightness = world.rand.nextFloat() * 0.3f;
|
||||||
|
ParticleBuilder.create(Type.DARK_MAGIC, world.rand, x, y, z, 2 * blastMultiplier, false)
|
||||||
|
.clr(brightness, brightness, brightness).spawn(world);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PacketBombExplosion.SPARK_BOMB:
|
||||||
|
ParticleBuilder.spawnShockParticles(world, x, y, z);
|
||||||
|
for(int id : message.secondaryTargetIDs){
|
||||||
|
net.minecraft.entity.Entity target = world.getEntityByID(id);
|
||||||
|
if(target instanceof net.minecraft.entity.EntityLivingBase){
|
||||||
|
ParticleBuilder.create(Type.LIGHTNING).pos(x, y, z).target(target).spawn(world);
|
||||||
|
ParticleBuilder.spawnShockParticles(world, target.posX,
|
||||||
|
target.posY + target.height / 2, target.posZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Rendering
|
// Rendering
|
||||||
// ===============================================================================================================
|
// ===============================================================================================================
|
||||||
|
|
||||||
@@ -716,6 +792,9 @@ public class ClientProxy extends CommonProxy {
|
|||||||
LayerTiledOverlay.initialiseLayers(LayerMindControl::new);
|
LayerTiledOverlay.initialiseLayers(LayerMindControl::new);
|
||||||
LayerTiledOverlay.initialiseLayers(LayerSummonAnimation::new);
|
LayerTiledOverlay.initialiseLayers(LayerSummonAnimation::new);
|
||||||
LayerTiledOverlay.initialiseLayers(LayerDisintegrateAnimation::new);
|
LayerTiledOverlay.initialiseLayers(LayerDisintegrateAnimation::new);
|
||||||
|
LayerTiledOverlay.initialiseLayers(LayerOak::new);
|
||||||
|
LayerTiledOverlay.initialiseLayers(LayerIron::new);
|
||||||
|
LayerTiledOverlay.initialiseLayers(LayerDiamond::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -754,6 +833,7 @@ public class ClientProxy extends CommonProxy {
|
|||||||
|
|
||||||
RenderingRegistry.registerEntityRenderingHandler(EntityIceGiant.class, RenderIceGiant::new);
|
RenderingRegistry.registerEntityRenderingHandler(EntityIceGiant.class, RenderIceGiant::new);
|
||||||
RenderingRegistry.registerEntityRenderingHandler(EntityPhoenix.class, RenderPhoenix::new);
|
RenderingRegistry.registerEntityRenderingHandler(EntityPhoenix.class, RenderPhoenix::new);
|
||||||
|
RenderingRegistry.registerEntityRenderingHandler(EntitySpectralGolem.class, RenderSpectralGolem::new);
|
||||||
|
|
||||||
// Projectiles
|
// Projectiles
|
||||||
RenderingRegistry.registerEntityRenderingHandler(EntityMagicMissile.class, manager -> new RenderMagicArrow(manager,
|
RenderingRegistry.registerEntityRenderingHandler(EntityMagicMissile.class, manager -> new RenderMagicArrow(manager,
|
||||||
@@ -768,6 +848,7 @@ public class ClientProxy extends CommonProxy {
|
|||||||
new ResourceLocation(Wizardry.MODID, "textures/entity/ice_lance.png"), false, 16.0, 3.0, 22, 5, false));
|
new ResourceLocation(Wizardry.MODID, "textures/entity/ice_lance.png"), false, 16.0, 3.0, 22, 5, false));
|
||||||
RenderingRegistry.registerEntityRenderingHandler(EntityFlamecatcherArrow.class, manager -> new RenderMagicArrow(manager,
|
RenderingRegistry.registerEntityRenderingHandler(EntityFlamecatcherArrow.class, manager -> new RenderMagicArrow(manager,
|
||||||
new ResourceLocation(Wizardry.MODID, "textures/entity/flamecatcher_arrow.png"), false, 8, 2.0, 16, 5, true));
|
new ResourceLocation(Wizardry.MODID, "textures/entity/flamecatcher_arrow.png"), false, 8, 2.0, 16, 5, true));
|
||||||
|
RenderingRegistry.registerEntityRenderingHandler(EntityConjuredArrow.class, RenderConjuredArrow::new);
|
||||||
|
|
||||||
RenderingRegistry.registerEntityRenderingHandler(EntityForceArrow.class, RenderForceArrow::new);
|
RenderingRegistry.registerEntityRenderingHandler(EntityForceArrow.class, RenderForceArrow::new);
|
||||||
|
|
||||||
@@ -857,4 +938,51 @@ public class ClientProxy extends CommonProxy {
|
|||||||
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityImbuementAltar.class, new RenderImbuementAltar());
|
ClientRegistry.bindTileEntitySpecialRenderer(TileEntityImbuementAltar.class, new RenderImbuementAltar());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void registerItemColorHandlers() {
|
||||||
|
// Spell book overlay textures are now per-element, so no runtime tinting is needed.
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerModelProperties() {
|
||||||
|
Item spellBook = WizardryItems.spell_book;
|
||||||
|
|
||||||
|
spellBook.addPropertyOverride(new ResourceLocation(Wizardry.MODID, "discovered"), (stack, world, entity) -> {
|
||||||
|
if (!Wizardry.settings.spellBookColors) return 0.0f;
|
||||||
|
|
||||||
|
boolean discovered = shouldDisplayDiscovered(Spell.byMetadata(stack.getMetadata()), stack);
|
||||||
|
|
||||||
|
if(discovered && Wizardry.settings.spellBookColorsRequireArchivistsEyeglass){
|
||||||
|
// Entity can be null so we have to check
|
||||||
|
if(entity instanceof EntityPlayer){
|
||||||
|
return ItemArtefact.isArtefactActive((EntityPlayer)entity, WizardryItems.charm_spell_discovery) ? 1.0f : 0.0f;
|
||||||
|
}
|
||||||
|
// If there's no entity, there's no charm, so no colour
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return discovered ? 1.0f : 0.0f;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Returns ordinal+1 for each element (1=MAGIC through 8=HEALING), or 0 if not yet discovered.
|
||||||
|
// Drives per-element bookmark texture selection via model overrides in spell_book.json.
|
||||||
|
spellBook.addPropertyOverride(new ResourceLocation(Wizardry.MODID, "element"), (stack, world, entity) -> {
|
||||||
|
if (!Wizardry.settings.spellBookColors) return 0.0f;
|
||||||
|
|
||||||
|
Spell spell = Spell.byMetadata(stack.getMetadata());
|
||||||
|
boolean discovered = shouldDisplayDiscovered(spell, stack);
|
||||||
|
|
||||||
|
if(!discovered) return 0.0f;
|
||||||
|
|
||||||
|
if(Wizardry.settings.spellBookColorsRequireArchivistsEyeglass){
|
||||||
|
if(entity instanceof EntityPlayer){
|
||||||
|
if(!ItemArtefact.isArtefactActive((EntityPlayer)entity, WizardryItems.charm_spell_discovery)) return 0.0f;
|
||||||
|
} else {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Element element = spell.getElement();
|
||||||
|
return element == null ? 0.0f : (float)(element.ordinal() + 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
package electroblob.wizardry.client;
|
package electroblob.wizardry.client;
|
||||||
|
|
||||||
|
import electroblob.wizardry.Wizardry;
|
||||||
import electroblob.wizardry.client.renderer.overlay.RenderBlinkEffect;
|
import electroblob.wizardry.client.renderer.overlay.RenderBlinkEffect;
|
||||||
import electroblob.wizardry.data.DispenserCastingData;
|
import electroblob.wizardry.data.DispenserCastingData;
|
||||||
import electroblob.wizardry.data.SpellEmitterData;
|
import electroblob.wizardry.data.SpellEmitterData;
|
||||||
import electroblob.wizardry.item.ItemArtefact;
|
import electroblob.wizardry.data.WizardData;
|
||||||
import electroblob.wizardry.item.ItemFlamecatcher;
|
import electroblob.wizardry.item.*;
|
||||||
import electroblob.wizardry.item.ItemSpectralBow;
|
|
||||||
import electroblob.wizardry.item.ItemWand;
|
|
||||||
import electroblob.wizardry.potion.PotionSlowTime;
|
import electroblob.wizardry.potion.PotionSlowTime;
|
||||||
import electroblob.wizardry.registry.WizardryItems;
|
import electroblob.wizardry.registry.WizardryItems;
|
||||||
import electroblob.wizardry.registry.WizardryPotions;
|
import electroblob.wizardry.registry.WizardryPotions;
|
||||||
@@ -16,6 +15,7 @@ import electroblob.wizardry.spell.SlowTime;
|
|||||||
import electroblob.wizardry.spell.Transience;
|
import electroblob.wizardry.spell.Transience;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.ScaledResolution;
|
import net.minecraft.client.gui.ScaledResolution;
|
||||||
|
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||||
import net.minecraft.client.renderer.BufferBuilder;
|
import net.minecraft.client.renderer.BufferBuilder;
|
||||||
import net.minecraft.client.renderer.GlStateManager;
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
import net.minecraft.client.renderer.Tessellator;
|
import net.minecraft.client.renderer.Tessellator;
|
||||||
@@ -26,14 +26,14 @@ import net.minecraft.tileentity.TileEntity;
|
|||||||
import net.minecraft.tileentity.TileEntityDispenser;
|
import net.minecraft.tileentity.TileEntityDispenser;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.client.event.FOVUpdateEvent;
|
import net.minecraftforge.client.event.*;
|
||||||
import net.minecraftforge.client.event.InputUpdateEvent;
|
|
||||||
import net.minecraftforge.client.event.MouseEvent;
|
|
||||||
import net.minecraftforge.client.event.RenderHandEvent;
|
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
|
import net.minecraft.client.resources.I18n;
|
||||||
|
import net.minecraft.util.text.TextFormatting;
|
||||||
|
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
|
||||||
import org.lwjgl.opengl.GL11;
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -120,6 +120,7 @@ public final class WizardryClientEventHandler {
|
|||||||
Minecraft.getMinecraft().player.prevRotationPitch = 0;
|
Minecraft.getMinecraft().player.prevRotationPitch = 0;
|
||||||
Minecraft.getMinecraft().player.rotationYaw = 0;
|
Minecraft.getMinecraft().player.rotationYaw = 0;
|
||||||
Minecraft.getMinecraft().player.rotationPitch = 0;
|
Minecraft.getMinecraft().player.rotationPitch = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,10 +134,10 @@ public final class WizardryClientEventHandler {
|
|||||||
event.getMovementInput().jump = false;
|
event.getMovementInput().jump = false;
|
||||||
event.getMovementInput().sneak = false;
|
event.getMovementInput().sneak = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ItemArtefact.isArtefactActive(event.getEntityPlayer(), WizardryItems.charm_move_speed)
|
if(ItemArtefact.isArtefactActive(event.getEntityPlayer(), WizardryItems.charm_move_speed)
|
||||||
&& event.getEntityPlayer().isHandActive()
|
&& event.getEntityPlayer().isHandActive()
|
||||||
&& event.getEntityPlayer().getActiveItemStack().getItem() instanceof ItemWand){
|
&& event.getEntityPlayer().getActiveItemStack().getItem() instanceof ISpellCastingItem){
|
||||||
// Normally speed is set to 20% when using items, this makes it 80%
|
// Normally speed is set to 20% when using items, this makes it 80%
|
||||||
event.getMovementInput().moveStrafe *= 4;
|
event.getMovementInput().moveStrafe *= 4;
|
||||||
event.getMovementInput().moveForward *= 4;
|
event.getMovementInput().moveForward *= 4;
|
||||||
@@ -187,6 +188,26 @@ public final class WizardryClientEventHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void onGuiOpenEvent(GuiOpenEvent event){
|
||||||
|
|
||||||
|
if(Minecraft.getMinecraft().player != null && event.getGui() instanceof GuiContainer) {
|
||||||
|
WizardData data = WizardData.get(Minecraft.getMinecraft().player);
|
||||||
|
if (data != null && data.getVariable(Possession.POSSESSEE_KEY) != null) {
|
||||||
|
event.setCanceled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public static void onItemTooltip(ItemTooltipEvent event) {
|
||||||
|
if (event.getItemStack().getItem() == WizardryItems.charm_spell_discovery) {
|
||||||
|
if (Wizardry.settings.spellBookColorsRequireArchivistsEyeglass) {
|
||||||
|
event.getToolTip().add(TextFormatting.GRAY + I18n.format("item.ebwizardry:charm_spell_discovery.desc.color"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders an overlay across the entire screen.
|
* Renders an overlay across the entire screen.
|
||||||
* @param resolution The screen resolution
|
* @param resolution The screen resolution
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
|||||||
private ContainerArcaneWorkbench arcaneWorkbenchContainer;
|
private ContainerArcaneWorkbench arcaneWorkbenchContainer;
|
||||||
|
|
||||||
private GuiButton applyBtn;
|
private GuiButton applyBtn;
|
||||||
|
private GuiButton clearBtn;
|
||||||
private GuiButton[] sortButtons = new GuiButton[3];
|
private GuiButton[] sortButtons = new GuiButton[3];
|
||||||
|
|
||||||
private GuiTextField searchField;
|
private GuiTextField searchField;
|
||||||
@@ -126,6 +127,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
|||||||
|
|
||||||
this.buttonList.clear();
|
this.buttonList.clear();
|
||||||
this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width / 2 + 64, this.height / 2 + 3));
|
this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width / 2 + 64, this.height / 2 + 3));
|
||||||
|
this.buttonList.add(this.clearBtn = new GuiButtonClear(0, this.width / 2 + 64, this.height / 2 - 16));
|
||||||
this.buttonList.add(sortButtons[0] = new GuiButtonSpellSort(1, this.guiLeft - 44, this.guiTop + 8, ISpellSortable.SortType.TIER, arcaneWorkbenchContainer, this));
|
this.buttonList.add(sortButtons[0] = new GuiButtonSpellSort(1, this.guiLeft - 44, this.guiTop + 8, ISpellSortable.SortType.TIER, arcaneWorkbenchContainer, this));
|
||||||
this.buttonList.add(sortButtons[1] = new GuiButtonSpellSort(2, this.guiLeft - 31, this.guiTop + 8, ISpellSortable.SortType.ELEMENT, arcaneWorkbenchContainer, this));
|
this.buttonList.add(sortButtons[1] = new GuiButtonSpellSort(2, this.guiLeft - 31, this.guiTop + 8, ISpellSortable.SortType.ELEMENT, arcaneWorkbenchContainer, this));
|
||||||
this.buttonList.add(sortButtons[2] = new GuiButtonSpellSort(3, this.guiLeft - 18, this.guiTop + 8, ISpellSortable.SortType.ALPHABETICAL, arcaneWorkbenchContainer, this));
|
this.buttonList.add(sortButtons[2] = new GuiButtonSpellSort(3, this.guiLeft - 18, this.guiTop + 8, ISpellSortable.SortType.ALPHABETICAL, arcaneWorkbenchContainer, this));
|
||||||
@@ -135,8 +137,8 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
|||||||
this.searchField.setEnableBackgroundDrawing(false);
|
this.searchField.setEnableBackgroundDrawing(false);
|
||||||
this.searchField.setVisible(true);
|
this.searchField.setVisible(true);
|
||||||
this.searchField.setTextColor(16777215);
|
this.searchField.setTextColor(16777215);
|
||||||
this.searchField.setCanLoseFocus(false);
|
this.searchField.setCanLoseFocus(Wizardry.settings.unfocusedSearchBars); // false by default
|
||||||
this.searchField.setFocused(true);
|
this.searchField.setFocused(!Wizardry.settings.unfocusedSearchBars); // true by default
|
||||||
|
|
||||||
this.tooltipElements.clear();
|
this.tooltipElements.clear();
|
||||||
this.tooltipElements.add(new TooltipElementItemName(new Style().setColor(TextFormatting.WHITE), LINE_SPACING_WIDE));
|
this.tooltipElements.add(new TooltipElementItemName(new Style().setColor(TextFormatting.WHITE), LINE_SPACING_WIDE));
|
||||||
@@ -205,6 +207,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
|||||||
|
|
||||||
// Show/hide the relevant gui elements
|
// Show/hide the relevant gui elements
|
||||||
this.applyBtn.enabled = centreSlot.getHasStack();
|
this.applyBtn.enabled = centreSlot.getHasStack();
|
||||||
|
this.clearBtn.enabled = centreSlot.getHasStack() && centreSlot.getStack().getItem() instanceof IWorkbenchItem && ((IWorkbenchItem) centreSlot.getStack().getItem()).isClearable();
|
||||||
for(GuiButton button : this.sortButtons) button.visible = arcaneWorkbenchContainer.hasBookshelves();
|
for(GuiButton button : this.sortButtons) button.visible = arcaneWorkbenchContainer.hasBookshelves();
|
||||||
this.searchField.setVisible(arcaneWorkbenchContainer.hasBookshelves());
|
this.searchField.setVisible(arcaneWorkbenchContainer.hasBookshelves());
|
||||||
|
|
||||||
@@ -428,6 +431,16 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
|||||||
|
|
||||||
// Controls
|
// Controls
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
|
||||||
|
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||||
|
if (this.searchField != null) {
|
||||||
|
this.searchField.mouseClicked(mouseX, mouseY, mouseButton);
|
||||||
|
// Set focus depending on whether the click was inside the search field
|
||||||
|
this.searchField.setFocused(this.searchField.isFocused());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void actionPerformed(GuiButton button){
|
protected void actionPerformed(GuiButton button){
|
||||||
|
|
||||||
@@ -444,6 +457,17 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
|||||||
animationTimer = 20;
|
animationTimer = 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(button == clearBtn){
|
||||||
|
// Packet building
|
||||||
|
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.CLEAR_BUTTON);
|
||||||
|
WizardryPacketHandler.net.sendToServer(msg);
|
||||||
|
// Sound
|
||||||
|
Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(
|
||||||
|
WizardrySounds.BLOCK_ARCANE_WORKBENCH_SPELLBIND, 0.8f));
|
||||||
|
// Animation
|
||||||
|
animationTimer = 20;
|
||||||
|
}
|
||||||
|
|
||||||
if(button instanceof GuiButtonSpellSort) this.arcaneWorkbenchContainer.setSortType(((GuiButtonSpellSort)button).sortType);
|
if(button instanceof GuiButtonSpellSort) this.arcaneWorkbenchContainer.setSortType(((GuiButtonSpellSort)button).sortType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -491,12 +515,13 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
|||||||
@Override
|
@Override
|
||||||
protected void keyTyped(char typedChar, int keyCode) throws IOException {
|
protected void keyTyped(char typedChar, int keyCode) throws IOException {
|
||||||
|
|
||||||
if(this.searchNeedsClearing){
|
if(this.searchNeedsClearing){
|
||||||
this.searchNeedsClearing = false;
|
this.searchNeedsClearing = false;
|
||||||
this.searchField.setText("");
|
this.searchField.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.searchField.textboxKeyTyped(typedChar, keyCode)){
|
// Allow exiting the GUI by pressing the inventory button. Does not work if bookshelves are present by default
|
||||||
|
if(this.searchField.getVisible() && this.searchField.textboxKeyTyped(typedChar, keyCode)){
|
||||||
arcaneWorkbenchContainer.setSearchText(searchField.getText().toLowerCase(Locale.ROOT));
|
arcaneWorkbenchContainer.setSearchText(searchField.getText().toLowerCase(Locale.ROOT));
|
||||||
}else{
|
}else{
|
||||||
super.keyTyped(typedChar, keyCode);
|
super.keyTyped(typedChar, keyCode);
|
||||||
@@ -1006,4 +1031,36 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
private static class GuiButtonClear extends GuiButton {
|
||||||
|
|
||||||
|
public GuiButtonClear(int id, int x, int y){
|
||||||
|
super(id, x, y, 16, 16, I18n.format("container." + Wizardry.MODID + ":arcane_workbench.clear"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawButton(Minecraft minecraft, int mouseX, int mouseY, float partialTicks){
|
||||||
|
|
||||||
|
// Whether the button is highlighted
|
||||||
|
this.hovered = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width && mouseY < this.y + this.height;
|
||||||
|
|
||||||
|
int k = 72;
|
||||||
|
int l = 236;
|
||||||
|
//int colour = 14737632;
|
||||||
|
|
||||||
|
if(this.enabled){
|
||||||
|
if(this.hovered){
|
||||||
|
k += this.width * 2;
|
||||||
|
//colour = 16777120;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
k += this.width;
|
||||||
|
//colour = 10526880;
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawingUtils.drawTexturedRect(this.x, this.y, k, l, this.width, this.height, TEXTURE_WIDTH, TEXTURE_HEIGHT);
|
||||||
|
//this.drawCenteredString(minecraft.fontRenderer, this.displayString, this.x + this.width / 2,
|
||||||
|
// this.y + (this.height - 8) / 2, colour);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -184,9 +184,8 @@ public class GuiLectern extends GuiSpellInfo implements ISpellSortable {
|
|||||||
this.searchField.setEnableBackgroundDrawing(false);
|
this.searchField.setEnableBackgroundDrawing(false);
|
||||||
this.searchField.setVisible(true);
|
this.searchField.setVisible(true);
|
||||||
this.searchField.setTextColor(16777215);
|
this.searchField.setTextColor(16777215);
|
||||||
this.searchField.setCanLoseFocus(false);
|
this.searchField.setCanLoseFocus(Wizardry.settings.unfocusedSearchBars); // false by default
|
||||||
this.searchField.setFocused(true);
|
this.searchField.setFocused(!Wizardry.settings.unfocusedSearchBars); // true by default
|
||||||
|
|
||||||
refreshAvailableSpells(); // Must be done last
|
refreshAvailableSpells(); // Must be done last
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -269,8 +268,13 @@ public class GuiLectern extends GuiSpellInfo implements ISpellSortable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
|
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
|
||||||
super.mouseClicked(mouseX, mouseY, mouseButton);
|
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||||
searchNeedsClearing = true;
|
if (this.searchField != null) {
|
||||||
|
this.searchField.mouseClicked(mouseX, mouseY, mouseButton);
|
||||||
|
// Set focus depending on whether the click was inside the search field
|
||||||
|
this.searchField.setFocused(this.searchField.isFocused());
|
||||||
|
}
|
||||||
|
searchNeedsClearing = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package electroblob.wizardry.client.gui.config;
|
package electroblob.wizardry.client.gui.config;
|
||||||
|
|
||||||
|
import com.mojang.realmsclient.gui.ChatFormatting;
|
||||||
import electroblob.wizardry.Settings;
|
import electroblob.wizardry.Settings;
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
import net.minecraft.client.gui.GuiScreen;
|
import net.minecraft.client.gui.GuiScreen;
|
||||||
@@ -18,9 +19,13 @@ import java.util.List;
|
|||||||
public class GuiConfigWizardry extends GuiConfig {
|
public class GuiConfigWizardry extends GuiConfig {
|
||||||
|
|
||||||
public GuiConfigWizardry(GuiScreen parent){
|
public GuiConfigWizardry(GuiScreen parent){
|
||||||
|
|
||||||
super(parent, getConfigEntries(), Wizardry.MODID, false, false,
|
super(parent, getConfigEntries(), Wizardry.MODID, false, false,
|
||||||
Wizardry.NAME + " - " + I18n.format("config." + Wizardry.MODID + ".title.general"));
|
Wizardry.NAME + " - " + I18n.format("config." + Wizardry.MODID + ".title.general"));
|
||||||
// this.titleLine2 = "File location: " + Wizardry.config.getConfigFile().getAbsolutePath();
|
|
||||||
|
if(Wizardry.settings.hasRedundantKeys()){
|
||||||
|
this.titleLine2 = ChatFormatting.GOLD.toString() + I18n.format("config." + Wizardry.MODID + ".redundant_keys");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<IConfigElement> getConfigEntries(){
|
private static List<IConfigElement> getConfigEntries(){
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ class Contents {
|
|||||||
int x = GuiWizardHandbook.isRightPage(startPage) ? left + GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : left + GuiWizardHandbook.TEXT_INSET_X;
|
int x = GuiWizardHandbook.isRightPage(startPage) ? left + GuiWizardHandbook.GUI_WIDTH - GuiWizardHandbook.TEXT_INSET_X - GuiWizardHandbook.PAGE_WIDTH : left + GuiWizardHandbook.TEXT_INSET_X;
|
||||||
int y = top + GuiWizardHandbook.TEXT_INSET_Y + startLine * font.FONT_HEIGHT;
|
int y = top + GuiWizardHandbook.TEXT_INSET_Y + startLine * font.FONT_HEIGHT;
|
||||||
|
|
||||||
list.add(new GuiButtonHyperlink.Internal(0, x, y, font, entry.title, entry, 0, "", maxLineNumber-startLine, GuiWizardHandbook.isRightPage(startPage)));
|
list.add(new GuiButtonHyperlink.Internal(0, x, y, font, entry.title, entry, 0, "", maxLineNumber-startLine, GuiWizardHandbook.isRightPage(startPage), false));
|
||||||
|
|
||||||
startLine++;
|
startLine++;
|
||||||
|
|
||||||
|
|||||||
@@ -28,15 +28,17 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
|||||||
final List<String> lines;
|
final List<String> lines;
|
||||||
final int linesLeft;
|
final int linesLeft;
|
||||||
|
|
||||||
GuiButtonHyperlink(int id, int x, int y, FontRenderer font, String text, int indent, String suffix, int linesLeft, boolean rightPage){
|
GuiButtonHyperlink(int id, int x, int y, FontRenderer font, String text, int indent, String suffix, int linesLeft, boolean rightPage, boolean spaceless){
|
||||||
|
|
||||||
super(id, x, y, font.getStringWidth(text), font.FONT_HEIGHT, text);
|
super(id, x, y, font.getStringWidth(text), font.FONT_HEIGHT, text);
|
||||||
|
|
||||||
// Sometimes a link has punctuation or something after it that causes it to wrap onto a new line
|
// Sometimes a link has punctuation or something after it that causes it to wrap onto a new line
|
||||||
String linkWithSuffix = text + suffix;
|
String linkWithSuffix = text + suffix;
|
||||||
|
|
||||||
// If the string won't fit any words at the end of the current line, treat it as if we started a new line
|
// If the string won't fit any words (or characters in a spaceless language) at the end of the current line,
|
||||||
if(font.getStringWidth(linkWithSuffix.split("\\s")[0]) > GuiWizardHandbook.PAGE_WIDTH - indent){
|
// treat it as if we started a new line
|
||||||
|
String firstWord = spaceless ? linkWithSuffix.substring(0, 1) : linkWithSuffix.split("\\s")[0];
|
||||||
|
if(font.getStringWidth(firstWord) > GuiWizardHandbook.PAGE_WIDTH - indent){
|
||||||
indent = 0;
|
indent = 0;
|
||||||
this.y += font.FONT_HEIGHT;
|
this.y += font.FONT_HEIGHT;
|
||||||
}
|
}
|
||||||
@@ -149,7 +151,7 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
|||||||
* @throws IllegalArgumentException if the given argument array is empty or contains more than 2 arguments
|
* @throws IllegalArgumentException if the given argument array is empty or contains more than 2 arguments
|
||||||
* @throws JsonSyntaxException if the specified link target is not a URL or a valid section ID
|
* @throws JsonSyntaxException if the specified link target is not a URL or a valid section ID
|
||||||
*/
|
*/
|
||||||
public static GuiButtonHyperlink create(int x, int y, FontRenderer font, List<String> upToLink, String[] arguments, String suffix, int linesLeft, boolean rightPage){
|
public static GuiButtonHyperlink create(int x, int y, FontRenderer font, List<String> upToLink, String[] arguments, String suffix, int linesLeft, boolean rightPage, boolean spaceless){
|
||||||
|
|
||||||
if(arguments.length == 0 || arguments.length > 2) throw new IllegalArgumentException("Incorrect array length!");
|
if(arguments.length == 0 || arguments.length > 2) throw new IllegalArgumentException("Incorrect array length!");
|
||||||
|
|
||||||
@@ -158,7 +160,7 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
|||||||
if(arguments[0].matches(URL_REGEX)){
|
if(arguments[0].matches(URL_REGEX)){
|
||||||
|
|
||||||
button = new GuiButtonHyperlink.External(0, x, y, font, arguments[arguments.length - 1], arguments[0],
|
button = new GuiButtonHyperlink.External(0, x, y, font, arguments[arguments.length - 1], arguments[0],
|
||||||
font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix, linesLeft, rightPage);
|
font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix, linesLeft, rightPage, spaceless);
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
|
|
||||||
@@ -167,7 +169,7 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
|||||||
if(target == null) throw new JsonSyntaxException("Hyperlink points to nonexistent section id " + arguments[0]);
|
if(target == null) throw new JsonSyntaxException("Hyperlink points to nonexistent section id " + arguments[0]);
|
||||||
|
|
||||||
button = new GuiButtonHyperlink.Internal(0, x, y, font, arguments[arguments.length - 1],
|
button = new GuiButtonHyperlink.Internal(0, x, y, font, arguments[arguments.length - 1],
|
||||||
target, font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix, linesLeft, rightPage);
|
target, font.getStringWidth(upToLink.get(upToLink.size() - 1)), suffix, linesLeft, rightPage, spaceless);
|
||||||
}
|
}
|
||||||
|
|
||||||
return button;
|
return button;
|
||||||
@@ -177,8 +179,8 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
|||||||
|
|
||||||
final Section target;
|
final Section target;
|
||||||
|
|
||||||
Internal(int id, int x, int y, FontRenderer font, String text, Section target, int indent, String suffix, int linesLeft, boolean rightPage){
|
Internal(int id, int x, int y, FontRenderer font, String text, Section target, int indent, String suffix, int linesLeft, boolean rightPage, boolean spaceless){
|
||||||
super(id, x, y, font, text, indent, suffix, linesLeft, rightPage);
|
super(id, x, y, font, text, indent, suffix, linesLeft, rightPage, spaceless);
|
||||||
this.target = target;
|
this.target = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,8 +218,8 @@ public abstract class GuiButtonHyperlink extends GuiButton {
|
|||||||
|
|
||||||
final ITextComponent link;
|
final ITextComponent link;
|
||||||
|
|
||||||
External(int id, int x, int y, FontRenderer font, String text, String url, int indent, String suffix, int linesLeft, boolean rightPage){
|
External(int id, int x, int y, FontRenderer font, String text, String url, int indent, String suffix, int linesLeft, boolean rightPage, boolean spaceless){
|
||||||
super(id, x, y, font, text, indent, suffix, linesLeft, rightPage);
|
super(id, x, y, font, text, indent, suffix, linesLeft, rightPage, spaceless);
|
||||||
this.link = new TextComponentString(text);
|
this.link = new TextComponentString(text);
|
||||||
link.getStyle().setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)).setColor(TextFormatting.DARK_BLUE);
|
link.getStyle().setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, url)).setColor(TextFormatting.DARK_BLUE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,9 +33,13 @@ import java.awt.*;
|
|||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.util.List;
|
|
||||||
import java.util.*;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GUI class for the wizard's handbook. Like any GUI class, this is instantiated each time the book is opened. As of
|
* GUI class for the wizard's handbook. Like any GUI class, this is instantiated each time the book is opened. As of
|
||||||
@@ -55,6 +59,8 @@ public class GuiWizardHandbook extends GuiScreen {
|
|||||||
|
|
||||||
private static final ResourceLocation DEFAULT = new ResourceLocation(Wizardry.MODID, "texts/handbook_en_us.json");
|
private static final ResourceLocation DEFAULT = new ResourceLocation(Wizardry.MODID, "texts/handbook_en_us.json");
|
||||||
|
|
||||||
|
private static List<String> ADDONS = new ArrayList<>();
|
||||||
|
|
||||||
static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook/handbook.png");
|
static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook/handbook.png");
|
||||||
|
|
||||||
/** Global Gson instance for the handbook. */
|
/** Global Gson instance for the handbook. */
|
||||||
@@ -406,9 +412,10 @@ public class GuiWizardHandbook extends GuiScreen {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IResource handbookFile = getHandbookResource(manager);
|
// IResource handbookFile = getHandbookResource(manager);
|
||||||
|
List<IResource> handbookFiles = getHandbookResource(manager);
|
||||||
|
|
||||||
if(handbookFile != null){
|
if(!handbookFiles.isEmpty()){
|
||||||
|
|
||||||
// Wipes all the maps before repopulating them
|
// Wipes all the maps before repopulating them
|
||||||
images.clear();
|
images.clear();
|
||||||
@@ -418,28 +425,31 @@ public class GuiWizardHandbook extends GuiScreen {
|
|||||||
|
|
||||||
bookmarkSection = null; // Also need to wipe the reference to the old bookmarked section
|
bookmarkSection = null; // Also need to wipe the reference to the old bookmarked section
|
||||||
|
|
||||||
BufferedReader reader = new BufferedReader(new InputStreamReader(handbookFile.getInputStream(), StandardCharsets.UTF_8));
|
for (IResource handbookFile : handbookFiles) {
|
||||||
|
|
||||||
JsonElement je = gson.fromJson(reader, JsonElement.class);
|
BufferedReader reader = new BufferedReader(new InputStreamReader(handbookFile.getInputStream(), StandardCharsets.UTF_8));
|
||||||
JsonObject json = je.getAsJsonObject();
|
|
||||||
|
|
||||||
JsonUtils.getJsonObject(json, "colours").entrySet().forEach(e -> colours.put(e.getKey(),
|
JsonElement je = gson.fromJson(reader, JsonElement.class);
|
||||||
Color.decode(e.getValue().getAsString()).getRGB()));
|
JsonObject json = je.getAsJsonObject();
|
||||||
|
|
||||||
// Repopulates the remaining maps
|
JsonUtils.getJsonObject(json, "colours").entrySet().forEach(e -> colours.put(e.getKey(),
|
||||||
Image.populate(images, json);
|
Color.decode(e.getValue().getAsString()).getRGB()));
|
||||||
CraftingRecipe.populate(recipes, json);
|
|
||||||
Section.populate(sections, json);
|
|
||||||
|
|
||||||
sectionList = Collections.unmodifiableList(new ArrayList<>(sections.values()));
|
// Repopulates the remaining maps
|
||||||
|
Image.populate(images, json);
|
||||||
|
CraftingRecipe.populate(recipes, json);
|
||||||
|
Section.populate(sections, json);
|
||||||
|
|
||||||
if(sections.isEmpty()){
|
sectionList = Collections.unmodifiableList(new ArrayList<>(sections.values()));
|
||||||
Wizardry.logger.warn("Handbook has no sections! Aborting loading...");
|
|
||||||
return;
|
if(sections.isEmpty()){
|
||||||
|
Wizardry.logger.warn("Handbook has no sections! Aborting loading...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bookmarkSection = JsonUtils.getString(json, "bookmark_start_section");
|
||||||
|
if(!sections.containsKey(bookmarkSection)) throw new JsonSyntaxException("Section with id " + bookmarkSection + " is undefined");
|
||||||
}
|
}
|
||||||
|
|
||||||
bookmarkSection = JsonUtils.getString(json, "bookmark_start_section");
|
|
||||||
if(!sections.containsKey(bookmarkSection)) throw new JsonSyntaxException("Section with id " + bookmarkSection + " is undefined");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The first resource load on startup is done before the packet handler is loaded
|
// The first resource load on startup is done before the packet handler is loaded
|
||||||
@@ -455,16 +465,17 @@ public class GuiWizardHandbook extends GuiScreen {
|
|||||||
* @param manager The resource manager instance to use.
|
* @param manager The resource manager instance to use.
|
||||||
* @return The handbook JSON file, as an IResource, or null if it was not found.
|
* @return The handbook JSON file, as an IResource, or null if it was not found.
|
||||||
*/
|
*/
|
||||||
private static IResource getHandbookResource(IResourceManager manager){
|
private static List<IResource> getHandbookResource(IResourceManager manager){
|
||||||
|
|
||||||
// TODO: Implement resource pack stacking to allow addon mods and texture packs to add/overwrite content
|
// TODO: Implement resource pack stacking to allow addon mods and texture packs to add/overwrite content
|
||||||
|
|
||||||
IResource handbookFile = null;
|
IResource handbookFile = null;
|
||||||
|
List<IResource> handbookFiles = new ArrayList<>();
|
||||||
|
|
||||||
try{
|
try{
|
||||||
handbookFile = manager.getResource(new ResourceLocation(Wizardry.MODID, "texts/handbook_"
|
handbookFile = manager.getResource(new ResourceLocation(Wizardry.MODID, "texts/handbook_"
|
||||||
+ Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode() + ".json"));
|
+ Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode() + ".json"));
|
||||||
}catch(IOException e){
|
}catch(Exception e){
|
||||||
|
|
||||||
Wizardry.logger.info("Wizard handbook JSON file missing for the current language (" + Minecraft.getMinecraft()
|
Wizardry.logger.info("Wizard handbook JSON file missing for the current language (" + Minecraft.getMinecraft()
|
||||||
.getLanguageManager().getCurrentLanguage() + "). Using default (English-US) instead.");
|
.getLanguageManager().getCurrentLanguage() + "). Using default (English-US) instead.");
|
||||||
@@ -476,7 +487,29 @@ public class GuiWizardHandbook extends GuiScreen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return handbookFile;
|
handbookFiles.add(handbookFile);
|
||||||
|
|
||||||
|
for (String modid : ADDONS) {
|
||||||
|
// Addons
|
||||||
|
Wizardry.logger.info("Registering addon Wizard's Handbook contents for " + modid);
|
||||||
|
try{
|
||||||
|
handbookFile = manager.getResource(new ResourceLocation(modid, "texts/handbook_"
|
||||||
|
+ Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode() + ".json"));
|
||||||
|
}catch(Exception e){
|
||||||
|
|
||||||
|
Wizardry.logger.info("Wizard handbook JSON file missing for the current language (" + Minecraft.getMinecraft()
|
||||||
|
.getLanguageManager().getCurrentLanguage() + "). Using default (English-US) instead.");
|
||||||
|
|
||||||
|
try{
|
||||||
|
handbookFile = manager.getResource(new ResourceLocation(modid, "texts/handbook_en_us.json"));
|
||||||
|
}catch(IOException x){
|
||||||
|
Wizardry.logger.error("Couldn't find file: " + DEFAULT + ". The file may be missing; please try re-downloading and reinstalling Wizardry.", x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handbookFiles.add(handbookFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
return handbookFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Controls
|
// Controls
|
||||||
@@ -496,24 +529,30 @@ public class GuiWizardHandbook extends GuiScreen {
|
|||||||
|
|
||||||
Section currentSection = null;
|
Section currentSection = null;
|
||||||
|
|
||||||
for(Section section : sections.values()){
|
if(currentPage < singleToDoublePage(pageCount)){
|
||||||
// We always want this button to do something, and taking the right-hand page means it always does
|
// Find current section
|
||||||
if(section.containsPage(doubleToSinglePage(currentPage, true))){
|
for(Section section : sections.values()){
|
||||||
currentSection = section;
|
// Take the right-hand page if going to the next section, and the left-hand page otherwise
|
||||||
break;
|
if(section.containsPage(doubleToSinglePage(currentPage, button == nextSection))){
|
||||||
|
currentSection = section;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(currentSection != null){
|
List<Section> visibleSections = new ArrayList<>(sectionList);
|
||||||
|
visibleSections.removeIf(s -> !s.isUnlocked());
|
||||||
|
|
||||||
List<Section> visibleSections = new ArrayList<>(sectionList);
|
int index = currentSection == null ? visibleSections.size() : visibleSections.indexOf(currentSection);
|
||||||
visibleSections.removeIf(s -> !s.isUnlocked());
|
|
||||||
|
|
||||||
int index = visibleSections.indexOf(currentSection);
|
if(button == nextSection){
|
||||||
|
if(index + 1 < visibleSections.size()){
|
||||||
if(button == nextSection && index + 1 < visibleSections.size()){
|
|
||||||
currentPage = singleToDoublePage(visibleSections.get(index + 1).startPage);
|
currentPage = singleToDoublePage(visibleSections.get(index + 1).startPage);
|
||||||
}else if(index > 0){
|
}else{
|
||||||
|
currentPage = singleToDoublePage(pageCount);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(index > 0){
|
||||||
currentPage = singleToDoublePage(visibleSections.get(index - 1).startPage);
|
currentPage = singleToDoublePage(visibleSections.get(index - 1).startPage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -570,4 +609,9 @@ public class GuiWizardHandbook extends GuiScreen {
|
|||||||
sections.values().forEach(s -> s.updateUnlockStatus(showToasts, completedAdvancements));
|
sections.values().forEach(s -> s.updateUnlockStatus(showToasts, completedAdvancements));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void registerAddonHandbookContent(String modid) {
|
||||||
|
if (!ADDONS.contains(modid)) {
|
||||||
|
ADDONS.add(modid);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package electroblob.wizardry.client.gui.handbook;
|
package electroblob.wizardry.client.gui.handbook;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Streams;
|
import com.google.common.collect.Streams;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
@@ -35,6 +36,8 @@ import java.util.*;
|
|||||||
// be a non-static inner class
|
// be a non-static inner class
|
||||||
class Section {
|
class Section {
|
||||||
|
|
||||||
|
private static final Set<String> SPACELESS_LANGUAGES = ImmutableSet.of("zh_cn", "zh_tw");
|
||||||
|
|
||||||
// Final fields are mandatory (none here though), the rest are optional
|
// Final fields are mandatory (none here though), the rest are optional
|
||||||
String title;
|
String title;
|
||||||
private String[] rawText;
|
private String[] rawText;
|
||||||
@@ -293,7 +296,11 @@ class Section {
|
|||||||
|
|
||||||
String linkRaw = paragraph.substring(linkStart, linkEnd + 1);
|
String linkRaw = paragraph.substring(linkStart, linkEnd + 1);
|
||||||
String[] arguments = paragraph.substring(linkStart + 1, linkEnd).split("\\s", 2);
|
String[] arguments = paragraph.substring(linkStart + 1, linkEnd).split("\\s", 2);
|
||||||
String suffix = paragraph.substring(linkEnd).split("\\s", 2)[0].substring(1); // substring(1) to remove the @
|
String suffix = "";
|
||||||
|
|
||||||
|
// Account for trailing punctuation, except in languages that don't use spaces such as Chinese
|
||||||
|
boolean spaceless = SPACELESS_LANGUAGES.contains(Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage() == null ? "en_us" : Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode());
|
||||||
|
if(!spaceless) paragraph.substring(linkEnd).split("\\s", 2)[0].substring(1); // substring(1) to remove the @
|
||||||
|
|
||||||
// The index of the single page currently being formatted, relative to the section
|
// The index of the single page currently being formatted, relative to the section
|
||||||
int pageRelative = (lines.size() + upToLink.size() - 1) / maxLineNumber;
|
int pageRelative = (lines.size() + upToLink.size() - 1) / maxLineNumber;
|
||||||
@@ -311,7 +318,7 @@ class Section {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The button id only does what you use it for, so we're just not using it at all.
|
// The button id only does what you use it for, so we're just not using it at all.
|
||||||
this.buttons.get(pageRelative).add(GuiButtonHyperlink.create(x, y, font, upToLink, arguments, suffix, maxLineNumber - lineNumber - 1, GuiWizardHandbook.isRightPage(page)));
|
this.buttons.get(pageRelative).add(GuiButtonHyperlink.create(x, y, font, upToLink, arguments, suffix, maxLineNumber - lineNumber - 1, GuiWizardHandbook.isRightPage(page), spaceless));
|
||||||
|
|
||||||
// The link button should exactly overlay the display text in the main string
|
// The link button should exactly overlay the display text in the main string
|
||||||
// If the link has no display text specified, it displays the unformatted target string
|
// If the link has no display text specified, it displays the unformatted target string
|
||||||
|
|||||||
@@ -13,17 +13,17 @@ import net.minecraftforge.client.model.IModel;
|
|||||||
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
import net.minecraftforge.client.model.ModelLoaderRegistry;
|
||||||
import net.minecraftforge.common.model.IModelState;
|
import net.minecraftforge.common.model.IModelState;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class ModelBookshelf implements IModel {
|
public class ModelBookshelf implements IModel {
|
||||||
|
|
||||||
private static final ResourceLocation DEFAULT_BOOK_TEXTURE = new ResourceLocation(Wizardry.MODID, "blocks/books");
|
//private static final ResourceLocation DEFAULT_BOOK_TEXTURE = new ResourceLocation(Wizardry.MODID, "blocks/books");
|
||||||
|
|
||||||
private static final List<ResourceLocation> bookModelLocations = new ArrayList<>();
|
private static final List<ResourceLocation> bookModelLocations = new ArrayList<>();
|
||||||
|
|
||||||
|
private static final Map<String, IBakedModel[][]> bakedBookModels = new HashMap<>();
|
||||||
|
|
||||||
private final ModelResourceLocation bookshelfModelLocation;
|
private final ModelResourceLocation bookshelfModelLocation;
|
||||||
private final String variant;
|
private final String variant;
|
||||||
|
|
||||||
@@ -49,19 +49,7 @@ public class ModelBookshelf implements IModel {
|
|||||||
// I don't know why default state works here (surely it ought to be the state param?), but it works so who cares
|
// I don't know why default state works here (surely it ought to be the state param?), but it works so who cares
|
||||||
IBakedModel bookshelf = bookshelfModel.bake(bookshelfModel.getDefaultState(), format, bakedTextureGetter);
|
IBakedModel bookshelf = bookshelfModel.bake(bookshelfModel.getDefaultState(), format, bakedTextureGetter);
|
||||||
|
|
||||||
ImmutableList<ResourceLocation> textures = BlockBookshelf.getBookTextures();
|
IBakedModel[][] books = getBakedBookModels(format, bakedTextureGetter);
|
||||||
|
|
||||||
IBakedModel[][] books = new IBakedModel[textures.size()][BlockBookshelf.SLOT_COUNT];
|
|
||||||
|
|
||||||
for(int i = 0; i < textures.size(); i++){
|
|
||||||
|
|
||||||
ImmutableMap<String, String> retexturer = ImmutableMap.of("books", textures.get(i).toString());
|
|
||||||
|
|
||||||
for(int j = 0; j < BlockBookshelf.SLOT_COUNT; j++){
|
|
||||||
IModel bookModel = ModelLoaderRegistry.getModel(new ModelResourceLocation(bookModelLocations.get(j), variant)).retexture(retexturer);
|
|
||||||
books[i][j] = bookModel.bake(bookModel.getDefaultState(), format, bakedTextureGetter); // Same here!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// To clarify: the whole point of doing this was to avoid having to bake 4 * 2^12 models per bookshelf type
|
// To clarify: the whole point of doing this was to avoid having to bake 4 * 2^12 models per bookshelf type
|
||||||
// Therefore we have to have a baked bookshelf model that's kind of dynamic
|
// Therefore we have to have a baked bookshelf model that's kind of dynamic
|
||||||
@@ -74,6 +62,29 @@ public class ModelBookshelf implements IModel {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Retrieves the baked book models, or bakes them if they haven't been created yet. */
|
||||||
|
protected IBakedModel[][] getBakedBookModels(VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter) throws Exception{
|
||||||
|
|
||||||
|
if(bakedBookModels.get(variant) == null){
|
||||||
|
|
||||||
|
ImmutableList<ResourceLocation> textures = BlockBookshelf.getBookTextures();
|
||||||
|
|
||||||
|
bakedBookModels.put(variant, new IBakedModel[textures.size()][BlockBookshelf.SLOT_COUNT]);
|
||||||
|
|
||||||
|
for(int i = 0; i < textures.size(); i++){
|
||||||
|
|
||||||
|
ImmutableMap<String, String> retexturer = ImmutableMap.of("books", textures.get(i).toString());
|
||||||
|
|
||||||
|
for(int j = 0; j < BlockBookshelf.SLOT_COUNT; j++){
|
||||||
|
IModel bookModel = ModelLoaderRegistry.getModel(new ModelResourceLocation(bookModelLocations.get(j), variant)).retexture(retexturer);
|
||||||
|
bakedBookModels.get(variant)[i][j] = bookModel.bake(bookModel.getDefaultState(), format, bakedTextureGetter); // Same here!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bakedBookModels.get(variant);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ResourceLocation> getDependencies(){
|
public Collection<ResourceLocation> getDependencies(){
|
||||||
return bookModelLocations;
|
return bookModelLocations;
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package electroblob.wizardry.client.model;
|
||||||
|
|
||||||
|
import electroblob.wizardry.block.BlockStatue;
|
||||||
|
import net.minecraft.client.model.ModelRenderer;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
|
||||||
|
public class ModelRobeArmour extends ModelArmourFixer {
|
||||||
|
|
||||||
|
ModelRenderer robe;
|
||||||
|
private boolean showHeadWithBody;
|
||||||
|
|
||||||
|
public ModelRobeArmour(float delta, boolean showHeadWithBody){
|
||||||
|
|
||||||
|
super(delta, 0, 64, 64);
|
||||||
|
|
||||||
|
this.showHeadWithBody = showHeadWithBody;
|
||||||
|
|
||||||
|
bipedBody = new ModelRenderer(this, 16, 16);
|
||||||
|
bipedBody.addBox(-4F, 0F, -2F, 8, 11, 4, delta);
|
||||||
|
bipedBody.setRotationPoint(0F, 0F, 0F);
|
||||||
|
bipedBody.setTextureSize(64, 64);
|
||||||
|
bipedBody.mirror = true;
|
||||||
|
setRotation(bipedBody, 0F, 0F, 0F);
|
||||||
|
|
||||||
|
robe = new ModelRenderer(this, 40, 32);
|
||||||
|
robe.addBox(-4F, 0F, -2F, 8, 9, 4, delta);
|
||||||
|
robe.setRotationPoint(0F, 12, 0F); // 12.5 accounts for the expansion of each box
|
||||||
|
robe.setTextureSize(64, 64);
|
||||||
|
robe.mirror = true;
|
||||||
|
setRotation(robe, 0F, 0F, 0F);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){
|
||||||
|
if(entity.isInvisible() && !entity.getEntityData().getBoolean(BlockStatue.PETRIFIED_NBT_KEY)
|
||||||
|
&& !entity.getEntityData().getBoolean(BlockStatue.FROZEN_NBT_KEY)) return;
|
||||||
|
super.render(entity, f, f1, f2, f3, f4, f5);
|
||||||
|
setRotationAngles(f, f1, f2, f3, f4, f5, entity);
|
||||||
|
this.robe.render(f5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRotation(ModelRenderer model, float x, float y, float z){
|
||||||
|
model.rotateAngleX = x;
|
||||||
|
model.rotateAngleY = y;
|
||||||
|
model.rotateAngleZ = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity){
|
||||||
|
super.setRotationAngles(f, f1, f2, f3, f4, f5, entity);
|
||||||
|
this.robe.showModel = this.bipedBody.showModel;
|
||||||
|
if(showHeadWithBody) this.bipedHead.showModel = this.bipedBody.showModel;
|
||||||
|
if(this.isSneak){
|
||||||
|
//this.robe.rotationPointY = 10.5f;
|
||||||
|
this.robe.rotationPointZ = 4;
|
||||||
|
}else{
|
||||||
|
//this.robe.rotationPointY = 12.5f;
|
||||||
|
this.robe.rotationPointZ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The bottom part of the robe takes the y rotation from the rest of the robe but the x/z rotation
|
||||||
|
// from the average of the two legs
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
package electroblob.wizardry.client.model;
|
||||||
|
|
||||||
|
import electroblob.wizardry.block.BlockStatue;
|
||||||
|
import net.minecraft.client.model.ModelRenderer;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
|
||||||
|
public class ModelSageArmour extends ModelArmourFixer {
|
||||||
|
|
||||||
|
ModelRenderer hatBrim;
|
||||||
|
ModelRenderer hatSegment1;
|
||||||
|
ModelRenderer hatSegment2;
|
||||||
|
ModelRenderer hatSegment3;
|
||||||
|
ModelRenderer hatSegment4;
|
||||||
|
ModelRenderer hatSegment5;
|
||||||
|
ModelRenderer hatSegment6;
|
||||||
|
ModelRenderer robe;
|
||||||
|
ModelRenderer collar;
|
||||||
|
|
||||||
|
public ModelSageArmour(float delta){
|
||||||
|
|
||||||
|
super(delta, 0, 64, 64);
|
||||||
|
|
||||||
|
// This is necessary to stop the head from scaling.
|
||||||
|
this.bipedHead = new ModelRenderer(this, 0, 0);
|
||||||
|
// The hat layer has an offset of 0.5, so 0.6 is about the smallest we can get away with
|
||||||
|
this.bipedHead.addBox(-4.0F, -8.0F, -4.0F, 8, 8, 8, 0.6f);
|
||||||
|
this.bipedHead.setRotationPoint(0.0F, 0.0F + 0, 0.0F);
|
||||||
|
|
||||||
|
hatBrim = new ModelRenderer(this, 10, 45);
|
||||||
|
// Making the height 1 stops the top and bottom z-fighting when the hat is enchanted
|
||||||
|
hatBrim.addBox(-9F, -5.7F, -9F, 18, 1, 18, 0.6f);
|
||||||
|
hatBrim.setRotationPoint(0F, 0F, 0F);
|
||||||
|
hatBrim.setTextureSize(64, 64);
|
||||||
|
hatBrim.mirror = true;
|
||||||
|
setRotation(hatBrim, 0F, 0F, 0F);
|
||||||
|
|
||||||
|
hatSegment1 = new ModelRenderer(this, 0, 42);
|
||||||
|
hatSegment1.addBox(0F, 0F, 0F, 6, 2, 6, 0.2f);
|
||||||
|
hatSegment1.setRotationPoint(-3F, -10.6F, -3F);
|
||||||
|
hatSegment1.setTextureSize(64, 64);
|
||||||
|
hatSegment1.mirror = true;
|
||||||
|
setRotation(hatSegment1, -0.1396263F, 0F, 0F);
|
||||||
|
|
||||||
|
hatSegment2 = new ModelRenderer(this, 0, 50);
|
||||||
|
hatSegment2.addBox(0F, 0F, 0F, 5, 2, 5, 0.1f);
|
||||||
|
hatSegment2.setRotationPoint(-2.5F, -12.13333F, -2F);
|
||||||
|
hatSegment2.setTextureSize(64, 64);
|
||||||
|
hatSegment2.mirror = true;
|
||||||
|
setRotation(hatSegment2, -0.2443461F, 0F, 0F);
|
||||||
|
|
||||||
|
hatSegment3 = new ModelRenderer(this, 0, 57);
|
||||||
|
hatSegment3.addBox(0F, 0F, 0F, 4, 2, 4);
|
||||||
|
hatSegment3.setRotationPoint(-2F, -13.6F, -1F);
|
||||||
|
hatSegment3.setTextureSize(64, 64);
|
||||||
|
hatSegment3.mirror = true;
|
||||||
|
setRotation(hatSegment3, -0.4014257F, 0F, 0F);
|
||||||
|
|
||||||
|
hatSegment4 = new ModelRenderer(this, 16, 58);
|
||||||
|
hatSegment4.addBox(0F, 0F, 0F, 3, 2, 3);
|
||||||
|
hatSegment4.setRotationPoint(-1.5F, -14.6F, 0F);
|
||||||
|
hatSegment4.setTextureSize(64, 64);
|
||||||
|
hatSegment4.mirror = true;
|
||||||
|
setRotation(hatSegment4, -0.5759587F, 0F, 0F);
|
||||||
|
|
||||||
|
hatSegment5 = new ModelRenderer(this, 20, 54);
|
||||||
|
hatSegment5.addBox(0F, 0F, 0F, 2, 2, 2);
|
||||||
|
hatSegment5.setRotationPoint(-1F, -14.6F, 0F);
|
||||||
|
hatSegment5.setTextureSize(64, 64);
|
||||||
|
hatSegment5.mirror = true;
|
||||||
|
setRotation(hatSegment5, 0.3316126F, 0F, 0F);
|
||||||
|
|
||||||
|
hatSegment6 = new ModelRenderer(this, 20, 50);
|
||||||
|
hatSegment6.addBox(0F, 0F, 0F, 1, 1, 3);
|
||||||
|
hatSegment6.setRotationPoint(-0.5F, -15.1F, 2F);
|
||||||
|
hatSegment6.setTextureSize(64, 64);
|
||||||
|
hatSegment6.mirror = true;
|
||||||
|
setRotation(hatSegment6, -0.5585054F, 0F, 0F);
|
||||||
|
|
||||||
|
bipedBody = new ModelRenderer(this, 16, 16);
|
||||||
|
bipedBody.addBox(-4F, 0F, -2F, 8, 11, 4, delta);
|
||||||
|
bipedBody.setRotationPoint(0F, 0F, 0F);
|
||||||
|
bipedBody.setTextureSize(64, 64);
|
||||||
|
bipedBody.mirror = true;
|
||||||
|
setRotation(bipedBody, 0F, 0F, 0F);
|
||||||
|
|
||||||
|
robe = new ModelRenderer(this, 40, 32);
|
||||||
|
robe.addBox(-4F, 0F, -2F, 8, 9, 4, delta);
|
||||||
|
robe.setRotationPoint(0F, 12, 0F); // 12.5 accounts for the expansion of each box
|
||||||
|
robe.setTextureSize(64, 64);
|
||||||
|
robe.mirror = true;
|
||||||
|
setRotation(robe, 0F, 0F, 0F);
|
||||||
|
|
||||||
|
collar = new ModelRenderer(this, 0, 32);
|
||||||
|
collar.addBox(-7F, 0F, -2F, 14, 4, 4, 1);
|
||||||
|
collar.setRotationPoint(0F, 0F, 0F);
|
||||||
|
collar.setTextureSize(64, 64);
|
||||||
|
collar.mirror = true;
|
||||||
|
setRotation(collar, 0F, 0F, 0F);
|
||||||
|
|
||||||
|
// Makes the hat rotate with the head.
|
||||||
|
bipedHead.addChild(hatBrim);
|
||||||
|
bipedHead.addChild(hatSegment1);
|
||||||
|
bipedHead.addChild(hatSegment2);
|
||||||
|
bipedHead.addChild(hatSegment3);
|
||||||
|
bipedHead.addChild(hatSegment4);
|
||||||
|
bipedHead.addChild(hatSegment5);
|
||||||
|
bipedHead.addChild(hatSegment6);
|
||||||
|
bipedBody.addChild(collar);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){
|
||||||
|
if(entity.isInvisible() && !entity.getEntityData().getBoolean(BlockStatue.PETRIFIED_NBT_KEY)
|
||||||
|
&& !entity.getEntityData().getBoolean(BlockStatue.FROZEN_NBT_KEY)) return;
|
||||||
|
super.render(entity, f, f1, f2, f3, f4, f5);
|
||||||
|
setRotationAngles(f, f1, f2, f3, f4, f5, entity);
|
||||||
|
this.robe.render(f5);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setRotation(ModelRenderer model, float x, float y, float z){
|
||||||
|
model.rotateAngleX = x;
|
||||||
|
model.rotateAngleY = y;
|
||||||
|
model.rotateAngleZ = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotationAngles(float f, float f1, float f2, float f3, float f4, float f5, Entity entity){
|
||||||
|
|
||||||
|
super.setRotationAngles(f, f1, f2, f3, f4, f5, entity);
|
||||||
|
|
||||||
|
this.robe.showModel = this.bipedBody.showModel;
|
||||||
|
|
||||||
|
if(this.isSneak){
|
||||||
|
//this.robe.rotationPointY = 10.5f;
|
||||||
|
this.robe.rotationPointZ = 4;
|
||||||
|
}else{
|
||||||
|
//this.robe.rotationPointY = 12.5f;
|
||||||
|
this.robe.rotationPointZ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The bottom part of the robe takes the y rotation from the rest of the robe but the x/z rotation
|
||||||
|
// from the average of the two legs
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
package electroblob.wizardry.client.renderer;
|
||||||
|
|
||||||
|
import electroblob.wizardry.Wizardry;
|
||||||
|
import net.minecraft.client.model.ModelIronGolem;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.client.renderer.entity.RenderLiving;
|
||||||
|
import net.minecraft.client.renderer.entity.RenderManager;
|
||||||
|
import net.minecraft.entity.monster.EntityIronGolem;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public class RenderSpectralGolem extends RenderLiving<EntityIronGolem>
|
||||||
|
{
|
||||||
|
private static final ResourceLocation SPECTRAL_GOLEM_TEXTURES = new ResourceLocation(Wizardry.MODID, "textures/entity/spectral_golem.png");
|
||||||
|
|
||||||
|
public RenderSpectralGolem(RenderManager renderManagerIn)
|
||||||
|
{
|
||||||
|
super(renderManagerIn, new ModelIronGolem(), 0.5F);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the location of an entity's texture. Doesn't seem to be called unless you call Render.bindEntityTexture.
|
||||||
|
*/
|
||||||
|
protected ResourceLocation getEntityTexture(EntityIronGolem entity)
|
||||||
|
{
|
||||||
|
return SPECTRAL_GOLEM_TEXTURES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void preRenderCallback(EntityIronGolem entity, float partialTickTime){
|
||||||
|
super.preRenderCallback(entity, partialTickTime);
|
||||||
|
GlStateManager.enableBlend();
|
||||||
|
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
GlStateManager.color(1, 1, 1, 0.7f);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void applyRotations(EntityIronGolem entityLiving, float ageInTicks, float rotationYaw, float partialTicks)
|
||||||
|
{
|
||||||
|
super.applyRotations(entityLiving, ageInTicks, rotationYaw, partialTicks);
|
||||||
|
|
||||||
|
if ((double)entityLiving.limbSwingAmount >= 0.01D)
|
||||||
|
{
|
||||||
|
float f = 13.0F;
|
||||||
|
float f1 = entityLiving.limbSwing - entityLiving.limbSwingAmount * (1.0F - partialTicks) + 6.0F;
|
||||||
|
float f2 = (Math.abs(f1 % 13.0F - 6.5F) - 3.25F) / 3.25F;
|
||||||
|
GlStateManager.rotate(6.5F * f2, 0.0F, 0.0F, 1.0F);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package electroblob.wizardry.client.renderer.entity;
|
||||||
|
|
||||||
|
import electroblob.wizardry.Wizardry;
|
||||||
|
import electroblob.wizardry.entity.projectile.EntityConjuredArrow;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.client.renderer.entity.RenderArrow;
|
||||||
|
import net.minecraft.client.renderer.entity.RenderManager;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
|
import org.lwjgl.opengl.GL11;
|
||||||
|
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public class RenderConjuredArrow extends RenderArrow<EntityConjuredArrow> {
|
||||||
|
|
||||||
|
public static final ResourceLocation CONJURED_ARROW_TEXTURE = new ResourceLocation(Wizardry.MODID, "textures/entity/conjured_arrow.png");
|
||||||
|
|
||||||
|
public RenderConjuredArrow(RenderManager manager) {
|
||||||
|
super(manager);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ResourceLocation getEntityTexture(EntityConjuredArrow entity) {
|
||||||
|
return CONJURED_ARROW_TEXTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doRender(EntityConjuredArrow entity, double x, double y, double z, float entityYaw, float partialTicks) {
|
||||||
|
GlStateManager.pushMatrix();
|
||||||
|
GlStateManager.enableBlend();
|
||||||
|
GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
GlStateManager.color(1, 1, 1, 0.4f);
|
||||||
|
super.doRender(entity, x, y, z, entityYaw, partialTicks);
|
||||||
|
GlStateManager.popMatrix();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package electroblob.wizardry.client.renderer.entity.layers;
|
||||||
|
|
||||||
|
import electroblob.wizardry.registry.WizardryPotions;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager.DestFactor;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
|
||||||
|
import net.minecraft.client.renderer.OpenGlHelper;
|
||||||
|
import net.minecraft.client.renderer.entity.RenderLivingBase;
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layer used to render the diamondflesh texture on creatures with the diamondflesh effect.
|
||||||
|
*
|
||||||
|
* @author WinDanesz
|
||||||
|
* @since Wizardry 4.3.7
|
||||||
|
*/
|
||||||
|
public class LayerDiamond extends LayerTiledOverlay<EntityLivingBase> {
|
||||||
|
|
||||||
|
private static final ResourceLocation TEXTURE = new ResourceLocation("textures/blocks/diamond_block.png");
|
||||||
|
|
||||||
|
public LayerDiamond(RenderLivingBase<?> renderer){
|
||||||
|
super(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldRender(EntityLivingBase entity, float partialTicks){
|
||||||
|
return !entity.isInvisible() && entity.isPotionActive(WizardryPotions.diamondflesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getTexture(EntityLivingBase entity, float partialTicks){
|
||||||
|
return TEXTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks,
|
||||||
|
float ageInTicks, float netHeadYaw, float headPitch, float scale){
|
||||||
|
|
||||||
|
GlStateManager.enableBlend();
|
||||||
|
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
int j = entity.getBrightnessForRender();
|
||||||
|
int k = j % 65536;
|
||||||
|
int l = j / 65536;
|
||||||
|
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float) k, (float) l);
|
||||||
|
|
||||||
|
super.doRenderLayer(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, headPitch, scale);
|
||||||
|
|
||||||
|
GlStateManager.disableBlend();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package electroblob.wizardry.client.renderer.entity.layers;
|
||||||
|
|
||||||
|
import electroblob.wizardry.registry.WizardryPotions;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager.DestFactor;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
|
||||||
|
import net.minecraft.client.renderer.OpenGlHelper;
|
||||||
|
import net.minecraft.client.renderer.entity.RenderLivingBase;
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layer used to render the ironflesh texture on creatures with the ironflesh effect.
|
||||||
|
*
|
||||||
|
* @author WinDanesz
|
||||||
|
* @since Wizardry 4.3.7
|
||||||
|
*/
|
||||||
|
public class LayerIron extends LayerTiledOverlay<EntityLivingBase> {
|
||||||
|
|
||||||
|
private static final ResourceLocation TEXTURE = new ResourceLocation("textures/blocks/iron_block.png");
|
||||||
|
|
||||||
|
public LayerIron(RenderLivingBase<?> renderer){
|
||||||
|
super(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldRender(EntityLivingBase entity, float partialTicks){
|
||||||
|
return !entity.isInvisible() && entity.isPotionActive(WizardryPotions.ironflesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getTexture(EntityLivingBase entity, float partialTicks){
|
||||||
|
return TEXTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks,
|
||||||
|
float ageInTicks, float netHeadYaw, float headPitch, float scale){
|
||||||
|
|
||||||
|
GlStateManager.enableBlend();
|
||||||
|
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
int j = entity.getBrightnessForRender();
|
||||||
|
int k = j % 65536;
|
||||||
|
int l = j / 65536;
|
||||||
|
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float) k, (float) l);
|
||||||
|
|
||||||
|
super.doRenderLayer(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, headPitch, scale);
|
||||||
|
|
||||||
|
GlStateManager.disableBlend();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package electroblob.wizardry.client.renderer.entity.layers;
|
||||||
|
|
||||||
|
import electroblob.wizardry.registry.WizardryPotions;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager.DestFactor;
|
||||||
|
import net.minecraft.client.renderer.GlStateManager.SourceFactor;
|
||||||
|
import net.minecraft.client.renderer.OpenGlHelper;
|
||||||
|
import net.minecraft.client.renderer.entity.RenderLivingBase;
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layer used to render the oakflesh texture on creatures with the oakflesh effect.
|
||||||
|
*
|
||||||
|
* @author WinDanesz
|
||||||
|
* @since Wizardry 4.3.7
|
||||||
|
*/
|
||||||
|
public class LayerOak extends LayerTiledOverlay<EntityLivingBase> {
|
||||||
|
|
||||||
|
private static final ResourceLocation TEXTURE = new ResourceLocation("textures/blocks/log_oak.png");
|
||||||
|
|
||||||
|
public LayerOak(RenderLivingBase<?> renderer){
|
||||||
|
super(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldRender(EntityLivingBase entity, float partialTicks){
|
||||||
|
return !entity.isInvisible() && entity.isPotionActive(WizardryPotions.oakflesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getTexture(EntityLivingBase entity, float partialTicks){
|
||||||
|
return TEXTURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doRenderLayer(EntityLivingBase entity, float limbSwing, float limbSwingAmount, float partialTicks,
|
||||||
|
float ageInTicks, float netHeadYaw, float headPitch, float scale){
|
||||||
|
|
||||||
|
GlStateManager.enableBlend();
|
||||||
|
GlStateManager.blendFunc(SourceFactor.SRC_ALPHA, DestFactor.ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
int j = entity.getBrightnessForRender();
|
||||||
|
int k = j % 65536;
|
||||||
|
int l = j / 65536;
|
||||||
|
OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, (float) k, (float) l);
|
||||||
|
|
||||||
|
super.doRenderLayer(entity, limbSwing, limbSwingAmount, partialTicks, ageInTicks, netHeadYaw, headPitch, scale);
|
||||||
|
|
||||||
|
GlStateManager.disableBlend();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -60,10 +60,12 @@ public class RenderSixthSense {
|
|||||||
|
|
||||||
Minecraft mc = Minecraft.getMinecraft();
|
Minecraft mc = Minecraft.getMinecraft();
|
||||||
RenderManager renderManager = event.getRenderer().getRenderManager();
|
RenderManager renderManager = event.getRenderer().getRenderManager();
|
||||||
|
float effectRadius = Spells.sixth_sense.getProperty(Spell.EFFECT_RADIUS).floatValue();
|
||||||
|
float distance = event.getEntity().getDistance(mc.player);
|
||||||
|
|
||||||
if(mc.player.isPotionActive(WizardryPotions.sixth_sense) && !(event.getEntity() instanceof EntityArmorStand)
|
if(mc.player.isPotionActive(WizardryPotions.sixth_sense) && !(event.getEntity() instanceof EntityArmorStand)
|
||||||
&& event.getEntity() != mc.player && mc.player.getActivePotionEffect(WizardryPotions.sixth_sense) != null
|
&& event.getEntity() != mc.player && mc.player.getActivePotionEffect(WizardryPotions.sixth_sense) != null
|
||||||
&& event.getEntity().getDistance(mc.player) < Spells.sixth_sense.getProperty(Spell.EFFECT_RADIUS).floatValue()
|
&& distance < effectRadius
|
||||||
* (1 + mc.player.getActivePotionEffect(WizardryPotions.sixth_sense).getAmplifier() * Constants.RANGE_INCREASE_PER_LEVEL)){
|
* (1 + mc.player.getActivePotionEffect(WizardryPotions.sixth_sense).getAmplifier() * Constants.RANGE_INCREASE_PER_LEVEL)){
|
||||||
|
|
||||||
Tessellator tessellator = Tessellator.getInstance();
|
Tessellator tessellator = Tessellator.getInstance();
|
||||||
@@ -87,7 +89,13 @@ public class RenderSixthSense {
|
|||||||
GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
|
GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.0F, 0.0F);
|
||||||
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
|
GlStateManager.rotate(yaw, 1.0F, 0.0F, 0.0F);
|
||||||
|
|
||||||
GlStateManager.color(1, 1, 1, 1);
|
//Decreases the opacity of the marker after 80% of the effect distance
|
||||||
|
float alpha = 1f;
|
||||||
|
float f = 5 * (1f - distance / effectRadius);
|
||||||
|
if (f <= 1) {
|
||||||
|
alpha = f;
|
||||||
|
}
|
||||||
|
GlStateManager.color(1, 1, 1, alpha);
|
||||||
|
|
||||||
ResourceLocation texture = PASSIVE_MOB_MARKER_TEXTURE;
|
ResourceLocation texture = PASSIVE_MOB_MARKER_TEXTURE;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package electroblob.wizardry.constants;
|
package electroblob.wizardry.constants;
|
||||||
|
|
||||||
|
import electroblob.wizardry.Wizardry;
|
||||||
import electroblob.wizardry.WizardryEventHandler;
|
import electroblob.wizardry.WizardryEventHandler;
|
||||||
|
|
||||||
/** Stores various global constants used in Wizardry. */
|
/** Stores various global constants used in Wizardry. */
|
||||||
@@ -7,50 +8,62 @@ public final class Constants {
|
|||||||
|
|
||||||
/** The amount of mana a crystal shard is worth */
|
/** The amount of mana a crystal shard is worth */
|
||||||
// 100 doesn't divide nicely by 9 so we're calling this 10. I guess you lose a little bit by smashing a crystal.
|
// 100 doesn't divide nicely by 9 so we're calling this 10. I guess you lose a little bit by smashing a crystal.
|
||||||
public static final int MANA_PER_SHARD = 10;
|
public static int MANA_PER_SHARD;
|
||||||
/** The amount of mana each magic crystal is worth */
|
/** The amount of mana each magic crystal is worth */
|
||||||
public static final int MANA_PER_CRYSTAL = 100;
|
public static int MANA_PER_CRYSTAL;
|
||||||
/** The amount of mana a grand magic crystal is worth */
|
/** The amount of mana a grand magic crystal is worth */
|
||||||
public static final int GRAND_CRYSTAL_MANA = 400;
|
public static int GRAND_CRYSTAL_MANA;
|
||||||
/** The maximum number of one type of wand upgrade which can be applied to a wand. */
|
/** The maximum number of one type of wand upgrade which can be applied to a wand. */
|
||||||
public static final int UPGRADE_STACK_LIMIT = 3;
|
public static int UPGRADE_STACK_LIMIT;
|
||||||
/** The bonus amount of wand upgrades that can be applied to a non-elemental wand. */
|
/** The bonus amount of wand upgrades that can be applied to a non-elemental wand. */
|
||||||
public static final int NON_ELEMENTAL_UPGRADE_BONUS = 3;
|
public static int NON_ELEMENTAL_UPGRADE_BONUS;
|
||||||
/** The fraction by which cooldowns are reduced for each level of cooldown upgrade. */
|
/** The fraction by which cooldowns are reduced for each level of cooldown upgrade. */
|
||||||
public static final float COOLDOWN_REDUCTION_PER_LEVEL = 0.15f;
|
public static float COOLDOWN_REDUCTION_PER_LEVEL;
|
||||||
/** The fraction by which maximum charge is increased for each level of storage upgrade. */
|
/** The fraction by which maximum charge is increased for each level of storage upgrade. */
|
||||||
public static final float STORAGE_INCREASE_PER_LEVEL = 0.15f;
|
public static float STORAGE_INCREASE_PER_LEVEL;
|
||||||
/** The fraction by which potency is increased for each tier of matching wand. */
|
/** The fraction by which potency is increased for each tier of matching wand. */
|
||||||
public static final float POTENCY_INCREASE_PER_TIER = 0.15f;
|
public static float POTENCY_INCREASE_PER_TIER;
|
||||||
/** The fraction by which costs are reduced for each piece of matching armour. */
|
|
||||||
public static final float COST_REDUCTION_PER_ARMOUR = 0.15f;
|
|
||||||
/** The extra fraction by which costs are reduced for a full set of elemental armour. */
|
|
||||||
public static final float FULL_ARMOUR_SET_BONUS = 0.2f;
|
|
||||||
/** The fraction by which spell duration is increased for each level of duration upgrade. */
|
/** The fraction by which spell duration is increased for each level of duration upgrade. */
|
||||||
public static final float DURATION_INCREASE_PER_LEVEL = 0.25f;
|
public static float DURATION_INCREASE_PER_LEVEL;
|
||||||
/** The fraction by which spell range is increased for each level of range upgrade. */
|
/** The fraction by which spell range is increased for each level of range upgrade. */
|
||||||
public static final float RANGE_INCREASE_PER_LEVEL = 0.25f;
|
public static float RANGE_INCREASE_PER_LEVEL;
|
||||||
/** The fraction by which spell blast radius is increased for each level of range upgrade. */
|
/** The fraction by which spell blast radius is increased for each level of range upgrade. */
|
||||||
public static final float BLAST_RADIUS_INCREASE_PER_LEVEL = 0.25f;
|
public static float BLAST_RADIUS_INCREASE_PER_LEVEL;
|
||||||
/** The fraction by which movement speed is reduced per level of frost effect. */
|
/** The fraction by which movement speed is reduced per level of frost effect. */
|
||||||
public static final double FROST_SLOWNESS_PER_LEVEL = 0.5;
|
public static double FROST_SLOWNESS_PER_LEVEL;
|
||||||
/** The fraction by which movement speed is reduced per level of decay effect. */
|
/** The fraction by which movement speed is reduced per level of decay effect. */
|
||||||
public static final double DECAY_SLOWNESS_PER_LEVEL = 0.2;
|
public static final double DECAY_SLOWNESS_PER_LEVEL = 0.2;
|
||||||
/** The fraction by which dig speed is reduced per level of frostbite effect. */
|
/** The fraction by which dig speed is reduced per level of frostbite effect. */
|
||||||
public static final float FROST_FATIGUE_PER_LEVEL = 0.45f;
|
public static final float FROST_FATIGUE_PER_LEVEL = 0.45f;
|
||||||
/** The number of ticks between each mana increase for wands with the condenser upgrade. */
|
/** The number of ticks between each mana increase for wands with the condenser upgrade. */
|
||||||
public static final int CONDENSER_TICK_INTERVAL = 50;
|
public static int CONDENSER_TICK_INTERVAL;
|
||||||
/**
|
/**
|
||||||
* The amount of mana given for a kill for each level of siphon upgrade. A random amount from 0 to this number - 1
|
* The amount of mana given for a kill for each level of siphon upgrade. A random amount from 0 to this number - 1
|
||||||
* is also added. See {@link WizardryEventHandler#onLivingDeathEvent} for more details.
|
* is also added. See {@link WizardryEventHandler#onLivingDeathEvent} for more details.
|
||||||
*/
|
*/
|
||||||
public static final int SIPHON_MANA_PER_LEVEL = 5;
|
public static int SIPHON_MANA_PER_LEVEL;
|
||||||
/**
|
/**
|
||||||
* The number of ticks between the spawning of patches of decay when an entity has the decay effect. Note that decay
|
* The number of ticks between the spawning of patches of decay when an entity has the decay effect. Note that decay
|
||||||
* won't spawn again if something is already standing in it.
|
* won't spawn again if something is already standing in it.
|
||||||
*/
|
*/
|
||||||
public static final int DECAY_SPREAD_INTERVAL = 8;
|
public static final int DECAY_SPREAD_INTERVAL = 8;
|
||||||
/** The fraction by which potency is increased per level of the empowerment effect. */
|
|
||||||
public static final float EMPOWERMENT_POTENCY_PER_LEVEL = 0.25f;
|
|
||||||
|
|
||||||
|
|
||||||
|
// making this as an update to the existing values to not break addons directly relying on the fields
|
||||||
|
static {
|
||||||
|
MANA_PER_SHARD = Wizardry.settings.manaPerShard;
|
||||||
|
MANA_PER_CRYSTAL = Wizardry.settings.manaPerCrystal;
|
||||||
|
GRAND_CRYSTAL_MANA = Wizardry.settings.grandCrystalMana;
|
||||||
|
UPGRADE_STACK_LIMIT = Wizardry.settings.upgradeStackLimit;
|
||||||
|
NON_ELEMENTAL_UPGRADE_BONUS = Wizardry.settings.nonElementalUpgradeBonus;
|
||||||
|
COOLDOWN_REDUCTION_PER_LEVEL = (float) Wizardry.settings.cooldownReductionPerLevel;
|
||||||
|
STORAGE_INCREASE_PER_LEVEL = Wizardry.settings.storageIncreasePerLevel;
|
||||||
|
POTENCY_INCREASE_PER_TIER = (float) Wizardry.settings.potencyIncreasePerTier;
|
||||||
|
DURATION_INCREASE_PER_LEVEL = (float) Wizardry.settings.durationIncreasePerLevel;
|
||||||
|
RANGE_INCREASE_PER_LEVEL = (float) Wizardry.settings.rangeIncreasePerLevel;
|
||||||
|
BLAST_RADIUS_INCREASE_PER_LEVEL = (float) Wizardry.settings.blastIncreasePerLevel;
|
||||||
|
FROST_SLOWNESS_PER_LEVEL = (float) Wizardry.settings.frostSlownessIncreasePerLevel;
|
||||||
|
SIPHON_MANA_PER_LEVEL = Wizardry.settings.siphonManaPerLevel;
|
||||||
|
CONDENSER_TICK_INTERVAL = Wizardry.settings.condenserTickInterval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ import java.util.Random;
|
|||||||
|
|
||||||
public enum Tier {
|
public enum Tier {
|
||||||
|
|
||||||
NOVICE(700, 3, 12, new Style().setColor(TextFormatting.WHITE), "novice"),
|
NOVICE(Wizardry.settings.noviceMaxCharge, Wizardry.settings.noviceUpgradeLimit, 12, new Style().setColor(TextFormatting.WHITE), "novice"),
|
||||||
APPRENTICE(1000, 5, 5, new Style().setColor(TextFormatting.AQUA), "apprentice"),
|
APPRENTICE(Wizardry.settings.apprenticeMaxCharge, Wizardry.settings.apprenticeUpgradeLimit, 5, new Style().setColor(TextFormatting.AQUA), "apprentice"),
|
||||||
ADVANCED(1500, 7, 2, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"),
|
ADVANCED(Wizardry.settings.advancedMaxCharge, Wizardry.settings.advancedUpgradeLimit, 2, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"),
|
||||||
MASTER(2500, 9, 1, new Style().setColor(TextFormatting.DARK_PURPLE), "master");
|
MASTER(Wizardry.settings.masterMaxCharge, Wizardry.settings.masterUpgradeLimit, 1, new Style().setColor(TextFormatting.DARK_PURPLE), "master");
|
||||||
|
|
||||||
/** Maximum mana a wand of this tier can store. */
|
/** Maximum mana a wand of this tier can store. */
|
||||||
public final int maxCharge;
|
public final int maxCharge;
|
||||||
|
|||||||
@@ -64,6 +64,11 @@ public interface IStoredVariable<T> extends IVariable<T> {
|
|||||||
this.ticker = (p, t) -> t; // Initialise this with a do-nothing function, can be overwritten later
|
this.ticker = (p, t) -> t; // Initialise this with a do-nothing function, can be overwritten later
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces this variable's update method with the given update function. <i>Beware of auto-unboxing of
|
* Replaces this variable's update method with the given update function. <i>Beware of auto-unboxing of
|
||||||
* primitive types! For lambda expressions, check the second parameter isn't null before operating on it.
|
* primitive types! For lambda expressions, check the second parameter isn't null before operating on it.
|
||||||
|
|||||||
@@ -47,7 +47,10 @@ public interface IVariable<T> {
|
|||||||
*/
|
*/
|
||||||
void write(ByteBuf buf, T value);
|
void write(ByteBuf buf, T value);
|
||||||
|
|
||||||
|
String getKey();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
*
|
||||||
* Reads this variable's value from the given {@link ByteBuf}.
|
* Reads this variable's value from the given {@link ByteBuf}.
|
||||||
*/
|
*/
|
||||||
T read(ByteBuf buf);
|
T read(ByteBuf buf);
|
||||||
@@ -110,6 +113,11 @@ public interface IVariable<T> {
|
|||||||
// NYI
|
// NYI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getKey() {
|
||||||
|
return "none"; // we don't mind as these are never synced (electroblob.wizardry.data.IVariable.Variable.isSynced)
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T read(ByteBuf buf){
|
public T read(ByteBuf buf){
|
||||||
return null; // NYI
|
return null; // NYI
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import electroblob.wizardry.enchantment.Imbuement;
|
|||||||
import electroblob.wizardry.entity.living.ISummonedCreature;
|
import electroblob.wizardry.entity.living.ISummonedCreature;
|
||||||
import electroblob.wizardry.event.SpellCastEvent;
|
import electroblob.wizardry.event.SpellCastEvent;
|
||||||
import electroblob.wizardry.event.SpellCastEvent.Source;
|
import electroblob.wizardry.event.SpellCastEvent.Source;
|
||||||
import electroblob.wizardry.item.ItemWand;
|
|
||||||
import electroblob.wizardry.packet.PacketCastContinuousSpell;
|
import electroblob.wizardry.packet.PacketCastContinuousSpell;
|
||||||
import electroblob.wizardry.packet.PacketPlayerSync;
|
import electroblob.wizardry.packet.PacketPlayerSync;
|
||||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||||
@@ -47,6 +46,7 @@ import javax.annotation.Nullable;
|
|||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.AbstractMap.SimpleEntry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Capability-based replacement for the old ExtendedPlayer class from 1.7.10. This has been reworked to leave minimum
|
* Capability-based replacement for the old ExtendedPlayer class from 1.7.10. This has been reworked to leave minimum
|
||||||
@@ -73,7 +73,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
|||||||
private static final Set<IStoredVariable> storedVariables = new HashSet<>();
|
private static final Set<IStoredVariable> storedVariables = new HashSet<>();
|
||||||
|
|
||||||
/** The maximum number of recent spells to track. */
|
/** The maximum number of recent spells to track. */
|
||||||
public static final int MAX_RECENT_SPELLS = ItemWand.BASE_SPELL_SLOTS;
|
public static int MAX_RECENT_SPELLS;
|
||||||
|
|
||||||
private static final int IMBUEMENT_UPDATE_INTERVAL = 20;
|
private static final int IMBUEMENT_UPDATE_INTERVAL = 20;
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
|||||||
* be modified via {@link WizardData#setVariable(IVariable, Object)}, which (as a method) is able to enforce it. */
|
* be modified via {@link WizardData#setVariable(IVariable, Object)}, which (as a method) is able to enforce it. */
|
||||||
private final Map<IVariable, Object> spellData;
|
private final Map<IVariable, Object> spellData;
|
||||||
|
|
||||||
private Queue<Spell> recentSpells;
|
private Queue<SimpleEntry<Spell, Long>> recentSpells;
|
||||||
|
|
||||||
// This one is still necessary, because I can't override the equip animation for items that aren't from Wizardry.
|
// This one is still necessary, because I can't override the equip animation for items that aren't from Wizardry.
|
||||||
// Leaving this for now because merging it into the spell data system will be more tricky
|
// Leaving this for now because merging it into the spell data system will be more tricky
|
||||||
@@ -199,9 +199,14 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a set containing the registered {@link IStoredVariable} objects for which {@link IVariable#isSynced()}
|
/** Returns a set containing the registered {@link IStoredVariable} objects for which {@link IVariable#isSynced()}
|
||||||
* returns true. Used internally for packet reading. */
|
* returns true, ordered by their keys obtained from {@link IVariable#getKey()}. Used internally for packets. */
|
||||||
public static Set<IVariable> getSyncedVariables(){
|
public static Set<IVariable> getSyncedVariablesOrderedByKey(){
|
||||||
return storedVariables.stream().filter(IVariable::isSynced).collect(Collectors.toSet());
|
Comparator<IVariable> keyComparator = Comparator.comparing(IVariable::getKey);
|
||||||
|
|
||||||
|
return storedVariables.stream()
|
||||||
|
.filter(IVariable::isSynced)
|
||||||
|
.sorted(keyComparator)
|
||||||
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -289,15 +294,19 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
|||||||
* @param spell The spell to be tracked.
|
* @param spell The spell to be tracked.
|
||||||
*/
|
*/
|
||||||
public void trackRecentSpell(Spell spell){
|
public void trackRecentSpell(Spell spell){
|
||||||
this.recentSpells.add(spell);
|
this.recentSpells.add(new SimpleEntry<>(spell, player.world.getTotalWorldTime()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of times the given spell is tracked in this player's recently-cast spells.
|
* Returns the number of times the given spell is tracked in this player's recently-cast spells.
|
||||||
|
* Only counts spells cast within the configured expiry time.
|
||||||
* @param spell The spell to count casts for.
|
* @param spell The spell to count casts for.
|
||||||
*/
|
*/
|
||||||
public int countRecentCasts(Spell spell){
|
public int countRecentCasts(Spell spell){
|
||||||
return (int)this.recentSpells.stream().filter(s -> s == spell).count(); // We know this can't be more than 5
|
long currentTime = player.world.getTotalWorldTime();
|
||||||
|
return (int)this.recentSpells.stream()
|
||||||
|
.filter(entry -> entry.getKey() == spell && (currentTime - entry.getValue()) < Wizardry.settings.recentSpellExpiryTime)
|
||||||
|
.count(); // We know this can't be more than 5
|
||||||
}
|
}
|
||||||
|
|
||||||
// Imbuements
|
// Imbuements
|
||||||
@@ -346,20 +355,20 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
|||||||
|
|
||||||
// For each item in the player's inventory
|
// For each item in the player's inventory
|
||||||
for(ItemStack stack : player.inventory.mainInventory){
|
for(ItemStack stack : player.inventory.mainInventory){
|
||||||
updateImbutedItem(stack, activeImbuements);
|
updateImbuedItem(stack, activeImbuements);
|
||||||
}
|
}
|
||||||
for(ItemStack stack : player.inventory.armorInventory){
|
for(ItemStack stack : player.inventory.armorInventory){
|
||||||
updateImbutedItem(stack, activeImbuements);
|
updateImbuedItem(stack, activeImbuements);
|
||||||
}
|
}
|
||||||
for(ItemStack stack : player.inventory.offHandInventory){
|
for(ItemStack stack : player.inventory.offHandInventory){
|
||||||
updateImbutedItem(stack, activeImbuements);
|
updateImbuedItem(stack, activeImbuements);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes all imbuements from the map that are no longer active
|
// Removes all imbuements from the map that are no longer active
|
||||||
this.imbuementDurations.keySet().retainAll(activeImbuements);
|
this.imbuementDurations.keySet().retainAll(activeImbuements);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateImbutedItem(ItemStack stack, Set<Imbuement> activeImbuements){
|
private void updateImbuedItem(ItemStack stack, Set<Imbuement> activeImbuements){
|
||||||
|
|
||||||
if(stack.isItemEnchanted()){
|
if(stack.isItemEnchanted()){
|
||||||
|
|
||||||
@@ -382,6 +391,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
|||||||
activeImbuements.add((Imbuement)enchantment);
|
activeImbuements.add((Imbuement)enchantment);
|
||||||
}else{
|
}else{
|
||||||
// Otherwise, removes the enchantment from the item
|
// Otherwise, removes the enchantment from the item
|
||||||
|
((Imbuement) enchantment).onImbuementRemoval(stack);
|
||||||
iterator.remove(); // FIXME: Apparently this can cause a CME
|
iterator.remove(); // FIXME: Apparently this can cause a CME
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -455,7 +465,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
|||||||
|
|
||||||
if(this.castCommandSpell != null && this.castCommandSpell.isContinuous){
|
if(this.castCommandSpell != null && this.castCommandSpell.isContinuous){
|
||||||
|
|
||||||
if(castCommandTick >= castCommandDuration){
|
if(castCommandTick > castCommandDuration){
|
||||||
this.stopCastingContinuousSpell();
|
this.stopCastingContinuousSpell();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -507,6 +517,12 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
|||||||
if(player.ticksExisted % IMBUEMENT_UPDATE_INTERVAL == 0) updateImbuedItems();
|
if(player.ticksExisted % IMBUEMENT_UPDATE_INTERVAL == 0) updateImbuedItems();
|
||||||
updateContinuousSpellCasting();
|
updateContinuousSpellCasting();
|
||||||
|
|
||||||
|
// Clean up expired recent spells every 60 ticks (1 second)
|
||||||
|
if(player.ticksExisted % 60 == 0) {
|
||||||
|
long currentTime = player.world.getTotalWorldTime();
|
||||||
|
this.recentSpells.removeIf(entry -> (currentTime - entry.getValue()) >= Wizardry.settings.recentSpellExpiryTime);
|
||||||
|
}
|
||||||
|
|
||||||
this.spellData.forEach((k, v) -> this.spellData.put(k, k.update(player, v)));
|
this.spellData.forEach((k, v) -> this.spellData.put(k, k.update(player, v)));
|
||||||
this.spellData.keySet().removeIf(k -> k.canPurge(player, this.spellData.get(k)));
|
this.spellData.keySet().removeIf(k -> k.canPurge(player, this.spellData.get(k)));
|
||||||
}
|
}
|
||||||
@@ -573,7 +589,15 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
|||||||
|
|
||||||
properties.setInteger("maxTierReached", maxTierReached.ordinal());
|
properties.setInteger("maxTierReached", maxTierReached.ordinal());
|
||||||
|
|
||||||
NBTExtras.storeTagSafely(properties, "recentSpells", NBTExtras.listToNBT(recentSpells, s -> new NBTTagInt(s.metadata())));
|
// Serialize recent spells with timestamps as compound tags
|
||||||
|
NBTTagList recentSpellsList = new NBTTagList();
|
||||||
|
for(SimpleEntry<Spell, Long> entry : recentSpells) {
|
||||||
|
NBTTagCompound spellTag = new NBTTagCompound();
|
||||||
|
spellTag.setInteger("spellId", entry.getKey().metadata());
|
||||||
|
spellTag.setLong("timestamp", entry.getValue());
|
||||||
|
recentSpellsList.appendTag(spellTag);
|
||||||
|
}
|
||||||
|
NBTExtras.storeTagSafely(properties, "recentSpells", recentSpellsList);
|
||||||
|
|
||||||
storedVariables.forEach(k -> k.write(properties, this.spellData.get(k)));
|
storedVariables.forEach(k -> k.write(properties, this.spellData.get(k)));
|
||||||
|
|
||||||
@@ -600,8 +624,14 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
|||||||
|
|
||||||
// Probably won't be null but we may as well just reinitialise it instead of clearing it
|
// Probably won't be null but we may as well just reinitialise it instead of clearing it
|
||||||
this.recentSpells = EvictingQueue.create(MAX_RECENT_SPELLS);
|
this.recentSpells = EvictingQueue.create(MAX_RECENT_SPELLS);
|
||||||
this.recentSpells.addAll(NBTExtras.NBTToList(nbt.getTagList("recentSpells", NBT.TAG_INT),
|
// Deserialize recent spells with timestamps
|
||||||
(NBTTagInt tag) -> Spell.byMetadata(tag.getInt())));
|
NBTTagList recentSpellsList = nbt.getTagList("recentSpells", NBT.TAG_COMPOUND);
|
||||||
|
for(int i = 0; i < recentSpellsList.tagCount(); i++) {
|
||||||
|
NBTTagCompound spellTag = recentSpellsList.getCompoundTagAt(i);
|
||||||
|
Spell spell = Spell.byMetadata(spellTag.getInteger("spellId"));
|
||||||
|
long timestamp = spellTag.getLong("timestamp");
|
||||||
|
this.recentSpells.add(new SimpleEntry<>(spell, timestamp));
|
||||||
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
storedVariables.forEach(k -> this.spellData.put(k, k.read(nbt)));
|
storedVariables.forEach(k -> this.spellData.put(k, k.read(nbt)));
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import java.util.Iterator;
|
|||||||
* than having to deal with each of them separately, which would be inefficient and cumbersome (the former of those
|
* than having to deal with each of them separately, which would be inefficient and cumbersome (the former of those
|
||||||
* classes cannot extend the latter because they both need to extend different subclasses of
|
* classes cannot extend the latter because they both need to extend different subclasses of
|
||||||
* {@link net.minecraft.enchantment.Enchantment}).
|
* {@link net.minecraft.enchantment.Enchantment}).
|
||||||
*
|
*
|
||||||
* @since Wizardry 1.2
|
* @since Wizardry 1.2
|
||||||
*/
|
*/
|
||||||
@Mod.EventBusSubscriber
|
@Mod.EventBusSubscriber
|
||||||
@@ -45,7 +45,8 @@ public interface Imbuement {
|
|||||||
public static void onLivingDropsEvent(LivingDropsEvent event){
|
public static void onLivingDropsEvent(LivingDropsEvent event){
|
||||||
// Instantly disenchants an imbued weapon if it is dropped when the player dies.
|
// Instantly disenchants an imbued weapon if it is dropped when the player dies.
|
||||||
for(EntityItem item : event.getDrops()){
|
for(EntityItem item : event.getDrops()){
|
||||||
removeImbuements(item.getItem());
|
// Apparently some mods don't behave and shove null items in the list, quite why I have no idea
|
||||||
|
if(item != null) removeImbuements(item.getItem());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,12 +69,16 @@ public interface Imbuement {
|
|||||||
Enchantment enchantment = Enchantment.getEnchantmentByID(enchantmentTag.getShort("id"));
|
Enchantment enchantment = Enchantment.getEnchantmentByID(enchantmentTag.getShort("id"));
|
||||||
// If the item contains a magic weapon enchantment, remove it from the item
|
// If the item contains a magic weapon enchantment, remove it from the item
|
||||||
if(enchantment instanceof Imbuement){
|
if(enchantment instanceof Imbuement){
|
||||||
|
((Imbuement) enchantment).onImbuementRemoval(stack);
|
||||||
enchantmentIt.remove();
|
enchantmentIt.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Allows executing some custom logic before this imbuement is being removed from the stack. Called when the imbuement is about to be removed. */
|
||||||
|
default void onImbuementRemoval(ItemStack stack){}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onPlayerOpenContainerEvent(PlayerContainerEvent event){
|
public static void onPlayerOpenContainerEvent(PlayerContainerEvent event){
|
||||||
// Brute-force fix to stop enchanted books in dungeon chests from having imbuements on them.
|
// Brute-force fix to stop enchanted books in dungeon chests from having imbuements on them.
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
package electroblob.wizardry.entity.construct;
|
package electroblob.wizardry.entity.construct;
|
||||||
|
|
||||||
|
import electroblob.wizardry.entity.projectile.EntityConjuredArrow;
|
||||||
import electroblob.wizardry.registry.Spells;
|
import electroblob.wizardry.registry.Spells;
|
||||||
import electroblob.wizardry.spell.Spell;
|
import electroblob.wizardry.spell.Spell;
|
||||||
import net.minecraft.entity.projectile.EntityTippedArrow;
|
|
||||||
import net.minecraft.init.Items;
|
|
||||||
import net.minecraft.item.ItemStack;
|
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
@@ -30,7 +28,7 @@ public class EntityArrowRain extends EntityScaledConstruct {
|
|||||||
double y = posY + world.rand.nextDouble() * (double)height;
|
double y = posY + world.rand.nextDouble() * (double)height;
|
||||||
double z = posZ + (world.rand.nextDouble() - 0.5D) * (double)width;
|
double z = posZ + (world.rand.nextDouble() - 0.5D) * (double)width;
|
||||||
|
|
||||||
EntityTippedArrow arrow = new EntityTippedArrow(world, x, y, z);
|
EntityConjuredArrow arrow = new EntityConjuredArrow(world, x, y, z);
|
||||||
|
|
||||||
arrow.motionX = MathHelper.cos((float)Math.toRadians(this.rotationYaw + 90));
|
arrow.motionX = MathHelper.cos((float)Math.toRadians(this.rotationYaw + 90));
|
||||||
arrow.motionY = -0.6;
|
arrow.motionY = -0.6;
|
||||||
@@ -38,7 +36,6 @@ public class EntityArrowRain extends EntityScaledConstruct {
|
|||||||
|
|
||||||
arrow.shootingEntity = this.getCaster();
|
arrow.shootingEntity = this.getCaster();
|
||||||
arrow.setDamage(7.0d * damageMultiplier);
|
arrow.setDamage(7.0d * damageMultiplier);
|
||||||
arrow.setPotionEffect(new ItemStack(Items.ARROW));
|
|
||||||
|
|
||||||
this.world.spawnEntity(arrow);
|
this.world.spawnEntity(arrow);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ public class EntityDecay extends EntityMagicConstruct {
|
|||||||
0.6F + rand.nextFloat() * 0.15F);
|
0.6F + rand.nextFloat() * 0.15F);
|
||||||
|
|
||||||
if(!this.world.isRemote){
|
if(!this.world.isRemote){
|
||||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(1.0d, this.posX, this.posY,
|
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(this.width/2f, this.posX, this.posY,
|
||||||
this.posZ, this.world);
|
this.posZ, this.height, this.world);
|
||||||
for(EntityLivingBase target : targets){
|
for(EntityLivingBase target : targets){
|
||||||
if(target != this.getCaster()){
|
if(target != this.getCaster()){
|
||||||
// If this check wasn't here the potion would be reapplied every tick and hence the entity would be
|
// If this check wasn't here the potion would be reapplied every tick and hence the entity would be
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ public class EntityFireRing extends EntityScaledConstruct {
|
|||||||
|
|
||||||
super.onUpdate();
|
super.onUpdate();
|
||||||
|
|
||||||
if(!this.world.isRemote){
|
if(this.ticksExisted % 5 == 0 && !this.world.isRemote){
|
||||||
|
|
||||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, this.posX, this.posY, this.posZ, this.world);
|
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(this.width/2, this.posX, this.posY, this.posZ, this.height, this.world);
|
||||||
|
|
||||||
for(EntityLivingBase target : targets){
|
for(EntityLivingBase target : targets){
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class EntityFireSigil extends EntityScaledConstruct {
|
|||||||
|
|
||||||
if(!this.world.isRemote){
|
if(!this.world.isRemote){
|
||||||
|
|
||||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, posX, posY, posZ, world);
|
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(this.width/2, this.posX, this.posY, this.posZ, this.height, this.world);
|
||||||
|
|
||||||
for(EntityLivingBase target : targets){
|
for(EntityLivingBase target : targets){
|
||||||
|
|
||||||
|
|||||||
@@ -146,30 +146,44 @@ public class EntityForcefield extends EntityMagicConstruct implements ICustomHit
|
|||||||
if(EntityUtils.isLiving(target)) nudgeVelocity = 0.25;
|
if(EntityUtils.isLiving(target)) nudgeVelocity = 0.25;
|
||||||
Vec3d extraVelocity = targetRelativePos.normalize().scale(nudgeVelocity);
|
Vec3d extraVelocity = targetRelativePos.normalize().scale(nudgeVelocity);
|
||||||
|
|
||||||
// ...make it bounce off!
|
//Moved up the check by "19" so that way allied players aren't being moved out of the forcefield because
|
||||||
target.motionX = target.motionX * -BOUNCINESS + extraVelocity.x;
|
//allied players aren't synced to client like minions. Minions are only synced because it's saved to their
|
||||||
target.motionY = target.motionY * -BOUNCINESS + extraVelocity.y;
|
//entity data which is synced in their serialize/deserialize methods
|
||||||
target.motionZ = target.motionZ * -BOUNCINESS + extraVelocity.z;
|
|
||||||
|
|
||||||
// Prevents the forcefield bouncing things into the floor
|
|
||||||
if(target.onGround && target.motionY < 0) target.motionY = 0.1;
|
|
||||||
|
|
||||||
// How far the target needs to move towards the centre (negative means away from the centre)
|
|
||||||
double distanceTowardsCentre = -(targetRelativePos.length() - radius) - (radius - nextTickDistance);
|
|
||||||
Vec3d targetNewPos = target.getPositionVector().add(targetRelativePos.normalize().scale(distanceTowardsCentre));
|
|
||||||
target.setPosition(targetNewPos.x, targetNewPos.y, targetNewPos.z);
|
|
||||||
|
|
||||||
world.playSound(target.posX, target.posY, target.posZ, WizardrySounds.ENTITY_FORCEFIELD_DEFLECT,
|
|
||||||
WizardrySounds.SPELLS, 0.3f, 1.3f, false);
|
|
||||||
|
|
||||||
if(!world.isRemote){
|
if(!world.isRemote){
|
||||||
|
// ...make it bounce off!
|
||||||
|
|
||||||
|
target.motionX = target.motionX * -BOUNCINESS + extraVelocity.x;
|
||||||
|
target.motionY = target.motionY * -BOUNCINESS + extraVelocity.y;
|
||||||
|
target.motionZ = target.motionZ * -BOUNCINESS + extraVelocity.z;
|
||||||
|
|
||||||
|
// Prevents the forcefield bouncing things into the floor
|
||||||
|
if(target.onGround && target.motionY < 0) target.motionY = 0.1;
|
||||||
|
|
||||||
|
// How far the target needs to move towards the centre (negative means away from the centre)
|
||||||
|
double distanceTowardsCentre = -(targetRelativePos.length() - radius) - (radius - nextTickDistance);
|
||||||
|
Vec3d targetNewPos = target.getPositionVector().add(targetRelativePos.normalize().scale(distanceTowardsCentre));
|
||||||
|
target.setPosition(targetNewPos.x, targetNewPos.y, targetNewPos.z);
|
||||||
|
|
||||||
|
world.playSound(target.posX, target.posY, target.posZ, WizardrySounds.ENTITY_FORCEFIELD_DEFLECT,
|
||||||
|
WizardrySounds.SPELLS, 0.3f, 1.3f, false);
|
||||||
|
|
||||||
|
|
||||||
// Player motion is handled on that player's client so needs packets
|
// Player motion is handled on that player's client so needs packets
|
||||||
if(target instanceof EntityPlayerMP){
|
if(target instanceof EntityPlayerMP){
|
||||||
((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target));
|
((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.ticksExisted % 5 == 0) {
|
||||||
|
this.lifetime = (int) (lifetime * 0.99);
|
||||||
|
}
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
|
|
||||||
|
//This is a super lazy way to make sure the visual isn't playing for players and probably won't display the visual
|
||||||
|
//for players if their velocity towards the forcefield is high. But it prevents the visual being spammed when ally player
|
||||||
|
//is in forcefield so it's fine #19
|
||||||
|
if(target instanceof EntityPlayer && target.getPositionVector().distanceTo(this.getPositionVector()) < this.getRadius()) return;
|
||||||
|
|
||||||
Vec3d relativeImpactPos = targetRelativePos.normalize().scale(radius);
|
Vec3d relativeImpactPos = targetRelativePos.normalize().scale(radius);
|
||||||
|
|
||||||
float yaw = (float)Math.atan2(relativeImpactPos.x, -relativeImpactPos.z);
|
float yaw = (float)Math.atan2(relativeImpactPos.x, -relativeImpactPos.z);
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ public class EntityFrostSigil extends EntityScaledConstruct {
|
|||||||
|
|
||||||
if(!this.world.isRemote){
|
if(!this.world.isRemote){
|
||||||
|
|
||||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, this.posX, this.posY,
|
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(width/2, this.posX, this.posY,
|
||||||
this.posZ, this.world);
|
this.posZ, this.height, this.world);
|
||||||
|
|
||||||
for(EntityLivingBase target : targets){
|
for(EntityLivingBase target : targets){
|
||||||
|
|
||||||
|
|||||||
@@ -33,30 +33,32 @@ public class EntityHealAura extends EntityScaledConstruct {
|
|||||||
|
|
||||||
if(!this.world.isRemote){
|
if(!this.world.isRemote){
|
||||||
|
|
||||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, posX, posY, posZ, world);
|
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(width/2, posX, posY, posZ, this.height, world);
|
||||||
|
|
||||||
for(EntityLivingBase target : targets){
|
for(EntityLivingBase target : targets){
|
||||||
|
|
||||||
if(this.isValidTarget(target)){
|
if(this.isValidTarget(target)){
|
||||||
|
|
||||||
if(target.isEntityUndead()){
|
if(target.isEntityUndead()) {
|
||||||
|
|
||||||
double velX = target.motionX;
|
double velX = target.motionX;
|
||||||
double velY = target.motionY;
|
double velY = target.motionY;
|
||||||
double velZ = target.motionZ;
|
double velZ = target.motionZ;
|
||||||
|
|
||||||
if(this.getCaster() != null){
|
if (this.ticksExisted % 10 == 1) {
|
||||||
target.attackEntityFrom(
|
if (this.getCaster() != null) {
|
||||||
MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.RADIANT),
|
target.attackEntityFrom(
|
||||||
Spells.healing_aura.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier);
|
MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.RADIANT),
|
||||||
}else{
|
Spells.healing_aura.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier);
|
||||||
target.attackEntityFrom(DamageSource.MAGIC, Spells.healing_aura.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier);
|
} else {
|
||||||
}
|
target.attackEntityFrom(DamageSource.MAGIC, Spells.healing_aura.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier);
|
||||||
|
}
|
||||||
|
|
||||||
// Removes knockback
|
// Removes knockback
|
||||||
target.motionX = velX;
|
target.motionX = velX;
|
||||||
target.motionY = velY;
|
target.motionY = velY;
|
||||||
target.motionZ = velZ;
|
target.motionZ = velZ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}else if(target.getHealth() < target.getMaxHealth() && target.ticksExisted % 5 == 0){
|
}else if(target.getHealth() < target.getMaxHealth() && target.ticksExisted % 5 == 0){
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ public class EntityLightningSigil extends EntityScaledConstruct {
|
|||||||
this.setDead();
|
this.setDead();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, this.posX, this.posY,
|
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(this.width/2, this.posX, this.posY,
|
||||||
this.posZ, this.world);
|
this.posZ, this.height, this.world);
|
||||||
|
|
||||||
for(EntityLivingBase target : targets){
|
for(EntityLivingBase target : targets){
|
||||||
|
|
||||||
|
|||||||
@@ -68,13 +68,15 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
|||||||
/** Data parameter for the wizard's element. */
|
/** Data parameter for the wizard's element. */
|
||||||
private static final DataParameter<Integer> ELEMENT = EntityDataManager.createKey(EntityEvilWizard.class,
|
private static final DataParameter<Integer> ELEMENT = EntityDataManager.createKey(EntityEvilWizard.class,
|
||||||
DataSerializers.VARINT);
|
DataSerializers.VARINT);
|
||||||
|
/** Data parameters for the wizard's current continuous spell. */
|
||||||
|
private static final DataParameter<String> CONTINUOUS_SPELL = EntityDataManager.createKey(EntityEvilWizard.class, DataSerializers.STRING);
|
||||||
|
private static final DataParameter<Integer> SPELL_COUNTER = EntityDataManager.createKey(EntityEvilWizard.class, DataSerializers.VARINT);
|
||||||
|
|
||||||
/** The resource location for the evil wizard's loot table. */
|
/** The resource location for the evil wizard's loot table. */
|
||||||
private static final ResourceLocation LOOT_TABLE = new ResourceLocation(Wizardry.MODID, "entities/evil_wizard");
|
private static final ResourceLocation LOOT_TABLE = new ResourceLocation(Wizardry.MODID, "entities/evil_wizard");
|
||||||
|
|
||||||
// Field implementations
|
// Field implementations
|
||||||
private List<Spell> spells = new ArrayList<Spell>(4);
|
private List<Spell> spells = new ArrayList<Spell>(4);
|
||||||
private Spell continuousSpell;
|
|
||||||
private int spellCounter;
|
|
||||||
|
|
||||||
public EntityEvilWizard(World world){
|
public EntityEvilWizard(World world){
|
||||||
|
|
||||||
@@ -93,6 +95,8 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
|||||||
super.entityInit();
|
super.entityInit();
|
||||||
this.dataManager.register(HEAL_COOLDOWN, -1);
|
this.dataManager.register(HEAL_COOLDOWN, -1);
|
||||||
this.dataManager.register(ELEMENT, -1);
|
this.dataManager.register(ELEMENT, -1);
|
||||||
|
this.dataManager.register(CONTINUOUS_SPELL, "ebwizardry:none");
|
||||||
|
this.dataManager.register(SPELL_COUNTER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -168,23 +172,23 @@ public class EntityEvilWizard extends EntityMob implements ISpellCaster, IEntity
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setContinuousSpell(Spell spell){
|
public void setContinuousSpell(Spell spell) {
|
||||||
this.continuousSpell = spell;
|
this.dataManager.set(CONTINUOUS_SPELL, spell.getRegistryName().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Spell getContinuousSpell(){
|
public Spell getContinuousSpell() {
|
||||||
return this.continuousSpell;
|
return Spell.get(this.dataManager.get(CONTINUOUS_SPELL));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSpellCounter(int count){
|
public void setSpellCounter(int count) {
|
||||||
spellCounter = count;
|
this.dataManager.set(SPELL_COUNTER, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSpellCounter(){
|
public int getSpellCounter() {
|
||||||
return spellCounter;
|
return this.dataManager.get(SPELL_COUNTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public class EntityMagicSlime extends EntitySlime implements ISummonedCreature {
|
|||||||
super(world);
|
super(world);
|
||||||
this.setPosition(target.posX, target.posY, target.posZ);
|
this.setPosition(target.posX, target.posY, target.posZ);
|
||||||
this.startRiding(target);
|
this.startRiding(target);
|
||||||
this.setOwnerId(caster.getUniqueID());
|
if (caster != null) this.setOwnerId(caster.getUniqueID());
|
||||||
this.setSlimeSize(2, false); // Needs to be called before setting the experience value to 0
|
this.setSlimeSize(2, false); // Needs to be called before setting the experience value to 0
|
||||||
this.experienceValue = 0;
|
this.experienceValue = 0;
|
||||||
this.lifetime = lifetime;
|
this.lifetime = lifetime;
|
||||||
|
|||||||
@@ -225,6 +225,7 @@ public class EntityRemnant extends EntityMob {
|
|||||||
@Override
|
@Override
|
||||||
public void startExecuting(){
|
public void startExecuting(){
|
||||||
EntityLivingBase entitylivingbase = EntityRemnant.this.getAttackTarget();
|
EntityLivingBase entitylivingbase = EntityRemnant.this.getAttackTarget();
|
||||||
|
if(entitylivingbase == null) return;
|
||||||
Vec3d vec3d = entitylivingbase.getPositionEyes(1.0F);
|
Vec3d vec3d = entitylivingbase.getPositionEyes(1.0F);
|
||||||
EntityRemnant.this.moveHelper.setMoveTo(vec3d.x, vec3d.y, vec3d.z, 1.0D);
|
EntityRemnant.this.moveHelper.setMoveTo(vec3d.x, vec3d.y, vec3d.z, 1.0D);
|
||||||
EntityRemnant.this.setAttacking(true);
|
EntityRemnant.this.setAttacking(true);
|
||||||
@@ -241,6 +242,8 @@ public class EntityRemnant extends EntityMob {
|
|||||||
|
|
||||||
EntityLivingBase entitylivingbase = EntityRemnant.this.getAttackTarget();
|
EntityLivingBase entitylivingbase = EntityRemnant.this.getAttackTarget();
|
||||||
|
|
||||||
|
if(entitylivingbase == null) return;
|
||||||
|
|
||||||
if(EntityRemnant.this.getEntityBoundingBox().intersects(entitylivingbase.getEntityBoundingBox())){
|
if(EntityRemnant.this.getEntityBoundingBox().intersects(entitylivingbase.getEntityBoundingBox())){
|
||||||
EntityRemnant.this.attackEntityAsMob(entitylivingbase);
|
EntityRemnant.this.attackEntityAsMob(entitylivingbase);
|
||||||
EntityRemnant.this.setAttacking(false);
|
EntityRemnant.this.setAttacking(false);
|
||||||
|
|||||||
@@ -0,0 +1,192 @@
|
|||||||
|
package electroblob.wizardry.entity.living;
|
||||||
|
|
||||||
|
import electroblob.wizardry.Wizardry;
|
||||||
|
import electroblob.wizardry.util.ParticleBuilder;
|
||||||
|
import net.minecraft.entity.EntityFlying;
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
|
import net.minecraft.entity.ai.EntityAIAttackMelee;
|
||||||
|
import net.minecraft.entity.ai.EntityAIHurtByTarget;
|
||||||
|
import net.minecraft.entity.ai.EntityAILookAtVillager;
|
||||||
|
import net.minecraft.entity.ai.EntityAILookIdle;
|
||||||
|
import net.minecraft.entity.ai.EntityAIMoveThroughVillage;
|
||||||
|
import net.minecraft.entity.ai.EntityAIMoveTowardsRestriction;
|
||||||
|
import net.minecraft.entity.ai.EntityAIMoveTowardsTarget;
|
||||||
|
import net.minecraft.entity.ai.EntityAINearestAttackableTarget;
|
||||||
|
import net.minecraft.entity.ai.EntityAIWanderAvoidWater;
|
||||||
|
import net.minecraft.entity.ai.EntityAIWatchClosest;
|
||||||
|
import net.minecraft.entity.monster.EntityIronGolem;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.network.datasync.DataParameter;
|
||||||
|
import net.minecraft.network.datasync.DataSerializers;
|
||||||
|
import net.minecraft.network.datasync.EntityDataManager;
|
||||||
|
import net.minecraft.util.EnumHand;
|
||||||
|
import net.minecraft.util.EnumParticleTypes;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraft.util.text.ITextComponent;
|
||||||
|
import net.minecraft.util.text.TextComponentTranslation;
|
||||||
|
import net.minecraft.world.DifficultyInstance;
|
||||||
|
import net.minecraft.world.EnumDifficulty;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class EntitySpectralGolem extends EntityIronGolem implements ISummonedCreature {
|
||||||
|
|
||||||
|
private static final DataParameter<Boolean> SPAWN_PARTICLES = EntityDataManager.createKey(EntitySpectralGolem.class, DataSerializers.BOOLEAN);
|
||||||
|
|
||||||
|
// Field implementations
|
||||||
|
private int lifetime = -1;
|
||||||
|
private UUID casterUUID;
|
||||||
|
|
||||||
|
// Setter + getter implementations
|
||||||
|
@Override public int getLifetime(){ return lifetime; }
|
||||||
|
@Override public void setLifetime(int lifetime){ this.lifetime = lifetime; }
|
||||||
|
@Override public UUID getOwnerId(){ return casterUUID; }
|
||||||
|
@Override public void setOwnerId(UUID uuid){ this.casterUUID = uuid; }
|
||||||
|
|
||||||
|
/** Creates a new golem minion in the given world. */
|
||||||
|
public EntitySpectralGolem(World world){
|
||||||
|
super(world);
|
||||||
|
this.experienceValue = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void entityInit(){
|
||||||
|
super.entityInit();
|
||||||
|
this.dataManager.register(SPAWN_PARTICLES, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initEntityAI() {
|
||||||
|
this.tasks.addTask(1, new EntityAIAttackMelee(this, 1.0D, true));
|
||||||
|
this.tasks.addTask(2, new EntityAIMoveTowardsTarget(this, 0.9D, 32.0F));
|
||||||
|
this.tasks.addTask(3, new EntityAIMoveThroughVillage(this, 0.6D, true));
|
||||||
|
this.tasks.addTask(4, new EntityAIMoveTowardsRestriction(this, 1.0D));
|
||||||
|
this.tasks.addTask(5, new EntityAILookAtVillager(this));
|
||||||
|
this.tasks.addTask(6, new EntityAIWanderAvoidWater(this, 0.6D));
|
||||||
|
this.tasks.addTask(7, new EntityAIWatchClosest(this, EntityPlayer.class, 6.0F));
|
||||||
|
this.tasks.addTask(8, new EntityAILookIdle(this));
|
||||||
|
this.targetTasks.addTask(1, new EntityAIHurtByTarget(this, false));
|
||||||
|
this.targetTasks.addTask(2, new EntityAINearestAttackableTarget<>(this, EntityLivingBase.class,
|
||||||
|
0, false, true, this.getTargetSelector()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override protected void setEquipmentBasedOnDifficulty(DifficultyInstance difficulty){} // They don't have equipment!
|
||||||
|
|
||||||
|
// Implementations
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRevengeTarget(EntityLivingBase entity){
|
||||||
|
if(this.shouldRevengeTarget(entity)) super.setRevengeTarget(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpdate(){
|
||||||
|
super.onUpdate();
|
||||||
|
this.updateDelegate();
|
||||||
|
|
||||||
|
// Adds a dust particle effect
|
||||||
|
if(this.world.isRemote){
|
||||||
|
double x = this.posX - this.width / 2 + this.rand.nextFloat() * width;
|
||||||
|
double y = this.posY + this.height * this.rand.nextFloat() + 0.2f;
|
||||||
|
double z = this.posZ - this.width / 2 + this.rand.nextFloat() * width;
|
||||||
|
ParticleBuilder.create(ParticleBuilder.Type.DUST).pos(x, y, z).clr(0.7f, 0.9f, 1).shaded(true).spawn(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSpawn(){
|
||||||
|
if(this.dataManager.get(SPAWN_PARTICLES)) this.spawnParticleEffect();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDespawn(){
|
||||||
|
this.spawnParticleEffect();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void spawnParticleEffect(){
|
||||||
|
if(this.world.isRemote){
|
||||||
|
for(int i = 0; i < 15; i++){
|
||||||
|
this.world.spawnParticle(EnumParticleTypes.SMOKE_LARGE, this.posX + this.rand.nextFloat() - 0.5f,
|
||||||
|
this.posY + this.rand.nextFloat() * 2, this.posZ + this.rand.nextFloat() - 0.5f, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasParticleEffect(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasAnimation(){
|
||||||
|
return this.dataManager.get(SPAWN_PARTICLES) || this.ticksExisted > 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hideParticles(){
|
||||||
|
this.dataManager.set(SPAWN_PARTICLES, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean processInteract(EntityPlayer player, EnumHand hand){
|
||||||
|
// In this case, the delegate method determines whether super is called.
|
||||||
|
// Rather handily, we can make use of Java's short-circuiting method of evaluating OR statements.
|
||||||
|
return this.interactDelegate(player, hand) || super.processInteract(player, hand);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeEntityToNBT(NBTTagCompound nbttagcompound){
|
||||||
|
super.writeEntityToNBT(nbttagcompound);
|
||||||
|
this.writeNBTDelegate(nbttagcompound);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readEntityFromNBT(NBTTagCompound nbttagcompound){
|
||||||
|
super.readEntityFromNBT(nbttagcompound);
|
||||||
|
this.readNBTDelegate(nbttagcompound);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recommended overrides
|
||||||
|
|
||||||
|
@Override protected int getExperiencePoints(EntityPlayer player){ return 0; }
|
||||||
|
@Override protected boolean canDropLoot(){ return false; }
|
||||||
|
@Override protected Item getDropItem(){ return null; }
|
||||||
|
@Override protected ResourceLocation getLootTable(){ return null; }
|
||||||
|
@Override public boolean canPickUpLoot(){ return false; }
|
||||||
|
|
||||||
|
// This vanilla method has nothing to do with the custom despawn() method.
|
||||||
|
@Override protected boolean canDespawn(){
|
||||||
|
return getCaster() == null && getOwnerId() == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getCanSpawnHere(){
|
||||||
|
return this.world.getDifficulty() != EnumDifficulty.PEACEFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canAttackClass(Class<? extends EntityLivingBase> entityType){
|
||||||
|
// Returns true unless the given entity type is a flying entity.
|
||||||
|
return !EntityFlying.class.isAssignableFrom(entityType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ITextComponent getDisplayName(){
|
||||||
|
if(getCaster() != null){
|
||||||
|
return new TextComponentTranslation(NAMEPLATE_TRANSLATION_KEY, getCaster().getName(),
|
||||||
|
new TextComponentTranslation("entity." + this.getEntityString() + ".name"));
|
||||||
|
}else{
|
||||||
|
return super.getDisplayName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasCustomName(){
|
||||||
|
// If this returns true, the renderer will show the nameplate when looking directly at the entity
|
||||||
|
return Wizardry.settings.summonedCreatureNames && getCaster() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -47,6 +47,7 @@ import net.minecraftforge.common.util.FakePlayer;
|
|||||||
import net.minecraftforge.event.world.BlockEvent;
|
import net.minecraftforge.event.world.BlockEvent;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
|
import net.minecraftforge.fml.common.registry.ForgeRegistries;
|
||||||
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
|
import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData;
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
@@ -67,7 +68,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
|||||||
protected Predicate<Entity> targetSelector;
|
protected Predicate<Entity> targetSelector;
|
||||||
|
|
||||||
/** The wizard's trades. */
|
/** The wizard's trades. */
|
||||||
private MerchantRecipeList trades;
|
public MerchantRecipeList trades;
|
||||||
/** The wizard's current customer. */
|
/** The wizard's current customer. */
|
||||||
@Nullable
|
@Nullable
|
||||||
private EntityPlayer customer;
|
private EntityPlayer customer;
|
||||||
@@ -81,11 +82,12 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
|||||||
private static final DataParameter<Integer> HEAL_COOLDOWN = EntityDataManager.createKey(EntityWizard.class, DataSerializers.VARINT);
|
private static final DataParameter<Integer> HEAL_COOLDOWN = EntityDataManager.createKey(EntityWizard.class, DataSerializers.VARINT);
|
||||||
/** Data parameter for the wizard's element. */
|
/** Data parameter for the wizard's element. */
|
||||||
private static final DataParameter<Integer> ELEMENT = EntityDataManager.createKey(EntityWizard.class, DataSerializers.VARINT);
|
private static final DataParameter<Integer> ELEMENT = EntityDataManager.createKey(EntityWizard.class, DataSerializers.VARINT);
|
||||||
|
/** Data parameters for the wizard's current continuous spell. */
|
||||||
|
private static final DataParameter<String> CONTINUOUS_SPELL = EntityDataManager.createKey(EntityWizard.class, DataSerializers.STRING);
|
||||||
|
private static final DataParameter<Integer> SPELL_COUNTER = EntityDataManager.createKey(EntityWizard.class, DataSerializers.VARINT);
|
||||||
|
|
||||||
// Field implementations
|
// Field implementations
|
||||||
private List<Spell> spells = new ArrayList<Spell>(4);
|
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. */
|
/** A set of the positions of the blocks that are part of this wizard's tower. */
|
||||||
private Set<BlockPos> towerBlocks;
|
private Set<BlockPos> towerBlocks;
|
||||||
@@ -102,6 +104,8 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
|||||||
super.entityInit();
|
super.entityInit();
|
||||||
this.dataManager.register(HEAL_COOLDOWN, -1);
|
this.dataManager.register(HEAL_COOLDOWN, -1);
|
||||||
this.dataManager.register(ELEMENT, 0);
|
this.dataManager.register(ELEMENT, 0);
|
||||||
|
this.dataManager.register(CONTINUOUS_SPELL, "ebwizardry:none");
|
||||||
|
this.dataManager.register(SPELL_COUNTER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -126,8 +130,12 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
|||||||
if(entity != null && !entity.isInvisible()
|
if(entity != null && !entity.isInvisible()
|
||||||
&& AllyDesignationSystem.isValidTarget(EntityWizard.this, entity)){
|
&& AllyDesignationSystem.isValidTarget(EntityWizard.this, entity)){
|
||||||
|
|
||||||
// ... and is a mob, a summoned creature ...
|
// ... and is a non summoned creature mob ...
|
||||||
if((entity instanceof IMob || entity instanceof ISummonedCreature
|
if((entity instanceof IMob && !(entity instanceof ISummonedCreature)
|
||||||
|
|
||||||
|
// or is a summoned creature with a mob owner or an owner who has attacked the wizard ...
|
||||||
|
|| entity instanceof ISummonedCreature && (((ISummonedCreature)entity).getOwner() instanceof IMob || ((ISummonedCreature)entity).getOwner() == this.getRevengeTarget() || ((ISummonedCreature) entity).getOwner() == this.getAttackTarget())
|
||||||
|
|
||||||
// ... or in the whitelist ...
|
// ... or in the whitelist ...
|
||||||
|| Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist)
|
|| Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist)
|
||||||
.contains(EntityList.getKey(entity.getClass())))
|
.contains(EntityList.getKey(entity.getClass())))
|
||||||
@@ -182,23 +190,23 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setContinuousSpell(Spell spell){
|
public void setContinuousSpell(Spell spell) {
|
||||||
this.continuousSpell = spell;
|
this.dataManager.set(CONTINUOUS_SPELL, spell.getRegistryName().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Spell getContinuousSpell(){
|
public Spell getContinuousSpell() {
|
||||||
return this.continuousSpell;
|
return Spell.get(this.dataManager.get(CONTINUOUS_SPELL));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSpellCounter(int count){
|
public void setSpellCounter(int count) {
|
||||||
spellCounter = count;
|
this.dataManager.set(SPELL_COUNTER, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSpellCounter(){
|
public int getSpellCounter() {
|
||||||
return spellCounter;
|
return this.dataManager.get(SPELL_COUNTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -609,7 +617,10 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
|||||||
// ((tier.ordinal() + 1) * 16 + rand.nextInt(6)) gives a 'value' for the item being bought
|
// ((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
|
// 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.
|
// The absolute maximum stack size that can result from this calculation (with value = 1) is 64.
|
||||||
return new ItemStack(item, MathHelper.clamp((8 + tier.ordinal() * 16 + rand.nextInt(9)) / value, 1, 64), meta);
|
ItemStack result = new ItemStack(item, MathHelper.clamp((8 + tier.ordinal() * 16 + rand.nextInt(9)) / value, 1, 64), meta);
|
||||||
|
NBTTagCompound nbt = Wizardry.settings.currencyItemNbt.get(itemName);
|
||||||
|
if(nbt != null) result.setTagCompound(nbt.copy());
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ItemStack getRandomItemOfTier(Tier tier){
|
private ItemStack getRandomItemOfTier(Tier tier){
|
||||||
@@ -634,10 +645,9 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
|||||||
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0 && !specialismSpells.isEmpty()){
|
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0 && !specialismSpells.isEmpty()){
|
||||||
// This means it is more likely for spell books sold to be of the same element as the wizard if the
|
// This means it is more likely for spell books sold to be of the same element as the wizard if the
|
||||||
// wizard has an element.
|
// wizard has an element.
|
||||||
return new ItemStack(WizardryItems.spell_book, 1,
|
return getBookStackForSpell(specialismSpells.get(rand.nextInt(specialismSpells.size())));
|
||||||
specialismSpells.get(rand.nextInt(specialismSpells.size())).metadata());
|
|
||||||
}else{
|
}else{
|
||||||
return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).metadata());
|
return getBookStackForSpell(spells.get(rand.nextInt(spells.size())));
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){
|
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){
|
||||||
@@ -656,10 +666,9 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
|||||||
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0 && !specialismSpells.isEmpty()){
|
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0 && !specialismSpells.isEmpty()){
|
||||||
// This means it is more likely for spell books sold to be of the same element as the wizard if the
|
// This means it is more likely for spell books sold to be of the same element as the wizard if the
|
||||||
// wizard has an element.
|
// wizard has an element.
|
||||||
return new ItemStack(WizardryItems.spell_book, 1,
|
return getBookStackForSpell(specialismSpells.get(rand.nextInt(specialismSpells.size())));
|
||||||
specialismSpells.get(rand.nextInt(specialismSpells.size())).metadata());
|
|
||||||
}else{
|
}else{
|
||||||
return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).metadata());
|
return getBookStackForSpell(spells.get(rand.nextInt(spells.size())));
|
||||||
}
|
}
|
||||||
}else if(randomiser < 6){
|
}else if(randomiser < 6){
|
||||||
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){
|
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){
|
||||||
@@ -693,10 +702,9 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
|||||||
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0 && !specialismSpells.isEmpty()){
|
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0 && !specialismSpells.isEmpty()){
|
||||||
// This means it is more likely for spell books sold to be of the same element as the wizard if the
|
// This means it is more likely for spell books sold to be of the same element as the wizard if the
|
||||||
// wizard has an element.
|
// wizard has an element.
|
||||||
return new ItemStack(WizardryItems.spell_book, 1,
|
return getBookStackForSpell(specialismSpells.get(rand.nextInt(specialismSpells.size())));
|
||||||
specialismSpells.get(rand.nextInt(specialismSpells.size())).metadata());
|
|
||||||
}else{
|
}else{
|
||||||
return new ItemStack(WizardryItems.spell_book, 1, spells.get(rand.nextInt(spells.size())).metadata());
|
return getBookStackForSpell(spells.get(rand.nextInt(spells.size())));
|
||||||
}
|
}
|
||||||
}else if(randomiser < 6){
|
}else if(randomiser < 6){
|
||||||
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){
|
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){
|
||||||
@@ -721,8 +729,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
|||||||
|
|
||||||
if(randomiser < 5 && this.getElement() != Element.MAGIC && !specialismSpells.isEmpty()){
|
if(randomiser < 5 && this.getElement() != Element.MAGIC && !specialismSpells.isEmpty()){
|
||||||
// Master spells can only be sold by a specialist in that element.
|
// Master spells can only be sold by a specialist in that element.
|
||||||
return new ItemStack(WizardryItems.spell_book, 1,
|
return getBookStackForSpell(specialismSpells.get(rand.nextInt(specialismSpells.size())));
|
||||||
specialismSpells.get(rand.nextInt(specialismSpells.size())).metadata());
|
|
||||||
|
|
||||||
}else if(randomiser < 6){
|
}else if(randomiser < 6){
|
||||||
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){
|
if(this.getElement() != Element.MAGIC && rand.nextInt(4) > 0){
|
||||||
@@ -798,7 +805,6 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
|||||||
Tier maxTier = Tier.NOVICE;
|
Tier maxTier = Tier.NOVICE;
|
||||||
|
|
||||||
List<Spell> npcSpells = Spell.getSpells(s -> s.canBeCastBy(wizard, false));
|
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++){
|
for(int i = 0; i < n; i++){
|
||||||
|
|
||||||
@@ -846,6 +852,22 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
|||||||
return maxTier;
|
return maxTier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to handle addon spell books.
|
||||||
|
* @param spell the spell to look up.
|
||||||
|
* @return Checks all items of the spell's namespace (modid) if they are applicable for the spell and returns the first match, or falls back to WizardryItems.spell_book if no match was found.
|
||||||
|
*/
|
||||||
|
public static ItemStack getBookStackForSpell(Spell spell) {
|
||||||
|
String modid = spell.getRegistryName().getNamespace();
|
||||||
|
if (modid.equals(Wizardry.MODID)) {
|
||||||
|
return new ItemStack(WizardryItems.spell_book, 1, spell.metadata());
|
||||||
|
}
|
||||||
|
Optional<Item> firstMatch = ForgeRegistries.ITEMS.getValuesCollection().stream().filter(v -> v instanceof ItemSpellBook && spell.applicableForItem(v)
|
||||||
|
&& v.getRegistryName().getNamespace().equals(modid)).findFirst();
|
||||||
|
|
||||||
|
return firstMatch.map(item -> new ItemStack(item, 1, spell.metadata())).orElseGet(() -> new ItemStack(WizardryItems.spell_book, 1, spell.metadata()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeSpawnData(ByteBuf data){
|
public void writeSpawnData(ByteBuf data){
|
||||||
data.writeInt(textureIndex);
|
data.writeInt(textureIndex);
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package electroblob.wizardry.entity.projectile;
|
||||||
|
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
|
import net.minecraft.entity.projectile.EntityArrow;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
public class EntityConjuredArrow extends EntityArrow {
|
||||||
|
|
||||||
|
public EntityConjuredArrow(World worldIn) {
|
||||||
|
super(worldIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityConjuredArrow(World worldIn, double x, double y, double z) {
|
||||||
|
super(worldIn, x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityConjuredArrow(World worldIn, EntityLivingBase shooter) {
|
||||||
|
super(worldIn, shooter);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUpdate() {
|
||||||
|
super.onUpdate();
|
||||||
|
if (this.timeInGround > 400) {
|
||||||
|
this.setDead();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ItemStack getArrowStack() {
|
||||||
|
return ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
package electroblob.wizardry.entity.projectile;
|
package electroblob.wizardry.entity.projectile;
|
||||||
|
|
||||||
|
import electroblob.wizardry.packet.PacketBombExplosion;
|
||||||
|
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||||
import electroblob.wizardry.registry.Spells;
|
import electroblob.wizardry.registry.Spells;
|
||||||
import electroblob.wizardry.registry.WizardrySounds;
|
import electroblob.wizardry.registry.WizardrySounds;
|
||||||
import electroblob.wizardry.spell.Spell;
|
import electroblob.wizardry.spell.Spell;
|
||||||
import electroblob.wizardry.util.EntityUtils;
|
import electroblob.wizardry.util.EntityUtils;
|
||||||
import electroblob.wizardry.util.MagicDamage;
|
import electroblob.wizardry.util.MagicDamage;
|
||||||
import electroblob.wizardry.util.MagicDamage.DamageType;
|
import electroblob.wizardry.util.MagicDamage.DamageType;
|
||||||
import electroblob.wizardry.util.ParticleBuilder;
|
|
||||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.EntityLivingBase;
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
import net.minecraft.util.EnumParticleTypes;
|
|
||||||
import net.minecraft.util.math.RayTraceResult;
|
import net.minecraft.util.math.RayTraceResult;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -29,41 +29,28 @@ public class EntityFirebomb extends EntityBomb {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onImpact(RayTraceResult rayTrace){
|
protected void onImpact(RayTraceResult rayTrace){
|
||||||
|
|
||||||
Entity entityHit = rayTrace.entityHit;
|
|
||||||
|
|
||||||
if(entityHit != null){
|
|
||||||
// This is if the firebomb gets a direct hit
|
|
||||||
float damage = Spells.firebomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier;
|
|
||||||
|
|
||||||
entityHit.attackEntityFrom(
|
|
||||||
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE).setProjectile(),
|
|
||||||
damage);
|
|
||||||
|
|
||||||
if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit))
|
|
||||||
entityHit.setFire(Spells.firebomb.getProperty(Spell.BURN_DURATION).intValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Particle effect
|
|
||||||
if(world.isRemote){
|
|
||||||
|
|
||||||
ParticleBuilder.create(Type.FLASH).pos(this.getPositionVector()).scale(5 * blastMultiplier).clr(1, 0.6f, 0)
|
|
||||||
.spawn(world);
|
|
||||||
|
|
||||||
for(int i = 0; i < 60 * blastMultiplier; i++){
|
|
||||||
|
|
||||||
ParticleBuilder.create(Type.MAGIC_FIRE, rand, posX, posY, posZ, 2*blastMultiplier, false)
|
|
||||||
.time(10 + rand.nextInt(4)).scale(2 + rand.nextFloat()).spawn(world);
|
|
||||||
|
|
||||||
ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false)
|
|
||||||
.clr(1.0f, 0.2f + rand.nextFloat() * 0.4f, 0.0f).spawn(world);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!this.world.isRemote){
|
if(!this.world.isRemote){
|
||||||
|
|
||||||
|
Entity entityHit = rayTrace.entityHit;
|
||||||
|
|
||||||
|
if(entityHit != null){
|
||||||
|
// This is if the firebomb gets a direct hit
|
||||||
|
float damage = Spells.firebomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier;
|
||||||
|
|
||||||
|
entityHit.attackEntityFrom(
|
||||||
|
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE).setProjectile(),
|
||||||
|
damage);
|
||||||
|
|
||||||
|
if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit))
|
||||||
|
entityHit.setFire(Spells.firebomb.getProperty(Spell.BURN_DURATION).intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify clients to play the explosion effect
|
||||||
|
WizardryPacketHandler.net.sendToAllAround(
|
||||||
|
new PacketBombExplosion.Message(PacketBombExplosion.FIREBOMB, posX, posY, posZ, blastMultiplier),
|
||||||
|
new NetworkRegistry.TargetPoint(world.provider.getDimension(), posX, posY, posZ, 64));
|
||||||
|
|
||||||
this.playSound(WizardrySounds.ENTITY_FIREBOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F);
|
this.playSound(WizardrySounds.ENTITY_FIREBOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F);
|
||||||
this.playSound(WizardrySounds.ENTITY_FIREBOMB_FIRE, 1, 1);
|
this.playSound(WizardrySounds.ENTITY_FIREBOMB_FIRE, 1, 1);
|
||||||
|
|
||||||
@@ -82,9 +69,9 @@ public class EntityFirebomb extends EntityBomb {
|
|||||||
target.setFire(Spells.firebomb.getProperty(Spell.BURN_DURATION).intValue());
|
target.setFire(Spells.firebomb.getProperty(Spell.BURN_DURATION).intValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setDead();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setDead();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,14 @@ import electroblob.wizardry.Wizardry;
|
|||||||
import electroblob.wizardry.registry.Spells;
|
import electroblob.wizardry.registry.Spells;
|
||||||
import electroblob.wizardry.spell.Spell;
|
import electroblob.wizardry.spell.Spell;
|
||||||
import electroblob.wizardry.util.EntityUtils;
|
import electroblob.wizardry.util.EntityUtils;
|
||||||
|
import electroblob.wizardry.util.MagicDamage;
|
||||||
|
import electroblob.wizardry.util.MagicDamage.DamageType;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.monster.EntityGhast;
|
||||||
import net.minecraft.entity.projectile.EntityLargeFireball;
|
import net.minecraft.entity.projectile.EntityLargeFireball;
|
||||||
import net.minecraft.nbt.NBTTagCompound;
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.util.DamageSource;
|
||||||
import net.minecraft.util.math.RayTraceResult;
|
import net.minecraft.util.math.RayTraceResult;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
|
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
|
||||||
@@ -47,6 +52,15 @@ public class EntityLargeMagicFireball extends EntityMagicFireball {
|
|||||||
return damage == -1 ? Spells.greater_fireball.getProperty(Spell.DAMAGE).floatValue() : damage;
|
return damage == -1 ? Spells.greater_fireball.getProperty(Spell.DAMAGE).floatValue() : damage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected DamageSource getDamageSource(Entity entityHit){
|
||||||
|
if(entityHit instanceof EntityGhast){
|
||||||
|
return MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.MAGIC).setProjectile();
|
||||||
|
}else{
|
||||||
|
return super.getDamageSource(entityHit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onImpact(RayTraceResult rayTrace){
|
protected void onImpact(RayTraceResult rayTrace){
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import electroblob.wizardry.util.ParticleBuilder;
|
|||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.EntityLivingBase;
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
|
import net.minecraft.entity.monster.EntityGhast;
|
||||||
import net.minecraft.entity.projectile.EntitySmallFireball;
|
import net.minecraft.entity.projectile.EntitySmallFireball;
|
||||||
import net.minecraft.init.Blocks;
|
import net.minecraft.init.Blocks;
|
||||||
import net.minecraft.nbt.NBTTagCompound;
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
@@ -75,9 +76,9 @@ public class EntityMagicFireball extends EntityMagicProjectile {
|
|||||||
|
|
||||||
float damage = getDamage() * damageMultiplier;
|
float damage = getDamage() * damageMultiplier;
|
||||||
|
|
||||||
entityHit.attackEntityFrom(
|
DamageSource source = getDamageSource(entityHit);
|
||||||
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE).setProjectile(),
|
|
||||||
damage);
|
entityHit.attackEntityFrom(source, damage);
|
||||||
|
|
||||||
if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit) && getBurnDuration() > 0)
|
if(!MagicDamage.isEntityImmune(DamageType.FIRE, entityHit) && getBurnDuration() > 0)
|
||||||
entityHit.setFire(getBurnDuration());
|
entityHit.setFire(getBurnDuration());
|
||||||
@@ -99,6 +100,10 @@ public class EntityMagicFireball extends EntityMagicProjectile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected DamageSource getDamageSource(Entity entityHit){
|
||||||
|
return MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.FIRE).setProjectile();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpdate(){
|
public void onUpdate(){
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
package electroblob.wizardry.entity.projectile;
|
package electroblob.wizardry.entity.projectile;
|
||||||
|
|
||||||
|
import electroblob.wizardry.packet.PacketBombExplosion;
|
||||||
|
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||||
import electroblob.wizardry.registry.Spells;
|
import electroblob.wizardry.registry.Spells;
|
||||||
import electroblob.wizardry.registry.WizardrySounds;
|
import electroblob.wizardry.registry.WizardrySounds;
|
||||||
import electroblob.wizardry.spell.Spell;
|
import electroblob.wizardry.spell.Spell;
|
||||||
import electroblob.wizardry.util.EntityUtils;
|
import electroblob.wizardry.util.EntityUtils;
|
||||||
import electroblob.wizardry.util.MagicDamage;
|
import electroblob.wizardry.util.MagicDamage;
|
||||||
import electroblob.wizardry.util.MagicDamage.DamageType;
|
import electroblob.wizardry.util.MagicDamage.DamageType;
|
||||||
import electroblob.wizardry.util.ParticleBuilder;
|
|
||||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.EntityLivingBase;
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
import net.minecraft.init.MobEffects;
|
import net.minecraft.init.MobEffects;
|
||||||
import net.minecraft.potion.PotionEffect;
|
import net.minecraft.potion.PotionEffect;
|
||||||
import net.minecraft.util.EnumParticleTypes;
|
|
||||||
import net.minecraft.util.math.RayTraceResult;
|
import net.minecraft.util.math.RayTraceResult;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -31,44 +31,30 @@ public class EntityPoisonBomb extends EntityBomb {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onImpact(RayTraceResult rayTrace){
|
protected void onImpact(RayTraceResult rayTrace){
|
||||||
|
|
||||||
Entity entityHit = rayTrace.entityHit;
|
|
||||||
|
|
||||||
if(entityHit != null){
|
|
||||||
// This is if the poison bomb gets a direct hit
|
|
||||||
float damage = Spells.poison_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier;
|
|
||||||
|
|
||||||
entityHit.attackEntityFrom(
|
|
||||||
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.POISON).setProjectile(),
|
|
||||||
damage);
|
|
||||||
|
|
||||||
if(entityHit instanceof EntityLivingBase && !MagicDamage.isEntityImmune(DamageType.POISON, entityHit))
|
|
||||||
((EntityLivingBase)entityHit).addPotionEffect(new PotionEffect(MobEffects.POISON,
|
|
||||||
Spells.poison_bomb.getProperty(Spell.DIRECT_EFFECT_DURATION).intValue(),
|
|
||||||
Spells.poison_bomb.getProperty(Spell.DIRECT_EFFECT_STRENGTH).intValue()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Particle effect
|
|
||||||
if(world.isRemote){
|
|
||||||
|
|
||||||
ParticleBuilder.create(Type.FLASH).pos(this.getPositionVector()).scale(5 * blastMultiplier)
|
|
||||||
.clr(0.2f + rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world);
|
|
||||||
|
|
||||||
for(int i = 0; i < 60 * blastMultiplier; i++){
|
|
||||||
|
|
||||||
ParticleBuilder.create(Type.SPARKLE, rand, posX, posY, posZ, 2*blastMultiplier, false).time(35)
|
|
||||||
.scale(2).clr(0.2f + rand.nextFloat() * 0.3f, 0.6f, 0.0f).spawn(world);
|
|
||||||
|
|
||||||
ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false)
|
|
||||||
.clr(0.2f + rand.nextFloat() * 0.2f, 0.8f, 0.0f).spawn(world);
|
|
||||||
}
|
|
||||||
// Spawning this after the other particles fixes the rendering colour bug. It's a bit of a cheat, but it
|
|
||||||
// works pretty well.
|
|
||||||
this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!this.world.isRemote){
|
if(!this.world.isRemote){
|
||||||
|
|
||||||
|
Entity entityHit = rayTrace.entityHit;
|
||||||
|
|
||||||
|
if(entityHit != null){
|
||||||
|
// This is if the poison bomb gets a direct hit
|
||||||
|
float damage = Spells.poison_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier;
|
||||||
|
|
||||||
|
entityHit.attackEntityFrom(
|
||||||
|
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.POISON).setProjectile(),
|
||||||
|
damage);
|
||||||
|
|
||||||
|
if(entityHit instanceof EntityLivingBase && !MagicDamage.isEntityImmune(DamageType.POISON, entityHit))
|
||||||
|
((EntityLivingBase)entityHit).addPotionEffect(new PotionEffect(MobEffects.POISON,
|
||||||
|
Spells.poison_bomb.getProperty(Spell.DIRECT_EFFECT_DURATION).intValue(),
|
||||||
|
Spells.poison_bomb.getProperty(Spell.DIRECT_EFFECT_STRENGTH).intValue()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify clients to play the explosion effect
|
||||||
|
WizardryPacketHandler.net.sendToAllAround(
|
||||||
|
new PacketBombExplosion.Message(PacketBombExplosion.POISON_BOMB, posX, posY, posZ, blastMultiplier),
|
||||||
|
new NetworkRegistry.TargetPoint(world.provider.getDimension(), posX, posY, posZ, 64));
|
||||||
|
|
||||||
this.playSound(WizardrySounds.ENTITY_POISON_BOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F);
|
this.playSound(WizardrySounds.ENTITY_POISON_BOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F);
|
||||||
this.playSound(WizardrySounds.ENTITY_POISON_BOMB_POISON, 1.2F, 1.0f);
|
this.playSound(WizardrySounds.ENTITY_POISON_BOMB_POISON, 1.2F, 1.0f);
|
||||||
|
|
||||||
@@ -88,8 +74,8 @@ public class EntityPoisonBomb extends EntityBomb {
|
|||||||
Spells.poison_bomb.getProperty(Spell.SPLASH_EFFECT_STRENGTH).intValue()));
|
Spells.poison_bomb.getProperty(Spell.SPLASH_EFFECT_STRENGTH).intValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setDead();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setDead();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
package electroblob.wizardry.entity.projectile;
|
package electroblob.wizardry.entity.projectile;
|
||||||
|
|
||||||
|
import electroblob.wizardry.packet.PacketBombExplosion;
|
||||||
|
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||||
import electroblob.wizardry.registry.Spells;
|
import electroblob.wizardry.registry.Spells;
|
||||||
import electroblob.wizardry.registry.WizardrySounds;
|
import electroblob.wizardry.registry.WizardrySounds;
|
||||||
import electroblob.wizardry.spell.Spell;
|
import electroblob.wizardry.spell.Spell;
|
||||||
import electroblob.wizardry.util.EntityUtils;
|
import electroblob.wizardry.util.EntityUtils;
|
||||||
import electroblob.wizardry.util.ParticleBuilder;
|
|
||||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
|
||||||
import net.minecraft.entity.EntityLivingBase;
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
import net.minecraft.init.MobEffects;
|
import net.minecraft.init.MobEffects;
|
||||||
import net.minecraft.potion.PotionEffect;
|
import net.minecraft.potion.PotionEffect;
|
||||||
import net.minecraft.util.EnumParticleTypes;
|
|
||||||
import net.minecraft.util.math.RayTraceResult;
|
import net.minecraft.util.math.RayTraceResult;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -29,27 +29,13 @@ public class EntitySmokeBomb extends EntityBomb {
|
|||||||
@Override
|
@Override
|
||||||
protected void onImpact(RayTraceResult rayTrace){
|
protected void onImpact(RayTraceResult rayTrace){
|
||||||
|
|
||||||
// Particle effect
|
|
||||||
if(world.isRemote){
|
|
||||||
|
|
||||||
ParticleBuilder.create(Type.FLASH).pos(this.getPositionVector()).scale(5 * blastMultiplier).clr(0, 0, 0).spawn(world);
|
|
||||||
|
|
||||||
this.world.spawnParticle(EnumParticleTypes.EXPLOSION_LARGE, this.posX, this.posY, this.posZ, 0, 0, 0);
|
|
||||||
|
|
||||||
for(int i = 0; i < 60 * blastMultiplier; i++){
|
|
||||||
|
|
||||||
float brightness = rand.nextFloat() * 0.1f + 0.1f;
|
|
||||||
ParticleBuilder.create(Type.CLOUD, rand, posX, posY, posZ, 2*blastMultiplier, false)
|
|
||||||
.clr(brightness, brightness, brightness).time(80 + this.rand.nextInt(12)).shaded(true).spawn(world);
|
|
||||||
|
|
||||||
brightness = rand.nextFloat() * 0.3f;
|
|
||||||
ParticleBuilder.create(Type.DARK_MAGIC, rand, posX, posY, posZ, 2*blastMultiplier, false)
|
|
||||||
.clr(brightness, brightness, brightness).spawn(world);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!this.world.isRemote){
|
if(!this.world.isRemote){
|
||||||
|
|
||||||
|
// Notify clients to play the explosion effect
|
||||||
|
WizardryPacketHandler.net.sendToAllAround(
|
||||||
|
new PacketBombExplosion.Message(PacketBombExplosion.SMOKE_BOMB, posX, posY, posZ, blastMultiplier),
|
||||||
|
new NetworkRegistry.TargetPoint(world.provider.getDimension(), posX, posY, posZ, 64));
|
||||||
|
|
||||||
this.playSound(WizardrySounds.ENTITY_SMOKE_BOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F);
|
this.playSound(WizardrySounds.ENTITY_SMOKE_BOMB_SMASH, 1.5F, rand.nextFloat() * 0.4F + 0.6F);
|
||||||
this.playSound(WizardrySounds.ENTITY_SMOKE_BOMB_SMOKE, 1.2F, 1.0f);
|
this.playSound(WizardrySounds.ENTITY_SMOKE_BOMB_SMOKE, 1.2F, 1.0f);
|
||||||
|
|
||||||
@@ -65,8 +51,8 @@ public class EntitySmokeBomb extends EntityBomb {
|
|||||||
target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, duration, 0));
|
target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, duration, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setDead();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setDead();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package electroblob.wizardry.entity.projectile;
|
package electroblob.wizardry.entity.projectile;
|
||||||
|
|
||||||
|
import electroblob.wizardry.packet.PacketBombExplosion;
|
||||||
|
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||||
import electroblob.wizardry.registry.Spells;
|
import electroblob.wizardry.registry.Spells;
|
||||||
import electroblob.wizardry.registry.WizardrySounds;
|
import electroblob.wizardry.registry.WizardrySounds;
|
||||||
import electroblob.wizardry.spell.Spell;
|
import electroblob.wizardry.spell.Spell;
|
||||||
@@ -13,7 +15,9 @@ import net.minecraft.entity.EntityLivingBase;
|
|||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.util.math.RayTraceResult;
|
import net.minecraft.util.math.RayTraceResult;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class EntitySparkBomb extends EntityBomb {
|
public class EntitySparkBomb extends EntityBomb {
|
||||||
@@ -31,47 +35,37 @@ public class EntitySparkBomb extends EntityBomb {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onImpact(RayTraceResult rayTrace){
|
protected void onImpact(RayTraceResult rayTrace){
|
||||||
|
|
||||||
this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT_BLOCK, 0.5f, 0.5f);
|
|
||||||
|
|
||||||
Entity entityHit = rayTrace.entityHit;
|
if(!this.world.isRemote){
|
||||||
|
|
||||||
if(entityHit != null){
|
Entity entityHit = rayTrace.entityHit;
|
||||||
// This is if the spark bomb gets a direct hit
|
|
||||||
float damage = Spells.spark_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier;
|
|
||||||
|
|
||||||
this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F));
|
if(entityHit != null){
|
||||||
|
// This is if the spark bomb gets a direct hit
|
||||||
|
float damage = Spells.spark_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier;
|
||||||
|
|
||||||
entityHit.attackEntityFrom(
|
this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F));
|
||||||
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK).setProjectile(),
|
|
||||||
damage);
|
|
||||||
|
|
||||||
}
|
entityHit.attackEntityFrom(
|
||||||
|
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK).setProjectile(),
|
||||||
|
damage);
|
||||||
|
}
|
||||||
|
|
||||||
// Particle effect
|
double seekerRange = Spells.spark_bomb.getProperty(Spell.EFFECT_RADIUS).doubleValue() * blastMultiplier;
|
||||||
if(world.isRemote){
|
|
||||||
ParticleBuilder.spawnShockParticles(world, posX, posY + height/2, posZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
double seekerRange = Spells.spark_bomb.getProperty(Spell.EFFECT_RADIUS).doubleValue() * blastMultiplier;
|
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(seekerRange, this.posX, this.posY,
|
||||||
|
this.posZ, this.world);
|
||||||
|
|
||||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(seekerRange, this.posX, this.posY,
|
List<Integer> secondaryTargetIDs = new ArrayList<>();
|
||||||
this.posZ, this.world);
|
|
||||||
|
|
||||||
for(int i = 0; i < Math.min(targets.size(), Spells.spark_bomb.getProperty(SECONDARY_MAX_TARGETS).intValue()); i++){
|
for(int i = 0; i < Math.min(targets.size(), Spells.spark_bomb.getProperty(SECONDARY_MAX_TARGETS).intValue()); i++){
|
||||||
|
|
||||||
boolean flag = targets.get(i) != entityHit && targets.get(i) != this.getThrower()
|
boolean flag = targets.get(i) != entityHit && targets.get(i) != this.getThrower()
|
||||||
&& !(targets.get(i) instanceof EntityPlayer
|
&& !(targets.get(i) instanceof EntityPlayer
|
||||||
&& ((EntityPlayer)targets.get(i)).isCreative());
|
&& ((EntityPlayer)targets.get(i)).isCreative());
|
||||||
|
|
||||||
// Detects (client side) if target is the thrower, to stop particles being spawned around them.
|
if(flag){
|
||||||
//if(flag && world.isRemote && targets.get(i).getEntityId() == this.playerID) flag = false;
|
EntityLivingBase target = targets.get(i);
|
||||||
|
|
||||||
if(flag){
|
|
||||||
|
|
||||||
EntityLivingBase target = targets.get(i);
|
|
||||||
|
|
||||||
if(!this.world.isRemote){
|
|
||||||
|
|
||||||
target.playSound(WizardrySounds.ENTITY_SPARK_BOMB_CHAIN, 1.0F, rand.nextFloat() * 0.4F + 1.5F);
|
target.playSound(WizardrySounds.ENTITY_SPARK_BOMB_CHAIN, 1.0F, rand.nextFloat() * 0.4F + 1.5F);
|
||||||
|
|
||||||
@@ -79,11 +73,18 @@ public class EntitySparkBomb extends EntityBomb {
|
|||||||
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK),
|
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK),
|
||||||
Spells.spark_bomb.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier);
|
Spells.spark_bomb.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier);
|
||||||
|
|
||||||
}else{
|
secondaryTargetIDs.add(target.getEntityId());
|
||||||
ParticleBuilder.create(Type.LIGHTNING).pos(this.getPositionVector()).target(target).spawn(world);
|
|
||||||
ParticleBuilder.spawnShockParticles(world, target.posX, target.posY + target.height/2, target.posZ);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Notify clients to play the explosion effect, including lightning arcs to secondary targets
|
||||||
|
int[] idArray = secondaryTargetIDs.stream().mapToInt(Integer::intValue).toArray();
|
||||||
|
WizardryPacketHandler.net.sendToAllAround(
|
||||||
|
new PacketBombExplosion.Message(PacketBombExplosion.SPARK_BOMB, posX, posY + height / 2, posZ,
|
||||||
|
blastMultiplier, idArray),
|
||||||
|
new NetworkRegistry.TargetPoint(world.provider.getDimension(), posX, posY, posZ, 64));
|
||||||
|
|
||||||
|
this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT_BLOCK, 0.5f, 0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setDead();
|
this.setDead();
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package electroblob.wizardry.event;
|
||||||
|
|
||||||
|
import electroblob.wizardry.item.ItemArtefact;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ArtefactCheckEvent is fired when a check happens for an ItemArtefact using {@link electroblob.wizardry.item.ItemArtefact#isArtefactActive(net.minecraft.entity.player.EntityPlayer, net.minecraft.item.Item)}
|
||||||
|
* <i>Fired on both sides.</i><br>
|
||||||
|
* <br>
|
||||||
|
* This event is {@link Cancelable}. <br>
|
||||||
|
* <br>
|
||||||
|
* This event has a result. {@link HasResult}. Set the result to Result.ALLOW to consider an artefact "active"<br>
|
||||||
|
* <br>
|
||||||
|
* This event is fired on the {@link MinecraftForge#EVENT_BUS}.
|
||||||
|
*
|
||||||
|
* @author WinDanesz
|
||||||
|
* @since Wizardry 4.3.10
|
||||||
|
*/
|
||||||
|
@Cancelable
|
||||||
|
@Event.HasResult
|
||||||
|
public class ArtefactCheckEvent extends PlayerEvent {
|
||||||
|
|
||||||
|
ItemArtefact artefact;
|
||||||
|
EntityPlayer player;
|
||||||
|
|
||||||
|
public ArtefactCheckEvent(EntityPlayer player, ItemArtefact artefact) {
|
||||||
|
super(player);
|
||||||
|
this.player = player;
|
||||||
|
this.artefact = artefact;
|
||||||
|
setResult(Result.DENY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemArtefact getArtefact() {
|
||||||
|
return artefact;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityPlayer getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package electroblob.wizardry.event;
|
||||||
|
|
||||||
|
import electroblob.wizardry.constants.Element;
|
||||||
|
import electroblob.wizardry.tileentity.TileEntityImbuementAltar;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ImbuementActivateEvent is fired when {@link TileEntityImbuementAltar#getImbuementResult(net.minecraft.item.ItemStack, electroblob.wizardry.constants.Element[],
|
||||||
|
* boolean, net.minecraft.world.World, net.minecraft.entity.player.EntityPlayer)} is called to allow adding in imbuement "recipes" dynamically, based on the
|
||||||
|
* contents of the Imbuement altar's receptacles and the item placed on the altar.
|
||||||
|
*
|
||||||
|
* <i>Note that this event is only fired on the server side.</i><br>
|
||||||
|
* <br>
|
||||||
|
* To alter the result of the imbuement process, change the {@link electroblob.wizardry.event.ImbuementActivateEvent#result} result of the process.<br>
|
||||||
|
* <br>
|
||||||
|
* This event is {@link Cancelable}. If this event is canceled, no further processing takes place.<br>
|
||||||
|
* <br>
|
||||||
|
* This event does not have a result. {@link Event.HasResult}<br>
|
||||||
|
* <br>
|
||||||
|
* This event is fired on the {@link MinecraftForge#EVENT_BUS}.
|
||||||
|
*
|
||||||
|
* @author WinDanesz
|
||||||
|
* @since Wizardry 4.3.5
|
||||||
|
*/
|
||||||
|
@Cancelable
|
||||||
|
public class ImbuementActivateEvent extends Event {
|
||||||
|
|
||||||
|
/** The item stack being imbued */
|
||||||
|
public ItemStack input;
|
||||||
|
|
||||||
|
/** The elements of the four receptacles */
|
||||||
|
public Element[] receptacleElements;
|
||||||
|
|
||||||
|
/** A reference to the current world object (may be null if {@code fullLootGen} is false) */
|
||||||
|
public World world;
|
||||||
|
|
||||||
|
/** The player that last interacted with the imbuement altar, or null if there isn't one (or if this is being queried for other reasons, e.g. JEI) */
|
||||||
|
public EntityPlayer lastUser;
|
||||||
|
|
||||||
|
/** The resulting item stack of the imbuement process */
|
||||||
|
public ItemStack result;
|
||||||
|
|
||||||
|
public ImbuementActivateEvent(ItemStack input, Element[] receptacleElements, World world, EntityPlayer lastUser, ItemStack result) {
|
||||||
|
super();
|
||||||
|
this.input = input;
|
||||||
|
this.receptacleElements = receptacleElements;
|
||||||
|
this.world = world;
|
||||||
|
this.lastUser = lastUser;
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package electroblob.wizardry.event;
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ResurrectionEvent is fired when a player is about to be resurrected, after all other checks have been performed.
|
||||||
|
* <i>Note that this event is only fired on the server side.</i><br>
|
||||||
|
* <br>
|
||||||
|
* This event is {@link Cancelable}. If this event is canceled, the player is not resurrected.<br>
|
||||||
|
* <br>
|
||||||
|
* This event does not have a result. {@link HasResult}<br>
|
||||||
|
* <br>
|
||||||
|
* This event is fired on the {@link MinecraftForge#EVENT_BUS}.
|
||||||
|
*
|
||||||
|
* @author Electroblob
|
||||||
|
* @since Wizardry 2.1
|
||||||
|
*/
|
||||||
|
@Cancelable
|
||||||
|
public class ResurrectionEvent extends PlayerEvent {
|
||||||
|
|
||||||
|
private final EntityPlayer caster;
|
||||||
|
|
||||||
|
public ResurrectionEvent(EntityPlayer player, EntityPlayer caster){
|
||||||
|
super(player);
|
||||||
|
this.caster = caster;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the player that cast the resurrection spell. If the player resurrected themselves, this will be the
|
||||||
|
* same as {@link ResurrectionEvent#getEntityPlayer()}. */
|
||||||
|
public EntityPlayer getCaster(){
|
||||||
|
return caster;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -46,6 +46,9 @@ public final class WizardryBaublesIntegration {
|
|||||||
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.RING, BaubleType.RING);
|
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.RING, BaubleType.RING);
|
||||||
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.AMULET, BaubleType.AMULET);
|
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.AMULET, BaubleType.AMULET);
|
||||||
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.CHARM, BaubleType.CHARM);
|
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.CHARM, BaubleType.CHARM);
|
||||||
|
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.BELT, BaubleType.BELT);
|
||||||
|
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.BODY, BaubleType.BODY);
|
||||||
|
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.HEAD, BaubleType.HEAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean enabled(){
|
public static boolean enabled(){
|
||||||
|
|||||||
@@ -73,7 +73,9 @@ public class WizardryJEIPlugin implements IModPlugin {
|
|||||||
addItemInfo(registry, WizardryItems.identification_scroll, ".desc_extended");
|
addItemInfo(registry, WizardryItems.identification_scroll, ".desc_extended");
|
||||||
addItemInfo(registry, WizardryItems.spell_book);
|
addItemInfo(registry, WizardryItems.spell_book);
|
||||||
addItemInfo(registry, WizardryItems.scroll);
|
addItemInfo(registry, WizardryItems.scroll);
|
||||||
addItemInfo(registry, WizardryItems.armour_upgrade, ".desc_extended");
|
addItemInfo(registry, WizardryItems.resplendent_thread, ".desc_extended");
|
||||||
|
addItemInfo(registry, WizardryItems.crystal_silver_plating, ".desc_extended");
|
||||||
|
addItemInfo(registry, WizardryItems.ethereal_crystalweave, ".desc_extended");
|
||||||
addItemInfo(registry, WizardryItems.purifying_elixir, ".desc_extended");
|
addItemInfo(registry, WizardryItems.purifying_elixir, ".desc_extended");
|
||||||
addItemInfo(registry, WizardryItems.astral_diamond);
|
addItemInfo(registry, WizardryItems.astral_diamond);
|
||||||
addItemInfo(registry, WizardryItems.ruined_spell_book);
|
addItemInfo(registry, WizardryItems.ruined_spell_book);
|
||||||
|
|||||||
@@ -99,7 +99,9 @@ public class ContainerArcaneWorkbench extends Container implements ISpellSortabl
|
|||||||
|
|
||||||
Set<Item> upgrades = new HashSet<>(WandHelper.getSpecialUpgrades()); // Can't be done statically.
|
Set<Item> upgrades = new HashSet<>(WandHelper.getSpecialUpgrades()); // Can't be done statically.
|
||||||
upgrades.add(WizardryItems.arcane_tome);
|
upgrades.add(WizardryItems.arcane_tome);
|
||||||
upgrades.add(WizardryItems.armour_upgrade);
|
upgrades.add(WizardryItems.resplendent_thread);
|
||||||
|
upgrades.add(WizardryItems.crystal_silver_plating);
|
||||||
|
upgrades.add(WizardryItems.ethereal_crystalweave);
|
||||||
|
|
||||||
this.addSlotToContainer(new SlotItemList(tileentity, UPGRADE_SLOT, 147, 17, 1, upgrades.toArray(new Item[0])))
|
this.addSlotToContainer(new SlotItemList(tileentity, UPGRADE_SLOT, 147, 17, 1, upgrades.toArray(new Item[0])))
|
||||||
.setBackgroundName(EMPTY_SLOT_UPGRADE.toString());
|
.setBackgroundName(EMPTY_SLOT_UPGRADE.toString());
|
||||||
@@ -450,6 +452,24 @@ public class ContainerArcaneWorkbench extends Container implements ISpellSortabl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called (via {@link electroblob.wizardry.packet.PacketControlInput PacketControlInput}) when the clear button in
|
||||||
|
* the arcane workbench GUI is pressed.
|
||||||
|
*/
|
||||||
|
// As of 2.1, for the sake of events and neatness of code, this was moved here from TileEntityArcaneWorkbench.
|
||||||
|
// As of 4.2, the spell binding/charging/upgrading code was delegated (via IWorkbenchItem) to the items themselves.
|
||||||
|
public void onClearButtonPressed(EntityPlayer player){
|
||||||
|
|
||||||
|
Slot centre = this.getSlot(CENTRE_SLOT);
|
||||||
|
|
||||||
|
if(centre.getStack().getItem() instanceof IWorkbenchItem){ // Should always be true, but no harm in checking.
|
||||||
|
|
||||||
|
Slot[] spellBooks = this.inventorySlots.subList(0, 8).toArray(new Slot[8]);
|
||||||
|
|
||||||
|
((IWorkbenchItem) centre.getStack().getItem()).onClearButtonPressed(player, centre, this.getSlot(CRYSTAL_SLOT), this.getSlot(UPGRADE_SLOT), spellBooks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Scrolls to the given row number. */
|
/** Scrolls to the given row number. */
|
||||||
public void scrollTo(int row){
|
public void scrollTo(int row){
|
||||||
this.scroll = row;
|
this.scroll = row;
|
||||||
|
|||||||
@@ -133,7 +133,6 @@ public class ContainerBookshelf extends Container {
|
|||||||
registerBookItem(WizardryItems.scroll);
|
registerBookItem(WizardryItems.scroll);
|
||||||
registerBookItem(WizardryItems.blank_scroll);
|
registerBookItem(WizardryItems.blank_scroll);
|
||||||
registerBookItem(WizardryItems.identification_scroll);
|
registerBookItem(WizardryItems.identification_scroll);
|
||||||
registerBookItem(WizardryItems.armour_upgrade);
|
|
||||||
// Not using the map in WandHelper for consistency with BlockBookshelf (again, addons must add theirs manually)
|
// Not using the map in WandHelper for consistency with BlockBookshelf (again, addons must add theirs manually)
|
||||||
registerBookItem(WizardryItems.storage_upgrade);
|
registerBookItem(WizardryItems.storage_upgrade);
|
||||||
registerBookItem(WizardryItems.siphon_upgrade);
|
registerBookItem(WizardryItems.siphon_upgrade);
|
||||||
|
|||||||
@@ -55,6 +55,26 @@ public interface IWorkbenchItem {
|
|||||||
*/
|
*/
|
||||||
boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks);
|
boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when this item is in the central slot of an arcane workbench and the apply clear is pressed. Items must
|
||||||
|
* implement this method to define what happens when the apply button is pressed.
|
||||||
|
* @param player The player that pressed the apply button.
|
||||||
|
* @param centre The central slot in the arcane workbench. This slot will always contain a stack of the implementing
|
||||||
|
* item, or in other words, <i>it is guaranteed that</i> {@code this == centre.getStack().getItem()}.
|
||||||
|
* @param crystals The magic crystal slot of the arcane workbench.
|
||||||
|
* @param upgrade The upgrade slot of the arcane workbench.
|
||||||
|
* @param spellBooks An array of the <i>active</i> (visible) spell book slots in the arcane workbench. The length of
|
||||||
|
* the array will be equal to the value returned by {@link IWorkbenchItem#getSpellSlotCount(ItemStack)}.
|
||||||
|
* */
|
||||||
|
default void onClearButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must be overridden in the item class to make the clear button in the Arcane Workbench clickable.
|
||||||
|
* */
|
||||||
|
default boolean isClearable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the tooltip (dark grey box) should be drawn when this item is in an arcane workbench. Only
|
* Returns whether the tooltip (dark grey box) should be drawn when this item is in an arcane workbench. Only
|
||||||
* called client-side.
|
* called client-side.
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
package electroblob.wizardry.item;
|
package electroblob.wizardry.item;
|
||||||
|
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
|
import electroblob.wizardry.block.BlockBookshelf;
|
||||||
import electroblob.wizardry.constants.Tier;
|
import electroblob.wizardry.constants.Tier;
|
||||||
import electroblob.wizardry.registry.WizardryTabs;
|
import electroblob.wizardry.registry.WizardryTabs;
|
||||||
import net.minecraft.creativetab.CreativeTabs;
|
import net.minecraft.creativetab.CreativeTabs;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.item.EnumRarity;
|
import net.minecraft.item.EnumRarity;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.EnumActionResult;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.EnumHand;
|
||||||
import net.minecraft.util.NonNullList;
|
import net.minecraft.util.NonNullList;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
@@ -25,7 +32,7 @@ public class ItemArcaneTome extends Item {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list){
|
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> list){
|
||||||
if(tab == WizardryTabs.WIZARDRY){ // Don't use isInCreativeTab here.
|
if(tab == WizardryTabs.WIZARDRY || tab == CreativeTabs.SEARCH){ // Don't use isInCreativeTab here.
|
||||||
for(int i = 1; i < Tier.values().length; i++){
|
for(int i = 1; i < Tier.values().length; i++){
|
||||||
list.add(new ItemStack(this, 1, i));
|
list.add(new ItemStack(this, 1, i));
|
||||||
}
|
}
|
||||||
@@ -51,6 +58,20 @@ public class ItemArcaneTome extends Item {
|
|||||||
return EnumRarity.COMMON;
|
return EnumRarity.COMMON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand,
|
||||||
|
EnumFacing facing, float hitX, float hitY, float hitZ){
|
||||||
|
if(player.isSneaking()){
|
||||||
|
IBlockState state = world.getBlockState(pos);
|
||||||
|
if(state.getBlock() instanceof BlockBookshelf){
|
||||||
|
if(state.getBlock().onBlockActivated(world, pos, state, player, hand, facing, hitX, hitY, hitZ)){
|
||||||
|
return EnumActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EnumActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
@SideOnly(Side.CLIENT)
|
@SideOnly(Side.CLIENT)
|
||||||
@Override
|
@Override
|
||||||
public void addInformation(ItemStack stack, World world, List<String> tooltip, net.minecraft.client.util.ITooltipFlag showAdvanced){
|
public void addInformation(ItemStack stack, World world, List<String> tooltip, net.minecraft.client.util.ITooltipFlag showAdvanced){
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class ItemArmourUpgrade extends Item {
|
|||||||
@Override
|
@Override
|
||||||
@SideOnly(Side.CLIENT)
|
@SideOnly(Side.CLIENT)
|
||||||
public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> tooltip, net.minecraft.client.util.ITooltipFlag flagIn) {
|
public void addInformation(ItemStack stack, @Nullable World worldIn, List<String> tooltip, net.minecraft.client.util.ITooltipFlag flagIn) {
|
||||||
Wizardry.proxy.addMultiLineDescription(tooltip, "item." + this.getRegistryName() + ".desc", "\u00A7d");
|
Wizardry.proxy.addMultiLineDescription(tooltip, "item." + this.getRegistryName() + ".desc");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import electroblob.wizardry.entity.living.ISummonedCreature;
|
|||||||
import electroblob.wizardry.entity.projectile.EntityDart;
|
import electroblob.wizardry.entity.projectile.EntityDart;
|
||||||
import electroblob.wizardry.entity.projectile.EntityForceOrb;
|
import electroblob.wizardry.entity.projectile.EntityForceOrb;
|
||||||
import electroblob.wizardry.entity.projectile.EntityIceShard;
|
import electroblob.wizardry.entity.projectile.EntityIceShard;
|
||||||
|
import electroblob.wizardry.event.ArtefactCheckEvent;
|
||||||
import electroblob.wizardry.event.SpellCastEvent;
|
import electroblob.wizardry.event.SpellCastEvent;
|
||||||
import electroblob.wizardry.event.SpellCastEvent.Source;
|
import electroblob.wizardry.event.SpellCastEvent.Source;
|
||||||
import electroblob.wizardry.integration.DamageSafetyChecker;
|
import electroblob.wizardry.integration.DamageSafetyChecker;
|
||||||
@@ -37,6 +38,7 @@ import net.minecraft.util.text.TextFormatting;
|
|||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.biome.Biome;
|
import net.minecraft.world.biome.Biome;
|
||||||
import net.minecraftforge.common.BiomeDictionary;
|
import net.minecraftforge.common.BiomeDictionary;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||||
import net.minecraftforge.event.entity.living.LivingDeathEvent;
|
import net.minecraftforge.event.entity.living.LivingDeathEvent;
|
||||||
import net.minecraftforge.event.entity.living.LivingEvent;
|
import net.minecraftforge.event.entity.living.LivingEvent;
|
||||||
@@ -88,7 +90,10 @@ public class ItemArtefact extends Item {
|
|||||||
|
|
||||||
/** An artefact that improves attacking spells. Two of these can be active at any one time. */ RING(2),
|
/** An artefact that improves attacking spells. Two of these can be active at any one time. */ RING(2),
|
||||||
/** An artefact that improves defensive spells. One of these can be active at any one time. */ AMULET(1),
|
/** An artefact that improves defensive spells. One of these can be active at any one time. */ AMULET(1),
|
||||||
/** An artefact that improves utility spells. One of these can be active at any one time. */ CHARM(1);
|
/** An artefact that improves utility spells. One of these can be active at any one time. */ CHARM(1),
|
||||||
|
/** Added for add-on artefacts. */ BELT(1),
|
||||||
|
/** Added for add-on artefacts. */ BODY(1),
|
||||||
|
/** Added for add-on artefacts. */ HEAD(1);
|
||||||
|
|
||||||
public final int maxAtOnce;
|
public final int maxAtOnce;
|
||||||
|
|
||||||
@@ -123,6 +128,8 @@ public class ItemArtefact extends Item {
|
|||||||
this.enabled = enabled;
|
this.enabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() { return enabled; }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EnumRarity getRarity(ItemStack stack){
|
public EnumRarity getRarity(ItemStack stack){
|
||||||
return rarity;
|
return rarity;
|
||||||
@@ -176,6 +183,13 @@ public class ItemArtefact extends Item {
|
|||||||
|
|
||||||
if(!((ItemArtefact)artefact).enabled) return false; // Disabled in the config
|
if(!((ItemArtefact)artefact).enabled) return false; // Disabled in the config
|
||||||
|
|
||||||
|
ArtefactCheckEvent event = new ArtefactCheckEvent(player, (ItemArtefact) artefact);
|
||||||
|
if(MinecraftForge.EVENT_BUS.post(event)) return false;
|
||||||
|
|
||||||
|
if (event.getResult() == Event.Result.ALLOW) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if(WizardryBaublesIntegration.enabled()){
|
if(WizardryBaublesIntegration.enabled()){
|
||||||
return WizardryBaublesIntegration.isBaubleEquipped(player, artefact);
|
return WizardryBaublesIntegration.isBaubleEquipped(player, artefact);
|
||||||
}else{
|
}else{
|
||||||
@@ -344,6 +358,8 @@ public class ItemArtefact extends Item {
|
|||||||
|
|
||||||
findMatchingWandAndExecute(player, Spells.shield, wand -> {
|
findMatchingWandAndExecute(player, Spells.shield, wand -> {
|
||||||
|
|
||||||
|
if(wand.getItem() instanceof ItemScroll) return; // Ignore scrolls since they shouldn't work
|
||||||
|
|
||||||
List<Entity> projectiles = EntityUtils.getEntitiesWithinRadius(5, player.posX, player.posY, player.posZ, world, Entity.class);
|
List<Entity> projectiles = EntityUtils.getEntitiesWithinRadius(5, player.posX, player.posY, player.posZ, world, Entity.class);
|
||||||
projectiles.removeIf(e -> !(e instanceof IProjectile));
|
projectiles.removeIf(e -> !(e instanceof IProjectile));
|
||||||
Vec3d look = player.getLookVec();
|
Vec3d look = player.getLookVec();
|
||||||
@@ -765,6 +781,7 @@ public class ItemArtefact extends Item {
|
|||||||
&& Streams.stream(player.getHeldEquipment()).anyMatch(s -> s.getItem() instanceof ISpellCastingItem
|
&& Streams.stream(player.getHeldEquipment()).anyMatch(s -> s.getItem() instanceof ISpellCastingItem
|
||||||
&& ((ISpellCastingItem)s.getItem()).getCurrentSpell(s).getElement() == Element.NECROMANCY))){
|
&& ((ISpellCastingItem)s.getItem()).getCurrentSpell(s).getElement() == Element.NECROMANCY))){
|
||||||
|
|
||||||
|
event.getEntityLiving().addPotionEffect(new PotionEffect(WizardryPotions.curse_of_soulbinding, 400));
|
||||||
CurseOfSoulbinding.getSoulboundCreatures(WizardData.get(player)).add(event.getEntity().getUniqueID());
|
CurseOfSoulbinding.getSoulboundCreatures(WizardData.get(player)).add(event.getEntity().getUniqueID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package electroblob.wizardry.item;
|
package electroblob.wizardry.item;
|
||||||
|
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
|
import electroblob.wizardry.block.BlockBookshelf;
|
||||||
import electroblob.wizardry.constants.Constants;
|
import electroblob.wizardry.constants.Constants;
|
||||||
import electroblob.wizardry.data.WizardData;
|
import electroblob.wizardry.data.WizardData;
|
||||||
import electroblob.wizardry.registry.Spells;
|
import electroblob.wizardry.registry.Spells;
|
||||||
@@ -8,12 +9,18 @@ import electroblob.wizardry.registry.WizardryItems;
|
|||||||
import electroblob.wizardry.registry.WizardryTabs;
|
import electroblob.wizardry.registry.WizardryTabs;
|
||||||
import electroblob.wizardry.spell.Spell;
|
import electroblob.wizardry.spell.Spell;
|
||||||
import electroblob.wizardry.util.SpellProperties;
|
import electroblob.wizardry.util.SpellProperties;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.inventory.Slot;
|
import net.minecraft.inventory.Slot;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.EnumActionResult;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.EnumHand;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
public class ItemBlankScroll extends Item implements IWorkbenchItem {
|
public class ItemBlankScroll extends Item implements IWorkbenchItem {
|
||||||
|
|
||||||
@@ -67,4 +74,18 @@ public class ItemBlankScroll extends Item implements IWorkbenchItem {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand,
|
||||||
|
EnumFacing facing, float hitX, float hitY, float hitZ){
|
||||||
|
if(player.isSneaking()){
|
||||||
|
IBlockState state = world.getBlockState(pos);
|
||||||
|
if(state.getBlock() instanceof BlockBookshelf){
|
||||||
|
if(state.getBlock().onBlockActivated(world, pos, state, player, hand, facing, hitX, hitY, hitZ)){
|
||||||
|
return EnumActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EnumActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class ItemCrystal extends Item implements IMultiTexturedItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> items){
|
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> items){
|
||||||
if(tab == WizardryTabs.WIZARDRY){
|
if(tab == WizardryTabs.WIZARDRY || tab == CreativeTabs.SEARCH){
|
||||||
for(Element element : Element.values()){
|
for(Element element : Element.values()){
|
||||||
items.add(new ItemStack(this, 1, element.ordinal()));
|
items.add(new ItemStack(this, 1, element.ordinal()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,14 +193,6 @@ public class ItemFlamecatcher extends ItemBow implements IConjuredItem {
|
|||||||
charge = net.minecraftforge.event.ForgeEventFactory.onArrowLoose(stack, world, (EntityPlayer)entity, charge, true);
|
charge = net.minecraftforge.event.ForgeEventFactory.onArrowLoose(stack, world, (EntityPlayer)entity, charge, true);
|
||||||
if(charge < 0) return;
|
if(charge < 0) return;
|
||||||
|
|
||||||
if(stack.getTagCompound() != null){
|
|
||||||
int shotsLeft = stack.getTagCompound().getInteger(Flamecatcher.SHOTS_REMAINING_NBT_KEY) - 1;
|
|
||||||
stack.getTagCompound().setInteger(Flamecatcher.SHOTS_REMAINING_NBT_KEY, shotsLeft);
|
|
||||||
if(shotsLeft == 0 && !world.isRemote){
|
|
||||||
stack.setItemDamage(getMaxDamage(stack) - getAnimationFrames());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float velocity = (float)charge / DRAW_TIME;
|
float velocity = (float)charge / DRAW_TIME;
|
||||||
velocity = (velocity * velocity + velocity * 2) / 3;
|
velocity = (velocity * velocity + velocity * 2) / 3;
|
||||||
|
|
||||||
@@ -208,6 +200,14 @@ public class ItemFlamecatcher extends ItemBow implements IConjuredItem {
|
|||||||
|
|
||||||
if((double)velocity >= 0.1D){
|
if((double)velocity >= 0.1D){
|
||||||
|
|
||||||
|
if(stack.getTagCompound() != null){
|
||||||
|
int shotsLeft = stack.getTagCompound().getInteger(Flamecatcher.SHOTS_REMAINING_NBT_KEY) - 1;
|
||||||
|
stack.getTagCompound().setInteger(Flamecatcher.SHOTS_REMAINING_NBT_KEY, shotsLeft);
|
||||||
|
if(shotsLeft == 0 && !world.isRemote){
|
||||||
|
stack.setItemDamage(getMaxDamage(stack) - getAnimationFrames());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!world.isRemote){
|
if(!world.isRemote){
|
||||||
EntityFlamecatcherArrow arrow = new EntityFlamecatcherArrow(world);
|
EntityFlamecatcherArrow arrow = new EntityFlamecatcherArrow(world);
|
||||||
arrow.aim(player, EntityFlamecatcherArrow.SPEED * velocity);
|
arrow.aim(player, EntityFlamecatcherArrow.SPEED * velocity);
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
package electroblob.wizardry.item;
|
package electroblob.wizardry.item;
|
||||||
|
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
|
import electroblob.wizardry.block.BlockBookshelf;
|
||||||
import electroblob.wizardry.data.WizardData;
|
import electroblob.wizardry.data.WizardData;
|
||||||
import electroblob.wizardry.event.DiscoverSpellEvent;
|
import electroblob.wizardry.event.DiscoverSpellEvent;
|
||||||
import electroblob.wizardry.registry.WizardrySounds;
|
import electroblob.wizardry.registry.WizardrySounds;
|
||||||
import electroblob.wizardry.registry.WizardryTabs;
|
import electroblob.wizardry.registry.WizardryTabs;
|
||||||
import electroblob.wizardry.spell.Spell;
|
import electroblob.wizardry.spell.Spell;
|
||||||
import electroblob.wizardry.util.InventoryUtils;
|
import electroblob.wizardry.util.InventoryUtils;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.item.EnumRarity;
|
import net.minecraft.item.EnumRarity;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.EnumActionResult;
|
import net.minecraft.util.EnumActionResult;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
import net.minecraft.util.EnumHand;
|
import net.minecraft.util.EnumHand;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.text.TextComponentTranslation;
|
import net.minecraft.util.text.TextComponentTranslation;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
@@ -47,6 +51,20 @@ public class ItemIdentificationScroll extends Item {
|
|||||||
Wizardry.proxy.addMultiLineDescription(tooltip, "item." + this.getRegistryName() + ".desc");
|
Wizardry.proxy.addMultiLineDescription(tooltip, "item." + this.getRegistryName() + ".desc");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand,
|
||||||
|
EnumFacing facing, float hitX, float hitY, float hitZ){
|
||||||
|
if(player.isSneaking()){
|
||||||
|
IBlockState state = world.getBlockState(pos);
|
||||||
|
if(state.getBlock() instanceof BlockBookshelf){
|
||||||
|
if(state.getBlock().onBlockActivated(world, pos, state, player, hand, facing, hitX, hitY, hitZ)){
|
||||||
|
return EnumActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EnumActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
|
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
|
||||||
|
|
||||||
|
|||||||
@@ -5,14 +5,19 @@ import electroblob.wizardry.registry.WizardrySounds;
|
|||||||
import electroblob.wizardry.registry.WizardryTabs;
|
import electroblob.wizardry.registry.WizardryTabs;
|
||||||
import electroblob.wizardry.util.EntityUtils;
|
import electroblob.wizardry.util.EntityUtils;
|
||||||
import electroblob.wizardry.util.InventoryUtils;
|
import electroblob.wizardry.util.InventoryUtils;
|
||||||
|
import electroblob.wizardry.util.ParticleBuilder;
|
||||||
|
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||||
import net.minecraft.client.util.ITooltipFlag;
|
import net.minecraft.client.util.ITooltipFlag;
|
||||||
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.item.EnumAction;
|
||||||
import net.minecraft.item.EnumRarity;
|
import net.minecraft.item.EnumRarity;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.EnumActionResult;
|
import net.minecraft.util.EnumActionResult;
|
||||||
import net.minecraft.util.EnumHand;
|
import net.minecraft.util.EnumHand;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
@@ -25,15 +30,17 @@ public class ItemManaFlask extends Item {
|
|||||||
|
|
||||||
public enum Size {
|
public enum Size {
|
||||||
|
|
||||||
SMALL(75, EnumRarity.COMMON),
|
SMALL(75, 25, EnumRarity.COMMON),
|
||||||
MEDIUM(700, EnumRarity.COMMON),
|
MEDIUM(350, 40, EnumRarity.COMMON),
|
||||||
LARGE(1400, EnumRarity.RARE);
|
LARGE(1400, 60, EnumRarity.RARE);
|
||||||
|
|
||||||
public int capacity;
|
public int capacity;
|
||||||
|
public int useDuration;
|
||||||
public EnumRarity rarity;
|
public EnumRarity rarity;
|
||||||
|
|
||||||
Size(int capacity, EnumRarity rarity){
|
Size(int capacity, int useDuration, EnumRarity rarity){
|
||||||
this.capacity = capacity;
|
this.capacity = capacity;
|
||||||
|
this.useDuration = useDuration;
|
||||||
this.rarity = rarity;
|
this.rarity = rarity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,6 +65,16 @@ public class ItemManaFlask extends Item {
|
|||||||
Wizardry.proxy.addMultiLineDescription(tooltip, "item." + Wizardry.MODID + ":mana_flask.desc", size.capacity);
|
Wizardry.proxy.addMultiLineDescription(tooltip, "item." + Wizardry.MODID + ":mana_flask.desc", size.capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumAction getItemUseAction(ItemStack stack){
|
||||||
|
return EnumAction.BLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxItemUseDuration(ItemStack stack){
|
||||||
|
return size.useDuration;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
|
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
|
||||||
|
|
||||||
@@ -66,6 +83,47 @@ public class ItemManaFlask extends Item {
|
|||||||
List<ItemStack> stacks = InventoryUtils.getPrioritisedHotbarAndOffhand(player);
|
List<ItemStack> stacks = InventoryUtils.getPrioritisedHotbarAndOffhand(player);
|
||||||
stacks.addAll(player.inventory.armorInventory); // player#getArmorInventoryList() only returns an Iterable
|
stacks.addAll(player.inventory.armorInventory); // player#getArmorInventoryList() only returns an Iterable
|
||||||
|
|
||||||
|
if(stacks.stream().anyMatch(s -> s.getItem() instanceof IManaStoringItem && !((IManaStoringItem)s.getItem()).isManaFull(s))){
|
||||||
|
|
||||||
|
if(player.capabilities.isCreativeMode){
|
||||||
|
findAndChargeItem(flask, player);
|
||||||
|
}else{
|
||||||
|
player.setActiveHand(hand);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ActionResult<>(EnumActionResult.SUCCESS, flask);
|
||||||
|
|
||||||
|
}else{
|
||||||
|
return new ActionResult<>(EnumActionResult.FAIL, flask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUsingTick(ItemStack stack, EntityLivingBase player, int count){
|
||||||
|
if(player.world.isRemote){
|
||||||
|
float f = count/(float)getMaxItemUseDuration(stack);
|
||||||
|
Vec3d pos = player.getPositionEyes(0).subtract(0, 0.2, 0).add(player.getLookVec().scale(0.6));
|
||||||
|
Vec3d delta = new Vec3d(0, 0.2 * f, 0).rotatePitch(count * 0.5f).rotateYaw((float)Math.toRadians(90 - player.rotationYawHead));
|
||||||
|
ParticleBuilder.create(Type.DUST).pos(pos.add(delta)).vel(delta.scale(0.2)).time(12 + player.world.rand.nextInt(6))
|
||||||
|
.clr(1, 1, 0.65f).fade(0.7f, 0, 1).spawn(player.world);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ItemStack onItemUseFinish(ItemStack stack, World world, EntityLivingBase entity){
|
||||||
|
|
||||||
|
if(entity instanceof EntityPlayer){
|
||||||
|
findAndChargeItem(stack, (EntityPlayer)entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findAndChargeItem(ItemStack stack, EntityPlayer player){
|
||||||
|
|
||||||
|
List<ItemStack> stacks = InventoryUtils.getPrioritisedHotbarAndOffhand(player);
|
||||||
|
stacks.addAll(player.inventory.armorInventory); // player#getArmorInventoryList() only returns an Iterable
|
||||||
|
|
||||||
// Find the chargeable item with the least mana
|
// Find the chargeable item with the least mana
|
||||||
ItemStack toCharge = stacks.stream()
|
ItemStack toCharge = stacks.stream()
|
||||||
.filter(s -> s.getItem() instanceof IManaStoringItem && !((IManaStoringItem)s.getItem()).isManaFull(s))
|
.filter(s -> s.getItem() instanceof IManaStoringItem && !((IManaStoringItem)s.getItem()).isManaFull(s))
|
||||||
@@ -78,13 +136,9 @@ public class ItemManaFlask extends Item {
|
|||||||
EntityUtils.playSoundAtPlayer(player, WizardrySounds.ITEM_MANA_FLASK_USE, 1, 1);
|
EntityUtils.playSoundAtPlayer(player, WizardrySounds.ITEM_MANA_FLASK_USE, 1, 1);
|
||||||
EntityUtils.playSoundAtPlayer(player, WizardrySounds.ITEM_MANA_FLASK_RECHARGE, 0.7f, 1.1f);
|
EntityUtils.playSoundAtPlayer(player, WizardrySounds.ITEM_MANA_FLASK_RECHARGE, 0.7f, 1.1f);
|
||||||
|
|
||||||
if(!player.isCreative()) flask.shrink(1);
|
if(!player.isCreative()) stack.shrink(1);
|
||||||
player.getCooldownTracker().setCooldown(this, 20);
|
player.getCooldownTracker().setCooldown(this, 20);
|
||||||
|
|
||||||
return new ActionResult<>(EnumActionResult.SUCCESS, flask);
|
|
||||||
|
|
||||||
}else{
|
|
||||||
return new ActionResult<>(EnumActionResult.FAIL, flask);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package electroblob.wizardry.item;
|
package electroblob.wizardry.item;
|
||||||
|
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
|
import electroblob.wizardry.block.BlockBookshelf;
|
||||||
import electroblob.wizardry.data.WizardData;
|
import electroblob.wizardry.data.WizardData;
|
||||||
import electroblob.wizardry.event.SpellCastEvent;
|
import electroblob.wizardry.event.SpellCastEvent;
|
||||||
import electroblob.wizardry.event.SpellCastEvent.Source;
|
import electroblob.wizardry.event.SpellCastEvent.Source;
|
||||||
@@ -9,15 +10,25 @@ import electroblob.wizardry.packet.WizardryPacketHandler;
|
|||||||
import electroblob.wizardry.registry.WizardryTabs;
|
import electroblob.wizardry.registry.WizardryTabs;
|
||||||
import electroblob.wizardry.spell.Spell;
|
import electroblob.wizardry.spell.Spell;
|
||||||
import electroblob.wizardry.util.SpellModifiers;
|
import electroblob.wizardry.util.SpellModifiers;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
import net.minecraft.creativetab.CreativeTabs;
|
import net.minecraft.creativetab.CreativeTabs;
|
||||||
import net.minecraft.entity.EntityLivingBase;
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.inventory.Slot;
|
import net.minecraft.inventory.Slot;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.*;
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.EnumActionResult;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.EnumHand;
|
||||||
|
import net.minecraft.util.NonNullList;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraft.util.text.Style;
|
||||||
|
import net.minecraft.util.text.TextFormatting;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.fml.common.Loader;
|
||||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
@@ -100,6 +111,13 @@ public class ItemScroll extends Item implements ISpellCastingItem, IWorkbenchIte
|
|||||||
tooltip.add(spell.getElement().getDisplayName());
|
tooltip.add(spell.getElement().getDisplayName());
|
||||||
tooltip.add(spell.getType().getDisplayName());
|
tooltip.add(spell.getType().getDisplayName());
|
||||||
}
|
}
|
||||||
|
// Advanced tooltips displays the source mod's name if the spell is not from Wizardry
|
||||||
|
if (advanced.isAdvanced() && this.getRegistryName().toString().equals(Wizardry.MODID + ":scroll") && !spell.getRegistryName().getNamespace().equals(Wizardry.MODID)) {
|
||||||
|
String modId = spell.getRegistryName().getNamespace();
|
||||||
|
String name = new Style().setColor(TextFormatting.BLUE).setItalic(true).getFormattingCode() +
|
||||||
|
Loader.instance().getIndexedModList().get(modId).getMetadata().name;
|
||||||
|
tooltip.add(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,6 +126,20 @@ public class ItemScroll extends Item implements ISpellCastingItem, IWorkbenchIte
|
|||||||
return CASTING_TIME;
|
return CASTING_TIME;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand,
|
||||||
|
EnumFacing facing, float hitX, float hitY, float hitZ){
|
||||||
|
if(player.isSneaking()){
|
||||||
|
IBlockState state = world.getBlockState(pos);
|
||||||
|
if(state.getBlock() instanceof BlockBookshelf){
|
||||||
|
if(state.getBlock().onBlockActivated(world, pos, state, player, hand, facing, hitX, hitY, hitZ)){
|
||||||
|
return EnumActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EnumActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
|
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
|
||||||
|
|
||||||
@@ -146,12 +178,21 @@ public class ItemScroll extends Item implements ISpellCastingItem, IWorkbenchIte
|
|||||||
|
|
||||||
Spell spell = Spell.byMetadata(stack.getItemDamage());
|
Spell spell = Spell.byMetadata(stack.getItemDamage());
|
||||||
// By default, scrolls have no modifiers - but with the event system, they could be added.
|
// By default, scrolls have no modifiers - but with the event system, they could be added.
|
||||||
SpellModifiers modifiers = new SpellModifiers();
|
|
||||||
|
SpellModifiers modifiers;
|
||||||
|
|
||||||
|
if(WizardData.get(player) != null){
|
||||||
|
modifiers = WizardData.get(player).itemCastingModifiers;
|
||||||
|
}else{
|
||||||
|
modifiers = new SpellModifiers();
|
||||||
|
}
|
||||||
|
|
||||||
int castingTick = stack.getMaxItemUseDuration() - count;
|
int castingTick = stack.getMaxItemUseDuration() - count;
|
||||||
|
|
||||||
// Continuous spells (these must check if they can be cast each tick since the mana changes)
|
// Continuous spells (these must check if they can be cast each tick since the mana changes)
|
||||||
// In theory the spell is always continuous here but just in case it isn't...
|
// In theory the spell is always continuous here but just in case it isn't...
|
||||||
if(spell.isContinuous && canCast(stack, spell, player, player.getActiveHand(), castingTick, modifiers)){
|
// Do not check canCast() on tick 0 as it is already done in onItemRightClick() and would duplicate modifiers
|
||||||
|
if(spell.isContinuous && (castingTick == 0 || canCast(stack, spell, player, player.getActiveHand(), castingTick, modifiers))){
|
||||||
cast(stack, spell, player, player.getActiveHand(), castingTick, modifiers);
|
cast(stack, spell, player, player.getActiveHand(), castingTick, modifiers);
|
||||||
}else{
|
}else{
|
||||||
// Scrolls normally work on the max use duration so this isn't ever reached by wizardry, but if the
|
// Scrolls normally work on the max use duration so this isn't ever reached by wizardry, but if the
|
||||||
@@ -195,7 +236,7 @@ public class ItemScroll extends Item implements ISpellCastingItem, IWorkbenchIte
|
|||||||
if(!spell.isContinuous && !caster.isCreative()) stack.shrink(1);
|
if(!spell.isContinuous && !caster.isCreative()) stack.shrink(1);
|
||||||
|
|
||||||
// Now uses the vanilla cooldown mechanic to prevent spamming of spells
|
// Now uses the vanilla cooldown mechanic to prevent spamming of spells
|
||||||
if(!spell.isContinuous) caster.getCooldownTracker().setCooldown(this, spell.getCooldown());
|
if(!spell.isContinuous && !caster.isCreative()) caster.getCooldownTracker().setCooldown(this, spell.getCooldown());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -230,7 +271,7 @@ public class ItemScroll extends Item implements ISpellCastingItem, IWorkbenchIte
|
|||||||
MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Finish(Source.SCROLL, spell, user, modifiers, castingTick));
|
MinecraftForge.EVENT_BUS.post(new SpellCastEvent.Finish(Source.SCROLL, spell, user, modifiers, castingTick));
|
||||||
spell.finishCasting(user.world, user, Double.NaN, Double.NaN, Double.NaN, null, castingTick, modifiers);
|
spell.finishCasting(user.world, user, Double.NaN, Double.NaN, Double.NaN, null, castingTick, modifiers);
|
||||||
|
|
||||||
if(user instanceof EntityPlayer){
|
if(user instanceof EntityPlayer && !((EntityPlayer)user).isCreative()){
|
||||||
((EntityPlayer)user).getCooldownTracker().setCooldown(this, spell.getCooldown());
|
((EntityPlayer)user).getCooldownTracker().setCooldown(this, spell.getCooldown());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package electroblob.wizardry.item;
|
package electroblob.wizardry.item;
|
||||||
|
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
|
import electroblob.wizardry.entity.projectile.EntityConjuredArrow;
|
||||||
import electroblob.wizardry.registry.Spells;
|
import electroblob.wizardry.registry.Spells;
|
||||||
import electroblob.wizardry.util.InventoryUtils;
|
import electroblob.wizardry.util.InventoryUtils;
|
||||||
import net.minecraft.enchantment.EnchantmentHelper;
|
import net.minecraft.enchantment.EnchantmentHelper;
|
||||||
@@ -14,6 +15,7 @@ import net.minecraft.init.SoundEvents;
|
|||||||
import net.minecraft.item.IItemPropertyGetter;
|
import net.minecraft.item.IItemPropertyGetter;
|
||||||
import net.minecraft.item.ItemArrow;
|
import net.minecraft.item.ItemArrow;
|
||||||
import net.minecraft.item.ItemBow;
|
import net.minecraft.item.ItemBow;
|
||||||
|
import net.minecraft.item.ItemSpectralArrow;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.stats.StatList;
|
import net.minecraft.stats.StatList;
|
||||||
import net.minecraft.util.*;
|
import net.minecraft.util.*;
|
||||||
@@ -197,8 +199,7 @@ public class ItemSpectralBow extends ItemBow implements IConjuredItem {
|
|||||||
|
|
||||||
if(!world.isRemote){
|
if(!world.isRemote){
|
||||||
|
|
||||||
ItemArrow itemarrow = (ItemArrow)Items.ARROW;
|
EntityConjuredArrow entityarrow = new EntityConjuredArrow(world, entityplayer);
|
||||||
EntityArrow entityarrow = itemarrow.createArrow(world, new ItemStack(itemarrow), entityplayer);
|
|
||||||
entityarrow.shoot(entityplayer, entityplayer.rotationPitch, entityplayer.rotationYaw, 0.0F,
|
entityarrow.shoot(entityplayer, entityplayer.rotationPitch, entityplayer.rotationYaw, 0.0F,
|
||||||
f * 3.0F, 1.0F);
|
f * 3.0F, 1.0F);
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ public class ItemSpectralDust extends Item implements IMultiTexturedItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> items){
|
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> items){
|
||||||
if(tab == WizardryTabs.WIZARDRY){
|
if(tab == WizardryTabs.WIZARDRY || tab == CreativeTabs.SEARCH){
|
||||||
for(Element element : Arrays.copyOfRange(Element.values(), 1, Element.values().length)){
|
for(Element element : Arrays.copyOfRange(Element.values(), 1, Element.values().length)){
|
||||||
items.add(new ItemStack(this, 1, element.ordinal()));
|
items.add(new ItemStack(this, 1, element.ordinal()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package electroblob.wizardry.item;
|
package electroblob.wizardry.item;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import electroblob.wizardry.block.BlockBookshelf;
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
import electroblob.wizardry.WizardryGuiHandler;
|
import electroblob.wizardry.WizardryGuiHandler;
|
||||||
import electroblob.wizardry.constants.Tier;
|
import electroblob.wizardry.constants.Tier;
|
||||||
@@ -12,10 +13,18 @@ import net.minecraft.creativetab.CreativeTabs;
|
|||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.*;
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.EnumActionResult;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.EnumHand;
|
||||||
|
import net.minecraft.util.NonNullList;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
import net.minecraft.util.text.Style;
|
import net.minecraft.util.text.Style;
|
||||||
import net.minecraft.util.text.TextFormatting;
|
import net.minecraft.util.text.TextFormatting;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.fml.common.Loader;
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
import net.minecraftforge.oredict.OreDictionary;
|
import net.minecraftforge.oredict.OreDictionary;
|
||||||
@@ -53,6 +62,21 @@ public class ItemSpellBook extends Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand,
|
||||||
|
EnumFacing facing, float hitX, float hitY, float hitZ){
|
||||||
|
// Minecraft skips onBlockActivated when sneaking with a non-empty hand, so we handle it here
|
||||||
|
if(player.isSneaking()){
|
||||||
|
IBlockState state = world.getBlockState(pos);
|
||||||
|
if(state.getBlock() instanceof BlockBookshelf){
|
||||||
|
if(state.getBlock().onBlockActivated(world, pos, state, player, hand, facing, hitX, hitY, hitZ)){
|
||||||
|
return EnumActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EnumActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
|
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
|
||||||
ItemStack stack = player.getHeldItem(hand);
|
ItemStack stack = player.getHeldItem(hand);
|
||||||
@@ -96,6 +120,13 @@ public class ItemSpellBook extends Item {
|
|||||||
tooltip.add(spell.getElement().getDisplayName());
|
tooltip.add(spell.getElement().getDisplayName());
|
||||||
tooltip.add(spell.getType().getDisplayName());
|
tooltip.add(spell.getType().getDisplayName());
|
||||||
}
|
}
|
||||||
|
// Advanced tooltips displays the source mod's name if the spell is not from Wizardry
|
||||||
|
if (advanced.isAdvanced() && this.getRegistryName().toString().equals(Wizardry.MODID + ":spell_book") && !spell.getRegistryName().getNamespace().equals(Wizardry.MODID)) {
|
||||||
|
String modId = spell.getRegistryName().getNamespace();
|
||||||
|
String name = new Style().setColor(TextFormatting.BLUE).setItalic(true).getFormattingCode() +
|
||||||
|
Loader.instance().getIndexedModList().get(modId).getMetadata().name;
|
||||||
|
tooltip.add(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import net.minecraft.inventory.Slot;
|
|||||||
import net.minecraft.item.EnumAction;
|
import net.minecraft.item.EnumAction;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
import net.minecraft.util.*;
|
import net.minecraft.util.*;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.RayTraceResult;
|
import net.minecraft.util.math.RayTraceResult;
|
||||||
@@ -45,6 +46,7 @@ import net.minecraftforge.fml.relauncher.Side;
|
|||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
@@ -68,7 +70,7 @@ import java.util.Random;
|
|||||||
public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem, IManaStoringItem {
|
public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem, IManaStoringItem {
|
||||||
|
|
||||||
/** The number of spell slots a wand has with no attunement upgrades applied. */
|
/** The number of spell slots a wand has with no attunement upgrades applied. */
|
||||||
public static final int BASE_SPELL_SLOTS = 5;
|
public static int BASE_SPELL_SLOTS;
|
||||||
|
|
||||||
/** The number of ticks between each time a continuous spell is added to the player's recently-cast spells. */
|
/** The number of ticks between each time a continuous spell is added to the player's recently-cast spells. */
|
||||||
private static final int CONTINUOUS_TRACKING_INTERVAL = 20;
|
private static final int CONTINUOUS_TRACKING_INTERVAL = 20;
|
||||||
@@ -101,7 +103,7 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
|||||||
|| s.getItemUseAction() == SpellActions.GRAPPLE
|
|| s.getItemUseAction() == SpellActions.GRAPPLE
|
||||||
|| s.getItemUseAction() == SpellActions.SUMMON) ? 1 : 0);
|
|| s.getItemUseAction() == SpellActions.SUMMON) ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Spell getCurrentSpell(ItemStack stack){
|
public Spell getCurrentSpell(ItemStack stack){
|
||||||
return WandHelper.getCurrentSpell(stack);
|
return WandHelper.getCurrentSpell(stack);
|
||||||
@@ -226,14 +228,22 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpdate(ItemStack stack, World world, Entity entity, int slot, boolean isHeld){
|
public void onUpdate(ItemStack stack, World world, Entity entity, int slot, boolean isHeldInMainhand){
|
||||||
|
boolean isHeld = isHeldInMainhand || entity instanceof EntityLivingBase && ItemStack.areItemStacksEqual(stack, ((EntityLivingBase) entity).getHeldItemOffhand());
|
||||||
|
|
||||||
WandHelper.decrementCooldowns(stack);
|
// If Wizardry.settings.wandsMustBeHeldToDecrementCooldown is false, the cooldowns will be decremented.
|
||||||
|
// If Wizardry.settings.wandsMustBeHeldToDecrementCooldown is true and isHeld is true, the cooldowns will also be decremented.
|
||||||
|
// If Wizardry.settings.wandsMustBeHeldToDecrementCooldown is true and isHeld is false, the cooldowns will not be decremented.
|
||||||
|
if (!Wizardry.settings.wandsMustBeHeldToDecrementCooldown || isHeld) {
|
||||||
|
WandHelper.decrementCooldowns(stack);
|
||||||
|
}
|
||||||
|
|
||||||
// Decrements wand damage (increases mana) every 1.5 seconds if it has a condenser upgrade
|
// Decrements wand damage (increases mana) every 1.5 seconds if it has a condenser upgrade
|
||||||
if(!world.isRemote && !this.isManaFull(stack) && world.getTotalWorldTime() % Constants.CONDENSER_TICK_INTERVAL == 0){
|
if(!world.isRemote && !this.isManaFull(stack) && world.getTotalWorldTime() % Constants.CONDENSER_TICK_INTERVAL == 0){
|
||||||
// If the upgrade level is 0, this does nothing anyway.
|
// If the upgrade level is 0, this does nothing anyway.
|
||||||
this.rechargeMana(stack, WandHelper.getUpgradeLevel(stack, WizardryItems.condenser_upgrade));
|
int baseAmount = WandHelper.getUpgradeLevel(stack, WizardryItems.condenser_upgrade);
|
||||||
|
int amount = (int)(baseAmount * Wizardry.settings.condenserAmountMultiplier);
|
||||||
|
this.rechargeMana(stack, amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,7 +719,7 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
|||||||
|
|
||||||
if(player != null) WizardData.get(player).setTierReached(tier);
|
if(player != null) WizardData.get(player).setTierReached(tier);
|
||||||
|
|
||||||
ItemStack newWand = new ItemStack(WizardryItems.getWand(tier, this.element));
|
ItemStack newWand = new ItemStack(getWand(tier, this.element));
|
||||||
newWand.setTagCompound(wand.getTagCompound());
|
newWand.setTagCompound(wand.getTagCompound());
|
||||||
// This needs to be done after copying the tag compound so the mana capacity for the new wand
|
// This needs to be done after copying the tag compound so the mana capacity for the new wand
|
||||||
// takes storage upgrades into account
|
// takes storage upgrades into account
|
||||||
@@ -727,7 +737,7 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
|||||||
Item specialUpgrade = upgrade.getItem();
|
Item specialUpgrade = upgrade.getItem();
|
||||||
|
|
||||||
int maxUpgrades = this.tier.upgradeLimit;
|
int maxUpgrades = this.tier.upgradeLimit;
|
||||||
if(this.element == Element.MAGIC) maxUpgrades += Constants.NON_ELEMENTAL_UPGRADE_BONUS;
|
if(this.element == null) maxUpgrades += Constants.NON_ELEMENTAL_UPGRADE_BONUS;
|
||||||
|
|
||||||
if(WandHelper.getTotalUpgrades(wand) < maxUpgrades
|
if(WandHelper.getTotalUpgrades(wand) < maxUpgrades
|
||||||
&& WandHelper.getUpgradeLevel(wand, specialUpgrade) < Constants.UPGRADE_STACK_LIMIT){
|
&& WandHelper.getUpgradeLevel(wand, specialUpgrade) < Constants.UPGRADE_STACK_LIMIT){
|
||||||
@@ -783,6 +793,30 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
|||||||
return wand;
|
return wand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to return the appropriate wand based on tier and element. This replaces the cumbersome wand map in
|
||||||
|
* {@link WizardryItems} by accessing the item registry dynamically by generating the registry name on the fly.
|
||||||
|
* <p></p>
|
||||||
|
* <i><b>This method will only return wands from the base mod.</b> It is unlikely that addons will need it, but it
|
||||||
|
* has been left public just in case. The intention is that this method is only used where there is no alternative.</i>
|
||||||
|
*
|
||||||
|
* @param tier The tier of the wand required.
|
||||||
|
* @param element The element of the wand required. Null will be converted to {@link Element#MAGIC}.
|
||||||
|
* @return The wand item which corresponds to the given tier and element, or null if no such item exists.
|
||||||
|
* @throws NullPointerException if the given tier is null.
|
||||||
|
*/
|
||||||
|
// As noted above, in a few SPECIFIC cases this method is necessary (without using a data-driven system, at least,
|
||||||
|
// which I'm not going to spend the time making in the near future). Wizard trades and gear have been left using the
|
||||||
|
// WizardryItems version because they need to be replaced with a better system that doesn't use this at all.
|
||||||
|
public static Item getWand(Tier tier, Element element){
|
||||||
|
if(tier == null) throw new NullPointerException("The given tier cannot be null.");
|
||||||
|
if(element == null) element = Element.MAGIC;
|
||||||
|
String registryName = tier == Tier.NOVICE && element == Element.MAGIC ? "magic" : tier.getUnlocalisedName();
|
||||||
|
if(element != Element.MAGIC) registryName = registryName + "_" + element.getName();
|
||||||
|
registryName = registryName + "_wand";
|
||||||
|
return Item.REGISTRY.getObject(new ResourceLocation(Wizardry.MODID, registryName));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){
|
public boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){
|
||||||
|
|
||||||
@@ -791,7 +825,7 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
|||||||
if(upgrade.getHasStack()){
|
if(upgrade.getHasStack()){
|
||||||
ItemStack original = centre.getStack().copy();
|
ItemStack original = centre.getStack().copy();
|
||||||
centre.putStack(this.applyUpgrade(player, centre.getStack(), upgrade.getStack()));
|
centre.putStack(this.applyUpgrade(player, centre.getStack(), upgrade.getStack()));
|
||||||
changed = ItemStack.areItemStacksEqual(centre.getStack(), original);
|
changed = !ItemStack.areItemStacksEqual(centre.getStack(), original);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads NBT spell metadata array to variable, edits this, then writes it back to NBT.
|
// Reads NBT spell metadata array to variable, edits this, then writes it back to NBT.
|
||||||
@@ -812,8 +846,19 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
|||||||
Spell spell = Spell.byMetadata(spellBooks[i].getStack().getItemDamage());
|
Spell spell = Spell.byMetadata(spellBooks[i].getStack().getItemDamage());
|
||||||
// If the wand is powerful enough for the spell, it's not already bound to that slot and it's enabled for wands
|
// If the wand is powerful enough for the spell, it's not already bound to that slot and it's enabled for wands
|
||||||
if(!(spell.getTier().level > this.tier.level) && spells[i] != spell && spell.isEnabled(SpellProperties.Context.WANDS)){
|
if(!(spell.getTier().level > this.tier.level) && spells[i] != spell && spell.isEnabled(SpellProperties.Context.WANDS)){
|
||||||
|
|
||||||
|
// Decide if we can bind this multiple times
|
||||||
|
if (Wizardry.settings.preventBindingSameSpellTwiceToWands && Arrays.stream(spells).anyMatch(s -> s == spell)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
spells[i] = spell;
|
spells[i] = spell;
|
||||||
changed = true;
|
changed = true;
|
||||||
|
|
||||||
|
// setting to consume books upon use
|
||||||
|
if (Wizardry.settings.singleUseSpellBooks) {
|
||||||
|
spellBooks[i].getStack().shrink(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -821,31 +866,35 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
|||||||
WandHelper.setSpells(centre.getStack(), spells);
|
WandHelper.setSpells(centre.getStack(), spells);
|
||||||
|
|
||||||
// Charges wand by appropriate amount
|
// Charges wand by appropriate amount
|
||||||
if(crystals.getStack() != ItemStack.EMPTY && !this.isManaFull(centre.getStack())){
|
if (WandHelper.rechargeManaOnApplyButtonPressed(centre, crystals)) {
|
||||||
|
|
||||||
int chargeDepleted = this.getManaCapacity(centre.getStack()) - this.getMana(centre.getStack());
|
|
||||||
|
|
||||||
int manaPerItem = Constants.MANA_PER_CRYSTAL;
|
|
||||||
if(crystals.getStack().getItem() == WizardryItems.crystal_shard) manaPerItem = Constants.MANA_PER_SHARD;
|
|
||||||
if(crystals.getStack().getItem() == WizardryItems.grand_crystal) manaPerItem = Constants.GRAND_CRYSTAL_MANA;
|
|
||||||
|
|
||||||
if(crystals.getStack().getCount() * manaPerItem < chargeDepleted){
|
|
||||||
// If there aren't enough crystals to fully charge the wand
|
|
||||||
this.rechargeMana(centre.getStack(), crystals.getStack().getCount() * manaPerItem);
|
|
||||||
crystals.decrStackSize(crystals.getStack().getCount());
|
|
||||||
|
|
||||||
}else{
|
|
||||||
// If there are excess crystals (or just enough)
|
|
||||||
this.setMana(centre.getStack(), this.getManaCapacity(centre.getStack()));
|
|
||||||
crystals.decrStackSize((int)Math.ceil(((double)chargeDepleted) / manaPerItem));
|
|
||||||
}
|
|
||||||
|
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return changed;
|
return changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClearButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){
|
||||||
|
ItemStack stack = centre.getStack();
|
||||||
|
if (stack.hasTagCompound() && stack.getTagCompound().hasKey(WandHelper.SPELL_ARRAY_KEY)) {
|
||||||
|
NBTTagCompound nbt = stack.getTagCompound();
|
||||||
|
int[] spells = nbt.getIntArray(WandHelper.SPELL_ARRAY_KEY);
|
||||||
|
int expectedSlotCount = BASE_SPELL_SLOTS + WandHelper.getUpgradeLevel(stack,
|
||||||
|
WizardryItems.attunement_upgrade);
|
||||||
|
|
||||||
|
// unbrick broken wands
|
||||||
|
if (spells.length < expectedSlotCount) {
|
||||||
|
spells = new int[expectedSlotCount];
|
||||||
|
}
|
||||||
|
Arrays.fill(spells, 0);
|
||||||
|
nbt.setIntArray(WandHelper.SPELL_ARRAY_KEY, spells);
|
||||||
|
stack.setTagCompound(nbt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isClearable() { return true; }
|
||||||
|
|
||||||
// hitEntity is only called server-side, so we'll have to use events
|
// hitEntity is only called server-side, so we'll have to use events
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onAttackEntityEvent(AttackEntityEvent event){
|
public static void onAttackEntityEvent(AttackEntityEvent event){
|
||||||
|
|||||||
@@ -1,10 +1,17 @@
|
|||||||
package electroblob.wizardry.item;
|
package electroblob.wizardry.item;
|
||||||
|
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
|
import electroblob.wizardry.block.BlockBookshelf;
|
||||||
import electroblob.wizardry.registry.WizardryTabs;
|
import electroblob.wizardry.registry.WizardryTabs;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.item.EnumRarity;
|
import net.minecraft.item.EnumRarity;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.EnumActionResult;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.EnumHand;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
@@ -24,6 +31,20 @@ public class ItemWandUpgrade extends Item {
|
|||||||
return EnumRarity.UNCOMMON;
|
return EnumRarity.UNCOMMON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand,
|
||||||
|
EnumFacing facing, float hitX, float hitY, float hitZ){
|
||||||
|
if(player.isSneaking()){
|
||||||
|
IBlockState state = world.getBlockState(pos);
|
||||||
|
if(state.getBlock() instanceof BlockBookshelf){
|
||||||
|
if(state.getBlock().onBlockActivated(world, pos, state, player, hand, facing, hitX, hitY, hitZ)){
|
||||||
|
return EnumActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EnumActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SideOnly(Side.CLIENT)
|
@SideOnly(Side.CLIENT)
|
||||||
public void addInformation(ItemStack stack, @Nullable World world, List<String> tooltip, net.minecraft.client.util.ITooltipFlag flag) {
|
public void addInformation(ItemStack stack, @Nullable World world, List<String> tooltip, net.minecraft.client.util.ITooltipFlag flag) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package electroblob.wizardry.item;
|
package electroblob.wizardry.item;
|
||||||
|
|
||||||
import com.google.common.collect.HashMultimap;
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.collect.Streams;
|
import com.google.common.collect.Streams;
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
@@ -8,10 +8,13 @@ import electroblob.wizardry.client.DrawingUtils;
|
|||||||
import electroblob.wizardry.constants.Constants;
|
import electroblob.wizardry.constants.Constants;
|
||||||
import electroblob.wizardry.constants.Element;
|
import electroblob.wizardry.constants.Element;
|
||||||
import electroblob.wizardry.event.SpellCastEvent;
|
import electroblob.wizardry.event.SpellCastEvent;
|
||||||
import electroblob.wizardry.registry.WizardryAdvancementTriggers;
|
|
||||||
import electroblob.wizardry.registry.WizardryItems;
|
import electroblob.wizardry.registry.WizardryItems;
|
||||||
|
import electroblob.wizardry.registry.WizardryItems.Materials;
|
||||||
|
import electroblob.wizardry.registry.WizardryPotions;
|
||||||
import electroblob.wizardry.registry.WizardryRecipes;
|
import electroblob.wizardry.registry.WizardryRecipes;
|
||||||
import electroblob.wizardry.registry.WizardryTabs;
|
import electroblob.wizardry.registry.WizardryTabs;
|
||||||
|
import electroblob.wizardry.spell.Spell;
|
||||||
|
import electroblob.wizardry.util.EntityUtils.Operations;
|
||||||
import electroblob.wizardry.util.InventoryUtils;
|
import electroblob.wizardry.util.InventoryUtils;
|
||||||
import electroblob.wizardry.util.SpellModifiers;
|
import electroblob.wizardry.util.SpellModifiers;
|
||||||
import net.minecraft.enchantment.Enchantment;
|
import net.minecraft.enchantment.Enchantment;
|
||||||
@@ -24,13 +27,17 @@ import net.minecraft.entity.ai.attributes.AttributeModifier;
|
|||||||
import net.minecraft.entity.ai.attributes.IAttributeInstance;
|
import net.minecraft.entity.ai.attributes.IAttributeInstance;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||||
|
import net.minecraft.inventory.EntityEquipmentSlot.Type;
|
||||||
import net.minecraft.inventory.Slot;
|
import net.minecraft.inventory.Slot;
|
||||||
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemArmor;
|
import net.minecraft.item.ItemArmor;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.nbt.NBTTagCompound;
|
import net.minecraft.potion.PotionEffect;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
import net.minecraft.util.text.Style;
|
import net.minecraft.util.text.Style;
|
||||||
import net.minecraft.util.text.TextFormatting;
|
import net.minecraft.util.text.TextFormatting;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.event.entity.living.LivingEquipmentChangeEvent;
|
||||||
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
|
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.common.eventhandler.EventPriority;
|
import net.minecraftforge.fml.common.eventhandler.EventPriority;
|
||||||
@@ -40,21 +47,94 @@ import net.minecraftforge.fml.relauncher.SideOnly;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@Mod.EventBusSubscriber
|
@Mod.EventBusSubscriber
|
||||||
public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IManaStoringItem {
|
public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IManaStoringItem {
|
||||||
|
|
||||||
// VanillaCopy, ItemArmor has this set to private for some reason.
|
// Full set bonuses
|
||||||
public static final UUID[] ARMOR_MODIFIERS = new UUID[] {UUID.fromString("845DB27C-C624-495F-8C9F-6020A9A58B6B"), UUID.fromString("D8499B04-0E66-4726-AB29-64469D734E0D"), UUID.fromString("9F3D476D-C118-4544-8365-64846904B48E"), UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150")};
|
private static final float SAGE_OTHER_COST_REDUCTION = 0.2f;
|
||||||
// Damage reduction values that used to be in WizardryItems.SILK [feet, legs, chest, head]
|
private static final float WARLOCK_SPEED_BOOST = 0.2f;
|
||||||
private static int[] reductions = new int[]{2, 4, 5, 2};
|
private static final UUID WARLOCK_SPEED_BOOST_UUID = UUID.fromString("4bad7152-2663-4b1b-bb59-552e92847031");
|
||||||
|
// Standard ItemArmor modifiers
|
||||||
public Element element;
|
private static final UUID[] ARMOR_MODIFIERS = new UUID[] {UUID.fromString("845DB27C-C624-495F-8C9F-6020A9A58B6B"), UUID.fromString("D8499B04-0E66-4726-AB29-64469D734E0D"), UUID.fromString("9F3D476D-C118-4544-8365-64846904B48E"), UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150")};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Multimap<String, AttributeModifier> getItemAttributeModifiers(EntityEquipmentSlot slot) {
|
||||||
|
// The vanilla armor handling logic from ItemArmor.getItemAttributeModifiers was moved to ItemWizardArmour.getAttributeModifiers to allow checking if the stack has enough mana
|
||||||
|
Multimap<String, AttributeModifier> multimap = ArrayListMultimap.create();
|
||||||
|
return multimap;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Multimap<String, AttributeModifier> getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack) {
|
||||||
|
Multimap<String, AttributeModifier> multimap = super.getAttributeModifiers(slot, stack);
|
||||||
|
|
||||||
|
// only grant armor if the equipment has mana
|
||||||
|
if (slot == this.armorType && !((ItemWizardArmour) stack.getItem()).isManaEmpty(stack)) {
|
||||||
|
multimap.put(SharedMonsterAttributes.ARMOR.getName(), new AttributeModifier(ARMOR_MODIFIERS[slot.getIndex()], "Armor modifier", this.damageReduceAmount, 0));
|
||||||
|
multimap.put(SharedMonsterAttributes.ARMOR_TOUGHNESS.getName(), new AttributeModifier(ARMOR_MODIFIERS[slot.getIndex()], "Armor toughness", this.toughness, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return multimap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ArmourClass {
|
||||||
|
|
||||||
|
WIZARD(Materials.SILK, () -> null, "wizard", 0.1f, 0, "hat", "robe", "leggings", "boots"),
|
||||||
|
SAGE(Materials.SAGE, () -> WizardryItems.resplendent_thread, "sage", 0.2f, 0, "hat", "robe", "leggings", "boots"),
|
||||||
|
BATTLEMAGE(Materials.BATTLEMAGE, () -> WizardryItems.crystal_silver_plating, "battlemage", 0.05f, 0.05f, "helmet", "chestplate", "leggings", "boots"),
|
||||||
|
WARLOCK(Materials.WARLOCK, () -> WizardryItems.ethereal_crystalweave, "warlock", 0.1f, 0.1f, "hood", "robe", "leggings", "boots");
|
||||||
|
|
||||||
|
/** The armour material to use for this armour class. */
|
||||||
|
final ArmorMaterial material;
|
||||||
|
/** The item that upgrades regular wizard armour into this class of armour. */
|
||||||
|
final Supplier<Item> upgradeItem;
|
||||||
|
/** The fraction by which spell cost is reduced for each armour piece of this class with the matching element. */
|
||||||
|
final float elementalCostReduction;
|
||||||
|
/** The fraction by which spell cooldown is reduced for each armour piece of this class. */
|
||||||
|
final float cooldownReduction;
|
||||||
|
/** The first part of the texture filenames for this armour class. Also defines certain translation keys. */
|
||||||
|
final String name;
|
||||||
|
/** The middle part of each item name (in the registry) for this armour class, e.g. "hat" or "chestplate". */
|
||||||
|
final Map<EntityEquipmentSlot, String> armourPieceNames;
|
||||||
|
|
||||||
|
ArmourClass(ArmorMaterial material, Supplier<Item> upgradeItem, String name, float elementalCostReduction,
|
||||||
|
float cooldownReduction, String... armourPieceNames){
|
||||||
|
this.material = material;
|
||||||
|
this.upgradeItem = upgradeItem;
|
||||||
|
this.name = name;
|
||||||
|
this.elementalCostReduction = elementalCostReduction;
|
||||||
|
this.cooldownReduction = cooldownReduction;
|
||||||
|
if(armourPieceNames.length != 4) throw new IllegalArgumentException("armourPieceNames must have a length of 4");
|
||||||
|
this.armourPieceNames = new EnumMap<>(EntityEquipmentSlot.class);
|
||||||
|
this.armourPieceNames.put(EntityEquipmentSlot.HEAD, armourPieceNames[0]);
|
||||||
|
this.armourPieceNames.put(EntityEquipmentSlot.CHEST, armourPieceNames[1]);
|
||||||
|
this.armourPieceNames.put(EntityEquipmentSlot.LEGS, armourPieceNames[2]);
|
||||||
|
this.armourPieceNames.put(EntityEquipmentSlot.FEET, armourPieceNames[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Element element; // Should be final, but isn't for backwards compatibility
|
||||||
|
public final ArmourClass armourClass;
|
||||||
|
|
||||||
|
@Deprecated // Retained for backwards-compatibility with addons, will be removed in future
|
||||||
public ItemWizardArmour(ArmorMaterial material, int renderIndex, EntityEquipmentSlot armourType, Element element){
|
public ItemWizardArmour(ArmorMaterial material, int renderIndex, EntityEquipmentSlot armourType, Element element){
|
||||||
super(material, renderIndex, armourType);
|
super(material, renderIndex, armourType);
|
||||||
|
this.armourClass = ArmourClass.WIZARD;
|
||||||
|
this.element = element;
|
||||||
|
setCreativeTab(WizardryTabs.GEAR);
|
||||||
|
WizardryRecipes.addToManaFlaskCharging(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemWizardArmour(ArmourClass armourClass, EntityEquipmentSlot armourType, Element element){
|
||||||
|
super(armourClass.material, 1, armourType);
|
||||||
|
this.armourClass = armourClass;
|
||||||
this.element = element;
|
this.element = element;
|
||||||
setCreativeTab(WizardryTabs.GEAR);
|
setCreativeTab(WizardryTabs.GEAR);
|
||||||
WizardryRecipes.addToManaFlaskCharging(this);
|
WizardryRecipes.addToManaFlaskCharging(this);
|
||||||
@@ -94,15 +174,75 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
|
|||||||
@SideOnly(Side.CLIENT)
|
@SideOnly(Side.CLIENT)
|
||||||
public void addInformation(ItemStack stack, World world, List<String> tooltip, net.minecraft.client.util.ITooltipFlag advanced){
|
public void addInformation(ItemStack stack, World world, List<String> tooltip, net.minecraft.client.util.ITooltipFlag advanced){
|
||||||
|
|
||||||
if(stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary"))
|
|
||||||
tooltip.add(Wizardry.proxy.translate("item." + Wizardry.MODID + ":wizard_armour.legendary",
|
|
||||||
new Style().setColor(TextFormatting.LIGHT_PURPLE)));
|
|
||||||
|
|
||||||
if(element != null){
|
if(element != null){
|
||||||
tooltip.add(Wizardry.proxy.translate("item." + Wizardry.MODID + ":wizard_armour.buff",
|
tooltip.add(Wizardry.proxy.translate("item." + Wizardry.MODID + ":wizard_armour.element_cost_reduction",
|
||||||
new Style().setColor(TextFormatting.DARK_GRAY),
|
new Style().setColor(TextFormatting.DARK_GRAY),
|
||||||
(int)(Constants.COST_REDUCTION_PER_ARMOUR * 100), element.getDisplayName()));
|
(int)(armourClass.elementalCostReduction * 100), element.getDisplayName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(armourClass == ArmourClass.SAGE){
|
||||||
|
tooltip.add(Wizardry.proxy.translate("item." + Wizardry.MODID + ":wizard_armour.enchantability",
|
||||||
|
new Style().setColor(TextFormatting.BLUE)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(armourClass.cooldownReduction > 0){
|
||||||
|
tooltip.add(Wizardry.proxy.translate("item." + Wizardry.MODID + ":wizard_armour.cooldown_reduction",
|
||||||
|
new Style().setColor(TextFormatting.DARK_GRAY), (int)(armourClass.cooldownReduction * 100)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(armourClass != ArmourClass.WIZARD){
|
||||||
|
|
||||||
|
tooltip.add(Wizardry.proxy.translate("item." + Wizardry.MODID + ":wizard_armour.full_set",
|
||||||
|
new Style().setColor(TextFormatting.AQUA)));
|
||||||
|
|
||||||
|
Object args = new Object[0];
|
||||||
|
|
||||||
|
if(armourClass == ArmourClass.SAGE) args = (int)(SAGE_OTHER_COST_REDUCTION * 100);
|
||||||
|
if(armourClass == ArmourClass.WARLOCK) args = (int)(WARLOCK_SPEED_BOOST * 100);
|
||||||
|
|
||||||
|
tooltip.add(Wizardry.proxy.translate("item." + Wizardry.MODID + ":" + armourClass.name
|
||||||
|
+ "_armour.full_set_bonus", new Style().setColor(TextFormatting.AQUA), args));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onArmorTick(World world, EntityPlayer player, ItemStack itemStack){
|
||||||
|
if(armorType == EntityEquipmentSlot.HEAD && player.ticksExisted % 20 == 0
|
||||||
|
&& isWearingFullSet(player, element, ArmourClass.BATTLEMAGE) && doAllArmourPiecesHaveMana(player)){
|
||||||
|
player.addPotionEffect(new PotionEffect(WizardryPotions.ward, 219, 0, true, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows this armour piece to change the modifiers for spells cast while wearing it. This is called once for
|
||||||
|
* <b>each piece of wizard armour</b> the caster is wearing. This means if you need to apply a full set bonus, you
|
||||||
|
* should have only one of the pieces handle it (by convention, this is usually the helmet, but it doesn't matter).
|
||||||
|
* <p></p>
|
||||||
|
* <i>N.B. The modifiers object passed into this method is not the actual one from the spell cast event. It is a
|
||||||
|
* blank one local to armour that then gets combined with the actual one via
|
||||||
|
* {@link SpellModifiers#combine(SpellModifiers)} after all four pieces have been processed. This is important as it
|
||||||
|
* allows armour modifiers to stack linearly. This means the values should be <b>added/subtracted rather than multiplied.</b></i>
|
||||||
|
* @param caster The entity casting the spell and wearing the armour.
|
||||||
|
* @param spell The spell being cast.
|
||||||
|
* @param modifiers The modifiers specific to armour to apply to the global ones after all four slots are processed.
|
||||||
|
*/
|
||||||
|
protected void applySpellModifiers(EntityLivingBase caster, Spell spell, SpellModifiers modifiers){
|
||||||
|
|
||||||
|
if(spell.getElement() == this.element){
|
||||||
|
modifiers.set(SpellModifiers.COST, modifiers.get(SpellModifiers.COST) - armourClass.elementalCostReduction, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
modifiers.set(WizardryItems.cooldown_upgrade, modifiers.get(WizardryItems.cooldown_upgrade) - armourClass.cooldownReduction, true);
|
||||||
|
|
||||||
|
// Full set bonuses
|
||||||
|
if(this.armorType == EntityEquipmentSlot.HEAD && isWearingFullSet(caster, element, armourClass) && doAllArmourPiecesHaveMana(caster)){
|
||||||
|
if(armourClass == ArmourClass.SAGE && spell.getElement() != this.element){
|
||||||
|
modifiers.set(SpellModifiers.COST, 1 - SAGE_OTHER_COST_REDUCTION, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -118,25 +258,18 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
|
|||||||
// Legs use modelBiped
|
// Legs use modelBiped
|
||||||
if(armourSlot == EntityEquipmentSlot.LEGS && !entityLiving.isInvisible()) return null;
|
if(armourSlot == EntityEquipmentSlot.LEGS && !entityLiving.isInvisible()) return null;
|
||||||
|
|
||||||
return Wizardry.proxy.getWizardArmourModel();
|
return Wizardry.proxy.getWizardArmourModel(getArmorMaterial());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getArmorTexture(ItemStack stack, Entity entity, EntityEquipmentSlot slot, String type){
|
public String getArmorTexture(ItemStack stack, Entity entity, EntityEquipmentSlot slot, String type){
|
||||||
|
|
||||||
// Returns a completely transparent texture if the player is invisible. This is such an annoyingly easy
|
String s = armourClass.name + "_armour";
|
||||||
// fix, considering how long I spent trying to do this before - a bit of lateral thinking was all it took.
|
|
||||||
// Do note however that a texture pack could override this.
|
|
||||||
// if(entity instanceof EntityLivingBase && entity.isInvisible() && !entity.getEntityData().getBoolean(BlockStatue.PETRIFIED_NBT_KEY))
|
|
||||||
// return "ebwizardry:textures/armour/invisible_armour.png";
|
|
||||||
|
|
||||||
String s = "wizard_armour";
|
if(Wizardry.tisTheSeason && armourClass == ArmourClass.WIZARD){
|
||||||
|
|
||||||
if(Wizardry.tisTheSeason){
|
|
||||||
s = s + "_festive";
|
s = s + "_festive";
|
||||||
}else{
|
}else{
|
||||||
if(this.element != null) s = s + "_" + this.element.getName();
|
if(this.element != null) s = s + "_" + this.element.getName();
|
||||||
if(stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary")) s = "legendary_" + s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(slot == EntityEquipmentSlot.LEGS) s = s + "_legs";
|
if(slot == EntityEquipmentSlot.LEGS) s = s + "_legs";
|
||||||
@@ -155,34 +288,6 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
|
|||||||
return !(enchantment instanceof EnchantmentMending) && super.canApplyAtEnchantingTable(stack, 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.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Multimap<String, AttributeModifier> getAttributeModifiers(EntityEquipmentSlot slot, ItemStack stack){
|
|
||||||
|
|
||||||
Multimap<String, AttributeModifier> map = HashMultimap.create();
|
|
||||||
|
|
||||||
if(!this.isManaEmpty(stack) && this.armorType == slot){
|
|
||||||
|
|
||||||
int defense = reductions[slot.getIndex()];
|
|
||||||
float toughness = 0f;
|
|
||||||
|
|
||||||
if(stack.hasTagCompound() && stack.getTagCompound().getBoolean("legendary")) {
|
|
||||||
defense = ArmorMaterial.DIAMOND.getDamageReductionAmount(slot);
|
|
||||||
toughness = ArmorMaterial.DIAMOND.getToughness();
|
|
||||||
}
|
|
||||||
|
|
||||||
map.put(SharedMonsterAttributes.ARMOR.getName(), new AttributeModifier(ARMOR_MODIFIERS[slot.getIndex()],
|
|
||||||
"Armor modifier", defense, 0));
|
|
||||||
map.put(SharedMonsterAttributes.ARMOR.getName(), new AttributeModifier(ARMOR_MODIFIERS[slot.getIndex()],
|
|
||||||
"Armor toughness", toughness, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workbench stuff
|
// Workbench stuff
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -196,17 +301,17 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
|
|||||||
@Override
|
@Override
|
||||||
public ItemStack applyUpgrade(@Nullable EntityPlayer player, ItemStack stack, ItemStack upgrade){
|
public ItemStack applyUpgrade(@Nullable EntityPlayer player, ItemStack stack, ItemStack upgrade){
|
||||||
|
|
||||||
// Applies legendary upgrade
|
// Apply class upgrades
|
||||||
if(upgrade.getItem() == WizardryItems.armour_upgrade){
|
if(this.armourClass == ArmourClass.WIZARD){
|
||||||
|
for(ArmourClass armourClass : ArmourClass.values()){
|
||||||
if(!stack.hasTagCompound()){
|
if(upgrade.getItem() == armourClass.upgradeItem.get()){
|
||||||
stack.setTagCompound(new NBTTagCompound());
|
Item newArmour = getArmour(this.element, armourClass, this.armorType);
|
||||||
}
|
ItemStack newStack = new ItemStack(newArmour);
|
||||||
|
((ItemWizardArmour)newArmour).setMana(newStack, this.getMana(stack));
|
||||||
if(!stack.getTagCompound().hasKey("legendary")){
|
newStack.setTagCompound(stack.getTagCompound());
|
||||||
stack.getTagCompound().setBoolean("legendary", true);
|
upgrade.shrink(1);
|
||||||
upgrade.shrink(1);
|
return newStack;
|
||||||
if(player != null) WizardryAdvancementTriggers.legendary.triggerFor(player);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,7 +326,7 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
|
|||||||
if(upgrade.getHasStack()){
|
if(upgrade.getHasStack()){
|
||||||
ItemStack original = centre.getStack().copy();
|
ItemStack original = centre.getStack().copy();
|
||||||
centre.putStack(this.applyUpgrade(player, centre.getStack(), upgrade.getStack()));
|
centre.putStack(this.applyUpgrade(player, centre.getStack(), upgrade.getStack()));
|
||||||
changed = ItemStack.areItemStacksEqual(centre.getStack(), original);
|
changed = !ItemStack.areItemStacksEqual(centre.getStack(), original);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Charges armour by appropriate amount
|
// Charges armour by appropriate amount
|
||||||
@@ -229,7 +334,12 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
|
|||||||
|
|
||||||
int chargeDepleted = this.getManaCapacity(centre.getStack()) - this.getMana(centre.getStack());
|
int chargeDepleted = this.getManaCapacity(centre.getStack()) - this.getMana(centre.getStack());
|
||||||
|
|
||||||
int manaPerItem = Constants.MANA_PER_CRYSTAL;
|
// Not too pretty but allows addons implementing the IManaStoringItem interface to provide their mana amount for custom crystals,
|
||||||
|
// previously this was defaulted to the regular crystal's amount, allowing players to exploit it if a crystal was worth less mana than that.
|
||||||
|
int manaPerItem = crystals.getStack().getItem() instanceof IManaStoringItem ?
|
||||||
|
((IManaStoringItem) crystals.getStack().getItem()).getMana(crystals.getStack()) :
|
||||||
|
crystals.getStack().getItem() instanceof ItemCrystal ? Constants.MANA_PER_CRYSTAL : Constants.MANA_PER_SHARD;
|
||||||
|
|
||||||
if(crystals.getStack().getItem() == WizardryItems.crystal_shard) manaPerItem = Constants.MANA_PER_SHARD;
|
if(crystals.getStack().getItem() == WizardryItems.crystal_shard) manaPerItem = Constants.MANA_PER_SHARD;
|
||||||
if(crystals.getStack().getItem() == WizardryItems.grand_crystal) manaPerItem = Constants.GRAND_CRYSTAL_MANA;
|
if(crystals.getStack().getItem() == WizardryItems.grand_crystal) manaPerItem = Constants.GRAND_CRYSTAL_MANA;
|
||||||
|
|
||||||
@@ -252,34 +362,43 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
|
|||||||
|
|
||||||
// Event Handlers
|
// Event Handlers
|
||||||
|
|
||||||
// @SubscribeEvent
|
// Can't use Item#getItemAttributeModifiers because it's not player-sensitive, grrr
|
||||||
// public static void onLivingUpdateEvent(LivingUpdateEvent event){
|
@SubscribeEvent
|
||||||
//
|
public static void onLivingEquipmentChangeEvent(LivingEquipmentChangeEvent event){
|
||||||
// if(event.getEntityLiving() instanceof EntityPlayer){
|
|
||||||
//
|
IAttributeInstance movementSpeed = event.getEntityLiving().getAttributeMap().getAttributeInstance(SharedMonsterAttributes.MOVEMENT_SPEED);
|
||||||
// EntityPlayer player = (EntityPlayer)event.getEntityLiving();
|
|
||||||
//
|
if(isWearingFullSet(event.getEntityLiving(), null, ArmourClass.WARLOCK) && doAllArmourPiecesHaveMana(event.getEntityLiving())){
|
||||||
// for(ItemStack stack : player.getArmorInventoryList()){
|
// Only apply the modifier once (can't just check this is the helmet since it might not be the last piece equipped)
|
||||||
// if(!(stack.getItem() instanceof ItemWizardArmour)){
|
if(movementSpeed.getModifier(WARLOCK_SPEED_BOOST_UUID) == null){
|
||||||
// return; // If any of the armour slots doesn't contain wizard armour, don't trigger the achievement.
|
movementSpeed.applyModifier(new AttributeModifier(WARLOCK_SPEED_BOOST_UUID, "Warlock set bonus", WARLOCK_SPEED_BOOST, Operations.MULTIPLY_FLAT));
|
||||||
// }
|
}
|
||||||
// }
|
}else{
|
||||||
// // If it gets this far, then all slots must be wizard armour, so trigger the achievement.
|
movementSpeed.removeModifier(WARLOCK_SPEED_BOOST_UUID);
|
||||||
// WizardryAdvancementTriggers.armour_set.triggerFor(player);
|
}
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
@SubscribeEvent(priority = EventPriority.LOW)
|
@SubscribeEvent(priority = EventPriority.LOW)
|
||||||
public static void onSpellCastPreEvent(SpellCastEvent.Pre event){
|
public static void onSpellCastPreEvent(SpellCastEvent.Pre event){
|
||||||
// Armour cost reduction
|
// Armour cost reduction
|
||||||
if(event.getCaster() == null) return;
|
if(event.getCaster() == null) return;
|
||||||
int armourPieces = getMatchingArmourCount(event.getCaster(), event.getSpell().getElement());
|
|
||||||
float multiplier = 1f - armourPieces * Constants.COST_REDUCTION_PER_ARMOUR;
|
final SpellModifiers armourModifiers = new SpellModifiers();
|
||||||
if(armourPieces == InventoryUtils.ARMOUR_SLOTS.length) multiplier -= Constants.FULL_ARMOUR_SET_BONUS;
|
|
||||||
event.getModifiers().set(SpellModifiers.COST, event.getModifiers().get(SpellModifiers.COST) * multiplier, false);
|
Arrays.stream(InventoryUtils.ARMOUR_SLOTS).map(s -> event.getCaster().getItemStackFromSlot(s).getItem())
|
||||||
|
.filter(i -> i instanceof ItemWizardArmour)
|
||||||
|
.forEach(i -> ((ItemWizardArmour)i).applySpellModifiers(event.getCaster(), event.getSpell(), armourModifiers));
|
||||||
|
|
||||||
|
event.getModifiers().combine(armourModifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Counts the number of armour pieces the given entity is wearing that match the given element. */
|
/**
|
||||||
|
* Counts the number of armour pieces the given entity is wearing that match the given element.
|
||||||
|
* @deprecated in favour of {@link ItemWizardArmour#applySpellModifiers(EntityLivingBase, Spell, SpellModifiers)}
|
||||||
|
* and {@link ItemWizardArmour#isWearingFullSet(EntityLivingBase, Element, ArmourClass)}. Retained for API stability
|
||||||
|
* between minor versions, will be removed in future.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public static int getMatchingArmourCount(EntityLivingBase entity, Element element){
|
public static int getMatchingArmourCount(EntityLivingBase entity, Element element){
|
||||||
return (int)Arrays.stream(InventoryUtils.ARMOUR_SLOTS)
|
return (int)Arrays.stream(InventoryUtils.ARMOUR_SLOTS)
|
||||||
.map(s -> entity.getItemStackFromSlot(s).getItem())
|
.map(s -> entity.getItemStackFromSlot(s).getItem())
|
||||||
@@ -287,6 +406,59 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
|
|||||||
.count();
|
.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to return the appropriate wand based on tier and element. This replaces the cumbersome wand map in
|
||||||
|
* {@link WizardryItems} by accessing the item registry dynamically by generating the registry name on the fly.
|
||||||
|
* <p></p>
|
||||||
|
* <i><b>This method will only return armour from the base mod.</b> It is unlikely that addons will need it, but it
|
||||||
|
* has been left public just in case. The intention is that this method is only used where there is no alternative.</i>
|
||||||
|
*
|
||||||
|
* @param element The element of the wand required. Null will be converted to {@link Element#MAGIC}.
|
||||||
|
* @param armourClass The {@link ArmourClass} required
|
||||||
|
* @param slot EntityEquipmentSlot of the armour piece required
|
||||||
|
* @return The wand item which corresponds to the given tier and element, or null if no such item exists.
|
||||||
|
* @throws NullPointerException if the given tier is null.
|
||||||
|
*/
|
||||||
|
// As noted above, in a few SPECIFIC cases this method is necessary (without using a data-driven system, at least,
|
||||||
|
// which I'm not going to spend the time making in the near future). Wizard trades and gear have been left using the
|
||||||
|
// WizardryItems version because they need to be replaced with a better system that doesn't use this at all.
|
||||||
|
public static Item getArmour(Element element, ArmourClass armourClass, EntityEquipmentSlot slot){
|
||||||
|
if(slot == null || slot.getSlotType() != Type.ARMOR)
|
||||||
|
throw new IllegalArgumentException("Must be a valid armour slot");
|
||||||
|
if(element == null) element = Element.MAGIC;
|
||||||
|
String registryName = armourClass.name + "_" + armourClass.armourPieceNames.get(slot);
|
||||||
|
if(element != Element.MAGIC) registryName = registryName + "_" + element.getName();
|
||||||
|
return Item.REGISTRY.getObject(new ResourceLocation(Wizardry.MODID, registryName));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given entity is wearing a full set of wizard armour of the given class and element.
|
||||||
|
* @param entity The entity to query.
|
||||||
|
* @param element The element to check, or null to accept any element as long as they are all the same.
|
||||||
|
* @param armourClass The class to check, or null to accept any class as long as they are all the same.
|
||||||
|
* @return True if the entity is wearing a full set of the given element and class, false otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean isWearingFullSet(EntityLivingBase entity, @Nullable Element element, @Nullable ArmourClass armourClass){
|
||||||
|
ItemStack helmet = entity.getItemStackFromSlot(EntityEquipmentSlot.HEAD);
|
||||||
|
if(!(helmet.getItem() instanceof ItemWizardArmour)) return false;
|
||||||
|
Element e = element == null ? ((ItemWizardArmour)helmet.getItem()).element : element;
|
||||||
|
ArmourClass ac = armourClass == null ? ((ItemWizardArmour)helmet.getItem()).armourClass : armourClass;
|
||||||
|
return Arrays.stream(InventoryUtils.ARMOUR_SLOTS)
|
||||||
|
.allMatch(s -> entity.getItemStackFromSlot(s).getItem() instanceof ItemWizardArmour
|
||||||
|
&& ((ItemWizardArmour)entity.getItemStackFromSlot(s).getItem()).element == e
|
||||||
|
&& ((ItemWizardArmour)entity.getItemStackFromSlot(s).getItem()).armourClass == ac);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the given entity's armour pieces which implement {@link IManaStoringItem} has mana. Ignores pieces which doesn't have a mana storage.
|
||||||
|
* @param entity The entity to query.
|
||||||
|
* @return True if all armour pieces which implement {@link IManaStoringItem} has mana, false otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean doAllArmourPiecesHaveMana(EntityLivingBase entity){
|
||||||
|
return Arrays.stream(InventoryUtils.ARMOUR_SLOTS).noneMatch(s -> entity.getItemStackFromSlot(s).getItem() instanceof IManaStoringItem
|
||||||
|
&& ((IManaStoringItem) entity.getItemStackFromSlot(s).getItem()).isManaEmpty(entity.getItemStackFromSlot(s)));
|
||||||
|
}
|
||||||
|
|
||||||
@SubscribeEvent
|
@SubscribeEvent
|
||||||
public static void onLivingSetAttackTargetEvent(LivingSetAttackTargetEvent event){
|
public static void onLivingSetAttackTargetEvent(LivingSetAttackTargetEvent event){
|
||||||
// Undo the mob detection penalty for wearing armour when invisible
|
// Undo the mob detection penalty for wearing armour when invisible
|
||||||
@@ -306,7 +478,7 @@ public class ItemWizardArmour extends ItemArmor implements IWorkbenchItem, IMana
|
|||||||
if(event.getTarget().isSneaking()) followRange *= 0.8;
|
if(event.getTarget().isSneaking()) followRange *= 0.8;
|
||||||
float f = (float)armourPieces / ((EntityPlayer)event.getTarget()).inventory.armorInventory.size();
|
float f = (float)armourPieces / ((EntityPlayer)event.getTarget()).inventory.armorInventory.size();
|
||||||
if(f < 0.1F) f = 0.1F;
|
if(f < 0.1F) f = 0.1F;
|
||||||
followRange *= (double)(0.7F * f);
|
followRange *= 0.7F * f;
|
||||||
// Don't need to worry about the isSuitableTarget check since it must already have been checked to get this far
|
// Don't need to worry about the isSuitableTarget check since it must already have been checked to get this far
|
||||||
if(event.getTarget().getDistance(event.getEntity()) > followRange) ((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
|
if(event.getTarget().getDistance(event.getEntity()) > followRange) ((EntityLiving)event.getEntityLiving()).setAttackTarget(null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,19 @@ package electroblob.wizardry.item;
|
|||||||
|
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
import electroblob.wizardry.WizardryGuiHandler;
|
import electroblob.wizardry.WizardryGuiHandler;
|
||||||
|
import electroblob.wizardry.block.BlockBookshelf;
|
||||||
import electroblob.wizardry.registry.WizardryTabs;
|
import electroblob.wizardry.registry.WizardryTabs;
|
||||||
|
import net.minecraft.block.state.IBlockState;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.EnumActionResult;
|
import net.minecraft.util.EnumActionResult;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
import net.minecraft.util.EnumHand;
|
import net.minecraft.util.EnumHand;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.text.Style;
|
import net.minecraft.util.text.Style;
|
||||||
|
import net.minecraft.util.text.TextComponentTranslation;
|
||||||
import net.minecraft.util.text.TextFormatting;
|
import net.minecraft.util.text.TextFormatting;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
@@ -33,10 +38,28 @@ public class ItemWizardHandbook extends Item {
|
|||||||
new Style().setColor(TextFormatting.GRAY), AUTHOR));
|
new Style().setColor(TextFormatting.GRAY), AUTHOR));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand,
|
||||||
|
EnumFacing facing, float hitX, float hitY, float hitZ){
|
||||||
|
if(player.isSneaking()){
|
||||||
|
IBlockState state = world.getBlockState(pos);
|
||||||
|
if(state.getBlock() instanceof BlockBookshelf){
|
||||||
|
if(state.getBlock().onBlockActivated(world, pos, state, player, hand, facing, hitX, hitY, hitZ)){
|
||||||
|
return EnumActionResult.SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EnumActionResult.PASS;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
|
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
|
||||||
ItemStack stack = player.getHeldItem(hand);
|
ItemStack stack = player.getHeldItem(hand);
|
||||||
player.openGui(Wizardry.instance, WizardryGuiHandler.WIZARD_HANDBOOK, world, 0, 0, 0);
|
if (Wizardry.settings.loadHandbook) {
|
||||||
|
player.openGui(Wizardry.instance, WizardryGuiHandler.WIZARD_HANDBOOK, world, 0, 0, 0);
|
||||||
|
} else if (!world.isRemote){
|
||||||
|
player.sendStatusMessage(new TextComponentTranslation("item." + Wizardry.MODID + ":wizard_handbook.disabled"), false);
|
||||||
|
}
|
||||||
return ActionResult.newResult(EnumActionResult.SUCCESS, stack);
|
return ActionResult.newResult(EnumActionResult.SUCCESS, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,16 @@ import electroblob.wizardry.entity.living.*;
|
|||||||
import electroblob.wizardry.entity.projectile.EntityFirebomb;
|
import electroblob.wizardry.entity.projectile.EntityFirebomb;
|
||||||
import electroblob.wizardry.entity.projectile.EntityMagicFireball;
|
import electroblob.wizardry.entity.projectile.EntityMagicFireball;
|
||||||
import electroblob.wizardry.event.SpellCastEvent;
|
import electroblob.wizardry.event.SpellCastEvent;
|
||||||
|
import electroblob.wizardry.event.SpellCastEvent.Source;
|
||||||
|
import electroblob.wizardry.item.IManaStoringItem;
|
||||||
|
import electroblob.wizardry.item.ISpellCastingItem;
|
||||||
import electroblob.wizardry.item.ItemArtefact;
|
import electroblob.wizardry.item.ItemArtefact;
|
||||||
import electroblob.wizardry.registry.*;
|
import electroblob.wizardry.registry.*;
|
||||||
import electroblob.wizardry.spell.Banish;
|
import electroblob.wizardry.spell.Banish;
|
||||||
import electroblob.wizardry.util.BlockUtils;
|
import electroblob.wizardry.util.BlockUtils;
|
||||||
import electroblob.wizardry.util.EntityUtils;
|
import electroblob.wizardry.util.EntityUtils;
|
||||||
|
import electroblob.wizardry.util.SpellModifiers;
|
||||||
|
import electroblob.wizardry.util.SpellProperties.Context;
|
||||||
import net.minecraft.entity.effect.EntityLightningBolt;
|
import net.minecraft.entity.effect.EntityLightningBolt;
|
||||||
import net.minecraft.entity.item.EntityFallingBlock;
|
import net.minecraft.entity.item.EntityFallingBlock;
|
||||||
import net.minecraft.entity.passive.EntitySquid;
|
import net.minecraft.entity.passive.EntitySquid;
|
||||||
@@ -73,7 +78,7 @@ public abstract class Forfeit {
|
|||||||
|
|
||||||
public Forfeit(ResourceLocation name){
|
public Forfeit(ResourceLocation name){
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.sound = WizardrySounds.createSound("forfeit." + name.getPath());
|
this.sound = WizardrySounds.createSound(name.getNamespace(), "forfeit." + name.getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void apply(World world, EntityPlayer player);
|
public abstract void apply(World world, EntityPlayer player);
|
||||||
@@ -172,6 +177,23 @@ public abstract class Forfeit {
|
|||||||
|
|
||||||
forfeit.apply(event.getWorld(), player);
|
forfeit.apply(event.getWorld(), player);
|
||||||
|
|
||||||
|
ItemStack stack = player.getHeldItemMainhand();
|
||||||
|
|
||||||
|
if(!(stack.getItem() instanceof ISpellCastingItem)){
|
||||||
|
stack = player.getHeldItemOffhand();
|
||||||
|
if(!(stack.getItem() instanceof ISpellCastingItem)) stack = ItemStack.EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!stack.isEmpty()){
|
||||||
|
// Still need to charge the player mana or consume the scroll
|
||||||
|
if(event.getSource() == Source.SCROLL){
|
||||||
|
if(!player.isCreative()) stack.shrink(1);
|
||||||
|
}else if(stack.getItem() instanceof IManaStoringItem){
|
||||||
|
int cost = (int)(event.getSpell().getCost() * event.getModifiers().get(SpellModifiers.COST) + 0.1f); // Weird floaty rounding
|
||||||
|
((IManaStoringItem)stack.getItem()).consumeMana(stack, cost, player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WizardryAdvancementTriggers.spell_failure.triggerFor(player);
|
WizardryAdvancementTriggers.spell_failure.triggerFor(player);
|
||||||
|
|
||||||
EntityUtils.playSoundAtPlayer(player, forfeit.getSound(), WizardrySounds.SPELLS, 1, 1);
|
EntityUtils.playSoundAtPlayer(player, forfeit.getSound(), WizardrySounds.SPELLS, 1, 1);
|
||||||
@@ -220,10 +242,11 @@ public abstract class Forfeit {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
add(Tier.MASTER, Element.FIRE, create("burn_surroundings", (w, p) -> {
|
add(Tier.MASTER, Element.FIRE, create("burn_surroundings", (w, p) -> {
|
||||||
if(!w.isRemote){
|
if(!w.isRemote && EntityUtils.canDamageBlocks(p, w)){
|
||||||
List<BlockPos> sphere = BlockUtils.getBlockSphere(p.getPosition(), 6);
|
List<BlockPos> sphere = BlockUtils.getBlockSphere(p.getPosition(), 6);
|
||||||
for(BlockPos pos : sphere){
|
for(BlockPos pos : sphere){
|
||||||
if(w.rand.nextBoolean() && w.isAirBlock(pos)) w.setBlockState(pos, Blocks.FIRE.getDefaultState());
|
if(w.rand.nextBoolean() && w.isAirBlock(pos) && BlockUtils.canPlaceBlock(p, w, pos))
|
||||||
|
w.setBlockState(pos, Blocks.FIRE.getDefaultState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -296,6 +319,7 @@ public abstract class Forfeit {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
add(Tier.APPRENTICE, Element.LIGHTNING, create("storm", (w, p) -> {
|
add(Tier.APPRENTICE, Element.LIGHTNING, create("storm", (w, p) -> {
|
||||||
|
if(!Spells.invoke_weather.isEnabled(Context.WANDS)) return;
|
||||||
int standardWeatherTime = (300 + (new Random()).nextInt(600)) * 20;
|
int standardWeatherTime = (300 + (new Random()).nextInt(600)) * 20;
|
||||||
w.getWorldInfo().setRaining(true);
|
w.getWorldInfo().setRaining(true);
|
||||||
w.getWorldInfo().setRainTime(standardWeatherTime);
|
w.getWorldInfo().setRainTime(standardWeatherTime);
|
||||||
@@ -373,10 +397,11 @@ public abstract class Forfeit {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
add(Tier.NOVICE, Element.EARTH, create("snares", (w, p) -> {
|
add(Tier.NOVICE, Element.EARTH, create("snares", (w, p) -> {
|
||||||
if(!w.isRemote){
|
if(!w.isRemote && EntityUtils.canDamageBlocks(p, w)){
|
||||||
for(EnumFacing direction : EnumFacing.HORIZONTALS){
|
for(EnumFacing direction : EnumFacing.HORIZONTALS){
|
||||||
BlockPos pos = p.getPosition().offset(direction);
|
BlockPos pos = p.getPosition().offset(direction);
|
||||||
if(BlockUtils.canBlockBeReplaced(w, pos)) w.setBlockState(pos, WizardryBlocks.snare.getDefaultState());
|
if(BlockUtils.canBlockBeReplaced(w, pos) && BlockUtils.canPlaceBlock(p, w, pos))
|
||||||
|
w.setBlockState(pos, WizardryBlocks.snare.getDefaultState());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -390,9 +415,9 @@ public abstract class Forfeit {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
add(Tier.APPRENTICE, Element.EARTH, create("uproot_plants", (w, p) -> {
|
add(Tier.APPRENTICE, Element.EARTH, create("uproot_plants", (w, p) -> {
|
||||||
if(!w.isRemote){
|
if(!w.isRemote && EntityUtils.canDamageBlocks(p, w)){
|
||||||
List<BlockPos> sphere = BlockUtils.getBlockSphere(p.getPosition(), 5);
|
List<BlockPos> sphere = BlockUtils.getBlockSphere(p.getPosition(), 5);
|
||||||
sphere.removeIf(pos -> !(w.getBlockState(pos).getBlock() instanceof IPlantable));
|
sphere.removeIf(pos -> !(w.getBlockState(pos).getBlock() instanceof IPlantable) || !BlockUtils.canBreakBlock(p, w, pos));
|
||||||
sphere.forEach(pos -> w.destroyBlock(pos, true));
|
sphere.forEach(pos -> w.destroyBlock(pos, true));
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -400,9 +425,9 @@ public abstract class Forfeit {
|
|||||||
add(Tier.APPRENTICE, Element.EARTH, create("poison_self", (w, p) -> p.addPotionEffect(new PotionEffect(MobEffects.POISON, 400, 1))));
|
add(Tier.APPRENTICE, Element.EARTH, create("poison_self", (w, p) -> p.addPotionEffect(new PotionEffect(MobEffects.POISON, 400, 1))));
|
||||||
|
|
||||||
add(Tier.ADVANCED, Element.EARTH, create("flood", (w, p) -> {
|
add(Tier.ADVANCED, Element.EARTH, create("flood", (w, p) -> {
|
||||||
if(!w.isRemote){
|
if(!w.isRemote && EntityUtils.canDamageBlocks(p, w)){
|
||||||
List<BlockPos> sphere = BlockUtils.getBlockSphere(p.getPosition().up(), 2);
|
List<BlockPos> sphere = BlockUtils.getBlockSphere(p.getPosition().up(), 2);
|
||||||
sphere.removeIf(pos -> !BlockUtils.canBlockBeReplaced(w, pos, true));
|
sphere.removeIf(pos -> !BlockUtils.canBlockBeReplaced(w, pos, true) || !BlockUtils.canPlaceBlock(p, w, pos));
|
||||||
sphere.forEach(pos -> w.setBlockState(pos, Blocks.WATER.getDefaultState()));
|
sphere.forEach(pos -> w.setBlockState(pos, Blocks.WATER.getDefaultState()));
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@@ -410,8 +435,7 @@ public abstract class Forfeit {
|
|||||||
add(Tier.MASTER, Element.EARTH, create("bury_self", (w, p) -> {
|
add(Tier.MASTER, Element.EARTH, create("bury_self", (w, p) -> {
|
||||||
if(!w.isRemote){
|
if(!w.isRemote){
|
||||||
List<BlockPos> sphere = BlockUtils.getBlockSphere(p.getPosition(), 4);
|
List<BlockPos> sphere = BlockUtils.getBlockSphere(p.getPosition(), 4);
|
||||||
sphere.removeIf(pos -> !w.getBlockState(pos).isFullCube());
|
sphere.removeIf(pos -> !w.getBlockState(pos).isFullCube() || BlockUtils.isBlockUnbreakable(w, pos) || BlockUtils.canBreakBlock(p, w, pos));
|
||||||
sphere.removeIf(pos -> BlockUtils.isBlockUnbreakable(w, pos));
|
|
||||||
sphere.forEach(pos -> {
|
sphere.forEach(pos -> {
|
||||||
EntityFallingBlock block = new EntityFallingBlock(w, pos.getX() + 0.5, pos.getY() + 0.5,
|
EntityFallingBlock block = new EntityFallingBlock(w, pos.getX() + 0.5, pos.getY() + 0.5,
|
||||||
pos.getZ() + 0.5, w.getBlockState(pos));
|
pos.getZ() + 0.5, w.getBlockState(pos));
|
||||||
@@ -462,6 +486,8 @@ public abstract class Forfeit {
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
add(Tier.MASTER, Element.SORCERY, create("teleport_self_large_distance", (w, p) -> ((Banish)Spells.banish).teleport(p, w, 8 + w.rand.nextDouble() * 700)));
|
||||||
|
|
||||||
add(Tier.NOVICE, Element.HEALING, create("damage_self", (w, p) -> p.attackEntityFrom(DamageSource.MAGIC, 4)));
|
add(Tier.NOVICE, Element.HEALING, create("damage_self", (w, p) -> p.attackEntityFrom(DamageSource.MAGIC, 4)));
|
||||||
|
|
||||||
add(Tier.NOVICE, Element.HEALING, create("spill_armour", (w, p) -> {
|
add(Tier.NOVICE, Element.HEALING, create("spill_armour", (w, p) -> {
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package electroblob.wizardry.misc;
|
package electroblob.wizardry.misc;
|
||||||
|
|
||||||
|
import com.google.common.collect.HashMultimap;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
import electroblob.wizardry.item.IManaStoringItem;
|
import electroblob.wizardry.item.IManaStoringItem;
|
||||||
import electroblob.wizardry.item.ItemManaFlask;
|
import electroblob.wizardry.item.ItemManaFlask;
|
||||||
import net.minecraft.inventory.InventoryCrafting;
|
import net.minecraft.inventory.InventoryCrafting;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.item.crafting.CraftingManager;
|
|
||||||
import net.minecraft.item.crafting.IRecipe;
|
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||||
@@ -15,6 +15,8 @@ import net.minecraftforge.fml.common.gameevent.PlayerEvent;
|
|||||||
import net.minecraftforge.oredict.OreDictionary;
|
import net.minecraftforge.oredict.OreDictionary;
|
||||||
import net.minecraftforge.oredict.ShapelessOreRecipe;
|
import net.minecraftforge.oredict.ShapelessOreRecipe;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements a dynamic crafting recipe for recharging items with mana flasks.
|
* Implements a dynamic crafting recipe for recharging items with mana flasks.
|
||||||
*
|
*
|
||||||
@@ -24,6 +26,8 @@ import net.minecraftforge.oredict.ShapelessOreRecipe;
|
|||||||
@Mod.EventBusSubscriber
|
@Mod.EventBusSubscriber
|
||||||
public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
|
public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
|
||||||
|
|
||||||
|
private static final Multimap<Item, RecipeRechargeWithFlask> FLASK_RECIPES = HashMultimap.create();
|
||||||
|
|
||||||
private final IManaStoringItem chargeable;
|
private final IManaStoringItem chargeable;
|
||||||
private final ItemManaFlask flask;
|
private final ItemManaFlask flask;
|
||||||
|
|
||||||
@@ -38,6 +42,7 @@ public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
|
|||||||
if(!(chargeable instanceof IManaStoringItem)) throw new IllegalArgumentException("Item to be charged must be an instance of IManaStoringItem");
|
if(!(chargeable instanceof IManaStoringItem)) throw new IllegalArgumentException("Item to be charged must be an instance of IManaStoringItem");
|
||||||
this.chargeable = (IManaStoringItem)chargeable;
|
this.chargeable = (IManaStoringItem)chargeable;
|
||||||
this.flask = flask;
|
this.flask = flask;
|
||||||
|
FLASK_RECIPES.put(chargeable, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commented out for now because JEI spams the log with errors about the recipe having no output
|
// Commented out for now because JEI spams the log with errors about the recipe having no output
|
||||||
@@ -91,11 +96,11 @@ public class RecipeRechargeWithFlask extends ShapelessOreRecipe {
|
|||||||
// This means that although I no longer have to replace the result every tick, I still need to do it here
|
// 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?!
|
// ... 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){
|
if(event.craftMatrix instanceof InventoryCrafting){
|
||||||
for(IRecipe recipe : CraftingManager.REGISTRY){
|
Collection<RecipeRechargeWithFlask> recipes = FLASK_RECIPES.get(event.crafting.getItem());
|
||||||
if(recipe instanceof RecipeRechargeWithFlask
|
for(RecipeRechargeWithFlask recipe : recipes){
|
||||||
&& recipe.matches((InventoryCrafting)event.craftMatrix, event.player.world)){
|
if(recipe.matches((InventoryCrafting)event.craftMatrix, event.player.world)){
|
||||||
// Have to modify the itemstack in the actual event, it cannot be replaced
|
// Have to modify the itemstack in the actual event, it cannot be replaced
|
||||||
((RecipeRechargeWithFlask)recipe).rechargeItemAndCopyNBT(event.crafting, (InventoryCrafting)event.craftMatrix);
|
recipe.rechargeItemAndCopyNBT(event.crafting, (InventoryCrafting)event.craftMatrix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package electroblob.wizardry.packet;
|
||||||
|
|
||||||
|
import electroblob.wizardry.Wizardry;
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
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 a bomb entity impacts something. It is used to guarantee that the
|
||||||
|
* client always sees the explosion effect, even in singleplayer where the server may remove the entity before the
|
||||||
|
* client's own simulation can call {@code onImpact()}.
|
||||||
|
*/
|
||||||
|
public class PacketBombExplosion implements IMessageHandler<PacketBombExplosion.Message, IMessage> {
|
||||||
|
|
||||||
|
/** Bomb type constants, matching the order bombs are handled in {@link electroblob.wizardry.CommonProxy}. */
|
||||||
|
public static final int FIREBOMB = 0;
|
||||||
|
public static final int POISON_BOMB = 1;
|
||||||
|
public static final int SMOKE_BOMB = 2;
|
||||||
|
public static final int SPARK_BOMB = 3;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IMessage onMessage(Message message, MessageContext ctx){
|
||||||
|
if(ctx.side.isClient()){
|
||||||
|
net.minecraft.client.Minecraft.getMinecraft().addScheduledTask(
|
||||||
|
() -> Wizardry.proxy.handleBombExplosionPacket(message));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Message implements IMessage {
|
||||||
|
|
||||||
|
/** One of the bomb type constants defined in {@link PacketBombExplosion}. */
|
||||||
|
public int bombType;
|
||||||
|
public double x, y, z;
|
||||||
|
public float blastMultiplier;
|
||||||
|
/** Entity IDs of secondary targets struck by the spark bomb chain. Empty for other bomb types. */
|
||||||
|
public int[] secondaryTargetIDs;
|
||||||
|
|
||||||
|
// Required no-arg constructor
|
||||||
|
public Message(){}
|
||||||
|
|
||||||
|
public Message(int bombType, double x, double y, double z, float blastMultiplier){
|
||||||
|
this(bombType, x, y, z, blastMultiplier, new int[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Message(int bombType, double x, double y, double z, float blastMultiplier, int[] secondaryTargetIDs){
|
||||||
|
this.bombType = bombType;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
this.blastMultiplier = blastMultiplier;
|
||||||
|
this.secondaryTargetIDs = secondaryTargetIDs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fromBytes(ByteBuf buf){
|
||||||
|
bombType = buf.readInt();
|
||||||
|
x = buf.readDouble();
|
||||||
|
y = buf.readDouble();
|
||||||
|
z = buf.readDouble();
|
||||||
|
blastMultiplier = buf.readFloat();
|
||||||
|
int count = buf.readInt();
|
||||||
|
secondaryTargetIDs = new int[count];
|
||||||
|
for(int i = 0; i < count; i++) secondaryTargetIDs[i] = buf.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void toBytes(ByteBuf buf){
|
||||||
|
buf.writeInt(bombType);
|
||||||
|
buf.writeDouble(x);
|
||||||
|
buf.writeDouble(y);
|
||||||
|
buf.writeDouble(z);
|
||||||
|
buf.writeFloat(blastMultiplier);
|
||||||
|
buf.writeInt(secondaryTargetIDs.length);
|
||||||
|
for(int id : secondaryTargetIDs) buf.writeInt(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package electroblob.wizardry.packet;
|
package electroblob.wizardry.packet;
|
||||||
|
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
|
import electroblob.wizardry.event.ResurrectionEvent;
|
||||||
import electroblob.wizardry.inventory.ContainerArcaneWorkbench;
|
import electroblob.wizardry.inventory.ContainerArcaneWorkbench;
|
||||||
import electroblob.wizardry.item.ISpellCastingItem;
|
import electroblob.wizardry.item.ISpellCastingItem;
|
||||||
import electroblob.wizardry.packet.PacketControlInput.Message;
|
import electroblob.wizardry.packet.PacketControlInput.Message;
|
||||||
@@ -13,6 +14,7 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import net.minecraft.entity.player.EntityPlayerMP;
|
import net.minecraft.entity.player.EntityPlayerMP;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.EnumHand;
|
import net.minecraft.util.EnumHand;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
|
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
|
||||||
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
|
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
|
||||||
@@ -49,6 +51,17 @@ public class PacketControlInput implements IMessageHandler<Message, IMessage> {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CLEAR_BUTTON:
|
||||||
|
|
||||||
|
if(!(player.openContainer instanceof ContainerArcaneWorkbench)){
|
||||||
|
Wizardry.logger.warn("Received a PacketControlInput, but the player that sent it was not " +
|
||||||
|
"currently using an arcane workbench. This should not happen!");
|
||||||
|
}else{
|
||||||
|
((ContainerArcaneWorkbench)player.openContainer).onClearButtonPressed(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case NEXT_SPELL_KEY:
|
case NEXT_SPELL_KEY:
|
||||||
|
|
||||||
if(wand.getItem() instanceof ISpellCastingItem){
|
if(wand.getItem() instanceof ISpellCastingItem){
|
||||||
@@ -79,6 +92,7 @@ public class PacketControlInput implements IMessageHandler<Message, IMessage> {
|
|||||||
.filter(s -> Resurrection.canStackResurrect(s, player)).findFirst().orElse(null);
|
.filter(s -> Resurrection.canStackResurrect(s, player)).findFirst().orElse(null);
|
||||||
|
|
||||||
if(stack != null){
|
if(stack != null){
|
||||||
|
if(MinecraftForge.EVENT_BUS.post(new ResurrectionEvent(player, player))) break;
|
||||||
// This should suffice, since this is the only way a player can cast resurrection when dead!
|
// This should suffice, since this is the only way a player can cast resurrection when dead!
|
||||||
((ISpellCastingItem)stack.getItem()).cast(stack, Spells.resurrection, player, EnumHand.MAIN_HAND, 0, new SpellModifiers());
|
((ISpellCastingItem)stack.getItem()).cast(stack, Spells.resurrection, player, EnumHand.MAIN_HAND, 0, new SpellModifiers());
|
||||||
break;
|
break;
|
||||||
@@ -130,7 +144,7 @@ public class PacketControlInput implements IMessageHandler<Message, IMessage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum ControlType {
|
public enum ControlType {
|
||||||
APPLY_BUTTON, NEXT_SPELL_KEY, PREVIOUS_SPELL_KEY, RESURRECT_BUTTON, CANCEL_RESURRECT, POSSESSION_PROJECTILE
|
APPLY_BUTTON, NEXT_SPELL_KEY, PREVIOUS_SPELL_KEY, RESURRECT_BUTTON, CANCEL_RESURRECT, POSSESSION_PROJECTILE, CLEAR_BUTTON
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Message implements IMessage {
|
public static class Message implements IMessage {
|
||||||
|
|||||||
@@ -10,7 +10,11 @@ import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
|||||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
|
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
|
||||||
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
|
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>[Server -> Client]</b> This packet is sent to synchronise any fields that need synchronising in
|
* <b>[Server -> Client]</b> This packet is sent to synchronise any fields that need synchronising in
|
||||||
@@ -54,9 +58,8 @@ public class PacketPlayerSync implements IMessageHandler<Message, IMessage> {
|
|||||||
|
|
||||||
this.seed = buf.readLong();
|
this.seed = buf.readLong();
|
||||||
this.selectedMinionID = buf.readInt();
|
this.selectedMinionID = buf.readInt();
|
||||||
|
|
||||||
this.spellData = new HashMap<>();
|
this.spellData = new HashMap<>();
|
||||||
WizardData.getSyncedVariables().forEach(v -> spellData.put(v, v.read(buf)));
|
WizardData.getSyncedVariablesOrderedByKey().forEach(v -> spellData.put(v, v.read(buf)));
|
||||||
// Have to send empty tags to guarantee correct ByteBuf size/order, but no point keeping the resulting nulls
|
// Have to send empty tags to guarantee correct ByteBuf size/order, but no point keeping the resulting nulls
|
||||||
spellData.values().removeIf(Objects::isNull);
|
spellData.values().removeIf(Objects::isNull);
|
||||||
|
|
||||||
@@ -73,7 +76,7 @@ public class PacketPlayerSync implements IMessageHandler<Message, IMessage> {
|
|||||||
buf.writeLong(seed);
|
buf.writeLong(seed);
|
||||||
buf.writeInt(selectedMinionID);
|
buf.writeInt(selectedMinionID);
|
||||||
|
|
||||||
WizardData.getSyncedVariables().forEach(v -> v.write(buf, spellData.get(v)));
|
WizardData.getSyncedVariablesOrderedByKey().forEach(v -> v.write(buf, spellData.get(v)));
|
||||||
|
|
||||||
if(this.spellsDiscovered == null) return;
|
if(this.spellsDiscovered == null) return;
|
||||||
for(Spell spell : this.spellsDiscovered){
|
for(Spell spell : this.spellsDiscovered){
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public class WizardryPacketHandler {
|
|||||||
registerMessage(PacketSpellQuickAccess.class, PacketSpellQuickAccess.Message.class);
|
registerMessage(PacketSpellQuickAccess.class, PacketSpellQuickAccess.Message.class);
|
||||||
registerMessage(PacketRequestDonationPerks.class, PacketRequestDonationPerks.Message.class);
|
registerMessage(PacketRequestDonationPerks.class, PacketRequestDonationPerks.Message.class);
|
||||||
registerMessage(PacketSyncDonationPerks.class, PacketSyncDonationPerks.Message.class);
|
registerMessage(PacketSyncDonationPerks.class, PacketSyncDonationPerks.Message.class);
|
||||||
|
registerMessage(PacketBombExplosion.class, PacketBombExplosion.Message.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int nextPacketId = 0;
|
private static int nextPacketId = 0;
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
package electroblob.wizardry.potion;
|
package electroblob.wizardry.potion;
|
||||||
|
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
|
import electroblob.wizardry.item.ItemWizardArmour;
|
||||||
import net.minecraft.entity.EntityLivingBase;
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.util.DamageSource;
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraftforge.common.ISpecialArmor;
|
||||||
|
|
||||||
public class CurseUndeath extends Curse {
|
public class CurseUndeath extends Curse {
|
||||||
|
|
||||||
@@ -25,7 +28,7 @@ public class CurseUndeath extends Curse {
|
|||||||
|
|
||||||
// Adapted from EntityZombie
|
// Adapted from EntityZombie
|
||||||
if(entitylivingbase.world.isDaytime() && !entitylivingbase.world.isRemote){
|
if(entitylivingbase.world.isDaytime() && !entitylivingbase.world.isRemote){
|
||||||
|
|
||||||
float f = entitylivingbase.getBrightness();
|
float f = entitylivingbase.getBrightness();
|
||||||
|
|
||||||
if(f > 0.5F && entitylivingbase.world.rand.nextFloat() * 30.0F < (f - 0.4F) * 2.0F
|
if(f > 0.5F && entitylivingbase.world.rand.nextFloat() * 30.0F < (f - 0.4F) * 2.0F
|
||||||
@@ -35,14 +38,21 @@ public class CurseUndeath extends Curse {
|
|||||||
boolean flag = true;
|
boolean flag = true;
|
||||||
ItemStack itemstack = entitylivingbase.getItemStackFromSlot(EntityEquipmentSlot.HEAD);
|
ItemStack itemstack = entitylivingbase.getItemStackFromSlot(EntityEquipmentSlot.HEAD);
|
||||||
|
|
||||||
if(!itemstack.isEmpty()){
|
if (!itemstack.isEmpty()) {
|
||||||
if(itemstack.isItemStackDamageable()){
|
if (itemstack.isItemStackDamageable()) {
|
||||||
|
|
||||||
itemstack.setItemDamage(itemstack.getItemDamage() + entitylivingbase.world.rand.nextInt(2));
|
if (itemstack.getItem() instanceof ISpecialArmor) {
|
||||||
|
((ISpecialArmor) itemstack.getItem()).damageArmor(entitylivingbase, itemstack, DamageSource.ON_FIRE, entitylivingbase.world.rand.nextInt(2), EntityEquipmentSlot.HEAD.getSlotIndex());
|
||||||
if(itemstack.getItemDamage() >= itemstack.getMaxDamage()){
|
} else {
|
||||||
entitylivingbase.renderBrokenItemStack(itemstack);
|
itemstack.setItemDamage(itemstack.getItemDamage() + entitylivingbase.world.rand.nextInt(2));
|
||||||
entitylivingbase.setItemStackToSlot(EntityEquipmentSlot.HEAD, ItemStack.EMPTY);
|
if (itemstack.getItemDamage() >= itemstack.getMaxDamage()) {
|
||||||
|
if (itemstack.getItem() instanceof ItemWizardArmour) {
|
||||||
|
entitylivingbase.setFire(8);
|
||||||
|
} else {
|
||||||
|
entitylivingbase.renderBrokenItemStack(itemstack);
|
||||||
|
entitylivingbase.setItemStackToSlot(EntityEquipmentSlot.HEAD, ItemStack.EMPTY);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,14 @@ package electroblob.wizardry.potion;
|
|||||||
|
|
||||||
import electroblob.wizardry.Wizardry;
|
import electroblob.wizardry.Wizardry;
|
||||||
import electroblob.wizardry.registry.WizardryPotions;
|
import electroblob.wizardry.registry.WizardryPotions;
|
||||||
|
import electroblob.wizardry.registry.WizardrySounds;
|
||||||
import electroblob.wizardry.util.EntityUtils;
|
import electroblob.wizardry.util.EntityUtils;
|
||||||
import electroblob.wizardry.util.GeometryUtils;
|
import electroblob.wizardry.util.GeometryUtils;
|
||||||
import electroblob.wizardry.util.NBTExtras;
|
import electroblob.wizardry.util.NBTExtras;
|
||||||
import net.minecraft.entity.EntityLivingBase;
|
import net.minecraft.entity.EntityLivingBase;
|
||||||
import net.minecraft.entity.player.EntityPlayer;
|
|
||||||
import net.minecraft.entity.player.EntityPlayerMP;
|
|
||||||
import net.minecraft.nbt.NBTUtil;
|
import net.minecraft.nbt.NBTUtil;
|
||||||
import net.minecraft.network.play.server.SPacketEntityVelocity;
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
import net.minecraft.util.ResourceLocation;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.MathHelper;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
|
import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
|
||||||
import net.minecraftforge.fml.common.Mod;
|
import net.minecraftforge.fml.common.Mod;
|
||||||
@@ -23,8 +20,6 @@ public class PotionContainment extends PotionMagicEffect {
|
|||||||
|
|
||||||
public static final String ENTITY_TAG = "containmentPos";
|
public static final String ENTITY_TAG = "containmentPos";
|
||||||
|
|
||||||
private static final double RUBBERBAND_THRESHOLD = 0.24;
|
|
||||||
|
|
||||||
public PotionContainment(boolean isBadEffect, int liquidColour){
|
public PotionContainment(boolean isBadEffect, int liquidColour){
|
||||||
super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/containment.png"));
|
super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/containment.png"));
|
||||||
this.setPotionName("potion." + Wizardry.MODID + ":containment");
|
this.setPotionName("potion." + Wizardry.MODID + ":containment");
|
||||||
@@ -41,7 +36,6 @@ public class PotionContainment extends PotionMagicEffect {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void performEffect(EntityLivingBase target, int strength){
|
public void performEffect(EntityLivingBase target, int strength){
|
||||||
|
|
||||||
float maxDistance = getContainmentDistance(strength);
|
float maxDistance = getContainmentDistance(strength);
|
||||||
|
|
||||||
// Initialise the containment position to the entity's position if it wasn't set already
|
// Initialise the containment position to the entity's position if it wasn't set already
|
||||||
@@ -63,59 +57,14 @@ public class PotionContainment extends PotionMagicEffect {
|
|||||||
if(target.getEntityBoundingBox().maxZ > origin.z + maxDistance) z = origin.z + maxDistance - target.width/2;
|
if(target.getEntityBoundingBox().maxZ > origin.z + maxDistance) z = origin.z + maxDistance - target.width/2;
|
||||||
if(target.getEntityBoundingBox().minZ < origin.z - maxDistance) z = origin.z - maxDistance + target.width/2;
|
if(target.getEntityBoundingBox().minZ < origin.z - maxDistance) z = origin.z - maxDistance + target.width/2;
|
||||||
|
|
||||||
if(x != target.posX || y != target.posY || z != target.posZ){
|
if(x != target.posX || y != target.posY || z != target.posZ)
|
||||||
|
{
|
||||||
// if(target.world.isRemote){
|
target.addVelocity(0.15 * Math.signum(x - target.posX), 0.15 * Math.signum(y - target.posY), 0.15 * Math.signum(z - target.posZ));
|
||||||
//
|
|
||||||
// if(x != target.posX){
|
|
||||||
// for(int i = 0; i < 20; i++){
|
|
||||||
// ParticleBuilder.create(ParticleBuilder.Type.DUST).pos(
|
|
||||||
// x,
|
|
||||||
// target.posY + target.height * target.world.rand.nextFloat(),
|
|
||||||
// target.posZ + target.width * (target.world.rand.nextFloat() - 0.5f))
|
|
||||||
// .face(EnumFacing.EAST).clr(0.8f, 0.9f, 1).spawn(target.world);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if(y != target.posY){
|
|
||||||
// for(int i = 0; i < 20; i++){
|
|
||||||
// ParticleBuilder.create(ParticleBuilder.Type.DUST).pos(
|
|
||||||
// target.posX + target.width * (target.world.rand.nextFloat() - 0.5f),
|
|
||||||
// y,
|
|
||||||
// target.posZ + target.width * (target.world.rand.nextFloat() - 0.5f))
|
|
||||||
// .face(EnumFacing.UP).clr(0.8f, 0.9f, 1).spawn(target.world);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if(z != target.posZ){
|
|
||||||
// for(int i = 0; i < 20; i++){
|
|
||||||
// ParticleBuilder.create(ParticleBuilder.Type.DUST).pos(
|
|
||||||
// target.posX + target.width * (target.world.rand.nextFloat() - 0.5f),
|
|
||||||
// target.posY + target.height * target.world.rand.nextFloat(),
|
|
||||||
// z)
|
|
||||||
// .face(EnumFacing.SOUTH).clr(0.8f, 0.9f, 1).spawn(target.world);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Rubberbanding prevention (the 0.25 limit is from NetHandlerPlayServer, just search "moved wrongly"
|
|
||||||
if(target instanceof EntityPlayer){
|
|
||||||
x = MathHelper.clamp(x, target.posX - RUBBERBAND_THRESHOLD, target.posX + RUBBERBAND_THRESHOLD);
|
|
||||||
y = MathHelper.clamp(y, target.posY - RUBBERBAND_THRESHOLD, target.posY + RUBBERBAND_THRESHOLD);
|
|
||||||
z = MathHelper.clamp(z, target.posZ - RUBBERBAND_THRESHOLD, target.posZ + RUBBERBAND_THRESHOLD);
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityUtils.undoGravity(target);
|
EntityUtils.undoGravity(target);
|
||||||
target.addVelocity(0.35 * Math.signum(x - target.posX), 0.35 * Math.signum(y - target.posY), 0.35 * Math.signum(z - target.posZ));
|
if(target.world.isRemote){
|
||||||
target.setPositionAndUpdate(x, y, z); // FIXME: This line must be causing the server rubberbanding, not sure why
|
target.world.playSound(target.posX, target.posY, target.posZ, WizardrySounds.ENTITY_FORCEFIELD_DEFLECT,
|
||||||
// Player motion is handled on that player's client so needs packets
|
WizardrySounds.SPELLS, 0.3f, 1f, false);
|
||||||
if(target instanceof EntityPlayerMP){
|
|
||||||
((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target));
|
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// target.world.playSound(target.posX, target.posY, target.posZ, WizardrySounds.ENTITY_FORCEFIELD_DEFLECT,
|
|
||||||
// WizardrySounds.SPELLS, 0.3f, 1f, false);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to do this here because it's the only way to hook into potion ending both client- and server-side
|
// Need to do this here because it's the only way to hook into potion ending both client- and server-side
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user