Compare commits
71 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 |
+2
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"homepage": "https://www.curseforge.com/minecraft/mc-mods/electroblobs-wizardry",
|
||||
"promos": {
|
||||
"1.12.2-latest": "4.3.10",
|
||||
"1.12.2-recommended": "4.3.10"
|
||||
"1.12.2-latest": "4.3.18",
|
||||
"1.12.2-recommended": "4.3.18"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
+115
-50
@@ -1,64 +1,130 @@
|
||||
import groovy.json.JsonOutput
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven { url = "http://files.minecraftforge.net/maven" }
|
||||
gradlePluginPortal()
|
||||
maven {
|
||||
name 'MinecraftForge'
|
||||
url 'https://maven.minecraftforge.net/'
|
||||
}
|
||||
maven {
|
||||
name 'Garden of Fancy'
|
||||
url 'https://maven.gofancy.wtf/releases'
|
||||
}
|
||||
//fallback for fancygradle maven
|
||||
//mavenLocal()
|
||||
maven {
|
||||
name 'Sponge'
|
||||
url 'https://repo.spongepowered.org/repository/maven-public/'
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
|
||||
classpath 'net.minecraftforge.gradle:ForgeGradle:5.+'
|
||||
classpath 'org.ajoberstar.grgit:grgit-gradle:3.1.1'
|
||||
classpath group: 'wtf.gofancy.fancygradle', name: 'wtf.gofancy.fancygradle.gradle.plugin', version: '1.1.+'
|
||||
}
|
||||
|
||||
repositories.each {
|
||||
if (it instanceof MavenArtifactRepository && it.url.toString() == "https://files.minecraftforge.net/maven") {
|
||||
it.url = "https://maven.minecraftforge.net"
|
||||
}
|
||||
}
|
||||
}
|
||||
apply plugin: 'net.minecraftforge.gradle.forge'
|
||||
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
|
||||
|
||||
apply plugin: 'net.minecraftforge.gradle'
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: org.ajoberstar.grgit.gradle.GrgitPlugin
|
||||
apply plugin: 'wtf.gofancy.fancygradle'
|
||||
|
||||
|
||||
version = "4.3.10"
|
||||
version = "4.3.18"
|
||||
group= "electroblob.wizardry"// http://maven.apache.org/guides/mini/guide-naming-conventions.html
|
||||
archivesBaseName = "ElectroblobsWizardry"
|
||||
|
||||
sourceCompatibility = targetCompatibility = "1.8" // Need this here so eclipse task generates correctly.
|
||||
compileJava {
|
||||
sourceCompatibility = targetCompatibility = "1.8"
|
||||
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
|
||||
|
||||
|
||||
minecraft {
|
||||
// The mappings can be changed at any time, and must be in the following format.
|
||||
// snapshot_YYYYMMDD Snapshot are built nightly.
|
||||
// stable_# Stables are built at the discretion of the MCP team.
|
||||
// Use non-default mappings at your own risk. they may not always work.
|
||||
// Simply re-run your setup task after changing the mappings to update your workspace.
|
||||
//mappings channel: 'snapshot', version: '20171003-1.12'
|
||||
mappings channel: "stable", version: "39-1.12"
|
||||
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
|
||||
|
||||
// accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
|
||||
|
||||
// Default run configurations.
|
||||
// These can be tweaked, removed, or duplicated as needed.
|
||||
|
||||
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 {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven {
|
||||
// location of the maven that hosts JEI files
|
||||
name = "Progwml6 maven"
|
||||
url = "http://dvs1.progwml6.com/files/maven"
|
||||
url = uri('https://www.cursemaven.com')
|
||||
content {
|
||||
includeGroup 'curse.maven'
|
||||
}
|
||||
}
|
||||
maven {
|
||||
// location of a maven mirror for JEI files, as a fallback
|
||||
name = "ModMaven"
|
||||
url = "modmaven.k-4u.nl"
|
||||
name = 'Modrinth'
|
||||
url = uri('https://api.modrinth.com/maven')
|
||||
content {
|
||||
includeGroup 'maven.modrinth'
|
||||
}
|
||||
}
|
||||
maven {
|
||||
name = "Curseforge Maven"
|
||||
url = "https://minecraft.curseforge.com/api/maven/"
|
||||
name = 'Sponge'
|
||||
url = uri('https://repo.spongepowered.org/maven')
|
||||
}
|
||||
maven {
|
||||
url = uri('https://maven.blamejared.com')
|
||||
}
|
||||
maven {
|
||||
url = uri('https://m2.dv8tion.net/releases')
|
||||
}
|
||||
maven {
|
||||
url = uri('https://jitpack.io')
|
||||
}
|
||||
}
|
||||
|
||||
minecraft {
|
||||
version = "1.12.2-14.23.5.2847"
|
||||
runDir = "run"
|
||||
|
||||
// the mappings can be changed at any time, and must be in the following format.
|
||||
// snapshot_YYYYMMDD snapshot are built nightly.
|
||||
// stable_# stables are built at the discretion of the MCP team.
|
||||
// Use non-default mappings at your own risk. they may not always work.
|
||||
// simply re-run your setup task after changing the mappings to update your workspace.
|
||||
mappings = "stable_39"
|
||||
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
// Compile against the JEI API but do not include it at runtime
|
||||
deobfProvided "mezz.jei:jei_${mc_version}:${jei_version}:api"
|
||||
// At runtime, use the full JEI jar
|
||||
runtime "mezz.jei:jei_${mc_version}:${jei_version}"
|
||||
|
||||
deobfCompile "baubles:Baubles:${mc_version_short}:${baubles_version}"
|
||||
deobfCompile "antique-atlas:antiqueatlas:${mc_version}:${antique_atlas_version}"
|
||||
//// MC version ////
|
||||
// Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed
|
||||
// that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied.
|
||||
// The userdev artifact is a special name and will get all sorts of transformations applied to it.
|
||||
minecraft "net.minecraftforge:forge:${project.mc_version}-${project.forge_version}"
|
||||
//// MC version ////
|
||||
implementation fg.deobf("curse.maven:baubles-${baubles_projectid}:${baubles_fileid}")
|
||||
implementation fg.deobf("mezz.jei:jei_${mc_version}:${jei_version}")
|
||||
implementation fg.deobf("curse.maven:antique-atlas-${antiqueatlas_projectid}:${antiqueatlas_fileid}")
|
||||
|
||||
}
|
||||
|
||||
@@ -68,20 +134,19 @@ task deobfJar(type: Jar) {
|
||||
}
|
||||
|
||||
processResources {
|
||||
// this will ensure that this task is redone when the versions change.
|
||||
inputs.property "version", project.version
|
||||
inputs.property "mcversion", project.minecraft.version
|
||||
|
||||
// replace stuff in mcmod.info, nothing else
|
||||
// replace tokens in mcmod.info, and pack.mcmeta
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
include 'pack.mcmeta'
|
||||
include 'mcmod.info'
|
||||
|
||||
// replace version and mcversion
|
||||
expand 'version':project.version, 'mcversion':project.minecraft.version
|
||||
}
|
||||
|
||||
// copy everything else except the mcmod.info
|
||||
from(sourceSets.main.resources.srcDirs) {
|
||||
exclude 'mcmod.info'
|
||||
|
||||
duplicatesStrategy = 'include'
|
||||
}
|
||||
|
||||
fancyGradle {
|
||||
patches {
|
||||
resources
|
||||
coremods
|
||||
asm
|
||||
}
|
||||
}
|
||||
|
||||
+15
-1
@@ -1,8 +1,22 @@
|
||||
# Sets default memory used for gradle commands. Can be overridden by user or command line properties.
|
||||
# This is required to provide enough memory for the Minecraft decompilation process.
|
||||
org.gradle.jvmargs=-Xmx3G
|
||||
mod_id=ebwizardry
|
||||
mc_version=1.12.2
|
||||
mc_version_short=1.12
|
||||
jei_version=4.15.0.291
|
||||
baubles_version=1.5.2
|
||||
antique_atlas_version=4.6.3
|
||||
antique_atlas_version=4.6.3
|
||||
forge_version=14.23.5.2860
|
||||
mappings_version=39
|
||||
mappings_channel=stable
|
||||
mappings_mc_version=1.12
|
||||
baubles_projectid=227083
|
||||
baubles_fileid=2518667
|
||||
jei_projectid=238222
|
||||
artemislib_projectid=313590
|
||||
artemislib_version=1.0.6
|
||||
artemislib_fileid=2741812
|
||||
antiqueatlas_projectid=227795
|
||||
antiqueatlas_fileid=2823030
|
||||
org.gradle.daemon=false
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.9-bin.zip
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -1,172 +1,232 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/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/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# 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
|
||||
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
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
JAVACMD=java
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
# 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" )
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
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
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
# 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
+25
-20
@@ -1,3 +1,19 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS=
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
@@ -35,7 +54,7 @@ goto fail
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
@@ -45,28 +64,14 @@ echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_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=%*
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
@@ -81,4 +86,4 @@ exit /b 1
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
:omega
|
||||
@@ -43,6 +43,10 @@ public class CommonProxy {
|
||||
|
||||
public void registerRenderers(){}
|
||||
|
||||
public void registerItemColorHandlers(){}
|
||||
|
||||
public void registerModelProperties(){}
|
||||
|
||||
public void initialiseLayers(){}
|
||||
|
||||
public void initialiseAnimations(){}
|
||||
@@ -175,6 +179,8 @@ public class CommonProxy {
|
||||
|
||||
public void handleConquerShrinePacket(PacketConquerShrine.Message message){}
|
||||
|
||||
public void handleBombExplosionPacket(PacketBombExplosion.Message message){}
|
||||
|
||||
// SECTION Misc
|
||||
// ===============================================================================================================
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@ import net.minecraft.entity.EntityList;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.item.Item;
|
||||
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.minecraftforge.common.config.ConfigCategory;
|
||||
import net.minecraftforge.common.config.Configuration;
|
||||
@@ -138,6 +141,12 @@ public final class Settings {
|
||||
new ResourceLocation(Wizardry.MODID, "shrine_5"),
|
||||
new ResourceLocation(Wizardry.MODID, "shrine_6"),
|
||||
new ResourceLocation(Wizardry.MODID, "shrine_7")};
|
||||
/** <b>[Server-only]</b> 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. */
|
||||
public int[] libraryDimensions = {0};
|
||||
/** <b>[Server-only]</b> The rarity of library ruins, used by the world generator. Larger numbers are rarer. */
|
||||
@@ -198,6 +207,13 @@ public final class Settings {
|
||||
public boolean playerBlockDamage = true;
|
||||
/** <b>[Server-only]</b> Whether spells cast by dispensers can destroy blocks in the world. */
|
||||
public boolean dispenserBlockDamage = true;
|
||||
/** <b>[Server-only]</b> Whether damage should be registered with the old system (wizardry_magic/indirect_wizardry_magic) prefixed damage with the elements like
|
||||
* necromancy_indirect_wizardry_magic, necromancy_wizardry_magic*/
|
||||
public boolean damageTypePerElement = false;
|
||||
/** <b>[Server-only]</b> Whether spell books are consumed when they are bound to a wand.*/
|
||||
public boolean singleUseSpellBooks = false;
|
||||
/** <b>[Server-only]</b> Whether to prevent binding the same spell to a wand multiple times*/
|
||||
public boolean preventBindingSameSpellTwiceToWands = false;
|
||||
/** <b>[Server-only]</b> Whether to revert to the old wand upgrade system, which only requires tomes of arcana. */
|
||||
public boolean legacyWandLevelling = false;
|
||||
/** <b>[Server-only]</b> Whether to tweak the blindness effect to reduce follow distance when used on non-players. */
|
||||
@@ -208,6 +224,8 @@ public final class Settings {
|
||||
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
|
||||
* to the defaults.
|
||||
@@ -236,6 +254,8 @@ public final class Settings {
|
||||
public Pair<ResourceLocation, Short>[] bowItemWhitelist = parseItemMetaStrings();
|
||||
/** <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<>();
|
||||
/** <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. */
|
||||
public double playerDamageScale = 1.0;
|
||||
/** <b>[Server-only]</b> Global damage scaling factor for all npc magic damage. */
|
||||
@@ -251,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. */
|
||||
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).
|
||||
/**
|
||||
* <b>[Server-only]</b> The maximum allowed multiplier for the /cast command. This limit is here to stop people from
|
||||
@@ -320,10 +360,40 @@ public final class Settings {
|
||||
* velocity-based one.
|
||||
*/
|
||||
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. */
|
||||
public double forfeitChance = 0.2;
|
||||
/** <b>[Synchronised]</b> Progression requirements for upgrading a wand to each tier. */
|
||||
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
|
||||
* able to link to it.
|
||||
@@ -390,12 +460,16 @@ public final class Settings {
|
||||
/** <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. */
|
||||
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.
|
||||
/** <b>[Client-only]</b> The string identifier of the skin used for the spell HUD. */
|
||||
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. */
|
||||
public enum GuiPosition {
|
||||
@@ -516,9 +590,32 @@ public final class Settings {
|
||||
setupArtefactsConfig();
|
||||
setupResistancesConfig();
|
||||
|
||||
// Update the constants with new values
|
||||
updateConstantsFromSettings();
|
||||
|
||||
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);
|
||||
@@ -625,6 +722,85 @@ public final class Settings {
|
||||
dispenserBlockDamage = property.getBoolean();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(GAMEPLAY_CATEGORY, "damageTypePerElement", false,
|
||||
"Whether damage should be registered with the old system (wizardry_magic/indirect_wizardry_magic) prefixed damage with the elements like "
|
||||
+ "necromancy_indirect_wizardry_magic, necromancy_wizardry_magic. This is disabled by default to not break existing modpacks."
|
||||
+ "The intention of this setting is to allow differentiating various damage types for e.g. the Distinct Damage Descriptions mod");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".damage_type_per_element");
|
||||
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||
damageTypePerElement = property.getBoolean();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(GAMEPLAY_CATEGORY, "singleUseSpellBooks", false,
|
||||
"Whether spell books are consumed when they are bound to a wand.");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".single_use_spell_books");
|
||||
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||
singleUseSpellBooks = property.getBoolean();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(GAMEPLAY_CATEGORY, "preventBindingSameSpellTwiceToWands", false,
|
||||
"Whether to prevent binding the same spell to a wand multiple times");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".prevent_binding_same_spell_twice_to_wands");
|
||||
Wizardry.proxy.setToNamedBooleanEntry(property);
|
||||
preventBindingSameSpellTwiceToWands = property.getBoolean();
|
||||
propOrder.add(property.getName());
|
||||
|
||||
property = config.get(GAMEPLAY_CATEGORY, "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,
|
||||
"Whether to allow players to move other players around using magic.");
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".players_move_each_other");
|
||||
@@ -749,6 +925,122 @@ public final class Settings {
|
||||
progressionRequirements = property.getIntList();
|
||||
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
|
||||
// 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.
|
||||
@@ -820,6 +1112,13 @@ public final class Settings {
|
||||
replaceVanillaFallDamage = property.getBoolean();
|
||||
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,
|
||||
"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");
|
||||
@@ -834,6 +1133,14 @@ public final class Settings {
|
||||
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.setLanguageKey("config." + Wizardry.MODID + ".mob_loot_table_whitelist");
|
||||
property.setRequiresMcRestart(true);
|
||||
@@ -922,32 +1229,60 @@ public final class Settings {
|
||||
bookshelfSearchRadius = property.getInt();
|
||||
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.",
|
||||
Pattern.compile("[A-Za-z0-9:_]+ [0-9]+"));
|
||||
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(".+ [0-9]+"));
|
||||
property.setLanguageKey("config." + Wizardry.MODID + ".currency_items");
|
||||
propOrder.add(property.getName());
|
||||
currencyItems = new HashMap<>();
|
||||
currencyItemNbt = new HashMap<>();
|
||||
for(String string : property.getStringList()){
|
||||
string = string.toLowerCase(Locale.ROOT).trim();
|
||||
String[] args = string.split(" ");
|
||||
if(args.length != 2){
|
||||
string = string.trim();
|
||||
// Split on the last space to separate the item spec from the integer value; this correctly
|
||||
// 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);
|
||||
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{
|
||||
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){
|
||||
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 + ".cast_command_multiplier_limit");
|
||||
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);
|
||||
@@ -1082,6 +1417,22 @@ public final class Settings {
|
||||
shrineFiles = getResourceLocationList(property);
|
||||
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.setLanguageKey("config." + Wizardry.MODID + ".library_dimensions");
|
||||
property.setRequiresWorldRestart(true);
|
||||
@@ -1174,12 +1525,26 @@ public final class Settings {
|
||||
showChargeMeter = property.getBoolean();
|
||||
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.setLanguageKey("config." + Wizardry.MODID + ".spell_hud_position");
|
||||
@@ -1341,6 +1706,18 @@ public final class Settings {
|
||||
}
|
||||
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[]{},
|
||||
"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");
|
||||
@@ -1485,16 +1862,46 @@ public final class Settings {
|
||||
|
||||
string = string.toLowerCase(Locale.ROOT).trim();
|
||||
|
||||
String[] itemArgs = string.split(":");
|
||||
String item;
|
||||
short meta;
|
||||
|
||||
try {
|
||||
meta = Short.parseShort(itemArgs[itemArgs.length-1]);
|
||||
item = String.join(":", Arrays.copyOfRange(itemArgs, 0, itemArgs.length-1));
|
||||
}catch(NumberFormatException e){ // If no metadata is specified
|
||||
meta = OreDictionary.WILDCARD_VALUE;
|
||||
int lastColon = string.lastIndexOf(':');
|
||||
|
||||
if (lastColon > -1 && lastColon < string.length() - 1) { // if there is a colon and it's not the last char
|
||||
String metaString = string.substring(lastColon + 1);
|
||||
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;
|
||||
meta = OreDictionary.WILDCARD_VALUE;
|
||||
}
|
||||
|
||||
return Pair.of(new ResourceLocation(item), meta);
|
||||
|
||||
@@ -82,7 +82,7 @@ public class Wizardry {
|
||||
* 1.x.x represents Minecraft 1.7.x versions, 2.x.x represents Minecraft 1.10.x versions, 3.x.x represents Minecraft
|
||||
* 1.11.x versions, and so on.
|
||||
*/
|
||||
public static final String VERSION = "4.3.10";
|
||||
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>.
|
||||
@@ -130,7 +130,6 @@ public class Wizardry {
|
||||
|
||||
configDirectory = new File(event.getModConfigurationDirectory(), Wizardry.MODID);
|
||||
settings.initConfig(event);
|
||||
proxy.registerResourceReloadListeners();
|
||||
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
tisTheSeason = calendar.get(Calendar.MONTH) + 1 == 12 && calendar.get(Calendar.DAY_OF_MONTH) >= 24
|
||||
@@ -161,9 +160,13 @@ public class Wizardry {
|
||||
|
||||
@EventHandler
|
||||
public void init(FMLInitializationEvent event){
|
||||
proxy.registerResourceReloadListeners();
|
||||
|
||||
settings.initConfigExtras();
|
||||
|
||||
// Update constants with configured values
|
||||
settings.updateConstantsFromSettings();
|
||||
|
||||
// World generators
|
||||
// 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
|
||||
@@ -195,6 +198,8 @@ public class Wizardry {
|
||||
// Client-side stuff (via proxies)
|
||||
proxy.initGuiBits();
|
||||
proxy.registerParticles();
|
||||
proxy.registerItemColorHandlers();
|
||||
proxy.registerModelProperties();
|
||||
proxy.registerSoundEventListener();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import electroblob.wizardry.Settings;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.WizardryGuiHandler;
|
||||
import electroblob.wizardry.inventory.ContainerBookshelf;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import electroblob.wizardry.tileentity.TileEntityBookshelf;
|
||||
@@ -22,6 +23,7 @@ import net.minecraft.init.Items;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.InventoryHelper;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.util.*;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
@@ -162,7 +164,37 @@ public class BlockBookshelf extends BlockHorizontal implements ITileEntityProvid
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ public class BlockCrystalFlower extends BlockBush {
|
||||
@SubscribeEvent
|
||||
public static void onBonemealEvent(BonemealEvent event){
|
||||
// Grows crystal flowers when bonemeal is used on grass
|
||||
if(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),
|
||||
event.getWorld().rand.nextInt(4) - event.getWorld().rand.nextInt(4),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package electroblob.wizardry.block;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.constants.Element;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import electroblob.wizardry.tileentity.TileEntityShrineCore;
|
||||
@@ -81,11 +82,25 @@ public class BlockPedestal extends Block implements ITileEntityProvider {
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
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);
|
||||
World world = target.world;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package electroblob.wizardry.client;
|
||||
|
||||
import electroblob.wizardry.CommonProxy;
|
||||
import electroblob.wizardry.Settings;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import electroblob.wizardry.client.animation.ActionAnimation;
|
||||
@@ -19,6 +18,8 @@ import electroblob.wizardry.client.model.ModelRobeArmour;
|
||||
import electroblob.wizardry.client.model.ModelSageArmour;
|
||||
import electroblob.wizardry.client.model.ModelWizardArmour;
|
||||
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.renderer.RenderSpectralGolem;
|
||||
import electroblob.wizardry.client.renderer.entity.*;
|
||||
@@ -38,6 +39,7 @@ import electroblob.wizardry.entity.projectile.*;
|
||||
import electroblob.wizardry.event.SpellCastEvent;
|
||||
import electroblob.wizardry.event.SpellCastEvent.Source;
|
||||
import electroblob.wizardry.integration.antiqueatlas.WizardryAntiqueAtlasIntegration;
|
||||
import electroblob.wizardry.item.ItemArtefact;
|
||||
import electroblob.wizardry.item.ItemScroll;
|
||||
import electroblob.wizardry.item.ItemSpellBook;
|
||||
import electroblob.wizardry.item.ItemWand;
|
||||
@@ -715,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");
|
||||
}
|
||||
|
||||
@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
|
||||
// ===============================================================================================================
|
||||
|
||||
@@ -877,4 +938,51 @@ public class ClientProxy extends CommonProxy {
|
||||
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;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.client.renderer.overlay.RenderBlinkEffect;
|
||||
import electroblob.wizardry.data.DispenserCastingData;
|
||||
import electroblob.wizardry.data.SpellEmitterData;
|
||||
import electroblob.wizardry.item.ItemArtefact;
|
||||
import electroblob.wizardry.item.ItemFlamecatcher;
|
||||
import electroblob.wizardry.item.ItemSpectralBow;
|
||||
import electroblob.wizardry.item.ItemWand;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.item.*;
|
||||
import electroblob.wizardry.potion.PotionSlowTime;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.registry.WizardryPotions;
|
||||
@@ -16,6 +15,7 @@ import electroblob.wizardry.spell.SlowTime;
|
||||
import electroblob.wizardry.spell.Transience;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.ScaledResolution;
|
||||
import net.minecraft.client.gui.inventory.GuiContainer;
|
||||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
@@ -26,14 +26,14 @@ import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityDispenser;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.client.event.FOVUpdateEvent;
|
||||
import net.minecraftforge.client.event.InputUpdateEvent;
|
||||
import net.minecraftforge.client.event.MouseEvent;
|
||||
import net.minecraftforge.client.event.RenderHandEvent;
|
||||
import net.minecraftforge.client.event.*;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.gameevent.TickEvent;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
import net.minecraftforge.event.entity.player.ItemTooltipEvent;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -120,6 +120,7 @@ public final class WizardryClientEventHandler {
|
||||
Minecraft.getMinecraft().player.prevRotationPitch = 0;
|
||||
Minecraft.getMinecraft().player.rotationYaw = 0;
|
||||
Minecraft.getMinecraft().player.rotationPitch = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,10 +134,10 @@ public final class WizardryClientEventHandler {
|
||||
event.getMovementInput().jump = false;
|
||||
event.getMovementInput().sneak = false;
|
||||
}
|
||||
|
||||
|
||||
if(ItemArtefact.isArtefactActive(event.getEntityPlayer(), WizardryItems.charm_move_speed)
|
||||
&& event.getEntityPlayer().isHandActive()
|
||||
&& event.getEntityPlayer().getActiveItemStack().getItem() instanceof ItemWand){
|
||||
&& event.getEntityPlayer().getActiveItemStack().getItem() instanceof ISpellCastingItem){
|
||||
// Normally speed is set to 20% when using items, this makes it 80%
|
||||
event.getMovementInput().moveStrafe *= 4;
|
||||
event.getMovementInput().moveForward *= 4;
|
||||
@@ -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.
|
||||
* @param resolution The screen resolution
|
||||
|
||||
@@ -93,6 +93,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
private ContainerArcaneWorkbench arcaneWorkbenchContainer;
|
||||
|
||||
private GuiButton applyBtn;
|
||||
private GuiButton clearBtn;
|
||||
private GuiButton[] sortButtons = new GuiButton[3];
|
||||
|
||||
private GuiTextField searchField;
|
||||
@@ -126,6 +127,7 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
|
||||
this.buttonList.clear();
|
||||
this.buttonList.add(this.applyBtn = new GuiButtonApply(0, this.width / 2 + 64, this.height / 2 + 3));
|
||||
this.buttonList.add(this.clearBtn = new GuiButtonClear(0, this.width / 2 + 64, this.height / 2 - 16));
|
||||
this.buttonList.add(sortButtons[0] = new GuiButtonSpellSort(1, this.guiLeft - 44, this.guiTop + 8, ISpellSortable.SortType.TIER, arcaneWorkbenchContainer, this));
|
||||
this.buttonList.add(sortButtons[1] = new GuiButtonSpellSort(2, this.guiLeft - 31, this.guiTop + 8, ISpellSortable.SortType.ELEMENT, arcaneWorkbenchContainer, this));
|
||||
this.buttonList.add(sortButtons[2] = new GuiButtonSpellSort(3, this.guiLeft - 18, this.guiTop + 8, ISpellSortable.SortType.ALPHABETICAL, arcaneWorkbenchContainer, this));
|
||||
@@ -135,8 +137,8 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
this.searchField.setEnableBackgroundDrawing(false);
|
||||
this.searchField.setVisible(true);
|
||||
this.searchField.setTextColor(16777215);
|
||||
this.searchField.setCanLoseFocus(false);
|
||||
this.searchField.setFocused(true);
|
||||
this.searchField.setCanLoseFocus(Wizardry.settings.unfocusedSearchBars); // false by default
|
||||
this.searchField.setFocused(!Wizardry.settings.unfocusedSearchBars); // true by default
|
||||
|
||||
this.tooltipElements.clear();
|
||||
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
|
||||
this.applyBtn.enabled = centreSlot.getHasStack();
|
||||
this.clearBtn.enabled = centreSlot.getHasStack() && centreSlot.getStack().getItem() instanceof IWorkbenchItem && ((IWorkbenchItem) centreSlot.getStack().getItem()).isClearable();
|
||||
for(GuiButton button : this.sortButtons) button.visible = arcaneWorkbenchContainer.hasBookshelves();
|
||||
this.searchField.setVisible(arcaneWorkbenchContainer.hasBookshelves());
|
||||
|
||||
@@ -428,6 +431,16 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
|
||||
// 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
|
||||
protected void actionPerformed(GuiButton button){
|
||||
|
||||
@@ -444,6 +457,17 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
animationTimer = 20;
|
||||
}
|
||||
|
||||
if(button == clearBtn){
|
||||
// Packet building
|
||||
IMessage msg = new PacketControlInput.Message(PacketControlInput.ControlType.CLEAR_BUTTON);
|
||||
WizardryPacketHandler.net.sendToServer(msg);
|
||||
// Sound
|
||||
Minecraft.getMinecraft().getSoundHandler().playSound(PositionedSoundRecord.getMasterRecord(
|
||||
WizardrySounds.BLOCK_ARCANE_WORKBENCH_SPELLBIND, 0.8f));
|
||||
// Animation
|
||||
animationTimer = 20;
|
||||
}
|
||||
|
||||
if(button instanceof GuiButtonSpellSort) this.arcaneWorkbenchContainer.setSortType(((GuiButtonSpellSort)button).sortType);
|
||||
}
|
||||
}
|
||||
@@ -491,12 +515,13 @@ public class GuiArcaneWorkbench extends GuiContainer {
|
||||
@Override
|
||||
protected void keyTyped(char typedChar, int keyCode) throws IOException {
|
||||
|
||||
if(this.searchNeedsClearing){
|
||||
this.searchNeedsClearing = false;
|
||||
if(this.searchNeedsClearing){
|
||||
this.searchNeedsClearing = false;
|
||||
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));
|
||||
}else{
|
||||
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.setVisible(true);
|
||||
this.searchField.setTextColor(16777215);
|
||||
this.searchField.setCanLoseFocus(false);
|
||||
this.searchField.setFocused(true);
|
||||
|
||||
this.searchField.setCanLoseFocus(Wizardry.settings.unfocusedSearchBars); // false by default
|
||||
this.searchField.setFocused(!Wizardry.settings.unfocusedSearchBars); // true by default
|
||||
refreshAvailableSpells(); // Must be done last
|
||||
|
||||
}
|
||||
@@ -269,8 +268,13 @@ public class GuiLectern extends GuiSpellInfo implements ISpellSortable {
|
||||
|
||||
@Override
|
||||
protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException {
|
||||
super.mouseClicked(mouseX, mouseY, mouseButton);
|
||||
searchNeedsClearing = true;
|
||||
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());
|
||||
}
|
||||
searchNeedsClearing = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,9 +33,13 @@ import java.awt.*;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* GUI class for the wizard's handbook. Like any GUI class, this is instantiated each time the book is opened. As of
|
||||
@@ -55,6 +59,8 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
|
||||
private static final ResourceLocation DEFAULT = new ResourceLocation(Wizardry.MODID, "texts/handbook_en_us.json");
|
||||
|
||||
private static List<String> ADDONS = new ArrayList<>();
|
||||
|
||||
static final ResourceLocation texture = new ResourceLocation(Wizardry.MODID, "textures/gui/handbook/handbook.png");
|
||||
|
||||
/** Global Gson instance for the handbook. */
|
||||
@@ -406,9 +412,10 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
return;
|
||||
}
|
||||
|
||||
IResource handbookFile = getHandbookResource(manager);
|
||||
// IResource handbookFile = getHandbookResource(manager);
|
||||
List<IResource> handbookFiles = getHandbookResource(manager);
|
||||
|
||||
if(handbookFile != null){
|
||||
if(!handbookFiles.isEmpty()){
|
||||
|
||||
// Wipes all the maps before repopulating them
|
||||
images.clear();
|
||||
@@ -418,28 +425,31 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
|
||||
bookmarkSection = null; // Also need to wipe the reference to the old bookmarked section
|
||||
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(handbookFile.getInputStream(), StandardCharsets.UTF_8));
|
||||
for (IResource handbookFile : handbookFiles) {
|
||||
|
||||
JsonElement je = gson.fromJson(reader, JsonElement.class);
|
||||
JsonObject json = je.getAsJsonObject();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(handbookFile.getInputStream(), StandardCharsets.UTF_8));
|
||||
|
||||
JsonUtils.getJsonObject(json, "colours").entrySet().forEach(e -> colours.put(e.getKey(),
|
||||
Color.decode(e.getValue().getAsString()).getRGB()));
|
||||
JsonElement je = gson.fromJson(reader, JsonElement.class);
|
||||
JsonObject json = je.getAsJsonObject();
|
||||
|
||||
// Repopulates the remaining maps
|
||||
Image.populate(images, json);
|
||||
CraftingRecipe.populate(recipes, json);
|
||||
Section.populate(sections, json);
|
||||
JsonUtils.getJsonObject(json, "colours").entrySet().forEach(e -> colours.put(e.getKey(),
|
||||
Color.decode(e.getValue().getAsString()).getRGB()));
|
||||
|
||||
sectionList = Collections.unmodifiableList(new ArrayList<>(sections.values()));
|
||||
// Repopulates the remaining maps
|
||||
Image.populate(images, json);
|
||||
CraftingRecipe.populate(recipes, json);
|
||||
Section.populate(sections, json);
|
||||
|
||||
if(sections.isEmpty()){
|
||||
Wizardry.logger.warn("Handbook has no sections! Aborting loading...");
|
||||
return;
|
||||
sectionList = Collections.unmodifiableList(new ArrayList<>(sections.values()));
|
||||
|
||||
if(sections.isEmpty()){
|
||||
Wizardry.logger.warn("Handbook has no sections! Aborting loading...");
|
||||
return;
|
||||
}
|
||||
|
||||
bookmarkSection = JsonUtils.getString(json, "bookmark_start_section");
|
||||
if(!sections.containsKey(bookmarkSection)) throw new JsonSyntaxException("Section with id " + bookmarkSection + " is undefined");
|
||||
}
|
||||
|
||||
bookmarkSection = JsonUtils.getString(json, "bookmark_start_section");
|
||||
if(!sections.containsKey(bookmarkSection)) throw new JsonSyntaxException("Section with id " + bookmarkSection + " is undefined");
|
||||
}
|
||||
|
||||
// The first resource load on startup is done before the packet handler is loaded
|
||||
@@ -455,16 +465,17 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
* @param manager The resource manager instance to use.
|
||||
* @return The handbook JSON file, as an IResource, or null if it was not found.
|
||||
*/
|
||||
private static IResource getHandbookResource(IResourceManager manager){
|
||||
private static List<IResource> getHandbookResource(IResourceManager manager){
|
||||
|
||||
// TODO: Implement resource pack stacking to allow addon mods and texture packs to add/overwrite content
|
||||
|
||||
IResource handbookFile = null;
|
||||
List<IResource> handbookFiles = new ArrayList<>();
|
||||
|
||||
try{
|
||||
handbookFile = manager.getResource(new ResourceLocation(Wizardry.MODID, "texts/handbook_"
|
||||
+ Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode() + ".json"));
|
||||
}catch(IOException e){
|
||||
}catch(Exception e){
|
||||
|
||||
Wizardry.logger.info("Wizard handbook JSON file missing for the current language (" + Minecraft.getMinecraft()
|
||||
.getLanguageManager().getCurrentLanguage() + "). Using default (English-US) instead.");
|
||||
@@ -476,7 +487,29 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
}
|
||||
}
|
||||
|
||||
return handbookFile;
|
||||
handbookFiles.add(handbookFile);
|
||||
|
||||
for (String modid : ADDONS) {
|
||||
// Addons
|
||||
Wizardry.logger.info("Registering addon Wizard's Handbook contents for " + modid);
|
||||
try{
|
||||
handbookFile = manager.getResource(new ResourceLocation(modid, "texts/handbook_"
|
||||
+ Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode() + ".json"));
|
||||
}catch(Exception e){
|
||||
|
||||
Wizardry.logger.info("Wizard handbook JSON file missing for the current language (" + Minecraft.getMinecraft()
|
||||
.getLanguageManager().getCurrentLanguage() + "). Using default (English-US) instead.");
|
||||
|
||||
try{
|
||||
handbookFile = manager.getResource(new ResourceLocation(modid, "texts/handbook_en_us.json"));
|
||||
}catch(IOException x){
|
||||
Wizardry.logger.error("Couldn't find file: " + DEFAULT + ". The file may be missing; please try re-downloading and reinstalling Wizardry.", x);
|
||||
}
|
||||
}
|
||||
handbookFiles.add(handbookFile);
|
||||
}
|
||||
|
||||
return handbookFiles;
|
||||
}
|
||||
|
||||
// Controls
|
||||
@@ -576,4 +609,9 @@ public class GuiWizardHandbook extends GuiScreen {
|
||||
sections.values().forEach(s -> s.updateUnlockStatus(showToasts, completedAdvancements));
|
||||
}
|
||||
|
||||
public static void registerAddonHandbookContent(String modid) {
|
||||
if (!ADDONS.contains(modid)) {
|
||||
ADDONS.add(modid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ class Section {
|
||||
String suffix = "";
|
||||
|
||||
// Account for trailing punctuation, except in languages that don't use spaces such as Chinese
|
||||
boolean spaceless = SPACELESS_LANGUAGES.contains(Minecraft.getMinecraft().getLanguageManager().getCurrentLanguage().getLanguageCode());
|
||||
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
|
||||
|
||||
@@ -60,10 +60,12 @@ public class RenderSixthSense {
|
||||
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
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)
|
||||
&& 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)){
|
||||
|
||||
Tessellator tessellator = Tessellator.getInstance();
|
||||
@@ -87,7 +89,13 @@ public class RenderSixthSense {
|
||||
GlStateManager.rotate(180 - renderManager.playerViewY, 0.0F, 1.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;
|
||||
|
||||
|
||||
@@ -8,40 +8,40 @@ public final class Constants {
|
||||
|
||||
/** 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.
|
||||
public static final int MANA_PER_SHARD = 10;
|
||||
public static int MANA_PER_SHARD;
|
||||
/** 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 */
|
||||
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. */
|
||||
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. */
|
||||
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. */
|
||||
public static 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. */
|
||||
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. */
|
||||
public static float POTENCY_INCREASE_PER_TIER = 0.15f;
|
||||
public static float POTENCY_INCREASE_PER_TIER;
|
||||
/** The fraction by which spell duration is increased for each level of duration upgrade. */
|
||||
public static 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. */
|
||||
public static 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. */
|
||||
public static 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. */
|
||||
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. */
|
||||
public static final double DECAY_SLOWNESS_PER_LEVEL = 0.2;
|
||||
/** The fraction by which dig speed is reduced per level of frostbite effect. */
|
||||
public static final float FROST_FATIGUE_PER_LEVEL = 0.45f;
|
||||
/** 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
|
||||
* 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
|
||||
* won't spawn again if something is already standing in it.
|
||||
@@ -51,11 +51,19 @@ public final class Constants {
|
||||
|
||||
// making this as an update to the existing values to not break addons directly relying on the fields
|
||||
static {
|
||||
POTENCY_INCREASE_PER_TIER = (float) Wizardry.settings.potencyIncreasePerTier;
|
||||
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;
|
||||
RANGE_INCREASE_PER_LEVEL = (float) Wizardry.settings.frostSlownessIncreasePerLevel;
|
||||
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 {
|
||||
|
||||
NOVICE(700, 3, 12, new Style().setColor(TextFormatting.WHITE), "novice"),
|
||||
APPRENTICE(1000, 5, 5, new Style().setColor(TextFormatting.AQUA), "apprentice"),
|
||||
ADVANCED(1500, 7, 2, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"),
|
||||
MASTER(2500, 9, 1, new Style().setColor(TextFormatting.DARK_PURPLE), "master");
|
||||
NOVICE(Wizardry.settings.noviceMaxCharge, Wizardry.settings.noviceUpgradeLimit, 12, new Style().setColor(TextFormatting.WHITE), "novice"),
|
||||
APPRENTICE(Wizardry.settings.apprenticeMaxCharge, Wizardry.settings.apprenticeUpgradeLimit, 5, new Style().setColor(TextFormatting.AQUA), "apprentice"),
|
||||
ADVANCED(Wizardry.settings.advancedMaxCharge, Wizardry.settings.advancedUpgradeLimit, 2, new Style().setColor(TextFormatting.DARK_BLUE), "advanced"),
|
||||
MASTER(Wizardry.settings.masterMaxCharge, Wizardry.settings.masterUpgradeLimit, 1, new Style().setColor(TextFormatting.DARK_PURPLE), "master");
|
||||
|
||||
/** Maximum mana a wand of this tier can store. */
|
||||
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
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces this variable's update method with the given update function. <i>Beware of auto-unboxing of
|
||||
* primitive types! For lambda expressions, check the second parameter isn't null before operating on it.
|
||||
|
||||
@@ -47,7 +47,10 @@ public interface IVariable<T> {
|
||||
*/
|
||||
void write(ByteBuf buf, T value);
|
||||
|
||||
String getKey();
|
||||
|
||||
/**
|
||||
*
|
||||
* Reads this variable's value from the given {@link ByteBuf}.
|
||||
*/
|
||||
T read(ByteBuf buf);
|
||||
@@ -110,6 +113,11 @@ public interface IVariable<T> {
|
||||
// NYI
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return "none"; // we don't mind as these are never synced (electroblob.wizardry.data.IVariable.Variable.isSynced)
|
||||
}
|
||||
|
||||
@Override
|
||||
public T read(ByteBuf buf){
|
||||
return null; // NYI
|
||||
|
||||
@@ -7,7 +7,6 @@ import electroblob.wizardry.enchantment.Imbuement;
|
||||
import electroblob.wizardry.entity.living.ISummonedCreature;
|
||||
import electroblob.wizardry.event.SpellCastEvent;
|
||||
import electroblob.wizardry.event.SpellCastEvent.Source;
|
||||
import electroblob.wizardry.item.ItemWand;
|
||||
import electroblob.wizardry.packet.PacketCastContinuousSpell;
|
||||
import electroblob.wizardry.packet.PacketPlayerSync;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
@@ -47,6 +46,7 @@ import javax.annotation.Nullable;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.*;
|
||||
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
|
||||
@@ -73,7 +73,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
||||
private static final Set<IStoredVariable> storedVariables = new HashSet<>();
|
||||
|
||||
/** The maximum number of recent spells to track. */
|
||||
public static final int MAX_RECENT_SPELLS = ItemWand.BASE_SPELL_SLOTS;
|
||||
public static int MAX_RECENT_SPELLS;
|
||||
|
||||
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. */
|
||||
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.
|
||||
// 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 true. Used internally for packet reading. */
|
||||
public static Set<IVariable> getSyncedVariables(){
|
||||
return storedVariables.stream().filter(IVariable::isSynced).collect(Collectors.toSet());
|
||||
* returns true, ordered by their keys obtained from {@link IVariable#getKey()}. Used internally for packets. */
|
||||
public static Set<IVariable> getSyncedVariablesOrderedByKey(){
|
||||
Comparator<IVariable> keyComparator = Comparator.comparing(IVariable::getKey);
|
||||
|
||||
return storedVariables.stream()
|
||||
.filter(IVariable::isSynced)
|
||||
.sorted(keyComparator)
|
||||
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -289,15 +294,19 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
||||
* @param spell The spell to be tracked.
|
||||
*/
|
||||
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.
|
||||
* Only counts spells cast within the configured expiry time.
|
||||
* @param spell The spell to count casts for.
|
||||
*/
|
||||
public int countRecentCasts(Spell spell){
|
||||
return (int)this.recentSpells.stream().filter(s -> s == spell).count(); // We know this can't be more than 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
|
||||
@@ -346,20 +355,20 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
||||
|
||||
// For each item in the player's inventory
|
||||
for(ItemStack stack : player.inventory.mainInventory){
|
||||
updateImbutedItem(stack, activeImbuements);
|
||||
updateImbuedItem(stack, activeImbuements);
|
||||
}
|
||||
for(ItemStack stack : player.inventory.armorInventory){
|
||||
updateImbutedItem(stack, activeImbuements);
|
||||
updateImbuedItem(stack, activeImbuements);
|
||||
}
|
||||
for(ItemStack stack : player.inventory.offHandInventory){
|
||||
updateImbutedItem(stack, activeImbuements);
|
||||
updateImbuedItem(stack, activeImbuements);
|
||||
}
|
||||
|
||||
// Removes all imbuements from the map that are no longer active
|
||||
this.imbuementDurations.keySet().retainAll(activeImbuements);
|
||||
}
|
||||
|
||||
private void updateImbutedItem(ItemStack stack, Set<Imbuement> activeImbuements){
|
||||
private void updateImbuedItem(ItemStack stack, Set<Imbuement> activeImbuements){
|
||||
|
||||
if(stack.isItemEnchanted()){
|
||||
|
||||
@@ -456,7 +465,7 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
||||
|
||||
if(this.castCommandSpell != null && this.castCommandSpell.isContinuous){
|
||||
|
||||
if(castCommandTick >= castCommandDuration){
|
||||
if(castCommandTick > castCommandDuration){
|
||||
this.stopCastingContinuousSpell();
|
||||
return;
|
||||
}
|
||||
@@ -508,6 +517,12 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
||||
if(player.ticksExisted % IMBUEMENT_UPDATE_INTERVAL == 0) updateImbuedItems();
|
||||
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.keySet().removeIf(k -> k.canPurge(player, this.spellData.get(k)));
|
||||
}
|
||||
@@ -574,7 +589,15 @@ public class WizardData implements INBTSerializable<NBTTagCompound> {
|
||||
|
||||
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)));
|
||||
|
||||
@@ -601,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
|
||||
this.recentSpells = EvictingQueue.create(MAX_RECENT_SPELLS);
|
||||
this.recentSpells.addAll(NBTExtras.NBTToList(nbt.getTagList("recentSpells", NBT.TAG_INT),
|
||||
(NBTTagInt tag) -> Spell.byMetadata(tag.getInt())));
|
||||
// Deserialize recent spells with timestamps
|
||||
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{
|
||||
storedVariables.forEach(k -> this.spellData.put(k, k.read(nbt)));
|
||||
|
||||
@@ -35,8 +35,8 @@ public class EntityDecay extends EntityMagicConstruct {
|
||||
0.6F + rand.nextFloat() * 0.15F);
|
||||
|
||||
if(!this.world.isRemote){
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(1.0d, this.posX, this.posY,
|
||||
this.posZ, this.world);
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(this.width/2f, this.posX, this.posY,
|
||||
this.posZ, this.height, this.world);
|
||||
for(EntityLivingBase target : targets){
|
||||
if(target != this.getCaster()){
|
||||
// If this check wasn't here the potion would be reapplied every tick and hence the entity would be
|
||||
|
||||
@@ -34,7 +34,7 @@ public class EntityFireRing extends EntityScaledConstruct {
|
||||
|
||||
if(this.ticksExisted % 5 == 0 && !this.world.isRemote){
|
||||
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, this.posX, this.posY, this.posZ, this.world);
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(this.width/2, this.posX, this.posY, this.posZ, this.height, this.world);
|
||||
|
||||
for(EntityLivingBase target : targets){
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ public class EntityFireSigil extends EntityScaledConstruct {
|
||||
|
||||
if(!this.world.isRemote){
|
||||
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, posX, posY, posZ, world);
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(this.width/2, this.posX, this.posY, this.posZ, this.height, this.world);
|
||||
|
||||
for(EntityLivingBase target : targets){
|
||||
|
||||
|
||||
@@ -146,23 +146,28 @@ public class EntityForcefield extends EntityMagicConstruct implements ICustomHit
|
||||
if(EntityUtils.isLiving(target)) nudgeVelocity = 0.25;
|
||||
Vec3d extraVelocity = targetRelativePos.normalize().scale(nudgeVelocity);
|
||||
|
||||
// ...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);
|
||||
|
||||
//Moved up the check by "19" so that way allied players aren't being moved out of the forcefield because
|
||||
//allied players aren't synced to client like minions. Minions are only synced because it's saved to their
|
||||
//entity data which is synced in their serialize/deserialize methods
|
||||
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
|
||||
if(target instanceof EntityPlayerMP){
|
||||
((EntityPlayerMP)target).connection.sendPacket(new SPacketEntityVelocity(target));
|
||||
@@ -174,6 +179,11 @@ public class EntityForcefield extends EntityMagicConstruct implements ICustomHit
|
||||
|
||||
}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);
|
||||
|
||||
float yaw = (float)Math.atan2(relativeImpactPos.x, -relativeImpactPos.z);
|
||||
|
||||
@@ -36,8 +36,8 @@ public class EntityFrostSigil extends EntityScaledConstruct {
|
||||
|
||||
if(!this.world.isRemote){
|
||||
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, this.posX, this.posY,
|
||||
this.posZ, this.world);
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(width/2, this.posX, this.posY,
|
||||
this.posZ, this.height, this.world);
|
||||
|
||||
for(EntityLivingBase target : targets){
|
||||
|
||||
|
||||
@@ -33,30 +33,32 @@ public class EntityHealAura extends EntityScaledConstruct {
|
||||
|
||||
if(!this.world.isRemote){
|
||||
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, posX, posY, posZ, world);
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(width/2, posX, posY, posZ, this.height, world);
|
||||
|
||||
for(EntityLivingBase target : targets){
|
||||
|
||||
if(this.isValidTarget(target)){
|
||||
|
||||
if(target.isEntityUndead()){
|
||||
if(target.isEntityUndead()) {
|
||||
|
||||
double velX = target.motionX;
|
||||
double velY = target.motionY;
|
||||
double velZ = target.motionZ;
|
||||
|
||||
if(this.getCaster() != null){
|
||||
target.attackEntityFrom(
|
||||
MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.RADIANT),
|
||||
Spells.healing_aura.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier);
|
||||
}else{
|
||||
target.attackEntityFrom(DamageSource.MAGIC, Spells.healing_aura.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier);
|
||||
}
|
||||
if (this.ticksExisted % 10 == 1) {
|
||||
if (this.getCaster() != null) {
|
||||
target.attackEntityFrom(
|
||||
MagicDamage.causeIndirectMagicDamage(this, getCaster(), DamageType.RADIANT),
|
||||
Spells.healing_aura.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier);
|
||||
} else {
|
||||
target.attackEntityFrom(DamageSource.MAGIC, Spells.healing_aura.getProperty(Spell.DAMAGE).floatValue() * damageMultiplier);
|
||||
}
|
||||
|
||||
// Removes knockback
|
||||
target.motionX = velX;
|
||||
target.motionY = velY;
|
||||
target.motionZ = velZ;
|
||||
// Removes knockback
|
||||
target.motionX = velX;
|
||||
target.motionY = velY;
|
||||
target.motionZ = velZ;
|
||||
}
|
||||
}
|
||||
|
||||
}else if(target.getHealth() < target.getMaxHealth() && target.ticksExisted % 5 == 0){
|
||||
|
||||
@@ -39,8 +39,8 @@ public class EntityLightningSigil extends EntityScaledConstruct {
|
||||
this.setDead();
|
||||
}
|
||||
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinRadius(width/2, this.posX, this.posY,
|
||||
this.posZ, this.world);
|
||||
List<EntityLivingBase> targets = EntityUtils.getLivingWithinCylinder(this.width/2, this.posX, this.posY,
|
||||
this.posZ, this.height, this.world);
|
||||
|
||||
for(EntityLivingBase target : targets){
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
protected Predicate<Entity> targetSelector;
|
||||
|
||||
/** The wizard's trades. */
|
||||
private MerchantRecipeList trades;
|
||||
public MerchantRecipeList trades;
|
||||
/** The wizard's current customer. */
|
||||
@Nullable
|
||||
private EntityPlayer customer;
|
||||
@@ -130,8 +130,12 @@ public class EntityWizard extends EntityCreature implements INpc, IMerchant, ISp
|
||||
if(entity != null && !entity.isInvisible()
|
||||
&& AllyDesignationSystem.isValidTarget(EntityWizard.this, entity)){
|
||||
|
||||
// ... and is a mob, a summoned creature ...
|
||||
if((entity instanceof IMob || entity instanceof ISummonedCreature
|
||||
// ... and is a non summoned creature mob ...
|
||||
if((entity instanceof IMob && !(entity instanceof ISummonedCreature)
|
||||
|
||||
// or is a summoned creature with a mob owner or an owner who has attacked the wizard ...
|
||||
|| entity instanceof ISummonedCreature && (((ISummonedCreature)entity).getOwner() instanceof IMob || ((ISummonedCreature)entity).getOwner() == this.getRevengeTarget() || ((ISummonedCreature) entity).getOwner() == this.getAttackTarget())
|
||||
|
||||
// ... or in the whitelist ...
|
||||
|| Arrays.asList(Wizardry.settings.summonedCreatureTargetsWhitelist)
|
||||
.contains(EntityList.getKey(entity.getClass())))
|
||||
@@ -613,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
|
||||
// This is then divided by the value of the currency item to give a price
|
||||
// The absolute maximum stack size that can result from this calculation (with value = 1) is 64.
|
||||
return new ItemStack(item, 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){
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
package electroblob.wizardry.entity.projectile;
|
||||
|
||||
import electroblob.wizardry.packet.PacketBombExplosion;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.EntityUtils;
|
||||
import electroblob.wizardry.util.MagicDamage;
|
||||
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.EntityLivingBase;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -29,41 +29,28 @@ public class EntityFirebomb extends EntityBomb {
|
||||
|
||||
@Override
|
||||
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){
|
||||
|
||||
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_FIRE, 1, 1);
|
||||
|
||||
@@ -82,9 +69,9 @@ public class EntityFirebomb extends EntityBomb {
|
||||
target.setFire(Spells.firebomb.getProperty(Spell.BURN_DURATION).intValue());
|
||||
}
|
||||
}
|
||||
|
||||
this.setDead();
|
||||
}
|
||||
|
||||
this.setDead();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
package electroblob.wizardry.entity.projectile;
|
||||
|
||||
import electroblob.wizardry.packet.PacketBombExplosion;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.EntityUtils;
|
||||
import electroblob.wizardry.util.MagicDamage;
|
||||
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.EntityLivingBase;
|
||||
import net.minecraft.init.MobEffects;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -31,44 +31,30 @@ public class EntityPoisonBomb extends EntityBomb {
|
||||
|
||||
@Override
|
||||
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){
|
||||
|
||||
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_POISON, 1.2F, 1.0f);
|
||||
|
||||
@@ -88,8 +74,8 @@ public class EntityPoisonBomb extends EntityBomb {
|
||||
Spells.poison_bomb.getProperty(Spell.SPLASH_EFFECT_STRENGTH).intValue()));
|
||||
}
|
||||
}
|
||||
|
||||
this.setDead();
|
||||
}
|
||||
|
||||
this.setDead();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package electroblob.wizardry.entity.projectile;
|
||||
|
||||
import electroblob.wizardry.packet.PacketBombExplosion;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.EntityUtils;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.init.MobEffects;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -29,27 +29,13 @@ public class EntitySmokeBomb extends EntityBomb {
|
||||
@Override
|
||||
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){
|
||||
|
||||
// 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_SMOKE, 1.2F, 1.0f);
|
||||
|
||||
@@ -65,8 +51,8 @@ public class EntitySmokeBomb extends EntityBomb {
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, duration, 0));
|
||||
}
|
||||
}
|
||||
|
||||
this.setDead();
|
||||
}
|
||||
|
||||
this.setDead();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package electroblob.wizardry.entity.projectile;
|
||||
|
||||
import electroblob.wizardry.packet.PacketBombExplosion;
|
||||
import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
@@ -13,7 +15,9 @@ import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.common.network.NetworkRegistry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class EntitySparkBomb extends EntityBomb {
|
||||
@@ -31,47 +35,37 @@ public class EntitySparkBomb extends EntityBomb {
|
||||
|
||||
@Override
|
||||
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){
|
||||
// This is if the spark bomb gets a direct hit
|
||||
float damage = Spells.spark_bomb.getProperty(Spell.DIRECT_DAMAGE).floatValue() * damageMultiplier;
|
||||
Entity entityHit = rayTrace.entityHit;
|
||||
|
||||
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(
|
||||
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK).setProjectile(),
|
||||
damage);
|
||||
this.playSound(WizardrySounds.ENTITY_SPARK_BOMB_HIT, 1.0F, 1.2F / (this.rand.nextFloat() * 0.2F + 0.9F));
|
||||
|
||||
}
|
||||
entityHit.attackEntityFrom(
|
||||
MagicDamage.causeIndirectMagicDamage(this, this.getThrower(), DamageType.SHOCK).setProjectile(),
|
||||
damage);
|
||||
}
|
||||
|
||||
// Particle effect
|
||||
if(world.isRemote){
|
||||
ParticleBuilder.spawnShockParticles(world, posX, posY + height/2, posZ);
|
||||
}
|
||||
double seekerRange = Spells.spark_bomb.getProperty(Spell.EFFECT_RADIUS).doubleValue() * blastMultiplier;
|
||||
|
||||
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,
|
||||
this.posZ, this.world);
|
||||
List<Integer> secondaryTargetIDs = new ArrayList<>();
|
||||
|
||||
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()
|
||||
&& !(targets.get(i) instanceof EntityPlayer
|
||||
&& ((EntityPlayer)targets.get(i)).isCreative());
|
||||
boolean flag = targets.get(i) != entityHit && targets.get(i) != this.getThrower()
|
||||
&& !(targets.get(i) instanceof EntityPlayer
|
||||
&& ((EntityPlayer)targets.get(i)).isCreative());
|
||||
|
||||
// Detects (client side) if target is the thrower, to stop particles being spawned around them.
|
||||
//if(flag && world.isRemote && targets.get(i).getEntityId() == this.playerID) flag = false;
|
||||
|
||||
if(flag){
|
||||
|
||||
EntityLivingBase target = targets.get(i);
|
||||
|
||||
if(!this.world.isRemote){
|
||||
if(flag){
|
||||
EntityLivingBase target = targets.get(i);
|
||||
|
||||
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),
|
||||
Spells.spark_bomb.getProperty(Spell.SPLASH_DAMAGE).floatValue() * damageMultiplier);
|
||||
|
||||
}else{
|
||||
ParticleBuilder.create(Type.LIGHTNING).pos(this.getPositionVector()).target(target).spawn(world);
|
||||
ParticleBuilder.spawnShockParticles(world, target.posX, target.posY + target.height/2, target.posZ);
|
||||
secondaryTargetIDs.add(target.getEntityId());
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
@@ -8,7 +8,7 @@ import net.minecraftforge.fml.common.eventhandler.Cancelable;
|
||||
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||
|
||||
/**
|
||||
* SpellBindEvent is fired when a check happens for an ItemArtefact using {@link electroblob.wizardry.item.ItemArtefact#isArtefactActive(net.minecraft.entity.player.EntityPlayer, net.minecraft.item.Item)}
|
||||
* 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>
|
||||
@@ -42,4 +42,4 @@ public class ArtefactCheckEvent extends PlayerEvent {
|
||||
return player;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ public final class WizardryBaublesIntegration {
|
||||
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.BELT, BaubleType.BELT);
|
||||
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.BODY, BaubleType.BODY);
|
||||
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.HEAD, BaubleType.HEAD);
|
||||
ARTEFACT_TYPE_MAP.put(ItemArtefact.Type.TRINKET, BaubleType.TRINKET);
|
||||
}
|
||||
|
||||
public static boolean enabled(){
|
||||
|
||||
@@ -452,6 +452,24 @@ public class ContainerArcaneWorkbench extends Container implements ISpellSortabl
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called (via {@link electroblob.wizardry.packet.PacketControlInput PacketControlInput}) when the clear button in
|
||||
* the arcane workbench GUI is pressed.
|
||||
*/
|
||||
// As of 2.1, for the sake of events and neatness of code, this was moved here from TileEntityArcaneWorkbench.
|
||||
// As of 4.2, the spell binding/charging/upgrading code was delegated (via IWorkbenchItem) to the items themselves.
|
||||
public void onClearButtonPressed(EntityPlayer player){
|
||||
|
||||
Slot centre = this.getSlot(CENTRE_SLOT);
|
||||
|
||||
if(centre.getStack().getItem() instanceof IWorkbenchItem){ // Should always be true, but no harm in checking.
|
||||
|
||||
Slot[] spellBooks = this.inventorySlots.subList(0, 8).toArray(new Slot[8]);
|
||||
|
||||
((IWorkbenchItem) centre.getStack().getItem()).onClearButtonPressed(player, centre, this.getSlot(CRYSTAL_SLOT), this.getSlot(UPGRADE_SLOT), spellBooks);
|
||||
}
|
||||
}
|
||||
|
||||
/** Scrolls to the given row number. */
|
||||
public void scrollTo(int row){
|
||||
this.scroll = row;
|
||||
|
||||
@@ -55,6 +55,26 @@ public interface IWorkbenchItem {
|
||||
*/
|
||||
boolean onApplyButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks);
|
||||
|
||||
/**
|
||||
* Called when this item is in the central slot of an arcane workbench and the apply clear is pressed. Items must
|
||||
* implement this method to define what happens when the apply button is pressed.
|
||||
* @param player The player that pressed the apply button.
|
||||
* @param centre The central slot in the arcane workbench. This slot will always contain a stack of the implementing
|
||||
* item, or in other words, <i>it is guaranteed that</i> {@code this == centre.getStack().getItem()}.
|
||||
* @param crystals The magic crystal slot of the arcane workbench.
|
||||
* @param upgrade The upgrade slot of the arcane workbench.
|
||||
* @param spellBooks An array of the <i>active</i> (visible) spell book slots in the arcane workbench. The length of
|
||||
* the array will be equal to the value returned by {@link IWorkbenchItem#getSpellSlotCount(ItemStack)}.
|
||||
* */
|
||||
default void onClearButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){};
|
||||
|
||||
/**
|
||||
* Must be overridden in the item class to make the clear button in the Arcane Workbench clickable.
|
||||
* */
|
||||
default boolean isClearable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the tooltip (dark grey box) should be drawn when this item is in an arcane workbench. Only
|
||||
* called client-side.
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
package electroblob.wizardry.item;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import electroblob.wizardry.constants.Tier;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
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.Item;
|
||||
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.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
@@ -25,7 +32,7 @@ public class ItemArcaneTome extends Item {
|
||||
|
||||
@Override
|
||||
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++){
|
||||
list.add(new ItemStack(this, 1, i));
|
||||
}
|
||||
@@ -51,6 +58,20 @@ public class ItemArcaneTome extends Item {
|
||||
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)
|
||||
@Override
|
||||
public void addInformation(ItemStack stack, World world, List<String> tooltip, net.minecraft.client.util.ITooltipFlag showAdvanced){
|
||||
|
||||
@@ -93,8 +93,7 @@ public class ItemArtefact extends Item {
|
||||
/** An artefact that improves utility spells. One of these can be active at any one time. */ CHARM(1),
|
||||
/** Added for add-on artefacts. */ BELT(1),
|
||||
/** Added for add-on artefacts. */ BODY(1),
|
||||
/** Added for add-on artefacts. */ HEAD(1),
|
||||
/** Added for add-on artefacts. */ TRINKET(1);
|
||||
/** Added for add-on artefacts. */ HEAD(1);
|
||||
|
||||
public final int maxAtOnce;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package electroblob.wizardry.item;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import electroblob.wizardry.constants.Constants;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.registry.Spells;
|
||||
@@ -8,12 +9,18 @@ import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.SpellProperties;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumActionResult;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class ItemBlankScroll extends Item implements IWorkbenchItem {
|
||||
|
||||
@@ -67,4 +74,18 @@ public class ItemBlankScroll extends Item implements IWorkbenchItem {
|
||||
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
|
||||
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> items){
|
||||
if(tab == WizardryTabs.WIZARDRY){
|
||||
if(tab == WizardryTabs.WIZARDRY || tab == CreativeTabs.SEARCH){
|
||||
for(Element element : Element.values()){
|
||||
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);
|
||||
if(charge < 0) return;
|
||||
|
||||
if(stack.getTagCompound() != null){
|
||||
int shotsLeft = stack.getTagCompound().getInteger(Flamecatcher.SHOTS_REMAINING_NBT_KEY) - 1;
|
||||
stack.getTagCompound().setInteger(Flamecatcher.SHOTS_REMAINING_NBT_KEY, shotsLeft);
|
||||
if(shotsLeft == 0 && !world.isRemote){
|
||||
stack.setItemDamage(getMaxDamage(stack) - getAnimationFrames());
|
||||
}
|
||||
}
|
||||
|
||||
float velocity = (float)charge / DRAW_TIME;
|
||||
velocity = (velocity * velocity + velocity * 2) / 3;
|
||||
|
||||
@@ -208,6 +200,14 @@ public class ItemFlamecatcher extends ItemBow implements IConjuredItem {
|
||||
|
||||
if((double)velocity >= 0.1D){
|
||||
|
||||
if(stack.getTagCompound() != null){
|
||||
int shotsLeft = stack.getTagCompound().getInteger(Flamecatcher.SHOTS_REMAINING_NBT_KEY) - 1;
|
||||
stack.getTagCompound().setInteger(Flamecatcher.SHOTS_REMAINING_NBT_KEY, shotsLeft);
|
||||
if(shotsLeft == 0 && !world.isRemote){
|
||||
stack.setItemDamage(getMaxDamage(stack) - getAnimationFrames());
|
||||
}
|
||||
}
|
||||
|
||||
if(!world.isRemote){
|
||||
EntityFlamecatcherArrow arrow = new EntityFlamecatcherArrow(world);
|
||||
arrow.aim(player, EntityFlamecatcherArrow.SPEED * velocity);
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
package electroblob.wizardry.item;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.event.DiscoverSpellEvent;
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.InventoryUtils;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.EnumRarity;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.EnumActionResult;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
@@ -47,6 +51,20 @@ public class ItemIdentificationScroll extends Item {
|
||||
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
|
||||
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package electroblob.wizardry.item;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import electroblob.wizardry.data.WizardData;
|
||||
import electroblob.wizardry.event.SpellCastEvent;
|
||||
import electroblob.wizardry.event.SpellCastEvent.Source;
|
||||
@@ -9,6 +10,7 @@ import electroblob.wizardry.packet.WizardryPacketHandler;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import electroblob.wizardry.spell.Spell;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.creativetab.CreativeTabs;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
@@ -17,8 +19,10 @@ import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
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;
|
||||
@@ -122,6 +126,20 @@ public class ItemScroll extends Item implements ISpellCastingItem, IWorkbenchIte
|
||||
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
|
||||
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
|
||||
|
||||
@@ -160,12 +178,21 @@ public class ItemScroll extends Item implements ISpellCastingItem, IWorkbenchIte
|
||||
|
||||
Spell spell = Spell.byMetadata(stack.getItemDamage());
|
||||
// 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;
|
||||
|
||||
// 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...
|
||||
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);
|
||||
}else{
|
||||
// Scrolls normally work on the max use duration so this isn't ever reached by wizardry, but if the
|
||||
|
||||
@@ -29,7 +29,7 @@ public class ItemSpectralDust extends Item implements IMultiTexturedItem {
|
||||
|
||||
@Override
|
||||
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)){
|
||||
items.add(new ItemStack(this, 1, element.ordinal()));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package electroblob.wizardry.item;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.WizardryGuiHandler;
|
||||
import electroblob.wizardry.constants.Tier;
|
||||
@@ -14,9 +15,12 @@ import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
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.TextFormatting;
|
||||
import net.minecraft.world.World;
|
||||
@@ -58,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
|
||||
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
|
||||
ItemStack stack = player.getHeldItem(hand);
|
||||
|
||||
@@ -28,6 +28,7 @@ import net.minecraft.inventory.Slot;
|
||||
import net.minecraft.item.EnumAction;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.*;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
@@ -45,6 +46,7 @@ import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
@@ -68,7 +70,7 @@ import java.util.Random;
|
||||
public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem, IManaStoringItem {
|
||||
|
||||
/** 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. */
|
||||
private static final int CONTINUOUS_TRACKING_INTERVAL = 20;
|
||||
@@ -239,7 +241,9 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
||||
// 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 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,7 +737,7 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
||||
Item specialUpgrade = upgrade.getItem();
|
||||
|
||||
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
|
||||
&& WandHelper.getUpgradeLevel(wand, specialUpgrade) < Constants.UPGRADE_STACK_LIMIT){
|
||||
@@ -842,8 +846,19 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
||||
Spell spell = Spell.byMetadata(spellBooks[i].getStack().getItemDamage());
|
||||
// If the wand is powerful enough for the spell, it's not already bound to that slot and it's enabled for wands
|
||||
if(!(spell.getTier().level > this.tier.level) && spells[i] != spell && spell.isEnabled(SpellProperties.Context.WANDS)){
|
||||
|
||||
// Decide if we can bind this multiple times
|
||||
if (Wizardry.settings.preventBindingSameSpellTwiceToWands && Arrays.stream(spells).anyMatch(s -> s == spell)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
spells[i] = spell;
|
||||
changed = true;
|
||||
|
||||
// setting to consume books upon use
|
||||
if (Wizardry.settings.singleUseSpellBooks) {
|
||||
spellBooks[i].getStack().shrink(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -851,36 +866,35 @@ public class ItemWand extends Item implements IWorkbenchItem, ISpellCastingItem,
|
||||
WandHelper.setSpells(centre.getStack(), spells);
|
||||
|
||||
// Charges wand by appropriate amount
|
||||
if(crystals.getStack() != ItemStack.EMPTY && !this.isManaFull(centre.getStack())){
|
||||
|
||||
int chargeDepleted = this.getManaCapacity(centre.getStack()) - this.getMana(centre.getStack());
|
||||
|
||||
// Not too pretty but allows addons implementing the IManaStoringItem interface to provide their mana amount for custom crystals,
|
||||
// previously this was defaulted to the regular crystal's amount, allowing players to exploit it if a crystal was worth less mana than that.
|
||||
int manaPerItem = crystals.getStack().getItem() instanceof IManaStoringItem ?
|
||||
((IManaStoringItem) crystals.getStack().getItem()).getMana(crystals.getStack()) :
|
||||
crystals.getStack().getItem() instanceof ItemCrystal ? Constants.MANA_PER_CRYSTAL : Constants.MANA_PER_SHARD;
|
||||
|
||||
if(crystals.getStack().getItem() == WizardryItems.crystal_shard) manaPerItem = Constants.MANA_PER_SHARD;
|
||||
if(crystals.getStack().getItem() == WizardryItems.grand_crystal) manaPerItem = Constants.GRAND_CRYSTAL_MANA;
|
||||
|
||||
if(crystals.getStack().getCount() * manaPerItem < chargeDepleted){
|
||||
// If there aren't enough crystals to fully charge the wand
|
||||
this.rechargeMana(centre.getStack(), crystals.getStack().getCount() * manaPerItem);
|
||||
crystals.decrStackSize(crystals.getStack().getCount());
|
||||
|
||||
}else{
|
||||
// If there are excess crystals (or just enough)
|
||||
this.setMana(centre.getStack(), this.getManaCapacity(centre.getStack()));
|
||||
crystals.decrStackSize((int)Math.ceil(((double)chargeDepleted) / manaPerItem));
|
||||
}
|
||||
|
||||
if (WandHelper.rechargeManaOnApplyButtonPressed(centre, crystals)) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClearButtonPressed(EntityPlayer player, Slot centre, Slot crystals, Slot upgrade, Slot[] spellBooks){
|
||||
ItemStack stack = centre.getStack();
|
||||
if (stack.hasTagCompound() && stack.getTagCompound().hasKey(WandHelper.SPELL_ARRAY_KEY)) {
|
||||
NBTTagCompound nbt = stack.getTagCompound();
|
||||
int[] spells = nbt.getIntArray(WandHelper.SPELL_ARRAY_KEY);
|
||||
int expectedSlotCount = BASE_SPELL_SLOTS + WandHelper.getUpgradeLevel(stack,
|
||||
WizardryItems.attunement_upgrade);
|
||||
|
||||
// unbrick broken wands
|
||||
if (spells.length < expectedSlotCount) {
|
||||
spells = new int[expectedSlotCount];
|
||||
}
|
||||
Arrays.fill(spells, 0);
|
||||
nbt.setIntArray(WandHelper.SPELL_ARRAY_KEY, spells);
|
||||
stack.setTagCompound(nbt);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClearable() { return true; }
|
||||
|
||||
// hitEntity is only called server-side, so we'll have to use events
|
||||
@SubscribeEvent
|
||||
public static void onAttackEntityEvent(AttackEntityEvent event){
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
package electroblob.wizardry.item;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
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.Item;
|
||||
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.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
@@ -24,6 +31,20 @@ public class ItemWandUpgrade extends Item {
|
||||
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
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void addInformation(ItemStack stack, @Nullable World world, List<String> tooltip, net.minecraft.client.util.ITooltipFlag flag) {
|
||||
|
||||
@@ -2,13 +2,17 @@ package electroblob.wizardry.item;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.WizardryGuiHandler;
|
||||
import electroblob.wizardry.block.BlockBookshelf;
|
||||
import electroblob.wizardry.registry.WizardryTabs;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.ActionResult;
|
||||
import net.minecraft.util.EnumActionResult;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.text.Style;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
@@ -34,6 +38,20 @@ public class ItemWizardHandbook extends Item {
|
||||
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
|
||||
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand){
|
||||
ItemStack stack = player.getHeldItem(hand);
|
||||
|
||||
@@ -78,7 +78,7 @@ public abstract class Forfeit {
|
||||
|
||||
public Forfeit(ResourceLocation 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);
|
||||
@@ -486,6 +486,8 @@ public abstract class Forfeit {
|
||||
}
|
||||
}));
|
||||
|
||||
add(Tier.MASTER, Element.SORCERY, create("teleport_self_large_distance", (w, p) -> ((Banish)Spells.banish).teleport(p, w, 8 + w.rand.nextDouble() * 700)));
|
||||
|
||||
add(Tier.NOVICE, Element.HEALING, create("damage_self", (w, p) -> p.attackEntityFrom(DamageSource.MAGIC, 4)));
|
||||
|
||||
add(Tier.NOVICE, Element.HEALING, create("spill_armour", (w, p) -> {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,17 @@ public class PacketControlInput implements IMessageHandler<Message, IMessage> {
|
||||
|
||||
break;
|
||||
|
||||
case CLEAR_BUTTON:
|
||||
|
||||
if(!(player.openContainer instanceof ContainerArcaneWorkbench)){
|
||||
Wizardry.logger.warn("Received a PacketControlInput, but the player that sent it was not " +
|
||||
"currently using an arcane workbench. This should not happen!");
|
||||
}else{
|
||||
((ContainerArcaneWorkbench)player.openContainer).onClearButtonPressed(player);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case NEXT_SPELL_KEY:
|
||||
|
||||
if(wand.getItem() instanceof ISpellCastingItem){
|
||||
@@ -133,7 +144,7 @@ public class PacketControlInput implements IMessageHandler<Message, IMessage> {
|
||||
}
|
||||
|
||||
public enum ControlType {
|
||||
APPLY_BUTTON, NEXT_SPELL_KEY, PREVIOUS_SPELL_KEY, RESURRECT_BUTTON, CANCEL_RESURRECT, POSSESSION_PROJECTILE
|
||||
APPLY_BUTTON, NEXT_SPELL_KEY, PREVIOUS_SPELL_KEY, RESURRECT_BUTTON, CANCEL_RESURRECT, POSSESSION_PROJECTILE, CLEAR_BUTTON
|
||||
}
|
||||
|
||||
public static class Message implements IMessage {
|
||||
|
||||
@@ -10,7 +10,11 @@ import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <b>[Server -> Client]</b> This packet is sent to synchronise any fields that need synchronising in
|
||||
@@ -54,9 +58,8 @@ public class PacketPlayerSync implements IMessageHandler<Message, IMessage> {
|
||||
|
||||
this.seed = buf.readLong();
|
||||
this.selectedMinionID = buf.readInt();
|
||||
|
||||
this.spellData = new HashMap<>();
|
||||
WizardData.getSyncedVariables().forEach(v -> spellData.put(v, v.read(buf)));
|
||||
WizardData.getSyncedVariablesOrderedByKey().forEach(v -> spellData.put(v, v.read(buf)));
|
||||
// Have to send empty tags to guarantee correct ByteBuf size/order, but no point keeping the resulting nulls
|
||||
spellData.values().removeIf(Objects::isNull);
|
||||
|
||||
@@ -73,7 +76,7 @@ public class PacketPlayerSync implements IMessageHandler<Message, IMessage> {
|
||||
buf.writeLong(seed);
|
||||
buf.writeInt(selectedMinionID);
|
||||
|
||||
WizardData.getSyncedVariables().forEach(v -> v.write(buf, spellData.get(v)));
|
||||
WizardData.getSyncedVariablesOrderedByKey().forEach(v -> v.write(buf, spellData.get(v)));
|
||||
|
||||
if(this.spellsDiscovered == null) return;
|
||||
for(Spell spell : this.spellsDiscovered){
|
||||
|
||||
@@ -35,6 +35,7 @@ public class WizardryPacketHandler {
|
||||
registerMessage(PacketSpellQuickAccess.class, PacketSpellQuickAccess.Message.class);
|
||||
registerMessage(PacketRequestDonationPerks.class, PacketRequestDonationPerks.Message.class);
|
||||
registerMessage(PacketSyncDonationPerks.class, PacketSyncDonationPerks.Message.class);
|
||||
registerMessage(PacketBombExplosion.class, PacketBombExplosion.Message.class);
|
||||
}
|
||||
|
||||
private static int nextPacketId = 0;
|
||||
|
||||
@@ -13,12 +13,15 @@ public class PotionDiamondflesh extends PotionMagicEffect {
|
||||
super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/diamondflesh.png"));
|
||||
// This needs to be here because registerPotionAttributeModifier doesn't like it if the potion has no name yet.
|
||||
this.setPotionName("potion." + Wizardry.MODID + ":ironflesh");
|
||||
this.registerPotionAttributeModifier(SharedMonsterAttributes.MOVEMENT_SPEED,
|
||||
"158a8af2-6db0-4340-a01c-a7b60d10ddf4", -0.1f, EntityUtils.Operations.MULTIPLY_CUMULATIVE);
|
||||
// Only apply slowness if the setting allows it
|
||||
if(Wizardry.settings.fleshSpellsCauseSlowness) {
|
||||
this.registerPotionAttributeModifier(SharedMonsterAttributes.MOVEMENT_SPEED,
|
||||
"158a8af2-6db0-4340-a01c-a7b60d10ddf4", -0.1f, EntityUtils.Operations.MULTIPLY_CUMULATIVE);
|
||||
}
|
||||
this.registerPotionAttributeModifier(SharedMonsterAttributes.ARMOR_TOUGHNESS,
|
||||
"a68d4532-5847-426c-9b03-d541b113cec2", 3.0f, EntityUtils.Operations.ADD);
|
||||
"a68d4532-5847-426c-9b03-d541b113cec2", (float)Wizardry.settings.diamondFleshArmorToughnessBonus, EntityUtils.Operations.ADD);
|
||||
this.registerPotionAttributeModifier(SharedMonsterAttributes.ARMOR,
|
||||
"46a095be-82dd-43fd-8b67-13f51591eb8e", 4.0f, EntityUtils.Operations.ADD);
|
||||
"46a095be-82dd-43fd-8b67-13f51591eb8e", (float)Wizardry.settings.diamondFleshArmorBonus, EntityUtils.Operations.ADD);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
package electroblob.wizardry.potion;
|
||||
|
||||
import electroblob.wizardry.registry.WizardrySounds;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.SoundCategory;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class PotionFireskin extends PotionMagicEffectParticles {
|
||||
|
||||
public PotionFireskin(boolean isBadEffect, int liquidColour, ResourceLocation texture) {
|
||||
super(isBadEffect, liquidColour, texture);
|
||||
this.setBeneficial();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void spawnCustomParticle(World world, double x, double y, double z){
|
||||
if(world.isRemote){
|
||||
// Spawn ambient fire particles around the entity
|
||||
world.spawnParticle(EnumParticleTypes.FLAME, x, y, z, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReady(int duration, int amplifier) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performEffect(EntityLivingBase entitylivingbase, int strength){
|
||||
|
||||
// Original fireskin behavior: extinguish the entity to prevent fire damage from melee attacks
|
||||
entitylivingbase.extinguish();
|
||||
|
||||
// Server-side cobweb burning logic
|
||||
World world = entitylivingbase.world;
|
||||
if(!world.isRemote){
|
||||
|
||||
AxisAlignedBB entityBox = entitylivingbase.getEntityBoundingBox();
|
||||
|
||||
// Expand the bounding box slightly to catch cobwebs the entity is touching
|
||||
entityBox = entityBox.expand(0.1, 0.1, 0.1);
|
||||
|
||||
BlockPos minPos = new BlockPos(entityBox.minX, entityBox.minY, entityBox.minZ);
|
||||
BlockPos maxPos = new BlockPos(entityBox.maxX, entityBox.maxY, entityBox.maxZ);
|
||||
|
||||
boolean burnedCobweb = false;
|
||||
|
||||
// Check all blocks in the entity's bounding box
|
||||
for(int x = minPos.getX(); x <= maxPos.getX(); x++){
|
||||
for(int y = minPos.getY(); y <= maxPos.getY(); y++){
|
||||
for(int z = minPos.getZ(); z <= maxPos.getZ(); z++){
|
||||
|
||||
BlockPos pos = new BlockPos(x, y, z);
|
||||
|
||||
if(world.getBlockState(pos).getBlock() == Blocks.WEB){
|
||||
// Burn the cobweb
|
||||
world.setBlockToAir(pos);
|
||||
burnedCobweb = true;
|
||||
|
||||
// Add visual effects - spawn particles on client side
|
||||
if(world.rand.nextFloat() < 0.7f){ // 70% chance to spawn particles for better visibility
|
||||
float offsetX = world.rand.nextFloat() * 0.1f - 0.05f;
|
||||
float offsetY = world.rand.nextFloat() * 0.1f + 0.05f;
|
||||
float offsetZ = world.rand.nextFloat() * 0.1f - 0.05f;
|
||||
|
||||
// Main flame particle rising up
|
||||
world.spawnParticle(EnumParticleTypes.FLAME,
|
||||
pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5,
|
||||
0, 0.1, 0);
|
||||
|
||||
// Two additional flame particles with random movement
|
||||
world.spawnParticle(EnumParticleTypes.FLAME,
|
||||
pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5,
|
||||
offsetX, offsetY, offsetZ);
|
||||
|
||||
world.spawnParticle(EnumParticleTypes.FLAME,
|
||||
pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5,
|
||||
offsetX * -0.5f, offsetY * 0.8f, offsetZ * -0.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Play the fire extinguish sound only when cobwebs were actually burned
|
||||
if(burnedCobweb){
|
||||
world.playSound(null, entitylivingbase.getPosition(), SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.BLOCKS, 0.6f, 0.8f + world.rand.nextFloat() * 0.4f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,12 +13,15 @@ public class PotionIronflesh extends PotionMagicEffect {
|
||||
super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/ironflesh.png"));
|
||||
// This needs to be here because registerPotionAttributeModifier doesn't like it if the potion has no name yet.
|
||||
this.setPotionName("potion." + Wizardry.MODID + ":ironflesh");
|
||||
this.registerPotionAttributeModifier(SharedMonsterAttributes.MOVEMENT_SPEED,
|
||||
"fe607d55-50e3-4f4f-a959-6571503f92f4", -0.1f, EntityUtils.Operations.MULTIPLY_CUMULATIVE);
|
||||
// Only apply slowness if the setting allows it
|
||||
if(Wizardry.settings.fleshSpellsCauseSlowness) {
|
||||
this.registerPotionAttributeModifier(SharedMonsterAttributes.MOVEMENT_SPEED,
|
||||
"fe607d55-50e3-4f4f-a959-6571503f92f4", -0.1f, EntityUtils.Operations.MULTIPLY_CUMULATIVE);
|
||||
}
|
||||
this.registerPotionAttributeModifier(SharedMonsterAttributes.KNOCKBACK_RESISTANCE,
|
||||
"6f78206e-8dd4-4d44-9792-d7a882111951", 0.3f, EntityUtils.Operations.ADD);
|
||||
this.registerPotionAttributeModifier(SharedMonsterAttributes.ARMOR,
|
||||
"e1adff1e-8510-4a09-96ed-ef677cad20c1", 4.0f, EntityUtils.Operations.ADD);
|
||||
"e1adff1e-8510-4a09-96ed-ef677cad20c1", (float)Wizardry.settings.ironFleshArmorBonus, EntityUtils.Operations.ADD);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -13,12 +13,15 @@ public class PotionOakflesh extends PotionMagicEffect {
|
||||
super(isBadEffect, liquidColour, new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/oakflesh.png"));
|
||||
// This needs to be here because registerPotionAttributeModifier doesn't like it if the potion has no name yet.
|
||||
this.setPotionName("potion." + Wizardry.MODID + ":ironflesh");
|
||||
this.registerPotionAttributeModifier(SharedMonsterAttributes.MOVEMENT_SPEED,
|
||||
"98b4ba66-7c50-4a4c-9f3f-40bcb37313b5", -0.1f, EntityUtils.Operations.MULTIPLY_CUMULATIVE);
|
||||
// Only apply slowness if the setting allows it
|
||||
if(Wizardry.settings.fleshSpellsCauseSlowness) {
|
||||
this.registerPotionAttributeModifier(SharedMonsterAttributes.MOVEMENT_SPEED,
|
||||
"98b4ba66-7c50-4a4c-9f3f-40bcb37313b5", -0.1f, EntityUtils.Operations.MULTIPLY_CUMULATIVE);
|
||||
}
|
||||
this.registerPotionAttributeModifier(SharedMonsterAttributes.MAX_HEALTH,
|
||||
"ed9d0423-60f4-4998-bd8d-dc7c33bd45b8", 0.2f, EntityUtils.Operations.MULTIPLY_FLAT);
|
||||
"ed9d0423-60f4-4998-bd8d-dc7c33bd45b8", (float)Wizardry.settings.oakFleshHealthBonus, EntityUtils.Operations.MULTIPLY_FLAT);
|
||||
this.registerPotionAttributeModifier(SharedMonsterAttributes.ARMOR,
|
||||
"0b607c3f-fb14-43d7-96b5-1c1b6f6da242", 3.0f, EntityUtils.Operations.ADD);
|
||||
"0b607c3f-fb14-43d7-96b5-1c1b6f6da242", (float)Wizardry.settings.oakFleshArmorBonus, EntityUtils.Operations.ADD);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,6 +2,7 @@ package electroblob.wizardry.registry;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.potion.*;
|
||||
import electroblob.wizardry.potion.PotionFireskin;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
@@ -95,19 +96,8 @@ public final class WizardryPotions {
|
||||
}
|
||||
}.setBeneficial()); // 0xffe89b
|
||||
|
||||
registerPotion(registry, "fireskin", new PotionMagicEffectParticles(false, 0,
|
||||
new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/fireskin.png")){
|
||||
@Override
|
||||
public void spawnCustomParticle(World world, double x, double y, double z){
|
||||
world.spawnParticle(EnumParticleTypes.FLAME, x, y, z, 0, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performEffect(EntityLivingBase entitylivingbase, int strength){
|
||||
entitylivingbase.extinguish(); // Stops melee mobs that are on fire from setting the player on fire,
|
||||
// without allowing the player to actually stand in fire or swim in lava without taking damage.
|
||||
}
|
||||
}.setBeneficial()); // 0xff2f02
|
||||
registerPotion(registry, "fireskin", new PotionFireskin(false, 0xff2f02,
|
||||
new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/fireskin.png")));
|
||||
|
||||
registerPotion(registry, "ice_shroud", new PotionMagicEffectParticles(false, 0,
|
||||
new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/ice_shroud.png")){
|
||||
@@ -130,17 +120,7 @@ public final class WizardryPotions {
|
||||
registerPotion(registry, "decay", new PotionDecay(true, 0x3c006c));
|
||||
|
||||
registerPotion(registry, "sixth_sense", new PotionMagicEffect(false, 0xc6ff01,
|
||||
new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/sixth_sense.png")){
|
||||
@Override
|
||||
public void performEffect(EntityLivingBase target, int strength){
|
||||
// Reset the shader (a bit dirty but both the potion expiry hooks are only fired server-side, and
|
||||
// there's no point sending packets unnecessarily if we can just do this instead)
|
||||
if(target.getActivePotionEffect(this).getDuration() <= 1 && target.world.isRemote
|
||||
&& target == net.minecraft.client.Minecraft.getMinecraft().player){
|
||||
net.minecraft.client.Minecraft.getMinecraft().entityRenderer.stopUseShader();
|
||||
}
|
||||
}
|
||||
}.setBeneficial());
|
||||
new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/sixth_sense.png")).setBeneficial());
|
||||
|
||||
registerPotion(registry, "arcane_jammer", new PotionMagicEffect(true, 0xcf4aa2,
|
||||
new ResourceLocation(Wizardry.MODID, "textures/gui/potion_icons/arcane_jammer.png")));
|
||||
|
||||
@@ -13,14 +13,18 @@ import net.minecraft.tileentity.TileEntityDispenser;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.event.entity.living.LivingDestroyBlockEvent;
|
||||
|
||||
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||
import net.minecraftforge.event.world.BlockEvent;
|
||||
import net.minecraftforge.event.world.ExplosionEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
|
||||
|
||||
@Mod.EventBusSubscriber
|
||||
public class ArcaneLock extends SpellRay {
|
||||
|
||||
@@ -167,4 +171,8 @@ public class ArcaneLock extends SpellRay {
|
||||
&& event.getWorld().getTileEntity(pos).getTileData().hasUniqueId(NBT_KEY));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@ public class BlindingFlash extends SpellAreaEffect {
|
||||
|
||||
if(EntityUtils.isLiving(target)){
|
||||
int duration = (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade));
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, duration, 0));
|
||||
if(!world.isRemote){
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.BLINDNESS, duration, 0));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -27,9 +27,11 @@ public class Containment extends SpellRay {
|
||||
protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
if(EntityUtils.isLiving(target)){
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.containment,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
if(!world.isRemote){
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.containment,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -28,12 +28,14 @@ public class CurseOfEnfeeblement extends SpellRay {
|
||||
|
||||
if(EntityUtils.isLiving(target)){
|
||||
// This will actually run out in the end, but only if you leave Minecraft running for 3.4 years
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.curse_of_enfeeblement,
|
||||
Integer.MAX_VALUE, getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
// Reduce the target's health to its new max health if necessary
|
||||
if(((EntityLivingBase)target).getHealth() > ((EntityLivingBase)target).getMaxHealth()){
|
||||
target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, MagicDamage.DamageType.WITHER),
|
||||
((EntityLivingBase)target).getHealth() - ((EntityLivingBase)target).getMaxHealth());
|
||||
if(!world.isRemote){
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.curse_of_enfeeblement,
|
||||
Integer.MAX_VALUE, getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
// Reduce the target's health to its new max health if necessary
|
||||
if(((EntityLivingBase)target).getHealth() > ((EntityLivingBase)target).getMaxHealth()){
|
||||
target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, MagicDamage.DamageType.WITHER),
|
||||
((EntityLivingBase)target).getHealth() - ((EntityLivingBase)target).getMaxHealth());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -55,14 +55,16 @@ public class CurseOfSoulbinding extends SpellRay {
|
||||
protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
if(EntityUtils.isLiving(target) && caster instanceof EntityPlayer){
|
||||
WizardData data = WizardData.get((EntityPlayer)caster);
|
||||
if(data != null){
|
||||
// Return false if soulbinding failed (e.g. if the target is already soulbound)
|
||||
if(getSoulboundCreatures(data).add(target.getUniqueID())){
|
||||
// This will actually run out in the end, but only if you leave Minecraft running for 3.4 years
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.curse_of_soulbinding, Integer.MAX_VALUE));
|
||||
}else{
|
||||
return false;
|
||||
if(!world.isRemote){
|
||||
WizardData data = WizardData.get((EntityPlayer)caster);
|
||||
if(data != null){
|
||||
// Return false if soulbinding failed (e.g. if the target is already soulbound)
|
||||
if(getSoulboundCreatures(data).add(target.getUniqueID())){
|
||||
// This will actually run out in the end, but only if you leave Minecraft running for 3.4 years
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.curse_of_soulbinding, Integer.MAX_VALUE));
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,10 @@ public class CurseOfUndeath extends SpellRay {
|
||||
if(EntityUtils.isLiving(target)){
|
||||
|
||||
// This will actually run out in the end, but only if you leave Minecraft running for 3.4 years
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.curse_of_undeath, Integer.MAX_VALUE,
|
||||
getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
if(!world.isRemote){
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.curse_of_undeath, Integer.MAX_VALUE,
|
||||
getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -42,9 +42,11 @@ public class EmpoweringPresence extends SpellAreaEffect {
|
||||
|
||||
int bonusAmplifier = SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.empowerment,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier));
|
||||
if(!world.isRemote){
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.empowerment,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -74,4 +76,4 @@ public class EmpoweringPresence extends SpellAreaEffect {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import electroblob.wizardry.item.SpellActions;
|
||||
import electroblob.wizardry.util.ParticleBuilder;
|
||||
import electroblob.wizardry.util.ParticleBuilder.Type;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import net.minecraft.entity.EntityCreature;
|
||||
import net.minecraft.entity.EntityLiving;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.tileentity.TileEntityDispenser;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
@@ -29,7 +29,7 @@ public class Enrage extends SpellAreaEffect {
|
||||
@Override
|
||||
protected boolean affectEntity(World world, Vec3d origin, @Nullable EntityLivingBase caster, EntityLivingBase target, int targetCount, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
if(caster != null && target instanceof EntityCreature){
|
||||
if(caster != null && target instanceof EntityLiving){
|
||||
target.setRevengeTarget(caster); // Yours truly, angry mobs
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ public class FireBreath extends SpellRay {
|
||||
this.getNameForTranslationFormatted()), true);
|
||||
// This now only damages in line with the maxHurtResistantTime. Some mods don't play nicely and fiddle
|
||||
// with this mechanic for their own purposes, so this line makes sure that doesn't affect wizardry.
|
||||
}else if(ticksInUse % ((EntityLivingBase)target).maxHurtResistantTime == 1){
|
||||
}else if(ticksInUse % 10 == 0){
|
||||
target.setFire((int)(getProperty(BURN_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)));
|
||||
EntityUtils.attackEntityWithoutKnockback(target,
|
||||
MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE),
|
||||
|
||||
@@ -56,7 +56,7 @@ public class FlameRay extends SpellRay {
|
||||
this.getNameForTranslationFormatted()), true);
|
||||
// This now only damages in line with the maxHurtResistantTime. Some mods don't play nicely and fiddle
|
||||
// with this mechanic for their own purposes, so this line makes sure that doesn't affect wizardry.
|
||||
}else if(ticksInUse % ((EntityLivingBase)target).maxHurtResistantTime == 1){
|
||||
}else if(ticksInUse % 10 == 0){
|
||||
target.setFire((int)(getProperty(BURN_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)));
|
||||
EntityUtils.attackEntityWithoutKnockback(target,
|
||||
MagicDamage.causeDirectMagicDamage(caster, DamageType.FIRE),
|
||||
|
||||
@@ -33,7 +33,7 @@ public class FontOfMana extends SpellAreaEffect {
|
||||
@Override
|
||||
protected boolean affectEntity(World world, Vec3d origin, @Nullable EntityLivingBase caster, EntityLivingBase target, int targetCount, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
if(target instanceof EntityPlayer){ // Font of mana is only useful to players
|
||||
if(target instanceof EntityPlayer && !world.isRemote){ // Font of mana is only useful to players
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.font_of_mana,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
(int)(getProperty(EFFECT_STRENGTH).intValue() + (modifiers.get(SpellModifiers.POTENCY) - 1) * 2)));
|
||||
@@ -58,4 +58,4 @@ public class FontOfMana extends SpellAreaEffect {
|
||||
/ (2 + event.getCaster().getActivePotionEffect(WizardryPotions.font_of_mana).getAmplifier()), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,9 +38,11 @@ public class ForestsCurse extends SpellAreaEffect {
|
||||
int duration = (int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade));
|
||||
int amplifier = (int)(getProperty(EFFECT_STRENGTH).floatValue() + bonusAmplifier);
|
||||
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.POISON, duration, amplifier));
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, duration, amplifier));
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, duration, amplifier));
|
||||
if(!world.isRemote){
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.POISON, duration, amplifier));
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.SLOWNESS, duration, amplifier));
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, duration, amplifier));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -42,9 +42,11 @@ public class Freeze extends SpellRay {
|
||||
if(!world.isRemote && caster instanceof EntityPlayer) ((EntityPlayer)caster).sendStatusMessage(
|
||||
new TextComponentTranslation("spell.resist", target.getName(), this.getNameForTranslationFormatted()), true);
|
||||
}else{
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.frost,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue()));
|
||||
if(!world.isRemote){
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.frost,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue()));
|
||||
}
|
||||
}
|
||||
|
||||
if(target.isBurning()) target.extinguish();
|
||||
|
||||
@@ -61,11 +61,13 @@ public class FrostRay extends SpellRay {
|
||||
// with this mechanic for their own purposes, so this line makes sure that doesn't affect wizardry.
|
||||
}else{
|
||||
// For frost ray the entity can move slightly, unlike freeze
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.frost,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue()));
|
||||
if(!world.isRemote){
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.frost,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue()));
|
||||
}
|
||||
|
||||
if(ticksInUse % ((EntityLivingBase)target).maxHurtResistantTime == 1){
|
||||
if(ticksInUse % 10 == 0){
|
||||
float damage = getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY);
|
||||
if(target instanceof EntityBlaze || target instanceof EntityMagmaCube) damage *= 2;
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ public class Heal extends SpellBuff {
|
||||
entity.heal(health);
|
||||
|
||||
// If the player is able to heal, they can't possibly have absorption hearts, so no need to check!
|
||||
if(excessHealth > 0 && entity instanceof EntityPlayer
|
||||
if(excessHealth > entity.getAbsorptionAmount() && entity instanceof EntityPlayer
|
||||
&& ItemArtefact.isArtefactActive((EntityPlayer)entity, WizardryItems.amulet_absorption)){
|
||||
entity.setAbsorptionAmount(excessHealth);
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class IceAge extends SpellAreaEffect {
|
||||
caster, (int)(getProperty(FREEZE_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)))){
|
||||
target.playSound(WizardrySounds.MISC_FREEZE, 1.0F, world.rand.nextFloat() * 0.4F + 0.8F);
|
||||
}
|
||||
}else if(target instanceof EntityPlayer){
|
||||
}else if(target instanceof EntityPlayer && !world.isRemote){
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.frost,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue()));
|
||||
|
||||
@@ -52,12 +52,14 @@ public class Intimidate extends SpellAreaEffect {
|
||||
|
||||
int bonusAmplifier = SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
NBTTagCompound entityNBT = target.getEntityData();
|
||||
if(entityNBT != null) entityNBT.setUniqueId(NBT_KEY, caster.getUniqueID());
|
||||
if(!world.isRemote){
|
||||
NBTTagCompound entityNBT = target.getEntityData();
|
||||
if(entityNBT != null) entityNBT.setUniqueId(NBT_KEY, caster.getUniqueID());
|
||||
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.fear,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier));
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.fear,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -29,9 +29,11 @@ public class InvigoratingPresence extends SpellAreaEffect {
|
||||
|
||||
int bonusAmplifier = SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.STRENGTH,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier));
|
||||
if(!world.isRemote){
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.STRENGTH,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + bonusAmplifier));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class LifeDrain extends SpellRay {
|
||||
|
||||
if(EntityUtils.isLiving(target)){
|
||||
|
||||
if(ticksInUse % 12 == 0){
|
||||
if(ticksInUse % 10 == 0){
|
||||
|
||||
float damage = getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY);
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ public class LightningRay extends SpellRay {
|
||||
this.getNameForTranslationFormatted()), true);
|
||||
// This now only damages in line with the maxHurtResistantTime. Some mods don't play nicely and fiddle
|
||||
// with this mechanic for their own purposes, so this line makes sure that doesn't affect wizardry.
|
||||
}else if(ticksInUse % ((EntityLivingBase)target).maxHurtResistantTime == 1){
|
||||
}else if(ticksInUse % 10 == 0){
|
||||
EntityUtils.attackEntityWithoutKnockback(target,
|
||||
MagicDamage.causeDirectMagicDamage(caster, DamageType.SHOCK),
|
||||
getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
@@ -53,7 +53,7 @@ public class LightningWeb extends SpellRay {
|
||||
@Override
|
||||
protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
if(EntityUtils.isLiving(target)){
|
||||
if(EntityUtils.isLiving(target) && ticksInUse % 10 == 0){
|
||||
|
||||
electrocute(world, caster, origin, target, getProperty(PRIMARY_DAMAGE).floatValue()
|
||||
* modifiers.get(SpellModifiers.POTENCY), ticksInUse);
|
||||
|
||||
@@ -32,7 +32,7 @@ public class MarkSacrifice extends SpellRay {
|
||||
@Override
|
||||
protected boolean onEntityHit(World world, Entity target, Vec3d hit, EntityLivingBase caster, Vec3d origin, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
if(EntityUtils.isLiving(target)){
|
||||
if(EntityUtils.isLiving(target) && !world.isRemote){
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.mark_of_sacrifice,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
|
||||
@@ -120,8 +120,10 @@ public class MindControl extends SpellRay {
|
||||
}
|
||||
|
||||
public static void startControlling(EntityLiving target, EntityLivingBase controller, int duration){
|
||||
target.getEntityData().setUniqueId(NBT_KEY, controller.getUniqueID());
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.mind_control, duration, 0));
|
||||
if(!target.world.isRemote){
|
||||
target.getEntityData().setUniqueId(NBT_KEY, controller.getUniqueID());
|
||||
target.addPotionEffect(new PotionEffect(WizardryPotions.mind_control, duration, 0));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,4 +240,4 @@ public class MindControl extends SpellRay {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,8 +64,10 @@ public class Paralysis extends SpellRay {
|
||||
}
|
||||
|
||||
float durationMultiplier = target instanceof EntityPlayer ? modifiers.get(PLAYER_EFFECT_DURATION_MULTIPLIER) : 1.0f;
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.paralysis,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * durationMultiplier * modifiers.get(WizardryItems.duration_upgrade)), 0));
|
||||
if(!world.isRemote){
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(WizardryPotions.paralysis,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * durationMultiplier * modifiers.get(WizardryItems.duration_upgrade)), 0));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -34,9 +34,11 @@ public class PlagueOfDarkness extends SpellAreaEffect {
|
||||
if(!MagicDamage.isEntityImmune(DamageType.WITHER, target)){
|
||||
target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.WITHER),
|
||||
getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY));
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.WITHER,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
if(!world.isRemote){
|
||||
target.addPotionEffect(new PotionEffect(MobEffects.WITHER,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -45,9 +45,11 @@ public class Poison extends SpellRay {
|
||||
}else{
|
||||
target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.POISON),
|
||||
getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY));
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.POISON,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
if(!world.isRemote){
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.POISON,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -330,9 +330,11 @@ public class Possession extends SpellRay {
|
||||
victim.setPosition(player.posX, player.posY, player.posZ);
|
||||
if(!player.world.isRemote) player.world.spawnEntity(victim);
|
||||
|
||||
for(PotionEffect effect : player.getActivePotionEffects()){
|
||||
if(effect.getPotion() instanceof PotionSlowTime) continue; // Don't transfer slow time
|
||||
victim.addPotionEffect(effect);
|
||||
if(!player.world.isRemote){
|
||||
for(PotionEffect effect : player.getActivePotionEffects()){
|
||||
if(effect.getPotion() instanceof PotionSlowTime) continue; // Don't transfer slow time
|
||||
victim.addPotionEffect(effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ public class RayOfPurification extends SpellRay {
|
||||
if(!world.isRemote && ticksInUse == 1 && caster instanceof EntityPlayer) ((EntityPlayer)caster)
|
||||
.sendStatusMessage(new TextComponentTranslation("spell.resist", target.getName(),
|
||||
this.getNameForTranslationFormatted()), true);
|
||||
}else{
|
||||
}else if (ticksInUse % 10 == 0) {
|
||||
|
||||
float damage = getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY);
|
||||
// Fire
|
||||
@@ -69,8 +69,10 @@ public class RayOfPurification extends SpellRay {
|
||||
EntityUtils.attackEntityWithoutKnockback(target,
|
||||
MagicDamage.causeDirectMagicDamage(caster, DamageType.RADIANT), damage);
|
||||
// Blindness
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.BLINDNESS,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))));
|
||||
if(!world.isRemote){
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.BLINDNESS,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,8 +41,10 @@ public class Shield extends Spell {
|
||||
@Override
|
||||
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
caster.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, 10,
|
||||
getProperty(EFFECT_STRENGTH).intValue(), false, false));
|
||||
if(!world.isRemote){
|
||||
caster.addPotionEffect(new PotionEffect(MobEffects.RESISTANCE, 10,
|
||||
getProperty(EFFECT_STRENGTH).intValue(), false, false));
|
||||
}
|
||||
|
||||
if(WizardData.get(caster).getVariable(SHIELD_KEY) == null){
|
||||
|
||||
|
||||
@@ -35,9 +35,11 @@ public class SixthSense extends Spell {
|
||||
@Override
|
||||
public boolean cast(World world, EntityPlayer caster, EnumHand hand, int ticksInUse, SpellModifiers modifiers){
|
||||
|
||||
caster.addPotionEffect(new PotionEffect(WizardryPotions.sixth_sense,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
(int)((modifiers.get(WizardryItems.range_upgrade) - 1f) / Constants.RANGE_INCREASE_PER_LEVEL)));
|
||||
if(!world.isRemote){
|
||||
caster.addPotionEffect(new PotionEffect(WizardryPotions.sixth_sense,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
(int)((modifiers.get(WizardryItems.range_upgrade) - 1f) / Constants.RANGE_INCREASE_PER_LEVEL)));
|
||||
}
|
||||
|
||||
if(world.isRemote){
|
||||
Wizardry.proxy.loadShader(caster, SHADER);
|
||||
|
||||
@@ -907,7 +907,7 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
|
||||
* its JSON file using a resource pack. If called with no arguments, defaults to any context, i.e. only returns
|
||||
* false if the spell is completely disabled in all contexts. */
|
||||
public final boolean isEnabled(SpellProperties.Context... contexts){
|
||||
return enabled && (contexts.length == 0 || properties.isEnabled(contexts));
|
||||
return enabled && (contexts.length == 0 || (arePropertiesInitialised() && properties.isEnabled(contexts)));
|
||||
}
|
||||
|
||||
/** Sets whether the spell is enabled or not. */
|
||||
@@ -922,6 +922,11 @@ public abstract class Spell extends IForgeRegistryEntry.Impl<Spell> implements C
|
||||
return Arrays.asList(applicableItems).contains(item);
|
||||
}
|
||||
|
||||
/** Returns the list of items this spell is applicable to. */
|
||||
public List<Item> getApplicableItems() {
|
||||
return Arrays.asList(applicableItems);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets which items this spell can appear on (these default to the regular spell book and scroll).
|
||||
* @param applicableItems The items this spell should naturally appear on (or no items at all).
|
||||
|
||||
@@ -168,6 +168,8 @@ public class SpellBuff extends Spell {
|
||||
* Returns a boolean to allow subclasses to cause the spell to fail if for some reason the effect cannot be applied
|
||||
* (for example, {@link Heal} fails if the caster is on full health). */
|
||||
protected boolean applyEffects(EntityLivingBase caster, SpellModifiers modifiers){
|
||||
if(caster.world.isRemote) return true;
|
||||
|
||||
// This will generate 0 for novice and apprentice, and 1 for advanced and master
|
||||
// TODO: Once we've found a way of detecting if amplifiers actually affect the potion type, implement it here.
|
||||
int bonusAmplifier = getBonusAmplifier(modifiers.get(SpellModifiers.POTENCY));
|
||||
|
||||
@@ -47,7 +47,7 @@ import javax.annotation.Nullable;
|
||||
public abstract class SpellRay extends Spell {
|
||||
|
||||
/** The distance below the caster's eyes that the bolt particles start from. */
|
||||
protected static final double Y_OFFSET = 0.25;
|
||||
public static final double Y_OFFSET = 0.25;
|
||||
|
||||
/** The distance between spawned particles. Defaults to 0.85. */
|
||||
// 0.85 was chosen to keep it similar to the most common method used previously, which gave an effective spacing of
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package electroblob.wizardry.spell;
|
||||
|
||||
import electroblob.wizardry.Wizardry;
|
||||
import electroblob.wizardry.item.ItemArtefact;
|
||||
import electroblob.wizardry.item.SpellActions;
|
||||
import electroblob.wizardry.registry.WizardryItems;
|
||||
import electroblob.wizardry.util.SpellModifiers;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.Entity;
|
||||
@@ -34,15 +36,15 @@ public class Telekinesis extends SpellRay {
|
||||
target.motionZ = (origin.z - target.posZ) / 6;
|
||||
return true;
|
||||
|
||||
}else if(target instanceof EntityPlayer && (Wizardry.settings.telekineticDisarmament || !(caster instanceof EntityPlayer))){
|
||||
} else if (target instanceof EntityPlayer && (Wizardry.settings.telekineticDisarmament && !ItemArtefact.isArtefactActive((EntityPlayer) target, WizardryItems.amulet_anchoring))) {
|
||||
|
||||
EntityPlayer player = (EntityPlayer) target;
|
||||
|
||||
EntityPlayer player = (EntityPlayer)target;
|
||||
|
||||
// IDEA: Disarm the offhand if the mainhand is empty or otherwise harmless?
|
||||
|
||||
if(!player.getHeldItemMainhand().isEmpty()){
|
||||
if (!player.getHeldItemMainhand().isEmpty()) {
|
||||
|
||||
if(!world.isRemote){
|
||||
if (!world.isRemote) {
|
||||
EntityItem item = player.entityDropItem(player.getHeldItemMainhand(), 0);
|
||||
// Makes the item move towards the caster
|
||||
item.motionX = (origin.x - player.posX) / 20;
|
||||
@@ -50,7 +52,7 @@ public class Telekinesis extends SpellRay {
|
||||
}
|
||||
|
||||
player.setHeldItem(EnumHand.MAIN_HAND, ItemStack.EMPTY);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,8 +157,10 @@ public class Transportation extends Spell {
|
||||
|
||||
if(BlockTransportationStone.testForCircle(world, destination)){
|
||||
this.playSound(world, player, 0, -1, modifiers);
|
||||
player.addPotionEffect(new PotionEffect(MobEffects.NAUSEA, 150, 0));
|
||||
data.setVariable(COUNTDOWN_KEY, getProperty(TELEPORT_COUNTDOWN).intValue());
|
||||
if(!world.isRemote){
|
||||
player.addPotionEffect(new PotionEffect(MobEffects.NAUSEA, 150, 0));
|
||||
data.setVariable(COUNTDOWN_KEY, getProperty(TELEPORT_COUNTDOWN).intValue());
|
||||
}
|
||||
return true;
|
||||
}else{
|
||||
if(!world.isRemote) player.sendStatusMessage(new TextComponentTranslation("spell." + this.getUnlocalisedName() + ".missing"), true);
|
||||
|
||||
@@ -39,9 +39,11 @@ public class Wither extends SpellRay {
|
||||
}else{
|
||||
target.attackEntityFrom(MagicDamage.causeDirectMagicDamage(caster, DamageType.WITHER),
|
||||
getProperty(DAMAGE).floatValue() * modifiers.get(SpellModifiers.POTENCY));
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.WITHER,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
if(!world.isRemote){
|
||||
((EntityLivingBase)target).addPotionEffect(new PotionEffect(MobEffects.WITHER,
|
||||
(int)(getProperty(EFFECT_DURATION).floatValue() * modifiers.get(WizardryItems.duration_upgrade)),
|
||||
getProperty(EFFECT_STRENGTH).intValue() + SpellBuff.getStandardBonusAmplifier(modifiers.get(SpellModifiers.POTENCY))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user