diff --git a/.gitignore b/.gitignore index 586a748e..ebe6a616 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ build eclipse logs run +runs # Files from Forge MDK forge*changelog.txt diff --git a/build.gradle b/build.gradle index b610c71a..3fc9d83d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,25 +1,15 @@ -buildscript { - repositories { - mavenCentral() - - maven { url = 'https://maven.parchmentmc.org' } - } - dependencies { - classpath 'org.parchmentmc:librarian:1.+' - } -} - plugins { + id 'java-library' id 'eclipse' id 'idea' id 'maven-publish' - id 'net.neoforged.gradle' version '[6.0.13, 6.2)' - id 'org.spongepowered.mixin' version '0.7.+' + id 'net.neoforged.gradle.userdev' version '7.0.170' id 'io.freefair.lombok' version '8.4' } -apply plugin: 'org.parchmentmc.librarian.forgegradle' -apply plugin: 'java' +tasks.named('wrapper', Wrapper).configure { + distributionType = Wrapper.DistributionType.BIN +} version = minecraft_version + "-" + mod_version group = mod_group_id @@ -28,81 +18,57 @@ base { archivesName = mod_id } -sourceCompatibility = targetCompatibility = JavaVersion.VERSION_17 - -println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) - -mixin { - add sourceSets.main, "relics.refmap.json" - config "relics.mixins.json" - - debug.verbose = true - debug.export = true -} +java.toolchain.languageVersion = JavaLanguageVersion.of(21) minecraft { - mappings channel: 'parchment', version: '2023.09.03-1.20.1' - - accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') - - copyIdeResources = true + accessTransformers { + file('src/main/resources/META-INF/accesstransformer.cfg') + } runs { - client { - workingDirectory project.file('run') + configureEach { + systemProperty 'forge.logging.markers', 'REGISTRIES' + systemProperty 'forge.logging.console.level', 'debug' - property 'forge.logging.markers', 'REGISTRIES' - property 'forge.logging.console.level', 'debug' - property 'forge.enabledGameTestNamespaces', mod_id - - jvmArg "-XX:+AllowEnhancedClassRedefinition" - jvmArg "-XX:+AllowRedefinitionToAddDeleteMethods" + modSource project.sourceSets.main + } - arg "-mixin.config=" + mod_id + ".mixins.json" - mods { - "${mod_id}" { - source sourceSets.main - } - } + client { + systemProperty 'forge.enabledGameTestNamespaces', project.mod_id } server { - workingDirectory project.file('run') - - property 'forge.logging.markers', 'REGISTRIES' - property 'forge.logging.console.level', 'debug' - property 'forge.enabledGameTestNamespaces', mod_id - - jvmArg "-XX:+AllowEnhancedClassRedefinition" - jvmArg "-XX:+AllowRedefinitionToAddDeleteMethods" + systemProperty 'forge.enabledGameTestNamespaces', project.mod_id - arg "-mixin.config=" + mod_id + ".mixins.json" - mods { - "${mod_id}" { - source sourceSets.main - } - } + programArgument '--nogui' } } } sourceSets.main.resources { srcDir 'src/generated/resources' } +configurations { + runtimeClasspath.extendsFrom localRuntime +} + repositories { + mavenLocal() flatDir { dirs 'libs' } maven { - url = "https://maven.theillusivec4.top/" + name = "TerraformersMC" + url = "https://maven.terraformersmc.com/" } maven { - name = "Blamejared maven" - url = "https://maven.blamejared.com/" + name = "OctoStudios" + url = uri("https://maven.octo-studios.com/releases") } maven { - name = "ModMaven" - url = "https://modmaven.k-4u.nl" + name = "Illusive Soulworks maven" + url = "https://maven.theillusivec4.top/" } + maven { url "https://maven.architectury.dev/" } exclusiveContent { forRepository { maven { @@ -116,21 +82,17 @@ repositories { } dependencies { - minecraft "net.neoforged:forge:${minecraft_version}-${forge_version}" - - if (System.getProperty("idea.sync.active") != "true") { - annotationProcessor "org.spongepowered:mixin:0.8.5:processor" - } + implementation "net.neoforged:neoforge:${neoforge_version}" implementation 'org.jetbrains:annotations:20.1.0' - runtimeOnly fg.deobf("top.theillusivec4.curios:curios-forge:5.7.0+1.20.1") - compileOnly fg.deobf("top.theillusivec4.curios:curios-forge:5.7.0+1.20.1:api") + implementation 'top.theillusivec4.curios:curios-neoforge:9.2.2+1.21.1' - compileOnly(fg.deobf("mezz.jei:jei-${minecraft_version}-common-api:15.2.0.27")) - compileOnly(fg.deobf("mezz.jei:jei-${minecraft_version}-forge-api:15.2.0.27")) + implementation "it.hurts.octostudios.octolib:octolib-neoforge:0.5.0.1+1.21" - runtimeOnly(fg.deobf("mezz.jei:jei-${minecraft_version}-forge:15.2.0.27")) + implementation "dev.architectury:architectury-neoforge:13.0.6" + + implementation "dev.emi:emi-neoforge:1.1.12+1.21" if (file("libs").isDirectory()) { file("libs").eachFile { file -> @@ -144,7 +106,7 @@ dependencies { def modreference = "lib:$modartifact:$modversion" dependencies { - implementation fg.deobf(project.dependencies.create(modreference) { + implementation (project.dependencies.create(modreference) { transitive = false }) } @@ -153,18 +115,18 @@ dependencies { } else file("libs").mkdir() } -def resourceTargets = ['META-INF/mods.toml', 'pack.mcmeta'] -def replaceProperties = [ - minecraft_version: minecraft_version, forge_version: forge_version, - mod_id : mod_id, mod_name: mod_name, mod_version: mod_version, - mod_authors : mod_authors -] - -processResources { +tasks.withType(ProcessResources).configureEach { + var replaceProperties = [ + minecraft_version : minecraft_version, + forge_version : neoforge_version, + mod_id : mod_id, + mod_name : mod_name, + mod_version : mod_version, + mod_authors : mod_authors + ] inputs.properties replaceProperties - replaceProperties.put 'project', project - filesMatching(resourceTargets) { + filesMatching(['META-INF/neoforge.mods.toml', 'pack.mcmeta']) { expand replaceProperties } } @@ -172,7 +134,6 @@ processResources { jar { manifest { attributes([ - "MixinConfigs" : mod_id + ".mixins.json", "Specification-Title" : mod_id, "Specification-Vendor" : mod_authors, "Specification-Version" : "1", @@ -184,8 +145,13 @@ jar { } } -jar.finalizedBy('reobfJar') - tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' +} + +idea { + module { + downloadSources = true + downloadJavadoc = true + } } \ No newline at end of file diff --git a/crowdin.yml b/crowdin.yml deleted file mode 100644 index ac4f6a0a..00000000 --- a/crowdin.yml +++ /dev/null @@ -1,3 +0,0 @@ -files: - - source: src/main/resources/assets/relics/lang/ - translation: src/main/resources/assets/relics/lang/ diff --git a/gradle.properties b/gradle.properties index e6cc531a..1d553c9b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,17 +1,17 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -minecraft_version=1.20.1 -forge_version=47.1.100 - -mapping_channel=official -mapping_version=1.20.1 +minecraft_version=1.21.1 +neoforge_version=21.1.90 mod_id=relics mod_name=Relics -mod_version=0.6.5.1 +mod_version=0.10.5 mod_group_id=it.hurts.sskirillss.relics -mod_authors=SSKirillSS \ No newline at end of file +mod_authors=SSKirillSS + +neogradle.subsystems.parchment.minecraftVersion=1.21.1 +neogradle.subsystems.parchment.mappingsVersion=2024.11.17 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 6985c875..8fc91c82 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +zipStorePath=wrapper/dists \ No newline at end of file diff --git a/gradlew b/gradlew index 65dcd68d..31042a67 100644 --- a/gradlew +++ b/gradlew @@ -83,10 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +131,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + 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 fi # Increase the maximum file descriptors if we can. @@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ @@ -241,4 +246,4 @@ eval "set -- $( tr '\n' ' ' )" '"$@"' -exec "$JAVACMD" "$@" +exec "$JAVACMD" "$@" \ No newline at end of file diff --git a/gradlew.bat b/gradlew.bat index 93e3f59f..0faad1ae 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -89,4 +89,4 @@ exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal -:omega +:omega \ No newline at end of file diff --git a/libs/octolib-1.20.1-0.3.jar b/libs/octolib-1.20.1-0.3.jar deleted file mode 100644 index 0dc42aa4..00000000 Binary files a/libs/octolib-1.20.1-0.3.jar and /dev/null differ diff --git a/libs/sophisticatedbackpacks-1.21.1-3.20.29.1156.jar b/libs/sophisticatedbackpacks-1.21.1-3.20.29.1156.jar new file mode 100644 index 00000000..d2dcf449 Binary files /dev/null and b/libs/sophisticatedbackpacks-1.21.1-3.20.29.1156.jar differ diff --git a/libs/sophisticatedcore-1.21.1-1.0.5.813.jar b/libs/sophisticatedcore-1.21.1-1.0.5.813.jar new file mode 100644 index 00000000..04d8d8e7 Binary files /dev/null and b/libs/sophisticatedcore-1.21.1-1.0.5.813.jar differ diff --git a/settings.gradle b/settings.gradle index 24584e97..fa236f1f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,5 +1,6 @@ pluginManagement { repositories { + mavenLocal() gradlePluginPortal() maven { name = 'NeoForged' @@ -9,5 +10,5 @@ pluginManagement { } plugins { - id 'org.gradle.toolchains.foojay-resolver-convention' version '0.5.0' + id 'org.gradle.toolchains.foojay-resolver-convention' version '0.9.0' } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/Relics.java b/src/main/java/it/hurts/sskirillss/relics/Relics.java index 92b6f4ac..948a012c 100644 --- a/src/main/java/it/hurts/sskirillss/relics/Relics.java +++ b/src/main/java/it/hurts/sskirillss/relics/Relics.java @@ -1,14 +1,12 @@ package it.hurts.sskirillss.relics; -import it.hurts.sskirillss.relics.config.ConfigHelper; import it.hurts.sskirillss.relics.init.*; -import it.hurts.sskirillss.relics.network.NetworkHandler; import it.hurts.sskirillss.relics.utils.Reference; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.InterModComms; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.fml.InterModComms; +import net.neoforged.fml.ModContainer; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -16,29 +14,28 @@ public class Relics { public static final Logger LOGGER = LogManager.getLogger(Reference.MODID); - public Relics() { - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setupCommon); - - MinecraftForge.EVENT_BUS.register(this); - - ItemRegistry.register(); - BlockRegistry.register(); - TileRegistry.register(); - EntityRegistry.register(); - EffectRegistry.register(); - CodecRegistry.register(); - SoundRegistry.register(); - CommandRegistry.register(); - ParticleRegistry.register(); - CreativeTabRegistry.register(); + public Relics(IEventBus bus, ModContainer container) { + bus.addListener(this::setupCommon); + + ItemRegistry.register(bus); + TileRegistry.register(bus); + BlockRegistry.register(bus); + SoundRegistry.register(bus); + BadgeRegistry.register(bus); + EntityRegistry.register(bus); + EffectRegistry.register(bus); + CommandRegistry.register(bus); + ParticleRegistry.register(bus); + LootCodecRegistry.register(bus); + CreativeTabRegistry.register(bus); + DataComponentRegistry.register(bus); + RelicContainerRegistry.register(bus); } private void setupCommon(final FMLCommonSetupEvent event) { - NetworkHandler.register(); DispenserBehaviorRegistry.register(); + ConfigRegistry.register(); - ConfigHelper.setupConfigs(); - - InterModComms.sendTo("carryon", "blacklistBlock", () -> "relics:researching_table"); + InterModComms.sendTo("darkmodeeverywhere", "dme-shaderblacklist", () -> Reference.MODID); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/api/events/base/RelicEvent.java b/src/main/java/it/hurts/sskirillss/relics/api/events/base/RelicEvent.java index 6ec1ec3a..97c0a7d5 100644 --- a/src/main/java/it/hurts/sskirillss/relics/api/events/base/RelicEvent.java +++ b/src/main/java/it/hurts/sskirillss/relics/api/events/base/RelicEvent.java @@ -4,7 +4,7 @@ import lombok.Getter; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.eventbus.api.Event; +import net.neoforged.bus.api.Event; import javax.annotation.Nullable; diff --git a/src/main/java/it/hurts/sskirillss/relics/api/events/common/ContainerSlotClickEvent.java b/src/main/java/it/hurts/sskirillss/relics/api/events/common/ContainerSlotClickEvent.java index acda5d98..3c33f15b 100644 --- a/src/main/java/it/hurts/sskirillss/relics/api/events/common/ContainerSlotClickEvent.java +++ b/src/main/java/it/hurts/sskirillss/relics/api/events/common/ContainerSlotClickEvent.java @@ -6,11 +6,10 @@ import net.minecraft.world.inventory.ClickAction; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.event.entity.player.PlayerContainerEvent; -import net.minecraftforge.eventbus.api.Cancelable; +import net.neoforged.bus.api.ICancellableEvent; +import net.neoforged.neoforge.event.entity.player.PlayerContainerEvent; -@Cancelable -public class ContainerSlotClickEvent extends PlayerContainerEvent { +public class ContainerSlotClickEvent extends PlayerContainerEvent implements ICancellableEvent { @Getter private final Slot slot; @Getter diff --git a/src/main/java/it/hurts/sskirillss/relics/api/events/common/EntityBlockSpeedFactorEvent.java b/src/main/java/it/hurts/sskirillss/relics/api/events/common/EntityBlockSpeedFactorEvent.java index 41a7786d..4b2b1f37 100644 --- a/src/main/java/it/hurts/sskirillss/relics/api/events/common/EntityBlockSpeedFactorEvent.java +++ b/src/main/java/it/hurts/sskirillss/relics/api/events/common/EntityBlockSpeedFactorEvent.java @@ -4,7 +4,7 @@ import lombok.Setter; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.event.entity.EntityEvent; +import net.neoforged.neoforge.event.entity.EntityEvent; public class EntityBlockSpeedFactorEvent extends EntityEvent { @Getter diff --git a/src/main/java/it/hurts/sskirillss/relics/api/events/common/FluidCollisionEvent.java b/src/main/java/it/hurts/sskirillss/relics/api/events/common/FluidCollisionEvent.java index 1b7afa3e..2c420180 100644 --- a/src/main/java/it/hurts/sskirillss/relics/api/events/common/FluidCollisionEvent.java +++ b/src/main/java/it/hurts/sskirillss/relics/api/events/common/FluidCollisionEvent.java @@ -3,11 +3,10 @@ import lombok.Getter; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.level.material.FluidState; -import net.minecraftforge.event.entity.living.LivingEvent; -import net.minecraftforge.eventbus.api.Cancelable; +import net.neoforged.bus.api.ICancellableEvent; +import net.neoforged.neoforge.event.entity.living.LivingEvent; -@Cancelable -public class FluidCollisionEvent extends LivingEvent { +public class FluidCollisionEvent extends LivingEvent implements ICancellableEvent { @Getter private final FluidState fluid; diff --git a/src/main/java/it/hurts/sskirillss/relics/api/events/common/LivingSlippingEvent.java b/src/main/java/it/hurts/sskirillss/relics/api/events/common/LivingSlippingEvent.java index 0062ef85..94d400ae 100644 --- a/src/main/java/it/hurts/sskirillss/relics/api/events/common/LivingSlippingEvent.java +++ b/src/main/java/it/hurts/sskirillss/relics/api/events/common/LivingSlippingEvent.java @@ -4,7 +4,7 @@ import lombok.Setter; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.event.entity.living.LivingEvent; +import net.neoforged.neoforge.event.entity.living.LivingEvent; public class LivingSlippingEvent extends LivingEvent { @Getter diff --git a/src/main/java/it/hurts/sskirillss/relics/api/events/common/TooltipDisplayEvent.java b/src/main/java/it/hurts/sskirillss/relics/api/events/common/TooltipDisplayEvent.java index 713b0873..9644a434 100644 --- a/src/main/java/it/hurts/sskirillss/relics/api/events/common/TooltipDisplayEvent.java +++ b/src/main/java/it/hurts/sskirillss/relics/api/events/common/TooltipDisplayEvent.java @@ -4,7 +4,7 @@ import lombok.Data; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.eventbus.api.Event; +import net.neoforged.bus.api.Event; @Data @AllArgsConstructor diff --git a/src/main/java/it/hurts/sskirillss/relics/api/events/leveling/ExperienceAddEvent.java b/src/main/java/it/hurts/sskirillss/relics/api/events/leveling/ExperienceAddEvent.java index 67671852..0ddc8817 100644 --- a/src/main/java/it/hurts/sskirillss/relics/api/events/leveling/ExperienceAddEvent.java +++ b/src/main/java/it/hurts/sskirillss/relics/api/events/leveling/ExperienceAddEvent.java @@ -5,12 +5,11 @@ import lombok.Setter; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.eventbus.api.Cancelable; +import net.neoforged.bus.api.ICancellableEvent; import javax.annotation.Nullable; -@Cancelable -public class ExperienceAddEvent extends RelicEvent { +public class ExperienceAddEvent extends RelicEvent implements ICancellableEvent { @Getter @Setter private int amount; diff --git a/src/main/java/it/hurts/sskirillss/relics/badges/ability/ChargeableBadge.java b/src/main/java/it/hurts/sskirillss/relics/badges/ability/ChargeableBadge.java new file mode 100644 index 00000000..969f0cfa --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/badges/ability/ChargeableBadge.java @@ -0,0 +1,10 @@ +package it.hurts.sskirillss.relics.badges.ability; + +import it.hurts.sskirillss.relics.badges.ability.base.CastTypeBadge; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; + +public class ChargeableBadge extends CastTypeBadge { + public ChargeableBadge() { + super(CastType.CHARGEABLE); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/badges/ability/CyclicalBadge.java b/src/main/java/it/hurts/sskirillss/relics/badges/ability/CyclicalBadge.java new file mode 100644 index 00000000..9c9202a6 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/badges/ability/CyclicalBadge.java @@ -0,0 +1,10 @@ +package it.hurts.sskirillss.relics.badges.ability; + +import it.hurts.sskirillss.relics.badges.ability.base.CastTypeBadge; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; + +public class CyclicalBadge extends CastTypeBadge { + public CyclicalBadge() { + super(CastType.CYCLICAL); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/badges/ability/FlawlessAbilityBadge.java b/src/main/java/it/hurts/sskirillss/relics/badges/ability/FlawlessAbilityBadge.java new file mode 100644 index 00000000..7fc8b981 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/badges/ability/FlawlessAbilityBadge.java @@ -0,0 +1,19 @@ +package it.hurts.sskirillss.relics.badges.ability; + +import it.hurts.sskirillss.relics.badges.base.AbilityBadge; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import net.minecraft.world.item.ItemStack; + +public class FlawlessAbilityBadge extends AbilityBadge { + public FlawlessAbilityBadge() { + super("flawless_ability"); + } + + @Override + public boolean isVisible(ItemStack stack, String ability) { + if (!(stack.getItem() instanceof IRelicItem relic)) + return false; + + return relic.isAbilityFlawless(stack, ability); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/badges/ability/InstantaneousBadge.java b/src/main/java/it/hurts/sskirillss/relics/badges/ability/InstantaneousBadge.java new file mode 100644 index 00000000..b3a4cb89 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/badges/ability/InstantaneousBadge.java @@ -0,0 +1,10 @@ +package it.hurts.sskirillss.relics.badges.ability; + +import it.hurts.sskirillss.relics.badges.ability.base.CastTypeBadge; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; + +public class InstantaneousBadge extends CastTypeBadge { + public InstantaneousBadge() { + super(CastType.INSTANTANEOUS); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/badges/ability/InterruptibleBadge.java b/src/main/java/it/hurts/sskirillss/relics/badges/ability/InterruptibleBadge.java new file mode 100644 index 00000000..f29cf826 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/badges/ability/InterruptibleBadge.java @@ -0,0 +1,10 @@ +package it.hurts.sskirillss.relics.badges.ability; + +import it.hurts.sskirillss.relics.badges.ability.base.CastTypeBadge; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; + +public class InterruptibleBadge extends CastTypeBadge { + public InterruptibleBadge() { + super(CastType.INTERRUPTIBLE); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/badges/ability/OblivionBadge.java b/src/main/java/it/hurts/sskirillss/relics/badges/ability/OblivionBadge.java new file mode 100644 index 00000000..dca134d8 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/badges/ability/OblivionBadge.java @@ -0,0 +1,9 @@ +package it.hurts.sskirillss.relics.badges.ability; + +import it.hurts.sskirillss.relics.badges.base.AbilityBadge; + +public class OblivionBadge extends AbilityBadge { + public OblivionBadge() { + super("oblivion"); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/badges/ability/SilenceBadge.java b/src/main/java/it/hurts/sskirillss/relics/badges/ability/SilenceBadge.java new file mode 100644 index 00000000..325747db --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/badges/ability/SilenceBadge.java @@ -0,0 +1,20 @@ +package it.hurts.sskirillss.relics.badges.ability; + +import it.hurts.sskirillss.relics.badges.base.AbilityBadge; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; +import net.minecraft.world.item.ItemStack; + +public class SilenceBadge extends AbilityBadge { + public SilenceBadge() { + super("silence"); + } + + @Override + public boolean isVisible(ItemStack stack, String ability) { + if (!(stack.getItem() instanceof IRelicItem relic)) + return false; + + return relic.getAbilityCastData(ability).getType() != CastType.NONE; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/badges/ability/ToggleableBadge.java b/src/main/java/it/hurts/sskirillss/relics/badges/ability/ToggleableBadge.java new file mode 100644 index 00000000..820fb9d6 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/badges/ability/ToggleableBadge.java @@ -0,0 +1,10 @@ +package it.hurts.sskirillss.relics.badges.ability; + +import it.hurts.sskirillss.relics.badges.ability.base.CastTypeBadge; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; + +public class ToggleableBadge extends CastTypeBadge { + public ToggleableBadge() { + super(CastType.TOGGLEABLE); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/badges/ability/base/CastTypeBadge.java b/src/main/java/it/hurts/sskirillss/relics/badges/ability/base/CastTypeBadge.java new file mode 100644 index 00000000..82c50b84 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/badges/ability/base/CastTypeBadge.java @@ -0,0 +1,38 @@ +package it.hurts.sskirillss.relics.badges.ability.base; + +import it.hurts.sskirillss.relics.badges.base.AbilityBadge; +import it.hurts.sskirillss.relics.init.HotkeyRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; +import lombok.Getter; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.item.ItemStack; + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +public class CastTypeBadge extends AbilityBadge { + @Getter + private final CastType type; + + public CastTypeBadge(CastType type) { + super(type.name().toLowerCase(Locale.ROOT)); + + this.type = type; + } + + @Override + public List getHint(ItemStack stack, String ability) { + return Arrays.asList(Component.translatable("tooltip.relics.researching.badge.ability.cast_type.hint", HotkeyRegistry.ACTIVE_ABILITIES_LIST.getKey().getDisplayName())); + } + + @Override + public boolean isVisible(ItemStack stack, String ability) { + if (!(stack.getItem() instanceof IRelicItem relic)) + return false; + + return relic.getAbilityCastData(ability).getType() == type; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/badges/base/AbilityBadge.java b/src/main/java/it/hurts/sskirillss/relics/badges/base/AbilityBadge.java new file mode 100644 index 00000000..f7df7fa2 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/badges/base/AbilityBadge.java @@ -0,0 +1,43 @@ +package it.hurts.sskirillss.relics.badges.base; + +import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public abstract non-sealed class AbilityBadge extends AbstractBadge { + public AbilityBadge(String id) { + super(id); + } + + public MutableComponent getTitle(ItemStack stack, String ability) { + return Component.translatable("tooltip.relics.researching.badge.ability." + getId() + ".title"); + } + + public List getDescription(ItemStack stack, String ability) { + return Arrays.asList(Component.translatable("tooltip.relics.researching.badge.ability." + getId() + ".description")); + } + + public List getHint(ItemStack stack, String ability) { + return new ArrayList<>(); + } + + public boolean isVisible(ItemStack stack, String ability) { + return false; + } + + @Override + public final ResourceLocation getIconTexture() { + return ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/badges/ability/" + getId() + ".png"); + } + + @Override + public final ResourceLocation getOutlineTexture() { + return ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/badges/ability/" + getId() + "_outline.png"); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/badges/base/AbstractBadge.java b/src/main/java/it/hurts/sskirillss/relics/badges/base/AbstractBadge.java new file mode 100644 index 00000000..bfbc44b5 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/badges/base/AbstractBadge.java @@ -0,0 +1,15 @@ +package it.hurts.sskirillss.relics.badges.base; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.minecraft.resources.ResourceLocation; + +@AllArgsConstructor +public abstract sealed class AbstractBadge permits AbilityBadge, RelicBadge { + @Getter + private final String id; + + public abstract ResourceLocation getIconTexture(); + + public abstract ResourceLocation getOutlineTexture(); +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/badges/base/RelicBadge.java b/src/main/java/it/hurts/sskirillss/relics/badges/base/RelicBadge.java new file mode 100644 index 00000000..9ceeb189 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/badges/base/RelicBadge.java @@ -0,0 +1,43 @@ +package it.hurts.sskirillss.relics.badges.base; + +import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public abstract non-sealed class RelicBadge extends AbstractBadge { + public RelicBadge(String id) { + super(id); + } + + public MutableComponent getTitle(ItemStack stack) { + return Component.translatable("tooltip.relics.researching.badge.relic." + getId() + ".title"); + } + + public List getDescription(ItemStack stack) { + return Arrays.asList(Component.translatable("tooltip.relics.researching.badge.relic." + getId() + ".description")); + } + + public List getHint(ItemStack stack) { + return new ArrayList<>(); + } + + public boolean isVisible(ItemStack stack) { + return false; + } + + @Override + public final ResourceLocation getIconTexture() { + return ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/badges/relic/" + getId() + ".png"); + } + + @Override + public final ResourceLocation getOutlineTexture() { + return ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/badges/relic/" + getId() + "_outline.png"); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/badges/relic/FlawlessRelicBadge.java b/src/main/java/it/hurts/sskirillss/relics/badges/relic/FlawlessRelicBadge.java new file mode 100644 index 00000000..c956e5f4 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/badges/relic/FlawlessRelicBadge.java @@ -0,0 +1,19 @@ +package it.hurts.sskirillss.relics.badges.relic; + +import it.hurts.sskirillss.relics.badges.base.RelicBadge; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import net.minecraft.world.item.ItemStack; + +public class FlawlessRelicBadge extends RelicBadge { + public FlawlessRelicBadge() { + super("flawless_relic"); + } + + @Override + public boolean isVisible(ItemStack stack) { + if (!(stack.getItem() instanceof IRelicItem relic)) + return false; + + return relic.isRelicFlawless(stack); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/blocks/PhantomBlock.java b/src/main/java/it/hurts/sskirillss/relics/blocks/PhantomBlock.java new file mode 100644 index 00000000..809ae554 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/blocks/PhantomBlock.java @@ -0,0 +1,119 @@ +package it.hurts.sskirillss.relics.blocks; + +import it.hurts.sskirillss.relics.init.ItemRegistry; +import it.hurts.sskirillss.relics.items.relics.feet.PhantomBootItem; +import it.hurts.sskirillss.relics.utils.EntityUtils; +import it.hurts.sskirillss.relics.utils.MathUtils; +import it.hurts.sskirillss.relics.utils.ParticleUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.EntityCollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; + +import java.awt.*; + +public class PhantomBlock extends Block { + public PhantomBlock() { + super(BlockBehaviour.Properties.of() + .friction(0.98F) + .sound(SoundType.WOOL) + .dynamicShape() + .noOcclusion() + .instabreak() + ); + } + + @Override + public void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { + level.scheduleTick(pos, this, Mth.nextInt(level.getRandom(), 80, 120)); + } + + @Override + protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + level.setBlockAndUpdate(pos, Blocks.AIR.defaultBlockState()); + + level.playSound(null, pos, SoundEvents.CANDLE_EXTINGUISH, SoundSource.MASTER, 1F, 2F); + + level.sendParticles(ParticleUtils.constructSimpleSpark(new Color(100 + random.nextInt(100), 0, 200 + random.nextInt(50)), 0.1F + random.nextFloat() * 0.2F, 40, 0.9F), + pos.getX() + 0.5F, pos.getY() + 0.5F, pos.getZ() + 0.5F, 25, 0.5F, 0.5F, 0.5F, 0.05F); + } + + @Override + public void fallOn(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance) { + entity.causeFallDamage(fallDistance, 0F, level.damageSources().fall()); + + level.playSound(null, pos, SoundEvents.PHANTOM_FLAP, SoundSource.MASTER, 1F, 2F); + + var random = level.getRandom(); + + var speed = Math.abs(entity.getDeltaMovement().y()); + + for (int i = 0; i < speed * 75; i++) + level.addParticle(ParticleUtils.constructSimpleSpark(new Color(100 + random.nextInt(100), 0, 200 + random.nextInt(50)), 0.1F + random.nextFloat() * 0.2F, 40 + random.nextInt(40), 0.95F), + entity.getX() + MathUtils.randomFloat(random) * speed, entity.getY(), entity.getZ() + MathUtils.randomFloat(random) * speed, 0F, 0.05F + (speed * random.nextFloat() * 0.25F), 0F); + } + + @Override + public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) { + if (!level.isClientSide()) + return; + + var random = level.getRandom(); + + var motion = entity.getDeltaMovement(); + + var speed = motion.multiply(1F, 0F, 1F).length(); + + var width = entity.getBbWidth(); + + for (float i = 0; i < speed; i += 0.05F) + level.addParticle(ParticleUtils.constructSimpleSpark(new Color(100 + random.nextInt(100), 0, 200 + random.nextInt(50)), 0.2F + random.nextFloat() * 0.25F, 10 + random.nextInt(20), 0.9F), + entity.getX() + MathUtils.randomFloat(random) * width, entity.getY(), entity.getZ() + MathUtils.randomFloat(random) * width, -motion.x(), 0F, -motion.z()); + } + + @Override + public void updateEntityAfterFallOn(BlockGetter level, Entity entity) { + Vec3 motion = entity.getDeltaMovement(); + + if (motion.y > -0.5D) { + super.updateEntityAfterFallOn(level, entity); + + return; + } + + entity.setDeltaMovement(motion.x, -motion.y, motion.z); + } + + @Override + public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { + if (context instanceof EntityCollisionContext entityContext) { + var entity = entityContext.getEntity(); + + var stack = EntityUtils.findEquippedCurio(entity, ItemRegistry.PHANTOM_BOOT.get()); + + if (!stack.isEmpty() && stack.getItem() instanceof PhantomBootItem relic && relic.isToggled(stack)) { + var shape = Shapes.block(); + + if (entityContext.isAbove(shape, pos, true)) + return shape; + } + } + + return Shapes.empty(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/blocks/ResearchingTableBlock.java b/src/main/java/it/hurts/sskirillss/relics/blocks/ResearchingTableBlock.java index d9cd1b88..54fa458f 100644 --- a/src/main/java/it/hurts/sskirillss/relics/blocks/ResearchingTableBlock.java +++ b/src/main/java/it/hurts/sskirillss/relics/blocks/ResearchingTableBlock.java @@ -1,15 +1,11 @@ package it.hurts.sskirillss.relics.blocks; -import it.hurts.sskirillss.relics.client.screen.description.RelicDescriptionScreen; +import com.mojang.serialization.MapCodec; import it.hurts.sskirillss.relics.init.TileRegistry; -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; import it.hurts.sskirillss.relics.tiles.ResearchingTableTile; import it.hurts.sskirillss.relics.utils.TickerUtils; -import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; -import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.item.ItemEntity; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.BlockGetter; @@ -17,29 +13,20 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.HorizontalDirectionalBlock; -import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.event.entity.player.PlayerInteractEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class ResearchingTableBlock extends HorizontalDirectionalBlock implements EntityBlock { - public ResearchingTableBlock() { - super(Properties.of() - .lightLevel((s) -> 15) - .strength(1.5F) - .sound(SoundType.WOOD) - .noOcclusion()); + public ResearchingTableBlock(BlockBehaviour.Properties properties) { + super(properties); } @Override @@ -54,11 +41,6 @@ public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState n super.onRemove(state, worldIn, pos, newState, isMoving); } - @OnlyIn(Dist.CLIENT) - public static void openGui(BlockPos pos) { - Minecraft.getInstance().setScreen(new RelicDescriptionScreen(pos)); - } - @Override public VoxelShape getShape(BlockState state, BlockGetter reader, BlockPos pos, CollisionContext context) { return Block.box(0, 0, 0, 16, 15, 16); @@ -89,52 +71,8 @@ public BlockState getStateForPlacement(BlockPlaceContext context) { return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite()); } - @Mod.EventBusSubscriber - public static class Events { - @SubscribeEvent - public static void onBlockRightClick(PlayerInteractEvent.RightClickBlock event) { - InteractionHand hand = event.getHand(); - - if (hand != InteractionHand.MAIN_HAND) - return; - - Level level = event.getLevel(); - BlockPos pos = event.getPos(); - - if (!(level.getBlockEntity(pos) instanceof ResearchingTableTile tile)) - return; - - Player player = event.getEntity(); - - ItemStack handStack = player.getMainHandItem(); - ItemStack tileStack = tile.getStack(); - - BlockState oldState = level.getBlockState(pos); - - if (tileStack.isEmpty()) { - if (!(handStack.getItem() instanceof IRelicItem)) - return; - - tile.setStack(handStack.split(1)); - } else { - if (player.isShiftKeyDown()) { - if (!(tileStack.getItem() instanceof IRelicItem relic)) - return; - - relic.setItemResearched(player, true); - - if (level.isClientSide()) - openGui(pos); - } else { - level.addFreshEntity(new ItemEntity(level, player.getX(), player.getY(), player.getZ(), tileStack)); - - tile.setStack(ItemStack.EMPTY); - } - } - - tile.setChanged(); - - level.sendBlockUpdated(pos, oldState, level.getBlockState(pos), 3); - } + @Override + protected MapCodec codec() { + return simpleCodec(ResearchingTableBlock::new); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/capability/entries/IRelicsCapability.java b/src/main/java/it/hurts/sskirillss/relics/capability/entries/IRelicsCapability.java deleted file mode 100644 index efca60ba..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/capability/entries/IRelicsCapability.java +++ /dev/null @@ -1,56 +0,0 @@ -package it.hurts.sskirillss.relics.capability.entries; - -import it.hurts.sskirillss.relics.init.CapabilityRegistry; -import lombok.Getter; -import lombok.Setter; -import net.minecraft.core.Direction; -import net.minecraft.nbt.CompoundTag; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.ICapabilityProvider; -import net.minecraftforge.common.util.INBTSerializable; -import net.minecraftforge.common.util.LazyOptional; - -public interface IRelicsCapability extends INBTSerializable { - CompoundTag getResearchData(); - - void setResearchData(CompoundTag data); - - class RelicsCapability implements IRelicsCapability { - @Getter - @Setter - private CompoundTag researchData = new CompoundTag(); - - @Override - public CompoundTag serializeNBT() { - final CompoundTag tag = new CompoundTag(); - - tag.put("researchData", this.researchData); - - return tag; - } - - @Override - public void deserializeNBT(CompoundTag nbt) { - this.researchData = nbt.getCompound("researchData"); - } - } - - class RelicsCapabilityProvider implements ICapabilityProvider, INBTSerializable { - private final IRelicsCapability backend = new IRelicsCapability.RelicsCapability(); - - @Override - public LazyOptional getCapability(Capability cap, Direction side) { - return CapabilityRegistry.DATA.orEmpty(cap, LazyOptional.of(() -> backend)); - } - - @Override - public CompoundTag serializeNBT() { - return this.backend.serializeNBT(); - } - - @Override - public void deserializeNBT(CompoundTag nbt) { - this.backend.deserializeNBT(nbt); - } - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/capability/handlers/SyncHandler.java b/src/main/java/it/hurts/sskirillss/relics/capability/handlers/SyncHandler.java deleted file mode 100644 index d5f479e1..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/capability/handlers/SyncHandler.java +++ /dev/null @@ -1,47 +0,0 @@ -package it.hurts.sskirillss.relics.capability.handlers; - -import it.hurts.sskirillss.relics.capability.utils.CapabilityUtils; -import it.hurts.sskirillss.relics.network.NetworkHandler; -import it.hurts.sskirillss.relics.network.packets.capability.CapabilitySyncPacket; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; -import net.minecraftforge.event.entity.player.PlayerEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; - -@Mod.EventBusSubscriber -public class SyncHandler { - @SubscribeEvent - public static void onPlayerRespawn(PlayerEvent.PlayerRespawnEvent event) { - Player player = event.getEntity(); - Level level = player.getCommandSenderWorld(); - - if (level.isClientSide()) - return; - - NetworkHandler.sendToClient(new CapabilitySyncPacket(CapabilityUtils.getRelicsCapability(player).serializeNBT()), (ServerPlayer) player); - } - - @SubscribeEvent - public static void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) { - Player player = event.getEntity(); - Level level = player.getCommandSenderWorld(); - - if (level.isClientSide()) - return; - - NetworkHandler.sendToClient(new CapabilitySyncPacket(CapabilityUtils.getRelicsCapability(player).serializeNBT()), (ServerPlayer) player); - } - - @SubscribeEvent - public static void onDimensionChange(PlayerEvent.PlayerChangedDimensionEvent event) { - Player player = event.getEntity(); - Level level = player.getCommandSenderWorld(); - - if (level.isClientSide()) - return; - - NetworkHandler.sendToClient(new CapabilitySyncPacket(CapabilityUtils.getRelicsCapability(player).serializeNBT()), (ServerPlayer) player); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/capability/utils/CapabilityUtils.java b/src/main/java/it/hurts/sskirillss/relics/capability/utils/CapabilityUtils.java deleted file mode 100644 index 76ca7f3a..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/capability/utils/CapabilityUtils.java +++ /dev/null @@ -1,11 +0,0 @@ -package it.hurts.sskirillss.relics.capability.utils; - -import it.hurts.sskirillss.relics.capability.entries.IRelicsCapability; -import it.hurts.sskirillss.relics.init.CapabilityRegistry; -import net.minecraft.world.entity.player.Player; - -public class CapabilityUtils { - public static IRelicsCapability getRelicsCapability(Player player) { - return player.getCapability(CapabilityRegistry.DATA).orElse(null); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/gui/layers/ActiveAbilitiesLayer.java b/src/main/java/it/hurts/sskirillss/relics/client/gui/layers/ActiveAbilitiesLayer.java new file mode 100644 index 00000000..855e2a3b --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/gui/layers/ActiveAbilitiesLayer.java @@ -0,0 +1,13 @@ +package it.hurts.sskirillss.relics.client.gui.layers; + +import it.hurts.sskirillss.relics.system.casts.handlers.HUDRenderHandler; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.LayeredDraw; + +public class ActiveAbilitiesLayer implements LayeredDraw.Layer { + @Override + public void render(GuiGraphics guiGraphics, DeltaTracker deltaTracker) { + HUDRenderHandler.render(guiGraphics, deltaTracker.getGameTimeDeltaPartialTick(true)); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/gui/layers/InfoTileLayer.java b/src/main/java/it/hurts/sskirillss/relics/client/gui/layers/InfoTileLayer.java new file mode 100644 index 00000000..e98a3d68 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/gui/layers/InfoTileLayer.java @@ -0,0 +1,37 @@ +package it.hurts.sskirillss.relics.client.gui.layers; + +import it.hurts.sskirillss.relics.tiles.base.IHasHUDInfo; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.LayeredDraw; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; + +public class InfoTileLayer implements LayeredDraw.Layer { + @Override + public void render(GuiGraphics guiGraphics, DeltaTracker deltaTracker) { + Minecraft MC = Minecraft.getInstance(); + + ClientLevel level = MC.level; + + if (level == null) + return; + + HitResult hit = MC.hitResult; + + if (hit == null || hit.getType() != HitResult.Type.BLOCK) + return; + + BlockPos pos = ((BlockHitResult) MC.hitResult).getBlockPos(); + BlockEntity tile = level.getBlockEntity(pos); + + if (!(tile instanceof IHasHUDInfo infoTile)) + return; + + infoTile.renderHUDInfo(guiGraphics.pose(), MC.getWindow()); + } +} diff --git a/src/main/java/it/hurts/sskirillss/relics/client/gui/layers/LeafyRingHideLayer.java b/src/main/java/it/hurts/sskirillss/relics/client/gui/layers/LeafyRingHideLayer.java new file mode 100644 index 00000000..1d5e213e --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/gui/layers/LeafyRingHideLayer.java @@ -0,0 +1,115 @@ +package it.hurts.sskirillss.relics.client.gui.layers; + +import com.mojang.blaze3d.systems.RenderSystem; +import it.hurts.sskirillss.relics.init.ItemRegistry; +import it.hurts.sskirillss.relics.items.relics.ring.LeafyRingItem; +import it.hurts.sskirillss.relics.utils.Easing; +import it.hurts.sskirillss.relics.utils.EntityUtils; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import it.hurts.sskirillss.relics.utils.data.SpriteMirror; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.LayeredDraw; +import net.minecraft.client.renderer.BiomeColors; +import net.minecraft.resources.ResourceLocation; + +import java.awt.*; + +public class LeafyRingHideLayer implements LayeredDraw.Layer { + private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/hud/leafy_ring_hide.png"); + private static final ResourceLocation VIGNETTE = ResourceLocation.withDefaultNamespace("textures/misc/vignette.png"); + + @Override + public void render(GuiGraphics guiGraphics, DeltaTracker deltaTracker) { + var MC = Minecraft.getInstance(); + var player = MC.player; + + if (player == null) + return; + + var stack = EntityUtils.findEquippedCurio(player, ItemRegistry.LEAFY_RING.get()); + + if (!(stack.getItem() instanceof LeafyRingItem relic)) + return; + + var progress = relic.getCurrentProgress(stack); + + if (progress <= 0) + return; + + var maxProgress = relic.getMaxProgress(); + var partialTick = deltaTracker.getGameTimeDeltaPartialTick(false); + + var progressRatio = Easing.easeOutQuad(Math.min(1F, (progress + (partialTick * (relic.isHiding(stack) ? 1 : -1))) / maxProgress)); + + var poseStack = guiGraphics.pose(); + + poseStack.pushPose(); + + var window = MC.getWindow(); + var width = window.getGuiScaledWidth(); + var height = window.getGuiScaledHeight(); + + var texWidth = 89; + var texHeight = 62; + + var alpha = progressRatio * 0.75F; + + var offsetX = texWidth * (1 - progressRatio); + var offsetY = texHeight * (1 - progressRatio); + + var color = new Color(BiomeColors.getAverageGrassColor(player.level(), player.blockPosition())).brighter(); + + RenderSystem.enableBlend(); + + GUIRenderer.begin(VIGNETTE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .patternSize(width, height) + .texSize(width, height) + .color(color) + .alpha(alpha * 0.25F) + .end(); + + GUIRenderer.begin(TEXTURE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(-offsetX, -offsetY) + .color(color) + .alpha(alpha) + .scale(2) + .end(); + + GUIRenderer.begin(TEXTURE, poseStack) + .pos(width + offsetX, -offsetY) + .mirror(SpriteMirror.HORIZONTAL) + .anchor(SpriteAnchor.TOP_RIGHT) + .color(color) + .alpha(alpha) + .scale(2) + .end(); + + GUIRenderer.begin(TEXTURE, poseStack) + .pos(-offsetX, height + offsetY) + .anchor(SpriteAnchor.BOTTOM_LEFT) + .mirror(SpriteMirror.VERTICAL) + .color(color) + .alpha(alpha) + .scale(2) + .end(); + + GUIRenderer.begin(TEXTURE, poseStack) + .pos(width + offsetX, height + offsetY) + .mirror(SpriteMirror.HORIZONTAL, SpriteMirror.VERTICAL) + .anchor(SpriteAnchor.BOTTOM_RIGHT) + .color(color) + .alpha(alpha) + .scale(2) + .end(); + + RenderSystem.disableBlend(); + + poseStack.popPose(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/gui/layers/PhantomBootBridgeLayer.java b/src/main/java/it/hurts/sskirillss/relics/client/gui/layers/PhantomBootBridgeLayer.java new file mode 100644 index 00000000..4e24e0fa --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/gui/layers/PhantomBootBridgeLayer.java @@ -0,0 +1,74 @@ +package it.hurts.sskirillss.relics.client.gui.layers; + +import com.mojang.blaze3d.systems.RenderSystem; +import it.hurts.sskirillss.relics.init.ItemRegistry; +import it.hurts.sskirillss.relics.items.relics.feet.PhantomBootItem; +import it.hurts.sskirillss.relics.items.relics.ring.LeafyRingItem; +import it.hurts.sskirillss.relics.utils.Easing; +import it.hurts.sskirillss.relics.utils.EntityUtils; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import it.hurts.sskirillss.relics.utils.data.SpriteMirror; +import net.minecraft.client.DeltaTracker; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.LayeredDraw; +import net.minecraft.client.renderer.BiomeColors; +import net.minecraft.resources.ResourceLocation; + +import java.awt.*; + +public class PhantomBootBridgeLayer implements LayeredDraw.Layer { + private static final ResourceLocation VIGNETTE = ResourceLocation.withDefaultNamespace("textures/misc/vignette.png"); + + @Override + public void render(GuiGraphics guiGraphics, DeltaTracker deltaTracker) { + var MC = Minecraft.getInstance(); + var player = MC.player; + + if (player == null) + return; + + var stack = EntityUtils.findEquippedCurio(player, ItemRegistry.PHANTOM_BOOT.get()); + + if (!(stack.getItem() instanceof PhantomBootItem relic)) + return; + + var progress = relic.getTime(stack); + + if (progress <= 0) + return; + + var maxProgress = relic.getMaxTime(stack); + + var partialTick = deltaTracker.getGameTimeDeltaPartialTick(false); + + var progressRatio = Math.min(1F, (progress + (partialTick * (relic.isToggled(stack) ? 1 : -1))) / maxProgress); + + var poseStack = guiGraphics.pose(); + + poseStack.pushPose(); + + var window = MC.getWindow(); + + var width = window.getGuiScaledWidth(); + var height = window.getGuiScaledHeight(); + + var alpha = progressRatio * 0.5F; + + RenderSystem.enableBlend(); + + GUIRenderer.begin(VIGNETTE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .patternSize(width, height) + .texSize(width, height) + .color(0xb632bf) + .alpha(alpha) + .end(); + + RenderSystem.disableBlend(); + + poseStack.popPose(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/handlers/ArmorRenderHandler.java b/src/main/java/it/hurts/sskirillss/relics/client/handlers/ArmorRenderHandler.java index 38464fad..bd911ad6 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/handlers/ArmorRenderHandler.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/handlers/ArmorRenderHandler.java @@ -8,21 +8,21 @@ import net.minecraft.core.NonNullList; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.RenderPlayerEvent; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.eventbus.api.EventPriority; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.ModList; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.EventPriority; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.ModList; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RenderPlayerEvent; import org.jetbrains.annotations.NotNull; import top.theillusivec4.curios.api.CuriosApi; import top.theillusivec4.curios.api.type.capability.ICuriosItemHandler; import java.util.ArrayDeque; import java.util.Deque; +import java.util.Optional; -@Mod.EventBusSubscriber(modid = Reference.MODID, value = Dist.CLIENT) +@EventBusSubscriber(modid = Reference.MODID, value = Dist.CLIENT) public class ArmorRenderHandler { private static final LoadingCache> cache = CacheBuilder.newBuilder().weakKeys().build(new CacheLoader>() { @Override @@ -88,7 +88,7 @@ private static boolean haveBoot(Player player) { if (ModList.get().isLoaded("cosmeticarmorreworked")) return false; - LazyOptional helper = CuriosApi.getCuriosHelper().getCuriosHandler(player); + Optional helper = CuriosApi.getCuriosHelper().getCuriosHandler(player); return helper.map(curios -> curios.getStacksHandler("feet").map(handler -> { for (int i = 0; i < handler.getSlots(); i++) { diff --git a/src/main/java/it/hurts/sskirillss/relics/client/handlers/DescriptionHandler.java b/src/main/java/it/hurts/sskirillss/relics/client/handlers/DescriptionHandler.java new file mode 100644 index 00000000..9e9469e5 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/handlers/DescriptionHandler.java @@ -0,0 +1,152 @@ +package it.hurts.sskirillss.relics.client.handlers; + +import com.mojang.blaze3d.platform.InputConstants; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.init.HotkeyRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import net.minecraft.network.chat.TextColor; +import net.minecraft.util.Mth; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.Slot; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.player.ItemTooltipEvent; +import net.neoforged.neoforge.event.tick.PlayerTickEvent; + +@EventBusSubscriber(value = Dist.CLIENT) +public class DescriptionHandler { + private static final int REQUIRED_TIME = 20; + + private static int ticksCountOld; + private static int ticksCount; + + private static Slot slot; + + private static int width = 200; + + @SubscribeEvent + public static void onPlayerTick(PlayerTickEvent.Post event) { + if (!(event.getEntity() instanceof LocalPlayer player)) + return; + + ticksCountOld = ticksCount; + + var MC = Minecraft.getInstance(); + + var isResearching = InputConstants.isKeyDown(MC.getWindow().getWindow(), HotkeyRegistry.RESEARCH_RELIC.getKey().getValue()); + + if (ticksCount > 0 && !isResearching) + ticksCount--; + + if (!(MC.screen instanceof AbstractContainerScreen screen)) + return; + + var window = MC.getWindow(); + + var mouseX = MC.mouseHandler.xpos() * window.getGuiScaledWidth() / window.getScreenWidth(); + var mouseY = MC.mouseHandler.ypos() * window.getGuiScaledHeight() / window.getScreenHeight(); + + var menu = player.containerMenu; + + var oldId = slot == null ? -1 : slot.getContainerSlot(); + var id = -1; + + for (int i = 0; i < menu.slots.size(); i++) { + var entry = menu.slots.get(i); + + if (isHovering(screen.getGuiLeft(), screen.getGuiTop(), entry.x, entry.y, mouseX, mouseY)) { + slot = entry; + id = i; + + break; + } + } + + if (slot == null || id == -1) { + ticksCount = 0; + ticksCountOld = 0; + + return; + } + + var stack = slot.getItem(); + + if (slot.getContainerSlot() != oldId) { + ticksCount = 0; + ticksCountOld = 0; + } + + if (!(stack.getItem() instanceof IRelicItem relic) || !isResearching) + return; + + ticksCount++; + + if (ticksCountOld >= REQUIRED_TIME) { + DescriptionUtils.openCachedScreen(relic, player, id, screen); + + ticksCount = 0; + ticksCountOld = 0; + } + } + + protected static boolean isHovering(int leftPos, int topPos, int slotX, int slotY, double mouseX, double mouseY) { + mouseX -= leftPos; + mouseY -= topPos; + + return mouseX >= (slotX - 1) && mouseX < (slotX + 16 + 1) && mouseY >= (slotY - 1) && mouseY < (slotY + 16 + 1); + } + + @SubscribeEvent + public static void onItemTooltip(ItemTooltipEvent event) { + if (!(event.getItemStack().getItem() instanceof IRelicItem)) + return; + + var filler = "|"; + + event.getToolTip().add(drawProgressBar(filler.repeat(width / Minecraft.getInstance().font.width(filler)))); + } + + public static MutableComponent drawProgressBar(String style) { + var string = new StringBuilder(style); + var percentage = Mth.lerp(Minecraft.getInstance().getTimer().getGameTimeDeltaPartialTick(true), ticksCountOld, ticksCount) / REQUIRED_TIME; + var offset = (int) Math.min(string.length(), Math.floor(string.length() * percentage)); + + var component = Component.literal(""); + var start = string.substring(0, offset); + + var startColor = 0x180133; + var endColor = 0x2c0863; + + for (int i = 0; i < offset; i++) { + var fraction = (float) i / (offset - 1); + + var r = (int) ((1 - fraction) * ((startColor >> 16) & 0xFF) + fraction * ((endColor >> 16) & 0xFF)); + var g = (int) ((1 - fraction) * ((startColor >> 8) & 0xFF) + fraction * ((endColor >> 8) & 0xFF)); + var b = (int) ((1 - fraction) * (startColor & 0xFF) + fraction * (endColor & 0xFF)); + + var color = (r << 16) | (g << 8) | b; + + component.append(Component.literal(String.valueOf(start.charAt(i))).setStyle(Style.EMPTY.withColor(TextColor.fromRgb(color)))); + } + + component.append(Component.literal(string.substring(offset)).setStyle(Style.EMPTY.withColor(ChatFormatting.DARK_GRAY))); + + return component; + } + +// @SubscribeEvent +// public static void onTooltipDisplay(TooltipDisplayEvent event) { +// if (!(event.getStack().getItem() instanceof IRelicItem)) +// return; +// +// width = event.getWidth(); +// } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/handlers/HandRenderHandler.java b/src/main/java/it/hurts/sskirillss/relics/client/handlers/HandRenderHandler.java index 142f7243..85fae0aa 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/handlers/HandRenderHandler.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/handlers/HandRenderHandler.java @@ -12,15 +12,15 @@ import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.world.entity.HumanoidArm; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.RenderArmEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RenderArmEvent; import top.theillusivec4.curios.api.CuriosApi; import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler; import top.theillusivec4.curios.api.type.inventory.IDynamicStackHandler; -@Mod.EventBusSubscriber(modid = Reference.MODID, bus = Mod.EventBusSubscriber.Bus.FORGE, value = Dist.CLIENT) +@EventBusSubscriber(modid = Reference.MODID, bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) public class HandRenderHandler { @SubscribeEvent public static void onRenderHand(RenderArmEvent event) { @@ -60,8 +60,7 @@ public static void onRenderHand(RenderArmEvent event) { poseStack.translate(0.01, -0.7, 0); } - model.renderToBuffer(poseStack, ItemRenderer.getArmorFoilBuffer(event.getMultiBufferSource(), RenderType.armorCutoutNoCull(renderable.getTexture(stack)), false, stack.hasFoil()), - event.getPackedLight(), OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, 1F); + model.renderToBuffer(poseStack, ItemRenderer.getArmorFoilBuffer(event.getMultiBufferSource(), RenderType.armorCutoutNoCull(renderable.getTexture(stack)), stack.hasFoil()), event.getPackedLight(), OverlayTexture.NO_OVERLAY); poseStack.popPose(); } diff --git a/src/main/java/it/hurts/sskirillss/relics/client/models/effects/StunStarModel.java b/src/main/java/it/hurts/sskirillss/relics/client/models/effects/StunStarModel.java index 225e3b1f..bdd31571 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/models/effects/StunStarModel.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/models/effects/StunStarModel.java @@ -12,7 +12,7 @@ import net.minecraft.world.entity.LivingEntity; public class StunStarModel extends HumanoidModel { - public static final ModelLayerLocation TEXTURE = new ModelLayerLocation(new ResourceLocation(Reference.MODID, "textures/mob_effect/effects/stun_star.png"), "star"); + public static final ModelLayerLocation TEXTURE = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/mob_effect/effects/stun_star.png"), "star"); private final ModelPart star; @@ -34,7 +34,7 @@ public static LayerDefinition createBodyLayer() { } @Override - public void renderToBuffer(PoseStack poseStack, VertexConsumer vertexConsumer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) { - star.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); + public void renderToBuffer(PoseStack poseStack, VertexConsumer vertexConsumer, int packedLight, int packedOverlay, int seed) { + star.render(poseStack, vertexConsumer, packedLight, packedOverlay, seed); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/models/entities/DissectionModel.java b/src/main/java/it/hurts/sskirillss/relics/client/models/entities/DissectionModel.java index 63d77526..d9797c78 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/models/entities/DissectionModel.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/models/entities/DissectionModel.java @@ -42,14 +42,14 @@ public void setupAnim(T entity, float limbSwing, float limbSwingAmount, float ag } @Override - public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) { + public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, int seed) { Minecraft MC = Minecraft.getInstance(); LocalPlayer player = Minecraft.getInstance().player; if (player == null) return; - float time = (float) Math.sin((player.tickCount + (MC.isPaused() ? 0 : MC.getFrameTime())) / 20F) * 50F; + float time = (float) Math.sin((player.tickCount + (MC.isPaused() ? 0 : MC.getTimer().getGameTimeDeltaPartialTick(true))) / 20F) * 50F; poseStack.pushPose(); diff --git a/src/main/java/it/hurts/sskirillss/relics/client/models/entities/ShadowGlaiveModel.java b/src/main/java/it/hurts/sskirillss/relics/client/models/entities/ShadowGlaiveModel.java index 3cdca426..df37f4fd 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/models/entities/ShadowGlaiveModel.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/models/entities/ShadowGlaiveModel.java @@ -9,69 +9,36 @@ import net.minecraft.world.entity.Entity; public class ShadowGlaiveModel extends EntityModel { - private final ModelPart bone10; + private final ModelPart bone; public ShadowGlaiveModel() { MeshDefinition meshdefinition = new MeshDefinition(); PartDefinition partdefinition = meshdefinition.getRoot(); - PartDefinition bone10 = partdefinition.addOrReplaceChild("bone10", CubeListBuilder.create(), PartPose.offset(0.0F, 24.0F, 0.0F)); + PartDefinition bone = partdefinition.addOrReplaceChild("bone", CubeListBuilder.create().texOffs(10, 6).addBox(-1.0F, -5.0F, -0.5F, 2.0F, 4.0F, 1.0F, new CubeDeformation(0.0F)) + .texOffs(12, 16).addBox(-1.0F, -6.0F, 0.0F, 2.0F, 1.0F, 0.0F, new CubeDeformation(0.0F)) + .texOffs(0, 6).addBox(-5.0F, -1.0F, -0.5F, 4.0F, 2.0F, 1.0F, new CubeDeformation(0.0F)) + .texOffs(6, 12).addBox(-6.0F, -1.0F, 0.0F, 1.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)) + .texOffs(0, 9).addBox(1.0F, -1.0F, -0.5F, 4.0F, 2.0F, 1.0F, new CubeDeformation(0.0F)) + .texOffs(18, 2).addBox(5.0F, -1.0F, 0.0F, 1.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)) + .texOffs(0, 12).addBox(-1.0F, 1.0F, -0.5F, 2.0F, 4.0F, 1.0F, new CubeDeformation(0.0F)) + .texOffs(16, 12).addBox(-1.0F, 5.0F, 0.0F, 2.0F, 1.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, 16.0F, 0.5F)); - PartDefinition bone11 = bone10.addOrReplaceChild("bone11", CubeListBuilder.create(), PartPose.offset(0.0F, 0.0F, 0.0F)); + bone.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(0, 0).addBox(-2.0F, -2.0F, -1.0F, 4.0F, 4.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.7854F)); - PartDefinition bone = bone11.addOrReplaceChild("bone", CubeListBuilder.create().texOffs(30, 31).mirror().addBox(-4.0032F, -2.0035F, -8.1399F, 8.0F, 4.0F, 2.0F, new CubeDeformation(0.0F)).mirror(false) - .texOffs(26, 19).mirror().addBox(-8.1032F, -2.0035F, -4.0149F, 2.0F, 4.0F, 8.0F, new CubeDeformation(0.0F)).mirror(false) - .texOffs(26, 19).addBox(6.1468F, -2.0035F, -4.0149F, 2.0F, 4.0F, 8.0F, new CubeDeformation(0.0F)) - .texOffs(0, 0).addBox(-8.0032F, -1.5475F, -8.0149F, 16.0F, 1.0F, 16.0F, new CubeDeformation(0.0F)) - .texOffs(0, 0).addBox(-8.0032F, 0.5719F, -8.0149F, 16.0F, 1.0F, 16.0F, new CubeDeformation(0.0F)) - .texOffs(30, 31).mirror().addBox(-4.0032F, -2.0035F, 6.1351F, 8.0F, 4.0F, 2.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offset(0.0032F, -12.9975F, 0.0149F)); + bone.addOrReplaceChild("cube_r2", CubeListBuilder.create().texOffs(0, 17).addBox(-1.0F, -3.0F, 0.0F, 2.0F, 1.0F, 0.0F, new CubeDeformation(0.0F)) + .texOffs(16, 5).addBox(-1.0F, -2.0F, -0.5F, 2.0F, 4.0F, 1.0F, new CubeDeformation(0.005F)), PartPose.offsetAndRotation(-2.6892F, -2.4651F, 0.0F, 0.0F, 0.0F, -0.7854F)); - PartDefinition cube_r1 = bone.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(0, 0).mirror().addBox(6.575F, -1.0F, -3.0F, 2.0F, 4.0F, 6.0F, new CubeDeformation(0.0F)).mirror(false) - .texOffs(0, 0).addBox(-8.5F, -1.0F, -3.0F, 2.0F, 4.0F, 6.0F, new CubeDeformation(0.0F)) - .texOffs(0, 10).addBox(-3.0F, -1.0F, -8.525F, 6.0F, 4.0F, 2.0F, new CubeDeformation(0.0F)) - .texOffs(0, 10).mirror().addBox(-3.0F, -1.0F, 6.625F, 6.0F, 4.0F, 2.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(-0.0032F, -1.0025F, -0.0149F, 0.0F, -0.7854F, 0.0F)); + bone.addOrReplaceChild("cube_r3", CubeListBuilder.create().texOffs(18, 0).addBox(-1.0F, 2.0F, 0.0F, 2.0F, 1.0F, 0.0F, new CubeDeformation(0.0F)) + .texOffs(6, 16).addBox(-1.0F, -2.0F, -0.5F, 2.0F, 4.0F, 1.0F, new CubeDeformation(0.005F)), PartPose.offsetAndRotation(-2.6892F, 2.4651F, 0.0F, 0.0F, 0.0F, 0.7854F)); - PartDefinition bone2 = bone.addOrReplaceChild("bone2", CubeListBuilder.create(), PartPose.offset(-6.3844F, -0.0244F, -2.6145F)); - PartDefinition cube_r2 = bone2.addOrReplaceChild("cube_r2", CubeListBuilder.create().texOffs(2, 41).addBox(-19.0F, 0.7F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(6.3812F, -2.9782F, 2.5996F, 0.1309F, -0.5672F, -0.1745F)); - PartDefinition cube_r3 = bone2.addOrReplaceChild("cube_r3", CubeListBuilder.create().texOffs(0, 17).addBox(-19.0F, 3.0F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(6.3812F, -2.9782F, 2.5996F, 0.0F, -0.5672F, 0.0F)); - PartDefinition cube_r4 = bone2.addOrReplaceChild("cube_r4", CubeListBuilder.create().texOffs(2, 41).addBox(-19.0F, -0.525F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(6.3812F, 2.7718F, 2.5996F, -0.1309F, -0.576F, 0.1745F)); + bone.addOrReplaceChild("cube_r4", CubeListBuilder.create().texOffs(16, 14).addBox(-1.0F, 2.0F, 0.0F, 2.0F, 1.0F, 0.0F, new CubeDeformation(0.0F)) + .texOffs(12, 0).addBox(-1.0F, -2.0F, -0.5F, 2.0F, 4.0F, 1.0F, new CubeDeformation(0.005F)), PartPose.offsetAndRotation(2.6892F, 2.4651F, 0.0F, 0.0F, 0.0F, -0.7854F)); - PartDefinition bone3 = bone.addOrReplaceChild("bone3", CubeListBuilder.create(), PartPose.offset(-2.1095F, -0.0331F, -6.5124F)); - PartDefinition cube_r5 = bone3.addOrReplaceChild("cube_r5", CubeListBuilder.create().texOffs(2, 41).addBox(-18.425F, 2.8F, -6.2F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.1063F, -2.9694F, 6.4976F, 0.1309F, -1.3526F, 0.1091F)); - PartDefinition cube_r6 = bone3.addOrReplaceChild("cube_r6", CubeListBuilder.create().texOffs(0, 17).addBox(-19.0F, 2.999F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.1063F, -2.9694F, 6.4976F, 0.0F, -1.3526F, 0.0F)); - PartDefinition cube_r7 = bone3.addOrReplaceChild("cube_r7", CubeListBuilder.create().texOffs(2, 41).addBox(-18.425F, -2.625F, -6.2F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.1063F, 2.7806F, 6.4976F, -0.1309F, -1.3614F, -0.1091F)); + bone.addOrReplaceChild("cube_r5", CubeListBuilder.create().texOffs(16, 10).addBox(-1.0F, -3.0F, 0.0F, 2.0F, 1.0F, 0.0F, new CubeDeformation(0.0F)) + .texOffs(10, 11).addBox(-1.0F, -2.0F, -0.5F, 2.0F, 4.0F, 1.0F, new CubeDeformation(0.005F)), PartPose.offsetAndRotation(2.6892F, -2.4651F, 0.0F, 0.0F, 0.0F, 0.7854F)); - PartDefinition bone4 = bone.addOrReplaceChild("bone4", CubeListBuilder.create(), PartPose.offset(3.1738F, -0.0294F, -6.8454F)); - PartDefinition cube_r8 = bone4.addOrReplaceChild("cube_r8", CubeListBuilder.create().texOffs(2, 41).addBox(-19.0F, 2.35F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-3.1771F, -2.9731F, 6.8305F, 0.1309F, -2.0944F, 0.0349F)); - PartDefinition cube_r9 = bone4.addOrReplaceChild("cube_r9", CubeListBuilder.create().texOffs(0, 17).addBox(-19.0F, 3.0F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-3.1771F, -2.9731F, 6.8305F, 0.0F, -2.0944F, 0.0F)); - PartDefinition cube_r10 = bone4.addOrReplaceChild("cube_r10", CubeListBuilder.create().texOffs(2, 41).addBox(-19.0F, -2.175F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-3.1771F, 2.7769F, 6.8305F, -0.1309F, -2.1031F, -0.0349F)); - - PartDefinition bone5 = bone.addOrReplaceChild("bone5", CubeListBuilder.create(), PartPose.offset(6.7812F, -0.0283F, -2.1706F)); - PartDefinition cube_r11 = bone5.addOrReplaceChild("cube_r11", CubeListBuilder.create().texOffs(2, 41).addBox(-19.0F, -2.025F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.7844F, 2.7758F, 2.1558F, -0.1309F, -2.9322F, -0.0349F)); - PartDefinition cube_r12 = bone5.addOrReplaceChild("cube_r12", CubeListBuilder.create().texOffs(0, 17).addBox(-19.0F, 2.999F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.7844F, -2.9742F, 2.1558F, 0.0F, -2.8798F, 0.0F)); - PartDefinition cube_r13 = bone5.addOrReplaceChild("cube_r13", CubeListBuilder.create().texOffs(2, 41).addBox(-19.0F, 2.2F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.7844F, -2.9742F, 2.1558F, 0.1309F, -2.9234F, 0.0349F)); - - PartDefinition bone6 = bone.addOrReplaceChild("bone6", CubeListBuilder.create(), PartPose.offset(6.4378F, -0.0272F, 2.6973F)); - PartDefinition cube_r14 = bone6.addOrReplaceChild("cube_r14", CubeListBuilder.create().texOffs(2, 41).addBox(-19.0F, -2.025F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.4411F, 2.7746F, -2.7122F, -0.1309F, 2.5656F, -0.0349F)); - PartDefinition cube_r15 = bone6.addOrReplaceChild("cube_r15", CubeListBuilder.create().texOffs(0, 17).addBox(-19.0F, 3.0F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.4411F, -2.9754F, -2.7122F, 0.0F, 2.5744F, 0.0F)); - PartDefinition cube_r16 = bone6.addOrReplaceChild("cube_r16", CubeListBuilder.create().texOffs(2, 41).addBox(-19.0F, 2.2F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.4411F, -2.9754F, -2.7122F, 0.1309F, 2.5744F, 0.0349F)); - - PartDefinition bone7 = bone.addOrReplaceChild("bone7", CubeListBuilder.create(), PartPose.offset(2.1086F, -0.0305F, 6.8512F)); - PartDefinition cube_r17 = bone7.addOrReplaceChild("cube_r17", CubeListBuilder.create().texOffs(2, 41).addBox(-19.0F, -2.575F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-2.1118F, 2.7779F, -6.8661F, -0.1309F, 1.7802F, 0.0524F)); - PartDefinition cube_r18 = bone7.addOrReplaceChild("cube_r18", CubeListBuilder.create().texOffs(0, 17).addBox(-19.0F, 2.999F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-2.1118F, -2.9721F, -6.8661F, 0.0F, 1.789F, 0.0F)); - PartDefinition cube_r19 = bone7.addOrReplaceChild("cube_r19", CubeListBuilder.create().texOffs(2, 41).addBox(-19.0F, 2.75F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-2.1118F, -2.9721F, -6.8661F, 0.1309F, 1.789F, -0.0524F)); - - PartDefinition bone8 = bone.addOrReplaceChild("bone8", CubeListBuilder.create(), PartPose.offset(-2.9435F, -0.0302F, 6.9542F)); - PartDefinition cube_r20 = bone8.addOrReplaceChild("cube_r20", CubeListBuilder.create().texOffs(2, 41).addBox(-19.0F, -2.025F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.9403F, 2.7776F, -6.9691F, -0.1309F, 1.069F, 0.0524F)); - PartDefinition cube_r21 = bone8.addOrReplaceChild("cube_r21", CubeListBuilder.create().texOffs(0, 17).addBox(-19.0F, 3.0F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.9403F, -2.9724F, -6.9691F, 0.0F, 1.0472F, 0.0F)); - PartDefinition cube_r22 = bone8.addOrReplaceChild("cube_r22", CubeListBuilder.create().texOffs(2, 41).addBox(-19.0F, 2.2F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.9403F, -2.9724F, -6.9691F, 0.1309F, 1.0777F, -0.0524F)); - - PartDefinition bone9 = bone.addOrReplaceChild("bone9", CubeListBuilder.create(), PartPose.offset(-6.1824F, -0.0285F, 2.4184F)); - PartDefinition cube_r23 = bone9.addOrReplaceChild("cube_r23", CubeListBuilder.create().texOffs(2, 41).addBox(-18.3F, -1.425F, -4.775F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(6.1792F, 2.776F, -2.4332F, -0.0524F, 0.1614F, 0.0916F)); - PartDefinition cube_r24 = bone9.addOrReplaceChild("cube_r24", CubeListBuilder.create().texOffs(0, 17).addBox(-19.0F, 2.999F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(6.1792F, -2.974F, -2.4332F, 0.0F, 0.2618F, 0.0F)); - PartDefinition cube_r25 = bone9.addOrReplaceChild("cube_r25", CubeListBuilder.create().texOffs(2, 41).addBox(-18.3F, 1.6F, -4.775F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(6.1792F, -2.974F, -2.4332F, 0.0524F, 0.1702F, -0.0916F)); - - this.bone10 = LayerDefinition.create(meshdefinition, 64, 64).bakeRoot().getChild("bone10"); + this.bone = LayerDefinition.create(meshdefinition, 32, 32).bakeRoot().getChild("bone"); } @Override @@ -80,7 +47,7 @@ public void setupAnim(T entity, float limbSwing, float limbSwingAmount, float ag } @Override - public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) { - bone10.render(poseStack, buffer, packedLight, packedOverlay); + public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, int seed) { + bone.render(poseStack, buffer, packedLight, packedOverlay, seed); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/models/entities/ShadowSawModel.java b/src/main/java/it/hurts/sskirillss/relics/client/models/entities/ShadowSawModel.java deleted file mode 100644 index 38300927..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/client/models/entities/ShadowSawModel.java +++ /dev/null @@ -1,110 +0,0 @@ -package it.hurts.sskirillss.relics.client.models.entities; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import net.minecraft.client.model.EntityModel; -import net.minecraft.client.model.geom.ModelPart; -import net.minecraft.client.model.geom.PartPose; -import net.minecraft.client.model.geom.builders.*; -import net.minecraft.world.entity.Entity; - -public class ShadowSawModel extends EntityModel { - private final ModelPart bone10; - - public ShadowSawModel() { - MeshDefinition meshdefinition = new MeshDefinition(); - PartDefinition partdefinition = meshdefinition.getRoot(); - - PartDefinition bone10 = partdefinition.addOrReplaceChild("bone10", CubeListBuilder.create(), PartPose.offset(0.0F, 24.0F, 0.0F)); - - PartDefinition bone11 = bone10.addOrReplaceChild("bone11", CubeListBuilder.create(), PartPose.offset(0.0F, 0.0F, 0.0F)); - - PartDefinition bone = bone11.addOrReplaceChild("bone", CubeListBuilder.create().texOffs(48, 10).mirror().addBox(-4.0032F, -2.0035F, -8.1399F, 8.0F, 4.0F, 2.0F, new CubeDeformation(0.0F)).mirror(false) - .texOffs(58, 74).mirror().addBox(-8.2282F, -2.0035F, -4.0149F, 2.0F, 4.0F, 8.0F, new CubeDeformation(0.0F)).mirror(false) - .texOffs(58, 74).addBox(6.1468F, -2.0035F, -4.0149F, 2.0F, 4.0F, 8.0F, new CubeDeformation(0.0F)) - .texOffs(0, 0).addBox(-8.0032F, -1.5475F, -8.0149F, 16.0F, 1.0F, 16.0F, new CubeDeformation(0.0F)) - .texOffs(0, 0).addBox(-8.0032F, 0.5719F, -8.0149F, 16.0F, 1.0F, 16.0F, new CubeDeformation(0.0F)) - .texOffs(48, 27).addBox(-4.0032F, -2.0035F, 6.1351F, 8.0F, 4.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0032F, -12.9975F, 0.0149F)); - - PartDefinition cube_r1 = bone.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(0, 17).addBox(6.575F, -1.0F, -3.0F, 2.0F, 4.0F, 6.0F, new CubeDeformation(0.0F)) - .texOffs(0, 0).addBox(-8.6F, -1.0F, -3.0F, 2.0F, 4.0F, 6.0F, new CubeDeformation(0.0F)) - .texOffs(0, 27).addBox(-3.0F, -1.0F, -8.525F, 6.0F, 4.0F, 2.0F, new CubeDeformation(0.0F)) - .texOffs(0, 10).addBox(-3.025F, -1.0F, 6.625F, 6.0F, 4.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-0.0032F, -1.0025F, -0.0149F, 0.0F, -0.7854F, 0.0F)); - - PartDefinition bone2 = bone.addOrReplaceChild("bone2", CubeListBuilder.create(), PartPose.offset(-6.3844F, -0.0244F, -2.6145F)); - - PartDefinition cube_r2 = bone2.addOrReplaceChild("cube_r2", CubeListBuilder.create().texOffs(0, 54).addBox(-18.75F, 1.45F, -6.25F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(6.3812F, -2.9782F, 2.5996F, 0.1309F, -0.5672F, -0.0873F)); - - PartDefinition cube_r3 = bone2.addOrReplaceChild("cube_r3", CubeListBuilder.create().texOffs(0, 74).addBox(-19.0F, 3.0F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(6.3812F, -2.9782F, 2.5996F, 0.0F, -0.5672F, 0.0F)); - - PartDefinition cube_r4 = bone2.addOrReplaceChild("cube_r4", CubeListBuilder.create().texOffs(0, 54).addBox(-19.0F, -0.025F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(6.3812F, 2.7718F, 2.5996F, -0.0436F, -0.576F, 0.1745F)); - - PartDefinition bone3 = bone.addOrReplaceChild("bone3", CubeListBuilder.create(), PartPose.offset(-2.1095F, -0.0331F, -6.5124F)); - - PartDefinition cube_r5 = bone3.addOrReplaceChild("cube_r5", CubeListBuilder.create().texOffs(0, 54).addBox(-18.675F, 2.8F, -6.7F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.1063F, -2.9694F, 6.4976F, 0.1309F, -1.3526F, 0.1091F)); - - PartDefinition cube_r6 = bone3.addOrReplaceChild("cube_r6", CubeListBuilder.create().texOffs(0, 74).addBox(-19.0F, 3.0F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.1063F, -2.9694F, 6.4976F, 0.0F, -1.3526F, 0.0F)); - - PartDefinition cube_r7 = bone3.addOrReplaceChild("cube_r7", CubeListBuilder.create().texOffs(0, 54).addBox(-18.925F, -2.375F, -6.7F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.1063F, 2.7806F, 6.4976F, -0.1309F, -1.3614F, -0.1091F)); - - PartDefinition bone4 = bone.addOrReplaceChild("bone4", CubeListBuilder.create(), PartPose.offset(3.1738F, -0.0294F, -6.8454F)); - - PartDefinition cube_r8 = bone4.addOrReplaceChild("cube_r8", CubeListBuilder.create().texOffs(0, 54).addBox(-18.5F, 2.35F, -6.4F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-3.1771F, -2.9731F, 6.8305F, 0.1309F, -2.0944F, 0.0349F)); - - PartDefinition cube_r9 = bone4.addOrReplaceChild("cube_r9", CubeListBuilder.create().texOffs(0, 74).addBox(-19.0F, 3.0F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-3.1771F, -2.9731F, 6.8305F, 0.0F, -2.0944F, 0.0F)); - - PartDefinition cube_r10 = bone4.addOrReplaceChild("cube_r10", CubeListBuilder.create().texOffs(0, 54).addBox(-18.5F, -2.175F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-3.1771F, 2.7769F, 6.8305F, -0.1309F, -2.1031F, -0.0349F)); - - PartDefinition bone5 = bone.addOrReplaceChild("bone5", CubeListBuilder.create(), PartPose.offset(6.7812F, -0.0283F, -2.1706F)); - - PartDefinition cube_r11 = bone5.addOrReplaceChild("cube_r11", CubeListBuilder.create().texOffs(0, 54).addBox(-19.0F, -2.025F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.7844F, 2.7758F, 2.1558F, -0.1309F, -2.9322F, -0.0349F)); - - PartDefinition cube_r12 = bone5.addOrReplaceChild("cube_r12", CubeListBuilder.create().texOffs(0, 74).addBox(-19.0F, 3.0F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.7844F, -2.9742F, 2.1558F, 0.0F, -2.8798F, 0.0F)); - - PartDefinition cube_r13 = bone5.addOrReplaceChild("cube_r13", CubeListBuilder.create().texOffs(0, 54).addBox(-19.0F, 2.2F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.7844F, -2.9742F, 2.1558F, 0.1309F, -2.9234F, 0.0349F)); - - PartDefinition bone6 = bone.addOrReplaceChild("bone6", CubeListBuilder.create(), PartPose.offset(6.4378F, -0.0272F, 2.6973F)); - - PartDefinition cube_r14 = bone6.addOrReplaceChild("cube_r14", CubeListBuilder.create().texOffs(0, 54).addBox(-19.0F, -2.025F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.4411F, 2.7746F, -2.7122F, -0.1309F, 2.5656F, -0.0349F)); - - PartDefinition cube_r15 = bone6.addOrReplaceChild("cube_r15", CubeListBuilder.create().texOffs(0, 74).addBox(-19.0F, 3.0F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.4411F, -2.9754F, -2.7122F, 0.0F, 2.5744F, 0.0F)); - - PartDefinition cube_r16 = bone6.addOrReplaceChild("cube_r16", CubeListBuilder.create().texOffs(0, 54).addBox(-19.0F, 2.2F, -6.65F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.4411F, -2.9754F, -2.7122F, 0.1309F, 2.5744F, 0.0349F)); - - PartDefinition bone7 = bone.addOrReplaceChild("bone7", CubeListBuilder.create(), PartPose.offset(2.1086F, -0.0305F, 6.8512F)); - - PartDefinition cube_r17 = bone7.addOrReplaceChild("cube_r17", CubeListBuilder.create().texOffs(0, 54).addBox(-19.0F, -2.575F, -6.15F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-2.1118F, 2.7779F, -6.8661F, -0.1309F, 1.7802F, 0.0524F)); - - PartDefinition cube_r18 = bone7.addOrReplaceChild("cube_r18", CubeListBuilder.create().texOffs(0, 74).addBox(-19.0F, 3.0F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-2.1118F, -2.9721F, -6.8661F, 0.0F, 1.789F, 0.0F)); - - PartDefinition cube_r19 = bone7.addOrReplaceChild("cube_r19", CubeListBuilder.create().texOffs(0, 54).addBox(-18.5F, 2.75F, -6.65F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-2.1118F, -2.9721F, -6.8661F, 0.1309F, 1.789F, -0.0524F)); - - PartDefinition bone8 = bone.addOrReplaceChild("bone8", CubeListBuilder.create(), PartPose.offset(-2.9435F, -0.0302F, 6.9542F)); - - PartDefinition cube_r20 = bone8.addOrReplaceChild("cube_r20", CubeListBuilder.create().texOffs(0, 54).addBox(-18.5F, -1.775F, -6.4F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.9403F, 2.7776F, -6.9691F, -0.1309F, 1.069F, 0.0524F)); - - PartDefinition cube_r21 = bone8.addOrReplaceChild("cube_r21", CubeListBuilder.create().texOffs(0, 74).addBox(-19.0F, 3.0F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.9403F, -2.9724F, -6.9691F, 0.0F, 1.0472F, 0.0F)); - - PartDefinition cube_r22 = bone8.addOrReplaceChild("cube_r22", CubeListBuilder.create().texOffs(0, 54).addBox(-18.75F, 1.95F, -6.9F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(2.9403F, -2.9724F, -6.9691F, 0.1309F, 1.0777F, -0.0524F)); - - PartDefinition bone9 = bone.addOrReplaceChild("bone9", CubeListBuilder.create(), PartPose.offset(-6.1824F, -0.0285F, 2.4184F)); - - PartDefinition cube_r23 = bone9.addOrReplaceChild("cube_r23", CubeListBuilder.create().texOffs(0, 54).addBox(-18.3F, -1.175F, -4.775F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(6.1792F, 2.776F, -2.4332F, -0.0524F, 0.1614F, 0.0916F)); - - PartDefinition cube_r24 = bone9.addOrReplaceChild("cube_r24", CubeListBuilder.create().texOffs(0, 74).addBox(-19.0F, 3.0F, -5.75F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(6.1792F, -2.974F, -2.4332F, 0.0F, 0.2618F, 0.0F)); - - PartDefinition cube_r25 = bone9.addOrReplaceChild("cube_r25", CubeListBuilder.create().texOffs(0, 54).addBox(-18.55F, 1.1F, -6.275F, 12.0F, 0.0F, 10.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(6.1792F, -2.974F, -2.4332F, 0.0524F, 0.2574F, -0.0916F)); - - this.bone10 = LayerDefinition.create(meshdefinition, 128, 128).bakeRoot().getChild("bone10"); - } - - @Override - public void setupAnim(T entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) { - - } - - @Override - public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) { - bone10.render(poseStack, buffer, packedLight, packedOverlay); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/models/entities/SolidSnowballModel.java b/src/main/java/it/hurts/sskirillss/relics/client/models/entities/SolidSnowballModel.java index cb96fa62..48f21fd1 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/models/entities/SolidSnowballModel.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/models/entities/SolidSnowballModel.java @@ -32,7 +32,7 @@ public void setupAnim(T entity, float limbSwing, float limbSwingAmount, float ag } @Override - public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) { - snowball.render(poseStack, buffer, packedLight, packedOverlay); + public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, int seed) { + snowball.render(poseStack, buffer, packedLight, packedOverlay, seed); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/models/entities/SporeModel.java b/src/main/java/it/hurts/sskirillss/relics/client/models/entities/SporeModel.java index 00d83687..e0e8af6c 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/models/entities/SporeModel.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/models/entities/SporeModel.java @@ -24,7 +24,6 @@ public SporeModel() { PartDefinition cube_r3 = spore.addOrReplaceChild("cube_r3", CubeListBuilder.create().texOffs(0, 0).addBox(0.0F, -21.0F, -7.0F, 0.0F, 14.0F, 14.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, 14.0F, 0.0F, 0.0F, -1.5708F, 0.0F)); this.spore = LayerDefinition.create(meshdefinition, 64, 64).bakeRoot().getChild("spore"); - ; } @Override @@ -33,7 +32,7 @@ public void setupAnim(T entity, float limbSwing, float limbSwingAmount, float ag } @Override - public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) { - spore.render(poseStack, buffer, packedLight, packedOverlay); + public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, int seed) { + spore.render(poseStack, buffer, packedLight, packedOverlay, seed); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/models/entities/StalactiteModel.java b/src/main/java/it/hurts/sskirillss/relics/client/models/entities/StalactiteModel.java index 1ce7d9ed..131dfe84 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/models/entities/StalactiteModel.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/models/entities/StalactiteModel.java @@ -31,7 +31,7 @@ public void setupAnim(T entity, float limbSwing, float limbSwingAmount, float ag } @Override - public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) { - stone.render(poseStack, buffer, packedLight, packedOverlay); + public void renderToBuffer(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, int seed) { + stone.render(poseStack, buffer, packedLight, packedOverlay, seed); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/models/items/CurioModel.java b/src/main/java/it/hurts/sskirillss/relics/client/models/items/CurioModel.java index 8cb82e26..22afb3d4 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/models/items/CurioModel.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/models/items/CurioModel.java @@ -7,10 +7,10 @@ import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.geom.ModelLayerLocation; import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.Item; -import net.minecraftforge.registries.ForgeRegistries; import javax.annotation.Nonnull; @@ -33,9 +33,9 @@ public CurioModel(Item item) { } public static ModelLayerLocation getLayerLocation(Item item) { - ResourceLocation id = ForgeRegistries.ITEMS.getKey(item); + ResourceLocation id = BuiltInRegistries.ITEM.getKey(item); - return new ModelLayerLocation(new ResourceLocation(id.getNamespace(), id.getPath()), id.getPath()); + return new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(id.getNamespace(), id.getPath()), id.getPath()); } public static ModelPart constructRoot(Item item) { diff --git a/src/main/java/it/hurts/sskirillss/relics/client/models/layers/WingsLayer.java b/src/main/java/it/hurts/sskirillss/relics/client/models/layers/WingsLayer.java new file mode 100644 index 00000000..33b211b2 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/models/layers/WingsLayer.java @@ -0,0 +1,55 @@ +package it.hurts.sskirillss.relics.client.models.layers; + +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.models.parts.HaloModel; +import it.hurts.sskirillss.relics.client.models.parts.WingsModel; +import it.hurts.sskirillss.relics.init.EffectRegistry; +import net.minecraft.client.Minecraft; +import net.minecraft.client.model.EntityModel; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.RenderLayerParent; +import net.minecraft.client.renderer.entity.layers.RenderLayer; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.world.entity.LivingEntity; +import top.theillusivec4.curios.api.client.ICurioRenderer; + +public class WingsLayer> extends RenderLayer { + private final HaloModel haloModel; + private final WingsModel wingsModel; + + public WingsLayer(RenderLayerParent pRenderer) { + super(pRenderer); + + haloModel = new HaloModel(HaloModel.createBodyLayer().bakeRoot()); + wingsModel = new WingsModel(WingsModel.createBodyLayer().bakeRoot()); + } + + @Override + public void render(PoseStack pPoseStack, MultiBufferSource pBuffer, int pPackedLight, T pLivingEntity, float pLimbSwing, float pLimbSwingAmount, float pPartialTicks, float pAgeInTicks, float pNetHeadYaw, float pHeadPitch) { + var player = Minecraft.getInstance().player; + + if (player == null || !player.hasEffect(EffectRegistry.IMMORTALITY)) + return; + + pPoseStack.pushPose(); + + pPoseStack.scale(0.75F, 0.75F, 0.75F); + pPoseStack.translate(0F, Math.sin(pLivingEntity.tickCount * 0.1F) * 0.05F, 0F); + + ICurioRenderer.followBodyRotations(pLivingEntity, haloModel); + + haloModel.renderToBuffer(pPoseStack, pBuffer.getBuffer(RenderType.entityTranslucentCull(HaloModel.LAYER_LOCATION.getModel())), LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY); + + pPoseStack.popPose(); + + pPoseStack.pushPose(); + + ICurioRenderer.followBodyRotations(pLivingEntity, wingsModel); + + wingsModel.renderToBuffer(pPoseStack, pBuffer.getBuffer(RenderType.entityTranslucentCull(WingsModel.LAYER_LOCATION.getModel())), LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY); + + pPoseStack.popPose(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/models/parts/HaloModel.java b/src/main/java/it/hurts/sskirillss/relics/client/models/parts/HaloModel.java new file mode 100644 index 00000000..0725108c --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/models/parts/HaloModel.java @@ -0,0 +1,53 @@ +package it.hurts.sskirillss.relics.client.models.parts; + +import com.google.common.collect.ImmutableList; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.model.geom.builders.*; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.LivingEntity; + +import javax.annotation.Nonnull; + +public class HaloModel extends HumanoidModel { + public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/parts/halo.png"), "halo"); + + public HaloModel(ModelPart root) { + super(root); + } + + public static LayerDefinition createBodyLayer() { + MeshDefinition mesh = HumanoidModel.createMesh(new CubeDeformation(0.4F), 0.0F); + + mesh.getRoot().getChild("head").addOrReplaceChild("halo", CubeListBuilder.create().texOffs(0, 10).addBox(4.0F, -1.0F, -4.0F, 1.0F, 2.0F, 8.0F, new CubeDeformation(0.0F)) + .texOffs(10, 3).addBox(-5.0F, -1.0F, 4.0F, 10.0F, 2.0F, 1.0F, new CubeDeformation(0.0F)) + .texOffs(10, 0).addBox(-5.0F, -1.0F, -5.0F, 10.0F, 2.0F, 1.0F, new CubeDeformation(0.0F)) + .texOffs(0, 0).addBox(-5.0F, -1.0F, -4.0F, 1.0F, 2.0F, 8.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, -15.0F, 0.0F)); + + return LayerDefinition.create(mesh, 32, 32); + } + + @Override + public void renderToBuffer(PoseStack p_102034_, VertexConsumer p_102035_, int p_102036_, int p_102037_, int p_350361_) { + head.skipDraw = true; + + super.renderToBuffer(p_102034_, p_102035_, p_102036_, p_102037_, p_350361_); + } + + @Override + @Nonnull + protected Iterable headParts() { + return ImmutableList.of(this.head); + } + + @Override + @Nonnull + protected Iterable bodyParts() { + return ImmutableList.of(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/models/parts/WingsModel.java b/src/main/java/it/hurts/sskirillss/relics/client/models/parts/WingsModel.java new file mode 100644 index 00000000..30406957 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/models/parts/WingsModel.java @@ -0,0 +1,123 @@ +package it.hurts.sskirillss.relics.client.models.parts; + +import com.google.common.collect.ImmutableList; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.model.geom.builders.*; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.LivingEntity; + +import javax.annotation.Nonnull; + +public class WingsModel extends HumanoidModel { + public static final ModelLayerLocation LAYER_LOCATION = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/parts/wings.png"), "wings"); + + public WingsModel(ModelPart root) { + super(root); + } + + public static LayerDefinition createBodyLayer() { + MeshDefinition mesh = HumanoidModel.createMesh(new CubeDeformation(0.4F), 0.0F); + PartDefinition partdefinition = mesh.getRoot().getChild("body"); + + PartDefinition bone = partdefinition.addOrReplaceChild("wings", CubeListBuilder.create(), PartPose.offset(-13.9643F, 4.2569F, -4.4757F)); + + PartDefinition cube_r1 = bone.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(36, 0).addBox(-9.6586F, -5.283F, -0.2953F, 7.0F, 2.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, -2.0F, 7.0F, -0.0657F, -0.1133F, 0.8328F)); + + PartDefinition cube_r2 = bone.addOrReplaceChild("cube_r2", CubeListBuilder.create().texOffs(36, 4).addBox(-1.1998F, -6.0505F, -0.2962F, 6.0F, 2.0F, 2.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, -2.0F, 7.0F, -0.0172F, -0.1298F, 0.4374F)); + + PartDefinition cube_r3 = bone.addOrReplaceChild("cube_r3", CubeListBuilder.create().texOffs(34, 9).addBox(-4.9428F, -2.4742F, -1.0783F, 8.0F, 2.0F, 2.0F, new CubeDeformation(0.0F)) + .texOffs(35, 35).addBox(-2.755F, -1.5004F, -0.2879F, 5.0F, 10.0F, 1.0F, new CubeDeformation(0.0F)) + .texOffs(36, 25).addBox(-1.69F, -5.4947F, 0.2078F, 4.0F, 4.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(10.8905F, -2.0449F, 8.3029F, 0.0114F, 0.0441F, 0.2194F)); + + PartDefinition cube_r4 = bone.addOrReplaceChild("cube_r4", CubeListBuilder.create().texOffs(0, 0).addBox(-25.2504F, -5.453F, 0.4201F, 18.0F, 11.0F, 0.0F, new CubeDeformation(0.0F)) + .texOffs(0, 15).addBox(-7.2504F, 3.547F, 0.4201F, 9.0F, 14.0F, 0.0F, new CubeDeformation(0.0F)) + .texOffs(0, 11).addBox(-16.6577F, -9.1841F, 0.896F, 17.0F, 4.0F, 0.0F, new CubeDeformation(0.0F)) + .texOffs(18, 15).addBox(-7.2504F, -5.453F, 0.4201F, 9.0F, 9.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, -2.0F, 7.0F, -0.0916F, -0.1687F, 0.7675F)); + + PartDefinition cube_r5 = bone.addOrReplaceChild("cube_r5", CubeListBuilder.create().texOffs(16, 36).addBox(-2.5F, 7.0F, -1.0F, 5.0F, 11.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(10.3486F, -0.6377F, 9.0425F, 0.0114F, 0.0441F, 0.2194F)); + + PartDefinition cube_r6 = bone.addOrReplaceChild("cube_r6", CubeListBuilder.create().texOffs(0, 29).addBox(0.4267F, 4.2147F, 0.9002F, 8.0F, 12.0F, 0.0F, new CubeDeformation(0.0F)) + .texOffs(18, 25).addBox(0.4267F, -5.7853F, 0.9002F, 8.0F, 10.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, -2.0F, 7.0F, 0.0F, -0.053F, 0.4175F)); + + PartDefinition cube_r7 = bone.addOrReplaceChild("cube_r7", CubeListBuilder.create().texOffs(34, 13).addBox(-0.5076F, -7.4805F, 0.9935F, 9.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0F, -2.0F, 6.7F, 0.0F, -0.1402F, 0.4175F)); + + PartDefinition bone2 = partdefinition.addOrReplaceChild("bone2", CubeListBuilder.create(), PartPose.offset(13.9643F, 4.2569F, -4.4757F)); + + PartDefinition cube_r8 = bone2.addOrReplaceChild("cube_r8", CubeListBuilder.create().texOffs(36, 25).mirror().addBox(-2.31F, -5.4947F, 0.2078F, 4.0F, 4.0F, 0.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(-10.8905F, -2.0449F, 8.3029F, 0.0114F, -0.0441F, -0.2194F)); + + PartDefinition bone3 = partdefinition.addOrReplaceChild("bone3", CubeListBuilder.create(), PartPose.offset(13.9643F, 4.2569F, -4.4757F)); + + PartDefinition cube_r9 = bone3.addOrReplaceChild("cube_r9", CubeListBuilder.create().texOffs(18, 15).mirror().addBox(-1.7496F, -5.453F, 0.4201F, 9.0F, 9.0F, 1.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(0.0F, -2.0F, 7.0F, -0.0916F, 0.1687F, -0.7675F)); + + PartDefinition bone4 = partdefinition.addOrReplaceChild("bone4", CubeListBuilder.create(), PartPose.offset(13.9643F, 4.2569F, -4.4757F)); + + PartDefinition cube_r10 = bone4.addOrReplaceChild("cube_r10", CubeListBuilder.create().texOffs(18, 25).mirror().addBox(-8.4267F, -5.7853F, 0.9002F, 8.0F, 10.0F, 1.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(0.0F, -2.0F, 7.0F, 0.0F, 0.053F, -0.4175F)); + + PartDefinition bone5 = partdefinition.addOrReplaceChild("bone5", CubeListBuilder.create(), PartPose.offset(13.9643F, 4.2569F, -4.4757F)); + + PartDefinition cube_r11 = bone5.addOrReplaceChild("cube_r11", CubeListBuilder.create().texOffs(35, 35).mirror().addBox(-2.245F, -1.5004F, -0.2879F, 5.0F, 10.0F, 1.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(-10.8905F, -2.0449F, 8.3029F, 0.0114F, -0.0441F, -0.2194F)); + + PartDefinition bone6 = partdefinition.addOrReplaceChild("bone6", CubeListBuilder.create(), PartPose.offset(13.9643F, 4.2569F, -4.4757F)); + + PartDefinition cube_r12 = bone6.addOrReplaceChild("cube_r12", CubeListBuilder.create().texOffs(34, 13).mirror().addBox(-8.4924F, -7.4805F, 0.9935F, 9.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(0.0F, -2.0F, 6.7F, 0.0F, 0.1402F, -0.4175F)); + + PartDefinition bone7 = partdefinition.addOrReplaceChild("bone7", CubeListBuilder.create(), PartPose.offset(13.9643F, 4.2569F, -4.4757F)); + + PartDefinition cube_r13 = bone7.addOrReplaceChild("cube_r13", CubeListBuilder.create().texOffs(0, 11).mirror().addBox(-0.3423F, -9.1841F, 0.896F, 17.0F, 4.0F, 0.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(0.0F, -2.0F, 7.0F, -0.0916F, 0.1687F, -0.7675F)); + + PartDefinition bone8 = partdefinition.addOrReplaceChild("bone8", CubeListBuilder.create(), PartPose.offset(13.9643F, 4.2569F, -4.4757F)); + + PartDefinition cube_r14 = bone8.addOrReplaceChild("cube_r14", CubeListBuilder.create().texOffs(0, 15).mirror().addBox(-1.7496F, 3.547F, 0.4201F, 9.0F, 14.0F, 0.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(0.0F, -2.0F, 7.0F, -0.0916F, 0.1687F, -0.7675F)); + + PartDefinition bone9 = partdefinition.addOrReplaceChild("bone9", CubeListBuilder.create(), PartPose.offset(13.9643F, 4.2569F, -4.4757F)); + + PartDefinition cube_r15 = bone9.addOrReplaceChild("cube_r15", CubeListBuilder.create().texOffs(0, 29).mirror().addBox(-8.4267F, 4.2147F, 0.9002F, 8.0F, 12.0F, 0.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(0.0F, -2.0F, 7.0F, 0.0F, 0.053F, -0.4175F)); + + PartDefinition bone10 = partdefinition.addOrReplaceChild("bone10", CubeListBuilder.create(), PartPose.offset(13.9643F, 4.2569F, -4.4757F)); + + PartDefinition cube_r16 = bone10.addOrReplaceChild("cube_r16", CubeListBuilder.create().texOffs(16, 36).mirror().addBox(-2.5F, 7.0F, -1.0F, 5.0F, 11.0F, 0.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(-10.3486F, -0.6377F, 9.0425F, 0.0114F, -0.0441F, -0.2194F)); + + PartDefinition bone11 = partdefinition.addOrReplaceChild("bone11", CubeListBuilder.create(), PartPose.offset(13.9643F, 4.2569F, -4.4757F)); + + PartDefinition cube_r17 = bone11.addOrReplaceChild("cube_r17", CubeListBuilder.create().texOffs(0, 0).mirror().addBox(7.2504F, -5.453F, 0.4201F, 18.0F, 11.0F, 0.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(0.0F, -2.0F, 7.0F, -0.0916F, 0.1687F, -0.7675F)); + + PartDefinition bone12 = partdefinition.addOrReplaceChild("bone12", CubeListBuilder.create(), PartPose.offset(13.9643F, 4.2569F, -4.4757F)); + + PartDefinition cube_r18 = bone12.addOrReplaceChild("cube_r18", CubeListBuilder.create().texOffs(34, 9).mirror().addBox(-3.0572F, -2.4742F, -1.0783F, 8.0F, 2.0F, 2.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(-10.8905F, -2.0449F, 8.3029F, 0.0114F, -0.0441F, -0.2194F)); + + PartDefinition bone13 = partdefinition.addOrReplaceChild("bone13", CubeListBuilder.create(), PartPose.offset(13.9643F, 4.2569F, -4.4757F)); + + PartDefinition cube_r19 = bone13.addOrReplaceChild("cube_r19", CubeListBuilder.create().texOffs(36, 4).mirror().addBox(-4.8002F, -6.0505F, -0.2962F, 6.0F, 2.0F, 2.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(0.0F, -2.0F, 7.0F, -0.0172F, 0.1298F, -0.4374F)); + + PartDefinition bone14 = partdefinition.addOrReplaceChild("bone14", CubeListBuilder.create(), PartPose.offset(13.9643F, 4.2569F, -4.4757F)); + + PartDefinition cube_r20 = bone14.addOrReplaceChild("cube_r20", CubeListBuilder.create().texOffs(36, 0).mirror().addBox(2.6586F, -5.283F, -0.2953F, 7.0F, 2.0F, 2.0F, new CubeDeformation(0.0F)).mirror(false), PartPose.offsetAndRotation(0.0F, -2.0F, 7.0F, -0.0657F, 0.1133F, -0.8328F)); + + return LayerDefinition.create(mesh, 64, 64); + } + + @Override + public void renderToBuffer(PoseStack p_102034_, VertexConsumer p_102035_, int p_102036_, int p_102037_, int p_350361_) { + body.skipDraw = true; + + super.renderToBuffer(p_102034_, p_102035_, p_102036_, p_102037_, p_350361_); + } + + @Override + @Nonnull + protected Iterable headParts() { + return ImmutableList.of(); + } + + @Override + @Nonnull + protected Iterable bodyParts() { + return ImmutableList.of(this.body); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/particles/BasicColoredParticle.java b/src/main/java/it/hurts/sskirillss/relics/client/particles/BasicColoredParticle.java new file mode 100644 index 00000000..46df303a --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/particles/BasicColoredParticle.java @@ -0,0 +1,229 @@ +package it.hurts.sskirillss.relics.client.particles; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.BufferBuilder; +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import com.mojang.blaze3d.vertex.Tesselator; +import com.mojang.blaze3d.vertex.VertexFormat; +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import io.netty.buffer.ByteBuf; +import it.hurts.sskirillss.relics.init.ParticleRegistry; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.particle.*; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.core.particles.ParticleOptions; +import net.minecraft.core.particles.ParticleType; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import org.jetbrains.annotations.Nullable; +import org.lwjgl.opengl.GL11; + +import javax.annotation.Nonnull; +import java.awt.*; + +public class BasicColoredParticle extends TextureSheetParticle { + private final Constructor constructor; + + public BasicColoredParticle(ClientLevel world, double x, double y, double z, double velocityX, double velocityY, double velocityZ, Constructor constructor) { + super(world, x, y, z, velocityX, velocityY, velocityZ); + + setColor(constructor.getColor().getRed() / 255F, constructor.getColor().getGreen() / 255F, constructor.getColor().getBlue() / 255F); + setSize(constructor.getDiameter(), constructor.getDiameter()); + setAlpha(constructor.getColor().getAlpha() / 255F); + setLifetime(constructor.getLifetime()); + + this.constructor = constructor; + + this.quadSize = constructor.getDiameter(); + this.hasPhysics = constructor.isPhysical(); + + this.xd = velocityX; + this.yd = velocityY; + this.zd = velocityZ; + } + + @Override + public void tick() { + this.quadSize *= constructor.getScaleModifier(); + + xo = x; + yo = y; + zo = z; + + oRoll = roll; + roll += constructor.getRoll(); + + move(xd, yd, zd); + + if (this.age++ >= this.lifetime) + this.remove(); + } + + @Override + protected int getLightColor(float partialTick) { + return LightTexture.FULL_BRIGHT; + } + + @Nonnull + @Override + public ParticleRenderType getRenderType() { + return RENDERER; + } + + private static final ParticleRenderType RENDERER = new ParticleRenderType() { + @Override + public BufferBuilder begin(Tesselator tesselator, TextureManager manager) { + RenderSystem.setShader(GameRenderer::getParticleShader); + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + RenderSystem.setShaderTexture(0, TextureAtlas.LOCATION_PARTICLES); + + RenderSystem.enableBlend(); + + RenderSystem.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); + + RenderSystem.depthMask(false); + + return tesselator.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.PARTICLE); + } + + @Override + public String toString() { + return Reference.MODID + ":" + "basic_colored"; + } + }; + + @Data + @Builder + public static class Constructor { + @Builder.Default + private Color color; + + @Builder.Default + private float diameter = 1F; + + @Builder.Default + private float roll = 0F; + + @Builder.Default + private boolean physical = true; + + @Builder.Default + private int lifetime = 20; + + @Builder.Default + private float scaleModifier = 1F; + + public static class ConstructorBuilder { + private Color color = new Color(0xFFFFFFFF, true); + + public ConstructorBuilder color(int color) { + this.color = new Color(color, true); + + return this; + } + + public ConstructorBuilder color(float r, float g, float b, float a) { + return this.color(new Color(r, g, b, a).getRGB()); + } + + public ConstructorBuilder color(float r, float g, float b) { + return this.color(r, g, b, 1F); + } + + public ConstructorBuilder color(int r, int g, int b, int a) { + return this.color(r / 255F, g / 255F, b / 255F, a / 255F); + } + + public ConstructorBuilder color(int r, int g, int b) { + return this.color(r, g, b, 0xFF); + } + } + } + + public static class Options implements ParticleOptions { + @Getter + private final Constructor data; + + private Options(int color, float diameter, int lifetime, float roll, float scaleModifier) { + this.data = Constructor.builder() + .color(color) + .diameter(diameter) + .lifetime(lifetime) + .roll(roll) + .scaleModifier(scaleModifier) + .build(); + } + + public Options(Constructor data) { + this.data = data; + } + + @Nonnull + @Override + public ParticleType getType() { + return ParticleRegistry.BASIC_COLORED.get(); + } + + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> instance.group( + Codec.INT.fieldOf("color").forGetter(options -> options.getData().getColor().getRGB()), + Codec.FLOAT.fieldOf("diameter").forGetter(options -> options.getData().getDiameter()), + Codec.INT.fieldOf("lifetime").forGetter(options -> options.getData().getLifetime()), + Codec.FLOAT.fieldOf("roll").forGetter(options -> options.getData().getRoll()), + Codec.FLOAT.fieldOf("scaleModifier").forGetter(options -> options.getData().getScaleModifier()) + ).apply(instance, Options::new)); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.INT, options -> options.getData().getColor().getRGB(), + ByteBufCodecs.FLOAT, options -> options.getData().getDiameter(), + ByteBufCodecs.INT, options -> options.getData().getLifetime(), + ByteBufCodecs.FLOAT, options -> options.getData().getRoll(), + ByteBufCodecs.FLOAT, options -> options.getData().getScaleModifier(), + Options::new + ); + } + + public static class Factory implements ParticleProvider { + private final SpriteSet sprites; + + public Factory(SpriteSet sprites) { + this.sprites = sprites; + } + + @Nullable + @Override + public Particle createParticle(Options options, ClientLevel world, double xPos, double yPos, double zPos, double xVelocity, double yVelocity, double zVelocity) { + BasicColoredParticle particle = new BasicColoredParticle(world, xPos, yPos, zPos, xVelocity, yVelocity, zVelocity, options.getData()); + + particle.pickSprite(sprites); + + return particle; + } + } + + public static class Type extends ParticleType { + public Type() { + super(false); + } + + @Override + public MapCodec codec() { + return Options.CODEC; + } + + @Override + public StreamCodec streamCodec() { + return Options.STREAM_CODEC; + } + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/BlockSimulationRenderer.java b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/BlockSimulationRenderer.java index d9a0e0fc..39b8072b 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/BlockSimulationRenderer.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/BlockSimulationRenderer.java @@ -14,7 +14,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.client.model.data.ModelData; +import net.neoforged.neoforge.client.model.data.ModelData; public class BlockSimulationRenderer extends EntityRenderer { public BlockSimulationRenderer(EntityRendererProvider.Context pContext) { diff --git a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/DissectionRenderer.java b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/DissectionRenderer.java index 5f99fb20..e8979b1a 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/DissectionRenderer.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/DissectionRenderer.java @@ -14,8 +14,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; @OnlyIn(Dist.CLIENT) public class DissectionRenderer extends EntityRenderer { @@ -45,14 +45,14 @@ public void render(DissectionEntity entityIn, float entityYaw, float partialTick matrixStackIn.mulPose(Axis.YP.rotationDegrees((float) angleY)); matrixStackIn.mulPose(Axis.XP.rotationDegrees((float) angleZ + 90F)); - new DissectionModel<>().renderToBuffer(matrixStackIn, bufferIn.getBuffer(RenderType.entityCutout(new ResourceLocation(Reference.MODID, - "textures/entities/dissection.png"))), packedLightIn, OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, 1F); + new DissectionModel<>().renderToBuffer(matrixStackIn, bufferIn.getBuffer(RenderType.entityCutout(ResourceLocation.fromNamespaceAndPath(Reference.MODID, + "textures/entities/dissection.png"))), packedLightIn, OverlayTexture.NO_OVERLAY); matrixStackIn.popPose(); } @Override public ResourceLocation getTextureLocation(DissectionEntity entity) { - return new ResourceLocation(Reference.MODID, "textures/entities/dissection.png"); + return ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/entities/dissection.png"); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/NullRenderer.java b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/NullRenderer.java index 6eeba0cc..5afb0ba1 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/NullRenderer.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/NullRenderer.java @@ -6,8 +6,8 @@ import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import javax.annotation.Nonnull; diff --git a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/RelicExperienceOrbRenderer.java b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/RelicExperienceOrbRenderer.java index 3a695f8b..b6966a44 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/RelicExperienceOrbRenderer.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/RelicExperienceOrbRenderer.java @@ -2,7 +2,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; -import com.mojang.math.Axis; import it.hurts.sskirillss.relics.entities.RelicExperienceOrbEntity; import it.hurts.sskirillss.relics.utils.Reference; import net.minecraft.client.renderer.LightTexture; @@ -14,10 +13,8 @@ import net.minecraft.core.BlockPos; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import org.joml.Matrix3f; -import org.joml.Matrix4f; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; @OnlyIn(Dist.CLIENT) public class RelicExperienceOrbRenderer extends EntityRenderer { @@ -42,9 +39,6 @@ public void render(RelicExperienceOrbEntity entity, float yaw, float pitch, Pose VertexConsumer consumer = buffer.getBuffer(RenderType.itemEntityTranslucentCull(getTextureLocation(entity))); PoseStack.Pose pose = poseStack.last(); - Matrix4f matrix4f = pose.pose(); - Matrix3f matrix3f = pose.normal(); - float scale = (float) (0.5F + Math.sin(entity.tickCount * 0.1F) * 0.05F); poseStack.scale(scale, scale, scale); @@ -52,26 +46,25 @@ public void render(RelicExperienceOrbEntity entity, float yaw, float pitch, Pose poseStack.translate(0.0F, 0.2F + (entity.getStage() * 0.05F), 0.0F); poseStack.mulPose(this.entityRenderDispatcher.cameraOrientation()); - poseStack.mulPose(Axis.YP.rotationDegrees(180F)); int alpha = (int) Math.min(255, 255 * (0.75F + Math.sin(entity.tickCount * 0.25F) * 0.1F)); - vertex(consumer, matrix4f, matrix3f, -0.5F, -0.5F, alpha, 0, 1); - vertex(consumer, matrix4f, matrix3f, 0.5F, -0.5F, alpha, 1, 1); - vertex(consumer, matrix4f, matrix3f, 0.5F, 0.5F, alpha, 1, 0); - vertex(consumer, matrix4f, matrix3f, -0.5F, 0.5F, alpha, 0, 0); + vertex(consumer, pose, -0.5F, -0.5F, alpha, 0, 1); + vertex(consumer, pose, 0.5F, -0.5F, alpha, 1, 1); + vertex(consumer, pose, 0.5F, 0.5F, alpha, 1, 0); + vertex(consumer, pose, -0.5F, 0.5F, alpha, 0, 0); poseStack.popPose(); super.render(entity, yaw, pitch, poseStack, buffer, light); } - private static void vertex(VertexConsumer consumer, Matrix4f matrix4f, Matrix3f matrix3f, float x, float y, int alpha, float u, float v) { - consumer.vertex(matrix4f, x, y, 0F).color(255, 255, 255, alpha).uv(u, v).overlayCoords(OverlayTexture.NO_OVERLAY).uv2(LightTexture.FULL_BRIGHT).normal(matrix3f, 0F, 1F, 0F).endVertex(); + private static void vertex(VertexConsumer consumer, PoseStack.Pose pose, float x, float y, int alpha, float u, float v) { + consumer.addVertex(pose, x, y, 0F).setColor(255, 255, 255, alpha).setUv(u, v).setOverlay(OverlayTexture.NO_OVERLAY).setLight(LightTexture.FULL_BRIGHT).setNormal(pose,0F, 1F, 0F); } @Override public ResourceLocation getTextureLocation(RelicExperienceOrbEntity entity) { - return new ResourceLocation(Reference.MODID, "textures/entities/experience/relics/relic_experience_" + entity.getStage() + ".png"); + return ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/entities/experience/relics/relic_experience_" + entity.getStage() + ".png"); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/ShadowGlaiveRenderer.java b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/ShadowGlaiveRenderer.java index b0e194d5..15c9423b 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/ShadowGlaiveRenderer.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/ShadowGlaiveRenderer.java @@ -12,36 +12,35 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider.Context; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.Mth; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; @OnlyIn(Dist.CLIENT) public class ShadowGlaiveRenderer extends EntityRenderer { + private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/entities/shadow_glaive.png"); + public ShadowGlaiveRenderer(Context renderManager) { super(renderManager); } @Override - public void render(ShadowGlaiveEntity entityIn, float entityYaw, float partialTicks, PoseStack matrixStackIn, MultiBufferSource bufferIn, int packedLightIn) { - float time = entityIn.tickCount + (Minecraft.getInstance().isPaused() ? 0 : partialTicks); + public void render(ShadowGlaiveEntity entity, float entityYaw, float partialTicks, PoseStack matrixStackIn, MultiBufferSource bufferIn, int packedLightIn) { + float time = entity.tickCount + (Minecraft.getInstance().isPaused() ? 0 : partialTicks); matrixStackIn.pushPose(); - matrixStackIn.translate(0, -0.2F, 0); - matrixStackIn.mulPose(Axis.YP.rotationDegrees(Mth.lerp(partialTicks, entityIn.getYRot(), entityIn.getYRot()) - 90.0F)); - matrixStackIn.mulPose(Axis.ZP.rotationDegrees(Mth.lerp(partialTicks, entityIn.getXRot(), entityIn.getXRot()))); - matrixStackIn.mulPose(Axis.YP.rotationDegrees(time * 40F)); - matrixStackIn.scale(0.35F, 0.35F, 0.35F); + matrixStackIn.scale(1.35F, 1.35F, 1.35F); + matrixStackIn.mulPose(Axis.XP.rotationDegrees(90F)); + matrixStackIn.mulPose(Axis.ZP.rotationDegrees(time * 40F)); + matrixStackIn.translate(0F, -1F, -0.075F); - new ShadowGlaiveModel<>().renderToBuffer(matrixStackIn, bufferIn.getBuffer(RenderType.entityCutout(new ResourceLocation(Reference.MODID, - "textures/entities/shadow_glaive.png"))), packedLightIn, OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, 1F); + new ShadowGlaiveModel<>().renderToBuffer(matrixStackIn, bufferIn.getBuffer(RenderType.entityCutout(getTextureLocation(entity))), packedLightIn, OverlayTexture.NO_OVERLAY); matrixStackIn.popPose(); } @Override public ResourceLocation getTextureLocation(ShadowGlaiveEntity entity) { - return new ResourceLocation(Reference.MODID, "textures/entities/shadow_glaive.png"); + return TEXTURE; } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/ShadowSawRenderer.java b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/ShadowSawRenderer.java deleted file mode 100644 index fb85761f..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/ShadowSawRenderer.java +++ /dev/null @@ -1,50 +0,0 @@ -package it.hurts.sskirillss.relics.client.renderer.entities; - -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Axis; -import it.hurts.sskirillss.relics.client.models.entities.ShadowSawModel; -import it.hurts.sskirillss.relics.entities.ShadowSawEntity; -import it.hurts.sskirillss.relics.utils.Reference; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.entity.EntityRenderer; -import net.minecraft.client.renderer.entity.EntityRendererProvider.Context; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -@OnlyIn(Dist.CLIENT) -public class ShadowSawRenderer extends EntityRenderer { - public ShadowSawRenderer(Context renderManager) { - super(renderManager); - } - - @Override - public void render(ShadowSawEntity entityIn, float entityYaw, float partialTicks, PoseStack matrixStackIn, MultiBufferSource bufferIn, int packedLightIn) { - float time = entityIn.tickCount + (Minecraft.getInstance().isPaused() ? 0 : partialTicks); - - matrixStackIn.pushPose(); - - matrixStackIn.translate(0, 1, 0); - - matrixStackIn.mulPose(Axis.YP.rotationDegrees(time * 30F)); - - matrixStackIn.mulPose(Axis.ZP.rotation((float) (Math.sin(time) * 0.3F) * 0.1F)); - - matrixStackIn.translate(0, Math.sin(time * 0.1F) * 0.05F, 0); - - matrixStackIn.scale(1.5F, -1F, 1.5F); - - new ShadowSawModel<>().renderToBuffer(matrixStackIn, bufferIn.getBuffer(RenderType.entityTranslucent(new ResourceLocation(Reference.MODID, - "textures/entities/shadow_saw.png"))), packedLightIn, OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, 1F); - - matrixStackIn.popPose(); - } - - @Override - public ResourceLocation getTextureLocation(ShadowSawEntity entity) { - return new ResourceLocation(Reference.MODID, "textures/entities/shadow_saw.png"); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/SolidSnowballRenderer.java b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/SolidSnowballRenderer.java index 04a5da00..a58d3006 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/SolidSnowballRenderer.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/SolidSnowballRenderer.java @@ -12,8 +12,8 @@ import net.minecraft.client.renderer.entity.EntityRendererProvider.Context; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.resources.ResourceLocation; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; @OnlyIn(Dist.CLIENT) public class SolidSnowballRenderer extends EntityRenderer { @@ -38,14 +38,14 @@ public void render(SolidSnowballEntity entityIn, float entityYaw, float partialT matrixStackIn.scale(scale, scale, scale); - new SolidSnowballModel<>().renderToBuffer(matrixStackIn, bufferIn.getBuffer(RenderType.entityCutout(new ResourceLocation(Reference.MODID, - "textures/entities/solid_snowball.png"))), packedLightIn, OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, 1F); + new SolidSnowballModel<>().renderToBuffer(matrixStackIn, bufferIn.getBuffer(RenderType.entityCutout(ResourceLocation.fromNamespaceAndPath(Reference.MODID, + "textures/entities/solid_snowball.png"))), packedLightIn, OverlayTexture.NO_OVERLAY); matrixStackIn.popPose(); } @Override public ResourceLocation getTextureLocation(SolidSnowballEntity entity) { - return new ResourceLocation(Reference.MODID, "textures/entities/solid_snowball.png"); + return ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/entities/solid_snowball.png"); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/SporeRenderer.java b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/SporeRenderer.java index a0b3b85a..f98e1d0b 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/SporeRenderer.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/SporeRenderer.java @@ -4,18 +4,17 @@ import com.mojang.math.Axis; import it.hurts.sskirillss.relics.client.models.entities.SporeModel; import it.hurts.sskirillss.relics.entities.SporeEntity; -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; import it.hurts.sskirillss.relics.utils.Reference; import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererProvider.Context; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; @OnlyIn(Dist.CLIENT) public class SporeRenderer extends EntityRenderer { @@ -24,42 +23,30 @@ public SporeRenderer(Context renderManager) { } @Override - public void render(SporeEntity entityIn, float entityYaw, float partialTicks, PoseStack matrixStackIn, MultiBufferSource bufferIn, int packedLightIn) { - float time = entityIn.tickCount + (Minecraft.getInstance().isPaused() ? 0 : partialTicks); - - matrixStackIn.pushPose(); - - matrixStackIn.translate(0, ((Math.pow(Math.log10(1 + entityIn.getSize()), 1D / 3D))) / 4F, 0); + public void render(SporeEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) { + if (entityIn.tickCount < 5) + return; - if (!entityIn.isStuck()) { - float speed = 15F; - - matrixStackIn.mulPose(Axis.YP.rotationDegrees(time * speed)); - matrixStackIn.mulPose(Axis.XN.rotationDegrees(time * speed)); - } + float time = entityIn.tickCount + (Minecraft.getInstance().isPaused() ? 0 : partialTicks); - ItemStack stack = entityIn.getStack(); + poseStack.pushPose(); - if (stack.getItem() instanceof IRelicItem relic) { - double inlinedSize = Math.pow(Math.log10(1 + entityIn.getSize()), 1D / 3D); + var scale = (float) (Math.clamp(entityIn.tickCount * 0.0175F, 0, 0.5F) + Math.sin(time * 0.1F) * 0.05F); - int maxLifetime = (int) Math.round(relic.getAbilityValue(entityIn.getStack(), "spore", "duration") * 20); - int lifetime = entityIn.getLifetime(); + poseStack.translate(0, 0.05F, 0); - float scale = (float) (inlinedSize + (Math.abs(Math.sin((entityIn.tickCount + (Minecraft.getInstance().isPaused() ? 0 : partialTicks)) * 0.2F)) * 0.05F) - + (lifetime >= maxLifetime - 20 ? (float) ((20 - (maxLifetime - lifetime) + (Minecraft.getInstance().isPaused() ? 0 : partialTicks)) * (inlinedSize * 0.035F)) : 0F)); + poseStack.scale(scale, scale, scale); - matrixStackIn.scale(scale, scale, scale); - } + poseStack.mulPose(Axis.YP.rotation(time * 0.25F)); + poseStack.mulPose(Axis.ZN.rotation(time * 0.25F)); - new SporeModel<>().renderToBuffer(matrixStackIn, bufferIn.getBuffer(RenderType.entityCutout(new ResourceLocation(Reference.MODID, - "textures/entities/spore.png"))), packedLightIn, OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, 1F); + new SporeModel<>().renderToBuffer(poseStack, bufferIn.getBuffer(RenderType.entityCutout(getTextureLocation(entityIn))), LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY); - matrixStackIn.popPose(); + poseStack.popPose(); } @Override public ResourceLocation getTextureLocation(SporeEntity entity) { - return new ResourceLocation(Reference.MODID, "textures/entities/spore.png"); + return ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/entities/spore.png"); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/StalactiteRenderer.java b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/StalactiteRenderer.java index f0d2ac88..7be8f2b6 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/StalactiteRenderer.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/renderer/entities/StalactiteRenderer.java @@ -13,8 +13,8 @@ import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.Mth; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; @OnlyIn(Dist.CLIENT) public class StalactiteRenderer extends EntityRenderer { @@ -37,14 +37,14 @@ public void render(StalactiteEntity entityIn, float entityYaw, float partialTick matrixStackIn.scale(0.35F, 0.35F, 0.35F); - new StalactiteModel<>().renderToBuffer(matrixStackIn, bufferIn.getBuffer(RenderType.entityCutout(new ResourceLocation(Reference.MODID, - "textures/entities/stalactite.png"))), packedLightIn, OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, 1F); + new StalactiteModel<>().renderToBuffer(matrixStackIn, bufferIn.getBuffer(RenderType.entityCutout(ResourceLocation.fromNamespaceAndPath(Reference.MODID, + "textures/entities/stalactite.png"))), packedLightIn, OverlayTexture.NO_OVERLAY); matrixStackIn.popPose(); } @Override public ResourceLocation getTextureLocation(StalactiteEntity entity) { - return new ResourceLocation(Reference.MODID, "textures/entities/stalactite.png"); + return ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/entities/stalactite.png"); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/base/IPagedDescriptionScreen.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/base/IPagedDescriptionScreen.java new file mode 100644 index 00000000..e61dba0a --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/base/IPagedDescriptionScreen.java @@ -0,0 +1,15 @@ +package it.hurts.sskirillss.relics.client.screen.base; + +import it.hurts.sskirillss.relics.client.screen.description.general.misc.DescriptionPage; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionCache; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; + +public interface IPagedDescriptionScreen { + DescriptionPage getPage(); + + default void updateCache(IRelicItem relic) { + DescriptionCache.setEntry(relic, DescriptionCache.getEntry(relic).toBuilder() + .selectedPage(getPage()) + .build()); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/base/IRelicScreenProvider.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/base/IRelicScreenProvider.java new file mode 100644 index 00000000..b17d6284 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/base/IRelicScreenProvider.java @@ -0,0 +1,11 @@ +package it.hurts.sskirillss.relics.client.screen.base; + +import net.minecraft.world.item.ItemStack; + +public interface IRelicScreenProvider { + ItemStack getStack(); + + int getContainer(); + + int getSlot(); +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/AbilityDescriptionScreen.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/AbilityDescriptionScreen.java deleted file mode 100644 index 327443ba..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/AbilityDescriptionScreen.java +++ /dev/null @@ -1,512 +0,0 @@ -package it.hurts.sskirillss.relics.client.screen.description; - -import com.google.common.collect.Lists; -import com.mojang.blaze3d.platform.GlStateManager; -import com.mojang.blaze3d.platform.InputConstants; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import it.hurts.sskirillss.relics.client.screen.base.IAutoScaledScreen; -import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; -import it.hurts.sskirillss.relics.client.screen.description.data.ExperienceParticleData; -import it.hurts.sskirillss.relics.client.screen.description.widgets.ability.AbilityRerollButtonWidget; -import it.hurts.sskirillss.relics.client.screen.description.widgets.ability.AbilityResetButtonWidget; -import it.hurts.sskirillss.relics.client.screen.description.widgets.ability.AbilityUpgradeButtonWidget; -import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; -import it.hurts.sskirillss.relics.client.screen.utils.ScreenUtils; -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; -import it.hurts.sskirillss.relics.tiles.ResearchingTableTile; -import it.hurts.sskirillss.relics.utils.EntityUtils; -import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.Reference; -import it.hurts.sskirillss.relics.utils.RenderUtils; -import it.hurts.sskirillss.relics.utils.data.AnimationData; -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.components.AbstractButton; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.FormattedCharSequence; -import net.minecraft.util.RandomSource; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.registries.ForgeRegistries; -import org.lwjgl.opengl.GL11; - -import java.awt.*; -import java.util.List; - -@OnlyIn(Dist.CLIENT) -public class AbilityDescriptionScreen extends Screen implements IAutoScaledScreen { - private final Minecraft MC = Minecraft.getInstance(); - - public static final ResourceLocation TEXTURE = new ResourceLocation(Reference.MODID, "textures/gui/description/ability_background.png"); - - public final BlockPos pos; - public ItemStack stack; - public final String ability; - - public int backgroundHeight = 171; - public int backgroundWidth = 268; - - public AbilityUpgradeButtonWidget upgradeButton; - public AbilityRerollButtonWidget rerollButton; - public AbilityResetButtonWidget resetButton; - - public int ticksExisted; - - public AbilityDescriptionScreen(BlockPos pos, ItemStack stack, String ability) { - super(Component.empty()); - - this.pos = pos; - this.stack = stack; - this.ability = ability; - } - - @Override - protected void init() { - if (stack == null || !(stack.getItem() instanceof IRelicItem)) - return; - - TextureManager manager = MC.getTextureManager(); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, TEXTURE); - - manager.bindForSetup(TEXTURE); - - this.upgradeButton = new AbilityUpgradeButtonWidget(((this.width - backgroundWidth) / 2) + 233, ((this.height - backgroundHeight) / 2) + 104, this, ability); - this.rerollButton = new AbilityRerollButtonWidget(((this.width - backgroundWidth) / 2) + 233, ((this.height - backgroundHeight) / 2) + 122, this, ability); - this.resetButton = new AbilityResetButtonWidget(((this.width - backgroundWidth) / 2) + 233, ((this.height - backgroundHeight) / 2) + 140, this, ability); - - this.addRenderableWidget(upgradeButton); - this.addRenderableWidget(rerollButton); - this.addRenderableWidget(resetButton); - } - - @Override - public void tick() { - super.tick(); - - LocalPlayer player = MC.player; - - if (player == null) - return; - - Level level = player.level(); - - if (!(level.getBlockEntity(pos) instanceof ResearchingTableTile tile)) - return; - - stack = tile.getStack(); - - if (stack == null || !(stack.getItem() instanceof IRelicItem)) - return; - - ticksExisted++; - - RandomSource random = player.getRandom(); - - int x = (this.width - backgroundWidth) / 2; - int y = (this.height - backgroundHeight) / 2; - - if (ticksExisted % 3 == 0) { - { - int percentage = (int) (player.totalExperience / ((player.totalExperience / player.experienceProgress) / 100)); - - int sourceWidth = 206; - int maxWidth = (int) (sourceWidth * (percentage / 100F)); - - if (maxWidth > 0) { - int xOff = random.nextInt(sourceWidth); - - if (xOff <= maxWidth) - ParticleStorage.addParticle(this, new ExperienceParticleData(new Color(100 + random.nextInt(50), 200 + random.nextInt(50), 0), - x + 30 + xOff, y + 82, 0.15F + (random.nextFloat() * 0.25F), 100 + random.nextInt(50))); - } - } - } - } - - @Override - public void render(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { - LocalPlayer player = MC.player; - - if (stack == null || !(stack.getItem() instanceof IRelicItem relic) || player == null) - return; - - RelicData relicData = relic.getRelicData(); - - if (relicData == null) - return; - - AbilityData abilityData = relic.getAbilityData(ability); - - if (abilityData == null) - return; - - PoseStack pPoseStack = guiGraphics.pose(); - TextureManager manager = MC.getTextureManager(); - - this.renderBackground(guiGraphics); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, TEXTURE); - - manager.bindForSetup(TEXTURE); - - int texWidth = 512; - int texHeight = 512; - - int x = (this.width - backgroundWidth) / 2; - int y = (this.height - backgroundHeight) / 2; - - guiGraphics.blit(TEXTURE, x, y, 0, 0, backgroundWidth, backgroundHeight, texWidth, texHeight); - - int percentage = (int) (player.totalExperience / ((player.totalExperience / player.experienceProgress) / 100)); - - guiGraphics.blit(TEXTURE, x + 30, y + 82, 301, 124, (int) Math.ceil(percentage / 100F * 206), 3, texWidth, texHeight); - - boolean hoveredVanillaExperience = ScreenUtils.isHovered(x + 30, y + 81, 206, 3, pMouseX, pMouseY); - - if (hoveredVanillaExperience) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/gui/description/experience_highlight.png")); - - RenderSystem.enableBlend(); - - RenderUtils.renderAnimatedTextureFromCenter(guiGraphics.pose(), x + 134F, y + 83.5F, 210, 98, 210, 7, 1F, AnimationData.builder() - .frame(0, 2) - .frame(1, 2) - .frame(2, 2) - .frame(3, 2) - .frame(4, 2) - .frame(5, 2) - .frame(6, 2) - .frame(7, 2) - .frame(8, 2) - .frame(9, 2) - .frame(10, 2) - .frame(11, 2) - .frame(12, 2) - .frame(13, 2) - ); - - RenderSystem.disableBlend(); - } - - pPoseStack.pushPose(); - - pPoseStack.scale(0.75F, 0.75F, 0.75F); - - MutableComponent experience = Component.literal(String.valueOf(player.experienceLevel)); - - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 135.75F) * 1.33F), ((y + 81) * 1.33F), 0x054503, false); - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 134.25F) * 1.33F), ((y + 81) * 1.33F), 0x054503, false); - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 135) * 1.33F), ((y + 81.75F) * 1.33F), 0x054503, false); - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 135) * 1.33F), ((y + 80.25F) * 1.33F), 0x054503, false); - - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 135) * 1.33F), ((y + 81) * 1.33F), 0x7efc20, false); - - pPoseStack.popPose(); - - pPoseStack.pushPose(); - - pPoseStack.scale(0.5F, 0.5F, 0.5F); - - int level = relic.getAbilityPoints(stack, ability); - int maxLevel = abilityData.getMaxLevel() == -1 ? (relicData.getLeveling().getMaxLevel() / abilityData.getRequiredPoints()) : abilityData.getMaxLevel(); - - MutableComponent name = Component.translatable("tooltip.relics." + ForgeRegistries.ITEMS.getKey(stack.getItem()).getPath() + ".ability." + ability); - - if (!abilityData.getStats().isEmpty()) - name.append(Component.translatable("tooltip.relics.relic.ability.level", level, maxLevel == -1 ? "∞" : maxLevel)); - - guiGraphics.drawString(MC.font, name.withStyle(ChatFormatting.BOLD), (x + 62) * 2, (y + 20) * 2 - 1, 0x412708, false); - - List lines = MC.font.split(Component.translatable("tooltip.relics." + ForgeRegistries.ITEMS.getKey(stack.getItem()).getPath() + ".ability." + ability + ".description"), 350); - - for (int i = 0; i < lines.size(); i++) { - guiGraphics.drawString(MC.font, lines.get(i), (x + 62) * 2, (y + 28 + (i * 5)) * 2, 0x412708, false); - } - - pPoseStack.popPose(); - - int yOff = 0; - int xOff = 0; - - boolean isLocked = !relic.canUseAbility(stack, ability); - - boolean isHoveredUpgrade = !isLocked && upgradeButton.isHovered(); - boolean isHoveredReroll = !isLocked && rerollButton.isHovered(); - boolean isHoveredReset = !isLocked && resetButton.isHovered(); - - for (String stat : relic.getAbilityInitialValues(stack, ability).keySet()) { - StatData statData = relic.getStatData(ability, stat); - - if (statData != null) { - MutableComponent cost = Component.literal(String.valueOf(statData.getFormatValue().apply(relic.getAbilityValue(stack, ability, stat)))); - - if (isHoveredUpgrade && level < maxLevel) { - cost.append(" ➠ " + statData.getFormatValue().apply(relic.getAbilityValue(stack, ability, stat, level + 1))); - } - - if (isHoveredReroll) { - cost.append(" ➠ ").append(Component.literal("X.XXX").withStyle(ChatFormatting.OBFUSCATED)); - } - - if (isHoveredReset && level > 0) { - cost.append(" ➠ " + statData.getFormatValue().apply(relic.getAbilityValue(stack, ability, stat, 0))); - } - - pPoseStack.pushPose(); - - pPoseStack.scale(0.5F, 0.5F, 0.5F); - - guiGraphics.drawString(MC.font, Component.translatable("tooltip.relics." + ForgeRegistries.ITEMS.getKey(stack.getItem()).getPath() + ".ability." + ability + ".stat." + stat + ".title"), (x + 35) * 2, (y + yOff + 102) * 2, 0x412708, false); - - guiGraphics.drawString(MC.font, Component.literal("● ").append(Component.translatable("tooltip.relics." + ForgeRegistries.ITEMS.getKey(stack.getItem()).getPath() + ".ability." + ability + ".stat." + stat + ".value", cost)), (x + 40) * 2, (y + yOff + 107) * 2, 0x412708, false); - - pPoseStack.popPose(); - - RenderSystem.setShaderTexture(0, TEXTURE); - - for (int i = 0; i < 5; i++) { - guiGraphics.blit(TEXTURE, x + xOff + 202, y + yOff + 102, 398, 15, 4, 4, 512, 512); - - xOff += 5; - } - - xOff = 0; - - manager.bindForSetup(TEXTURE); - - for (int i = 1; i < relic.getStatQuality(stack, ability, stat) + 1; i++) { - boolean isAliquot = i % 2 == 1; - - guiGraphics.blit(TEXTURE, x + xOff + 202, y + yOff + 102, (isLocked ? 407 : 398) + (isAliquot ? 0 : 2), 10, isAliquot ? 2 : 3, 4, 512, 512); - - xOff += (isAliquot ? 2 : 3); - } - - yOff += 14; - xOff = 0; - } - } - - ResourceLocation card = new ResourceLocation(Reference.MODID, "textures/gui/description/cards/" + ForgeRegistries.ITEMS.getKey(stack.getItem()).getPath() + "/" + abilityData.getIcon().apply(player, stack, ability) + ".png"); - - RenderSystem.setShaderTexture(0, card); - - manager.bindForSetup(card); - - if (GlStateManager._getTexLevelParameter(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_HEIGHT) == 29) { - if (isLocked) - RenderSystem.setShaderColor(0.25F, 0.25F, 0.25F, 1F); - - guiGraphics.blit(card, x + 17, y + 11, 36, 50, 0, 0, 20, 29, 20, 29); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - } - - RenderSystem.setShaderTexture(0, TEXTURE); - - manager.bindForSetup(TEXTURE); - - if (isLocked) - guiGraphics.blit(TEXTURE, x + 12, y + 7, 349, 0, 47, 69, texWidth, texHeight); - else - guiGraphics.blit(TEXTURE, x + 13, y + 7, 302, 0, 46, 69, texWidth, texHeight); - - for (int i = 1; i < relic.getAbilityQuality(stack, ability) + 1; i++) { - boolean isAliquot = i % 2 == 1; - - guiGraphics.blit(TEXTURE, x + 15 + xOff, y + 63, (isLocked ? 407 : 397) + (isAliquot ? 0 : 5), 0, isAliquot ? 5 : 4, 9, texWidth, texHeight); - - xOff += isAliquot ? 5 : 3; - } - - int points = relic.getPoints(stack); - - if (points > 0) { - pPoseStack.pushPose(); - - MutableComponent value = Component.literal(String.valueOf(points)).withStyle(ChatFormatting.BOLD); - - ResourceLocation icon = new ResourceLocation(Reference.MODID, "textures/gui/description/leveling_point.png"); - - manager.bindForSetup(icon); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, icon); - - guiGraphics.blit(icon, x + backgroundWidth + 5, y - 2, 0, 0, 50, 31, 50, 31); - - guiGraphics.drawString(MC.font, value, x + backgroundWidth + 39 - (MC.font.width(value) / 2), y + 10, 0xffce96); - - pPoseStack.popPose(); - } - - super.render(guiGraphics, pMouseX, pMouseY, pPartialTick); - - if (hoveredVanillaExperience) { - pPoseStack.pushPose(); - - pPoseStack.translate(0, 0, 10); - - List tooltip = Lists.newArrayList(); - - int maxWidth = 200; - int renderWidth = 0; - - List entries = Lists.newArrayList( - Component.translatable("tooltip.relics.relic.vanilla_experience.title").withStyle(ChatFormatting.BOLD), - Component.literal(" "), - Component.literal("● ").append(Component.translatable("tooltip.relics.relic.vanilla_experience.current_amount", (player.totalExperience - EntityUtils.getTotalExperienceForLevel(player.experienceLevel)), - (EntityUtils.getTotalExperienceForLevel(player.experienceLevel + 1) - EntityUtils.getTotalExperienceForLevel(player.experienceLevel)), - MathUtils.round(player.experienceProgress * 100F, 1))), - Component.literal("● ").append(Component.translatable("tooltip.relics.relic.vanilla_experience.total_amount", player.totalExperience)) - ); - - for (MutableComponent entry : entries) { - int entryWidth = (MC.font.width(entry)) / 2; - - if (entryWidth > renderWidth) - renderWidth = Math.min(entryWidth, maxWidth); - - tooltip.addAll(MC.font.split(entry, maxWidth * 2)); - } - - int height = Math.round(tooltip.size() * 4.5F); - - int renderX = pMouseX - 9 - (renderWidth / 2); - int renderY = y + 87; - - ScreenUtils.drawTexturedTooltipBorder(guiGraphics, new ResourceLocation(Reference.MODID, "textures/gui/tooltip/border/paper.png"), - renderWidth, height, renderX, renderY); - - yOff = 0; - - pPoseStack.scale(0.5F, 0.5F, 0.5F); - - for (FormattedCharSequence entry : tooltip) { - guiGraphics.drawString(MC.font, entry, (renderX + 9) * 2, (renderY + 9 + yOff) * 2, 0x412708, false); - - yOff += 5; - } - - pPoseStack.scale(1F, 1F, 1F); - - pPoseStack.popPose(); - } - - if (points > 0 && ScreenUtils.isHovered(x + backgroundWidth + 5, y - 2, 50, 31, pMouseX, pMouseY)) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/gui/description/leveling_point_highlight.png")); - - RenderSystem.enableBlend(); - - RenderUtils.renderAnimatedTextureFromCenter(guiGraphics.pose(), x + backgroundWidth + 5 + (50 / 2), y - 2 + (31 / 2), 64, 768, 64, 64, 1F, AnimationData.builder() - .frame(0, 2) - .frame(1, 2) - .frame(2, 2) - .frame(3, 2) - .frame(4, 2) - .frame(5, 2) - .frame(6, 2) - .frame(7, 2) - .frame(8, 2) - .frame(9, 2) - .frame(10, 2) - .frame(11, 2) - ); - - RenderSystem.disableBlend(); - - pPoseStack.pushPose(); - - pPoseStack.translate(0, 0, 10); - - List tooltip = Lists.newArrayList(); - - int maxWidth = 200; - int renderWidth = 0; - - List entries = Lists.newArrayList( - Component.translatable("tooltip.relics.relic.leveling_points.title").withStyle(ChatFormatting.BOLD) - ); - - for (MutableComponent entry : entries) { - int entryWidth = (MC.font.width(entry)) / 2; - - if (entryWidth > renderWidth) - renderWidth = Math.min(entryWidth, maxWidth); - - tooltip.addAll(MC.font.split(entry, maxWidth * 2)); - } - - int height = Math.round(tooltip.size() * 4.5F); - - int renderX = pMouseX + 1; - int renderY = pMouseY + 1; - - ScreenUtils.drawTexturedTooltipBorder(guiGraphics, new ResourceLocation(Reference.MODID, "textures/gui/tooltip/border/paper.png"), - renderWidth, height, renderX, renderY); - - yOff = 0; - - pPoseStack.scale(0.5F, 0.5F, 0.5F); - - for (FormattedCharSequence entry : tooltip) { - guiGraphics.drawString(MC.font, entry, (renderX + 9) * 2, (renderY + 9 + yOff) * 2, 0x412708, false); - - yOff += 5; - } - - pPoseStack.scale(1F, 1F, 1F); - - pPoseStack.popPose(); - } - - for (GuiEventListener listener : this.children()) { - if (listener instanceof AbstractButton button && button.isHovered() - && button instanceof IHoverableWidget widget) - widget.onHovered(guiGraphics, pMouseX, pMouseY); - } - } - - @Override - public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) { - if (MC.options.keyInventory.isActiveAndMatches(InputConstants.getKey(pKeyCode, pScanCode))) { - this.onClose(); - - return true; - } - - return super.keyPressed(pKeyCode, pScanCode, pModifiers); - } - - @Override - public void onClose() { - MC.setScreen(new RelicDescriptionScreen(pos)); - } - - @Override - public boolean isPauseScreen() { - return false; - } - - @Override - public int getAutoScale() { - return 0; - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/RelicDescriptionScreen.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/RelicDescriptionScreen.java deleted file mode 100644 index 9326e576..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/RelicDescriptionScreen.java +++ /dev/null @@ -1,596 +0,0 @@ -package it.hurts.sskirillss.relics.client.screen.description; - -import com.google.common.collect.Lists; -import com.mojang.blaze3d.platform.InputConstants; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import it.hurts.sskirillss.relics.client.screen.base.IAutoScaledScreen; -import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; -import it.hurts.sskirillss.relics.client.screen.description.data.ExperienceParticleData; -import it.hurts.sskirillss.relics.client.screen.description.widgets.relic.AbilityCardIconWidget; -import it.hurts.sskirillss.relics.client.screen.description.widgets.relic.ExperienceExchangeWidget; -import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; -import it.hurts.sskirillss.relics.client.screen.utils.ScreenUtils; -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.tiles.ResearchingTableTile; -import it.hurts.sskirillss.relics.utils.EntityUtils; -import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.Reference; -import it.hurts.sskirillss.relics.utils.RenderUtils; -import it.hurts.sskirillss.relics.utils.data.AnimationData; -import net.minecraft.ChatFormatting; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.components.AbstractButton; -import net.minecraft.client.gui.components.events.GuiEventListener; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.core.BlockPos; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.FormattedCharSequence; -import net.minecraft.util.RandomSource; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.registries.ForgeRegistries; - -import java.awt.*; -import java.util.List; -import java.util.Map; - -@OnlyIn(Dist.CLIENT) -public class RelicDescriptionScreen extends Screen implements IAutoScaledScreen { - private final Minecraft MC = Minecraft.getInstance(); - - public static final ResourceLocation TEXTURE = new ResourceLocation(Reference.MODID, "textures/gui/description/relic_background.png"); - - public final BlockPos pos; - public ItemStack stack; - - public int backgroundHeight = 171; - public int backgroundWidth = 268; - - public int ticksExisted; - - public RelicDescriptionScreen(BlockPos pos) { - super(Component.empty()); - - this.pos = pos; - - gatherData(); - } - - public void gatherData() { - Level level = MC.level; - - if (!(level.getBlockEntity(pos) instanceof ResearchingTableTile tile)) - return; - - ItemStack stack = tile.getStack(); - - if (!(stack.getItem() instanceof IRelicItem)) - return; - - this.stack = stack; - } - - @Override - protected void init() { - if (stack == null || !(stack.getItem() instanceof IRelicItem relic)) - return; - - TextureManager manager = MC.getTextureManager(); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, TEXTURE); - - manager.bindForSetup(TEXTURE); - - int x = (this.width - backgroundWidth) / 2; - int y = (this.height - backgroundHeight) / 2; - - int step = 0; - - for (Map.Entry ability : relic.getRelicData().getAbilities().getAbilities().entrySet()) { - this.addRenderableWidget(new AbilityCardIconWidget(x + 41 + step, y + 105, this, ability.getKey())); - - step += 39; - } - - this.addRenderableWidget(new ExperienceExchangeWidget(x + 239, y + 72, this)); - } - - @Override - public void tick() { - super.tick(); - - LocalPlayer player = MC.player; - - if (player == null) - return; - - Level level = player.level(); - - if (!(level.getBlockEntity(pos) instanceof ResearchingTableTile tile)) - return; - - stack = tile.getStack(); - - if (stack == null || !(stack.getItem() instanceof IRelicItem relic)) - return; - - ticksExisted++; - - RandomSource random = player.getRandom(); - - int x = (this.width - backgroundWidth) / 2; - int y = (this.height - backgroundHeight) / 2; - - if (ticksExisted % 3 == 0) { - { - int relicLevel = relic.getLevel(stack); - - float percentage = relic.isMaxLevel(stack) ? 100F : relic.getExperience(stack) / (relic.getExperienceBetweenLevels(stack, relicLevel, relicLevel + 1) / 100F); - - int sourceWidth = 206; - int maxWidth = (int) (sourceWidth * (percentage / 100F)); - - if (maxWidth > 0) { - int xOff = random.nextInt(sourceWidth); - - if (xOff <= maxWidth) - ParticleStorage.addParticle(this, new ExperienceParticleData(new Color(200 + random.nextInt(50), 150 + random.nextInt(100), 0), - x + 30 + xOff, y + 73, 0.15F + (random.nextFloat() * 0.25F), 100 + random.nextInt(50))); - } - } - - { - float percentage = (int) (player.totalExperience / ((player.totalExperience / player.experienceProgress) / 100F)); - - int sourceWidth = 206; - int maxWidth = (int) (sourceWidth * (percentage / 100F)); - - if (maxWidth > 0) { - int xOff = random.nextInt(sourceWidth); - - if (xOff <= maxWidth) - ParticleStorage.addParticle(this, new ExperienceParticleData(new Color(100 + random.nextInt(50), 200 + random.nextInt(50), 0), - x + 30 + xOff, y + 86, 0.15F + (random.nextFloat() * 0.25F), 100 + random.nextInt(50))); - } - } - } - - if (this.ticksExisted % 10 == 0) { - { - if (relic.getPoints(stack) > 0) { - ParticleStorage.addParticle(this, new ExperienceParticleData( - new Color(200 + random.nextInt(50), 150 + random.nextInt(100), 0), - x + backgroundWidth + 15 + random.nextInt(16), y + 8 + random.nextInt(10), - 0.15F + (random.nextFloat() * 0.25F), 100 + random.nextInt(50))); - } - } - } - } - - @Override - public void render(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { - LocalPlayer player = MC.player; - - if (stack == null || !(stack.getItem() instanceof IRelicItem relic) || player == null) - return; - - RelicData relicData = relic.getRelicData(); - - if (relicData == null) - return; - - PoseStack pPoseStack = guiGraphics.pose(); - TextureManager manager = MC.getTextureManager(); - - this.renderBackground(guiGraphics); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, TEXTURE); - - manager.bindForSetup(TEXTURE); - - int texWidth = 512; - int texHeight = 512; - - int x = (this.width - backgroundWidth) / 2; - int y = (this.height - backgroundHeight) / 2; - - guiGraphics.blit(TEXTURE, x, y, 0, 0, backgroundWidth, backgroundHeight, texWidth, texHeight); - - int level = relic.getLevel(stack); - - float percentage = relic.getExperience(stack) / (relic.getExperienceBetweenLevels(stack, level, level + 1) / 100F); - - boolean isMaxLevel = relic.isMaxLevel(stack); - - guiGraphics.blit(TEXTURE, x + 30, y + 72, 302, 144, isMaxLevel ? 206 : (int) Math.ceil(percentage / 100F * 206), 3, texWidth, texHeight); - - boolean hoveredRelicExperience = ScreenUtils.isHovered(x + 30, y + 72, 206, 3, pMouseX, pMouseY); - - if (hoveredRelicExperience) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/gui/description/relic_experience_highlight.png")); - - RenderSystem.enableBlend(); - - RenderUtils.renderAnimatedTextureFromCenter(guiGraphics.pose(), x + 133F, y + 73.5F, 210, 98, 210, 7, 1F, AnimationData.builder() - .frame(0, 2) - .frame(1, 2) - .frame(2, 2) - .frame(3, 2) - .frame(4, 2) - .frame(5, 2) - .frame(6, 2) - .frame(7, 2) - .frame(8, 2) - .frame(9, 2) - .frame(10, 2) - .frame(11, 2) - .frame(12, 2) - .frame(13, 2) - ); - - RenderSystem.disableBlend(); - } - - percentage = (player.totalExperience / ((player.totalExperience / player.experienceProgress) / 100F)); - - guiGraphics.blit(TEXTURE, x + 30, y + 85, 302, 148, (int) Math.ceil(percentage / 100F * 206), 3, texWidth, texHeight); - - boolean hoveredVanillaExperience = ScreenUtils.isHovered(x + 30, y + 85, 206, 3, pMouseX, pMouseY); - - if (hoveredVanillaExperience) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/gui/description/experience_highlight.png")); - - RenderSystem.enableBlend(); - - RenderUtils.renderAnimatedTextureFromCenter(guiGraphics.pose(), x + 133F, y + 86.5F, 210, 98, 210, 7, 1F, AnimationData.builder() - .frame(0, 2) - .frame(1, 2) - .frame(2, 2) - .frame(3, 2) - .frame(4, 2) - .frame(5, 2) - .frame(6, 2) - .frame(7, 2) - .frame(8, 2) - .frame(9, 2) - .frame(10, 2) - .frame(11, 2) - .frame(12, 2) - .frame(13, 2) - ); - - RenderSystem.disableBlend(); - } - - ResourceLocation background = relic.getStyleData().getBackground(); - - RenderSystem.setShaderTexture(0, background); - - float color = (float) (0.75F + Math.sin(player.tickCount * 0.1F) * 0.05F); - - RenderSystem.setShaderColor(color, color, color, 1F); - - guiGraphics.blit(background, x + 18, y + 15, 0, 0, 34, 34, 34, 34); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, TEXTURE); - - guiGraphics.blit(TEXTURE, x + 13, y + 10, 302, 5, 46, 55, texWidth, texHeight); - - pPoseStack.pushPose(); - - float scale = 1.5F; - - pPoseStack.translate(x + 23, y + 20, 0); - pPoseStack.scale(scale, scale, scale); - - RenderSystem.setShaderColor(255F, 255F, 255F, 1F); - - guiGraphics.renderItem(stack, 1, 0); - guiGraphics.renderItem(stack, -1, 0); - guiGraphics.renderItem(stack, 0, 1); - guiGraphics.renderItem(stack, 0, -1); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - - guiGraphics.renderItem(stack, 0, 0); - - pPoseStack.popPose(); - - int xOff = 0; - - for (int i = 1; i < relic.getRelicQuality(stack) + 1; i++) { - boolean isAliquot = i % 2 == 1; - - guiGraphics.blit(TEXTURE, x + 15 + xOff, y + 51, 353 + (isAliquot ? 0 : 5), 3, isAliquot ? 5 : 4, 9, texWidth, texHeight); - - xOff += isAliquot ? 5 : 3; - } - - MutableComponent name = Component.literal(stack.getDisplayName().getString() - .replace("[", "").replace("]", "")) - .withStyle(ChatFormatting.BOLD); - - pPoseStack.pushPose(); - - pPoseStack.scale(0.5F, 0.5F, 1F); - - guiGraphics.drawString(MC.font, name, (x + 62) * 2, (y + 21) * 2, 0x412708, false); - - pPoseStack.popPose(); - - pPoseStack.pushPose(); - - pPoseStack.scale(0.75F, 0.75F, 0.75F); - - MutableComponent experience = isMaxLevel ? Component.translatable("tooltip.relics.relic.max_level") : Component.literal(String.valueOf(level)); - - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 135.75F) * 1.33F), ((y + 71) * 1.33F), 0x793300, false); - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 134.25F) * 1.33F), ((y + 71) * 1.33F), 0x793300, false); - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 135) * 1.33F), ((y + 71.75F) * 1.33F), 0x793300, false); - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 135) * 1.33F), ((y + 70.25F) * 1.33F), 0x793300, false); - - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 135) * 1.33F), ((y + 71) * 1.33F), 0xfff500, false); - - experience = Component.literal(String.valueOf(player.experienceLevel)); - - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 135.75F) * 1.33F), ((y + 84) * 1.33F), 0x054503, false); - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 134.25F) * 1.33F), ((y + 84) * 1.33F), 0x054503, false); - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 135) * 1.33F), ((y + 84.75F) * 1.33F), 0x054503, false); - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 135) * 1.33F), ((y + 83.25F) * 1.33F), 0x054503, false); - - ScreenUtils.drawCenteredString(guiGraphics, MC.font, experience, ((x + 135) * 1.33F), ((y + 84) * 1.33F), 0x7efc20, false); - - pPoseStack.popPose(); - - String registryName = ForgeRegistries.ITEMS.getKey(stack.getItem()).getPath(); - - pPoseStack.pushPose(); - - pPoseStack.scale(0.5F, 0.5F, 1F); - - int yOff = 9; - - for (FormattedCharSequence line : MC.font.split(Component.translatable("tooltip.relics." + registryName + ".description"), 350)) { - guiGraphics.drawString(MC.font, line, (x + 62) * 2, (y + 26) * 2 + yOff, 0x412708, false); - - yOff += 9; - } - - pPoseStack.popPose(); - - int points = relic.getPoints(stack); - - if (points > 0) { - pPoseStack.pushPose(); - - MutableComponent value = Component.literal(String.valueOf(points)).withStyle(ChatFormatting.BOLD); - - ResourceLocation icon = new ResourceLocation(Reference.MODID, "textures/gui/description/leveling_point.png"); - - manager.bindForSetup(icon); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, icon); - - guiGraphics.blit(icon, x + backgroundWidth + 5, y - 2, 0, 0, 50, 31, 50, 31); - - guiGraphics.drawString(MC.font, value, x + backgroundWidth + 39 - (MC.font.width(value) / 2), y + 10, 0xffce96); - - pPoseStack.popPose(); - } - - super.render(guiGraphics, pMouseX, pMouseY, pPartialTick); - - if (hoveredRelicExperience) { - pPoseStack.pushPose(); - - pPoseStack.translate(0, 0, 10); - - List tooltip = Lists.newArrayList(); - - int maxWidth = 200; - int renderWidth = 0; - - List entries = Lists.newArrayList( - Component.translatable("tooltip.relics.relic.relic_experience.title").withStyle(ChatFormatting.BOLD) - ); - - if (!isMaxLevel) { - entries.add(Component.literal(" ")); - - entries.add(Component.literal("● ").append(Component.translatable("tooltip.relics.relic.relic_experience.current_amount", relic.getExperience(stack), - relic.getExperienceBetweenLevels(stack, level, level + 1), - MathUtils.round((relic.getExperience(stack) / (relic.getExperienceBetweenLevels(stack, level, level + 1) / 100F)), 1)))); - } - - for (MutableComponent entry : entries) { - int entryWidth = (MC.font.width(entry)) / 2; - - if (entryWidth > renderWidth) - renderWidth = Math.min(entryWidth, maxWidth); - - tooltip.addAll(MC.font.split(entry, maxWidth * 2)); - } - - int height = Math.round(tooltip.size() * 4.5F); - - int renderX = pMouseX - 9 - (renderWidth / 2); - int renderY = y + 77; - - ScreenUtils.drawTexturedTooltipBorder(guiGraphics, new ResourceLocation(Reference.MODID, "textures/gui/tooltip/border/paper.png"), - renderWidth, height, renderX, renderY); - - yOff = 0; - - pPoseStack.scale(0.5F, 0.5F, 0.5F); - - for (FormattedCharSequence entry : tooltip) { - guiGraphics.drawString(MC.font, entry, (renderX + 9) * 2, (renderY + 9 + yOff) * 2, 0x412708, false); - - yOff += 5; - } - - pPoseStack.scale(1F, 1F, 1F); - - pPoseStack.popPose(); - } - - if (hoveredVanillaExperience) { - pPoseStack.pushPose(); - - pPoseStack.translate(0, 0, 10); - - List tooltip = Lists.newArrayList(); - - int maxWidth = 200; - int renderWidth = 0; - - List entries = Lists.newArrayList( - Component.translatable("tooltip.relics.relic.vanilla_experience.title").withStyle(ChatFormatting.BOLD), - Component.literal(" "), - Component.literal("● ").append(Component.translatable("tooltip.relics.relic.vanilla_experience.current_amount", (player.totalExperience - EntityUtils.getTotalExperienceForLevel(player.experienceLevel)), - (EntityUtils.getTotalExperienceForLevel(player.experienceLevel + 1) - EntityUtils.getTotalExperienceForLevel(player.experienceLevel)), - MathUtils.round(player.experienceProgress * 100F, 1))), - Component.literal("● ").append(Component.translatable("tooltip.relics.relic.vanilla_experience.total_amount", player.totalExperience)) - ); - - for (MutableComponent entry : entries) { - int entryWidth = (MC.font.width(entry)) / 2; - - if (entryWidth > renderWidth) - renderWidth = Math.min(entryWidth, maxWidth); - - tooltip.addAll(MC.font.split(entry, maxWidth * 2)); - } - - int height = Math.round(tooltip.size() * 4.5F); - - int renderX = pMouseX - 9 - (renderWidth / 2); - int renderY = y + 90; - - ScreenUtils.drawTexturedTooltipBorder(guiGraphics, new ResourceLocation(Reference.MODID, "textures/gui/tooltip/border/paper.png"), - renderWidth, height, renderX, renderY); - - yOff = 0; - - pPoseStack.scale(0.5F, 0.5F, 0.5F); - - for (FormattedCharSequence entry : tooltip) { - guiGraphics.drawString(MC.font, entry, (renderX + 9) * 2, (renderY + 9 + yOff) * 2, 0x412708, false); - - yOff += 5; - } - - pPoseStack.scale(1F, 1F, 1F); - - pPoseStack.popPose(); - } - - if (points > 0 && ScreenUtils.isHovered(x + backgroundWidth + 5, y - 2, 50, 31, pMouseX, pMouseY)) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/gui/description/leveling_point_highlight.png")); - - RenderSystem.enableBlend(); - - RenderUtils.renderAnimatedTextureFromCenter(guiGraphics.pose(), x + backgroundWidth + 5 + (50 / 2), y - 2 + (31 / 2), 64, 768, 64, 64, 1F, AnimationData.builder() - .frame(0, 2) - .frame(1, 2) - .frame(2, 2) - .frame(3, 2) - .frame(4, 2) - .frame(5, 2) - .frame(6, 2) - .frame(7, 2) - .frame(8, 2) - .frame(9, 2) - .frame(10, 2) - .frame(11, 2) - ); - - RenderSystem.disableBlend(); - - pPoseStack.pushPose(); - - pPoseStack.translate(0, 0, 10); - - List tooltip = Lists.newArrayList(); - - int maxWidth = 200; - int renderWidth = 0; - - List entries = Lists.newArrayList( - Component.translatable("tooltip.relics.relic.leveling_points.title").withStyle(ChatFormatting.BOLD) - ); - - for (MutableComponent entry : entries) { - int entryWidth = (MC.font.width(entry)) / 2; - - if (entryWidth > renderWidth) - renderWidth = Math.min(entryWidth, maxWidth); - - tooltip.addAll(MC.font.split(entry, maxWidth * 2)); - } - - int height = Math.round(tooltip.size() * 4.5F); - - int renderX = pMouseX + 1; - int renderY = pMouseY + 1; - - ScreenUtils.drawTexturedTooltipBorder(guiGraphics, new ResourceLocation(Reference.MODID, "textures/gui/tooltip/border/paper.png"), - renderWidth, height, renderX, renderY); - - yOff = 0; - - pPoseStack.scale(0.5F, 0.5F, 0.5F); - - for (FormattedCharSequence entry : tooltip) { - guiGraphics.drawString(MC.font, entry, (renderX + 9) * 2, (renderY + 9 + yOff) * 2, 0x412708, false); - - yOff += 5; - } - - pPoseStack.scale(1F, 1F, 1F); - - pPoseStack.popPose(); - } - - for (GuiEventListener listener : this.children()) { - if (listener instanceof AbstractButton button && button.isHovered() - && button instanceof IHoverableWidget widget) - widget.onHovered(guiGraphics, pMouseX, pMouseY); - } - } - - @Override - public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) { - if (MC.options.keyInventory.isActiveAndMatches(InputConstants.getKey(pKeyCode, pScanCode))) { - this.onClose(); - - return true; - } - - return super.keyPressed(pKeyCode, pScanCode, pModifiers); - } - - @Override - public boolean isPauseScreen() { - return false; - } - - @Override - public int getAutoScale() { - return 0; - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/AbilityDescriptionScreen.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/AbilityDescriptionScreen.java new file mode 100644 index 00000000..7cf5ff0a --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/AbilityDescriptionScreen.java @@ -0,0 +1,426 @@ +package it.hurts.sskirillss.relics.client.screen.description.ability; + +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.badges.base.AbilityBadge; +import it.hurts.sskirillss.relics.client.screen.base.IAutoScaledScreen; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.IPagedDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import it.hurts.sskirillss.relics.client.screen.description.ability.widgets.*; +import it.hurts.sskirillss.relics.client.screen.description.experience.ExperienceDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.general.misc.DescriptionPage; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.*; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionCache; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.client.screen.description.relic.RelicDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.relic.widgets.RelicExperienceWidget; +import it.hurts.sskirillss.relics.client.screen.utils.ScreenUtils; +import it.hurts.sskirillss.relics.init.BadgeRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +import it.hurts.sskirillss.relics.utils.MathUtils; +import it.hurts.sskirillss.relics.utils.data.AnimationData; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import lombok.Getter; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractButton; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.registries.DeferredHolder; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +@OnlyIn(Dist.CLIENT) +public class AbilityDescriptionScreen extends Screen implements IAutoScaledScreen, IRelicScreenProvider, IPagedDescriptionScreen { + public final Screen screen; + + @Getter + public final int container; + @Getter + public final int slot; + @Getter + public ItemStack stack; + + private final int backgroundHeight = 256; + private final int backgroundWidth = 418; + + public UpgradeAbilityActionWidget upgradeButton; + public RerollAbilityActionWidget rerollButton; + public ResetAbilityActionWidget resetButton; + + public AbilityDescriptionScreen(Player player, int container, int slot, Screen screen) { + super(Component.empty()); + + this.container = container; + this.slot = slot; + this.screen = screen; + + stack = DescriptionUtils.gatherRelicStack(player, slot); + } + + public String getSelectedAbility() { + return DescriptionCache.getSelectedAbility(stack); + } + + public void setSelectedAbility(String ability) { + DescriptionCache.setSelectedAbility(stack, ability); + } + + @Override + protected void init() { + if (stack == null || !(stack.getItem() instanceof IRelicItem relic)) + return; + + var ability = getSelectedAbility(); + + if (relic.getAbilityData(ability) == null) + return; + + updateCache(relic); + + int x = (this.width - backgroundWidth) / 2; + int y = (this.height - backgroundHeight) / 2; + + var sources = relic.getLevelingSourcesData().getSources(); + var abilities = relic.getAbilitiesData().getAbilities().keySet().stream().filter(entry -> relic.isAbilityEnabled(stack, entry)).toList(); + + this.addRenderableWidget(new PageWidget(x + 81, y + 123, this, DescriptionPage.RELIC, new RelicDescriptionScreen(minecraft.player, this.container, this.slot, this.screen))); + + int xOff = 19; + + if (!abilities.isEmpty()) { + this.addRenderableWidget(new PageWidget(x + 81 + xOff, y + 123, this, DescriptionPage.ABILITY, new AbilityDescriptionScreen(minecraft.player, this.container, this.slot, this.screen))); + + xOff += 19; + } + + if (!sources.isEmpty()) + this.addRenderableWidget(new PageWidget(x + 81 + xOff, y + 123, this, DescriptionPage.EXPERIENCE, new ExperienceDescriptionScreen(minecraft.player, this.container, this.slot, this.screen))); + + this.addRenderableWidget(new BigAbilityCardWidget(x + 60, y + 47, this)); + + this.addRenderableWidget(new LogoWidget(x + 313, y + 57, this)); + + if (relic.isSomethingWrongWithLevelingPoints(stack)) + this.addRenderableWidget(new PointsFixWidget(x + 330, y + 33, this)); + + this.addRenderableWidget(new PointsPlateWidget(x + 313, y + 77, this)); + this.addRenderableWidget(new PlayerExperiencePlateWidget(x + 313, y + 102, this)); + this.addRenderableWidget(new LuckPlateWidget(x + 313, y + 127, this)); + + xOff = 0; + + if (relic.isAbilityUnlocked(stack, ability)) { + for (AbilityBadge badge : BadgeRegistry.BADGES.getEntries().stream().map(DeferredHolder::get).filter(entry -> entry instanceof AbilityBadge).map(entry -> (AbilityBadge) entry).toList()) { + if (!badge.isVisible(stack, ability)) + continue; + + this.addRenderableWidget(new AbilityBadgeWidget(x + 270 - xOff, y + 63, this, badge, ability)); + + xOff += 15; + } + } + + if (!abilities.isEmpty()) { + int objectWidth = 32; + int containerWidth = 209; + + int count = Math.min(5, abilities.size()); + + int spacing = objectWidth + 8 + (3 * (5 - count)); + + xOff = (containerWidth / 2) - (((objectWidth * count) + ((spacing - objectWidth) * Math.max(count - 1, 0))) / 2); + + for (String entry : abilities) { + this.addRenderableWidget(new AbilityCardWidget(x + 77 + xOff, y + 153, this, entry)); + + xOff += spacing; + } + } + + this.addRenderableWidget(new RelicExperienceWidget(x + 142, y + 121, this)); + + if (relic.isAbilityUpgradeEnabled(stack, ability)) + this.upgradeButton = this.addRenderableWidget(new UpgradeAbilityActionWidget(x + 288, y + 63, this)); + if (relic.isAbilityRerollEnabled(stack, ability)) + this.rerollButton = this.addRenderableWidget(new RerollAbilityActionWidget(x + 288, y + 80, this)); + if (relic.isAbilityResetEnabled(stack, ability)) + this.resetButton = this.addRenderableWidget(new ResetAbilityActionWidget(x + 288, y + 97, this)); + } + + @Override + public void rebuildWidgets() { + stack = DescriptionUtils.gatherRelicStack(minecraft.player, slot); + + super.rebuildWidgets(); + } + + @Override + public void tick() { + super.tick(); + + stack = DescriptionUtils.gatherRelicStack(minecraft.player, slot); + } + + @Override + public void renderBackground(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + super.renderBackground(guiGraphics, pMouseX, pMouseY, pPartialTick); + + LocalPlayer player = minecraft.player; + + if (stack == null || !(stack.getItem() instanceof IRelicItem relic) || player == null) + return; + + var ability = getSelectedAbility(); + + if (relic.getAbilityData(ability) == null) + return; + + RelicData relicData = relic.getRelicData(); + + if (relicData == null) + return; + + int level = relic.getAbilityLevel(stack, ability); + + PoseStack poseStack = guiGraphics.pose(); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + RenderSystem.setShaderTexture(0, DescriptionTextures.SPACE_BACKGROUND); + + int x = (this.width - backgroundWidth) / 2; + int y = (this.height - backgroundHeight) / 2; + + int yOff = 0; + int xOff = 0; + + GUIRenderer.begin(DescriptionTextures.SPACE_BACKGROUND, poseStack) + .texSize(418, 4096) + .patternSize(backgroundWidth, backgroundHeight) + .pos(x + (backgroundWidth / 2F), y + (backgroundHeight / 2F)) + .animation(AnimationData.builder() + .frame(0, 2).frame(1, 2).frame(2, 2) + .frame(3, 2).frame(4, 2).frame(5, 2) + .frame(6, 2).frame(7, 2).frame(8, 2) + .frame(9, 2).frame(10, 2).frame(11, 2) + .frame(12, 2).frame(13, 2).frame(14, 2) + .frame(15, 2)) + .end(); + + GUIRenderer.begin(DescriptionTextures.TOP_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(x + 107, y + 47) + .end(); + + GUIRenderer.begin(DescriptionTextures.BOTTOM_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(x + 60, y + 133) + .end(); + + poseStack.pushPose(); + + poseStack.scale(0.75F, 0.75F, 1F); + + var title = Component.translatableWithFallback("tooltip.relics." + BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath() + ".ability." + ability, ability); + + if (!relic.isAbilityUnlocked(stack, ability)) { + title = ScreenUtils.stylizeWithReplacement(title, 1F, Style.EMPTY.withFont(ScreenUtils.ILLAGER_ALT_FONT).withColor(0x9E00B0), ability.length()); + + var random = player.getRandom(); + + var shakeX = MathUtils.randomFloat(random) * 0.5F; + var shakeY = MathUtils.randomFloat(random) * 0.5F; + + poseStack.translate(shakeX, shakeY, 0F); + } else + title.withStyle(ChatFormatting.BOLD); + + guiGraphics.drawString(minecraft.font, title, (int) ((x + 113) * 1.33F), (int) ((y + 67) * 1.33F), DescriptionUtils.TEXT_COLOR, false); + + poseStack.popPose(); + + poseStack.pushPose(); + + poseStack.scale(0.5F, 0.5F, 1F); + + yOff = 9; + + if (relic.isAbilityUnlocked(stack, ability)) { + List components = new ArrayList<>(); + + var wantsUpgrade = upgradeButton != null && upgradeButton.isHovered() && relic.mayUpgrade(stack, ability); + var wantsReroll = rerollButton != null && rerollButton.isHovered() && relic.mayReroll(stack, ability); + var wantsReset = resetButton != null && resetButton.isHovered() && relic.mayReset(stack, ability); + + int color = DescriptionUtils.TEXT_COLOR; + + for (var stat : relic.getAbilityData(ability).getStats().values()) { + if (wantsUpgrade) + color = 0x228B22; + + if (wantsReroll) + color = 0xFF8C00; + + if (wantsReset) + color = 0xB22222; + + if (color != DescriptionUtils.TEXT_COLOR) { + var brightness = (float) (0.75F + 0.1F * Math.sin(2 * Math.PI * 0.75F * player.tickCount / 20F)); + + var hsb = Color.RGBtoHSB((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, null); + + hsb[2] = Mth.clamp(brightness, 0F, 1F); + + color = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]); + } + + var value = String.valueOf(stat.getFormatValue().apply(relic.getStatValue(stack, ability, stat.getId(), wantsUpgrade ? level + 1 : wantsReset ? 0 : level))); + var component = Component.literal(value.endsWith(".0") ? value.replace(".0", "") : value).withStyle(ChatFormatting.BOLD); + + components.add(component.withColor(color)); + } + + var pattern = Pattern.compile("([^ .,!?;:]*%(\\d+)\\$s[^ .,!?;:]*)"); + + // This is a crutchy workaround to fix issue caused by other unknown mod, that replaces placeholders without replacements to empty string + List replacements = new ArrayList<>(); + + for (int i = 1; i < 10; i++) + replacements.add("%" + i + "$s"); + + for (var line : font.getSplitter().splitLines(Component.translatable("tooltip.relics." + BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath() + ".ability." + ability + ".description", replacements.toArray()).getString(), 340, Style.EMPTY)) { + String unformattedLine = line.getString().replace("%%", "%"); + + int currentX = (x + 112) * 2; + int currentY = (y + 74) * 2 + yOff; + + var matcher = pattern.matcher(unformattedLine); + + int lastEnd = 0; + + while (matcher.find()) { + String dynamicSegment = matcher.group(1); + + int index = Integer.parseInt(matcher.group(2)) - 1; + + String staticText = unformattedLine.substring(lastEnd, matcher.start()); + + if (!staticText.isEmpty()) { + guiGraphics.drawString(font, staticText, currentX, currentY, DescriptionUtils.TEXT_COLOR, false); + + currentX += font.width(staticText); + } + + if (index >= 0 && index < components.size()) { + MutableComponent dynamicComponent = components.get(index); + + var dynamicValue = Component.literal(dynamicSegment.substring(0, dynamicSegment.indexOf('%')) + dynamicComponent.getString() + dynamicSegment.substring(dynamicSegment.lastIndexOf('s') + 1)).withStyle(dynamicComponent.getStyle()); + + guiGraphics.drawString(font, dynamicValue, currentX + 2, currentY + 1, color, false); + + int frameStartX = currentX - 1; + int frameStartY = currentY - 1; + int frameEndX = currentX + font.width(dynamicValue) + 4; + int frameEndY = currentY + font.lineHeight + 1; + + guiGraphics.fill(frameStartX, frameStartY, frameEndX, frameStartY + 1, 0xFF000000 + color); + guiGraphics.fill(frameStartX, frameEndY - 1, frameEndX, frameEndY, 0xFF000000 + color); + guiGraphics.fill(frameStartX, frameStartY, frameStartX + 1, frameEndY, 0xFF000000 + color); + guiGraphics.fill(frameEndX - 1, frameStartY, frameEndX, frameEndY, 0xFF000000 + color); + + currentX += font.width(dynamicValue) + 3; + + lastEnd = matcher.end(); + } + } + + if (lastEnd < unformattedLine.length()) + guiGraphics.drawString(font, unformattedLine.substring(lastEnd), currentX, currentY, DescriptionUtils.TEXT_COLOR, false); + + yOff += 10; + } + } else { + List placeholders = new ArrayList<>(); + + for (var stat : relic.getAbilityData(ability).getStats().values()) + placeholders.add(stat.getFormatValue().apply(relic.getStatValue(stack, ability, stat.getId(), level))); + + var component = ScreenUtils.stylizeWithReplacement(Component.translatable("tooltip.relics." + BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath() + ".ability." + ability + ".description", placeholders.toArray()), 1F, Style.EMPTY.withFont(ScreenUtils.ILLAGER_ALT_FONT), ability.length()); + + for (FormattedCharSequence line : font.split(component, 340)) { + guiGraphics.drawString(font, line, (x + 112) * 2, (y + 74) * 2 + yOff, 0x662f13, false); + + yOff += 10; + } + } + + poseStack.popPose(); + } + + @Override + public void render(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + super.render(guiGraphics, pMouseX, pMouseY, pPartialTick); + + for (GuiEventListener listener : this.children()) { + if (listener instanceof AbstractButton button && button.isHovered() + && button instanceof IHoverableWidget widget) { + guiGraphics.pose().translate(0, 0, 100); + + widget.onHovered(guiGraphics, pMouseX, pMouseY); + } + } + } + + @Override + public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) { + if (minecraft.options.keyInventory.isActiveAndMatches(InputConstants.getKey(pKeyCode, pScanCode))) { + this.onClose(); + + return true; + } + + return super.keyPressed(pKeyCode, pScanCode, pModifiers); + } + + @Override + public void onClose() { + screen.rebuildWidgets(); + + Minecraft.getInstance().setScreen(screen); + } + + @Override + public boolean isPauseScreen() { + return false; + } + + @Override + public int getAutoScale() { + return 0; + } + + @Override + public DescriptionPage getPage() { + return DescriptionPage.ABILITY; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/AbilityCardWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/AbilityCardWidget.java new file mode 100644 index 00000000..3c1f837b --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/AbilityCardWidget.java @@ -0,0 +1,489 @@ +package it.hurts.sskirillss.relics.client.screen.description.ability.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; +import it.hurts.sskirillss.relics.client.screen.description.ability.AbilityDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractDescriptionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.client.screen.description.relic.particles.ChainParticleData; +import it.hurts.sskirillss.relics.client.screen.description.relic.particles.ExperienceParticleData; +import it.hurts.sskirillss.relics.client.screen.description.relic.particles.SparkParticleData; +import it.hurts.sskirillss.relics.client.screen.description.research.AbilityResearchScreen; +import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; +import it.hurts.sskirillss.relics.client.screen.utils.ScreenUtils; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; +import it.hurts.sskirillss.relics.network.NetworkHandler; +import it.hurts.sskirillss.relics.network.packets.lock.PacketAbilityUnlock; +import it.hurts.sskirillss.relics.utils.MathUtils; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.RenderUtils; +import it.hurts.sskirillss.relics.utils.data.AnimationData; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec2; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; + +public class AbilityCardWidget extends AbstractDescriptionWidget implements IHoverableWidget, ITickingWidget { + private final AbilityDescriptionScreen screen; + private final String ability; + + private float scale = 1F; + private float scaleOld = 1F; + + private int shakeDelta = 0; + private int colorDelta = 0; + + public AbilityCardWidget(int x, int y, AbilityDescriptionScreen screen, String ability) { + super(x, y, 32, 47); + + this.screen = screen; + this.ability = ability; + } + + @Override + public void onPress() { + if (!(screen.getStack().getItem() instanceof IRelicItem relic)) + return; + + ItemStack stack = screen.getStack(); + + boolean isEnoughLevel = relic.isEnoughLevel(stack, ability); + boolean isLockUnlocked = relic.isLockUnlocked(stack, ability); + boolean isAbilityResearched = relic.isAbilityResearched(stack, ability); + + SoundManager soundManager = minecraft.getSoundManager(); + + if (isEnoughLevel) { + if (isLockUnlocked) { + if (isAbilityResearched) { + if (!screen.getSelectedAbility().equals(ability)) { + screen.setSelectedAbility(ability); + + screen.rebuildWidgets(); + + for (var entry : screen.renderables) { + if (!(entry instanceof AbilityCardWidget card) || !card.ability.equals(ability)) + continue; + + card.scale = scale; + card.scaleOld = scaleOld; + + card.shakeDelta = shakeDelta; + card.colorDelta = colorDelta; + } + } + } else + minecraft.setScreen(new AbilityResearchScreen(minecraft.player, screen.container, screen.slot, screen, ability)); + } else { + int unlocks = relic.getLockUnlocks(stack, ability) + 1; + + RandomSource random = minecraft.player.getRandom(); + + for (int i = 0; i < unlocks * 50; i++) { + var center = new Vec2(width / 2F, height / 2F); + var margin = new Vec2(center.x + MathUtils.randomFloat(random) * 7F, center.y + MathUtils.randomFloat(random) * 8.5F); + + var motion = new Vec2(margin.x - center.x, margin.y - center.y).normalized().scale(5F + unlocks); + + ParticleStorage.addParticle(screen, new SparkParticleData(new Color(150 + random.nextInt(100), 100 + random.nextInt(50), 0), + getX() + margin.x, getY() + margin.y, 1F + (random.nextFloat() * 0.5F), 20 + random.nextInt(100)) + .setDeltaX(random.nextFloat() * motion.x) + .setDeltaY(random.nextFloat() * motion.y) + ); + } + + NetworkHandler.sendToServer(new PacketAbilityUnlock(screen.container, screen.slot, ability, unlocks)); + + shakeDelta = Math.min(20, shakeDelta + 5 + random.nextInt(5)); + scale += 0.05F; + + soundManager.play(SimpleSoundInstance.forUI(SoundEvents.ZOMBIE_ATTACK_IRON_DOOR, 1F)); + + if (unlocks >= relic.getMaxLockUnlocks()) { + for (int i = 0; i < 25; i++) { + var center = new Vec2(width / 2F, height / 2F); + var margin = new Vec2(center.x + MathUtils.randomFloat(random) * 7F, center.y + MathUtils.randomFloat(random) * 8.5F); + + var motion = new Vec2(margin.x - center.x, margin.y - center.y).normalized().scale(7.5F); + + ParticleStorage.addParticle(screen, new ChainParticleData(new Color(255, 255, 255), + getX() + margin.x, getY() + margin.y, 1F + (random.nextFloat() * 0.5F), 50 + random.nextInt(20)) + .setDeltaX(random.nextFloat() * motion.x) + .setDeltaY(random.nextFloat() * motion.y) + ); + } + + soundManager.play(SimpleSoundInstance.forUI(SoundEvents.WITHER_BREAK_BLOCK, 1F)); + soundManager.play(SimpleSoundInstance.forUI(SoundEvents.GENERIC_EXPLODE, 1F)); + } + } + } else { + shakeDelta = Math.min(20, shakeDelta + 10); + colorDelta = Math.min(20, colorDelta + 10); + + soundManager.play(SimpleSoundInstance.forUI(SoundEvents.CHAIN_BREAK, 1F)); + } + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + var player = Minecraft.getInstance().player; + + if (player == null || !(screen.stack.getItem() instanceof IRelicItem relic)) + return; + + var stack = screen.getStack(); + + var manager = minecraft.getTextureManager(); + var poseStack = guiGraphics.pose(); + + var unlocks = relic.getLockUnlocks(stack, ability); + + var isEnoughLevel = relic.isEnoughLevel(stack, ability); + var isLockUnlocked = relic.isLockUnlocked(stack, ability); + var isAbilityResearched = relic.isAbilityResearched(stack, ability); + + var canUse = isEnoughLevel && isLockUnlocked && isAbilityResearched; + + var canUpgrade = relic.mayPlayerUpgrade(minecraft.player, stack, ability); + var canResearch = relic.mayResearch(stack, ability); + + var canBeUpgraded = relic.canBeUpgraded(ability); + + var hasAction = canUpgrade || canResearch; + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + RenderSystem.enableBlend(); + + poseStack.pushPose(); + + var partialTicks = minecraft.getTimer().getGameTimeDeltaPartialTick(false); + + var lerpedScale = Mth.lerp(partialTicks, scaleOld, scale); + + poseStack.scale(lerpedScale, lerpedScale, lerpedScale); + + poseStack.translate((getX() + (width / 2F)) / lerpedScale, (getY() + (height / 2F)) / lerpedScale, 0); + + var color = (float) ((canUpgrade ? 0.75F : 1.05F) + (Math.sin((player.tickCount + (ability.length() * 10)) * 0.2F) * 0.1F)); + + if (isLockUnlocked) + GUIRenderer.begin(DescriptionTextures.getAbilityCardTexture(stack, ability), poseStack) + .color(color, color, color, 1F) + .texSize(22, 31) + .scale(1.01F) + .end(); + + if (!canUse) + GUIRenderer.begin(isLockUnlocked ? DescriptionTextures.SMALL_CARD_RESEARCH_BACKGROUND : DescriptionTextures.SMALL_CARD_LOCK_BACKGROUND, poseStack) + .scale(1.01F) + .end(); + + GUIRenderer.begin(canBeUpgraded ? canUse ? DescriptionTextures.SMALL_CARD_FRAME_UNLOCKED_ACTIVE : DescriptionTextures.SMALL_CARD_FRAME_UNLOCKED_INACTIVE : canUse ? DescriptionTextures.SMALL_CARD_FRAME_LOCKED_ACTIVE : DescriptionTextures.SMALL_CARD_FRAME_LOCKED_INACTIVE, poseStack).end(); + + if (isHovered()) + GUIRenderer.begin(DescriptionTextures.SMALL_CARD_FRAME_OUTLINE, poseStack) + .pos(0, 0.5F) + .end(); + + if (isLockUnlocked) { + if (!isAbilityResearched) { + var time = minecraft.player.tickCount + (ability.length() * 10F) + partialTick; + + GUIRenderer.begin(DescriptionTextures.RESEARCH, poseStack) + .pos((float) Math.sin(time * 0.25F), (float) Math.cos(time * 0.25F) + 0.5F) + .patternSize(16, 16) + .animation(AnimationData.builder() + .frame(0, 2).frame(1, 2) + .frame(2, 2).frame(3, 2) + .frame(4, 2).frame(5, 2) + .frame(6, 2).frame(7, 2) + .frame(8, 2).frame(9, 2) + .frame(10, 2).frame(11, 40)) + .end(); + } + } else { + GUIRenderer.begin(isEnoughLevel ? ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/chains_active_" + unlocks + ".png") : DescriptionTextures.CHAINS_INACTIVE, poseStack) + .pos(0, -1) + .end(); + + MutableComponent level = Component.literal(String.valueOf(relic.getAbilityData(ability).getRequiredLevel())).withStyle(ChatFormatting.BOLD); + + color = Math.min(0.75F, colorDelta * 0.04F); + + RenderSystem.setShaderColor(1, 1 - color, 1 - color, 1); + + poseStack.pushPose(); + + if (shakeDelta > 0) + poseStack.mulPose(Axis.ZP.rotation((float) Math.sin((player.tickCount + partialTick) * 0.75F) * ((shakeDelta / 30F) * 0.75F))); + + GUIRenderer.begin(isEnoughLevel ? ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/icons/lock_active_" + unlocks + ".png") : DescriptionTextures.LOCK_INACTIVE, poseStack).end(); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + guiGraphics.drawString(minecraft.font, level, (-(width / 2) + 16) * 2 - minecraft.font.width(level) / 2, (-(height / 2) + 24) * 2, isEnoughLevel ? 0xFFE278 : 0xB7AED9, true); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + poseStack.popPose(); + } + + { + if (canUse) { + if (canUpgrade) { + RenderSystem.setShaderTexture(0, DescriptionTextures.UPGRADE); + + manager.bindForSetup(DescriptionTextures.UPGRADE); + + RenderSystem.enableBlend(); + + RenderUtils.renderAnimatedTextureFromCenter(poseStack, 0, -1, 20, 400, 20, 20, 0.9F + ((float) (Math.sin((player.tickCount + partialTick) * 0.25F) * 0.025F)), AnimationData.builder() + .frame(0, 2).frame(1, 2) + .frame(2, 2).frame(3, 2) + .frame(4, 2).frame(5, 2) + .frame(6, 2).frame(7, 2) + .frame(8, 2).frame(9, 2) + .frame(10, 2).frame(11, 2) + .frame(12, 2).frame(13, 2) + .frame(14, 2).frame(15, 2) + .frame(16, 2).frame(17, 2) + .frame(18, 2).frame(19, 2) + ); + + RenderSystem.disableBlend(); + } + } + } + + { + if (canBeUpgraded && canUse) { + int xOff = 0; + + for (int i = 0; i < 5; i++) { + guiGraphics.blit(DescriptionTextures.SMALL_STAR_HOLE, -(width / 2) + xOff + 4, -(height / 2) + 40, 0, 0, 4, 4, 4, 4); + + xOff += 5; + } + + xOff = 0; + + int quality = relic.getAbilityQuality(screen.stack, ability); + boolean isAliquot = quality % 2 == 1; + + for (int i = 0; i < Math.floor(quality / 2D); i++) { + guiGraphics.blit(DescriptionTextures.SMALL_STAR_ACTIVE, -(width / 2) + xOff + 4, -(height / 2) + 40, 0, 0, 4, 4, 4, 4); + + xOff += 5; + } + + if (isAliquot) + guiGraphics.blit(DescriptionTextures.SMALL_STAR_ACTIVE, -(width / 2) + xOff + 4, -(height / 2) + 40, 0, 0, 2, 4, 4, 4); + } + } + + { + if (canBeUpgraded) { + MutableComponent title = Component.literal(canUse ? String.valueOf(relic.getAbilityLevel(screen.stack, ability)) : "?").withStyle(ChatFormatting.BOLD); + + float textScale = 0.5F; + + poseStack.scale(textScale, textScale, textScale); + + guiGraphics.drawString(minecraft.font, title, -((width + 1) / 2) - (minecraft.font.width(title) / 2) + 16, (-(height / 2) - 19), canUse ? 0xFFE278 : 0xB7AED9, true); + } + } + + RenderSystem.disableBlend(); + + poseStack.popPose(); + } + + @Override + public void onTick() { + if (!(screen.stack.getItem() instanceof IRelicItem relic)) + return; + + float maxScale = 1.15F; + float minScale = 1F; + + RandomSource random = minecraft.player.getRandom(); + + boolean canUpgrade = relic.mayPlayerUpgrade(minecraft.player, screen.stack, ability); + boolean canResearch = relic.mayResearch(screen.stack, ability); + + if (canUpgrade || canResearch) { + if (minecraft.player.tickCount % 7 == 0) + ParticleStorage.addParticle(screen, new ExperienceParticleData(new Color(200 + random.nextInt(50), 150 + random.nextInt(100), 0), + getX() + 5 + random.nextInt(18), getY() + 18, 1F + (random.nextFloat() * 0.5F), 100 + random.nextInt(50))); + } + + scaleOld = scale; + + if (scale > maxScale) + scale = Math.max(minScale, scale - 0.01F); + + if (isHovered()) { + if (minecraft.player.tickCount % 3 == 0) + ParticleStorage.addParticle(screen, new ExperienceParticleData( + new Color(200 + random.nextInt(50), 150 + random.nextInt(100), 0), + getX() + random.nextInt(width), getY() - 1, 1F + (random.nextFloat() * 0.5F), 100 + random.nextInt(50))); + + if (scale < maxScale) + scale = Math.min(maxScale, scale + 0.04F); + } else { + if (scale > minScale) + scale = Math.max(minScale, scale - 0.03F); + } + + if (shakeDelta > 0) + shakeDelta--; + + if (colorDelta > 0) + colorDelta--; + } + + @Override + public boolean isLocked() { + return screen.getSelectedAbility().equals(ability); + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + var stack = screen.stack; + + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + AbilityData data = relic.getAbilityData(ability); + + if (data == null) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + var title = Component.translatableWithFallback("tooltip.relics." + BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath() + ".ability." + ability, ability); + + int maxWidth = 110; + int renderWidth = Math.min((minecraft.font.width(title.withStyle(ChatFormatting.BOLD)) / 2) + 4, maxWidth); + + List entries = new ArrayList<>(); + + entries.add(Component.literal(" ")); + + int level = relic.getRelicLevel(screen.stack); + int requiredLevel = data.getRequiredLevel(); + + if (level < requiredLevel) { + entries.add(Component.literal(" ")); + + entries.add(Component.literal("").append(Component.translatable("tooltip.relics.researching.relic.card.low_level", Component.literal(String.valueOf(requiredLevel)).withStyle(ChatFormatting.BOLD)))); + } else { + if (!relic.isLockUnlocked(screen.stack, ability)) { + entries.add(Component.literal(" ")); + + entries.add(Component.literal("").append(Component.translatable("tooltip.relics.researching.relic.card.ready_to_unlock", Component.literal(String.valueOf(relic.getMaxLockUnlocks() - relic.getLockUnlocks(screen.stack, ability))).withStyle(ChatFormatting.BOLD)))); + } else { + if (!relic.isAbilityResearched(screen.stack, ability)) { + entries.add(Component.literal(" ")); + + entries.add(Component.literal("").append(Component.translatable("tooltip.relics.researching.relic.card.unresearched"))); + } else if (relic.mayPlayerUpgrade(minecraft.player, screen.stack, ability)) { + entries.add(Component.literal(" ")); + + entries.add(Component.literal("").append(Component.translatable("tooltip.relics.researching.relic.card.ready_to_upgrade"))); + } + } + } + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry)) / 2; + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth + 4, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + int height = tooltip.size() * 5; + + int y = getHeight() / 2; + + float partialTicks = minecraft.getTimer().getGameTimeDeltaPartialTick(false); + + float lerpedScale = Mth.lerp(partialTicks, scaleOld, scale); + + poseStack.scale(lerpedScale, lerpedScale, lerpedScale); + + poseStack.translate((getX() + (getWidth() / 2F)) / lerpedScale, (getY() + (getHeight() / 2F)) / lerpedScale, 0); + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, height, -((renderWidth + 19) / 2), y); + + int yOff = 0; + + poseStack.pushPose(); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + if (!relic.isAbilityUnlocked(stack, ability)) { + title = ScreenUtils.stylizeWithReplacement(title, 1F, Style.EMPTY.withFont(ScreenUtils.ILLAGER_ALT_FONT).withColor(0x9E00B0), ability.length()); + + var random = minecraft.player.getRandom(); + + var shakeX = MathUtils.randomFloat(random) * 0.5F; + var shakeY = MathUtils.randomFloat(random) * 0.5F; + + poseStack.translate(shakeX, shakeY, 0F); + + } else + title.withStyle(ChatFormatting.BOLD); + + guiGraphics.drawString(minecraft.font, title, -(minecraft.font.width(title) / 2), ((y + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + poseStack.popPose(); + + for (FormattedCharSequence entry : tooltip) { + poseStack.pushPose(); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + guiGraphics.drawString(minecraft.font, entry, -(minecraft.font.width(entry) / 2), ((y + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + + poseStack.popPose(); + } + } + + @Override + public void playDownSound(SoundManager handler) { + if (!isLocked() && screen.getStack().getItem() instanceof IRelicItem relic && relic.isAbilityUnlocked(screen.stack, ability)) + super.playDownSound(handler); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/BigAbilityCardWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/BigAbilityCardWidget.java new file mode 100644 index 00000000..02fb66f2 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/BigAbilityCardWidget.java @@ -0,0 +1,205 @@ +package it.hurts.sskirillss.relics.client.screen.description.ability.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; +import it.hurts.sskirillss.relics.client.screen.description.ability.AbilityDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractDescriptionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.client.screen.description.research.particles.SmokeParticleData; +import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.MathUtils; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.RandomSource; + +import java.util.List; + +public class BigAbilityCardWidget extends AbstractDescriptionWidget implements IHoverableWidget, ITickingWidget { + private AbilityDescriptionScreen screen; + + public BigAbilityCardWidget(int x, int y, AbilityDescriptionScreen screen) { + super(x, y, 48, 74); + + this.screen = screen; + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + var stack = screen.getStack(); + + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + var player = minecraft.player; + var poseStack = guiGraphics.pose(); + var ability = screen.getSelectedAbility(); + + var isUnlocked = relic.isAbilityUnlocked(stack, ability); + var canBeUpgraded = relic.canBeUpgraded(ability); + + poseStack.pushPose(); + + float color = (float) (1.05F + (Math.sin((player.tickCount + (ability.length() * 10)) * 0.2F) * 0.1F)); + + if (isUnlocked) + GUIRenderer.begin(DescriptionTextures.getAbilityCardTexture(stack, ability), poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .color(color, color, color, 1F) + .pos(getX() + 7, getY() + 10) + .texSize(34, 49) + .end(); + else + GUIRenderer.begin(DescriptionTextures.BIG_CARD_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + 7, getY() + 10) + .end(); + + GUIRenderer.begin(canBeUpgraded ? isUnlocked ? DescriptionTextures.BIG_CARD_FRAME_UNLOCKED_ACTIVE : DescriptionTextures.BIG_CARD_FRAME_UNLOCKED_INACTIVE : isUnlocked ? DescriptionTextures.BIG_CARD_FRAME_LOCKED_ACTIVE : DescriptionTextures.BIG_CARD_FRAME_LOCKED_INACTIVE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX(), getY()) + .end(); + + int xOff = 0; + + if (isUnlocked && canBeUpgraded) { + for (int i = 0; i < 5; i++) { + GUIRenderer.begin(DescriptionTextures.BIG_STAR_HOLE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + xOff + 4, getY() + 63) + .end(); + + xOff += 8; + } + + xOff = 0; + + var quality = relic.getAbilityQuality(stack, ability); + var isAliquot = quality % 2 == 1; + + for (int i = 0; i < Math.floor(quality / 2D); i++) { + GUIRenderer.begin(DescriptionTextures.BIG_STAR_ACTIVE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + xOff + 4, getY() + 63) + .end(); + + xOff += 8; + } + + if (isAliquot) + GUIRenderer.begin(DescriptionTextures.BIG_STAR_ACTIVE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + xOff + 4, getY() + 63) + .patternSize(4, 7) + .texSize(8, 7) + .end(); + } + + if (canBeUpgraded) { + poseStack.pushPose(); + + MutableComponent pointsComponent = Component.literal(isUnlocked ? String.valueOf(relic.getAbilityLevel(stack, ability)) : "?").withStyle(ChatFormatting.BOLD); + + poseStack.scale(0.75F, 0.75F, 1F); + + guiGraphics.drawString(minecraft.font, pointsComponent, (int) (((getX() + 25.5F) * 1.33F) - (minecraft.font.width(pointsComponent) / 2F)), (int) ((getY() + 4) * 1.33F), isUnlocked ? 0xFFE278 : 0xB7AED9, true); + + poseStack.popPose(); + } + + if (isUnlocked && canBeUpgraded && isHovered()) + GUIRenderer.begin(DescriptionTextures.BIG_CARD_FRAME_OUTLINE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() - 1, getY() - 1) + .end(); + + poseStack.popPose(); + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + var stack = screen.getStack(); + var ability = screen.getSelectedAbility(); + + if (!(stack.getItem() instanceof IRelicItem relic) || !relic.isAbilityUnlocked(stack, ability) || !relic.canBeUpgraded(ability)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 150; + int renderWidth = 0; + + List entries = Lists.newArrayList( + Component.literal("").append(Component.translatable("tooltip.relics.researching.ability.info.level").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.UNDERLINE)).append(" " + relic.getAbilityLevel(stack, ability) + "/" + relic.getAbilityData(ability).getMaxLevel()), + Component.literal("").append(Component.translatable("tooltip.relics.researching.ability.info.quality").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.UNDERLINE)).append(" " + MathUtils.round(relic.getAbilityQuality(stack, ability) / 2F, 1) + "/" + relic.getMaxQuality() / 2), + Component.literal(" ") + ); + + if (Screen.hasShiftDown()) + entries.add(Component.translatable("tooltip.relics.researching.ability.info.extra_info").withStyle(ChatFormatting.ITALIC)); + else + entries.add(Component.translatable("tooltip.relics.researching.general.extra_info")); + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) / 2); + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth + 2, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + poseStack.pushPose(); + + poseStack.translate(0F, 0F, 400); + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, tooltip.size() * 5, mouseX - 9 - (renderWidth / 2), mouseY); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + int yOff = 0; + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, ((mouseX - renderWidth / 2) + 1) * 2, ((mouseY + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.popPose(); + } + + @Override + public void onTick() { + var stack = screen.getStack(); + var ability = screen.getSelectedAbility(); + + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + var isUnlocked = relic.isAbilityUnlocked(stack, ability); + + if (!isUnlocked) { + RandomSource random = minecraft.player.getRandom(); + + ParticleStorage.addParticle(screen, new SmokeParticleData(getX() + 11 + random.nextInt(27), getY() + 15 + random.nextInt(43), 0.75F + (random.nextFloat() * 0.25F), 20 + random.nextInt(40), 0.5F) + .setDeltaX(MathUtils.randomFloat(random) * 0.1F).setDeltaY(MathUtils.randomFloat(random) * 0.1F)); + } + } + + @Override + public void playDownSound(SoundManager handler) { + + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/RerollAbilityActionWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/RerollAbilityActionWidget.java new file mode 100644 index 00000000..3da88cb0 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/RerollAbilityActionWidget.java @@ -0,0 +1,149 @@ +package it.hurts.sskirillss.relics.client.screen.description.ability.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.description.ability.widgets.base.AbstractAbilityActionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.client.screen.description.ability.AbilityDescriptionScreen; +import it.hurts.sskirillss.relics.init.SoundRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; +import it.hurts.sskirillss.relics.network.NetworkHandler; +import it.hurts.sskirillss.relics.network.packets.leveling.PacketRelicTweak; +import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; + +import java.util.List; + +public class RerollAbilityActionWidget extends AbstractAbilityActionWidget { + public RerollAbilityActionWidget(int x, int y, AbilityDescriptionScreen screen) { + super(x, y, PacketRelicTweak.Operation.REROLL, screen); + } + + @Override + public boolean isLocked() { + return !(getScreen().getStack().getItem() instanceof IRelicItem relic) || !relic.mayPlayerReroll(minecraft.player, getScreen().getStack(), getAbility()); + } + + @Override + public void playDownSound(SoundManager handler) { + if (isLocked() || !(getScreen().getStack().getItem() instanceof IRelicItem relic) + || (relic.getAbilityQuality(getScreen().getStack(), getAbility()) == relic.getMaxQuality() && !Screen.hasShiftDown())) + return; + + handler.play(SimpleSoundInstance.forUI(SoundRegistry.TABLE_REROLL.get(), 1F)); + } + + @Override + public void onPress() { + if (isLocked() || !(getScreen().getStack().getItem() instanceof IRelicItem relic)) + return; + + boolean hasWarning = relic.getAbilityQuality(getScreen().getStack(), getAbility()) == relic.getMaxQuality(); + + if (hasWarning && !Screen.hasShiftDown()) + return; + + NetworkHandler.sendToServer(new PacketRelicTweak(getScreen().getContainer(), getScreen().getSlot(), getAbility(), PacketRelicTweak.Operation.REROLL, !hasWarning && Screen.hasShiftDown())); + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + if (!(getScreen().getStack().getItem() instanceof IRelicItem relic)) + return; + + boolean isWarning = relic.getAbilityQuality(getScreen().getStack(), getAbility()) == relic.getMaxQuality(); + boolean isQuick = Screen.hasShiftDown() && relic.mayPlayerReroll(minecraft.player, getScreen().getStack(), getAbility()); + + float color = (isWarning && Screen.hasShiftDown()) || isQuick ? (float) (1.05F + (Math.sin((minecraft.player.tickCount + (getAbility().length() * 10)) * 0.5F) * 0.1F)) : 1F; + + RenderSystem.setShaderColor(color, color, color, 1F); + + guiGraphics.blit(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/ability/reroll_button" + (isLocked() ? "_inactive" : "_active" + (isWarning ? "_warning" : isQuick ? "_quick" : "")) + ".png"), getX(), getY(), 0, 0, width, height, width, height); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + if (isHovered) + guiGraphics.blit(DescriptionTextures.ACTION_BUTTON_OUTLINE, getX(), getY(), 0, 0, width, height, width, height); + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + if (!(getScreen().getStack().getItem() instanceof IRelicItem relic) || !relic.isAbilityUnlocked(getScreen().getStack(), getAbility())) + return; + + AbilityData data = relic.getAbilityData(getAbility()); + + if (data.getStats().isEmpty()) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 100; + int renderWidth = 0; + + int requiredLevel = relic.getRerollRequiredLevel(getScreen().getStack(), getAbility()); + + int level = minecraft.player.experienceLevel; + + MutableComponent negativeStatus = Component.translatable("tooltip.relics.relic.status.negative"); + MutableComponent positiveStatus = Component.translatable("tooltip.relics.relic.status.positive"); + MutableComponent unknownStatus = Component.translatable("tooltip.relics.relic.status.unknown"); + + boolean isQuick = relic.mayPlayerReroll(minecraft.player, getScreen().getStack(), getAbility()) && relic.getAbilityQuality(getScreen().getStack(), getAbility()) != relic.getMaxQuality(); + + List entries = Lists.newArrayList( + Component.translatable("tooltip.relics.relic.reroll.description").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.UNDERLINE), + Component.literal(" "), + Component.translatable("tooltip.relics.relic.reroll.cost", isQuick && Screen.hasShiftDown() ? Component.literal("XXX").withStyle(ChatFormatting.OBFUSCATED) : requiredLevel, (requiredLevel > level ? negativeStatus : isQuick && Screen.hasShiftDown() ? unknownStatus : positiveStatus)) + ); + + if (relic.getAbilityQuality(getScreen().getStack(), getAbility()) == relic.getMaxQuality()) { + entries.add(Component.literal(" ")); + entries.add(Component.literal("▶ ").append(Component.translatable("tooltip.relics.relic.reroll.warning"))); + } else if (relic.mayPlayerReroll(minecraft.player, getScreen().getStack(), getAbility())) { + entries.add(Component.literal(" ")); + entries.add(Component.literal("▶ ").append(Component.translatable("tooltip.relics.relic.reroll.quick"))); + } + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) + 4) / 2; + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + int height = Math.round(tooltip.size() * 5F); + + int renderX = getX() + width + 1; + int renderY = mouseY - (height / 2) - 9; + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, height, renderX, renderY); + + int yOff = 0; + + poseStack.scale(0.5F, 0.5F, 0.5F); + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, (renderX + 10) * 2, (renderY + 9 + yOff) * 2, DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.scale(1F, 1F, 1F); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/ResetAbilityActionWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/ResetAbilityActionWidget.java new file mode 100644 index 00000000..9d9d1bf1 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/ResetAbilityActionWidget.java @@ -0,0 +1,100 @@ +package it.hurts.sskirillss.relics.client.screen.description.ability.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.description.ability.widgets.base.AbstractAbilityActionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.client.screen.description.ability.AbilityDescriptionScreen; +import it.hurts.sskirillss.relics.init.SoundRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; +import it.hurts.sskirillss.relics.network.packets.leveling.PacketRelicTweak; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; + +import java.util.List; + +public class ResetAbilityActionWidget extends AbstractAbilityActionWidget { + public ResetAbilityActionWidget(int x, int y, AbilityDescriptionScreen screen) { + super(x, y, PacketRelicTweak.Operation.RESET, screen); + } + + @Override + public boolean isLocked() { + return !(getScreen().getStack().getItem() instanceof IRelicItem relic) || !relic.mayPlayerReset(minecraft.player, getScreen().getStack(), getAbility()); + } + + @Override + public void playDownSound(SoundManager handler) { + if (!isLocked()) + handler.play(SimpleSoundInstance.forUI(SoundRegistry.TABLE_RESET.get(), 1F)); + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + if (!(getScreen().getStack().getItem() instanceof IRelicItem relic) || !relic.isAbilityUnlocked(getScreen().getStack(), getAbility())) + return; + + AbilityData data = relic.getAbilityData(getAbility()); + + if (data.getStats().isEmpty()) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 100; + int renderWidth = 0; + + int requiredLevel = relic.getResetRequiredLevel(getScreen().getStack(), getAbility()); + + int level = minecraft.player.experienceLevel; + + MutableComponent negativeStatus = Component.translatable("tooltip.relics.relic.status.negative"); + MutableComponent positiveStatus = Component.translatable("tooltip.relics.relic.status.positive"); + + List entries = Lists.newArrayList( + Component.translatable("tooltip.relics.relic.reset.description").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.UNDERLINE), + Component.literal(" ")); + + if (relic.getAbilityLevel(getScreen().getStack(), getAbility()) > 0) + entries.add(Component.translatable("tooltip.relics.relic.reset.cost", requiredLevel, + (requiredLevel > level ? negativeStatus : positiveStatus))); + else + entries.add(Component.translatable("tooltip.relics.relic.reset.locked")); + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) + 4) / 2; + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + int height = Math.round(tooltip.size() * 5F); + + int renderX = getX() + width + 1; + int renderY = mouseY - (height / 2) - 9; + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, height, renderX, renderY); + + int yOff = 0; + + poseStack.scale(0.5F, 0.5F, 0.5F); + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, (renderX + 10) * 2, (renderY + 9 + yOff) * 2, DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.scale(1F, 1F, 1F); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/UpgradeAbilityActionWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/UpgradeAbilityActionWidget.java new file mode 100644 index 00000000..3d668fd0 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/UpgradeAbilityActionWidget.java @@ -0,0 +1,142 @@ +package it.hurts.sskirillss.relics.client.screen.description.ability.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.description.ability.widgets.base.AbstractAbilityActionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.client.screen.description.ability.AbilityDescriptionScreen; +import it.hurts.sskirillss.relics.init.SoundRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; +import it.hurts.sskirillss.relics.network.packets.leveling.PacketRelicTweak; +import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; + +import java.util.List; + +public class UpgradeAbilityActionWidget extends AbstractAbilityActionWidget { + public UpgradeAbilityActionWidget(int x, int y, AbilityDescriptionScreen screen) { + super(x, y, PacketRelicTweak.Operation.UPGRADE, screen); + } + + @Override + public boolean isLocked() { + return !(getScreen().getStack().getItem() instanceof IRelicItem relic) || !relic.mayPlayerUpgrade(minecraft.player, getScreen().getStack(), getAbility()); + } + + @Override + public void playDownSound(SoundManager handler) { + if (getScreen().getStack().getItem() instanceof IRelicItem relic && !isLocked()) { + int level = relic.getAbilityLevel(getScreen().getStack(), getAbility()); + int maxLevel = relic.getAbilityData(getAbility()).getMaxLevel(); + + handler.play(SimpleSoundInstance.forUI(SoundRegistry.TABLE_UPGRADE.get(), Screen.hasShiftDown() && relic.mayPlayerUpgrade(minecraft.player, getScreen().getStack(), getAbility()) ? 2F : 1F + ((float) level / maxLevel))); + } + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + if (!(getScreen().getStack().getItem() instanceof IRelicItem relic)) + return; + + boolean isQuick = Screen.hasShiftDown() && relic.mayPlayerUpgrade(minecraft.player, getScreen().getStack(), getAbility()); + + float color = isQuick ? (float) (1.05F + (Math.sin((minecraft.player.tickCount + (getAbility().length() * 10)) * 0.5F) * 0.1F)) : 1F; + + RenderSystem.setShaderColor(color, color, color, 1F); + + guiGraphics.blit(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/ability/upgrade_button_" + (isLocked() ? "inactive" : "active") + (isQuick ? "_quick" : "") + ".png"), getX(), getY(), 0, 0, width, height, width, height); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + if (isHovered) + guiGraphics.blit(DescriptionTextures.ACTION_BUTTON_OUTLINE, getX(), getY(), 0, 0, width, height, width, height); + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + if (!(getScreen().getStack().getItem() instanceof IRelicItem relic) || !relic.isAbilityUnlocked(getScreen().getStack(), getAbility())) + return; + + AbilityData data = relic.getAbilityData(getAbility()); + + if (data.getStats().isEmpty()) + return; + + List tooltip = Lists.newArrayList(); + + PoseStack poseStack = guiGraphics.pose(); + + int maxWidth = 100; + int renderWidth = 0; + + int requiredPoints = data.getRequiredPoints(); + int requiredLevel = relic.getUpgradeRequiredLevel(getScreen().getStack(), getAbility()); + + int points = relic.getRelicLevelingPoints(getScreen().getStack()); + int level = minecraft.player.experienceLevel; + + MutableComponent negativeStatus = Component.translatable("tooltip.relics.relic.status.negative"); + MutableComponent positiveStatus = Component.translatable("tooltip.relics.relic.status.positive"); + + List entries = Lists.newArrayList(Component.translatable("tooltip.relics.relic.upgrade.description").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.UNDERLINE)); + + boolean isMaxLevel = relic.isAbilityMaxLevel(getScreen().getStack(), getAbility()); + boolean isQuick = Screen.hasShiftDown() && relic.mayPlayerUpgrade(minecraft.player, getScreen().getStack(), getAbility()); + + if (!isMaxLevel) { + entries.add(Component.literal(" ")); + entries.add(Component.translatable("tooltip.relics.relic.upgrade.cost", isQuick ? Component.literal("XXX").withStyle(ChatFormatting.OBFUSCATED) : requiredPoints, + (requiredPoints > points ? negativeStatus : positiveStatus), isQuick ? Component.literal("XXX").withStyle(ChatFormatting.OBFUSCATED) : requiredLevel, + (requiredLevel > level ? negativeStatus : positiveStatus))); + } + + if (!isLocked()) { + entries.add(Component.literal(" ")); + entries.add(Component.literal("▶ ").append(Component.translatable("tooltip.relics.relic.upgrade.quick"))); + } + + if (isMaxLevel) { + entries.add(Component.literal(" ")); + entries.add(Component.literal("▶ ").append(Component.translatable("tooltip.relics.relic.upgrade.locked"))); + } + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) + 4) / 2; + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + int height = Math.round(tooltip.size() * 5F); + + int renderX = getX() + width + 1; + int renderY = mouseY - (height / 2) - 9; + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, height, renderX, renderY); + + int yOff = 0; + + poseStack.scale(0.5F, 0.5F, 0.5F); + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, (renderX + 10) * 2, (renderY + 9 + yOff) * 2, DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.scale(1F, 1F, 1F); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/base/AbstractAbilityActionWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/base/AbstractAbilityActionWidget.java new file mode 100644 index 00000000..25a4e14f --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/ability/widgets/base/AbstractAbilityActionWidget.java @@ -0,0 +1,76 @@ +package it.hurts.sskirillss.relics.client.screen.description.ability.widgets.base; + +import com.mojang.blaze3d.systems.RenderSystem; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractDescriptionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.ability.AbilityDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.relic.particles.ExperienceParticleData; +import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; +import it.hurts.sskirillss.relics.network.NetworkHandler; +import it.hurts.sskirillss.relics.network.packets.leveling.PacketRelicTweak; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.Getter; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.RandomSource; + +import java.awt.*; +import java.util.Locale; + +public abstract class AbstractAbilityActionWidget extends AbstractDescriptionWidget implements IHoverableWidget, ITickingWidget { + @Getter + private final PacketRelicTweak.Operation operation; + @Getter + private final AbilityDescriptionScreen screen; + + public AbstractAbilityActionWidget(int x, int y, PacketRelicTweak.Operation operation, AbilityDescriptionScreen screen) { + super(x, y, 14, 13); + + this.operation = operation; + this.screen = screen; + } + + @Override + public abstract boolean isLocked(); + + public String getAbility() { + return screen.getSelectedAbility(); + } + + @Override + public void onPress() { + if (!isLocked()) + NetworkHandler.sendToServer(new PacketRelicTweak(getScreen().getContainer(), getScreen().getSlot(), getAbility(), operation, Screen.hasShiftDown())); + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + String actionId = operation.toString().toLowerCase(Locale.ROOT); + + guiGraphics.blit(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/ability/" + actionId + "_button_" + (isLocked() ? "inactive" : "active") + ".png"), getX(), getY(), 0, 0, width, height, width, height); + + if (isHovered) + guiGraphics.blit(DescriptionTextures.ACTION_BUTTON_OUTLINE, getX(), getY(), 0, 0, width, height, width, height); + } + + @Override + public void onTick() { + if (minecraft.player == null) + return; + + RandomSource random = minecraft.player.getRandom(); + + if (!isHovered() || minecraft.player.tickCount % 5 != 0) + return; + + ParticleStorage.addParticle((Screen) screen, new ExperienceParticleData( + new Color(200 + random.nextInt(50), 150 + random.nextInt(100), 0), + getX() + random.nextInt(width), getY() + random.nextInt(height / 4), + 1F + (random.nextFloat() * 0.25F), 50 + random.nextInt(50))); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/data/ExperienceParticleData.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/data/ExperienceParticleData.java deleted file mode 100644 index 9f8d5b8f..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/data/ExperienceParticleData.java +++ /dev/null @@ -1,60 +0,0 @@ -package it.hurts.sskirillss.relics.client.screen.description.data; - -import com.mojang.blaze3d.systems.RenderSystem; -import it.hurts.sskirillss.relics.client.screen.description.data.base.ParticleData; -import it.hurts.sskirillss.relics.utils.Reference; -import it.hurts.sskirillss.relics.utils.RenderUtils; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.RandomSource; -import org.lwjgl.opengl.GL11; - -import java.awt.*; - -public class ExperienceParticleData extends ParticleData { - private static final ResourceLocation TEXTURE = new ResourceLocation(Reference.MODID, "textures/gui/description/experience_particle.png"); - - public ExperienceParticleData(Color color, float xStart, float yStart, float scale, int lifeTime) { - super(TEXTURE, color, xStart, yStart, scale, lifeTime); - } - - @Override - public void tick(Screen screen) { - LocalPlayer player = screen.getMinecraft().player; - - if (player == null) - return; - - RandomSource random = player.getRandom(); - - setX((float) (getX() + (Math.sin(getLifeTime() * 0.15F) * (0.1F + (random.nextFloat() * 0.25F))))); - setY(getY() - 0.2F); - } - - @Override - public void render(Screen screen, GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { - Minecraft MC = screen.getMinecraft(); - - float lifePercentage = 1F - ((getMaxLifeTime() - getLifeTime()) / 100F); - - RenderSystem.setShaderColor(getColor().getRed() / 255F, getColor().getGreen() / 255F, getColor().getBlue() / 255F, 1F * lifePercentage); - RenderSystem.setShaderTexture(0, getTexture()); - - RenderSystem.enableBlend(); - RenderSystem.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); - - MC.getTextureManager().getTexture(getTexture()).setBlurMipmap(true, false); - - RenderUtils.renderTextureFromCenter(guiGraphics.pose(), getX(), getY(), 8, 8, getScale() * lifePercentage); - - MC.getTextureManager().getTexture(getTexture()).restoreLastBlurMipmap(); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - - RenderSystem.defaultBlendFunc(); - RenderSystem.disableBlend(); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/ExperienceDescriptionScreen.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/ExperienceDescriptionScreen.java new file mode 100644 index 00000000..0b51c9cd --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/ExperienceDescriptionScreen.java @@ -0,0 +1,399 @@ +package it.hurts.sskirillss.relics.client.screen.description.experience; + +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.base.IAutoScaledScreen; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.IPagedDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import it.hurts.sskirillss.relics.client.screen.description.ability.AbilityDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.experience.widgets.BigExperienceCardWidget; +import it.hurts.sskirillss.relics.client.screen.description.experience.widgets.ExperienceGemWidget; +import it.hurts.sskirillss.relics.client.screen.description.experience.widgets.ResetExperienceActionWidget; +import it.hurts.sskirillss.relics.client.screen.description.experience.widgets.UpgradeExperienceActionWidget; +import it.hurts.sskirillss.relics.client.screen.description.general.misc.DescriptionPage; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.*; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionCache; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.client.screen.description.relic.RelicDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.relic.widgets.RelicExperienceWidget; +import it.hurts.sskirillss.relics.client.screen.utils.ScreenUtils; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.MathUtils; +import it.hurts.sskirillss.relics.utils.data.AnimationData; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import lombok.Getter; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractButton; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.regex.Pattern; + +@OnlyIn(Dist.CLIENT) +public class ExperienceDescriptionScreen extends Screen implements IAutoScaledScreen, IRelicScreenProvider, IPagedDescriptionScreen { + public final Screen screen; + + @Getter + public final int container; + @Getter + public final int slot; + @Getter + public ItemStack stack; + + private final int backgroundHeight = 256; + private final int backgroundWidth = 418; + + public UpgradeExperienceActionWidget upgradeButton; + public ResetExperienceActionWidget resetButton; + + public ExperienceDescriptionScreen(Player player, int container, int slot, Screen screen) { + super(Component.empty()); + + this.container = container; + this.slot = slot; + this.screen = screen; + + stack = DescriptionUtils.gatherRelicStack(player, slot); + } + + public String getSelectedSource() { + return DescriptionCache.getSelectedExperienceSource(stack); + } + + public void setSelectedSource(String source) { + DescriptionCache.setSelectedExperienceSource(stack, source); + } + + @Override + protected void init() { + if (stack == null || !(stack.getItem() instanceof IRelicItem relic)) + return; + + var source = getSelectedSource(); + + if (relic.getLevelingSourceData(source) == null) + return; + + updateCache(relic); + + int x = (this.width - backgroundWidth) / 2; + int y = (this.height - backgroundHeight) / 2; + + var sources = relic.getLevelingSourcesData().getSources().keySet().stream().filter(entry -> relic.isLevelingSourceEnabled(stack, entry)).toList(); + var abilities = relic.getAbilitiesData().getAbilities().keySet().stream().filter(entry -> relic.isAbilityEnabled(stack, entry)).toList(); + + this.addRenderableWidget(new PageWidget(x + 81, y + 123, this, DescriptionPage.RELIC, new RelicDescriptionScreen(minecraft.player, this.container, this.slot, this.screen))); + + int xOff = 19; + + if (!abilities.isEmpty()) { + this.addRenderableWidget(new PageWidget(x + 81 + xOff, y + 123, this, DescriptionPage.ABILITY, new AbilityDescriptionScreen(minecraft.player, this.container, this.slot, this.screen))); + + xOff += 19; + } + + if (!sources.isEmpty()) + this.addRenderableWidget(new PageWidget(x + 81 + xOff, y + 123, this, DescriptionPage.EXPERIENCE, new ExperienceDescriptionScreen(minecraft.player, this.container, this.slot, this.screen))); + + this.addRenderableWidget(new BigExperienceCardWidget(x + 60, y + 47, this)); + + this.addRenderableWidget(new LogoWidget(x + 313, y + 57, this)); + + if (relic.isSomethingWrongWithLevelingPoints(stack)) + this.addRenderableWidget(new PointsFixWidget(x + 330, y + 33, this)); + + this.addRenderableWidget(new PointsPlateWidget(x + 313, y + 77, this)); + this.addRenderableWidget(new PlayerExperiencePlateWidget(x + 313, y + 102, this)); + this.addRenderableWidget(new LuckPlateWidget(x + 313, y + 127, this)); + + if (!sources.isEmpty()) { + int objectWidth = 32; + int containerWidth = 209; + + int count = Math.min(5, sources.size()); + + int spacing = objectWidth + 8 + (3 * (5 - count)); + + xOff = (containerWidth / 2) - (((objectWidth * count) + ((spacing - objectWidth) * Math.max(count - 1, 0))) / 2); + + for (String entry : sources) { + this.addRenderableWidget(new ExperienceGemWidget(x + 77 + xOff, y + 153, this, entry)); + + xOff += spacing; + } + } + + this.addRenderableWidget(new RelicExperienceWidget(x + 142, y + 121, this)); + + if (relic.isLevelingSourceUnlocked(stack, source)) { + this.upgradeButton = this.addRenderableWidget(new UpgradeExperienceActionWidget(x + 288, y + 70, this)); + this.resetButton = this.addRenderableWidget(new ResetExperienceActionWidget(x + 288, y + 90, this)); + } + } + + @Override + public void rebuildWidgets() { + stack = DescriptionUtils.gatherRelicStack(minecraft.player, slot); + + super.rebuildWidgets(); + } + + @Override + public void tick() { + super.tick(); + + stack = DescriptionUtils.gatherRelicStack(minecraft.player, slot); + } + + @Override + public void renderBackground(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + super.renderBackground(guiGraphics, pMouseX, pMouseY, pPartialTick); + + var player = minecraft.player; + + if (stack == null || !(stack.getItem() instanceof IRelicItem relic) || player == null) + return; + + var source = getSelectedSource(); + var sourceData = relic.getLevelingSourceData(source); + + if (sourceData == null) + return; + + PoseStack poseStack = guiGraphics.pose(); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + RenderSystem.setShaderTexture(0, DescriptionTextures.SPACE_BACKGROUND); + + int x = (this.width - backgroundWidth) / 2; + int y = (this.height - backgroundHeight) / 2; + + int yOff = 0; + int xOff = 0; + + GUIRenderer.begin(DescriptionTextures.SPACE_BACKGROUND, poseStack) + .texSize(418, 4096) + .patternSize(backgroundWidth, backgroundHeight) + .pos(x + (backgroundWidth / 2F), y + (backgroundHeight / 2F)) + .animation(AnimationData.builder() + .frame(0, 2).frame(1, 2).frame(2, 2) + .frame(3, 2).frame(4, 2).frame(5, 2) + .frame(6, 2).frame(7, 2).frame(8, 2) + .frame(9, 2).frame(10, 2).frame(11, 2) + .frame(12, 2).frame(13, 2).frame(14, 2) + .frame(15, 2)) + .end(); + + GUIRenderer.begin(DescriptionTextures.BIG_CARD_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(x + 67, y + 57) + .end(); + + GUIRenderer.begin(DescriptionTextures.TOP_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(x + 107, y + 47) + .end(); + + GUIRenderer.begin(DescriptionTextures.BOTTOM_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(x + 60, y + 133) + .end(); + + poseStack.pushPose(); + + poseStack.scale(0.75F, 0.75F, 1F); + + var title = Component.translatableWithFallback(sourceData.getTranslationPath().apply(stack) + ".title", source); + + if (!relic.isLevelingSourceUnlocked(stack, source)) { + title = ScreenUtils.stylizeWithReplacement(title, 1F, Style.EMPTY.withFont(ScreenUtils.ILLAGER_ALT_FONT).withColor(0x9E00B0), source.length()); + + var random = player.getRandom(); + + var shakeX = MathUtils.randomFloat(random) * 0.5F; + var shakeY = MathUtils.randomFloat(random) * 0.5F; + + poseStack.translate(shakeX, shakeY, 0F); + } else + title.withStyle(ChatFormatting.BOLD); + + guiGraphics.drawString(minecraft.font, title, (int) ((x + 113) * 1.33F), (int) ((y + 67) * 1.33F), DescriptionUtils.TEXT_COLOR, false); + + poseStack.popPose(); + + poseStack.pushPose(); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + yOff = 9; + + var ability = sourceData.getRequiredAbility(); + + title = Component.literal("«").append(ability.isEmpty() ? title : Component.translatableWithFallback("tooltip.relics." + BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath() + ".ability." + ability, ability)).append("»").withStyle(ChatFormatting.BOLD); + + if (relic.isLevelingSourceUnlocked(stack, source)) { + List components = new ArrayList<>(); + + var wantsUpgrade = upgradeButton != null && upgradeButton.isHovered(); + var wantsReset = resetButton != null && resetButton.isHovered(); + + int color = DescriptionUtils.TEXT_COLOR; + + var component = Component.literal(String.valueOf(relic.getLevelingSourceData(source).getInitialValue())).withStyle(ChatFormatting.BOLD); + + if (wantsUpgrade) + color = 0x228B22; + + if (wantsReset) + color = 0xB22222; + + if (color != DescriptionUtils.TEXT_COLOR) { + var brightness = (float) (0.75F + 0.1F * Math.sin(2 * Math.PI * 0.75F * player.tickCount / 20F)); + + var hsb = Color.RGBtoHSB((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, null); + + hsb[2] = Mth.clamp(brightness, 0F, 1F); + + color = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]); + } + + components.add(component.withColor(color)); + + var pattern = Pattern.compile("([^ .,!?;:]*%(1)\\$s[^ .,!?;:]*)"); + + for (var line : font.getSplitter().splitLines(Component.translatable(sourceData.getTranslationPath().apply(stack) + ".description", "%1$s", title), 340, Style.EMPTY)) { + String unformattedLine = line.getString().replace("%%", "%"); + + int currentX = (x + 112) * 2; + int currentY = (y + 74) * 2 + yOff; + + var matcher = pattern.matcher(unformattedLine); + + int lastEnd = 0; + + while (matcher.find()) { + String dynamicSegment = matcher.group(1); + + int index = Integer.parseInt(matcher.group(2)) - 1; + + String staticText = unformattedLine.substring(lastEnd, matcher.start()); + + if (!staticText.isEmpty()) { + guiGraphics.drawString(font, staticText, currentX, currentY, DescriptionUtils.TEXT_COLOR, false); + + currentX += font.width(staticText); + } + + if (index >= 0 && index < components.size()) { + MutableComponent dynamicComponent = components.get(index); + + var dynamicValue = Component.literal(dynamicSegment.substring(0, dynamicSegment.indexOf('%')) + dynamicComponent.getString() + dynamicSegment.substring(dynamicSegment.lastIndexOf('s') + 1)).withStyle(dynamicComponent.getStyle()); + + guiGraphics.drawString(font, dynamicValue, currentX + 2, currentY + 1, color, false); + + int frameStartX = currentX - 1; + int frameStartY = currentY - 1; + int frameEndX = currentX + font.width(dynamicValue) + 4; + int frameEndY = currentY + font.lineHeight + 1; + + guiGraphics.fill(frameStartX, frameStartY, frameEndX, frameStartY + 1, 0xFF000000 + color); + guiGraphics.fill(frameStartX, frameEndY - 1, frameEndX, frameEndY, 0xFF000000 + color); + guiGraphics.fill(frameStartX, frameStartY, frameStartX + 1, frameEndY, 0xFF000000 + color); + guiGraphics.fill(frameEndX - 1, frameStartY, frameEndX, frameEndY, 0xFF000000 + color); + + currentX += font.width(dynamicValue) + 3; + + lastEnd = matcher.end(); + } + } + + if (lastEnd < unformattedLine.length()) + guiGraphics.drawString(font, unformattedLine.substring(lastEnd), currentX, currentY, DescriptionUtils.TEXT_COLOR, false); + + yOff += 10; + } + } else { + List placeholders = Arrays.asList( + relic.getLevelingSourceData(source).getInitialValue(), + title + ); + + var component = ScreenUtils.stylizeWithReplacement(Component.translatable(sourceData.getTranslationPath().apply(stack) + ".description", placeholders.toArray()), 1F, Style.EMPTY.withFont(ScreenUtils.ILLAGER_ALT_FONT), source.length()); + + for (FormattedCharSequence line : font.split(component, 340)) { + guiGraphics.drawString(font, line, (x + 112) * 2, (y + 74) * 2 + yOff, 0x662f13, false); + + yOff += 10; + } + } + + poseStack.popPose(); + } + + @Override + public void render(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + super.render(guiGraphics, pMouseX, pMouseY, pPartialTick); + + for (GuiEventListener listener : this.children()) { + if (listener instanceof AbstractButton button && button.isHovered() + && button instanceof IHoverableWidget widget) { + guiGraphics.pose().translate(0, 0, 100); + + widget.onHovered(guiGraphics, pMouseX, pMouseY); + } + } + } + + @Override + public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) { + if (minecraft.options.keyInventory.isActiveAndMatches(InputConstants.getKey(pKeyCode, pScanCode))) { + this.onClose(); + + return true; + } + + return super.keyPressed(pKeyCode, pScanCode, pModifiers); + } + + @Override + public void onClose() { + screen.rebuildWidgets(); + + Minecraft.getInstance().setScreen(screen); + } + + @Override + public boolean isPauseScreen() { + return false; + } + + @Override + public int getAutoScale() { + return 0; + } + + @Override + public DescriptionPage getPage() { + return DescriptionPage.EXPERIENCE; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/BigExperienceCardWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/BigExperienceCardWidget.java new file mode 100644 index 00000000..d01c6f51 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/BigExperienceCardWidget.java @@ -0,0 +1,118 @@ +package it.hurts.sskirillss.relics.client.screen.description.experience.widgets; + +import com.mojang.blaze3d.systems.RenderSystem; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; +import it.hurts.sskirillss.relics.client.screen.description.experience.ExperienceDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractDescriptionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.research.particles.SmokeParticleData; +import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.MathUtils; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.RandomSource; + +import java.util.Locale; + +public class BigExperienceCardWidget extends AbstractDescriptionWidget implements ITickingWidget { + private ExperienceDescriptionScreen screen; + + public BigExperienceCardWidget(int x, int y, ExperienceDescriptionScreen screen) { + super(x, y, 48, 74); + + this.screen = screen; + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + var stack = screen.getStack(); + + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + var player = minecraft.player; + var poseStack = guiGraphics.pose(); + var source = screen.getSelectedSource(); + var sourceData = relic.getLevelingSourcesData().getSources().get(source); + + var isUnlocked = relic.isLevelingSourceUnlocked(stack, source); + + float color = (float) (1.05F + (Math.sin((player.tickCount + (sourceData.getId().length() * 10)) * 0.2F) * 0.1F)); + + poseStack.pushPose(); + + if (isUnlocked) { + GUIRenderer.begin(sourceData.getIcon().apply(stack), poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .color(color, color, color, 1F) + .pos(getX() + 7, getY() + 10) + .texSize(34, 49) + .end(); + + RenderSystem.enableBlend(); + + GUIRenderer.begin(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/experience/filters/" + sourceData.getColor().name().toLowerCase(Locale.ROOT) + ".png"), poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + 7, getY() + 10) + .texSize(34, 49) + .end(); + + RenderSystem.disableBlend(); + } else + GUIRenderer.begin(DescriptionTextures.BIG_CARD_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + 7, getY() + 10) + .end(); + + GUIRenderer.begin(isUnlocked ? DescriptionTextures.BIG_CARD_FRAME_UNLOCKED_ACTIVE : DescriptionTextures.BIG_CARD_FRAME_UNLOCKED_INACTIVE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX(), getY()) + .end(); + + { + poseStack.pushPose(); + + MutableComponent pointsComponent = Component.literal(isUnlocked ? String.valueOf(relic.getLevelingSourceLevel(stack, source)) : "?").withStyle(ChatFormatting.BOLD); + + poseStack.scale(0.75F, 0.75F, 1F); + + guiGraphics.drawString(minecraft.font, pointsComponent, (int) (((getX() + 25.5F) * 1.33F) - (minecraft.font.width(pointsComponent) / 2F)), (int) ((getY() + 4) * 1.33F), isUnlocked ? 0xFFE278 : 0xB7AED9, true); + + poseStack.popPose(); + } + + poseStack.popPose(); + } + + @Override + public void onTick() { + var stack = screen.getStack(); + var source = screen.getSelectedSource(); + + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + var isUnlocked = relic.isLevelingSourceUnlocked(stack, source); + + if (!isUnlocked) { + RandomSource random = minecraft.player.getRandom(); + + ParticleStorage.addParticle(screen, new SmokeParticleData(getX() + 11 + random.nextInt(27), getY() + 15 + random.nextInt(43), 0.75F + (random.nextFloat() * 0.25F), 20 + random.nextInt(40), 0.5F) + .setDeltaX(MathUtils.randomFloat(random) * 0.1F).setDeltaY(MathUtils.randomFloat(random) * 0.1F)); + } + } + + @Override + public void playDownSound(SoundManager handler) { + + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/ExperienceGemWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/ExperienceGemWidget.java new file mode 100644 index 00000000..fcc1bad5 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/ExperienceGemWidget.java @@ -0,0 +1,264 @@ +package it.hurts.sskirillss.relics.client.screen.description.experience.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; +import it.hurts.sskirillss.relics.client.screen.description.experience.ExperienceDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractDescriptionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.client.screen.description.relic.particles.ExperienceParticleData; +import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; +import it.hurts.sskirillss.relics.client.screen.utils.ScreenUtils; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.MathUtils; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; + +import java.awt.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public class ExperienceGemWidget extends AbstractDescriptionWidget implements ITickingWidget, IHoverableWidget { + private final ExperienceDescriptionScreen screen; + private final String source; + + private float scale = 1F; + private float scaleOld = 1F; + + public ExperienceGemWidget(int x, int y, ExperienceDescriptionScreen screen, String source) { + super(x, y, 32, 47); + + this.screen = screen; + this.source = source; + } + + @Override + public void onPress() { + if (screen.getSelectedSource().equals(source)) + return; + + screen.setSelectedSource(source); + + screen.rebuildWidgets(); + + for (var entry : screen.renderables) { + if (!(entry instanceof ExperienceGemWidget gem) || !gem.source.equals(source)) + continue; + + gem.scale = scale; + gem.scaleOld = scaleOld; + } + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + var player = Minecraft.getInstance().player; + + if (player == null || !(screen.stack.getItem() instanceof IRelicItem relic)) + return; + + var stack = screen.getStack(); + var poseStack = guiGraphics.pose(); + var sourceData = relic.getLevelingSourcesData().getSources().get(source); + + var isUnlocked = relic.isLevelingSourceUnlocked(stack, source); + + poseStack.pushPose(); + + RenderSystem.enableBlend(); + + var partialTicks = minecraft.getTimer().getGameTimeDeltaPartialTick(false); + + var lerpedScale = Mth.lerp(partialTicks, scaleOld, scale); + + poseStack.scale(lerpedScale, lerpedScale, lerpedScale); + + poseStack.translate((getX() + (width / 2F)) / lerpedScale, (getY() + (height / 2F)) / lerpedScale, 0); + + var shape = sourceData.getShape().name().toLowerCase(Locale.ROOT); + + var color = (float) (1.05F + (Math.sin((player.tickCount + (source.length() * 10)) * 0.2F) * 0.1F)); + + if (isUnlocked) + GUIRenderer.begin(sourceData.getIcon().apply(stack), poseStack) + .pos(0, -1) + .color(color, color, color, 1F) + .end(); + else + GUIRenderer.begin(DescriptionTextures.SMALL_CARD_LOCK_BACKGROUND, poseStack) + .pos(0, -1) + .end(); + + GUIRenderer.begin(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/experience/gems/" + shape + "/" + sourceData.getColor().name().toLowerCase(Locale.ROOT) + ".png"), poseStack) + .end(); + + GUIRenderer.begin(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/experience/gems/" + shape + "/frame_" + (isUnlocked ? "unlocked" : "locked") + ".png"), poseStack) + .end(); + + RenderSystem.disableBlend(); + + { + MutableComponent title = Component.literal(isUnlocked ? String.valueOf(relic.getLevelingSourceLevel(stack, source)) : "?").withStyle(ChatFormatting.BOLD); + + float textScale = 0.5F; + + poseStack.scale(textScale, textScale, textScale); + + guiGraphics.drawString(minecraft.font, title, -((width + 1) / 2) - (minecraft.font.width(title) / 2) + 16, (-(height / 2) + 40), isUnlocked ? 0xFFE278 : 0xB7AED9, true); + } + + poseStack.popPose(); + } + + @Override + public void onTick() { + if (!(screen.stack.getItem() instanceof IRelicItem relic)) + return; + + float maxScale = 1.15F; + float minScale = 1F; + + RandomSource random = minecraft.player.getRandom(); + + scaleOld = scale; + + if (scale > maxScale) + scale = Math.max(minScale, scale - 0.01F); + + if (isHovered()) { + if (minecraft.player.tickCount % 3 == 0) + ParticleStorage.addParticle(screen, new ExperienceParticleData( + new Color(200 + random.nextInt(50), 150 + random.nextInt(100), 0), + getX() + random.nextInt(width), getY() - 1, 1F + (random.nextFloat() * 0.5F), 100 + random.nextInt(50))); + + if (scale < maxScale) + scale = Math.min(maxScale, scale + 0.04F); + } else { + if (scale > minScale) + scale = Math.max(minScale, scale - 0.03F); + } + } + + @Override + public boolean isLocked() { + return screen.getSelectedSource().equals(source); + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + var stack = screen.stack; + + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + var data = relic.getLevelingSourceData(source); + + if (data == null) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + var title = Component.translatableWithFallback(data.getTranslationPath().apply(stack) + ".title", source); + + int maxWidth = 110; + int renderWidth = Math.min((minecraft.font.width(title.withStyle(ChatFormatting.BOLD)) / 2) + 4, maxWidth); + + List entries = new ArrayList<>(); + + entries.add(Component.literal(" ")); + + var requiredLevel = data.getRequiredLevel(); + var requiredAbility = data.getRequiredAbility(); + + if (relic.getRelicLevel(screen.stack) < requiredLevel) { + entries.add(Component.literal(" ")); + + entries.add(Component.literal("").append(Component.translatable("tooltip.relics.researching.relic.gem.low_level", Component.literal(String.valueOf(requiredLevel)).withStyle(ChatFormatting.BOLD)))); + } else if (!requiredAbility.isEmpty() && !relic.isAbilityUnlocked(stack, requiredAbility)) { + entries.add(Component.literal(" ")); + + entries.add(Component.literal("").append(Component.translatable("tooltip.relics.researching.relic.gem.locked_ability"))); + } + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry)) / 2; + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth + 4, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + int height = tooltip.size() * 5; + + int y = getHeight() / 2; + + float partialTicks = minecraft.getTimer().getGameTimeDeltaPartialTick(false); + + float lerpedScale = Mth.lerp(partialTicks, scaleOld, scale); + + poseStack.scale(lerpedScale, lerpedScale, lerpedScale); + + poseStack.translate((getX() + (getWidth() / 2F)) / lerpedScale, (getY() + (getHeight() / 2F)) / lerpedScale, 0); + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, height, -((renderWidth + 19) / 2), y); + + int yOff = 0; + + poseStack.pushPose(); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + if (!relic.isLevelingSourceUnlocked(stack, source)) { + title = ScreenUtils.stylizeWithReplacement(title, 1F, Style.EMPTY.withFont(ScreenUtils.ILLAGER_ALT_FONT).withColor(0x9E00B0), source.length()); + + var random = minecraft.player.getRandom(); + + var shakeX = MathUtils.randomFloat(random) * 0.5F; + var shakeY = MathUtils.randomFloat(random) * 0.5F; + + poseStack.translate(shakeX, shakeY, 0F); + + } else + title.withStyle(ChatFormatting.BOLD); + + guiGraphics.drawString(minecraft.font, title, -(minecraft.font.width(title) / 2), ((y + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + poseStack.popPose(); + + for (FormattedCharSequence entry : tooltip) { + poseStack.pushPose(); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + guiGraphics.drawString(minecraft.font, entry, -(minecraft.font.width(entry) / 2), ((y + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + + poseStack.popPose(); + } + } + + @Override + public void playDownSound(SoundManager handler) { + if (!isLocked()) + super.playDownSound(handler); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/ResetExperienceActionWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/ResetExperienceActionWidget.java new file mode 100644 index 00000000..b0d247b7 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/ResetExperienceActionWidget.java @@ -0,0 +1,79 @@ +package it.hurts.sskirillss.relics.client.screen.description.experience.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.description.ability.AbilityDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.ability.widgets.base.AbstractAbilityActionWidget; +import it.hurts.sskirillss.relics.client.screen.description.experience.ExperienceDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.experience.widgets.base.AbstractExperienceActionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.network.packets.leveling.PacketRelicTweak; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; + +import java.util.List; + +public class ResetExperienceActionWidget extends AbstractExperienceActionWidget { + public ResetExperienceActionWidget(int x, int y, ExperienceDescriptionScreen screen) { + super(x, y, PacketRelicTweak.Operation.RESET, screen); + } + + @Override + public boolean isLocked() { + return true; + } + + @Override + public void playDownSound(SoundManager handler) { + + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + if (!(getScreen().getStack().getItem() instanceof IRelicItem)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 100; + int renderWidth = 0; + + List entries = Lists.newArrayList( + Component.literal("To avoid issues with existing worlds, this feature will be added with the update to Minecraft 1.22.") + ); + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) + 4) / 2; + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + int height = Math.round(tooltip.size() * 5F); + + int renderX = getX() + width + 1; + int renderY = mouseY - (height / 2) - 9; + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, height, renderX, renderY); + + int yOff = 0; + + poseStack.scale(0.5F, 0.5F, 0.5F); + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, (renderX + 10) * 2, (renderY + 9 + yOff) * 2, DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.scale(1F, 1F, 1F); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/UpgradeExperienceActionWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/UpgradeExperienceActionWidget.java new file mode 100644 index 00000000..61f3dad6 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/UpgradeExperienceActionWidget.java @@ -0,0 +1,88 @@ +package it.hurts.sskirillss.relics.client.screen.description.experience.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.description.ability.AbilityDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.ability.widgets.base.AbstractAbilityActionWidget; +import it.hurts.sskirillss.relics.client.screen.description.experience.ExperienceDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.experience.widgets.base.AbstractExperienceActionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.init.SoundRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; +import it.hurts.sskirillss.relics.network.packets.leveling.PacketRelicTweak; +import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; + +import java.util.List; + +public class UpgradeExperienceActionWidget extends AbstractExperienceActionWidget { + public UpgradeExperienceActionWidget(int x, int y, ExperienceDescriptionScreen screen) { + super(x, y, PacketRelicTweak.Operation.UPGRADE, screen); + } + + @Override + public boolean isLocked() { + return true; + } + + @Override + public void playDownSound(SoundManager handler) { + + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + if (!(getScreen().getStack().getItem() instanceof IRelicItem)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 100; + int renderWidth = 0; + + List entries = Lists.newArrayList( + Component.literal("To avoid issues with existing worlds, this feature will be added with the update to Minecraft 1.22.") + ); + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) + 4) / 2; + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + int height = Math.round(tooltip.size() * 5F); + + int renderX = getX() + width + 1; + int renderY = mouseY - (height / 2) - 9; + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, height, renderX, renderY); + + int yOff = 0; + + poseStack.scale(0.5F, 0.5F, 0.5F); + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, (renderX + 10) * 2, (renderY + 9 + yOff) * 2, DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.scale(1F, 1F, 1F); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/base/AbstractExperienceActionWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/base/AbstractExperienceActionWidget.java new file mode 100644 index 00000000..d99b598b --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/experience/widgets/base/AbstractExperienceActionWidget.java @@ -0,0 +1,69 @@ +package it.hurts.sskirillss.relics.client.screen.description.experience.widgets.base; + +import com.mojang.blaze3d.systems.RenderSystem; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; +import it.hurts.sskirillss.relics.client.screen.description.experience.ExperienceDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractDescriptionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.relic.particles.ExperienceParticleData; +import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; +import it.hurts.sskirillss.relics.network.packets.leveling.PacketRelicTweak; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.Getter; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.RandomSource; + +import java.awt.*; +import java.util.Locale; + +public abstract class AbstractExperienceActionWidget extends AbstractDescriptionWidget implements IHoverableWidget, ITickingWidget { + @Getter + private final PacketRelicTweak.Operation operation; + @Getter + private final ExperienceDescriptionScreen screen; + + public AbstractExperienceActionWidget(int x, int y, PacketRelicTweak.Operation operation, ExperienceDescriptionScreen screen) { + super(x, y, 14, 13); + + this.operation = operation; + this.screen = screen; + } + + @Override + public abstract boolean isLocked(); + + public String getSource() { + return screen.getSelectedSource(); + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + String actionId = operation.toString().toLowerCase(Locale.ROOT); + + guiGraphics.blit(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/ability/" + actionId + "_button_" + (isLocked() ? "inactive" : "active") + ".png"), getX(), getY(), 0, 0, width, height, width, height); + + if (isHovered) + guiGraphics.blit(DescriptionTextures.ACTION_BUTTON_OUTLINE, getX(), getY(), 0, 0, width, height, width, height); + } + + @Override + public void onTick() { + if (minecraft.player == null) + return; + + RandomSource random = minecraft.player.getRandom(); + + if (!isHovered() || minecraft.player.tickCount % 5 != 0) + return; + + ParticleStorage.addParticle((Screen) screen, new ExperienceParticleData( + new Color(200 + random.nextInt(50), 150 + random.nextInt(100), 0), + getX() + random.nextInt(width), getY() + random.nextInt(height / 4), + 1F + (random.nextFloat() * 0.25F), 50 + random.nextInt(50))); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/misc/DescriptionPage.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/misc/DescriptionPage.java new file mode 100644 index 00000000..f6d4fee7 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/misc/DescriptionPage.java @@ -0,0 +1,7 @@ +package it.hurts.sskirillss.relics.client.screen.description.general.misc; + +public enum DescriptionPage { + RELIC, + ABILITY, + EXPERIENCE +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/data/base/ParticleData.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/particles/base/ParticleData.java similarity index 58% rename from src/main/java/it/hurts/sskirillss/relics/client/screen/description/data/base/ParticleData.java rename to src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/particles/base/ParticleData.java index 52711f22..aa1d50bb 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/data/base/ParticleData.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/particles/base/ParticleData.java @@ -1,6 +1,7 @@ -package it.hurts.sskirillss.relics.client.screen.description.data.base; +package it.hurts.sskirillss.relics.client.screen.description.general.particles.base; import lombok.Data; +import lombok.experimental.Accessors; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.Screen; import net.minecraft.resources.ResourceLocation; @@ -8,7 +9,8 @@ import java.awt.*; @Data -public class ParticleData { +@Accessors(chain = true) +public abstract class ParticleData { private final ResourceLocation texture; private final Color color; @@ -22,8 +24,17 @@ public class ParticleData { private int lifeTime; + private float roll; + + private float deltaX; + private float deltaY; + + private float xO; + private float yO; + private float x; private float y; + private float z; public ParticleData(ResourceLocation texture, Color color, float xStart, float yStart, float scale, int lifeTime) { this.texture = texture; @@ -39,15 +50,23 @@ public ParticleData(ResourceLocation texture, Color color, float xStart, float y this.maxLifeTime = lifeTime; + this.roll = 0F; + + this.deltaX = 0F; + this.deltaY = 0F; + + this.xO = xStart; + this.yO = yStart; + this.x = xStart; this.y = yStart; + this.z = 0F; } public void tick(Screen screen) { - + this.xO = x; + this.yO = y; } - public void render(Screen screen, GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { - - } + public abstract void render(Screen screen, GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick); } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/AbilityBadgeWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/AbilityBadgeWidget.java new file mode 100644 index 00000000..3c134481 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/AbilityBadgeWidget.java @@ -0,0 +1,95 @@ +package it.hurts.sskirillss.relics.client.screen.description.general.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.badges.base.AbilityBadge; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractBadgeWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.world.item.ItemStack; + +import java.util.List; + +public class AbilityBadgeWidget extends AbstractBadgeWidget { + private final AbilityBadge badge; + private final String ability; + + public AbilityBadgeWidget(int x, int y, IRelicScreenProvider provider, AbilityBadge badge, String ability) { + super(x, y, provider, badge); + + this.badge = badge; + this.ability = ability; + } + + @Override + public AbilityBadge getBadge() { + return badge; + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + ItemStack stack = getProvider().getStack(); + + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 100; + int renderWidth = 0; + + List entries = Lists.newArrayList( + getBadge().getTitle(stack, ability).withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.UNDERLINE), + Component.literal(" ") + ); + + entries.addAll(getBadge().getDescription(stack, ability)); + + List hint = getBadge().getHint(stack, ability); + + if (!hint.isEmpty()) { + entries.add(Component.literal(" ")); + + if (Screen.hasShiftDown()) + entries.addAll(hint.stream().map(entry -> entry.withStyle(ChatFormatting.ITALIC)).toList()); + else + entries.add(Component.translatable("tooltip.relics.researching.general.extra_info")); + } + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) / 2); + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth + 2, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + poseStack.pushPose(); + + poseStack.translate(0F, 0F, 400); + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, tooltip.size() * 5, mouseX - 9 - (renderWidth / 2), mouseY); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + int yOff = 0; + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, ((mouseX - renderWidth / 2) + 1) * 2, ((mouseY + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.popPose(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/LogoWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/LogoWidget.java new file mode 100644 index 00000000..5da419c6 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/LogoWidget.java @@ -0,0 +1,95 @@ +package it.hurts.sskirillss.relics.client.screen.description.general.widgets; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; +import it.hurts.sskirillss.relics.client.screen.description.relic.particles.ExperienceParticleData; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractDescriptionWidget; +import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.data.AnimationData; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import lombok.Getter; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.util.RandomSource; + +import java.awt.*; + +public class LogoWidget extends AbstractDescriptionWidget implements IHoverableWidget, ITickingWidget { + @Getter + private IRelicScreenProvider provider; + + public LogoWidget(int x, int y, IRelicScreenProvider provider) { + super(x, y, 54, 14); + + this.provider = provider; + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + LocalPlayer player = Minecraft.getInstance().player; + + if (player == null || !(provider.getStack().getItem() instanceof IRelicItem relic)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + poseStack.pushPose(); + + float color = (float) (1.05F + (Math.sin(player.tickCount * 0.25F) * 0.1F)); + + RenderSystem.setShaderColor(color, color, color, 1F); + + RenderSystem.setShaderTexture(0, DescriptionTextures.LOGO); + + poseStack.translate(getX() + Math.sin((minecraft.player.tickCount + pPartialTick) * 0.075F), getY() + Math.cos((minecraft.player.tickCount + pPartialTick) * 0.075F) * 0.5F, 0); + + GUIRenderer.begin(DescriptionTextures.LOGO, poseStack) + .animation(AnimationData.builder() + .frame(0, 2).frame(1, 2).frame(2, 2) + .frame(3, 2).frame(4, 2).frame(5, 2) + .frame(6, 2).frame(7, 2).frame(8, 2) + .frame(9, 2).frame(10, 2).frame(11, 2) + .frame(12, 2).frame(13, 2).frame(14, 2) + .frame(15, 20)) + .anchor(SpriteAnchor.TOP_LEFT) + .texSize(width, height * 16) + .patternSize(width, height) + .end(); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + poseStack.popPose(); + } + + @Override + public void onTick() { + if (!(provider.getStack().getItem() instanceof IRelicItem relic) || minecraft.player == null) + return; + + RandomSource random = minecraft.player.getRandom(); + + if (minecraft.player.tickCount % 5 == 0) { + ParticleStorage.addParticle((Screen) provider, new ExperienceParticleData(new Color(200 + random.nextInt(50), 150 + random.nextInt(100), 0), + getX() + random.nextInt(width), getY() + random.nextInt(3), 1F + (random.nextFloat() * 0.25F), 50 + random.nextInt(50))); + } + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + + } + + @Override + public void playDownSound(SoundManager handler) { + + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/LuckPlateWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/LuckPlateWidget.java new file mode 100644 index 00000000..288194b3 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/LuckPlateWidget.java @@ -0,0 +1,85 @@ +package it.hurts.sskirillss.relics.client.screen.description.general.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractPlateWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.world.item.ItemStack; + +import java.util.List; + +public class LuckPlateWidget extends AbstractPlateWidget { + public LuckPlateWidget(int x, int y, IRelicScreenProvider provider) { + super(x, y, provider, "luck"); + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + ItemStack stack = getProvider().getStack(); + + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 150; + int renderWidth = 0; + + List entries = Lists.newArrayList( + Component.literal("").append(Component.translatable("tooltip.relics.researching.general.luck.title").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.UNDERLINE)).append(" " + relic.getRelicLuck(stack) + "%"), + Component.literal(" ") + ); + + if (Screen.hasShiftDown()) + entries.add(Component.translatable("tooltip.relics.researching.general.luck.extra_info").withStyle(ChatFormatting.ITALIC)); + else + entries.add(Component.translatable("tooltip.relics.researching.general.extra_info")); + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) / 2); + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth + 2, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + poseStack.pushPose(); + + poseStack.translate(0F, 0F, 100); + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, tooltip.size() * 5, mouseX - 9 - (renderWidth / 2), mouseY); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + int yOff = 0; + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, ((mouseX - renderWidth / 2) + 1) * 2, ((mouseY + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.popPose(); + } + + @Override + public void onTick() { + + } + + @Override + public String getValue(ItemStack stack) { + return (stack.getItem() instanceof IRelicItem relic ? relic.getRelicLuck(stack) : 0) + "%"; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/PageWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/PageWidget.java new file mode 100644 index 00000000..e6068ce6 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/PageWidget.java @@ -0,0 +1,143 @@ +package it.hurts.sskirillss.relics.client.screen.description.general.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.IPagedDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import it.hurts.sskirillss.relics.client.screen.description.general.misc.DescriptionPage; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractDescriptionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.GUIScissors; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import lombok.Getter; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; + +import java.util.List; +import java.util.Locale; + +public class PageWidget extends AbstractDescriptionWidget implements IHoverableWidget { + @Getter + private IRelicScreenProvider source; + + @Getter + private IRelicScreenProvider target; + + @Getter + private DescriptionPage page; + + public PageWidget(int x, int y, IRelicScreenProvider source, DescriptionPage page, IRelicScreenProvider target) { + super(x, y, 17, 19); + + this.source = source; + this.target = target; + this.page = page; + } + + @Override + public void onPress() { + if (isLocked()) + return; + + minecraft.setScreen((Screen) target); + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + var poseStack = guiGraphics.pose(); + var player = minecraft.player; + + poseStack.pushPose(); + + if (isLocked()) { + GUIScissors.begin(getX(), getY(), width, 19); + + GUIRenderer.begin(DescriptionTextures.TAB, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX(), getY() + 11) + .end(); + + GUIScissors.end(); + } else { + GUIRenderer.begin(DescriptionTextures.TAB, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX(), getY()) + .end(); + + GUIRenderer.begin(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/tabs/" + page.name().toLowerCase(Locale.ROOT) + ".png"), poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + 2, getY() + 5) + .end(); + + if (isHovered()) + GUIRenderer.begin(DescriptionTextures.TAB_OUTLINE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() - 1, getY() - 1) + .end(); + } + + poseStack.popPose(); + } + + @Override + public boolean isLocked() { + return minecraft.screen instanceof IPagedDescriptionScreen screen && screen.getPage() == page; + } + + @Override + public void playDownSound(SoundManager handler) { + if (!isLocked()) + super.playDownSound(handler); + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 100; + int renderWidth = 0; + + List entries = Lists.newArrayList( + Component.translatable("tooltip.relics.researching.tab." + page.name().toLowerCase(Locale.ROOT)).withStyle(ChatFormatting.BOLD) + ); + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) + 4) / 2; + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + poseStack.pushPose(); + + poseStack.translate(0F, 0F, 100); + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, tooltip.size() * 5, mouseX - 9 - (renderWidth / 2), mouseY); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + int yOff = 0; + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, ((mouseX - renderWidth / 2) + 1) * 2, ((mouseY + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.popPose(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/PlayerExperiencePlateWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/PlayerExperiencePlateWidget.java new file mode 100644 index 00000000..a153e74e --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/PlayerExperiencePlateWidget.java @@ -0,0 +1,115 @@ +package it.hurts.sskirillss.relics.client.screen.description.general.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractPlateWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.world.item.ItemStack; + +import java.util.List; + +public class PlayerExperiencePlateWidget extends AbstractPlateWidget { + public PlayerExperiencePlateWidget(int x, int y, IRelicScreenProvider provider) { + super(x, y, provider, "player_experience"); + } + + @Override + public void renderContent(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + LocalPlayer player = minecraft.player; + + int barWidth = 52; + int barHeight = 2; + + PoseStack poseStack = guiGraphics.pose(); + + poseStack.pushPose(); + + GUIRenderer.begin(DescriptionTextures.PLATE_PLAYER_EXPERIENCE_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(1, height - 3) + .end(); + + GUIRenderer.begin(DescriptionTextures.PLATE_PLAYER_EXPERIENCE_FILLER, poseStack) + .pos(1, height - 3) + .texSize(barWidth, barHeight) + .anchor(SpriteAnchor.TOP_LEFT) + .patternSize((int) (barWidth * ((player.totalExperience / ((player.totalExperience / player.experienceProgress) / 100F)) / 100F)), barHeight) + .end(); + + poseStack.popPose(); + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + ItemStack stack = getProvider().getStack(); + + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 150; + int renderWidth = 0; + + List entries = Lists.newArrayList( + Component.literal("").append(Component.translatable("tooltip.relics.researching.general.player_experience.title").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.UNDERLINE)).append(" " + minecraft.player.experienceLevel), + Component.literal(" ") + ); + + if (Screen.hasShiftDown()) + entries.add(Component.translatable("tooltip.relics.researching.general.player_experience.extra_info").withStyle(ChatFormatting.ITALIC)); + else + entries.add(Component.translatable("tooltip.relics.researching.general.extra_info")); + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) / 2); + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth + 2, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + poseStack.pushPose(); + + poseStack.translate(0F, 0F, 100); + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, tooltip.size() * 5, mouseX - 9 - (renderWidth / 2), mouseY); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + int yOff = 0; + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, ((mouseX - renderWidth / 2) + 1) * 2, ((mouseY + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.popPose(); + } + + @Override + public void onTick() { + + } + + @Override + public String getValue(ItemStack stack) { + return String.valueOf(minecraft.player.experienceLevel); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/PointsFixWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/PointsFixWidget.java new file mode 100644 index 00000000..6d5edec9 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/PointsFixWidget.java @@ -0,0 +1,117 @@ +package it.hurts.sskirillss.relics.client.screen.description.general.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractDescriptionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.network.NetworkHandler; +import it.hurts.sskirillss.relics.network.packets.leveling.FixLevelingPoints; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import lombok.Getter; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.world.item.ItemStack; + +import java.util.List; + +@Deprecated(forRemoval = true) +public class PointsFixWidget extends AbstractDescriptionWidget implements IHoverableWidget { + @Getter + private IRelicScreenProvider provider; + + public PointsFixWidget(int x, int y, IRelicScreenProvider provider) { + super(x, y, 18, 18); + + this.provider = provider; + } + + @Override + public void onPress() { + if (!(provider.getStack().getItem() instanceof IRelicItem relic) || !relic.isSomethingWrongWithLevelingPoints(provider.getStack())) + return; + + NetworkHandler.sendToServer(new FixLevelingPoints(provider.getContainer(), provider.getSlot())); + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + LocalPlayer player = Minecraft.getInstance().player; + + if (player == null || !(provider.getStack().getItem() instanceof IRelicItem relic) + || !relic.isSomethingWrongWithLevelingPoints(provider.getStack())) + return; + + PoseStack poseStack = guiGraphics.pose(); + + poseStack.pushPose(); + + float color = (float) (1.25F + (Math.sin(player.tickCount) * 0.5F)); + + GUIRenderer.begin(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/fix.png"), poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .color(color, color, color, 1F) + .pos(getX(), getY()) + .end(); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + poseStack.popPose(); + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + ItemStack stack = getProvider().getStack(); + + if (!(stack.getItem() instanceof IRelicItem relic) || !relic.isSomethingWrongWithLevelingPoints(provider.getStack())) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 150; + int renderWidth = 0; + + List entries = Lists.newArrayList( + Component.literal("Looks like you have an incorrect number of leveling points. This may be a compatibility issue with previous releases of Relics. If you're sure something is wrong, click this button to fix it! This action cannot be undone!") + ); + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) / 2); + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth + 2, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + poseStack.pushPose(); + + poseStack.translate(0F, 0F, 100); + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, tooltip.size() * 5, mouseX - 9 - (renderWidth / 2), mouseY); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + int yOff = 0; + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, ((mouseX - renderWidth / 2) + 1) * 2, ((mouseY + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.popPose(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/PointsPlateWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/PointsPlateWidget.java new file mode 100644 index 00000000..f5b21d13 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/PointsPlateWidget.java @@ -0,0 +1,85 @@ +package it.hurts.sskirillss.relics.client.screen.description.general.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractPlateWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.world.item.ItemStack; + +import java.util.List; + +public class PointsPlateWidget extends AbstractPlateWidget { + public PointsPlateWidget(int x, int y, IRelicScreenProvider provider) { + super(x, y, provider, "leveling_point"); + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + ItemStack stack = getProvider().getStack(); + + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 150; + int renderWidth = 0; + + List entries = Lists.newArrayList( + Component.literal("").append(Component.translatable("tooltip.relics.researching.general.leveling_point.title").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.UNDERLINE)).append(" " + relic.getRelicLevelingPoints(stack)), + Component.literal(" ") + ); + + if (Screen.hasShiftDown()) + entries.add(Component.translatable("tooltip.relics.researching.general.leveling_point.extra_info").withStyle(ChatFormatting.ITALIC)); + else + entries.add(Component.translatable("tooltip.relics.researching.general.extra_info")); + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) / 2); + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth + 2, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + poseStack.pushPose(); + + poseStack.translate(0F, 0F, 100); + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, tooltip.size() * 5, mouseX - 9 - (renderWidth / 2), mouseY); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + int yOff = 0; + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, ((mouseX - renderWidth / 2) + 1) * 2, ((mouseY + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.popPose(); + } + + @Override + public void onTick() { + + } + + @Override + public String getValue(ItemStack stack) { + return stack.getItem() instanceof IRelicItem relic ? String.valueOf(relic.getRelicLevelingPoints(stack)) : ""; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/RelicBadgeWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/RelicBadgeWidget.java new file mode 100644 index 00000000..d90105ff --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/RelicBadgeWidget.java @@ -0,0 +1,93 @@ +package it.hurts.sskirillss.relics.client.screen.description.general.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.badges.base.RelicBadge; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractBadgeWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.world.item.ItemStack; + +import java.util.List; + +public class RelicBadgeWidget extends AbstractBadgeWidget { + private final RelicBadge badge; + + public RelicBadgeWidget(int x, int y, IRelicScreenProvider provider, RelicBadge badge) { + super(x, y, provider, badge); + + this.badge = badge; + } + + @Override + public RelicBadge getBadge() { + return badge; + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + ItemStack stack = getProvider().getStack(); + + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 100; + int renderWidth = 0; + + List entries = Lists.newArrayList( + getBadge().getTitle(stack).withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.UNDERLINE), + Component.literal(" ") + ); + + entries.addAll(getBadge().getDescription(stack)); + + List hint = getBadge().getHint(stack); + + if (!hint.isEmpty()) { + entries.add(Component.literal(" ")); + + if (Screen.hasShiftDown()) + entries.addAll(hint.stream().map(entry -> entry.withStyle(ChatFormatting.ITALIC)).toList()); + else + entries.add(Component.translatable("tooltip.relics.researching.general.extra_info")); + } + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) / 2); + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth + 2, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + poseStack.pushPose(); + + poseStack.translate(0F, 0F, 400); + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, tooltip.size() * 5, mouseX - 9 - (renderWidth / 2), mouseY); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + int yOff = 0; + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, ((mouseX - renderWidth / 2) + 1) * 2, ((mouseY + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.popPose(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/base/AbstractBadgeWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/base/AbstractBadgeWidget.java new file mode 100644 index 00000000..9bbb68e7 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/base/AbstractBadgeWidget.java @@ -0,0 +1,62 @@ +package it.hurts.sskirillss.relics.client.screen.description.general.widgets.base; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import it.hurts.sskirillss.relics.badges.base.AbstractBadge; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import lombok.Getter; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.sounds.SoundManager; + +public abstract class AbstractBadgeWidget extends AbstractDescriptionWidget implements IHoverableWidget { + @Getter + private IRelicScreenProvider provider; + + public AbstractBadgeWidget(int x, int y, IRelicScreenProvider provider, AbstractBadge badge) { + super(x, y, 13, 10); + + this.provider = provider; + } + + public abstract AbstractBadge getBadge(); + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + if (minecraft.player == null) + return; + + PoseStack poseStack = guiGraphics.pose(); + + poseStack.pushPose(); + + float color = (float) (1.05F + (Math.sin((minecraft.player.tickCount + (getBadge().getId().length() * 10)) * 0.2F) * 0.1F)); + + RenderSystem.setShaderColor(color, color, color, 1F); + + poseStack.translate(getX(), getY(), 0); + + if (isHovered) { + poseStack.translate(width / 2F, height / 2F, 0); + + poseStack.mulPose(Axis.ZP.rotationDegrees((float) Math.cos((minecraft.player.tickCount + pPartialTick) * 0.35F) * 7.5F)); + + poseStack.translate(-(width / 2F), -(height / 2F), 0); + } + + guiGraphics.blit(getBadge().getIconTexture(), 0, 0, 0, 0, width, height, width, height); + + if (isHovered) + guiGraphics.blit(getBadge().getOutlineTexture(), -1, -1, 0, 0, width + 2, height + 2, width + 2, height + 2); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + poseStack.popPose(); + } + + @Override + public void playDownSound(SoundManager handler) { + + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/base/AbstractDescriptionWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/base/AbstractDescriptionWidget.java similarity index 86% rename from src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/base/AbstractDescriptionWidget.java rename to src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/base/AbstractDescriptionWidget.java index 5b785cef..bb8abfc9 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/base/AbstractDescriptionWidget.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/base/AbstractDescriptionWidget.java @@ -1,4 +1,4 @@ -package it.hurts.sskirillss.relics.client.screen.description.widgets.base; +package it.hurts.sskirillss.relics.client.screen.description.general.widgets.base; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.AbstractButton; @@ -9,7 +9,7 @@ import net.minecraft.sounds.SoundEvents; public class AbstractDescriptionWidget extends AbstractButton { - public final Minecraft MC = Minecraft.getInstance(); + public final Minecraft minecraft = Minecraft.getInstance(); public AbstractDescriptionWidget(int x, int y, int width, int height) { super(x, y, width, height, Component.empty()); diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/base/AbstractPlateWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/base/AbstractPlateWidget.java new file mode 100644 index 00000000..34e3eef2 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/general/widgets/base/AbstractPlateWidget.java @@ -0,0 +1,74 @@ +package it.hurts.sskirillss.relics.client.screen.description.general.widgets.base; + +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import lombok.Getter; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; + +public abstract class AbstractPlateWidget extends AbstractDescriptionWidget implements IHoverableWidget, ITickingWidget { + @Getter + private IRelicScreenProvider provider; + @Getter + private final String icon; + + public abstract String getValue(ItemStack stack); + + public AbstractPlateWidget(int x, int y, IRelicScreenProvider provider, String icon) { + super(x, y, 54, 19); + + this.provider = provider; + this.icon = icon; + } + + @Override + public final void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + PoseStack poseStack = guiGraphics.pose(); + + poseStack.pushPose(); + + poseStack.translate(getX() + Math.sin((minecraft.player.tickCount + pPartialTick + icon.length() * 10) * 0.075F), getY() + Math.cos((minecraft.player.tickCount + pPartialTick + icon.length() * 10) * 0.075F) * 0.5F, 0); + + GUIRenderer.begin(DescriptionTextures.PLATE_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .end(); + + GUIRenderer.begin(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/icons/" + icon + ".png"), poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(3, 3) + .end(); + + MutableComponent value = Component.literal(getValue(provider.getStack())).withStyle(ChatFormatting.BOLD); + + guiGraphics.drawString(minecraft.font, value, 19, 6, 0xffe278, true); + + renderContent(guiGraphics, pMouseX, pMouseY, pPartialTick); + + if (isHovered()) + GUIRenderer.begin(DescriptionTextures.PLATE_OUTLINE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .end(); + + poseStack.popPose(); + } + + public void renderContent(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + + } + + @Override + public void playDownSound(SoundManager handler) { + + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/misc/DescriptionCache.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/misc/DescriptionCache.java new file mode 100644 index 00000000..3dd78e13 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/misc/DescriptionCache.java @@ -0,0 +1,127 @@ +package it.hurts.sskirillss.relics.client.screen.description.misc; + +import it.hurts.sskirillss.relics.client.screen.description.general.misc.DescriptionPage; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import lombok.*; +import net.minecraft.world.item.ItemStack; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class DescriptionCache { + private static final Map CACHE = new HashMap<>(); + + public static CacheEntry getEntry(IRelicItem relic) { + return CACHE.computeIfAbsent(relic, entry -> new CacheEntry()); + } + + public static void setEntry(IRelicItem relic, CacheEntry cache) { + CACHE.put(relic, cache); + } + + public static String getSelectedAbility(ItemStack stack) { + if (!(stack.getItem() instanceof IRelicItem relic)) + return ""; + + var cache = getEntry(relic); + var index = cache.getSelectionIndex(DescriptionPage.ABILITY); + var abilities = relic.getAbilitiesData().getAbilities().keySet().stream().filter(entry -> relic.isAbilityEnabled(stack, entry)).toList(); + var ability = abilities.get(index); + + if (ability == null) { + index = 0; + + ability = abilities.get(index); + + setEntry(relic, cache.toBuilder() + .selectionIndex(DescriptionPage.ABILITY, index) + .build()); + } + + return ability; + } + + public static void setSelectedAbility(ItemStack stack, String ability) { + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + var cache = getEntry(relic); + + var abilities = relic.getAbilitiesData().getAbilities().keySet().stream().filter(entry -> relic.isAbilityEnabled(stack, entry)).toList(); + + if (!abilities.contains(ability)) + return; + + var index = abilities.indexOf(ability); + + setEntry(relic, cache.toBuilder() + .selectionIndex(DescriptionPage.ABILITY, index) + .build()); + } + + public static String getSelectedExperienceSource(ItemStack stack) { + if (!(stack.getItem() instanceof IRelicItem relic)) + return ""; + + var cache = getEntry(relic); + var index = cache.getSelectionIndex(DescriptionPage.EXPERIENCE); + var sources = relic.getLevelingSourcesData().getSources().keySet().stream().filter(entry -> relic.isLevelingSourceEnabled(stack, entry)).toList(); + var source = sources.get(index); + + if (source == null) { + index = 0; + + source = sources.get(index); + + setEntry(relic, cache.toBuilder() + .selectionIndex(DescriptionPage.EXPERIENCE, index) + .build()); + } + + return source; + } + + public static void setSelectedExperienceSource(ItemStack stack, String source) { + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + var cache = getEntry(relic); + + var sources = relic.getLevelingSourcesData().getSources().keySet().stream().filter(entry -> relic.isLevelingSourceEnabled(stack, entry)).toList(); + + if (!sources.contains(source)) + return; + + var index = sources.indexOf(source); + + setEntry(relic, cache.toBuilder() + .selectionIndex(DescriptionPage.EXPERIENCE, index) + .build()); + } + + @NoArgsConstructor + @AllArgsConstructor + @Builder(toBuilder = true) + public static class CacheEntry { + @Getter + private DescriptionPage selectedPage = DescriptionPage.RELIC; + + private Map selectionIndices = new HashMap<>() {{ + for (var page : DescriptionPage.values()) + put(page, 0); + }}; + + public int getSelectionIndex(DescriptionPage page) { + return selectionIndices.computeIfAbsent(page, entry -> 0); + } + + public static class CacheEntryBuilder { + public CacheEntryBuilder selectionIndex(DescriptionPage page, int index) { + selectionIndices.put(page, index); + + return this; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/misc/DescriptionTextures.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/misc/DescriptionTextures.java new file mode 100644 index 00000000..53d45f93 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/misc/DescriptionTextures.java @@ -0,0 +1,95 @@ +package it.hurts.sskirillss.relics.client.screen.description.misc; + +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.client.Minecraft; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; + +public class DescriptionTextures { + public static final ResourceLocation PLATE_BACKGROUND = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/plate_background.png"); + public static final ResourceLocation PLATE_OUTLINE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/plate_outline.png"); + + public static final ResourceLocation SPACE_BACKGROUND = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/background.png"); + + public static final ResourceLocation TOP_BACKGROUND = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/top_background.png"); + public static final ResourceLocation BOTTOM_BACKGROUND = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/bottom_background.png"); + + public static final ResourceLocation ACTION_BUTTON_OUTLINE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/ability/action_button_outline.png"); + public static final ResourceLocation STAT_DELIMITER = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/ability/stat_delimiter.png"); + + public static final ResourceLocation TAB = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/tab.png"); + public static final ResourceLocation TAB_OUTLINE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/tab_outline.png"); + + public static final ResourceLocation BIG_STAR_HOLE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/big_star_hole.png"); + public static final ResourceLocation BIG_STAR_ACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/big_star_active.png"); + public static final ResourceLocation BIG_STAR_INACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/big_star_inactive.png"); + + public static final ResourceLocation SMALL_CARD_LOCK_BACKGROUND = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/small_card_lock_background.png"); + public static final ResourceLocation SMALL_CARD_RESEARCH_BACKGROUND = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/small_card_research_background.png"); + public static final ResourceLocation SMALL_CARD_FRAME_UNLOCKED_ACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/small_card_frame_unlocked_active.png"); + public static final ResourceLocation SMALL_CARD_FRAME_UNLOCKED_INACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/small_card_frame_unlocked_inactive.png"); + public static final ResourceLocation SMALL_CARD_FRAME_LOCKED_ACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/small_card_frame_locked_active.png"); + public static final ResourceLocation SMALL_CARD_FRAME_LOCKED_INACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/small_card_frame_locked_inactive.png"); + public static final ResourceLocation SMALL_CARD_FRAME_OUTLINE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/small_card_frame_outline.png"); + + public static final ResourceLocation RESEARCH_BACKGROUND = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/research/research_background.png"); + public static final ResourceLocation RESEARCH_FOG = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/research/research_fog.png"); + + public static final ResourceLocation BIG_CARD_BACKGROUND = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/big_card_background.png"); + public static final ResourceLocation BIG_CARD_FRAME_UNLOCKED_ACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/big_card_frame_unlocked_active.png"); + public static final ResourceLocation BIG_CARD_FRAME_UNLOCKED_INACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/big_card_frame_unlocked_inactive.png"); + public static final ResourceLocation BIG_CARD_FRAME_LOCKED_ACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/big_card_frame_locked_active.png"); + public static final ResourceLocation BIG_CARD_FRAME_LOCKED_INACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/big_card_frame_locked_inactive.png"); + public static final ResourceLocation BIG_CARD_FRAME_OUTLINE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/big_card_frame_outline.png"); + + public static final ResourceLocation CHAINS_INACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/chains_inactive.png"); + + public static final ResourceLocation SMALL_STAR_HOLE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/small_star_hole.png"); + public static final ResourceLocation SMALL_STAR_ACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/small_star_active.png"); + public static final ResourceLocation SMALL_STAR_INACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/small_star_inactive.png"); + + public static final ResourceLocation LOCK_INACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/icons/lock_inactive.png"); + public static final ResourceLocation UPGRADE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/icons/upgrade.png"); + public static final ResourceLocation RESEARCH = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/icons/research.png"); + + public static final ResourceLocation RELIC_EXPERIENCE_BACKGROUND = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/relic_experience_background.png"); + public static final ResourceLocation RELIC_EXPERIENCE_FILLER = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/relic_experience_filler.png"); + public static final ResourceLocation RELIC_EXPERIENCE_OUTLINE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/relic_experience_outline.png"); + + public static final ResourceLocation PLATE_PLAYER_EXPERIENCE_BACKGROUND = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/plate_player_experience_background.png"); + public static final ResourceLocation PLATE_PLAYER_EXPERIENCE_FILLER = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/plate_player_experience_filler.png"); + + public static final ResourceLocation LOGO = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/logo.png"); + + public static final ResourceLocation HINT_BACKGROUND = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/research/hint_background.png"); + public static final ResourceLocation HINT_OUTLINE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/research/hint_outline.png"); + + public static final ResourceLocation TIP_BACKGROUND = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/research/tip_background.png"); + public static final ResourceLocation TIP_OUTLINE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/research/tip_outline.png"); + + public static final ResourceLocation BULB = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/research/bulb.png"); + public static final ResourceLocation BULB_BROKEN = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/research/bulb_broken.png"); + public static final ResourceLocation BULB_GLOWING = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/research/bulb_glowing.png"); + public static final ResourceLocation BULB_BURNING = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/research/bulb_burning.png"); + + private static final ResourceLocation SMALL_CARD_MISSING = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/abilities/missing.png"); + + // TODO: Since ability may have different icons based on the relic state we need to implement some sort of default icon that will be used in the description UIs + @OnlyIn(Dist.CLIENT) + public static ResourceLocation getAbilityCardTexture(ItemStack stack, String ability) { + var item = stack.getItem(); + + if (!(item instanceof IRelicItem relic)) + return SMALL_CARD_MISSING; + + var minecraft = Minecraft.getInstance(); + + var texture = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/abilities/" + BuiltInRegistries.ITEM.getKey(item).getPath() + "/" + relic.getAbilityData(ability).getIcon().apply(minecraft.player, stack, ability) + ".png"); + + return minecraft.getResourceManager().getResource(texture).orElse(null) == null ? SMALL_CARD_MISSING : texture; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/misc/DescriptionUtils.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/misc/DescriptionUtils.java new file mode 100644 index 00000000..f2c09502 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/misc/DescriptionUtils.java @@ -0,0 +1,68 @@ +package it.hurts.sskirillss.relics.client.screen.description.misc; + +import it.hurts.sskirillss.relics.client.screen.description.ability.AbilityDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.experience.ExperienceDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.relic.RelicDescriptionScreen; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; + +public class DescriptionUtils { + public static final int TEXT_COLOR = 0x662F13; + private static final ResourceLocation TOOLTIP = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/tooltip.png"); + + @OnlyIn(Dist.CLIENT) + public static void drawTooltipBackground(GuiGraphics guiGraphics, int width, int height, int x, int y) { + int texWidth = 12; + int texHeight = 15; + + int xStep = 0; + + for (int i = 0; i < 2; i++) { + guiGraphics.blit(TOOLTIP, x + xStep, y, 9, 7, 0, 0, 9, 7, texWidth, texHeight); + guiGraphics.blit(TOOLTIP, x + xStep, y + 7, 9, height + 4, 0, 7, 9, 1, texWidth, texHeight); + guiGraphics.blit(TOOLTIP, x + xStep, y + height + 9, 9, 7, 0, 8, 9, 7, texWidth, texHeight); + + xStep += width + 9; + } + + guiGraphics.blit(TOOLTIP, x + 7, y + 5, 1, height + 6, 9, 0, 1, 1, texWidth, texHeight); + guiGraphics.blit(TOOLTIP, x + width + 10, y + 5, 1, height + 6, 10, 0, 1, 1, texWidth, texHeight); + + guiGraphics.blit(TOOLTIP, x + 8, y + 5, width + 2, 3, 11, 0, 1, 3, texWidth, texHeight); + guiGraphics.blit(TOOLTIP, x + 8, y + 8, width + 2, height + 1, 11, 3, 1, 1, texWidth, texHeight); + guiGraphics.blit(TOOLTIP, x + 8, y + height + 9, width + 2, 3, 11, 4, 1, 3, texWidth, texHeight); + } + + public static ItemStack gatherRelicStack(Player player, int slot) { + if (!player.containerMenu.isValidSlotIndex(slot)) + return ItemStack.EMPTY; + + ItemStack stack = player.containerMenu.getSlot(slot).getItem(); + + if (!(stack.getItem() instanceof IRelicItem)) + return ItemStack.EMPTY; + + return stack; + } + + @OnlyIn(Dist.CLIENT) + public static void openCachedScreen(IRelicItem relic, Player player, int slot, Screen screen) { + Screen descriptionScreen; + + switch (DescriptionCache.getEntry(relic).getSelectedPage()) { + case ABILITY -> descriptionScreen = new AbilityDescriptionScreen(player, player.containerMenu.containerId, slot, screen); + case EXPERIENCE -> descriptionScreen = new ExperienceDescriptionScreen(player, player.containerMenu.containerId, slot, screen); + default -> descriptionScreen = new RelicDescriptionScreen(player, player.containerMenu.containerId, slot, screen); + } + + Minecraft.getInstance().setScreen(descriptionScreen); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/RelicDescriptionScreen.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/RelicDescriptionScreen.java new file mode 100644 index 00000000..98cf7d4e --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/RelicDescriptionScreen.java @@ -0,0 +1,279 @@ +package it.hurts.sskirillss.relics.client.screen.description.relic; + +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.badges.base.RelicBadge; +import it.hurts.sskirillss.relics.client.screen.base.IAutoScaledScreen; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.IPagedDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import it.hurts.sskirillss.relics.client.screen.description.ability.AbilityDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.experience.ExperienceDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.general.misc.DescriptionPage; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.*; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.client.screen.description.relic.particles.ExperienceParticleData; +import it.hurts.sskirillss.relics.client.screen.description.relic.widgets.BigRelicCardWidget; +import it.hurts.sskirillss.relics.client.screen.description.relic.widgets.RelicExperienceWidget; +import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; +import it.hurts.sskirillss.relics.init.BadgeRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +import it.hurts.sskirillss.relics.utils.data.AnimationData; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import lombok.Getter; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractButton; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.RandomSource; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.registries.DeferredHolder; + +import java.awt.*; + +@OnlyIn(Dist.CLIENT) +public class RelicDescriptionScreen extends Screen implements IAutoScaledScreen, IRelicScreenProvider, IPagedDescriptionScreen { + public final Screen screen; + + @Getter + public final int container; + @Getter + public final int slot; + @Getter + public ItemStack stack; + + private final int backgroundHeight = 256; + private final int backgroundWidth = 418; + + public RelicDescriptionScreen(Player player, int container, int slot, Screen screen) { + super(Component.empty()); + + this.container = container; + this.slot = slot; + this.screen = screen; + + stack = DescriptionUtils.gatherRelicStack(player, slot); + } + + @Override + protected void init() { + if (stack == null || !(stack.getItem() instanceof IRelicItem relic)) + return; + + updateCache(relic); + + int x = (this.width - backgroundWidth) / 2; + int y = (this.height - backgroundHeight) / 2; + + var sources = relic.getLevelingSourcesData().getSources(); + var abilities = relic.getAbilitiesData().getAbilities(); + + this.addRenderableWidget(new PageWidget(x + 81, y + 123, this, DescriptionPage.RELIC, new RelicDescriptionScreen(minecraft.player, this.container, this.slot, this.screen))); + + int xOff = 19; + + if (!abilities.isEmpty()) { + this.addRenderableWidget(new PageWidget(x + 81 + xOff, y + 123, this, DescriptionPage.ABILITY, new AbilityDescriptionScreen(minecraft.player, this.container, this.slot, this.screen))); + + xOff += 19; + } + + if (!sources.isEmpty()) + this.addRenderableWidget(new PageWidget(x + 81 + xOff, y + 123, this, DescriptionPage.EXPERIENCE, new ExperienceDescriptionScreen(minecraft.player, this.container, this.slot, this.screen))); + + this.addRenderableWidget(new BigRelicCardWidget(x + 60, y + 47, this)); + + this.addRenderableWidget(new LogoWidget(x + 313, y + 57, this)); + + if (relic.isSomethingWrongWithLevelingPoints(stack)) + this.addRenderableWidget(new PointsFixWidget(x + 330, y + 33, this)); + + this.addRenderableWidget(new PointsPlateWidget(x + 313, y + 77, this)); + this.addRenderableWidget(new PlayerExperiencePlateWidget(x + 313, y + 102, this)); + this.addRenderableWidget(new LuckPlateWidget(x + 313, y + 127, this)); + + xOff = 0; + + for (RelicBadge badge : BadgeRegistry.BADGES.getEntries().stream().map(DeferredHolder::get).filter(entry -> entry instanceof RelicBadge).map(entry -> (RelicBadge) entry).toList()) { + if (!badge.isVisible(stack)) + continue; + + this.addRenderableWidget(new RelicBadgeWidget(x + 270 - xOff, y + 63, this, badge)); + + xOff += 15; + } + + this.addRenderableWidget(new RelicExperienceWidget(x + 142, y + 121, this)); + } + + @Override + public void rebuildWidgets() { + stack = DescriptionUtils.gatherRelicStack(minecraft.player, slot); + + super.rebuildWidgets(); + } + + @Override + public void tick() { + super.tick(); + + stack = DescriptionUtils.gatherRelicStack(minecraft.player, slot); + + LocalPlayer player = minecraft.player; + + if (player == null || stack == null || !(stack.getItem() instanceof IRelicItem)) + return; + + RandomSource random = player.getRandom(); + + int x = (this.width - backgroundWidth) / 2; + int y = (this.height - backgroundHeight) / 2; + + if (player.tickCount % 3 == 0) { + ParticleStorage.addParticle(this, new ExperienceParticleData( + new Color(140, random.nextInt(50), 255), + x + 73 + random.nextInt(20), y + 73 + random.nextInt(20), + 1.5F + (random.nextFloat() * 0.5F), 100 + random.nextInt(50))); + } + } + + @Override + public void renderBackground(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + super.renderBackground(guiGraphics, pMouseX, pMouseY, pPartialTick); + + LocalPlayer player = minecraft.player; + + if (stack == null || !(stack.getItem() instanceof IRelicItem relic) || player == null) + return; + + RelicData relicData = relic.getRelicData(); + + if (relicData == null) + return; + + int level = relic.getRelicLevel(stack); + + PoseStack poseStack = guiGraphics.pose(); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + RenderSystem.setShaderTexture(0, DescriptionTextures.SPACE_BACKGROUND); + + int x = (this.width - backgroundWidth) / 2; + int y = (this.height - backgroundHeight) / 2; + + int yOff = 0; + int xOff = 0; + + GUIRenderer.begin(DescriptionTextures.SPACE_BACKGROUND, poseStack) + .texSize(418, 4096) + .patternSize(backgroundWidth, backgroundHeight) + .pos(x + (backgroundWidth / 2F), y + (backgroundHeight / 2F)) + .animation(AnimationData.builder() + .frame(0, 2).frame(1, 2).frame(2, 2) + .frame(3, 2).frame(4, 2).frame(5, 2) + .frame(6, 2).frame(7, 2).frame(8, 2) + .frame(9, 2).frame(10, 2).frame(11, 2) + .frame(12, 2).frame(13, 2).frame(14, 2) + .frame(15, 2)) + .end(); + + GUIRenderer.begin(DescriptionTextures.BIG_CARD_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(x + 67, y + 57) + .end(); + + GUIRenderer.begin(DescriptionTextures.TOP_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(x + 107, y + 47) + .end(); + + GUIRenderer.begin(DescriptionTextures.BOTTOM_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(x + 60, y + 133) + .end(); + + poseStack.pushPose(); + + poseStack.scale(0.75F, 0.75F, 1F); + + guiGraphics.drawString(minecraft.font, Component.literal(stack.getDisplayName().getString() + .replace("[", "").replace("]", "")) + .withStyle(ChatFormatting.BOLD), (int) ((x + 113) * 1.33F), (int) ((y + 67) * 1.33F), DescriptionUtils.TEXT_COLOR, false); + + poseStack.popPose(); + + poseStack.pushPose(); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + yOff = 9; + + for (FormattedCharSequence line : minecraft.font.split(Component.translatable("tooltip.relics." + BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath() + ".description"), 340)) { + guiGraphics.drawString(minecraft.font, line, (x + 112) * 2, (y + 74) * 2 + yOff, DescriptionUtils.TEXT_COLOR, false); + + yOff += 10; + } + + poseStack.popPose(); + } + + @Override + public void render(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + super.render(guiGraphics, pMouseX, pMouseY, pPartialTick); + + for (GuiEventListener listener : this.children()) { + if (listener instanceof AbstractButton button && button.isHovered() + && button instanceof IHoverableWidget widget) { + guiGraphics.pose().translate(0, 0, 100); + + widget.onHovered(guiGraphics, pMouseX, pMouseY); + } + } + } + + @Override + public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) { + if (minecraft.options.keyInventory.isActiveAndMatches(InputConstants.getKey(pKeyCode, pScanCode))) { + this.onClose(); + + return true; + } + + return super.keyPressed(pKeyCode, pScanCode, pModifiers); + } + + @Override + public void onClose() { + screen.rebuildWidgets(); + + Minecraft.getInstance().setScreen(screen); + } + + @Override + public boolean isPauseScreen() { + return false; + } + + @Override + public int getAutoScale() { + return 0; + } + + @Override + public DescriptionPage getPage() { + return DescriptionPage.RELIC; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/particles/ChainParticleData.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/particles/ChainParticleData.java new file mode 100644 index 00000000..9b4c056c --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/particles/ChainParticleData.java @@ -0,0 +1,68 @@ +package it.hurts.sskirillss.relics.client.screen.description.relic.particles; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import it.hurts.sskirillss.relics.client.screen.description.general.particles.base.ParticleData; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; + +import java.awt.*; + +public class ChainParticleData extends ParticleData { + private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/particles/chain.png"); + + public ChainParticleData(Color color, float xStart, float yStart, float scale, int lifeTime) { + super(TEXTURE, color, xStart, yStart, scale, lifeTime); + } + + @Override + public void tick(Screen screen) { + super.tick(screen); + + LocalPlayer player = screen.getMinecraft().player; + + if (player == null) + return; + + var lifePercentage = (float) getLifeTime() / getMaxLifeTime(); + + setX(getX() + getDeltaX() * lifePercentage); + setY(getY() + getDeltaY() * lifePercentage + (getMaxLifeTime() - getLifeTime())); + } + + @Override + public void render(Screen screen, GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + PoseStack poseStack = guiGraphics.pose(); + + var lifePercentage = (float) getLifeTime() / getMaxLifeTime(); + + poseStack.pushPose(); + + RenderSystem.setShaderColor(getColor().getRed() / 255F, getColor().getGreen() / 255F, getColor().getBlue() / 255F, 1F); + + RenderSystem.enableBlend(); + + poseStack.translate(Mth.lerp(partialTick, getXO(), getX()), Mth.lerp(partialTick, getYO(), getY()), 0); + + poseStack.mulPose(Axis.ZP.rotationDegrees((getLifeTime() + partialTick) * getDeltaX())); + + GUIRenderer.begin(TEXTURE, guiGraphics.pose()) + .scale(getScale() * lifePercentage) + .anchor(SpriteAnchor.CENTER) + .end(); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + RenderSystem.defaultBlendFunc(); + RenderSystem.disableBlend(); + + poseStack.popPose(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/particles/ExperienceParticleData.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/particles/ExperienceParticleData.java new file mode 100644 index 00000000..a7ccff1a --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/particles/ExperienceParticleData.java @@ -0,0 +1,73 @@ +package it.hurts.sskirillss.relics.client.screen.description.relic.particles; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import it.hurts.sskirillss.relics.client.screen.description.general.particles.base.ParticleData; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import org.lwjgl.opengl.GL11; + +import java.awt.*; + +public class ExperienceParticleData extends ParticleData { + private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/particles/pixel.png"); + + public ExperienceParticleData(Color color, float xStart, float yStart, float scale, int lifeTime) { + super(TEXTURE, color, xStart, yStart, scale, lifeTime); + } + + @Override + public void tick(Screen screen) { + super.tick(screen); + + LocalPlayer player = screen.getMinecraft().player; + + if (player == null) + return; + + RandomSource random = player.getRandom(); + + setX((float) (getX() + (Math.sin(getLifeTime() * 0.15F) * (0.1F + (random.nextFloat() * 0.5F))))); + setY(getY() - 0.35F); + } + + @Override + public void render(Screen screen, GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + PoseStack poseStack = guiGraphics.pose(); + + var lifePercentage = (float) getLifeTime() / getMaxLifeTime(); + + float blinkOffset = 0.15F + (float) (Math.sin((getLifeTime() + partialTick) * 0.5F) * 0.3F); + + poseStack.pushPose(); + + RenderSystem.setShaderColor(getColor().getRed() / 255F + blinkOffset, getColor().getGreen() / 255F + blinkOffset, getColor().getBlue() / 255F + blinkOffset, lifePercentage); + + RenderSystem.enableBlend(); + RenderSystem.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); + + poseStack.translate(Mth.lerp(partialTick, getXO(), getX()), Mth.lerp(partialTick, getYO(), getY()), 0); + + poseStack.mulPose(Axis.ZP.rotationDegrees((getLifeTime() + partialTick) * 10)); + + GUIRenderer.begin(TEXTURE, guiGraphics.pose()) + .scale(getScale() * lifePercentage) + .anchor(SpriteAnchor.CENTER) + .end(); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + RenderSystem.defaultBlendFunc(); + RenderSystem.disableBlend(); + + poseStack.popPose(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/particles/SparkParticleData.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/particles/SparkParticleData.java new file mode 100644 index 00000000..41a95ba7 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/particles/SparkParticleData.java @@ -0,0 +1,72 @@ +package it.hurts.sskirillss.relics.client.screen.description.relic.particles; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import it.hurts.sskirillss.relics.client.screen.description.general.particles.base.ParticleData; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import org.lwjgl.opengl.GL11; + +import java.awt.*; + +public class SparkParticleData extends ParticleData { + private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/particles/pixel.png"); + + public SparkParticleData(Color color, float xStart, float yStart, float scale, int lifeTime) { + super(TEXTURE, color, xStart, yStart, scale, lifeTime); + } + + @Override + public void tick(Screen screen) { + super.tick(screen); + + LocalPlayer player = screen.getMinecraft().player; + + if (player == null) + return; + + var lifePercentage = (float) getLifeTime() / getMaxLifeTime(); + + setX(getX() + getDeltaX() * lifePercentage); + setY(getY() + getDeltaY() * lifePercentage + (getMaxLifeTime() - getLifeTime())); + } + + @Override + public void render(Screen screen, GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + PoseStack poseStack = guiGraphics.pose(); + + var lifePercentage = (float) getLifeTime() / getMaxLifeTime(); + + float blinkOffset = 0.25F + (float) (Math.sin(getLifeTime() + partialTick) * 0.5F); + + poseStack.pushPose(); + + RenderSystem.setShaderColor(getColor().getRed() / 255F + blinkOffset, getColor().getGreen() / 255F + blinkOffset, getColor().getBlue() / 255F + blinkOffset, lifePercentage); + + RenderSystem.enableBlend(); + RenderSystem.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); + + poseStack.translate(Mth.lerp(partialTick, getXO(), getX()), Mth.lerp(partialTick, getYO(), getY()), 0); + + poseStack.mulPose(Axis.ZP.rotationDegrees((getLifeTime() + partialTick) * 5)); + + GUIRenderer.begin(TEXTURE, guiGraphics.pose()) + .scale(getScale() * lifePercentage) + .anchor(SpriteAnchor.CENTER) + .end(); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + RenderSystem.defaultBlendFunc(); + RenderSystem.disableBlend(); + + poseStack.popPose(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/widgets/BigRelicCardWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/widgets/BigRelicCardWidget.java new file mode 100644 index 00000000..dedb2c2e --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/widgets/BigRelicCardWidget.java @@ -0,0 +1,179 @@ +package it.hurts.sskirillss.relics.client.screen.description.relic.widgets; + +import com.google.common.collect.Lists; +import com.mojang.math.Axis; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractDescriptionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.client.screen.description.relic.RelicDescriptionScreen; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.MathUtils; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.world.item.ItemStack; + +import java.util.List; + +public class BigRelicCardWidget extends AbstractDescriptionWidget implements IHoverableWidget { + private RelicDescriptionScreen screen; + + public BigRelicCardWidget(int x, int y, RelicDescriptionScreen screen) { + super(x, y, 48, 74); + + this.screen = screen; + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + var stack = screen.getStack(); + + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + var player = minecraft.player; + var poseStack = guiGraphics.pose(); + + poseStack.pushPose(); + + GUIRenderer.begin(DescriptionTextures.BIG_CARD_FRAME_UNLOCKED_ACTIVE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX(), getY()) + .end(); + + int xOff = 0; + + if (relic.hasUnlockedUpgradeableAbility(stack)) { + for (int i = 0; i < 5; i++) { + GUIRenderer.begin(DescriptionTextures.BIG_STAR_HOLE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + xOff + 4, getY() + 63) + .end(); + + xOff += 8; + } + + xOff = 0; + + var quality = relic.getRelicQuality(stack); + var isAliquot = quality % 2 == 1; + + for (int i = 0; i < Math.floor(quality / 2D); i++) { + GUIRenderer.begin(DescriptionTextures.BIG_STAR_ACTIVE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + xOff + 4, getY() + 63) + .end(); + + xOff += 8; + } + + if (isAliquot) + GUIRenderer.begin(DescriptionTextures.BIG_STAR_ACTIVE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + xOff + 4, getY() + 63) + .patternSize(4, 7) + .texSize(8, 7) + .end(); + } + + poseStack.pushPose(); + + float scale = 1.75F; + + poseStack.translate(getX() + 10 + 8 * scale, getY() + 21 + Math.sin((player.tickCount + pPartialTick) * 0.1F) * 2F + 8 * scale, 0); + + poseStack.mulPose(Axis.ZP.rotationDegrees((float) Math.cos((player.tickCount + pPartialTick) * 0.05F) * 5F)); + poseStack.mulPose(Axis.YP.rotationDegrees((float) Math.cos((player.tickCount + pPartialTick) * 0.075F) * 25F)); + + poseStack.translate(-8 * scale, -8 * scale, -150 * scale); + + poseStack.scale(scale, scale, scale); + + guiGraphics.renderItem(stack, 0, 0); + + poseStack.popPose(); + + poseStack.pushPose(); + + poseStack.scale(0.75F, 0.75F, 1F); + + MutableComponent levelComponent = Component.literal(String.valueOf(relic.getRelicLevel(stack))).withStyle(ChatFormatting.BOLD); + + guiGraphics.drawString(minecraft.font, levelComponent, (int) (((getX() + 25.5F) * 1.33F) - (minecraft.font.width(levelComponent) / 2F)), (int) ((getY() + 4) * 1.33F), 0xFFE278, true); + + poseStack.popPose(); + + if (isHovered() && relic.hasUnlockedUpgradeableAbility(stack)) + GUIRenderer.begin(DescriptionTextures.BIG_CARD_FRAME_OUTLINE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() - 1, getY() - 1) + .end(); + + poseStack.popPose(); + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + ItemStack stack = screen.getStack(); + + if (!(stack.getItem() instanceof IRelicItem relic) || !relic.hasUnlockedUpgradeableAbility(stack)) + return; + + var poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 150; + int renderWidth = 0; + + List entries = Lists.newArrayList( + Component.literal("").append(Component.translatable("tooltip.relics.researching.relic.info.level").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.UNDERLINE)).append(" " + relic.getRelicLevel(stack) + "/" + relic.getLevelingData().getMaxLevel()), + Component.literal("").append(Component.translatable("tooltip.relics.researching.relic.info.quality").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.UNDERLINE)).append(" " + MathUtils.round(relic.getRelicQuality(stack) / 2F, 1) + "/" + relic.getMaxQuality() / 2), + Component.literal(" ") + ); + + if (Screen.hasShiftDown()) + entries.add(Component.translatable("tooltip.relics.researching.relic.info.extra_info").withStyle(ChatFormatting.ITALIC)); + else + entries.add(Component.translatable("tooltip.relics.researching.general.extra_info")); + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) / 2); + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth + 2, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + poseStack.pushPose(); + + poseStack.translate(0F, 0F, 400); + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, tooltip.size() * 5, mouseX - 9 - (renderWidth / 2), mouseY); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + int yOff = 0; + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, ((mouseX - renderWidth / 2) + 1) * 2, ((mouseY + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.popPose(); + } + + @Override + public void playDownSound(SoundManager handler) { + + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/widgets/RelicExperienceWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/widgets/RelicExperienceWidget.java new file mode 100644 index 00000000..1bb89abb --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/relic/widgets/RelicExperienceWidget.java @@ -0,0 +1,173 @@ +package it.hurts.sskirillss.relics.client.screen.description.relic.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractDescriptionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.client.screen.description.relic.RelicDescriptionScreen; +import it.hurts.sskirillss.relics.client.screen.description.relic.particles.ExperienceParticleData; +import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.MathUtils; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.RandomSource; + +import java.awt.*; +import java.util.List; + +public class RelicExperienceWidget extends AbstractDescriptionWidget implements IHoverableWidget, ITickingWidget { + private static final int FILLER_WIDTH = 125; + + private final IRelicScreenProvider screen; + + public RelicExperienceWidget(int x, int y, IRelicScreenProvider screen) { + super(x, y, 139, 15); + + this.screen = screen; + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + LocalPlayer player = Minecraft.getInstance().player; + + if (player == null || !(screen.getStack().getItem() instanceof IRelicItem relic)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + poseStack.pushPose(); + + float color = (float) (1.025F + (Math.sin(player.tickCount * 0.5F) * 0.05F)); + + GUIRenderer.begin(DescriptionTextures.RELIC_EXPERIENCE_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX(), getY() - 10) + .end(); + + RenderSystem.enableBlend(); + + GUIRenderer.begin(DescriptionTextures.RELIC_EXPERIENCE_FILLER, poseStack) + .patternSize(calculateFillerWidth(relic), 11) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + 3, getY() + 2) + .color(color, color, color, 1F) + .texSize(FILLER_WIDTH, 11) + .end(); + + RenderSystem.disableBlend(); + + if (isHovered()) + GUIRenderer.begin(DescriptionTextures.RELIC_EXPERIENCE_OUTLINE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() - 1, getY() - 6) + .end(); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + MutableComponent percentage = Component.literal(relic.isRelicMaxLevel(screen.getStack()) ? "MAX" : MathUtils.round(calculateFillerPercentage(relic), 1) + "%").withStyle(ChatFormatting.BOLD); + + guiGraphics.drawString(minecraft.font, percentage, (getX() + 67) * 2 - (minecraft.font.width(percentage) / 2), (getY() + 6) * 2, DescriptionUtils.TEXT_COLOR, false); + + poseStack.popPose(); + } + + @Override + public void onTick() { + if (!(screen.getStack().getItem() instanceof IRelicItem relic) || minecraft.player == null) + return; + + RandomSource random = minecraft.player.getRandom(); + + int fillerWidth = calculateFillerWidth(relic); + + if (minecraft.player.tickCount % 5 == 0) { + for (float i = 0; i < fillerWidth / 40F; i++) { + ParticleStorage.addParticle((Screen) screen, new ExperienceParticleData(new Color(200, 255, 0), + getX() + 5 + random.nextInt(fillerWidth), getY() + random.nextInt(2), 1F + (random.nextFloat() * 0.25F), 50 + random.nextInt(50))); + } + } + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + if (!(screen.getStack().getItem() instanceof IRelicItem relic)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 150; + int renderWidth = 0; + + int level = relic.getRelicLevel(screen.getStack()); + + List entries = Lists.newArrayList( + Component.literal("").append(Component.translatable("tooltip.relics.researching.relic.experience.title").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.UNDERLINE)) + .append(" " + (relic.isRelicMaxLevel(screen.getStack()) ? "MAX" : relic.getRelicExperience(screen.getStack()) + "/" + relic.getTotalRelicExperienceBetweenLevels(level, level + 1))), + Component.literal(" ") + ); + + if (Screen.hasShiftDown()) + entries.add(Component.translatable("tooltip.relics.researching.relic.experience.extra_info").withStyle(ChatFormatting.ITALIC)); + else + entries.add(Component.translatable("tooltip.relics.researching.general.extra_info")); + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) / 2); + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth + 2, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + poseStack.pushPose(); + + poseStack.translate(0F, 0F, 100); + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, tooltip.size() * 5, mouseX - 9 - (renderWidth / 2), mouseY); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + int yOff = 0; + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, ((mouseX - renderWidth / 2) + 1) * 2, ((mouseY + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.popPose(); + } + + @Override + public void playDownSound(SoundManager handler) { + + } + + private float calculateFillerPercentage(IRelicItem relic) { + int level = relic.getRelicLevel(screen.getStack()); + + return relic.getRelicExperience(screen.getStack()) / (relic.getTotalRelicExperienceBetweenLevels(level, level + 1) / 100F); + } + + private int calculateFillerWidth(IRelicItem relic) { + return relic.isRelicMaxLevel(screen.getStack()) ? FILLER_WIDTH : (int) Math.ceil(calculateFillerPercentage(relic) / 100F * FILLER_WIDTH); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/AbilityResearchScreen.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/AbilityResearchScreen.java new file mode 100644 index 00000000..b263ce2d --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/AbilityResearchScreen.java @@ -0,0 +1,709 @@ +package it.hurts.sskirillss.relics.client.screen.description.research; + +import com.google.common.collect.Lists; +import com.google.common.collect.Multimap; +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import it.hurts.sskirillss.relics.client.screen.base.IAutoScaledScreen; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.IRelicScreenProvider; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.*; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.client.screen.description.research.misc.BurnPoint; +import it.hurts.sskirillss.relics.client.screen.description.research.particles.ResearchParticleData; +import it.hurts.sskirillss.relics.client.screen.description.research.widgets.HintWidget; +import it.hurts.sskirillss.relics.client.screen.description.research.widgets.StarWidget; +import it.hurts.sskirillss.relics.client.screen.description.research.widgets.TipWidget; +import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; +import it.hurts.sskirillss.relics.client.screen.utils.ScreenUtils; +import it.hurts.sskirillss.relics.init.SoundRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +import it.hurts.sskirillss.relics.items.relics.base.data.research.ResearchData; +import it.hurts.sskirillss.relics.items.relics.base.data.research.StarData; +import it.hurts.sskirillss.relics.network.NetworkHandler; +import it.hurts.sskirillss.relics.network.packets.research.PacketManageLink; +import it.hurts.sskirillss.relics.utils.MathUtils; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.RenderUtils; +import it.hurts.sskirillss.relics.utils.data.AnimationData; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import lombok.Getter; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.AbstractButton; +import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.Style; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.phys.Vec2; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import org.apache.commons.lang3.tuple.Pair; +import org.joml.Vector2f; +import org.lwjgl.glfw.GLFW; + +import javax.annotation.Nullable; +import java.awt.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; + +@OnlyIn(Dist.CLIENT) +public class AbilityResearchScreen extends Screen implements IAutoScaledScreen, IRelicScreenProvider { + public final Screen screen; + + @Getter + public final int container; + @Getter + public final int slot; + @Getter + public ItemStack stack; + + public final String ability; + + public int backgroundHeight = 256; + public int backgroundWidth = 418; + + public int x; + public int y; + + @Nullable + public StarData selectedStar; + + private List points = new ArrayList<>(); + private List stars = new ArrayList<>(); + + private final int maxResearchProgress = 40; + private int researchProgress = 0; + + public AbilityResearchScreen(Player player, int container, int slot, Screen screen, String ability) { + super(Component.empty()); + + this.container = container; + this.slot = slot; + this.screen = screen; + + this.ability = ability; + + stack = DescriptionUtils.gatherRelicStack(player, slot); + } + + public int getTotalConnectionsCount(StarData star) { + if (!(stack.getItem() instanceof IRelicItem relic)) + return 0; + + return relic.getAbilityData(ability).getResearchData().getConnectedStars(star).size(); + } + + public int getOccupiedConnectionsCount(StarData star) { + if (!(stack.getItem() instanceof IRelicItem relic)) + return 0; + + int index = star.getIndex(); + + return (int) relic.getResearchLinks(stack, ability).entries().stream() + .filter(entry -> entry.getKey() == index || entry.getValue() == index) + .map(entry -> entry.getKey() < entry.getValue() + ? entry.getKey() + "-" + entry.getValue() + : entry.getValue() + "-" + entry.getKey()) + .distinct() + .count(); + } + + @Override + protected void init() { + super.init(); + + this.x = (this.width - backgroundWidth) / 2; + this.y = (this.height - backgroundHeight) / 2; + + if (stack == null || !(stack.getItem() instanceof IRelicItem relic)) + return; + + researchProgress = 0; + + stars.clear(); + points.clear(); + + this.addRenderableWidget(new LogoWidget(x + 313, y + 57, this)); + + if (relic.isSomethingWrongWithLevelingPoints(stack)) + this.addRenderableWidget(new PointsFixWidget(x + 330, y + 33, this)); + + this.addRenderableWidget(new PointsPlateWidget(x + 313, y + 77, this)); + this.addRenderableWidget(new PlayerExperiencePlateWidget(x + 313, y + 102, this)); + this.addRenderableWidget(new LuckPlateWidget(x + 313, y + 127, this)); + + this.addRenderableWidget(new TipWidget(x + 117, y + 207, this)); + + this.addRenderableWidget(new HintWidget(x + 192, y + 198, this)); + + int starSize = 17; + + for (var entry : relic.getAbilityData(ability).getResearchData().getStars().values()) + stars.add(this.addWidget(new StarWidget((int) (x + 67 + (entry.getX() * 5F) - starSize / 2F), (int) (y + 54 + (entry.getY() * 5F) - starSize / 2F), this, entry))); + } + + @Override + public void rebuildWidgets() { + stack = DescriptionUtils.gatherRelicStack(minecraft.player, slot); + + super.rebuildWidgets(); + } + + @Override + public void tick() { + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + super.tick(); + + stack = DescriptionUtils.gatherRelicStack(minecraft.player, slot); + + RandomSource random = minecraft.player.getRandom(); + + if (relic.isAbilityResearched(stack, ability)) { + if (researchProgress >= 0 && researchProgress < maxResearchProgress) { + researchProgress++; + + if (researchProgress % 3 == 0) { + ResearchData researchData = relic.getResearchData(ability); + + for (var link : relic.getResearchLinks(stack, ability).entries()) { + var start = researchData.getStars().get(link.getKey()).getPos(); + var end = researchData.getStars().get(link.getValue()).getPos(); + + executeForConnection(start, end, 0.75F, point -> { + ParticleStorage.addParticle(this, new ResearchParticleData(new Color(100 + random.nextInt(150), random.nextInt(25), 200 + random.nextInt(50)), + point.x + MathUtils.randomFloat(random), point.y + MathUtils.randomFloat(random), 1F + (random.nextFloat() * 0.25F), 20 + random.nextInt(40 + researchProgress), random.nextFloat() * 0.025F)); + }); + } + } + } + } + + if (minecraft.player.tickCount % 3 == 0) { + var links = relic.getResearchLinks(stack, ability); + + for (var pair : links.entries()) { + var start = pair.getKey(); + var end = pair.getValue(); + + var startStar = stars.stream().filter(entry -> entry.getStar().getIndex() == start).findFirst(); + var endStar = stars.stream().filter(entry -> entry.getStar().getIndex() == end).findFirst(); + + if (startStar.isPresent() && endStar.isPresent()) + executeForConnection(startStar.get().getStar().getPos(), endStar.get().getStar().getPos(), 1.1F, point -> { + addStaticPoint((int) point.x, (int) point.y, 0.06F, Pair.of(start, end)); + }); + } + + for (var pair : points.stream().map(BurnPoint::getLink).filter(Objects::nonNull).toList()) { + var start = pair.getKey(); + var end = pair.getValue(); + + if (!links.containsEntry(start, end) && !links.containsEntry(end, start)) { + this.points.stream().filter(point -> point.getLink() != null && point.getLink().getKey().equals(start) && point.getLink().getValue().equals(end)).forEach(entry -> { + entry.setLink(null); + entry.setTicker(point -> { + int time = point.getLifeTime(); + + if (time <= 0) + return; + + point.setLifeTime(--time); + + float diff = Mth.clamp(point.getLifeTime(), 0.01F, point.getMaxLifeTime()) / point.getMaxLifeTime(); + + point.setScaleO(point.getScale()); + point.setScale(point.getScale() * diff); + }); + }); + } + } + } + + for (BurnPoint point : points) + point.tick(); + } + + private void addAbstractPoint(BurnPoint point) { + if (points.size() >= 256) + return; + + var optional = points.stream().filter(entry -> entry.getX() == point.getX() && entry.getY() == point.getY()).findAny(); + + if (optional.isPresent()) { + if (optional.get().getLifeTime() > 0) + return; + } else + optional = points.stream().filter(entry -> entry.getLifeTime() <= 0).findFirst(); + + if (optional.isEmpty()) + points.add(point); + else optional.get().set(point); + } + + private void addLivingPoint(int x, int y, int lifeTime, float scale) { + addAbstractPoint(BurnPoint.builder(x, y, scale) + .lifeTime(lifeTime) + .maxLifeTime(lifeTime) + .ticker(point -> { + int time = point.getLifeTime(); + + if (time < 0) + return; + + point.setLifeTime(--time); + + float diff = Mth.clamp(point.getLifeTime(), 0.01F, point.getMaxLifeTime()) / point.getMaxLifeTime(); + + point.setScaleO(point.getScale()); + point.setScale(point.getMaxScale() * diff); + }) + .build()); + } + + private void addStaticPoint(int x, int y, float scale, Pair link) { + addAbstractPoint(BurnPoint.builder(x, y, scale) + .scale(0F) + .lifeTime(1) + .maxLifeTime(8) + .ticker(point -> { + point.setScaleO(point.getScale()); + + if (researchProgress <= 0) { + int time = point.getLifeTime(); + + if (time >= point.getMaxLifeTime()) + return; + + point.setLifeTime(++time); + + float diff = Mth.clamp(point.getLifeTime(), 0.01F, point.getMaxLifeTime()) / point.getMaxLifeTime(); + + point.setScale(point.getMaxScale() * diff); + } else + point.setScale(point.getScale() + (researchProgress * 0.00075F)); + }) + .link(link) + .build()); + } + + @Override + public void renderBackground(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + super.renderBackground(guiGraphics, pMouseX, pMouseY, pPartialTick); + + LocalPlayer player = minecraft.player; + + if (stack == null || !(stack.getItem() instanceof IRelicItem relic) || player == null) + return; + + RelicData relicData = relic.getRelicData(); + + if (relicData == null) + return; + + PoseStack poseStack = guiGraphics.pose(); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + GUIRenderer.begin(DescriptionTextures.SPACE_BACKGROUND, poseStack) + .texSize(418, 4096) + .patternSize(backgroundWidth, backgroundHeight) + .pos(x + (backgroundWidth / 2F), y + (backgroundHeight / 2F)) + .animation(AnimationData.builder() + .frame(0, 2).frame(1, 2).frame(2, 2) + .frame(3, 2).frame(4, 2).frame(5, 2) + .frame(6, 2).frame(7, 2).frame(8, 2) + .frame(9, 2).frame(10, 2).frame(11, 2) + .frame(12, 2).frame(13, 2).frame(14, 2) + .frame(15, 2)) + .end(); + + { + float color = (float) (0.5F + (Math.sin((player.tickCount + pPartialTick) * 0.1F) * 0.1F)); + + GUIRenderer.begin(DescriptionTextures.getAbilityCardTexture(stack, ability), poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .color(color, color, color, 1F) + .pos(x + 67, y + 54) + .texSize(110, 155) + .end(); + } + + { + ResearchData researchData = relic.getAbilityData(ability).getResearchData(); + + for (var link : relic.getResearchLinks(stack, ability).entries()) { + var start = researchData.getStars().get(link.getKey()).getPos(); + var end = researchData.getStars().get(link.getValue()).getPos(); + + drawLink(poseStack, getScaledPos(start), getScaledPos(end), pMouseX, pMouseY, pPartialTick); + } + + if (selectedStar != null) { + var pos = selectedStar.getPos(); + + drawLink(poseStack, getScaledPos(pos), new Vec2(pMouseX, pMouseY), pMouseX, pMouseY, pPartialTick); + } + } + + { + for (StarWidget widget : stars) { + widget.renderWidget(guiGraphics, pMouseX, pMouseY, pPartialTick); + } + } + + { + poseStack.pushPose(); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + RenderSystem.setShaderTexture(0, DescriptionTextures.RESEARCH_FOG); + + List positions = Lists.newArrayList(new Vector2f(pMouseX, pMouseY)); + List scales = Lists.newArrayList(0.15F); + List noises = Lists.newArrayList(10F); + + addLivingPoint(pMouseX, pMouseY, 3, 0.1F); + + for (BurnPoint point : points) { + boolean shouldRender = point.getLifeTime() > 0; + + positions.add(new Vector2f(shouldRender ? point.getX() : -100, shouldRender ? point.getY() : -100)); + scales.add(Mth.lerp(pPartialTick, point.getScaleO(), point.getScale())); + noises.add(point.getScale() * 75); + } + + poseStack.translate(0, 0, 5000); + + RenderUtils.renderRevealingPanel(poseStack, x + 67, y + 54, 110, 155, positions, scales, noises, (player.tickCount + pPartialTick) / 50F); + + GUIRenderer.begin(DescriptionTextures.RESEARCH_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(x + 60, y + 45) + .end(); + + poseStack.popPose(); + } + + { + poseStack.pushPose(); + + var title = Component.translatableWithFallback("tooltip.relics." + BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath() + ".ability." + ability, ability); + + if (!relic.isAbilityUnlocked(stack, ability)) { + title = ScreenUtils.stylizeWithReplacement(title, 1F, Style.EMPTY.withFont(ScreenUtils.ILLAGER_ALT_FONT).withColor(0x9E00B0), ability.length()); + + var random = player.getRandom(); + + var shakeX = MathUtils.randomFloat(random) * 0.5F; + var shakeY = MathUtils.randomFloat(random) * 0.5F; + + poseStack.translate(shakeX, shakeY, 0F); + } else + title.withStyle(ChatFormatting.BOLD); + + poseStack.translate((int) (x + 184 + (102 / 2F) - (minecraft.font.width(title) / 2F / 1.3F)), y + 67, 0F); + + poseStack.scale(0.75F, 0.75F, 1F); + + guiGraphics.drawString(minecraft.font, title, 0, 0, DescriptionUtils.TEXT_COLOR, false); + + poseStack.popPose(); + } + + { + poseStack.pushPose(); + + poseStack.translate(x + 184 + (102 / 2F), y + 100, 0F); + + poseStack.scale(0.5F, 0.5F, 1F); + + int yOff = 0; + + List placeholders = new ArrayList<>(); + + for (var stat : relic.getAbilityData(ability).getStats().values()) + placeholders.add(stat.getFormatValue().apply(relic.getStatValue(stack, ability, stat.getId(), relic.getAbilityLevel(stack, ability)))); + + var component = Component.translatable("tooltip.relics." + BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath() + ".ability." + ability + ".description", placeholders.toArray()); + + var startColor = 0xE500FF; + var endColor = DescriptionUtils.TEXT_COLOR; + + float progress = (float) researchProgress / maxResearchProgress; + + int startRed = (startColor >> 16) & 0xFF; + int startGreen = (startColor >> 8) & 0xFF; + int startBlue = startColor & 0xFF; + + int endRed = (endColor >> 16) & 0xFF; + int endGreen = (endColor >> 8) & 0xFF; + int endBlue = endColor & 0xFF; + + int red = (int) (startRed + (endRed - startRed) * progress); + int green = (int) (startGreen + (endGreen - startGreen) * progress); + int blue = (int) (startBlue + (endBlue - startBlue) * progress); + + int color = (red << 16) | (green << 8) | blue; + + if (researchProgress < maxResearchProgress) + component.withColor(color); + + component = ScreenUtils.stylizeWithReplacement(component, 1F - progress, Style.EMPTY.withFont(ScreenUtils.ILLAGER_ALT_FONT), ability.length()); + + for (FormattedCharSequence line : minecraft.font.split(component, 180)) { + guiGraphics.drawString(minecraft.font, line, -(minecraft.font.width(line) / 2F), yOff, DescriptionUtils.TEXT_COLOR, false); + + yOff += 10; + } + + poseStack.popPose(); + } + } + + public Vec2 getScaledPos(Vec2 pos) { + int scale = 5; + + return new Vec2(x + 67 + (pos.x * scale), y + 54 + (pos.y * scale)); + } + + private void drawLink(PoseStack poseStack, Vec2 start, Vec2 end, int mouseX, int mouseY, float partialTick) { + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + poseStack.pushPose(); + + float offset = (float) (Math.sin(((minecraft.player.tickCount + partialTick + start.length()) * 0.2F)) * 0.1F); + float color = 1.25F + offset; + + if (!relic.isAbilityResearched(stack, ability) && isHoveringConnection(start, end, mouseX, mouseY)) + RenderSystem.setShaderColor(color, 0.25F, 0.25F, 0.75F + offset); + else + RenderSystem.setShaderColor(color, color, color, 0.75F + offset); + + RenderSystem.enableBlend(); + + int width = 6; + int height = 4; + + int distance = (int) Math.sqrt(start.distanceToSqr(end)); + + poseStack.translate(start.x, start.y, 0); + + poseStack.mulPose(Axis.ZP.rotationDegrees(getAngle(start, end))); + + poseStack.translate(-(width / 2F), -(height / 2F), 0); + + RenderSystem.setShaderTexture(0, ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/research/line.png")); + + GUIRenderer.begin(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/research/line.png"), poseStack) + .pos(0, 0) + .texSize(width, height * 6) + .patternSize(distance, height) + .anchor(SpriteAnchor.TOP_LEFT) + .animation(AnimationData.builder() + .frame(0, 2).frame(1, 2).frame(2, 2) + .frame(3, 2).frame(4, 2).frame(5, 2) + ) + .end(); + + poseStack.mulPose(Axis.ZP.rotationDegrees(-getAngle(start, end))); + + RenderSystem.disableBlend(); + + poseStack.popPose(); + } + + private void executeForConnection(Vec2 start, Vec2 end, float step, Consumer task) { + int steps = (int) (Math.sqrt(start.distanceToSqr(end)) / step); + + Vec2 direction = new Vec2(end.x - start.x, end.y - start.y).normalized(); + + for (int i = 0; i <= steps; i++) { + Vec2 point = new Vec2(direction.x * step * i, direction.y * step * i).add(start); + + task.accept(getScaledPos(point)); + } + } + + private boolean isHoveringConnection(Vec2 start, Vec2 end, int mouseX, int mouseY) { + float minDistance = 4F; + float thickness = 4F; + + float x1 = start.x; + float y1 = start.y; + + float x2 = end.x; + float y2 = end.y; + + double distanceToStart = Math.hypot(mouseX - x1, mouseY - y1); + double distanceToEnd = Math.hypot(mouseX - x2, mouseY - y2); + + if (distanceToStart < minDistance || distanceToEnd < minDistance) + return false; + + double collinearity = (x2 - x1) * (mouseY - y1) - (y2 - y1) * (mouseX - x1); + + double lineLength = Math.hypot(x2 - x1, y2 - y1); + double distanceFromLine = Math.abs(collinearity / lineLength); + + if (distanceFromLine > thickness / 2) + return false; + + return Math.min(x1, x2) - thickness / 2 <= mouseX && mouseX <= Math.max(x1, x2) + thickness / 2 + && Math.min(y1, y2) - thickness / 2 <= mouseY && mouseY <= Math.max(y1, y2) + thickness / 2; + } + + @Override + public void render(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + super.render(guiGraphics, pMouseX, pMouseY, pPartialTick); + + for (GuiEventListener listener : this.children()) { + if (listener instanceof AbstractButton button && button.isHovered() + && button instanceof IHoverableWidget widget) { + guiGraphics.pose().translate(0, 0, 100); + + widget.onHovered(guiGraphics, pMouseX, pMouseY); + } + } + } + + @Override + public boolean keyPressed(int pKeyCode, int pScanCode, int pModifiers) { + if (minecraft.options.keyInventory.isActiveAndMatches(InputConstants.getKey(pKeyCode, pScanCode))) { + this.onClose(); + + return true; + } + + return super.keyPressed(pKeyCode, pScanCode, pModifiers); + } + + @Override + public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) { + if (stack.getItem() instanceof IRelicItem relic && !relic.isAbilityResearched(stack, ability) && pButton == GLFW.GLFW_MOUSE_BUTTON_LEFT) { + ResearchData researchData = relic.getResearchData(ability); + + Pair toRemove = null; + + for (var link : relic.getResearchLinks(stack, ability).entries()) + if (isHoveringConnection(getScaledPos(researchData.getStars().get(link.getKey()).getPos()), getScaledPos(researchData.getStars().get(link.getValue()).getPos()), (int) pMouseX, (int) pMouseY)) + toRemove = Pair.of(link.getKey(), link.getValue()); + + if (toRemove != null) + removeLink(toRemove.getKey(), toRemove.getValue()); + } + + return super.mouseClicked(pMouseX, pMouseY, pButton); + } + + public void addLink(int start, int end) { + var startStar = stars.stream().filter(entry -> entry.getStar().getIndex() == start).findFirst(); + var endStar = stars.stream().filter(entry -> entry.getStar().getIndex() == end).findFirst(); + + if (startStar.isEmpty() || endStar.isEmpty()) + return; + + var random = minecraft.player.getRandom(); + + NetworkHandler.sendToServer(new PacketManageLink(container, slot, ability, PacketManageLink.Operation.ADD, start, end)); + + executeForConnection(startStar.get().getStar().getPos(), endStar.get().getStar().getPos(), 0.25F, point -> { + ParticleStorage.addParticle(this, new ResearchParticleData(new Color(100 + random.nextInt(150), random.nextInt(25), 200 + random.nextInt(50)), + point.x + MathUtils.randomFloat(random), point.y + MathUtils.randomFloat(random), 1F + (random.nextFloat() * 0.25F), 20 + random.nextInt(60), random.nextFloat() * 0.025F)); + }); + } + + public void removeLink(int start, int end) { + var startStar = stars.stream().filter(entry -> entry.getStar().getIndex() == start).findFirst(); + var endStar = stars.stream().filter(entry -> entry.getStar().getIndex() == end).findFirst(); + + if (startStar.isEmpty() || endStar.isEmpty()) + return; + + var random = minecraft.player.getRandom(); + + NetworkHandler.sendToServer(new PacketManageLink(container, slot, ability, PacketManageLink.Operation.REMOVE, start, end)); + + executeForConnection(startStar.get().getStar().getPos(), endStar.get().getStar().getPos(), 0.1F, point -> { + ParticleStorage.addParticle(this, new ResearchParticleData(new Color(100 + random.nextInt(150), random.nextInt(25), 200 + random.nextInt(50)), + point.x + MathUtils.randomFloat(random), point.y + MathUtils.randomFloat(random), 1F + (random.nextFloat() * 0.25F), 10 + random.nextInt(50), random.nextFloat() * 0.01F)); + }); + + minecraft.getSoundManager().play(SimpleSoundInstance.forUI(SoundRegistry.DISCONNECT_STARS.get(), 0.75F + minecraft.player.getRandom().nextFloat() * 0.5F, 0.75F)); + } + + @Override + public boolean mouseReleased(double pMouseX, double pMouseY, int pButton) { + if (stack.getItem() instanceof IRelicItem relic && pButton == GLFW.GLFW_MOUSE_BUTTON_LEFT && selectedStar != null) { + + for (StarWidget widget : stars) { + if (!widget.isHovered()) + continue; + + Multimap links = relic.getResearchLinks(stack, ability); + + int start = selectedStar.getIndex(); + int end = widget.getStar().getIndex(); + + StarData star = widget.getStar(); + + if (start == end || getOccupiedConnectionsCount(star) >= getTotalConnectionsCount(star) + || links.containsEntry(start, end) || links.containsEntry(end, start)) + continue; + + addLink(start, end); + + break; + } + + selectedStar = null; + } + + return super.mouseReleased(pMouseX, pMouseY, pButton); + } + + @Override + public void onClose() { + screen.rebuildWidgets(); + + minecraft.setScreen(screen); + } + + @Override + public boolean isPauseScreen() { + return false; + } + + @Override + public int getAutoScale() { + return 0; + } + + public float getAngle(Vec2 from, Vec2 to) { + float angle = (float) Math.toDegrees(Math.atan2(to.y - from.y, to.x - from.x)); + + if (angle < 0) + angle += 360; + + return angle; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/misc/BurnPoint.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/misc/BurnPoint.java new file mode 100644 index 00000000..10bab9cd --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/misc/BurnPoint.java @@ -0,0 +1,75 @@ +package it.hurts.sskirillss.relics.client.screen.description.research.misc; + +import lombok.Builder; +import lombok.Data; +import org.apache.commons.lang3.tuple.Pair; + +import javax.annotation.Nullable; +import java.util.function.Consumer; + +@Data +@Builder +public class BurnPoint { + public static BurnPointBuilder builder(int x, int y, float scale) { + BurnPointBuilder builder = new BurnPointBuilder(); + + builder.x(x); + builder.y(y); + + builder.maxScale(scale); + builder.scale(scale); + + builder.link(null); + + return builder; + } + + @Nullable + private Pair link; + + private float x; + private float y; + + private int maxLifeTime; + private int lifeTime; + + private float maxScale; + private float scale; + private float scaleO; + + @Builder.Default + private Consumer ticker = (point) -> { + + }; + + public final void tick() { + getTicker().accept(this); + } + + public BurnPoint set(BurnPoint other) { + setLink(other.getLink()); + + setX(other.getX()); + setY(other.getY()); + + setMaxLifeTime(other.getMaxLifeTime()); + setLifeTime(other.getLifeTime()); + + setMaxScale(other.getMaxScale()); + setScaleO(other.getScale()); + setScale(other.getScale()); + + setTicker(other.getTicker()); + + return this; + } + + public static class BurnPointBuilder { + public BurnPointBuilder scale(float scale) { + this.scaleO = scale; + this.scale = scale; + + return this; + } + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/particles/ResearchParticleData.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/particles/ResearchParticleData.java new file mode 100644 index 00000000..566e22fe --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/particles/ResearchParticleData.java @@ -0,0 +1,77 @@ +package it.hurts.sskirillss.relics.client.screen.description.research.particles; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import it.hurts.sskirillss.relics.client.screen.description.general.particles.base.ParticleData; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import org.lwjgl.opengl.GL11; + +import java.awt.*; + +public class ResearchParticleData extends ParticleData { + private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/general/particles/pixel.png"); + + private final float verticalAcceleration; + + public ResearchParticleData(Color color, float xStart, float yStart, float scale, int lifeTime, float verticalAcceleration) { + super(TEXTURE, color, xStart, yStart, scale, lifeTime); + + this.verticalAcceleration = verticalAcceleration; + } + + @Override + public void tick(Screen screen) { + super.tick(screen); + + LocalPlayer player = screen.getMinecraft().player; + + if (player == null) + return; + + RandomSource random = player.getRandom(); + + setX((float) (getX() + (Math.sin(getLifeTime() * 0.15F) * (0.1F + (random.nextFloat() * 0.5F))))); + setY(getY() - (getLifeTime() * verticalAcceleration)); + } + + @Override + public void render(Screen screen, GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + PoseStack poseStack = guiGraphics.pose(); + + var lifePercentage = (float) getLifeTime() / getMaxLifeTime(); + + float blinkOffset = 0.25F + (float) (Math.sin(getLifeTime() + partialTick) * 0.5F); + + poseStack.pushPose(); + + RenderSystem.setShaderColor(getColor().getRed() / 255F + blinkOffset, getColor().getGreen() / 255F + blinkOffset, getColor().getBlue() / 255F + blinkOffset, lifePercentage); + + RenderSystem.enableBlend(); + RenderSystem.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); + + poseStack.translate(Mth.lerp(partialTick, getXO(), getX()), Mth.lerp(partialTick, getYO(), getY()), 0); + + poseStack.mulPose(Axis.ZP.rotationDegrees((getLifeTime() + partialTick) * 25)); + + GUIRenderer.begin(TEXTURE, guiGraphics.pose()) + .scale(getScale() * lifePercentage) + .anchor(SpriteAnchor.CENTER) + .end(); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + RenderSystem.defaultBlendFunc(); + RenderSystem.disableBlend(); + + poseStack.popPose(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/particles/SmokeParticleData.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/particles/SmokeParticleData.java new file mode 100644 index 00000000..ce2c0e06 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/particles/SmokeParticleData.java @@ -0,0 +1,75 @@ +package it.hurts.sskirillss.relics.client.screen.description.research.particles; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import it.hurts.sskirillss.relics.client.screen.description.general.particles.base.ParticleData; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Mth; + +import java.awt.*; + +public class SmokeParticleData extends ParticleData { + private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/relic/particles/smoke.png"); + + private final float fadeInPercentage; + + public SmokeParticleData(float xStart, float yStart, float scale, int lifeTime, float fadeInPercentage) { + super(TEXTURE, new Color(1F, 1F, 1F), xStart, yStart, scale, lifeTime); + + this.fadeInPercentage = fadeInPercentage; + } + + @Override + public void tick(Screen screen) { + super.tick(screen); + + LocalPlayer player = screen.getMinecraft().player; + + if (player == null) + return; + + var lifePercentage = (float) getLifeTime() / getMaxLifeTime(); + + setX(getX() + getDeltaX() * lifePercentage); + setY(getY() + getDeltaY() * lifePercentage); + } + + @Override + public void render(Screen screen, GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTick) { + PoseStack poseStack = guiGraphics.pose(); + + var lifePercentage = (float) getLifeTime() / getMaxLifeTime(); + + float maxScale = getScale(); + float ratio = 1F - lifePercentage; + float scale = ratio <= fadeInPercentage ? maxScale * (ratio / fadeInPercentage) : maxScale; + + poseStack.pushPose(); + + RenderSystem.setShaderColor(getColor().getRed() / 255F, getColor().getGreen() / 255F, getColor().getBlue() / 255F, lifePercentage * 0.75F); + + RenderSystem.enableBlend(); + + poseStack.translate(Mth.lerp(partialTick, getXO(), getX()), Mth.lerp(partialTick, getYO(), getY()), 0); + + poseStack.mulPose(Axis.ZP.rotationDegrees((getLifeTime() + partialTick) * lifePercentage)); + + GUIRenderer.begin(TEXTURE, guiGraphics.pose()) + .scale(scale) + .anchor(SpriteAnchor.CENTER) + .end(); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + RenderSystem.disableBlend(); + + poseStack.popPose(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/widgets/HintWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/widgets/HintWidget.java new file mode 100644 index 00000000..3d5ed641 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/widgets/HintWidget.java @@ -0,0 +1,192 @@ +package it.hurts.sskirillss.relics.client.screen.description.research.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractDescriptionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.client.screen.description.relic.particles.ExperienceParticleData; +import it.hurts.sskirillss.relics.client.screen.description.research.AbilityResearchScreen; +import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.network.NetworkHandler; +import it.hurts.sskirillss.relics.network.packets.research.PacketResearchHint; +import it.hurts.sskirillss.relics.utils.data.AnimationData; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.RandomSource; + +import java.awt.*; +import java.util.List; + +public class HintWidget extends AbstractDescriptionWidget implements IHoverableWidget, ITickingWidget { + private final AbilityResearchScreen screen; + + public HintWidget(int x, int y, AbilityResearchScreen screen) { + super(x, y, 87, 22); + + this.screen = screen; + } + + @Override + public void onPress() { + if (!(screen.stack.getItem() instanceof IRelicItem relic) || relic.isAbilityResearched(screen.stack, screen.ability)) + return; + + int links = relic.getResearchData(screen.ability).getLinks().size(); + + int requiredLevel = relic.getResearchHintCost(screen.ability) * (Screen.hasShiftDown() ? (links + 1) : 1); + + int level = minecraft.player.experienceLevel; + + if (level >= requiredLevel) + NetworkHandler.sendToServer(new PacketResearchHint(screen.container, screen.slot, screen.ability, Screen.hasShiftDown() ? links : 1)); + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + LocalPlayer player = Minecraft.getInstance().player; + + if (player == null || !(screen.stack.getItem() instanceof IRelicItem relic)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + poseStack.pushPose(); + + GUIRenderer.begin(DescriptionTextures.HINT_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX(), getY() - 10) + .end(); + + if (relic.isAbilityResearched(screen.stack, screen.ability)) { + GUIRenderer.begin(DescriptionTextures.BULB_BROKEN, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + 34, getY() - 3) + .end(); + } else { + if (isHovered()) { + float color = (float) (1.025F + (Math.sin(player.tickCount + pPartialTick) * 0.05F)); + + if (Screen.hasShiftDown()) + GUIRenderer.begin(DescriptionTextures.BULB_BURNING, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + 34, getY() - 17) + .patternSize(16, 34) + .color(color, color, color, 1F) + .animation(AnimationData.builder() + .frame(0, 2).frame(1, 2).frame(2, 2) + .frame(3, 2).frame(4, 2).frame(5, 2) + .frame(6, 2).frame(7, 2)) + .end(); + else + GUIRenderer.begin(DescriptionTextures.BULB_GLOWING, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + 34, getY() - 3) + .color(color, color, color, 1F) + .end(); + } else + GUIRenderer.begin(DescriptionTextures.BULB, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() + 34, getY() - 3) + .end(); + } + + if (isHovered()) + GUIRenderer.begin(DescriptionTextures.HINT_OUTLINE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX() - 1, getY() - 6) + .end(); + + poseStack.popPose(); + } + + @Override + public void onTick() { + if (!isHovered() || !(screen.stack.getItem() instanceof IRelicItem relic) || relic.isAbilityResearched(screen.stack, screen.ability)) + return; + + RandomSource random = minecraft.player.getRandom(); + + if (minecraft.player.tickCount % 5 == 0) { + ParticleStorage.addParticle(screen, new ExperienceParticleData(new Color(255, 200 + random.nextInt(50), random.nextInt(50)), + getX() + 34 + random.nextInt(16), getY() - 6 + random.nextInt(16), 1F + (random.nextFloat() * 0.25F), 50 + random.nextInt(50))); + } + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + if (!(screen.stack.getItem() instanceof IRelicItem relic)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 150; + int renderWidth = 0; + + int requiredLevel = relic.getResearchHintCost(screen.ability) * (Screen.hasShiftDown() ? relic.getResearchData(screen.ability).getLinks().size() : 1); + + int level = minecraft.player.experienceLevel; + + MutableComponent negativeStatus = Component.translatable("tooltip.relics.relic.status.negative"); + MutableComponent positiveStatus = Component.translatable("tooltip.relics.relic.status.positive"); + + List entries = Lists.newArrayList( + Component.translatable("tooltip.relics.researching.research.hint.description").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.UNDERLINE), + Component.literal(" ") + ); + + if (relic.isAbilityResearched(screen.stack, screen.ability)) + entries.add(Component.translatable("tooltip.relics.researching.research.hint.locked")); + else { + entries.add(Component.translatable("tooltip.relics.relic.reset.cost", requiredLevel, (requiredLevel > level ? negativeStatus : positiveStatus))); + entries.add(Component.literal(" ")); + entries.add(Component.literal("▶ ").append(Component.translatable("tooltip.relics.researching.research.hint.quick"))); + } + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) / 2); + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth + 2, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + poseStack.pushPose(); + + poseStack.translate(0F, 0F, 100); + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, tooltip.size() * 5, mouseX - 9 - (renderWidth / 2), mouseY); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + int yOff = 0; + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, ((mouseX - renderWidth / 2) + 1) * 2, ((mouseY + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.popPose(); + } + + @Override + public void playDownSound(SoundManager handler) { + + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/widgets/StarWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/widgets/StarWidget.java new file mode 100644 index 00000000..44f4fc99 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/widgets/StarWidget.java @@ -0,0 +1,156 @@ +package it.hurts.sskirillss.relics.client.screen.description.research.widgets; + +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractDescriptionWidget; +import it.hurts.sskirillss.relics.client.screen.description.research.AbilityResearchScreen; +import it.hurts.sskirillss.relics.client.screen.description.research.particles.ResearchParticleData; +import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.research.StarData; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.AnimationData; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import lombok.Getter; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.RandomSource; + +import java.awt.*; + +public class StarWidget extends AbstractDescriptionWidget implements ITickingWidget { + private AbilityResearchScreen screen; + @Getter + private StarData star; + + public StarWidget(int x, int y, AbilityResearchScreen screen, StarData star) { + super(x, y, 17, 17); + + this.screen = screen; + this.star = star; + } + + @Override + public boolean isLocked() { + return screen.stack.getItem() instanceof IRelicItem relic && relic.isAbilityResearched(screen.stack, screen.ability); + } + + @Override + public void onPress() { + if (!isLocked() && screen.getOccupiedConnectionsCount(star) < screen.getTotalConnectionsCount(star)) + screen.selectedStar = star; + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + this.isHovered = guiGraphics.containsPointInScissor(pMouseX, pMouseY) + && pMouseX >= this.getX() + && pMouseY >= this.getY() + && pMouseX < this.getX() + this.width + && pMouseY < this.getY() + this.height; + + int index = star.getIndex(); + + LocalPlayer player = Minecraft.getInstance().player; + + if (player == null) + return; + + PoseStack poseStack = guiGraphics.pose(); + + poseStack.pushPose(); + + float time = (player.tickCount + pPartialTick + (index * 100F)); + + { + poseStack.pushPose(); + + RenderSystem.enableBlend(); + + poseStack.translate(getX() + width / 2F, getY() + height / 2F, 0); + + var totalCount = screen.getTotalConnectionsCount(star); + var connectedCount = screen.getOccupiedConnectionsCount(star); + + float angle = time * 0.05F; + + float radius = (float) (8 + Math.sin(time * 0.1F)); + + float angleStep = (float) (2 * Math.PI / totalCount); + + for (int i = 0; i < totalCount; i++) { + float color = (float) (0.25F + (Math.sin((time + (i * 10)) * 0.25F) * 0.5F)); + + if (i < connectedCount) + RenderSystem.setShaderColor(0.25F, 1F + color, 1F, 1F); + else + RenderSystem.setShaderColor(1F + color, 1F + color, 1F + color, 1F); + + float currentAngle = angle + i * angleStep; + + float x = (float) (radius * Math.cos(currentAngle)); + float y = (float) (radius * Math.sin(currentAngle)); + + GUIRenderer.begin(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/research/dot.png"), poseStack) + .pos(x, y) + .end(); + } + + RenderSystem.disableBlend(); + + poseStack.popPose(); + } + + { + poseStack.pushPose(); + + float color = (float) (1.1F + (Math.sin(time) * 0.2F)); + + RenderSystem.setShaderColor(color, color, color, 1F); + + RenderSystem.enableBlend(); + + poseStack.translate(getX() + 0.5F + width / 2F, getY() + 0.5F + height / 2F, 0); + poseStack.mulPose(Axis.ZN.rotationDegrees((time * 0.75F) * (index % 2 == 0 ? 1 : -1))); + + GUIRenderer.begin(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/research/star.png"), poseStack) + .texSize(17, 136) + .patternSize(17, 17) + .scale((float) (1F + (Math.sin(time * 0.5F) * 0.1F))) + .animation(AnimationData.builder() + .frame(0, 2).frame(1, 2) + .frame(2, 2).frame(3, 2) + .frame(4, 2).frame(5, 2) + .frame(6, 2).frame(7, 2)) + .end(); + + RenderSystem.setShaderColor(1F, 1F, 1F, 1F); + + RenderSystem.disableBlend(); + + poseStack.popPose(); + } + + poseStack.popPose(); + } + + @Override + public void onTick() { + RandomSource random = minecraft.player.getRandom(); + + if (minecraft.player.tickCount % 5 == 0) { + ParticleStorage.addParticle(screen, new ResearchParticleData(new Color(100 + random.nextInt(150), random.nextInt(25), 200 + random.nextInt(50)), + getX() + random.nextFloat() * width, getY() + random.nextFloat() * height, 1F + (random.nextFloat() * 0.25F), 10 + random.nextInt(30), 0.01F)); + } + } + + @Override + public void playDownSound(SoundManager handler) { + + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/widgets/TipWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/widgets/TipWidget.java new file mode 100644 index 00000000..e2ae1b8a --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/research/widgets/TipWidget.java @@ -0,0 +1,126 @@ +package it.hurts.sskirillss.relics.client.screen.description.research.widgets; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; +import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; +import it.hurts.sskirillss.relics.client.screen.description.general.widgets.base.AbstractDescriptionWidget; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.client.screen.description.relic.particles.ExperienceParticleData; +import it.hurts.sskirillss.relics.client.screen.description.research.AbilityResearchScreen; +import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.data.GUIRenderer; +import it.hurts.sskirillss.relics.utils.data.SpriteAnchor; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.sounds.SoundManager; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.RandomSource; + +import java.awt.*; +import java.util.List; + +public class TipWidget extends AbstractDescriptionWidget implements IHoverableWidget, ITickingWidget { + private final AbilityResearchScreen screen; + + public TipWidget(int x, int y, AbilityResearchScreen screen) { + super(x, y, 12, 14); + + this.screen = screen; + } + + @Override + public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { + LocalPlayer player = Minecraft.getInstance().player; + + if (player == null || !(screen.stack.getItem() instanceof IRelicItem)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + poseStack.pushPose(); + + float color = (float) (1.05F + (Math.sin((player.tickCount + pPartialTick) * 0.5F) * 0.1F)); + + GUIRenderer.begin(DescriptionTextures.TIP_BACKGROUND, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .color(color, color, color, 1F) + .pos(getX() + 2, getY() + 1) + .end(); + + if (isHovered()) + GUIRenderer.begin(DescriptionTextures.TIP_OUTLINE, poseStack) + .anchor(SpriteAnchor.TOP_LEFT) + .pos(getX(), getY() - 1) + .end(); + + poseStack.popPose(); + } + + @Override + public void onTick() { + if (!isHovered() || !(screen.stack.getItem() instanceof IRelicItem) || minecraft.player == null) + return; + + RandomSource random = minecraft.player.getRandom(); + + if (minecraft.player.tickCount % 5 == 0) { + ParticleStorage.addParticle(screen, new ExperienceParticleData(new Color(255, 200 + random.nextInt(50), random.nextInt(50)), + getX() + 34 + random.nextInt(16), getY() - 6 + random.nextInt(16), 1F + (random.nextFloat() * 0.25F), 50 + random.nextInt(50))); + } + } + + @Override + public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { + if (!(screen.stack.getItem() instanceof IRelicItem relic)) + return; + + PoseStack poseStack = guiGraphics.pose(); + + List tooltip = Lists.newArrayList(); + + int maxWidth = 180; + int renderWidth = 0; + + List entries = Lists.newArrayList( + Component.translatable("tooltip.relics.researching.research.tip") + ); + + for (MutableComponent entry : entries) { + int entryWidth = (minecraft.font.width(entry) / 2); + + if (entryWidth > renderWidth) + renderWidth = Math.min(entryWidth + 2, maxWidth); + + tooltip.addAll(minecraft.font.split(entry, maxWidth * 2)); + } + + poseStack.pushPose(); + + poseStack.translate(0F, 0F, 100); + + DescriptionUtils.drawTooltipBackground(guiGraphics, renderWidth, tooltip.size() * 5, mouseX - 9 - (renderWidth / 2), mouseY); + + poseStack.scale(0.5F, 0.5F, 0.5F); + + int yOff = 0; + + for (FormattedCharSequence entry : tooltip) { + guiGraphics.drawString(minecraft.font, entry, ((mouseX - renderWidth / 2) + 1) * 2, ((mouseY + yOff + 9) * 2), DescriptionUtils.TEXT_COLOR, false); + + yOff += 5; + } + + poseStack.popPose(); + } + + @Override + public void playDownSound(SoundManager handler) { + + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/ability/AbilityRerollButtonWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/ability/AbilityRerollButtonWidget.java deleted file mode 100644 index 8f7f31d6..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/ability/AbilityRerollButtonWidget.java +++ /dev/null @@ -1,171 +0,0 @@ -package it.hurts.sskirillss.relics.client.screen.description.widgets.ability; - -import com.google.common.collect.Lists; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; -import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; -import it.hurts.sskirillss.relics.client.screen.description.AbilityDescriptionScreen; -import it.hurts.sskirillss.relics.client.screen.description.data.ExperienceParticleData; -import it.hurts.sskirillss.relics.client.screen.description.widgets.base.AbstractDescriptionWidget; -import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; -import it.hurts.sskirillss.relics.client.screen.utils.ScreenUtils; -import it.hurts.sskirillss.relics.init.SoundRegistry; -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.network.NetworkHandler; -import it.hurts.sskirillss.relics.network.packets.leveling.PacketRelicTweak; -import it.hurts.sskirillss.relics.utils.Reference; -import it.hurts.sskirillss.relics.utils.RenderUtils; -import it.hurts.sskirillss.relics.utils.data.AnimationData; -import net.minecraft.ChatFormatting; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.client.resources.sounds.SimpleSoundInstance; -import net.minecraft.client.sounds.SoundManager; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.FormattedCharSequence; -import net.minecraft.util.RandomSource; - -import java.awt.*; -import java.util.List; - -public class AbilityRerollButtonWidget extends AbstractDescriptionWidget implements IHoverableWidget, ITickingWidget { - private final AbilityDescriptionScreen screen; - private final String ability; - - public AbilityRerollButtonWidget(int x, int y, AbilityDescriptionScreen screen, String ability) { - super(x, y, 17, 17); - - this.screen = screen; - this.ability = ability; - } - - @Override - public boolean isLocked() { - return !(screen.stack.getItem() instanceof IRelicItem relic) || !relic.mayPlayerReroll(MC.player, screen.stack, ability); - } - - @Override - public void playDownSound(SoundManager handler) { - if (!isLocked()) - handler.play(SimpleSoundInstance.forUI(SoundRegistry.TABLE_REROLL.get(), 1F)); - } - - @Override - public void onPress() { - if (!isLocked()) - NetworkHandler.sendToServer(new PacketRelicTweak(screen.pos, ability, PacketRelicTweak.Operation.REROLL)); - } - - @Override - public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { - TextureManager manager = MC.getTextureManager(); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, AbilityDescriptionScreen.TEXTURE); - - manager.bindForSetup(AbilityDescriptionScreen.TEXTURE); - - guiGraphics.blit(AbilityDescriptionScreen.TEXTURE, getX(), getY(), isLocked() ? 320 : 302, 88, width, height, 512, 512); - - if (isHovered) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/gui/description/reroll_highlight_" + (isLocked() ? "locked" : "unlocked") + ".png")); - - RenderSystem.enableBlend(); - - RenderUtils.renderAnimatedTextureFromCenter(guiGraphics.pose(), getX() + width / 2, getY() + height / 2, 32, 384, 32, 32, 1F, AnimationData.builder() - .frame(0, 2) - .frame(1, 2) - .frame(2, 2) - .frame(3, 2) - .frame(4, 2) - .frame(5, 2) - .frame(6, 2) - .frame(7, 2) - .frame(8, 2) - .frame(9, 2) - .frame(10, 2) - .frame(11, 2) - ); - - RenderSystem.disableBlend(); - } - } - - @Override - public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { - if (!(screen.stack.getItem() instanceof IRelicItem relic) || !relic.canUseAbility(screen.stack, ability)) - return; - - AbilityData data = relic.getAbilityData(ability); - - if (data.getStats().isEmpty()) - return; - - PoseStack poseStack = guiGraphics.pose(); - - List tooltip = Lists.newArrayList(); - - int maxWidth = 100; - int renderWidth = 0; - - int requiredExperience = relic.getRerollRequiredExperience(ability); - - int experience = MC.player.totalExperience; - - MutableComponent negativeStatus = Component.translatable("tooltip.relics.relic.status.negative").withStyle(ChatFormatting.RED); - MutableComponent positiveStatus = Component.translatable("tooltip.relics.relic.status.positive").withStyle(ChatFormatting.GREEN); - - List entries = Lists.newArrayList( - Component.translatable("tooltip.relics.relic.reroll.description").withStyle(ChatFormatting.BOLD), - Component.literal(" "), - Component.translatable("tooltip.relics.relic.reroll.cost", requiredExperience, - (requiredExperience > experience ? negativeStatus : positiveStatus))); - - for (MutableComponent entry : entries) { - int entryWidth = (MC.font.width(entry) + 4) / 2; - - if (entryWidth > renderWidth) - renderWidth = Math.min(entryWidth, maxWidth); - - tooltip.addAll(MC.font.split(entry, maxWidth * 2)); - } - - int height = Math.round(tooltip.size() * 4.5F); - - int renderX = getX() + width + 1; - int renderY = mouseY - (height / 2) - 9; - - ScreenUtils.drawTexturedTooltipBorder(guiGraphics, new ResourceLocation(Reference.MODID, "textures/gui/tooltip/border/paper.png"), - renderWidth, height, renderX, renderY); - - int yOff = 0; - - poseStack.scale(0.5F, 0.5F, 0.5F); - - for (FormattedCharSequence entry : tooltip) { - guiGraphics.drawString(MC.font, entry, (renderX + 9) * 2, (renderY + 9 + yOff) * 2, 0x412708, false); - - yOff += 5; - } - - poseStack.scale(1F, 1F, 1F); - } - - @Override - public void onTick() { - RandomSource random = MC.player.getRandom(); - - if (isHoveredOrFocused()) { - if (screen.ticksExisted % 10 == 0) - ParticleStorage.addParticle(screen, new ExperienceParticleData(isLocked() - ? new Color(100 + random.nextInt(100), 100 + random.nextInt(100), 100 + random.nextInt(100)) - : new Color(200 + random.nextInt(50), 150 + random.nextInt(100), 0), - getX() + random.nextInt(width), getY() + random.nextInt(height), - 0.15F + (random.nextFloat() * 0.25F), 100 + random.nextInt(50))); - } - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/ability/AbilityResetButtonWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/ability/AbilityResetButtonWidget.java deleted file mode 100644 index 366b947c..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/ability/AbilityResetButtonWidget.java +++ /dev/null @@ -1,175 +0,0 @@ -package it.hurts.sskirillss.relics.client.screen.description.widgets.ability; - -import com.google.common.collect.Lists; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; -import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; -import it.hurts.sskirillss.relics.client.screen.description.AbilityDescriptionScreen; -import it.hurts.sskirillss.relics.client.screen.description.data.ExperienceParticleData; -import it.hurts.sskirillss.relics.client.screen.description.widgets.base.AbstractDescriptionWidget; -import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; -import it.hurts.sskirillss.relics.client.screen.utils.ScreenUtils; -import it.hurts.sskirillss.relics.init.SoundRegistry; -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.network.NetworkHandler; -import it.hurts.sskirillss.relics.network.packets.leveling.PacketRelicTweak; -import it.hurts.sskirillss.relics.utils.Reference; -import it.hurts.sskirillss.relics.utils.RenderUtils; -import it.hurts.sskirillss.relics.utils.data.AnimationData; -import net.minecraft.ChatFormatting; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.client.resources.sounds.SimpleSoundInstance; -import net.minecraft.client.sounds.SoundManager; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.FormattedCharSequence; -import net.minecraft.util.RandomSource; - -import java.awt.*; -import java.util.List; - -public class AbilityResetButtonWidget extends AbstractDescriptionWidget implements IHoverableWidget, ITickingWidget { - private final AbilityDescriptionScreen screen; - private final String ability; - - public AbilityResetButtonWidget(int x, int y, AbilityDescriptionScreen screen, String ability) { - super(x, y, 17, 17); - - this.screen = screen; - this.ability = ability; - } - - @Override - public boolean isLocked() { - return !(screen.stack.getItem() instanceof IRelicItem relic) || !relic.mayPlayerReset(MC.player, screen.stack, ability); - } - - @Override - public void playDownSound(SoundManager handler) { - if (!isLocked()) - handler.play(SimpleSoundInstance.forUI(SoundRegistry.TABLE_RESET.get(), 1F)); - } - - @Override - public void onPress() { - if (!isLocked()) - NetworkHandler.sendToServer(new PacketRelicTweak(screen.pos, ability, PacketRelicTweak.Operation.RESET)); - } - - @Override - public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { - TextureManager manager = MC.getTextureManager(); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, AbilityDescriptionScreen.TEXTURE); - - manager.bindForSetup(AbilityDescriptionScreen.TEXTURE); - - guiGraphics.blit(AbilityDescriptionScreen.TEXTURE, getX(), getY(), isLocked() ? 320 : 302, 106, width, height, 512, 512); - - if (isHovered) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/gui/description/reset_highlight_" + (isLocked() ? "locked" : "unlocked") + ".png")); - - RenderSystem.enableBlend(); - - RenderUtils.renderAnimatedTextureFromCenter(guiGraphics.pose(), getX() + width / 2, getY() + height / 2, 32, 384, 32, 32, 1F, AnimationData.builder() - .frame(0, 2) - .frame(1, 2) - .frame(2, 2) - .frame(3, 2) - .frame(4, 2) - .frame(5, 2) - .frame(6, 2) - .frame(7, 2) - .frame(8, 2) - .frame(9, 2) - .frame(10, 2) - .frame(11, 2) - ); - - RenderSystem.disableBlend(); - } - } - - @Override - public void onTick() { - RandomSource random = MC.player.getRandom(); - - if (isHoveredOrFocused()) { - if (screen.ticksExisted % 10 == 0) - ParticleStorage.addParticle(screen, new ExperienceParticleData(isLocked() - ? new Color(100 + random.nextInt(100), 100 + random.nextInt(100), 100 + random.nextInt(100)) - : new Color(200 + random.nextInt(50), 150 + random.nextInt(100), 0), - getX() + random.nextInt(width), getY() + random.nextInt(height), - 0.15F + (random.nextFloat() * 0.25F), 100 + random.nextInt(50))); - } - } - - @Override - public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { - if (!(screen.stack.getItem() instanceof IRelicItem relic) || !relic.canUseAbility(screen.stack, ability)) - return; - - AbilityData data = relic.getAbilityData(ability); - - if (data.getStats().isEmpty()) - return; - - PoseStack poseStack = guiGraphics.pose(); - - List tooltip = Lists.newArrayList(); - - int maxWidth = 100; - int renderWidth = 0; - - int requiredExperience = relic.getResetRequiredExperience(screen.stack, ability); - - int experience = MC.player.totalExperience; - - MutableComponent negativeStatus = Component.translatable("tooltip.relics.relic.status.negative").withStyle(ChatFormatting.RED); - MutableComponent positiveStatus = Component.translatable("tooltip.relics.relic.status.positive").withStyle(ChatFormatting.GREEN); - - List entries = Lists.newArrayList( - Component.translatable("tooltip.relics.relic.reset.description").withStyle(ChatFormatting.BOLD), - Component.literal(" ")); - - if (relic.getAbilityPoints(screen.stack, ability) > 0) - entries.add(Component.translatable("tooltip.relics.relic.reset.cost", requiredExperience, - (requiredExperience > experience ? negativeStatus : positiveStatus))); - else - entries.add(Component.literal("▶ ").append(Component.translatable("tooltip.relics.relic.reset.locked"))); - - for (MutableComponent entry : entries) { - int entryWidth = (MC.font.width(entry) + 4) / 2; - - if (entryWidth > renderWidth) - renderWidth = Math.min(entryWidth, maxWidth); - - tooltip.addAll(MC.font.split(entry, maxWidth * 2)); - } - - int height = Math.round(tooltip.size() * 4.5F); - - int renderX = getX() + width + 1; - int renderY = mouseY - (height / 2) - 9; - - ScreenUtils.drawTexturedTooltipBorder(guiGraphics, new ResourceLocation(Reference.MODID, "textures/gui/tooltip/border/paper.png"), - renderWidth, height, renderX, renderY); - - int yOff = 0; - - poseStack.scale(0.5F, 0.5F, 0.5F); - - for (FormattedCharSequence entry : tooltip) { - guiGraphics.drawString(MC.font, entry, (renderX + 9) * 2, (renderY + 9 + yOff) * 2, 0x412708, false); - - yOff += 5; - } - - poseStack.scale(1F, 1F, 1F); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/ability/AbilityUpgradeButtonWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/ability/AbilityUpgradeButtonWidget.java deleted file mode 100644 index b8846774..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/ability/AbilityUpgradeButtonWidget.java +++ /dev/null @@ -1,180 +0,0 @@ -package it.hurts.sskirillss.relics.client.screen.description.widgets.ability; - -import com.google.common.collect.Lists; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; -import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; -import it.hurts.sskirillss.relics.client.screen.description.AbilityDescriptionScreen; -import it.hurts.sskirillss.relics.client.screen.description.data.ExperienceParticleData; -import it.hurts.sskirillss.relics.client.screen.description.widgets.base.AbstractDescriptionWidget; -import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; -import it.hurts.sskirillss.relics.client.screen.utils.ScreenUtils; -import it.hurts.sskirillss.relics.init.SoundRegistry; -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.network.NetworkHandler; -import it.hurts.sskirillss.relics.network.packets.leveling.PacketRelicTweak; -import it.hurts.sskirillss.relics.utils.Reference; -import it.hurts.sskirillss.relics.utils.RenderUtils; -import it.hurts.sskirillss.relics.utils.data.AnimationData; -import net.minecraft.ChatFormatting; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.client.resources.sounds.SimpleSoundInstance; -import net.minecraft.client.sounds.SoundManager; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.FormattedCharSequence; -import net.minecraft.util.RandomSource; - -import java.awt.*; -import java.util.List; - -public class AbilityUpgradeButtonWidget extends AbstractDescriptionWidget implements IHoverableWidget, ITickingWidget { - private final AbilityDescriptionScreen screen; - private final String ability; - - public AbilityUpgradeButtonWidget(int x, int y, AbilityDescriptionScreen screen, String ability) { - super(x, y, 17, 17); - - this.screen = screen; - this.ability = ability; - } - - @Override - public boolean isLocked() { - return !(screen.stack.getItem() instanceof IRelicItem relic) || !relic.mayPlayerUpgrade(MC.player, screen.stack, ability); - } - - @Override - public void playDownSound(SoundManager handler) { - if (screen.stack.getItem() instanceof IRelicItem relic && !isLocked()) { - int level = relic.getAbilityPoints(screen.stack, ability); - int maxLevel = relic.getAbilityData(ability).getMaxLevel(); - - handler.play(SimpleSoundInstance.forUI(SoundRegistry.TABLE_UPGRADE.get(), 1F + ((float) level / maxLevel))); - } - } - - @Override - public void onPress() { - if (!isLocked()) - NetworkHandler.sendToServer(new PacketRelicTweak(screen.pos, ability, PacketRelicTweak.Operation.INCREASE)); - } - - @Override - public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { - TextureManager manager = MC.getTextureManager(); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, AbilityDescriptionScreen.TEXTURE); - - manager.bindForSetup(AbilityDescriptionScreen.TEXTURE); - - guiGraphics.blit(AbilityDescriptionScreen.TEXTURE, getX(), getY(), isLocked() ? 320 : 302, 70, width, height, 512, 512); - - if (isHovered) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/gui/description/upgrade_highlight_" + (isLocked() ? "locked" : "unlocked") + ".png")); - - RenderSystem.enableBlend(); - - RenderUtils.renderAnimatedTextureFromCenter(guiGraphics.pose(), getX() + width / 2, getY() + height / 2, 32, 384, 32, 32, 1F, AnimationData.builder() - .frame(0, 2) - .frame(1, 2) - .frame(2, 2) - .frame(3, 2) - .frame(4, 2) - .frame(5, 2) - .frame(6, 2) - .frame(7, 2) - .frame(8, 2) - .frame(9, 2) - .frame(10, 2) - .frame(11, 2) - ); - } - } - - @Override - public void onTick() { - RandomSource random = MC.player.getRandom(); - - if (isHoveredOrFocused()) { - if (screen.ticksExisted % 10 == 0) - ParticleStorage.addParticle(screen, new ExperienceParticleData(isLocked() - ? new Color(100 + random.nextInt(100), 100 + random.nextInt(100), 100 + random.nextInt(100)) - : new Color(200 + random.nextInt(50), 150 + random.nextInt(100), 0), - getX() + random.nextInt(width), getY() + random.nextInt(height), - 0.15F + (random.nextFloat() * 0.25F), 100 + random.nextInt(50))); - } - } - - @Override - public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { - if (!(screen.stack.getItem() instanceof IRelicItem relic) || !relic.canUseAbility(screen.stack, ability)) - return; - - AbilityData data = relic.getAbilityData(ability); - - if (data.getStats().isEmpty()) - return; - - List tooltip = Lists.newArrayList(); - - PoseStack poseStack = guiGraphics.pose(); - - int maxWidth = 100; - int renderWidth = 0; - - int requiredPoints = data.getRequiredPoints(); - int requiredExperience = relic.getUpgradeRequiredExperience(screen.stack, ability); - - int points = relic.getPoints(screen.stack); - int experience = MC.player.totalExperience; - - MutableComponent negativeStatus = Component.translatable("tooltip.relics.relic.status.negative"); - MutableComponent positiveStatus = Component.translatable("tooltip.relics.relic.status.positive"); - - List entries = Lists.newArrayList( - Component.translatable("tooltip.relics.relic.upgrade.description").withStyle(ChatFormatting.BOLD), - Component.literal(" ")); - - if (!relic.isAbilityMaxLevel(screen.stack, ability)) - entries.add(Component.translatable("tooltip.relics.relic.upgrade.cost", requiredPoints, - (requiredPoints > points ? negativeStatus : positiveStatus), requiredExperience, - (requiredExperience > experience ? negativeStatus : positiveStatus))); - else - entries.add(Component.literal("▶ ").append(Component.translatable("tooltip.relics.relic.upgrade.locked"))); - - for (MutableComponent entry : entries) { - int entryWidth = (MC.font.width(entry) + 4) / 2; - - if (entryWidth > renderWidth) - renderWidth = Math.min(entryWidth, maxWidth); - - tooltip.addAll(MC.font.split(entry, maxWidth * 2)); - } - - int height = Math.round(tooltip.size() * 4.5F); - - int renderX = getX() + width + 1; - int renderY = mouseY - (height / 2) - 9; - - ScreenUtils.drawTexturedTooltipBorder(guiGraphics, new ResourceLocation(Reference.MODID, "textures/gui/tooltip/border/paper.png"), - renderWidth, height, renderX, renderY); - - int yOff = 0; - - poseStack.scale(0.5F, 0.5F, 0.5F); - - for (FormattedCharSequence entry : tooltip) { - guiGraphics.drawString(MC.font, entry, (renderX + 9) * 2, (renderY + 9 + yOff) * 2, 0x412708, false); - - yOff += 5; - } - - poseStack.scale(1F, 1F, 1F); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/relic/AbilityCardIconWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/relic/AbilityCardIconWidget.java deleted file mode 100644 index d838d40f..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/relic/AbilityCardIconWidget.java +++ /dev/null @@ -1,290 +0,0 @@ -package it.hurts.sskirillss.relics.client.screen.description.widgets.relic; - -import com.google.common.collect.Lists; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; -import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; -import it.hurts.sskirillss.relics.client.screen.description.AbilityDescriptionScreen; -import it.hurts.sskirillss.relics.client.screen.description.RelicDescriptionScreen; -import it.hurts.sskirillss.relics.client.screen.description.data.ExperienceParticleData; -import it.hurts.sskirillss.relics.client.screen.description.widgets.base.AbstractDescriptionWidget; -import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; -import it.hurts.sskirillss.relics.client.screen.utils.ScreenUtils; -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.utils.Reference; -import it.hurts.sskirillss.relics.utils.RenderUtils; -import it.hurts.sskirillss.relics.utils.data.AnimationData; -import net.minecraft.ChatFormatting; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.util.FormattedCharSequence; -import net.minecraft.util.RandomSource; -import net.minecraftforge.registries.ForgeRegistries; - -import java.awt.*; -import java.util.List; - -public class AbilityCardIconWidget extends AbstractDescriptionWidget implements IHoverableWidget, ITickingWidget { - private final RelicDescriptionScreen screen; - private final String ability; - - private float scale = 1F; - - public AbilityCardIconWidget(int x, int y, RelicDescriptionScreen screen, String ability) { - super(x, y, 30, 46); - - this.screen = screen; - this.ability = ability; - } - - @Override - public void onPress() { - MC.setScreen(new AbilityDescriptionScreen(screen.pos, screen.stack, ability)); - } - - @Override - public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { - if (!(screen.stack.getItem() instanceof IRelicItem relic)) - return; - - TextureManager manager = MC.getTextureManager(); - PoseStack poseStack = guiGraphics.pose(); - - boolean canUse = relic.canUseAbility(screen.stack, ability); - boolean canUpgrade = relic.mayPlayerUpgrade(MC.player, screen.stack, ability); - - ResourceLocation card = new ResourceLocation(Reference.MODID, "textures/gui/description/cards/" + ForgeRegistries.ITEMS.getKey(screen.stack.getItem()).getPath() + "/" + relic.getAbilityData(ability).getIcon().apply(MC.player, screen.stack, ability) + ".png"); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, card); - - manager.bindForSetup(card); - - poseStack.pushPose(); - - poseStack.scale(scale, scale, scale); - - poseStack.translate((getX() + (width / 2F)) / scale, (getY() + (height / 2F)) / scale, 0); - - if (!canUse) - RenderSystem.setShaderColor(0.25F, 0.25F, 0.25F, scale); - else if (canUpgrade) - RenderSystem.setShaderColor(0.5F, 0.5F, 0.5F, scale); - - guiGraphics.blit(card, -(20 / 2) - 1, -(29 / 2) - 2, 0, 0, 20, 29, 20, 29); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, RelicDescriptionScreen.TEXTURE); - - manager.bindForSetup(RelicDescriptionScreen.TEXTURE); - - if (canUse) { - guiGraphics.blit(RelicDescriptionScreen.TEXTURE, -(width / 2), -(height / 2), 302, 61, width, height, 512, 512); - - if (isHovered()) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/gui/description/card_highlight_unlocked.png")); - - RenderSystem.enableBlend(); - - RenderUtils.renderAnimatedTextureFromCenter(poseStack, 0, 0, 64, 768, 64, 64, 1F, AnimationData.builder() - .frame(0, 2) - .frame(1, 2) - .frame(2, 2) - .frame(3, 2) - .frame(4, 2) - .frame(5, 2) - .frame(6, 2) - .frame(7, 2) - .frame(8, 2) - .frame(9, 2) - .frame(10, 2) - .frame(11, 2) - ); - - RenderSystem.disableBlend(); - } - } else { - guiGraphics.blit(RelicDescriptionScreen.TEXTURE, -(width / 2) - 1, -(height / 2), 333, 61, width + 1, height, 512, 512); - - if (isHovered()) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/gui/description/card_highlight_locked.png")); - - RenderSystem.enableBlend(); - - RenderUtils.renderAnimatedTextureFromCenter(poseStack, 0, 0, 64, 768, 64, 64, 1F, AnimationData.builder() - .frame(0, 2) - .frame(1, 2) - .frame(2, 2) - .frame(3, 2) - .frame(4, 2) - .frame(5, 2) - .frame(6, 2) - .frame(7, 2) - .frame(8, 2) - .frame(9, 2) - .frame(10, 2) - .frame(11, 2) - ); - - RenderSystem.disableBlend(); - } - } - - if (canUpgrade) { - ResourceLocation icon = new ResourceLocation(Reference.MODID, "textures/gui/description/upgrade_available.png"); - - RenderSystem.setShaderTexture(0, icon); - - manager.bindForSetup(icon); - - RenderSystem.enableBlend(); - - RenderUtils.renderAnimatedTextureFromCenter(poseStack, -1, -1, 32, 256, 32, 32, 0.9F + ((float) (Math.sin((screen.ticksExisted + pPartialTick) * 0.25F) * 0.025F)), AnimationData.builder() - .frame(0, 2) - .frame(1, 2) - .frame(2, 2) - .frame(3, 2) - .frame(4, 2) - .frame(5, 2) - .frame(6, 2) - .frame(7, 20) - ); - - RenderSystem.disableBlend(); - } - - int xOff = 0; - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, RelicDescriptionScreen.TEXTURE); - - manager.bindForSetup(RelicDescriptionScreen.TEXTURE); - - for (int i = 1; i < relic.getAbilityQuality(screen.stack, ability) + 1; i++) { - boolean isAliquot = i % 2 == 1; - - guiGraphics.blit(RelicDescriptionScreen.TEXTURE, -(width / 2) + xOff + 2, -(height / 2) + 38, (canUse ? 302 : 334) + (isAliquot ? 0 : 2), 108, isAliquot ? 2 : 3, 4, 512, 512); - - xOff += (isAliquot ? 2 : 3); - } - - MutableComponent title = Component.literal(String.valueOf(relic.getAbilityPoints(screen.stack, ability))).withStyle(ChatFormatting.BOLD); - - float textScale = 0.5F; - - poseStack.scale(textScale, textScale, textScale); - - guiGraphics.drawString(MC.font, title, -((width + 1) / 2) - (MC.font.width(title) / 2) + 13, (-(height / 2) - 19), 0xffce96, true); - - poseStack.popPose(); - } - - @Override - public void onTick() { - if (!(screen.stack.getItem() instanceof IRelicItem relic)) - return; - - float maxScale = 1.1F; - float minScale = 1F; - - RandomSource random = MC.player.getRandom(); - - if (relic.mayPlayerUpgrade(MC.player, screen.stack, ability)) { - if (screen.ticksExisted % 7 == 0) - ParticleStorage.addParticle(screen, new ExperienceParticleData(new Color(200 + random.nextInt(50), 150 + random.nextInt(100), 0), - getX() + 5 + random.nextInt(18), getY() + 18, 0.15F + (random.nextFloat() * 0.25F), 100 + random.nextInt(50))); - } - - if (isHovered()) { - if (screen.ticksExisted % 3 == 0) - ParticleStorage.addParticle(screen, new ExperienceParticleData(relic.canUseAbility(screen.stack, ability) - ? new Color(200 + random.nextInt(50), 150 + random.nextInt(100), 0) - : new Color(100 + random.nextInt(100), 100 + random.nextInt(100), 100 + random.nextInt(100)), - getX() + random.nextInt(width), getY() - 1, 0.15F + (random.nextFloat() * 0.25F), 100 + random.nextInt(50))); - - if (scale < maxScale) - scale = Math.min(maxScale, scale + ((maxScale - scale) * (0.25F))); - } else { - if (scale != minScale) - scale = Math.max(minScale, (scale - 0.025F)); - } - } - - @Override - public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { - if (!(screen.stack.getItem() instanceof IRelicItem relic)) - return; - - AbilityData data = relic.getAbilityData(ability); - - if (data == null) - return; - - PoseStack poseStack = guiGraphics.pose(); - - List tooltip = Lists.newArrayList(); - - int maxWidth = 110; - int renderWidth = 0; - - List entries = Lists.newArrayList( - Component.translatable("tooltip.relics." + ForgeRegistries.ITEMS.getKey(screen.stack.getItem()).getPath() + ".ability." + ability).withStyle(ChatFormatting.BOLD) - ); - - int level = relic.getLevel(screen.stack); - int requiredLevel = data.getRequiredLevel(); - - if (level < requiredLevel) { - entries.add(Component.literal(" ")); - - entries.add(Component.literal("▶ ").append(Component.translatable("tooltip.relics.relic.ability.tooltip.low_level", requiredLevel, Component.translatable("tooltip.relics.relic.status.negative").withStyle(ChatFormatting.RED)))); - } else if (data.getMaxLevel() == 0) { - entries.add(Component.literal(" ")); - - entries.add(Component.literal("▶ ").append(Component.translatable("tooltip.relics.relic.ability.tooltip.no_stats"))); - } else if (relic.mayPlayerUpgrade(MC.player, screen.stack, ability)) { - entries.add(Component.literal(" ")); - - entries.add(Component.literal("▶ ").append(Component.translatable("tooltip.relics.relic.ability.tooltip.ready_to_upgrade", Component.translatable("tooltip.relics.relic.status.positive").withStyle(ChatFormatting.GREEN)))); - } - - for (MutableComponent entry : entries) { - int entryWidth = (MC.font.width(entry)) / 2; - - if (entryWidth > renderWidth) - renderWidth = Math.min(entryWidth, maxWidth); - - tooltip.addAll(MC.font.split(entry, maxWidth * 2)); - } - - int height = Math.round(tooltip.size() * 4.5F); - - int y = getHeight() / 2; - - poseStack.scale(scale, scale, scale); - - poseStack.translate((getX() + (getWidth() / 2F)) / scale, (getY() + (getHeight() / 2F)) / scale, 0); - - ScreenUtils.drawTexturedTooltipBorder(guiGraphics, new ResourceLocation(Reference.MODID, "textures/gui/tooltip/border/paper.png"), - renderWidth, height, -((renderWidth + 19) / 2), y); - - int yOff = 0; - - for (FormattedCharSequence entry : tooltip) { - poseStack.pushPose(); - - poseStack.scale(0.5F, 0.5F, 0.5F); - - guiGraphics.drawString(MC.font, entry, -(MC.font.width(entry) / 2), ((y + yOff + 9) * 2), 0x412708, false); - - yOff += 5; - - poseStack.popPose(); - } - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/relic/ExperienceExchangeWidget.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/relic/ExperienceExchangeWidget.java deleted file mode 100644 index acd64ae2..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/client/screen/description/widgets/relic/ExperienceExchangeWidget.java +++ /dev/null @@ -1,199 +0,0 @@ -package it.hurts.sskirillss.relics.client.screen.description.widgets.relic; - -import com.google.common.collect.Lists; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import it.hurts.sskirillss.relics.client.screen.base.IHoverableWidget; -import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; -import it.hurts.sskirillss.relics.client.screen.description.RelicDescriptionScreen; -import it.hurts.sskirillss.relics.client.screen.description.data.ExperienceParticleData; -import it.hurts.sskirillss.relics.client.screen.description.widgets.base.AbstractDescriptionWidget; -import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; -import it.hurts.sskirillss.relics.client.screen.utils.ScreenUtils; -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; -import it.hurts.sskirillss.relics.network.NetworkHandler; -import it.hurts.sskirillss.relics.network.packets.leveling.PacketExperienceExchange; -import it.hurts.sskirillss.relics.utils.Reference; -import it.hurts.sskirillss.relics.utils.RenderUtils; -import it.hurts.sskirillss.relics.utils.data.AnimationData; -import net.minecraft.ChatFormatting; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.client.renderer.texture.TextureManager; -import net.minecraft.client.resources.sounds.SimpleSoundInstance; -import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.MutableComponent; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.util.FormattedCharSequence; -import net.minecraft.util.RandomSource; - -import java.awt.*; -import java.util.List; - -public class ExperienceExchangeWidget extends AbstractDescriptionWidget implements ITickingWidget, IHoverableWidget { - private final RelicDescriptionScreen screen; - - private int exchangeSpeed = 1; - - public ExperienceExchangeWidget(int x, int y, RelicDescriptionScreen screen) { - super(x, y, 12, 16); - - this.screen = screen; - } - - @Override - public boolean isLocked() { - return !(screen.stack.getItem() instanceof IRelicItem relic) || !relic.isExchangeAvailable(MC.player, screen.stack) || relic.isMaxLevel(screen.stack); - } - - @Override - public void onPress() { - if (isLocked()) - exchangeSpeed = 1; - } - - @Override - public void onTick() { - LocalPlayer player = MC.player; - - if (player == null) - return; - - RandomSource random = player.getRandom(); - - if (isHoveredOrFocused()) { - if (screen.ticksExisted % 10 == 0) - ParticleStorage.addParticle(screen, new ExperienceParticleData(isLocked() - ? new Color(100 + random.nextInt(100), 100 + random.nextInt(100), 100 + random.nextInt(100)) - : new Color(200 + random.nextInt(50), 150 + random.nextInt(100), 0), - getX() + random.nextInt(width), getY() + random.nextInt(height), - 0.15F + (random.nextFloat() * 0.25F), 100 + random.nextInt(50))); - - screen.gatherData(); - } - - if (isLocked() || !(isFocused() && isHovered())) - return; - - if (player.experienceLevel > 0 || player.totalExperience > 0) { - if (screen.ticksExisted % 2 == 0) - exchangeSpeed += 1; - - NetworkHandler.sendToServer(new PacketExperienceExchange(screen.pos, (int) Math.ceil(exchangeSpeed / 4F))); - - MC.getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.EXPERIENCE_ORB_PICKUP, 1F + (exchangeSpeed * 0.02F))); - } - } - - @Override - public void onRelease(double pMouseX, double pMouseY) { - this.setFocused(false); - - exchangeSpeed = 1; - } - - @Override - public void renderWidget(GuiGraphics guiGraphics, int pMouseX, int pMouseY, float pPartialTick) { - TextureManager manager = MC.getTextureManager(); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, RelicDescriptionScreen.TEXTURE); - - manager.bindForSetup(RelicDescriptionScreen.TEXTURE); - - boolean isLocked = isLocked(); - - guiGraphics.blit(RelicDescriptionScreen.TEXTURE, getX(), getY(), isLocked ? 407 : 394, 1, width, height, 512, 512); - - if (isHovered) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/gui/description/exchange_highlight_" + (isLocked ? "locked" : "unlocked") + ".png")); - - RenderSystem.enableBlend(); - - RenderUtils.renderAnimatedTextureFromCenter(guiGraphics.pose(), getX() + 6, getY() + 7, 32, 384, 32, 32, 1F, AnimationData.builder() - .frame(0, 2) - .frame(1, 2) - .frame(2, 2) - .frame(3, 2) - .frame(4, 2) - .frame(5, 2) - .frame(6, 2) - .frame(7, 2) - .frame(8, 2) - .frame(9, 2) - .frame(10, 2) - .frame(11, 2) - ); - - RenderSystem.disableBlend(); - } - } - - - @Override - public void onHovered(GuiGraphics guiGraphics, int mouseX, int mouseY) { - if (!(screen.stack.getItem() instanceof IRelicItem relic)) - return; - - RelicData data = relic.getRelicData(); - - if (data == null) - return; - - PoseStack poseStack = guiGraphics.pose(); - - List tooltip = Lists.newArrayList(); - - int maxWidth = 100; - int renderWidth = 0; - - int cost = relic.getExchangeCost(screen.stack); - - int experience = MC.player.totalExperience; - - MutableComponent negativeStatus = Component.translatable("tooltip.relics.relic.status.negative").withStyle(ChatFormatting.RED); - MutableComponent positiveStatus = Component.translatable("tooltip.relics.relic.status.positive").withStyle(ChatFormatting.GREEN); - - List entries = Lists.newArrayList( - Component.translatable("tooltip.relics.relic.exchange.description").withStyle(ChatFormatting.BOLD), - Component.literal(" ") - ); - - if (relic.isMaxLevel(screen.stack)) - entries.add(Component.literal("▶ ").append(Component.translatable("tooltip.relics.relic.exchange.locked"))); - else - entries.add(Component.translatable("tooltip.relics.relic.exchange.cost", cost, - (cost >= experience ? negativeStatus : positiveStatus))); - - for (MutableComponent entry : entries) { - int entryWidth = (MC.font.width(entry) + 4) / 2; - - if (entryWidth > renderWidth) - renderWidth = Math.min(entryWidth, maxWidth); - - tooltip.addAll(MC.font.split(entry, maxWidth * 2)); - } - - int height = Math.round(tooltip.size() * 5); - - int renderX = getX() + width + 1; - int renderY = mouseY - (height / 2) - 9; - - ScreenUtils.drawTexturedTooltipBorder(guiGraphics, new ResourceLocation(Reference.MODID, "textures/gui/tooltip/border/paper.png"), - renderWidth, height, renderX, renderY); - - int yOff = 0; - - poseStack.scale(0.5F, 0.5F, 0.5F); - - for (FormattedCharSequence entry : tooltip) { - guiGraphics.drawString(MC.font, entry, (renderX + 9) * 2, (renderY + 9 + yOff) * 2, 0x412708, false); - - yOff += 5; - } - - poseStack.scale(1F, 1F, 1F); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/utils/ParticleStorage.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/utils/ParticleStorage.java index 90ec9b62..7ae5d226 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/screen/utils/ParticleStorage.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/utils/ParticleStorage.java @@ -1,7 +1,7 @@ package it.hurts.sskirillss.relics.client.screen.utils; import com.google.common.collect.Lists; -import it.hurts.sskirillss.relics.client.screen.description.data.base.ParticleData; +import it.hurts.sskirillss.relics.client.screen.description.general.particles.base.ParticleData; import net.minecraft.client.gui.screens.Screen; import java.util.ArrayList; diff --git a/src/main/java/it/hurts/sskirillss/relics/client/screen/utils/ScreenUtils.java b/src/main/java/it/hurts/sskirillss/relics/client/screen/utils/ScreenUtils.java index 1998145c..40ef5087 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/screen/utils/ScreenUtils.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/screen/utils/ScreenUtils.java @@ -5,8 +5,15 @@ import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.FormattedCharSequence; +import net.minecraft.util.RandomSource; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.IntStream; public class ScreenUtils { public static void drawTexturedTooltipBorder(GuiGraphics guiGraphics, ResourceLocation texture, int width, int height, int x, int y) { @@ -52,4 +59,72 @@ public static void drawCenteredString(GuiGraphics guiGraphics, Font font, Format public static boolean isHovered(int x, int y, int width, int height, int mouseX, int mouseY) { return (mouseX >= x && mouseX <= x + width) && (mouseY >= y && mouseY <= y + height); } + + public static final ResourceLocation ALT_FONT = ResourceLocation.withDefaultNamespace("alt"); + public static final ResourceLocation ILLAGER_ALT_FONT = ResourceLocation.withDefaultNamespace("illageralt"); + + public static MutableComponent illageriate(MutableComponent input, double percentage, long seed) { + return stylizeWithReplacement(input, percentage, Style.EMPTY.withFont(ILLAGER_ALT_FONT), seed); + } + + public static MutableComponent galactizate(MutableComponent input, double percentage, long seed) { + return stylizeWithReplacement(input, percentage, Style.EMPTY.withFont(ALT_FONT), seed); + } + + public static MutableComponent obfuscate(MutableComponent input, double percentage, long seed) { + return stylize(input, percentage, Style.EMPTY.withObfuscated(true), seed); + } + + public static MutableComponent stylizeWithReplacement(String input, double percentage, Style style, long seed) { + return stylizeWithReplacement(Component.literal(input), percentage, style, seed); + } + + public static MutableComponent stylizeWithReplacement(MutableComponent input, double percentage, Style style, long seed) { + RandomSource random = RandomSource.create(seed); + + String text = input.getString(); + + List letterIndices = IntStream.range(0, text.length()) + .filter(i -> !Character.isSpaceChar(text.charAt(i))) + .boxed().collect(Collectors.toList()); + + Collections.shuffle(letterIndices, new Random(seed)); + + Set indicesToReplace = new HashSet<>(letterIndices.subList(0, Math.min((int) Math.round(letterIndices.size() * percentage), letterIndices.size()))); + + List englishLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".chars() + .mapToObj(c -> (char) c) + .toList(); + + return IntStream.range(0, text.length()).mapToObj(i -> { + if (indicesToReplace.contains(i)) + return Component.literal(String.valueOf(englishLetters.get(random.nextInt(englishLetters.size())))).setStyle(style); + + return Component.literal(String.valueOf(text.charAt(i))).setStyle(input.getStyle()); + }).collect(Component::empty, MutableComponent::append, MutableComponent::append); + } + + public static MutableComponent stylize(MutableComponent input, double percentage, Style style, long seed) { + RandomSource random = RandomSource.create(seed); + + String text = input.getString(); + int length = text.length(); + + var indices = IntStream.generate(() -> random.nextInt(length)) + .distinct() + .limit((int) (length * percentage)) + .boxed() + .collect(Collectors.toSet()); + + return IntStream.range(0, length) + .mapToObj(index -> { + MutableComponent component = Component.literal(String.valueOf(text.charAt(index))).setStyle(input.getStyle()); + + if (indices.contains(index)) + component.setStyle(style.applyTo(component.getStyle())); + + return component; + }) + .collect(Component::empty, MutableComponent::append, MutableComponent::append); + } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/client/tooltip/TooltipBorderHandler.java b/src/main/java/it/hurts/sskirillss/relics/client/tooltip/TooltipBorderHandler.java index 488b95a8..e1fd6e0c 100644 --- a/src/main/java/it/hurts/sskirillss/relics/client/tooltip/TooltipBorderHandler.java +++ b/src/main/java/it/hurts/sskirillss/relics/client/tooltip/TooltipBorderHandler.java @@ -11,16 +11,16 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.player.LocalPlayer; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.RenderTooltipEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RenderTooltipEvent; import org.lwjgl.opengl.GL11; -@Mod.EventBusSubscriber(modid = Reference.MODID, bus = Mod.EventBusSubscriber.Bus.FORGE, value = Dist.CLIENT) +@EventBusSubscriber(modid = Reference.MODID, bus = EventBusSubscriber.Bus.GAME, value = Dist.CLIENT) public class TooltipBorderHandler { @SubscribeEvent public static void onTooltipDisplay(TooltipDisplayEvent event) { @@ -48,9 +48,9 @@ public static void onTooltipDisplay(TooltipDisplayEvent event) { int x = event.getX(); int y = event.getY(); - String id = tooltip.getIcon().isEmpty() ? ForgeRegistries.ITEMS.getKey(stack.getItem()).getPath() : tooltip.getIcon(); + String id = tooltip.getIcon().isEmpty() ? BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath() : tooltip.getIcon(); - ResourceLocation texture = new ResourceLocation(Reference.MODID, "textures/gui/tooltip/frame/" + id + "_frame.png"); + ResourceLocation texture = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/tooltip/frame/" + id + "_frame.png"); RenderSystem.setShaderColor(1F, 1F, 1F, 1F); RenderSystem.setShaderTexture(0, texture); @@ -91,7 +91,7 @@ public static void onTooltipDisplay(TooltipDisplayEvent event) { graphics.blit(texture, x + (width - middleWidth) / 2, y - middleHeight + 1, cornerWidth, offset, middleWidth, middleHeight, texWidth, texHeight); graphics.blit(texture, x + (width - middleWidth) / 2, y + height - 1, cornerWidth, middleHeight + offset, middleWidth, middleHeight, texWidth, texHeight); - texture = new ResourceLocation(Reference.MODID, "textures/gui/tooltip/frame/" + id + "_star.png"); + texture = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/tooltip/frame/" + id + "_star.png"); RenderSystem.setShaderTexture(0, texture); @@ -100,7 +100,7 @@ public static void onTooltipDisplay(TooltipDisplayEvent event) { for (int i = 1; i < relic.getRelicQuality(stack) + 1; i++) { boolean isAliquot = i % 2 == 1; - float color = (float) (0.85F + Math.sin(player.tickCount * Math.ceil(i / 2F) * 0.075F) * 0.3F); + float color = (float) (0.85F + Math.sin(player.tickCount * Math.ceil(i / 2F) * 0.075F) * 0.2F); RenderSystem.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE); @@ -133,7 +133,7 @@ public static void onTooltipColorEvent(RenderTooltipEvent.Color event) { event.setBorderEnd(tooltip.getBorderBottom()); if (tooltip.getBackgroundTop() != -1) - event.setBorderStart(tooltip.getBackgroundTop()); + event.setBackgroundStart(tooltip.getBackgroundTop()); if (tooltip.getBackgroundBottom() != -1) event.setBackgroundEnd(tooltip.getBackgroundBottom()); } diff --git a/src/main/java/it/hurts/sskirillss/relics/commands/RelicsCommand.java b/src/main/java/it/hurts/sskirillss/relics/commands/RelicsCommand.java index bdd74fe4..0222c973 100644 --- a/src/main/java/it/hurts/sskirillss/relics/commands/RelicsCommand.java +++ b/src/main/java/it/hurts/sskirillss/relics/commands/RelicsCommand.java @@ -6,35 +6,20 @@ import com.mojang.brigadier.arguments.IntegerArgumentType; import it.hurts.sskirillss.relics.commands.arguments.RelicAbilityArgument; import it.hurts.sskirillss.relics.commands.arguments.RelicAbilityStatArgument; -import it.hurts.sskirillss.relics.config.ConfigHelper; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.network.chat.Component; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; -import net.minecraft.world.item.ItemStack; -import net.minecraftforge.server.command.EnumArgument; - -import java.util.Map; +import net.neoforged.neoforge.server.command.EnumArgument; public class RelicsCommand { public static void register(CommandDispatcher dispatcher) { dispatcher.register(Commands.literal("relics").requires(sender -> sender.hasPermission(2)) - .then(Commands.literal("config") - .then(Commands.literal("reload") - .executes(context -> { - ConfigHelper.readConfigs(); - - return Command.SINGLE_SUCCESS; - }))) .then(Commands.literal("maximize") .executes(context -> { - ServerPlayer player = context.getSource().getPlayerOrException(); - ItemStack stack = player.getItemInHand(InteractionHand.MAIN_HAND); + var player = context.getSource().getPlayerOrException(); + var stack = player.getItemInHand(InteractionHand.MAIN_HAND); if (!(stack.getItem() instanceof IRelicItem relic)) { context.getSource().sendFailure(Component.translatable("command.relics.base.not_relic")); @@ -42,21 +27,20 @@ public static void register(CommandDispatcher dispatcher) { return 0; } - RelicData relicData = relic.getRelicData(); - - relic.setLevel(stack, relicData.getLeveling().getMaxLevel()); + var relicData = relic.getRelicData(); - for (Map.Entry abilityEntry : relicData.getAbilities().getAbilities().entrySet()) { - String abilityId = abilityEntry.getKey(); - AbilityData abilityInfo = abilityEntry.getValue(); + relic.setRelicLevel(stack, relicData.getLeveling().getMaxLevel()); - relic.setAbilityPoints(stack, abilityId, abilityInfo.getMaxLevel()); + for (var abilityEntry : relicData.getAbilities().getAbilities().entrySet()) { + var abilityId = abilityEntry.getKey(); + var abilityData = abilityEntry.getValue(); - for (Map.Entry statEntry : abilityInfo.getStats().entrySet()) { - String statId = statEntry.getKey(); + relic.setAbilityLevel(stack, abilityId, abilityData.getMaxLevel()); + relic.setLockUnlocks(stack, abilityId, relic.getMaxLockUnlocks()); + relic.setAbilityResearched(stack, abilityId, true); - relic.setAbilityValue(stack, abilityId, statId, relic.getStatByQuality(abilityId, statId, relic.getMaxQuality())); - } + for (var statEntry : abilityData.getStats().entrySet()) + relic.setStatInitialValue(stack, abilityId, statEntry.getKey(), statEntry.getValue().getInitialValue().getValue()); } return Command.SINGLE_SUCCESS; @@ -64,8 +48,8 @@ public static void register(CommandDispatcher dispatcher) { ) .then(Commands.literal("minimize") .executes(context -> { - ServerPlayer player = context.getSource().getPlayerOrException(); - ItemStack stack = player.getItemInHand(InteractionHand.MAIN_HAND); + var player = context.getSource().getPlayerOrException(); + var stack = player.getItemInHand(InteractionHand.MAIN_HAND); if (!(stack.getItem() instanceof IRelicItem relic)) { context.getSource().sendFailure(Component.translatable("command.relics.base.not_relic")); @@ -73,20 +57,22 @@ public static void register(CommandDispatcher dispatcher) { return 0; } - RelicData relicData = relic.getRelicData(); + var relicData = relic.getRelicData(); - relic.setLevel(stack, relicData.getLeveling().getMaxLevel()); + relic.setRelicLevel(stack, relicData.getLeveling().getMaxLevel()); + relic.setRelicExperience(stack, 0); - for (Map.Entry abilityEntry : relicData.getAbilities().getAbilities().entrySet()) { - String abilityId = abilityEntry.getKey(); + for (var abilityEntry : relicData.getAbilities().getAbilities().entrySet()) { + var abilityId = abilityEntry.getKey(); - relic.setAbilityPoints(stack, abilityId, 0); + relic.setAbilityResearched(stack, abilityId, false); + relic.setAbilityLevel(stack, abilityId, 0); - for (Map.Entry statEntry : abilityEntry.getValue().getStats().entrySet()) { - String statId = statEntry.getKey(); + if (!relic.isEnoughLevel(stack, abilityId)) + relic.setLockUnlocks(stack, abilityId, 0); - relic.setAbilityValue(stack, abilityId, statId, relic.getStatByQuality(abilityId, statId, 0)); - } + for (var statEntry : abilityEntry.getValue().getStats().entrySet()) + relic.setStatInitialValue(stack, abilityId, statEntry.getKey(), statEntry.getValue().getInitialValue().getKey()); } return Command.SINGLE_SUCCESS; @@ -96,8 +82,8 @@ public static void register(CommandDispatcher dispatcher) { .then(Commands.argument("action", EnumArgument.enumArgument(CommandAction.class)) .then(Commands.argument("level", IntegerArgumentType.integer()) .executes(context -> { - ServerPlayer player = context.getSource().getPlayerOrException(); - ItemStack stack = player.getItemInHand(InteractionHand.MAIN_HAND); + var player = context.getSource().getPlayerOrException(); + var stack = player.getItemInHand(InteractionHand.MAIN_HAND); if (!(stack.getItem() instanceof IRelicItem relic)) { context.getSource().sendFailure(Component.translatable("command.relics.base.not_relic")); @@ -105,14 +91,12 @@ public static void register(CommandDispatcher dispatcher) { return 0; } - CommandAction action = context.getArgument("action", CommandAction.class); + var level = IntegerArgumentType.getInteger(context, "level"); - int level = IntegerArgumentType.getInteger(context, "level"); - - switch (action) { - case SET -> relic.setLevel(stack, level); - case ADD -> relic.addLevel(stack, level); - case TAKE -> relic.addLevel(stack, -level); + switch (context.getArgument("action", CommandAction.class)) { + case SET -> relic.setRelicLevel(stack, level); + case ADD -> relic.addRelicLevel(stack, level); + case TAKE -> relic.addRelicLevel(stack, -level); } return Command.SINGLE_SUCCESS; @@ -121,8 +105,8 @@ public static void register(CommandDispatcher dispatcher) { .then(Commands.argument("action", EnumArgument.enumArgument(CommandAction.class)) .then(Commands.argument("experience", IntegerArgumentType.integer()) .executes(context -> { - ServerPlayer player = context.getSource().getPlayerOrException(); - ItemStack stack = player.getItemInHand(InteractionHand.MAIN_HAND); + var player = context.getSource().getPlayerOrException(); + var stack = player.getItemInHand(InteractionHand.MAIN_HAND); if (!(stack.getItem() instanceof IRelicItem relic)) { context.getSource().sendFailure(Component.translatable("command.relics.base.not_relic")); @@ -130,14 +114,12 @@ public static void register(CommandDispatcher dispatcher) { return 0; } - CommandAction action = context.getArgument("action", CommandAction.class); - - int experience = IntegerArgumentType.getInteger(context, "experience"); + var experience = IntegerArgumentType.getInteger(context, "experience"); - switch (action) { - case SET -> relic.setExperience(stack, experience); - case ADD -> relic.addExperience(stack, experience); - case TAKE -> relic.addExperience(stack, -experience); + switch (context.getArgument("action", CommandAction.class)) { + case SET -> relic.setRelicExperience(stack, experience); + case ADD -> relic.addRelicExperience(stack, experience); + case TAKE -> relic.addRelicExperience(stack, -experience); } return Command.SINGLE_SUCCESS; @@ -146,8 +128,8 @@ public static void register(CommandDispatcher dispatcher) { .then(Commands.argument("action", EnumArgument.enumArgument(CommandAction.class)) .then(Commands.argument("points", IntegerArgumentType.integer()) .executes(context -> { - ServerPlayer player = context.getSource().getPlayerOrException(); - ItemStack stack = player.getItemInHand(InteractionHand.MAIN_HAND); + var player = context.getSource().getPlayerOrException(); + var stack = player.getItemInHand(InteractionHand.MAIN_HAND); if (!(stack.getItem() instanceof IRelicItem relic)) { context.getSource().sendFailure(Component.translatable("command.relics.base.not_relic")); @@ -155,14 +137,12 @@ public static void register(CommandDispatcher dispatcher) { return 0; } - CommandAction action = context.getArgument("action", CommandAction.class); + var points = IntegerArgumentType.getInteger(context, "points"); - int points = IntegerArgumentType.getInteger(context, "points"); - - switch (action) { - case SET -> relic.setPoints(stack, points); - case ADD -> relic.addPoints(stack, points); - case TAKE -> relic.addPoints(stack, -points); + switch (context.getArgument("action", CommandAction.class)) { + case SET -> relic.setRelicLevelingPoints(stack, points); + case ADD -> relic.addRelicLevelingPoints(stack, points); + case TAKE -> relic.addRelicLevelingPoints(stack, -points); } return Command.SINGLE_SUCCESS; @@ -173,8 +153,8 @@ public static void register(CommandDispatcher dispatcher) { .then(Commands.argument("ability", RelicAbilityArgument.ability()) .then(Commands.argument("points", IntegerArgumentType.integer()) .executes(context -> { - ServerPlayer player = context.getSource().getPlayerOrException(); - ItemStack stack = player.getItemInHand(InteractionHand.MAIN_HAND); + var player = context.getSource().getPlayerOrException(); + var stack = player.getItemInHand(InteractionHand.MAIN_HAND); if (!(stack.getItem() instanceof IRelicItem relic)) { context.getSource().sendFailure(Component.translatable("command.relics.base.not_relic")); @@ -182,24 +162,24 @@ public static void register(CommandDispatcher dispatcher) { return 0; } - CommandAction action = context.getArgument("action", CommandAction.class); + var action = context.getArgument("action", CommandAction.class); - String ability = RelicAbilityArgument.getAbility(context, "ability"); - int points = IntegerArgumentType.getInteger(context, "points"); + var ability = RelicAbilityArgument.getAbility(context, "ability"); + var points = IntegerArgumentType.getInteger(context, "points"); if (ability.equals("all")) { - for (String entry : relic.getRelicData().getAbilities().getAbilities().keySet()) { + for (var entry : relic.getRelicData().getAbilities().getAbilities().keySet()) { switch (action) { - case SET -> relic.setAbilityPoints(stack, entry, points); - case ADD -> relic.addAbilityPoints(stack, entry, points); - case TAKE -> relic.addAbilityPoints(stack, entry, -points); + case SET -> relic.setAbilityLevel(stack, entry, points); + case ADD -> relic.addAbilityLevel(stack, entry, points); + case TAKE -> relic.addAbilityLevel(stack, entry, -points); } } } else { switch (action) { - case SET -> relic.setAbilityPoints(stack, ability, points); - case ADD -> relic.addAbilityPoints(stack, ability, points); - case TAKE -> relic.addAbilityPoints(stack, ability, -points); + case SET -> relic.setAbilityLevel(stack, ability, points); + case ADD -> relic.addAbilityLevel(stack, ability, points); + case TAKE -> relic.addAbilityLevel(stack, ability, -points); } } @@ -211,8 +191,8 @@ public static void register(CommandDispatcher dispatcher) { .then(Commands.argument("stat", RelicAbilityStatArgument.abilityStat()) .then(Commands.argument("value", DoubleArgumentType.doubleArg()) .executes(context -> { - ServerPlayer player = context.getSource().getPlayerOrException(); - ItemStack stack = player.getItemInHand(InteractionHand.MAIN_HAND); + var player = context.getSource().getPlayerOrException(); + var stack = player.getItemInHand(InteractionHand.MAIN_HAND); if (!(stack.getItem() instanceof IRelicItem relic)) { context.getSource().sendFailure(Component.translatable("command.relics.base.not_relic")); @@ -220,44 +200,44 @@ public static void register(CommandDispatcher dispatcher) { return 0; } - CommandAction action = context.getArgument("action", CommandAction.class); + var action = context.getArgument("action", CommandAction.class); - String ability = RelicAbilityArgument.getAbility(context, "ability"); - String stat = RelicAbilityStatArgument.getAbilityStat(context, "stat"); - double value = DoubleArgumentType.getDouble(context, "value"); + var ability = RelicAbilityArgument.getAbility(context, "ability"); + var stat = RelicAbilityStatArgument.getAbilityStat(context, "stat"); + var value = DoubleArgumentType.getDouble(context, "value"); if (ability.equals("all")) { - for (String abilityEntry : relic.getRelicData().getAbilities().getAbilities().keySet()) { + for (var abilityEntry : relic.getRelicData().getAbilities().getAbilities().keySet()) { if (stat.equals("all")) { - for (String statEntry : relic.getAbilityData(abilityEntry).getStats().keySet()) { + for (var statEntry : relic.getAbilityData(abilityEntry).getStats().keySet()) { switch (action) { - case SET -> relic.setAbilityValue(stack, abilityEntry, statEntry, value); - case ADD -> relic.addAbilityValue(stack, abilityEntry, statEntry, value); - case TAKE -> relic.addAbilityValue(stack, abilityEntry, statEntry, -value); + case SET -> relic.setStatInitialValue(stack, abilityEntry, statEntry, value); + case ADD -> relic.addStatInitialValue(stack, abilityEntry, statEntry, value); + case TAKE -> relic.addStatInitialValue(stack, abilityEntry, statEntry, -value); } } } else { switch (action) { - case SET -> relic.setAbilityValue(stack, abilityEntry, stat, value); - case ADD -> relic.addAbilityValue(stack, abilityEntry, stat, value); - case TAKE -> relic.addAbilityValue(stack, abilityEntry, stat, -value); + case SET -> relic.setStatInitialValue(stack, abilityEntry, stat, value); + case ADD -> relic.addStatInitialValue(stack, abilityEntry, stat, value); + case TAKE -> relic.addStatInitialValue(stack, abilityEntry, stat, -value); } } } } else { if (stat.equals("all")) { - for (String statEntry : relic.getAbilityData(ability).getStats().keySet()) { + for (var statEntry : relic.getAbilityData(ability).getStats().keySet()) { switch (action) { - case SET -> relic.setAbilityValue(stack, ability, statEntry, value); - case ADD -> relic.addAbilityValue(stack, ability, statEntry, value); - case TAKE -> relic.addAbilityValue(stack, ability, statEntry, -value); + case SET -> relic.setStatInitialValue(stack, ability, statEntry, value); + case ADD -> relic.addStatInitialValue(stack, ability, statEntry, value); + case TAKE -> relic.addStatInitialValue(stack, ability, statEntry, -value); } } } else { switch (action) { - case SET -> relic.setAbilityValue(stack, ability, stat, value); - case ADD -> relic.addAbilityValue(stack, ability, stat, value); - case TAKE -> relic.addAbilityValue(stack, ability, stat, -value); + case SET -> relic.setStatInitialValue(stack, ability, stat, value); + case ADD -> relic.addStatInitialValue(stack, ability, stat, value); + case TAKE -> relic.addStatInitialValue(stack, ability, stat, -value); } } } @@ -270,8 +250,8 @@ public static void register(CommandDispatcher dispatcher) { .then(Commands.argument("stat", RelicAbilityStatArgument.abilityStat()) .then(Commands.argument("quality", IntegerArgumentType.integer()) .executes(context -> { - ServerPlayer player = context.getSource().getPlayerOrException(); - ItemStack stack = player.getItemInHand(InteractionHand.MAIN_HAND); + var player = context.getSource().getPlayerOrException(); + var stack = player.getItemInHand(InteractionHand.MAIN_HAND); if (!(stack.getItem() instanceof IRelicItem relic)) { context.getSource().sendFailure(Component.translatable("command.relics.base.not_relic")); @@ -279,52 +259,52 @@ public static void register(CommandDispatcher dispatcher) { return 0; } - CommandAction action = context.getArgument("action", CommandAction.class); + var action = context.getArgument("action", CommandAction.class); - String ability = RelicAbilityArgument.getAbility(context, "ability"); - String stat = RelicAbilityStatArgument.getAbilityStat(context, "stat"); - int quality = IntegerArgumentType.getInteger(context, "quality"); + var ability = RelicAbilityArgument.getAbility(context, "ability"); + var stat = RelicAbilityStatArgument.getAbilityStat(context, "stat"); + var quality = IntegerArgumentType.getInteger(context, "quality"); if (ability.equals("all")) { for (String abilityEntry : relic.getRelicData().getAbilities().getAbilities().keySet()) { if (stat.equals("all")) { for (String statEntry : relic.getAbilityData(abilityEntry).getStats().keySet()) { - double value = relic.getStatByQuality(abilityEntry, statEntry, quality); + double value = relic.getStatValueByQuality(abilityEntry, statEntry, quality); switch (action) { - case SET -> relic.setAbilityValue(stack, abilityEntry, statEntry, value); - case ADD -> relic.addAbilityValue(stack, abilityEntry, statEntry, value); - case TAKE -> relic.addAbilityValue(stack, abilityEntry, statEntry, -value); + case SET -> relic.setStatInitialValue(stack, abilityEntry, statEntry, value); + case ADD -> relic.addStatInitialValue(stack, abilityEntry, statEntry, value); + case TAKE -> relic.addStatInitialValue(stack, abilityEntry, statEntry, -value); } } } else { - double value = relic.getStatByQuality(abilityEntry, stat, quality); + double value = relic.getStatValueByQuality(abilityEntry, stat, quality); switch (action) { - case SET -> relic.setAbilityValue(stack, abilityEntry, stat, value); - case ADD -> relic.addAbilityValue(stack, abilityEntry, stat, value); - case TAKE -> relic.addAbilityValue(stack, abilityEntry, stat, -value); + case SET -> relic.setStatInitialValue(stack, abilityEntry, stat, value); + case ADD -> relic.addStatInitialValue(stack, abilityEntry, stat, value); + case TAKE -> relic.addStatInitialValue(stack, abilityEntry, stat, -value); } } } } else { if (stat.equals("all")) { for (String statEntry : relic.getAbilityData(ability).getStats().keySet()) { - double value = relic.getStatByQuality(ability, statEntry, quality); + double value = relic.getStatValueByQuality(ability, statEntry, quality); switch (action) { - case SET -> relic.setAbilityValue(stack, ability, statEntry, value); - case ADD -> relic.addAbilityValue(stack, ability, statEntry, value); - case TAKE -> relic.addAbilityValue(stack, ability, statEntry, -value); + case SET -> relic.setStatInitialValue(stack, ability, statEntry, value); + case ADD -> relic.addStatInitialValue(stack, ability, statEntry, value); + case TAKE -> relic.addStatInitialValue(stack, ability, statEntry, -value); } } } else { - double value = relic.getStatByQuality(ability, stat, quality); + double value = relic.getStatValueByQuality(ability, stat, quality); switch (action) { - case SET -> relic.setAbilityValue(stack, ability, stat, value); - case ADD -> relic.addAbilityValue(stack, ability, stat, value); - case TAKE -> relic.addAbilityValue(stack, ability, stat, -value); + case SET -> relic.setStatInitialValue(stack, ability, stat, value); + case ADD -> relic.addStatInitialValue(stack, ability, stat, value); + case TAKE -> relic.addStatInitialValue(stack, ability, stat, -value); } } } @@ -335,8 +315,8 @@ public static void register(CommandDispatcher dispatcher) { .then(Commands.argument("ability", RelicAbilityArgument.ability()) .then(Commands.argument("stat", RelicAbilityStatArgument.abilityStat()) .executes(context -> { - ServerPlayer player = context.getSource().getPlayerOrException(); - ItemStack stack = player.getItemInHand(InteractionHand.MAIN_HAND); + var player = context.getSource().getPlayerOrException(); + var stack = player.getItemInHand(InteractionHand.MAIN_HAND); if (!(stack.getItem() instanceof IRelicItem relic)) { context.getSource().sendFailure(Component.translatable("command.relics.base.not_relic")); @@ -344,13 +324,13 @@ public static void register(CommandDispatcher dispatcher) { return 0; } - String ability = RelicAbilityArgument.getAbility(context, "ability"); - String stat = RelicAbilityStatArgument.getAbilityStat(context, "stat"); + var ability = RelicAbilityArgument.getAbility(context, "ability"); + var stat = RelicAbilityStatArgument.getAbilityStat(context, "stat"); if (ability.equals("all")) { - for (String abilityEntry : relic.getRelicData().getAbilities().getAbilities().keySet()) { + for (var abilityEntry : relic.getRelicData().getAbilities().getAbilities().keySet()) { if (stat.equals("all")) { - for (String statEntry : relic.getAbilityData(abilityEntry).getStats().keySet()) + for (var statEntry : relic.getAbilityData(abilityEntry).getStats().keySet()) relic.randomizeStat(stack, abilityEntry, statEntry); } else { relic.randomizeStat(stack, abilityEntry, stat); @@ -358,7 +338,7 @@ public static void register(CommandDispatcher dispatcher) { } } else { if (stat.equals("all")) { - for (String statEntry : relic.getAbilityData(ability).getStats().keySet()) + for (var statEntry : relic.getAbilityData(ability).getStats().keySet()) relic.randomizeStat(stack, ability, statEntry); } else { relic.randomizeStat(stack, ability, stat); diff --git a/src/main/java/it/hurts/sskirillss/relics/components/AbilitiesComponent.java b/src/main/java/it/hurts/sskirillss/relics/components/AbilitiesComponent.java new file mode 100644 index 00000000..3ac26e55 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/components/AbilitiesComponent.java @@ -0,0 +1,18 @@ +package it.hurts.sskirillss.relics.components; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.Builder; +import lombok.Singular; + +import java.util.Map; + +@Builder(toBuilder = true) +public record AbilitiesComponent(@Singular Map abilities) { + public static final AbilitiesComponent EMPTY = new AbilitiesComponent(Map.of()); + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group(Codec.unboundedMap(Codec.STRING, AbilityComponent.CODEC).fieldOf("abilities").forGetter(AbilitiesComponent::abilities)) + .apply(instance, AbilitiesComponent::new) + ); +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/components/AbilityComponent.java b/src/main/java/it/hurts/sskirillss/relics/components/AbilityComponent.java new file mode 100644 index 00000000..cc28029f --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/components/AbilityComponent.java @@ -0,0 +1,22 @@ +package it.hurts.sskirillss.relics.components; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.Builder; +import lombok.Singular; + +import java.util.Map; + +@Builder(toBuilder = true) +public record AbilityComponent(@Singular Map stats, ResearchComponent research, LockComponent lock, AbilityExtenderComponent extender, int points) { + public static final AbilityComponent EMPTY = new AbilityComponent(Map.of(), ResearchComponent.EMPTY, LockComponent.EMPTY, AbilityExtenderComponent.EMPTY, 0); + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group(Codec.unboundedMap(Codec.STRING, StatComponent.CODEC).fieldOf("stats").forGetter(AbilityComponent::stats), + ResearchComponent.CODEC.fieldOf("research").forGetter(AbilityComponent::research), + LockComponent.CODEC.fieldOf("lock").forGetter(AbilityComponent::lock), + AbilityExtenderComponent.CODEC.fieldOf("extender").forGetter(AbilityComponent::extender), + Codec.INT.fieldOf("points").forGetter(AbilityComponent::points)) + .apply(instance, AbilityComponent::new) + ); +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/components/AbilityExtenderComponent.java b/src/main/java/it/hurts/sskirillss/relics/components/AbilityExtenderComponent.java new file mode 100644 index 00000000..cabbf6d7 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/components/AbilityExtenderComponent.java @@ -0,0 +1,17 @@ +package it.hurts.sskirillss.relics.components; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.Builder; + +@Builder(toBuilder = true) +public record AbilityExtenderComponent(int cooldownCap, int cooldown, boolean ticking) { + public static final AbilityExtenderComponent EMPTY = new AbilityExtenderComponent(0, 0, false); + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group(Codec.INT.fieldOf("cooldownCap").forGetter(AbilityExtenderComponent::cooldownCap), + Codec.INT.fieldOf("cooldown").forGetter(AbilityExtenderComponent::cooldown), + Codec.BOOL.fieldOf("ticking").forGetter(AbilityExtenderComponent::ticking)) + .apply(instance, AbilityExtenderComponent::new) + ); +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/components/DataComponent.java b/src/main/java/it/hurts/sskirillss/relics/components/DataComponent.java new file mode 100644 index 00000000..9517374c --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/components/DataComponent.java @@ -0,0 +1,16 @@ +package it.hurts.sskirillss.relics.components; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.Builder; + +@Builder(toBuilder = true) +public record DataComponent(AbilitiesComponent abilities, LevelingComponent leveling) { + public static final DataComponent EMPTY = new DataComponent(AbilitiesComponent.EMPTY, LevelingComponent.EMPTY); + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group(AbilitiesComponent.CODEC.fieldOf("abilities").forGetter(DataComponent::abilities), + LevelingComponent.CODEC.fieldOf("leveling").forGetter(DataComponent::leveling)) + .apply(instance, DataComponent::new) + ); +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/components/LevelingComponent.java b/src/main/java/it/hurts/sskirillss/relics/components/LevelingComponent.java new file mode 100644 index 00000000..e29a2912 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/components/LevelingComponent.java @@ -0,0 +1,18 @@ +package it.hurts.sskirillss.relics.components; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.Builder; + +@Builder(toBuilder = true) +public record LevelingComponent(int level, int experience, int points, int luck) { + public static final LevelingComponent EMPTY = new LevelingComponent(0, 0, 0, 0); + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group(Codec.INT.fieldOf("level").forGetter(LevelingComponent::level), + Codec.INT.fieldOf("experience").forGetter(LevelingComponent::experience), + Codec.INT.fieldOf("points").forGetter(LevelingComponent::points), + Codec.INT.fieldOf("luck").forGetter(LevelingComponent::luck)) + .apply(instance, LevelingComponent::new) + ); +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/components/LockComponent.java b/src/main/java/it/hurts/sskirillss/relics/components/LockComponent.java new file mode 100644 index 00000000..26faafb4 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/components/LockComponent.java @@ -0,0 +1,15 @@ +package it.hurts.sskirillss.relics.components; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.Builder; + +@Builder(toBuilder = true) +public record LockComponent(int unlocks) { + public static final LockComponent EMPTY = new LockComponent(0); + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group(Codec.INT.fieldOf("breaks").forGetter(LockComponent::unlocks)) + .apply(instance, LockComponent::new) + ); +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/components/ResearchComponent.java b/src/main/java/it/hurts/sskirillss/relics/components/ResearchComponent.java new file mode 100644 index 00000000..c32e0e31 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/components/ResearchComponent.java @@ -0,0 +1,20 @@ +package it.hurts.sskirillss.relics.components; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.Builder; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Builder(toBuilder = true) +public record ResearchComponent(Map> links, boolean researched) { + public static final ResearchComponent EMPTY = new ResearchComponent(new HashMap<>(), false); + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group(Codec.unboundedMap(Codec.STRING, Codec.list(Codec.INT)).fieldOf("links").forGetter(ResearchComponent::links), + Codec.BOOL.fieldOf("researched").forGetter(ResearchComponent::researched) + ).apply(instance, ResearchComponent::new) + ); +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/components/StatComponent.java b/src/main/java/it/hurts/sskirillss/relics/components/StatComponent.java new file mode 100644 index 00000000..ec4b17e0 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/components/StatComponent.java @@ -0,0 +1,15 @@ +package it.hurts.sskirillss.relics.components; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.Builder; + +@Builder(toBuilder = true) +public record StatComponent(double initialValue) { + public static final StatComponent EMPTY = new StatComponent(0D); + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group(Codec.DOUBLE.fieldOf("initialValue").forGetter(StatComponent::initialValue)) + .apply(instance, StatComponent::new) + ); +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/config/ConfigHelper.java b/src/main/java/it/hurts/sskirillss/relics/config/ConfigHelper.java deleted file mode 100644 index 8d7bb159..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/config/ConfigHelper.java +++ /dev/null @@ -1,168 +0,0 @@ -package it.hurts.sskirillss.relics.config; - -import it.hurts.sskirillss.octolib.config.data.OctoConfig; -import it.hurts.sskirillss.octolib.config.storage.ConfigStorage; -import it.hurts.sskirillss.relics.config.data.*; -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollection; -import net.minecraftforge.fml.loading.FMLPaths; -import net.minecraftforge.registries.ForgeRegistries; -import org.apache.commons.lang3.tuple.Pair; - -import java.nio.file.Path; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class ConfigHelper { - public static Map CACHE = new HashMap<>(); - - public static OctoConfig getRelicConfig(IRelicItem relic) { - return ConfigStorage.get(getPath(relic)); - } - - public static Path getPath(IRelicItem relic) { - if (ConfigHelper.CACHE.containsKey(relic)) - return ConfigHelper.CACHE.get(relic); - - Path path = FMLPaths.CONFIGDIR.get().resolve(ForgeRegistries.ITEMS.getKey(relic.getItem()).getNamespace()).resolve(ForgeRegistries.ITEMS.getKey(relic.getItem()).getPath() + ".json"); - - ConfigHelper.CACHE.put(relic, path); - - return path; - } - - public static void setupConfigs() { - ConfigHelper.constructConfigs(); - ConfigHelper.readConfigs(); - } - - public static void readConfigs() { - List relics = ForgeRegistries.ITEMS.getValues().stream().filter(entry -> entry instanceof IRelicItem).map(entry -> (IRelicItem) entry).toList(); - - if (relics.isEmpty()) - return; - - for (IRelicItem relic : relics) - readRelicConfig(relic); - } - - private static void readRelicConfig(IRelicItem relic) { - RelicData relicData = relic.getRelicData(); - - if (relicData == null) - return; - - OctoConfig config = getRelicConfig(relic); - - if (config == null || !(config.getConstructor() instanceof RelicConfigData)) - return; - - config.loadFromFile(); - - RelicConfigData relicConfig = config.get("$", RelicConfigData.class); - - LevelingConfigData levelingConfig = relicConfig.getLevelingData(); - LevelingData levelingData = relicData.getLeveling(); - - if (levelingConfig != null && levelingData != null) { - levelingData.setMaxLevel(levelingConfig.getMaxLevel()); - levelingData.setStep(levelingConfig.getStep()); - levelingData.setInitialCost(levelingConfig.getInitialCost()); - } - - AbilitiesConfigData abilitiesConfig = relicConfig.getAbilitiesData(); - - if (abilitiesConfig != null) { - for (Map.Entry abilityMapEntry : relicData.getAbilities().getAbilities().entrySet()) { - AbilityConfigData abilityConfig = abilitiesConfig.getAbilities().get(abilityMapEntry.getKey()); - - if (abilityConfig == null) - continue; - - AbilityData abilityEntry = abilityMapEntry.getValue(); - - abilityEntry.setMaxLevel(abilityConfig.getMaxLevel()); - abilityEntry.setRequiredLevel(abilityConfig.getRequiredLevel()); - abilityEntry.setRequiredPoints(abilityConfig.getRequiredPoints()); - - for (Map.Entry statMapEntry : abilityEntry.getStats().entrySet()) { - StatConfigData statConfig = abilityConfig.getStats().get(statMapEntry.getKey()); - - if (statConfig == null) - continue; - - StatData statEntry = statMapEntry.getValue(); - - statEntry.setInitialValue(Pair.of(statConfig.getMinInitialValue(), statConfig.getMaxInitialValue())); - statEntry.setThresholdValue(Pair.of(statConfig.getMinThresholdValue(), statConfig.getMaxThresholdValue())); - statEntry.setUpgradeModifier(Pair.of(statConfig.getUpgradeOperation(), statConfig.getUpgradeModifier())); - } - } - } - - relicData.getLoot().setCollection(LootCollection.builder() - .entries(relicConfig.getLootData().getEntries()) - .build()); - - relic.setRelicData(relicData); - } - - public static void constructConfigs() { - List relics = ForgeRegistries.ITEMS.getValues().stream().filter(entry -> entry instanceof IRelicItem).map(entry -> (IRelicItem) entry).toList(); - - if (relics.isEmpty()) - return; - - for (IRelicItem relic : relics) - constructRelicConfig(relic); - } - - private static void constructRelicConfig(IRelicItem relic) { - RelicData relicData = relic.getRelicData(); - - if (relicData == null) - return; - - RelicConfigData relicConfig = new RelicConfigData(relic); - - LevelingData levelingData = relicData.getLeveling(); - - if (levelingData != null) - relicConfig.setLevelingData(new LevelingConfigData(levelingData.getInitialCost(), levelingData.getMaxLevel(), levelingData.getStep())); - - AbilitiesConfigData abilitiesConfig = new AbilitiesConfigData(); - - for (Map.Entry abilityMapEntry : relicData.getAbilities().getAbilities().entrySet()) { - AbilityData abilityEntry = abilityMapEntry.getValue(); - - AbilityConfigData abilityConfig = new AbilityConfigData(abilityEntry.getRequiredPoints(), abilityEntry.getRequiredLevel(), abilityEntry.getMaxLevel()); - - for (Map.Entry statMapEntry : abilityEntry.getStats().entrySet()) { - StatData statEntry = statMapEntry.getValue(); - - StatConfigData statConfig = new StatConfigData(statEntry.getInitialValue().getKey(), statEntry.getInitialValue().getValue(), - statEntry.getThresholdValue().getKey(), statEntry.getThresholdValue().getValue(), - statEntry.getUpgradeModifier().getKey(), statEntry.getUpgradeModifier().getValue()); - - abilityConfig.getStats().put(statMapEntry.getKey(), statConfig); - } - - abilitiesConfig.getAbilities().put(abilityMapEntry.getKey(), abilityConfig); - } - - relicConfig.setAbilitiesData(abilitiesConfig); - - LootConfigData lootConfigData = new LootConfigData(); - - lootConfigData.setEntries(relicData.getLoot().getCollection().getEntries()); - - relicConfig.setLootData(lootConfigData); - - relicConfig.setup(); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/config/LootConfigData.java b/src/main/java/it/hurts/sskirillss/relics/config/LootConfigData.java new file mode 100644 index 00000000..11a97f63 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/config/LootConfigData.java @@ -0,0 +1,9 @@ +package it.hurts.sskirillss.relics.config; + +import it.hurts.octostudios.octolib.modules.config.impl.OctoConfig; +import lombok.Data; + +@Data +public class LootConfigData implements OctoConfig { + private double relicGenChance = 0.33D; +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/config/RelicsConfigData.java b/src/main/java/it/hurts/sskirillss/relics/config/RelicsConfigData.java new file mode 100644 index 00000000..471eb8e0 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/config/RelicsConfigData.java @@ -0,0 +1,15 @@ +package it.hurts.sskirillss.relics.config; + +import it.hurts.octostudios.octolib.modules.config.annotations.Prop; +import it.hurts.octostudios.octolib.modules.config.impl.OctoConfig; +import lombok.Data; + +@Data +public class RelicsConfigData implements OctoConfig { + @Prop(comment = """ + Toggles advanced configuration files, allowing customization of most of the mod's functionality. May contain WIP content that may change in the future. + + Activating this feature may lead to unintended consequences, so use it only if you know what you're doing. If any part of the mod update involves changes to the configuration file values, these changes will not be applied automatically. You will need to manually update the necessary sections or reset them to their original state. + """) + private boolean enabledExtendedConfigs = false; +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/config/data/AbilitiesConfigData.java b/src/main/java/it/hurts/sskirillss/relics/config/data/AbilitiesConfigData.java index 0802188d..f70f6719 100644 --- a/src/main/java/it/hurts/sskirillss/relics/config/data/AbilitiesConfigData.java +++ b/src/main/java/it/hurts/sskirillss/relics/config/data/AbilitiesConfigData.java @@ -1,13 +1,26 @@ package it.hurts.sskirillss.relics.config.data; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.stream.Collectors; @Data @NoArgsConstructor +@AllArgsConstructor public class AbilitiesConfigData { - private Map abilities = new HashMap<>(); + private Map abilities = new LinkedHashMap<>(); + + public AbilitiesData toData(IRelicItem relic) { + AbilitiesData data = relic.getAbilitiesData(); + + data.setAbilities(abilities.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toData(relic, e.getKey()), (o1, o2) -> o1, LinkedHashMap::new))); + + return data; + } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/config/data/AbilityConfigData.java b/src/main/java/it/hurts/sskirillss/relics/config/data/AbilityConfigData.java index 8cc6b3c1..fefe5844 100644 --- a/src/main/java/it/hurts/sskirillss/relics/config/data/AbilityConfigData.java +++ b/src/main/java/it/hurts/sskirillss/relics/config/data/AbilityConfigData.java @@ -1,21 +1,37 @@ package it.hurts.sskirillss.relics.config.data; +import it.hurts.octostudios.octolib.modules.config.annotations.Prop; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.stream.Collectors; @Data +@NoArgsConstructor +@AllArgsConstructor public class AbilityConfigData { - public AbilityConfigData(int requiredPoints, int requiredLevel, int maxLevel) { - this.requiredPoints = requiredPoints; - this.requiredLevel = requiredLevel; - this.maxLevel = maxLevel; - } - + @Prop(comment = "Number of leveling points needed to increase the ability level") private int requiredPoints; + @Prop(comment = "Relic level at which the ability becomes unlocked") private int requiredLevel; + @Prop(comment = "Highest level to which the ability can be upgraded") private int maxLevel; - private Map stats = new HashMap<>(); + private Map stats = new LinkedHashMap<>(); + + public AbilityData toData(IRelicItem relic, String ability) { + AbilityData data = relic.constructDefaultRelicData().getAbilities().getAbilities().get(ability); + + data.setRequiredPoints(requiredPoints); + data.setRequiredLevel(requiredLevel); + data.setMaxLevel(maxLevel); + data.setStats(data.getStats().entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> stats.get(entry.getKey()).toData(relic, ability, entry.getKey()), (o1, o2) -> o1, LinkedHashMap::new))); + + return data; + } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/config/data/LevelingConfigData.java b/src/main/java/it/hurts/sskirillss/relics/config/data/LevelingConfigData.java index 757b3289..4423a268 100644 --- a/src/main/java/it/hurts/sskirillss/relics/config/data/LevelingConfigData.java +++ b/src/main/java/it/hurts/sskirillss/relics/config/data/LevelingConfigData.java @@ -1,12 +1,30 @@ package it.hurts.sskirillss.relics.config.data; +import it.hurts.octostudios.octolib.modules.config.annotations.Prop; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; @Data +@NoArgsConstructor @AllArgsConstructor public class LevelingConfigData { + @Prop(comment = "Amount of experience required to level up to relic level 1") private int initialCost; + @Prop(comment = "Maximum level of the relic") private int maxLevel; + @Prop(comment = "Increment in experience required for each subsequent level of the relic") private int step; + + public LevelingData toData(IRelicItem relic) { + LevelingData data = relic.getLevelingData(); + + data.setInitialCost(initialCost); + data.setMaxLevel(maxLevel); + data.setStep(step); + + return data; + } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/config/data/LootConfigData.java b/src/main/java/it/hurts/sskirillss/relics/config/data/LootConfigData.java index 9abeb002..de0a1f2c 100644 --- a/src/main/java/it/hurts/sskirillss/relics/config/data/LootConfigData.java +++ b/src/main/java/it/hurts/sskirillss/relics/config/data/LootConfigData.java @@ -1,13 +1,27 @@ package it.hurts.sskirillss.relics.config.data; +import it.hurts.octostudios.octolib.modules.config.annotations.Prop; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootEntry; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import java.util.HashMap; -import java.util.Map; +import java.util.List; @Data @NoArgsConstructor +@AllArgsConstructor public class LootConfigData { - private Map entries = new HashMap<>(); + @Prop(comment = "List of conditions for obtaining the relic. Supports both direct ID specification and regular expressions.") + private List entries; + + public LootData toData(IRelicItem relic) { + LootData data = relic.getLootData(); + + data.setEntries(entries.stream().map(entry -> new LootEntry(entry.getDimensions(), entry.getBiomes(), entry.getTables(), entry.getWeight())).toList()); + + return data; + } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/config/data/LootEntryConfigData.java b/src/main/java/it/hurts/sskirillss/relics/config/data/LootEntryConfigData.java new file mode 100644 index 00000000..14e7d41c --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/config/data/LootEntryConfigData.java @@ -0,0 +1,18 @@ +package it.hurts.sskirillss.relics.config.data; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class LootEntryConfigData { + private List dimensions; + private List biomes; + private List tables; + + private int weight; +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/config/data/RelicConfigData.java b/src/main/java/it/hurts/sskirillss/relics/config/data/RelicConfigData.java index 78e365a3..c1f3ce0f 100644 --- a/src/main/java/it/hurts/sskirillss/relics/config/data/RelicConfigData.java +++ b/src/main/java/it/hurts/sskirillss/relics/config/data/RelicConfigData.java @@ -1,34 +1,47 @@ package it.hurts.sskirillss.relics.config.data; -import com.google.gson.annotations.Expose; -import com.google.gson.annotations.SerializedName; -import it.hurts.sskirillss.octolib.config.api.IOctoConfig; -import it.hurts.sskirillss.relics.config.ConfigHelper; +import it.hurts.octostudios.octolib.modules.config.annotations.IgnoreProp; +import it.hurts.octostudios.octolib.modules.config.impl.OctoConfig; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +import it.hurts.sskirillss.relics.level.RelicLootModifier; import lombok.Data; - -import java.nio.file.Path; +import lombok.NoArgsConstructor; @Data -public class RelicConfigData implements IOctoConfig { - @Expose - private final transient IRelicItem relic; +@NoArgsConstructor +public class RelicConfigData implements OctoConfig { + @IgnoreProp + private IRelicItem relic; public RelicConfigData(IRelicItem relic) { this.relic = relic; + + this.setAbilitiesData(relic.getAbilitiesData().toConfigData()); + this.setLevelingData(relic.getLevelingData().toConfigData()); + this.setLootData(relic.getLootData().toConfigData()); } - @Override - public Path getPath() { - return ConfigHelper.getPath(relic); + public RelicData toData(IRelicItem relic) { + RelicData data = relic.getRelicData(); + + data.setAbilities(abilitiesData.toData(relic)); + data.setLeveling(levelingData.toData(relic)); + data.setLoot(lootData.toData(relic)); + + return data; } - @SerializedName("ability") private AbilitiesConfigData abilitiesData; - @SerializedName("leveling") private LevelingConfigData levelingData; - @SerializedName("loot") private LootConfigData lootData; + + @Override + public void onLoadObject(Object object) { + relic.setRelicData(((RelicConfigData) object).toData(relic)); + + RelicLootModifier.processRelicCache(relic); + } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/config/data/StatConfigData.java b/src/main/java/it/hurts/sskirillss/relics/config/data/StatConfigData.java index baaef19b..c2fd02bd 100644 --- a/src/main/java/it/hurts/sskirillss/relics/config/data/StatConfigData.java +++ b/src/main/java/it/hurts/sskirillss/relics/config/data/StatConfigData.java @@ -1,18 +1,47 @@ package it.hurts.sskirillss.relics.config.data; +import it.hurts.octostudios.octolib.modules.config.annotations.Prop; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.tuple.Pair; @Data +@NoArgsConstructor @AllArgsConstructor public class StatConfigData { + @Prop(comment = "Minimum base value of the stat. A random value within this range is assigned when the relic is first created") private double minInitialValue; + @Prop(comment = "Maximum base value of the stat. A random value within this range is assigned when the relic is first created") private double maxInitialValue; + @Prop(comment = "Minimum threshold value for the stat, representing hard limits that cannot be surpassed through ability level upgrades or other methods") private double minThresholdValue; + @Prop(comment = "Maximum threshold value for the stat, representing hard limits that cannot be surpassed through ability level upgrades or other methods") private double maxThresholdValue; + @Prop(comment = """ + Type of mathematical operation used to calculate the stat's value based on the ability level. Supported operations include: + MULTIPLY_BASE: x + ((x * y) * z), + MULTIPLY_TOTAL: x * (y + 1)^z, + ADD: x + (y * z). + + ...where x - Base stat value, y - Value of [upgradeModifier], z - Current relic level + """) private UpgradeOperation upgradeOperation; + @Prop(comment = "Modifier applied to the base value of the stat, depending on the [upgradeOperation] parameter.") private double upgradeModifier; + + public StatData toData(IRelicItem relic, String ability, String stat) { + StatData data = relic.constructDefaultRelicData().getAbilities().getAbilities().get(ability).getStats().get(stat); + + data.setInitialValue(Pair.of(minInitialValue, maxInitialValue)); + data.setThresholdValue(Pair.of(minThresholdValue, maxThresholdValue)); + data.setUpgradeModifier(Pair.of(upgradeOperation, upgradeModifier)); + + return data; + } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/config/handlers/ConfigHandler.java b/src/main/java/it/hurts/sskirillss/relics/config/handlers/ConfigHandler.java deleted file mode 100644 index 5c89a145..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/config/handlers/ConfigHandler.java +++ /dev/null @@ -1,21 +0,0 @@ -package it.hurts.sskirillss.relics.config.handlers; - -import it.hurts.sskirillss.octolib.config.api.IOctoConfig; -import it.hurts.sskirillss.octolib.config.api.events.ConfigConstructEvent; -import it.hurts.sskirillss.relics.config.data.RelicConfigData; -import it.hurts.sskirillss.relics.utils.Reference; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; - -@Mod.EventBusSubscriber(modid = Reference.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) -public class ConfigHandler { - @SubscribeEvent - public static void onConfigConstruct(ConfigConstructEvent event) { - IOctoConfig constructor = event.getConstructor(); - - if (!(constructor instanceof RelicConfigData config)) - return; - - config.getRelic().appendConfig(event.getSchema()); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/effects/AntiHealEffect.java b/src/main/java/it/hurts/sskirillss/relics/effects/AntiHealEffect.java index 5c55e611..78b430f0 100644 --- a/src/main/java/it/hurts/sskirillss/relics/effects/AntiHealEffect.java +++ b/src/main/java/it/hurts/sskirillss/relics/effects/AntiHealEffect.java @@ -5,22 +5,22 @@ import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectCategory; import net.minecraft.world.entity.LivingEntity; -import net.minecraftforge.event.entity.living.LivingHealEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.living.LivingHealEvent; public class AntiHealEffect extends MobEffect { public AntiHealEffect() { super(MobEffectCategory.HARMFUL, 0X6836AA); } - @Mod.EventBusSubscriber(modid = Reference.MODID) + @EventBusSubscriber(modid = Reference.MODID) public static class Events { @SubscribeEvent public static void onLivingHeal(LivingHealEvent event) { LivingEntity entity = event.getEntity(); - if (entity.hasEffect(EffectRegistry.ANTI_HEAL.get())) + if (entity.hasEffect(EffectRegistry.ANTI_HEAL)) event.setCanceled(true); } } diff --git a/src/main/java/it/hurts/sskirillss/relics/effects/BleedingEffect.java b/src/main/java/it/hurts/sskirillss/relics/effects/BleedingEffect.java index d2980fc4..9420b6d1 100644 --- a/src/main/java/it/hurts/sskirillss/relics/effects/BleedingEffect.java +++ b/src/main/java/it/hurts/sskirillss/relics/effects/BleedingEffect.java @@ -4,22 +4,20 @@ import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectCategory; import net.minecraft.world.entity.LivingEntity; -import net.minecraftforge.event.entity.living.LivingEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.tick.EntityTickEvent; public class BleedingEffect extends MobEffect { public BleedingEffect() { super(MobEffectCategory.HARMFUL, 0X6836AA); } - @Mod.EventBusSubscriber + @EventBusSubscriber public static class Events { @SubscribeEvent - public static void onLivingUpdate(LivingEvent.LivingTickEvent event) { - LivingEntity entity = event.getEntity(); - - if (entity.tickCount % 20 == 0 && entity.hasEffect(EffectRegistry.BLEEDING.get())) + public static void onLivingUpdate(EntityTickEvent.Post event) { + if (event.getEntity() instanceof LivingEntity entity && entity.tickCount % 20 == 0 && entity.hasEffect(EffectRegistry.BLEEDING)) entity.hurt(entity.level().damageSources().magic(), Math.min(10, entity.getHealth() * 0.05F)); } } diff --git a/src/main/java/it/hurts/sskirillss/relics/effects/ConfusionEffect.java b/src/main/java/it/hurts/sskirillss/relics/effects/ConfusionEffect.java index e58c548c..1a3124d5 100644 --- a/src/main/java/it/hurts/sskirillss/relics/effects/ConfusionEffect.java +++ b/src/main/java/it/hurts/sskirillss/relics/effects/ConfusionEffect.java @@ -6,23 +6,23 @@ import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectCategory; import net.minecraft.world.entity.player.Player; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.MovementInputUpdateEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.MovementInputUpdateEvent; public class ConfusionEffect extends MobEffect { public ConfusionEffect() { super(MobEffectCategory.HARMFUL, 0X6836AA); } - @Mod.EventBusSubscriber(modid = Reference.MODID, value = Dist.CLIENT) + @EventBusSubscriber(modid = Reference.MODID, value = Dist.CLIENT) public static class ClientEvents { @SubscribeEvent - public static void onChatMessage(MovementInputUpdateEvent event) { + public static void onMovementInput(MovementInputUpdateEvent event) { Player player = event.getEntity(); - if (player.hasEffect(EffectRegistry.CONFUSION.get())) { + if (player.hasEffect(EffectRegistry.CONFUSION)) { Input input = event.getInput(); input.leftImpulse *= -1; diff --git a/src/main/java/it/hurts/sskirillss/relics/effects/ImmortalityEffect.java b/src/main/java/it/hurts/sskirillss/relics/effects/ImmortalityEffect.java new file mode 100644 index 00000000..e6635f9f --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/effects/ImmortalityEffect.java @@ -0,0 +1,23 @@ +package it.hurts.sskirillss.relics.effects; + +import it.hurts.sskirillss.relics.init.EffectRegistry; +import net.minecraft.world.effect.MobEffect; +import net.minecraft.world.effect.MobEffectCategory; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; + +public class ImmortalityEffect extends MobEffect { + public ImmortalityEffect() { + super(MobEffectCategory.BENEFICIAL, 0X6836AA); + } + + @EventBusSubscriber + public static class Events { + @SubscribeEvent + public static void onLivingIncomingDamage(LivingIncomingDamageEvent event) { + if (event.getEntity().hasEffect(EffectRegistry.IMMORTALITY)) + event.setCanceled(true); + } + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/effects/ParalysisEffect.java b/src/main/java/it/hurts/sskirillss/relics/effects/ParalysisEffect.java index 61f284d2..d4253ec9 100644 --- a/src/main/java/it/hurts/sskirillss/relics/effects/ParalysisEffect.java +++ b/src/main/java/it/hurts/sskirillss/relics/effects/ParalysisEffect.java @@ -6,23 +6,23 @@ import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectCategory; import net.minecraft.world.entity.player.Player; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.MovementInputUpdateEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.MovementInputUpdateEvent; public class ParalysisEffect extends MobEffect { public ParalysisEffect() { super(MobEffectCategory.HARMFUL, 0X6836AA); } - @Mod.EventBusSubscriber(modid = Reference.MODID, value = Dist.CLIENT) + @EventBusSubscriber(modid = Reference.MODID, value = Dist.CLIENT) public static class ClientEvents { @SubscribeEvent public static void onMovementInput(MovementInputUpdateEvent event) { Player player = event.getEntity(); - if (player.hasEffect(EffectRegistry.PARALYSIS.get())) { + if (player.hasEffect(EffectRegistry.PARALYSIS)) { Input input = event.getInput(); input.shiftKeyDown = false; diff --git a/src/main/java/it/hurts/sskirillss/relics/effects/StunEffect.java b/src/main/java/it/hurts/sskirillss/relics/effects/StunEffect.java index 240fe4eb..af620475 100644 --- a/src/main/java/it/hurts/sskirillss/relics/effects/StunEffect.java +++ b/src/main/java/it/hurts/sskirillss/relics/effects/StunEffect.java @@ -13,25 +13,25 @@ import net.minecraft.world.effect.MobEffectCategory; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.InputEvent; -import net.minecraftforge.client.event.RenderHighlightEvent; -import net.minecraftforge.client.event.RenderLivingEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.InputEvent; +import net.neoforged.neoforge.client.event.RenderHighlightEvent; +import net.neoforged.neoforge.client.event.RenderLivingEvent; public class StunEffect extends MobEffect { public StunEffect() { super(MobEffectCategory.HARMFUL, 0X6836AA); } - @Mod.EventBusSubscriber(modid = Reference.MODID, value = Dist.CLIENT) + @EventBusSubscriber(modid = Reference.MODID, value = Dist.CLIENT) public static class ClientEvents { @SubscribeEvent public static void onMouseInput(InputEvent.InteractionKeyMappingTriggered event) { Player player = Minecraft.getInstance().player; - if (player != null && player.hasEffect(EffectRegistry.STUN.get())) { + if (player != null && player.hasEffect(EffectRegistry.STUN)) { event.setSwingHand(false); event.setCanceled(true); @@ -39,10 +39,10 @@ public static void onMouseInput(InputEvent.InteractionKeyMappingTriggered event) } @SubscribeEvent - public void onBlockHighlight(RenderHighlightEvent.Block event) { + public static void onBlockHighlight(RenderHighlightEvent.Block event) { Player player = Minecraft.getInstance().player; - if (player != null && player.hasEffect(EffectRegistry.STUN.get())) + if (player != null && player.hasEffect(EffectRegistry.STUN)) event.setCanceled(true); } @@ -50,7 +50,7 @@ public void onBlockHighlight(RenderHighlightEvent.Block event) { public static void onEntityRender(RenderLivingEvent.Pre event) { LivingEntity entity = event.getEntity(); - if (!entity.hasEffect(EffectRegistry.STUN.get()) || entity.isDeadOrDying()) + if (!entity.hasEffect(EffectRegistry.STUN) || entity.isDeadOrDying()) return; PoseStack poseStack = event.getPoseStack(); diff --git a/src/main/java/it/hurts/sskirillss/relics/effects/VanishingEffect.java b/src/main/java/it/hurts/sskirillss/relics/effects/VanishingEffect.java index c8b9426e..45ae296f 100644 --- a/src/main/java/it/hurts/sskirillss/relics/effects/VanishingEffect.java +++ b/src/main/java/it/hurts/sskirillss/relics/effects/VanishingEffect.java @@ -2,23 +2,31 @@ import it.hurts.sskirillss.relics.init.EffectRegistry; import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.client.Minecraft; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectCategory; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.RenderLivingEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RenderHandEvent; +import net.neoforged.neoforge.client.event.RenderLivingEvent; public class VanishingEffect extends MobEffect { public VanishingEffect() { super(MobEffectCategory.BENEFICIAL, 0X6836AA); } - @Mod.EventBusSubscriber(modid = Reference.MODID, value = Dist.CLIENT) + @EventBusSubscriber(modid = Reference.MODID, value = Dist.CLIENT) public static class ClientEvents { @SubscribeEvent public static void onEntityRender(RenderLivingEvent.Pre event) { - if (event.getEntity().hasEffect(EffectRegistry.VANISHING.get())) + if (event.getEntity().hasEffect(EffectRegistry.VANISHING)) + event.setCanceled(true); + } + + @SubscribeEvent + public static void onHandRender(RenderHandEvent event) { + if (Minecraft.getInstance().player.hasEffect(EffectRegistry.VANISHING) && event.getItemStack().isEmpty()) event.setCanceled(true); } } diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/ArrowRainEntity.java b/src/main/java/it/hurts/sskirillss/relics/entities/ArrowRainEntity.java index cc171351..76150066 100644 --- a/src/main/java/it/hurts/sskirillss/relics/entities/ArrowRainEntity.java +++ b/src/main/java/it/hurts/sskirillss/relics/entities/ArrowRainEntity.java @@ -1,205 +1,200 @@ -package it.hurts.sskirillss.relics.entities; - -import it.hurts.sskirillss.relics.init.SoundRegistry; -import it.hurts.sskirillss.relics.items.relics.back.ArrowQuiverItem; -import it.hurts.sskirillss.relics.utils.EntityUtils; -import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.ParticleUtils; -import lombok.Getter; -import lombok.Setter; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; -import net.minecraft.network.syncher.EntityDataAccessor; -import net.minecraft.network.syncher.EntityDataSerializers; -import net.minecraft.network.syncher.SynchedEntityData; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.RandomSource; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.entity.projectile.AbstractArrow; -import net.minecraft.world.entity.projectile.ThrowableProjectile; -import net.minecraft.world.item.ArrowItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.EntityHitResult; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.event.entity.ProjectileImpactEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.network.NetworkHooks; - -import javax.annotation.Nonnull; -import java.awt.*; -import java.util.Comparator; -import java.util.List; - -public class ArrowRainEntity extends ThrowableProjectile { - private static final EntityDataAccessor RADIUS = SynchedEntityData.defineId(ArrowRainEntity.class, EntityDataSerializers.FLOAT); - - @Getter - @Setter - private int delay; - - @Getter - @Setter - private int duration; - - @Getter - @Setter - private ItemStack quiver; - - public float getRadius() { - return this.getEntityData().get(RADIUS); - } - - public void setRadius(float radius) { - this.getEntityData().set(RADIUS, radius); - } - - public ArrowRainEntity(EntityType entityType, Level level) { - super(entityType, level); - } - - @Override - public void tick() { - super.tick(); - - RandomSource random = level().getRandom(); - - ParticleUtils.createCyl(ParticleUtils.constructSimpleSpark(new Color(255, 255, 255), 0.2F, 1, 1F), - this.position(), level(), getRadius(), 0.2F); - - if (!level().isClientSide()) { - if (getDelay() == 0 || getRadius() == 0 || quiver.isEmpty() || getDuration() < this.tickCount) { - this.discard(); - - return; - } - } - - AABB area = this.getBoundingBox().inflate(getRadius(), getRadius() * 2, getRadius()); - - for (AbstractArrow arrow : level().getEntitiesOfClass(AbstractArrow.class, area)) { - if (arrow.onGround()) - continue; - - List entities = level().getEntitiesOfClass(LivingEntity.class, area).stream() - .filter(entry -> entry.hasLineOfSight(arrow)) - .filter(entry -> entry.position().distanceTo(this.position()) <= getRadius()) - .filter(entry -> !EntityUtils.isAlliedTo(this.getOwner(), entry)) - .sorted(Comparator.comparing(entry -> entry.position().distanceTo(arrow.position()))) - .toList(); - - if (entities.isEmpty()) - continue; - - LivingEntity target = entities.get(0); - - Vec3 motion = target.position().subtract(arrow.position()).normalize().scale(0.1F); - - arrow.setDeltaMovement(arrow.getDeltaMovement().add(motion.x(), 0, motion.z())); - } - - if (!(getOwner() instanceof Player player)) - return; - - if (this.tickCount % getDelay() == 0) { - List arrows = ArrowQuiverItem.getArrows(quiver); - - if (arrows.isEmpty()) { - this.discard(); - - return; - } - - for (int i = 0; i < Math.ceil(getRadius() / 5F); i++) { - ItemStack arrow = arrows.get(random.nextInt(arrows.size())); - - if (arrow.getItem() instanceof ArrowItem item) { - AbstractArrow entity = item.createArrow(level(), arrow, player); - - double theta = MathUtils.randomFloat(random) * 2 * Math.PI; - double r = random.nextFloat() * getRadius(); - - double xOff = r * Math.cos(theta); - double zOff = r * Math.sin(theta); - - entity.setPos(this.getX() + xOff, this.getY() + 15 + getRadius(), this.getZ() + zOff); - entity.getPersistentData().putBoolean("relics_arrow_rain", true); - entity.setDeltaMovement(0, -0.5F, 0); - entity.setOwner(player); - entity.life = 1100; - - entity.pickup = AbstractArrow.Pickup.CREATIVE_ONLY; - - level().addFreshEntity(entity); - - if (!level().isClientSide()) - ((ServerLevel) level()).sendParticles(ParticleTypes.CLOUD, entity.getX(), entity.getY(), entity.getZ(), 5, 0, 0, 0, 0.1F); - - level().playSound(null, entity.blockPosition(), SoundRegistry.ARROW_RAIN.get(), SoundSource.MASTER, 2F, 1F + random.nextFloat() * 0.25F); - } - } - } - } - - @Override - protected void defineSynchedData() { - this.entityData.define(RADIUS, 5F); - } - - @Override - protected void readAdditionalSaveData(CompoundTag compound) { - setRadius(compound.getFloat("radius")); - setDelay(compound.getInt("delay")); - setDuration(compound.getInt("duration")); - - quiver = ItemStack.of(compound.getCompound("quiver")); - } - - @Override - protected void addAdditionalSaveData(CompoundTag compound) { - compound.putFloat("radius", getRadius()); - compound.putFloat("delay", getDelay()); - compound.putFloat("duration", getDuration()); - - quiver.save(compound.getCompound("quiver")); - } - - @Override - protected float getGravity() { - return 0F; - } - - @Override - public boolean isPushedByFluid() { - return false; - } - - @Nonnull - @Override - public Packet getAddEntityPacket() { - return NetworkHooks.getEntitySpawningPacket(this); - } - - @Mod.EventBusSubscriber - public static class Events { - @SubscribeEvent - public static void onProjectileImpact(ProjectileImpactEvent event) { - if (!(event.getEntity() instanceof AbstractArrow arrow) - || !arrow.getPersistentData().getBoolean("relics_arrow_rain") - || !(arrow.getOwner() instanceof Player player) - || !(event.getRayTraceResult() instanceof EntityHitResult result) - || !(result.getEntity() instanceof LivingEntity entity) - || !EntityUtils.isAlliedTo(player, entity)) - return; - - event.setCanceled(true); - } - } -} \ No newline at end of file +//package it.hurts.sskirillss.relics.entities; +// +//import it.hurts.sskirillss.relics.init.SoundRegistry; +//import it.hurts.sskirillss.relics.utils.EntityUtils; +//import it.hurts.sskirillss.relics.utils.MathUtils; +//import it.hurts.sskirillss.relics.utils.ParticleUtils; +//import lombok.Getter; +//import lombok.Setter; +//import net.minecraft.core.particles.ParticleTypes; +//import net.minecraft.nbt.CompoundTag; +//import net.minecraft.network.syncher.EntityDataAccessor; +//import net.minecraft.network.syncher.EntityDataSerializers; +//import net.minecraft.network.syncher.SynchedEntityData; +//import net.minecraft.server.level.ServerLevel; +//import net.minecraft.sounds.SoundSource; +//import net.minecraft.util.RandomSource; +//import net.minecraft.world.entity.EntityType; +//import net.minecraft.world.entity.LivingEntity; +//import net.minecraft.world.entity.player.Player; +//import net.minecraft.world.entity.projectile.AbstractArrow; +//import net.minecraft.world.entity.projectile.ThrowableProjectile; +//import net.minecraft.world.item.ArrowItem; +//import net.minecraft.world.item.ItemStack; +//import net.minecraft.world.level.Level; +//import net.minecraft.world.phys.AABB; +//import net.minecraft.world.phys.EntityHitResult; +//import net.minecraft.world.phys.Vec3; +//import net.neoforged.bus.api.SubscribeEvent; +//import net.neoforged.fml.common.EventBusSubscriber; +//import net.neoforged.neoforge.event.entity.ProjectileImpactEvent; +// +//import java.awt.*; +//import java.util.Comparator; +//import java.util.List; +// +//public class ArrowRainEntity extends ThrowableProjectile { +// private static final EntityDataAccessor RADIUS = SynchedEntityData.defineId(ArrowRainEntity.class, EntityDataSerializers.FLOAT); +// +// @Getter +// @Setter +// private int delay; +// +// @Getter +// @Setter +// private int duration; +// +// @Getter +// @Setter +// private ItemStack quiver; +// +// public float getRadius() { +// return this.getEntityData().get(RADIUS); +// } +// +// public void setRadius(float radius) { +// this.getEntityData().set(RADIUS, radius); +// } +// +// public ArrowRainEntity(EntityType entityType, Level level) { +// super(entityType, level); +// } +// +// @Override +// public void tick() { +// super.tick(); +// +// RandomSource random = level().getRandom(); +// +// ParticleUtils.createCyl(ParticleUtils.constructSimpleSpark(new Color(255, 255, 255), 0.2F, 1, 1F), +// this.position(), level(), getRadius(), 0.2F); +// +// if (!level().isClientSide()) { +// if (getDelay() == 0 || getRadius() == 0 || quiver.isEmpty() || getDuration() < this.tickCount) { +// this.discard(); +// +// return; +// } +// } +// +// AABB area = this.getBoundingBox().inflate(getRadius(), getRadius() * 2, getRadius()); +// +// for (AbstractArrow arrow : level().getEntitiesOfClass(AbstractArrow.class, area)) { +// if (arrow.onGround()) +// continue; +// +// List entities = level().getEntitiesOfClass(LivingEntity.class, area).stream() +// .filter(entry -> entry.hasLineOfSight(arrow)) +// .filter(entry -> entry.position().distanceTo(this.position()) <= getRadius()) +// .filter(entry -> !EntityUtils.isAlliedTo(this.getOwner(), entry)) +// .sorted(Comparator.comparing(entry -> entry.position().distanceTo(arrow.position()))) +// .toList(); +// +// if (entities.isEmpty()) +// continue; +// +// LivingEntity target = entities.get(0); +// +// Vec3 motion = target.position().subtract(arrow.position()).normalize().scale(0.1F); +// +// arrow.setDeltaMovement(arrow.getDeltaMovement().add(motion.x(), 0, motion.z())); +// } +// +// if (!(getOwner() instanceof Player player)) +// return; +// +// if (this.tickCount % getDelay() == 0) { +// List arrows = ArrowQuiverItem.getArrows(player.registryAccess(), quiver); +// +// if (arrows.isEmpty()) { +// this.discard(); +// +// return; +// } +// +// for (int i = 0; i < Math.ceil(getRadius() / 5F); i++) { +// ItemStack arrow = arrows.get(random.nextInt(arrows.size())); +// +// if (arrow.getItem() instanceof ArrowItem item) { +// AbstractArrow entity = item.createArrow(level(), arrow, player, null); +// +// double theta = MathUtils.randomFloat(random) * 2 * Math.PI; +// double r = random.nextFloat() * getRadius(); +// +// double xOff = r * Math.cos(theta); +// double zOff = r * Math.sin(theta); +// +// entity.setPos(this.getX() + xOff, this.getY() + 15 + getRadius(), this.getZ() + zOff); +// entity.getPersistentData().putBoolean("relics_arrow_rain", true); +// entity.setDeltaMovement(0, -0.5F, 0); +// entity.setOwner(player); +// entity.life = 1100; +// +// entity.pickup = AbstractArrow.Pickup.CREATIVE_ONLY; +// +// level().addFreshEntity(entity); +// +// if (!level().isClientSide()) +// ((ServerLevel) level()).sendParticles(ParticleTypes.CLOUD, entity.getX(), entity.getY(), entity.getZ(), 5, 0, 0, 0, 0.1F); +// +// level().playSound(null, entity.blockPosition(), SoundRegistry.ARROW_RAIN.get(), SoundSource.MASTER, 2F, 1F + random.nextFloat() * 0.25F); +// } +// } +// } +// } +// +// @Override +// protected void defineSynchedData(SynchedEntityData.Builder builder) { +// builder.define(RADIUS, 5F); +// } +// +// @Override +// protected void readAdditionalSaveData(CompoundTag compound) { +// setRadius(compound.getFloat("radius")); +// setDelay(compound.getInt("delay")); +// setDuration(compound.getInt("duration")); +// +// quiver = ItemStack.parseOptional(this.registryAccess(), compound.getCompound("quiver")); +// } +// +// @Override +// protected void addAdditionalSaveData(CompoundTag compound) { +// compound.putFloat("radius", getRadius()); +// compound.putFloat("delay", getDelay()); +// compound.putFloat("duration", getDuration()); +// +// quiver.save(this.registryAccess(), compound.getCompound("quiver")); +// } +// +//// @Override +//// public float getGravity() { +//// return 0F; +//// } +// +// @Override +// public boolean isPushedByFluid() { +// return false; +// } +// +//// @Nonnull +//// @Override +//// public Packet getAddEntityPacket() { +//// return NetworkHooks.getEntitySpawningPacket(this); +//// } +// +// @EventBusSubscriber +// public static class Events { +// @SubscribeEvent +// public static void onProjectileImpact(ProjectileImpactEvent event) { +// if (!(event.getEntity() instanceof AbstractArrow arrow) +// || !arrow.getPersistentData().getBoolean("relics_arrow_rain") +// || !(arrow.getOwner() instanceof Player player) +// || !(event.getRayTraceResult() instanceof EntityHitResult result) +// || !(result.getEntity() instanceof LivingEntity entity) +// || !EntityUtils.isAlliedTo(player, entity)) +// return; +// +// event.setCanceled(true); +// } +// } +//} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/BlockSimulationEntity.java b/src/main/java/it/hurts/sskirillss/relics/entities/BlockSimulationEntity.java index b5831a56..7329371e 100644 --- a/src/main/java/it/hurts/sskirillss/relics/entities/BlockSimulationEntity.java +++ b/src/main/java/it/hurts/sskirillss/relics/entities/BlockSimulationEntity.java @@ -9,13 +9,13 @@ import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.level.ServerEntity; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.MoverType; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.network.NetworkHooks; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -57,8 +57,8 @@ public BlockState getBlockState() { } @Override - protected void defineSynchedData() { - this.entityData.define(BLOCK_STATE, Blocks.AIR.defaultBlockState()); + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(BLOCK_STATE, Blocks.AIR.defaultBlockState()); } @Override @@ -79,9 +79,9 @@ public boolean isPushedByFluid() { return false; } - @Nonnull - @Override - public Packet getAddEntityPacket() { - return NetworkHooks.getEntitySpawningPacket(this); - } +// @Nonnull +// @Override +// public Packet getAddEntityPacket(ServerEntity entity) { +// return NetworkHooks.getEntitySpawningPacket(this); +// } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/ChairEntity.java b/src/main/java/it/hurts/sskirillss/relics/entities/ChairEntity.java new file mode 100644 index 00000000..94b77f09 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/entities/ChairEntity.java @@ -0,0 +1,42 @@ +package it.hurts.sskirillss.relics.entities; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +public class ChairEntity extends Entity { + public ChairEntity(EntityType pEntityType, Level level) { + super(pEntityType, level); + + this.noPhysics = true; + } + + @Override + public void tick() { + if (this.getPassengers().isEmpty()) + this.discard(); + } + + @Override + public Vec3 getPassengerRidingPosition(Entity pEntity) { + return super.getPassengerRidingPosition(pEntity).add(0F, -0.5F, 0F); + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder pBuilder) { + + } + + @Override + protected void readAdditionalSaveData(CompoundTag pCompound) { + + } + + @Override + protected void addAdditionalSaveData(CompoundTag pCompound) { + + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/DeathEssenceEntity.java b/src/main/java/it/hurts/sskirillss/relics/entities/DeathEssenceEntity.java new file mode 100644 index 00000000..5d583ef4 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/entities/DeathEssenceEntity.java @@ -0,0 +1,160 @@ +package it.hurts.sskirillss.relics.entities; + +import it.hurts.octostudios.octolib.modules.particles.OctoRenderManager; +import it.hurts.octostudios.octolib.modules.particles.trail.TrailProvider; +import it.hurts.sskirillss.relics.entities.misc.ITargetableEntity; +import it.hurts.sskirillss.relics.network.NetworkHandler; +import it.hurts.sskirillss.relics.network.packets.sync.S2CEntityTargetPacket; +import it.hurts.sskirillss.relics.utils.EntityUtils; +import it.hurts.sskirillss.relics.utils.ParticleUtils; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.projectile.ThrowableProjectile; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; + +import java.awt.*; + +public class DeathEssenceEntity extends ThrowableProjectile implements ITargetableEntity, TrailProvider { + private static final EntityDataAccessor DAMAGE = SynchedEntityData.defineId(DeathEssenceEntity.class, EntityDataSerializers.FLOAT); + + public void setDamage(float heal) { + this.getEntityData().set(DAMAGE, heal); + } + + public float getDamage() { + return this.getEntityData().get(DAMAGE); + } + + private LivingEntity target; + + public DeathEssenceEntity(EntityType type, Level worldIn) { + super(type, worldIn); + } + + @Override + public void tick() { + super.tick(); + + var level = this.getCommandSenderWorld(); + + level.addParticle((ParticleUtils.constructSimpleSpark(new Color(random.nextInt(150), 150 + random.nextInt(50), 200 + random.nextInt(50)), 0.05F, 10, 0.9F)), this.xOld, this.yOld, this.zOld, + -this.getDeltaMovement().x * 0.1F * random.nextFloat(), -this.getDeltaMovement().y * 0.1F * random.nextFloat(), -this.getDeltaMovement().z * 0.1F * random.nextFloat()); + + if (target == null || target.isDeadOrDying()) { + if (!level.isClientSide()) + this.discard(); + + return; + } + + if (this.position().distanceTo(target.getEyePosition()) > 1F) { + var direction = target.getEyePosition().subtract(this.position()).normalize(); + var motion = this.getDeltaMovement(); + + var window = 5; + + if (tickCount > window) { + var factor = Math.clamp((tickCount - window) * 0.1F, 0F, 1F); + + this.setDeltaMovement(motion.x + (direction.x * factor - motion.x) * factor, motion.y + (direction.y * factor - motion.y) * factor, motion.z + (direction.z * factor - motion.z) * factor); + } + } else { + target.invulnerableTime = 0; + + EntityUtils.hurt(target, level.damageSources().thrown(this, this.getOwner()), getDamage()); + + this.discard(); + } + } + + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(DAMAGE, 0F); + } + + @Override + public void addAdditionalSaveData(CompoundTag tag) { + super.addAdditionalSaveData(tag); + + tag.putFloat("damage", getDamage()); + } + + @Override + public void readAdditionalSaveData(CompoundTag tag) { + super.readAdditionalSaveData(tag); + + setDamage(tag.getFloat("damage")); + } + + @Override + public boolean isNoGravity() { + return false; + } + + @Override + public void onAddedToLevel() { + super.onAddedToLevel(); + + OctoRenderManager.registerProvider(this); + } + + @Nullable + @Override + public LivingEntity getTarget() { + return target; + } + + @Override + public void setTarget(LivingEntity target) { + this.target = target; + + if (!level().isClientSide() && target != null) + NetworkHandler.sendToClientsTrackingEntity(new S2CEntityTargetPacket(this.getId(), target.getId()), this); + } + + @Override + public Vec3 getTrailPosition(float partialTicks) { + return getPosition(partialTicks).add(getDeltaMovement().scale(-1)); + } + + @Override + public int getTrailUpdateFrequency() { + return 1; + } + + @Override + public boolean isTrailAlive() { + return isAlive(); + } + + @Override + public boolean isTrailGrowing() { + return tickCount > 2; + } + + @Override + public int getTrailMaxLength() { + return 5; + } + + @Override + public int getTrailFadeInColor() { + return 0xFF00FFFF; + } + + @Override + public int getTrailFadeOutColor() { + return 0x80FF00FF; + } + + @Override + public double getTrailScale() { + return 0.025F; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/DissectionEntity.java b/src/main/java/it/hurts/sskirillss/relics/entities/DissectionEntity.java index 0b2e1c46..aa34d152 100644 --- a/src/main/java/it/hurts/sskirillss/relics/entities/DissectionEntity.java +++ b/src/main/java/it/hurts/sskirillss/relics/entities/DissectionEntity.java @@ -11,8 +11,6 @@ import net.minecraft.commands.arguments.EntityAnchorArgument; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; @@ -26,9 +24,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.network.NetworkHooks; -import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.awt.*; import java.util.ArrayList; @@ -207,7 +203,7 @@ public void tick() { target.fallDistance = 0F; - ((LivingEntity) target).addEffect(new MobEffectInstance(EffectRegistry.VANISHING.get(), 5, 0, false, false)); + ((LivingEntity) target).addEffect(new MobEffectInstance(EffectRegistry.VANISHING, 5, 0, false, false)); serverLevel.sendParticles(ParticleUtils.constructSimpleSpark(new Color(150 + random.nextInt(100), 100, 0), 0.2F, 20, 0.9F), target.getX(), target.getY() + 1.25F, target.getZ(), Math.round(target.getBbHeight() * 3), 0.1F, 0.1F, 0.1F, 0.05F); @@ -242,8 +238,8 @@ public void tick() { } @Override - public void onRemovedFromWorld() { - super.onRemovedFromWorld(); + public void onRemovedFromLevel() { + super.onRemovedFromLevel(); if (this.isMaster()) return; @@ -257,8 +253,8 @@ public void onRemovedFromWorld() { } @Override - protected void defineSynchedData() { - entityData.define(LIFE_TIME, 100); + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(LIFE_TIME, 100); } @Override @@ -280,9 +276,9 @@ public boolean isPushedByFluid() { return false; } - @Nonnull - @Override - public Packet getAddEntityPacket() { - return NetworkHooks.getEntitySpawningPacket(this); - } +// @Nonnull +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/LifeEssenceEntity.java b/src/main/java/it/hurts/sskirillss/relics/entities/LifeEssenceEntity.java index 61e81775..6a5675bb 100644 --- a/src/main/java/it/hurts/sskirillss/relics/entities/LifeEssenceEntity.java +++ b/src/main/java/it/hurts/sskirillss/relics/entities/LifeEssenceEntity.java @@ -1,95 +1,157 @@ package it.hurts.sskirillss.relics.entities; -import it.hurts.sskirillss.relics.init.EntityRegistry; -import it.hurts.sskirillss.relics.utils.EntityUtils; +import it.hurts.octostudios.octolib.modules.particles.OctoRenderManager; +import it.hurts.octostudios.octolib.modules.particles.trail.TrailProvider; +import it.hurts.sskirillss.relics.entities.misc.ITargetableEntity; +import it.hurts.sskirillss.relics.network.NetworkHandler; +import it.hurts.sskirillss.relics.network.packets.sync.S2CEntityTargetPacket; import it.hurts.sskirillss.relics.utils.ParticleUtils; -import lombok.Getter; -import lombok.Setter; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.RandomSource; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.ThrowableProjectile; import net.minecraft.world.level.Level; -import net.minecraftforge.network.NetworkHooks; -import org.jetbrains.annotations.NotNull; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; import java.awt.*; -public class LifeEssenceEntity extends ThrowableProjectile { - @Setter - @Getter - private float heal; +public class LifeEssenceEntity extends ThrowableProjectile implements ITargetableEntity, TrailProvider { + private static final EntityDataAccessor HEAL = SynchedEntityData.defineId(LifeEssenceEntity.class, EntityDataSerializers.FLOAT); - public LifeEssenceEntity(EntityType type, Level worldIn) { - super(type, worldIn); + public void setHeal(float heal) { + this.getEntityData().set(HEAL, heal); } - public LifeEssenceEntity(LivingEntity throwerIn, float heal) { - super(EntityRegistry.LIFE_ESSENCE.get(), throwerIn.getCommandSenderWorld()); + public float getHeal() { + return this.getEntityData().get(HEAL); + } - this.setOwner(throwerIn); + private LivingEntity target; - this.heal = heal; + public LifeEssenceEntity(EntityType type, Level worldIn) { + super(type, worldIn); } @Override public void tick() { super.tick(); - if (level().isClientSide()) + var level = this.getCommandSenderWorld(); + + level.addParticle((ParticleUtils.constructSimpleSpark(new Color(200 + random.nextInt(50), 150 + random.nextInt(50), random.nextInt(50)), 0.05F, 10, 0.9F)), this.xOld, this.yOld, this.zOld, + -this.getDeltaMovement().x * 0.1F * random.nextFloat(), -this.getDeltaMovement().y * 0.1F * random.nextFloat(), -this.getDeltaMovement().z * 0.1F * random.nextFloat()); + + if (target == null || target.isDeadOrDying()) { + if (!level.isClientSide()) + this.discard(); + return; + } - RandomSource random = level().getRandom(); + if (this.position().distanceTo(target.getEyePosition()) > 1F) { + var direction = target.getEyePosition().subtract(this.position()).normalize(); + var motion = this.getDeltaMovement(); - double size = 0.02D + heal * 0.001D; + var window = 5; - ((ServerLevel) level()).sendParticles(ParticleUtils.constructSimpleSpark(new Color(200, 150 + random.nextInt(50), random.nextInt(50)), 0.1F + (heal * 0.01F), 20 + Math.round(heal * 0.025F), 0.9F), - this.xo, this.yo, this.zo, 1, size, size, size, 0.01F + heal * 0.0001F); + if (tickCount > window) { + var factor = Math.clamp((tickCount - window) * 0.1F, 0F, 1F); - if (!(getOwner() instanceof Player player) || player.isDeadOrDying()) { - this.remove(RemovalReason.KILLED); + this.setDeltaMovement(motion.x + (direction.x * factor - motion.x) * factor, motion.y + (direction.y * factor - motion.y) * factor, motion.z + (direction.z * factor - motion.z) * factor); + } + } else { + target.heal(getHeal()); - return; + this.discard(); } + } - for (LifeEssenceEntity essence : level().getEntitiesOfClass(LifeEssenceEntity.class, this.getBoundingBox().inflate(heal * 0.05F))) { - if (essence.getStringUUID().equals(this.getStringUUID()) || (essence.getOwner() instanceof Player p1 - && this.getOwner() instanceof Player p2 && !p1.getStringUUID().equals(p2.getStringUUID()))) - continue; + @Override + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(HEAL, 0F); + } - setHeal(getHeal() + essence.getHeal()); + @Override + public void addAdditionalSaveData(CompoundTag tag) { + super.addAdditionalSaveData(tag); - essence.remove(RemovalReason.KILLED); - } + tag.putFloat("heal", getHeal()); + } - double distance = this.position().distanceTo(player.position().add(0, player.getBbHeight() / 2, 0)); + @Override + public void readAdditionalSaveData(CompoundTag tag) { + super.readAdditionalSaveData(tag); - if (distance > 1) { - if (distance > 32) { - this.remove(RemovalReason.KILLED); + setHeal(tag.getFloat("heal")); + } - return; - } + @Override + public boolean isNoGravity() { + return false; + } - EntityUtils.moveTowardsPosition(this, player.position().add(0, player.getBbHeight() / 2, 0), 0.25F); - } else { - player.heal(heal); + @Override + public void onAddedToLevel() { + super.onAddedToLevel(); - this.remove(RemovalReason.KILLED); - } + OctoRenderManager.registerProvider(this); + } + + @Nullable + @Override + public LivingEntity getTarget() { + return target; } @Override - protected void defineSynchedData() { + public void setTarget(LivingEntity target) { + this.target = target; + if (!level().isClientSide() && target != null) + NetworkHandler.sendToClientsTrackingEntity(new S2CEntityTargetPacket(this.getId(), target.getId()), this); + } + + @Override + public Vec3 getTrailPosition(float partialTicks) { + return getPosition(partialTicks).add(getDeltaMovement().scale(-1)); + } + + @Override + public int getTrailUpdateFrequency() { + return 1; + } + + @Override + public boolean isTrailAlive() { + return isAlive(); + } + + @Override + public boolean isTrailGrowing() { + return tickCount > 2; + } + + @Override + public int getTrailMaxLength() { + return 5; + } + + @Override + public int getTrailFadeInColor() { + return 0xFFFFFF00; + } + + @Override + public int getTrailFadeOutColor() { + return 0x80FF0000; } @Override - public @NotNull Packet getAddEntityPacket() { - return NetworkHooks.getEntitySpawningPacket(this); + public double getTrailScale() { + return 0.025F; } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/RelicExperienceOrbEntity.java b/src/main/java/it/hurts/sskirillss/relics/entities/RelicExperienceOrbEntity.java index 8dd11561..865ceb86 100644 --- a/src/main/java/it/hurts/sskirillss/relics/entities/RelicExperienceOrbEntity.java +++ b/src/main/java/it/hurts/sskirillss/relics/entities/RelicExperienceOrbEntity.java @@ -1,11 +1,10 @@ package it.hurts.sskirillss.relics.entities; +import it.hurts.sskirillss.relics.init.RegistryRegistry; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.RelicContainer; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.containers.base.RelicContainer; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; @@ -16,11 +15,11 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraftforge.fluids.FluidType; -import net.minecraftforge.network.NetworkHooks; +import net.neoforged.neoforge.fluids.FluidType; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class RelicExperienceOrbEntity extends Entity { private static final EntityDataAccessor EXPERIENCE = SynchedEntityData.defineId(RelicExperienceOrbEntity.class, EntityDataSerializers.INT); @@ -50,8 +49,8 @@ public int getStage() { private List getUpgradeableRelics(Player player) { List relics = new ArrayList<>(); - for (RelicContainer source : RelicContainer.values()) - relics.addAll(source.gatherRelics().apply(player).stream().filter(entry -> !((IRelicItem) entry.getItem()).isMaxLevel(entry)).toList()); + for (RelicContainer source : RegistryRegistry.RELIC_CONTAINER_REGISTRY.entrySet().stream().map(Map.Entry::getValue).toList()) + relics.addAll(source.gatherRelics().apply(player).stream().filter(entry -> !((IRelicItem) entry.getItem()).isRelicMaxLevel(entry)).toList()); return relics; } @@ -103,7 +102,7 @@ public void tick() { if (!upgradeable.isEmpty()) { ItemStack stack = upgradeable.get(random.nextInt(upgradeable.size())); - ((IRelicItem) stack.getItem()).spreadExperience(player, stack, this.getExperience()); + ((IRelicItem) stack.getItem()).spreadRelicExperience(player, stack, this.getExperience()); this.discard(); @@ -143,12 +142,12 @@ protected void addAdditionalSaveData(CompoundTag tag) { } @Override - protected void defineSynchedData() { - entityData.define(EXPERIENCE, 0); + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(EXPERIENCE, 0); } @Override - protected BlockPos getBlockPosBelowThatAffectsMyMovement() { + public BlockPos getBlockPosBelowThatAffectsMyMovement() { return this.getOnPos(0.999F); } @@ -162,11 +161,6 @@ public boolean isAttackable() { return false; } - @Override - public Packet getAddEntityPacket() { - return NetworkHooks.getEntitySpawningPacket(this); - } - @Override public SoundSource getSoundSource() { return SoundSource.AMBIENT; diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/ShadowGlaiveEntity.java b/src/main/java/it/hurts/sskirillss/relics/entities/ShadowGlaiveEntity.java index 8394c404..63b5ee92 100644 --- a/src/main/java/it/hurts/sskirillss/relics/entities/ShadowGlaiveEntity.java +++ b/src/main/java/it/hurts/sskirillss/relics/entities/ShadowGlaiveEntity.java @@ -1,15 +1,16 @@ package it.hurts.sskirillss.relics.entities; +import it.hurts.octostudios.octolib.modules.particles.OctoRenderManager; +import it.hurts.octostudios.octolib.modules.particles.trail.TrailProvider; +import it.hurts.sskirillss.relics.entities.misc.ITargetableEntity; import it.hurts.sskirillss.relics.init.EntityRegistry; -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.network.NetworkHandler; +import it.hurts.sskirillss.relics.network.packets.sync.S2CEntityTargetPacket; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; import it.hurts.sskirillss.relics.utils.ParticleUtils; import lombok.Getter; -import lombok.Setter; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; @@ -18,188 +19,187 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.ThrowableProjectile; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraftforge.network.NetworkHooks; +import net.minecraft.world.phys.Vec3; -import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.awt.*; -import java.util.Arrays; import java.util.Comparator; +import java.util.HashSet; import java.util.List; -import java.util.stream.Collectors; +import java.util.Set; -public class ShadowGlaiveEntity extends ThrowableProjectile { +public class ShadowGlaiveEntity extends ThrowableProjectile implements ITargetableEntity, TrailProvider { + private static final EntityDataAccessor MAX_BOUNCES = SynchedEntityData.defineId(ShadowGlaiveEntity.class, EntityDataSerializers.INT); private static final EntityDataAccessor BOUNCES = SynchedEntityData.defineId(ShadowGlaiveEntity.class, EntityDataSerializers.INT); - private static final EntityDataAccessor TARGET = SynchedEntityData.defineId(ShadowGlaiveEntity.class, EntityDataSerializers.STRING); - private static final EntityDataAccessor BOUNCED_ENTITIES = SynchedEntityData.defineId(ShadowGlaiveEntity.class, EntityDataSerializers.STRING); + private static final EntityDataAccessor DAMAGE = SynchedEntityData.defineId(ShadowGlaiveEntity.class, EntityDataSerializers.FLOAT); + private static final EntityDataAccessor CHANCE = SynchedEntityData.defineId(ShadowGlaiveEntity.class, EntityDataSerializers.FLOAT); - private static final String TAG_BOUNCES_AMOUNT = "bounces"; - private static final String TAG_TARGET_UUID = "target"; - private static final String TAG_BOUNCED_ENTITIES = "entities"; + @Getter + private Set bouncedTargets = new HashSet<>(); - private boolean isBounced = false; - private LivingEntity target; + @Nullable + private LivingEntity currentTarget = null; + @Nullable + private LivingEntity lastTarget = null; - @Getter - @Setter - private ItemStack stack = ItemStack.EMPTY; + public ShadowGlaiveEntity(EntityType type, Level level) { + super(type, level); + } - public ShadowGlaiveEntity(EntityType type, Level worldIn) { - super(type, worldIn); + public void setMaxBounces(int maxBounces) { + this.getEntityData().set(MAX_BOUNCES, maxBounces); } - public ShadowGlaiveEntity(Level world, LivingEntity throwerIn) { - super(EntityRegistry.SHADOW_GLAIVE.get(), throwerIn, world); + public int getMaxBounces() { + return this.getEntityData().get(MAX_BOUNCES); } - public void setTarget(LivingEntity target) { - this.target = target; + public void setBounces(int bounces) { + this.getEntityData().set(BOUNCES, bounces); + } - if (target != null) - entityData.set(TARGET, target.getUUID().toString()); + public int getBounces() { + return this.getEntityData().get(BOUNCES); } - private void locateNearestTarget() { - if (!(stack.getItem() instanceof IRelicItem relic)) - return; + public void addBounces(int bounces) { + setBounces(Math.clamp(getBounces() + bounces, 0, getMaxBounces())); + } - if (entityData.get(BOUNCES) >= relic.getAbilityValue(stack, "glaive", "bounces")) { - this.discard(); + public void setDamage(float damage) { + this.getEntityData().set(DAMAGE, damage); + } - return; - } + public float getDamage() { + return this.getEntityData().get(DAMAGE); + } - List bouncedEntities = Arrays.asList(entityData.get(BOUNCED_ENTITIES).split(",")); - List entitiesAround = level().getEntitiesOfClass(LivingEntity.class, - this.getBoundingBox().inflate(relic.getAbilityValue(stack, "glaive", "radius"))); - - entitiesAround = entitiesAround.stream() - .filter(entity -> !bouncedEntities.contains(entity.getUUID().toString())) - .filter(EntitySelector.NO_CREATIVE_OR_SPECTATOR) - .filter(entity -> { - if (!(this.getOwner() instanceof Player player)) - return false; - - return !entity.getStringUUID().equals(player.getStringUUID()) - && !EntityUtils.isAlliedTo(player, entity); - }) - .filter(entity -> entity.hasLineOfSight(this)) - .sorted(Comparator.comparing(entity -> entity.position().distanceTo(this.position()))) - .collect(Collectors.toList()); - - if (entitiesAround.isEmpty()) { - if (isBounced) - this.discard(); + public void setChance(float chance) { + this.getEntityData().set(CHANCE, chance); + } - return; - } + public float getChance() { + return this.getEntityData().get(CHANCE); + } - LivingEntity target = null; + public List locateNearestTargets() { + return EntityUtils.gatherPotentialTargets(this, LivingEntity.class,16) + .filter(entity -> (lastTarget == null || !lastTarget.getStringUUID().equals(entity.getStringUUID())) + && (!(this.getOwner() instanceof Player player) || !EntityUtils.isAlliedTo(player, entity))) + .toList(); + } - for (LivingEntity entity : entitiesAround) { - if (entity == null || !entity.isAlive()) - continue; + @Override + public void tick() { + super.tick(); - target = entity; + var level = getCommandSenderWorld(); - break; - } + var particleCenter = this.position().add(this.getDeltaMovement().scale(-1F)); - if (target == null || !target.isAlive()) { - this.discard(); + for (int i = 0; i < 5; i++) + level.addParticle(ParticleUtils.constructSimpleSpark(new Color(50 + random.nextInt(100), 0, 150 + random.nextInt(100)), 0.1F + random.nextFloat() * 0.15F, 5 + random.nextInt(10), 0.85F), + particleCenter.x() + MathUtils.randomFloat(random) * 0.25F, particleCenter.y(), particleCenter.z() + MathUtils.randomFloat(random) * 0.25F, 0F, 0F, 0F); - return; - } + var currentTarget = getTarget(); - this.setTarget(target); - } + if (currentTarget != null && (this.position().distanceTo(currentTarget.position()) >= 16F || currentTarget.isDeadOrDying())) + currentTarget = null; - @Override - public void tick() { - super.tick(); + if (!level.isClientSide()) { + LivingEntity potentialTarget = null; - if (!(stack.getItem() instanceof IRelicItem relic)) - return; + var candidateEntities = locateNearestTargets(); - for (int i = 0; i < 3; i++) - level().addParticle(ParticleUtils.constructSimpleSpark(new Color(255, random.nextInt(100), 255), 0.2F, 30, 0.99F), - this.xo, this.yo, this.zo, MathUtils.randomFloat(random) * 0.01F, 0, MathUtils.randomFloat(random) * 0.01F); + var targetEntities = candidateEntities.stream() + .filter(entity -> !bouncedTargets.contains(entity.getStringUUID())) + .toList(); - if (level().isClientSide()) - return; + if (!targetEntities.isEmpty()) + potentialTarget = targetEntities.getFirst(); + else if (!candidateEntities.isEmpty()) { + bouncedTargets.clear(); - if (!isBounced && target == null && this.tickCount > 30) - this.discard(); + potentialTarget = candidateEntities.getFirst(); + } - if (this.tickCount > 300) - this.discard(); + if (potentialTarget != null && (currentTarget == null || !currentTarget.getStringUUID().equals(potentialTarget.getStringUUID()))) { + NetworkHandler.sendToClientsTrackingEntity(new S2CEntityTargetPacket(this.getId(), potentialTarget.getId()), this); - if (target == null && this.tickCount > 10 && this.tickCount % 2 == 0) { - this.locateNearestTarget(); + setTarget(potentialTarget); - return; + currentTarget = potentialTarget; + } } - if (target != null && target.isAlive()) { - EntityUtils.moveTowardsPosition(this, target.position() - .add(0D, target.getBbHeight() * 0.5D, 0D), 0.75F); + if (currentTarget == null || currentTarget.isDeadOrDying() || this.tickCount >= 250 || getBounces() >= getMaxBounces()) { + if (!level.isClientSide()) + this.discard(); - for (LivingEntity entity : level().getEntitiesOfClass(LivingEntity.class, - this.getBoundingBox().inflate(0.3D, 3D, 0.3D))) { - if (this.getOwner() instanceof Player player && entity.getStringUUID().equals(player.getStringUUID())) - continue; + return; + } - String bouncedEntitiesString = entityData.get(BOUNCED_ENTITIES); - List bouncedEntities = Arrays.asList(bouncedEntitiesString.split(",")); + if (this.getEyePosition().distanceTo(currentTarget.getEyePosition()) <= 1.5F) { + currentTarget.invulnerableTime = 0; - float damage = (float) relic.getAbilityValue(stack, "glaive", "damage"); + if (currentTarget.hurt(level.damageSources().thrown(this, getOwner()), getDamage())) { + bouncedTargets.add(currentTarget.getStringUUID()); + lastTarget = currentTarget; - if (this.getOwner() instanceof Player player) { - if (EntityUtils.hurt(entity, level().damageSources().thrown(this, player), damage)) - relic.spreadExperience(player, stack, 1); - } else - entity.hurt(level().damageSources().magic(), damage); + setTarget(null); + addBounces(1); - if (!bouncedEntities.contains(entity.getUUID().toString())) { - entityData.set(BOUNCED_ENTITIES, bouncedEntitiesString + "," + entity.getUUID()); + if (random.nextDouble() <= getChance()) { + var entity = new ShadowGlaiveEntity(EntityRegistry.SHADOW_GLAIVE.get(), level); - entityData.set(BOUNCES, entityData.get(BOUNCES) + 1); + entity.setMaxBounces(getMaxBounces()); + entity.setBounces(getBounces()); + entity.setPos(getEyePosition()); + entity.setDamage(getDamage()); + entity.setOwner(getOwner()); - isBounced = true; + level.addFreshEntity(entity); } + } + } else { + this.setDeltaMovement(currentTarget.getEyePosition().subtract(this.getEyePosition()).normalize()); + } + } - this.locateNearestTarget(); + @Override + public void onAddedToLevel() { + super.onAddedToLevel(); - break; - } - } else - this.locateNearestTarget(); + OctoRenderManager.registerProvider(this); } @Override - protected void defineSynchedData() { - entityData.define(BOUNCES, 0); - entityData.define(TARGET, ""); - entityData.define(BOUNCED_ENTITIES, ""); + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(MAX_BOUNCES, 10); + builder.define(BOUNCES, 0); + builder.define(DAMAGE, 1F); + builder.define(CHANCE, -1F); } @Override public void addAdditionalSaveData(CompoundTag tag) { - tag.putInt(TAG_BOUNCES_AMOUNT, entityData.get(BOUNCES)); - tag.putString(TAG_TARGET_UUID, entityData.get(TARGET)); - tag.putString(TAG_BOUNCED_ENTITIES, entityData.get(BOUNCED_ENTITIES)); - super.addAdditionalSaveData(tag); + + tag.putInt("max_bounces", getMaxBounces()); + tag.putInt("bounces", getBounces()); + tag.putFloat("damage", getDamage()); + tag.putFloat("chance", getChance()); } @Override public void readAdditionalSaveData(CompoundTag tag) { - entityData.set(BOUNCES, tag.getInt(TAG_BOUNCES_AMOUNT)); - entityData.set(TARGET, tag.getString(TAG_TARGET_UUID)); - entityData.set(BOUNCED_ENTITIES, tag.getString(TAG_BOUNCED_ENTITIES)); - super.readAdditionalSaveData(tag); + + setMaxBounces(tag.getInt("max_bounces")); + setBounces(tag.getInt("bounces")); + setDamage(tag.getFloat("damage")); + setChance(tag.getFloat("chance")); } @Override @@ -208,13 +208,57 @@ public boolean isPushedByFluid() { } @Override - protected float getGravity() { - return 0F; + protected double getDefaultGravity() { + return 0D; + } + + @Override + public @Nullable LivingEntity getTarget() { + return currentTarget; + } + + @Override + public void setTarget(LivingEntity target) { + this.currentTarget = target; + } + + @Override + public Vec3 getTrailPosition(float partialTicks) { + return getPosition(partialTicks).add(getDeltaMovement().scale(-1)); + } + + @Override + public int getTrailUpdateFrequency() { + return 1; + } + + @Override + public boolean isTrailAlive() { + return isAlive(); + } + + @Override + public boolean isTrailGrowing() { + return getKnownMovement().length() >= 0.1F; + } + + @Override + public int getTrailMaxLength() { + return 5; + } + + @Override + public int getTrailFadeInColor() { + return 0xFFFF00FF; + } + + @Override + public int getTrailFadeOutColor() { + return 0x800000FF; } - @Nonnull @Override - public Packet getAddEntityPacket() { - return NetworkHooks.getEntitySpawningPacket(this); + public double getTrailScale() { + return 0.15F; } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/ShadowSawEntity.java b/src/main/java/it/hurts/sskirillss/relics/entities/ShadowSawEntity.java deleted file mode 100644 index 0f07d7c6..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/entities/ShadowSawEntity.java +++ /dev/null @@ -1,163 +0,0 @@ -package it.hurts.sskirillss.relics.entities; - -import it.hurts.sskirillss.relics.init.EntityRegistry; -import it.hurts.sskirillss.relics.init.ItemRegistry; -import it.hurts.sskirillss.relics.items.relics.ShadowGlaiveItem; -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.utils.EntityUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; -import it.hurts.sskirillss.relics.utils.ParticleUtils; -import lombok.Getter; -import lombok.Setter; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.Mth; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.MoverType; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.entity.projectile.ThrowableProjectile; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraftforge.network.NetworkHooks; - -import javax.annotation.Nonnull; -import java.awt.*; - -public class ShadowSawEntity extends ThrowableProjectile { - @Getter - @Setter - private ItemStack stack = ItemStack.EMPTY; - - public boolean isReturning = false; - - public ShadowSawEntity(EntityType pEntityType, Level level) { - super(pEntityType, level); - } - - public ShadowSawEntity(ItemStack stack, LivingEntity owner) { - super(EntityRegistry.SHADOW_SAW.get(), owner.getCommandSenderWorld()); - - setStack(stack); - } - - @Override - public void tick() { - this.move(MoverType.SELF, this.getDeltaMovement()); - - if (level().isClientSide() || !(stack.getItem() instanceof IRelicItem relic)) - return; - - if (this.tickCount >= 1200) - this.isReturning = true; - - if (isReturning) { - this.noPhysics = true; - - if (this.getOwner() instanceof Player player) { - if (this.position().distanceTo(player.position()) > this.getBbWidth()) - this.setDeltaMovement(player.position().add(0, player.getBbHeight() / 2, 0).subtract(this.position()).normalize().multiply(0.75, 0.75, 0.75)); - else { - for (int i = 0; i < player.getInventory().getContainerSize(); i++) { - ItemStack stack = player.getInventory().getItem(i); - - if (stack.getItem() != ItemRegistry.SHADOW_GLAIVE.get()) - continue; - - if (NBTUtils.getString(stack, ShadowGlaiveItem.TAG_SAW, "").equals(this.getStringUUID())) { - NBTUtils.setInt(stack, ShadowGlaiveItem.TAG_CHARGES, 8); - NBTUtils.clearTag(stack, ShadowGlaiveItem.TAG_SAW); - - break; - } - } - - this.discard(); - } - } else - this.discard(); - } else { - if (this.onGround()) - this.setDeltaMovement(this.getDeltaMovement().multiply(0.75F, 0.75F, 0.75F)); - else - this.setDeltaMovement(this.getDeltaMovement().add(0F, -0.05F, 0F)); - } - - int speed = (int) Math.round(relic.getAbilityValue(stack, "saw", "speed")); - - if (this.tickCount % speed == 0) { - float damage = (float) Math.max(relic.getAbilityValue(stack, "saw", "damage"), 0.1D); - - for (LivingEntity entity : level().getEntitiesOfClass(LivingEntity.class, this.getBoundingBox().inflate(0.5D))) { - boolean mayContinue = false; - - if (this.getOwner() instanceof Player player) { - if (EntityUtils.hurt(entity, level().damageSources().playerAttack(player), damage)) - mayContinue = true; - } else { - if (entity.hurt(level().damageSources().magic(), damage)) - mayContinue = true; - } - - if (mayContinue) - entity.invulnerableTime = speed; - } - } - - ServerLevel serverLevel = (ServerLevel) level(); - - double radius = 1.5D; - - for (int i = 0; i < 5; i++) { - float angle = -(this.tickCount * 20 + i * 120) * 0.0105F; - - double extraX = (radius * Mth.sin((float) (Math.PI + angle))) + this.getX(); - double extraZ = (radius * Mth.cos(angle)) + this.getZ(); - - serverLevel.sendParticles(ParticleUtils.constructSimpleSpark(new Color(200, 0, 255), 0.075F, 20, 0.95F), - extraX, this.getY() + 0.25F, extraZ, 1, 0.01, 0.01, 0.01, 0.025F); - } - - serverLevel.sendParticles(ParticleUtils.constructSimpleSpark(new Color(102, 0, 255), 0.1F, 20, 0.9F), - this.getX(), this.getY() + 0.3F, this.getZ(), 2, 0.25, 0.1, 0.25, 0.02F); - } - - @Override - protected void onHitBlock(BlockHitResult pResult) { - this.setDeltaMovement(this.getDeltaMovement().multiply(1, 0, 1)); - } - - @Override - protected float getGravity() { - return 0.05F; - } - - @Override - protected void defineSynchedData() { - - } - - @Override - protected void readAdditionalSaveData(CompoundTag compound) { - - } - - @Override - protected void addAdditionalSaveData(CompoundTag compound) { - - } - - @Override - public boolean isPushedByFluid() { - return false; - } - - @Nonnull - @Override - public Packet getAddEntityPacket() { - return NetworkHooks.getEntitySpawningPacket(this); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/ShockwaveEntity.java b/src/main/java/it/hurts/sskirillss/relics/entities/ShockwaveEntity.java index 592efc3d..290cb849 100644 --- a/src/main/java/it/hurts/sskirillss/relics/entities/ShockwaveEntity.java +++ b/src/main/java/it/hurts/sskirillss/relics/entities/ShockwaveEntity.java @@ -6,8 +6,7 @@ import lombok.Setter; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; @@ -18,9 +17,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.network.NetworkHooks; -import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.List; @@ -81,7 +78,10 @@ public void tick() { if (!level.isClientSide()) { float damage = radius * this.damage / step; - for (LivingEntity entity : level.getEntitiesOfClass(LivingEntity.class, new AABB(p, p.above(3)).inflate(0.5F))) { + if (Float.isNaN(damage)) + damage = 1F; + + for (LivingEntity entity : level.getEntitiesOfClass(LivingEntity.class, new AABB(Vec3.atCenterOf(p), Vec3.atCenterOf(p.above(3))).inflate(0.5F))) { if (owner != null && entity.getStringUUID().equals(owner.getStringUUID())) continue; @@ -117,7 +117,7 @@ public void tick() { } @Override - protected void defineSynchedData() { + protected void defineSynchedData(SynchedEntityData.Builder builder) { } @@ -137,10 +137,4 @@ protected void addAdditionalSaveData(CompoundTag compound) { public boolean isPushedByFluid() { return false; } - - @Nonnull - @Override - public Packet getAddEntityPacket() { - return NetworkHooks.getEntitySpawningPacket(this); - } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/SolidSnowballEntity.java b/src/main/java/it/hurts/sskirillss/relics/entities/SolidSnowballEntity.java index e289afda..d9dd7fab 100644 --- a/src/main/java/it/hurts/sskirillss/relics/entities/SolidSnowballEntity.java +++ b/src/main/java/it/hurts/sskirillss/relics/entities/SolidSnowballEntity.java @@ -9,8 +9,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; @@ -28,9 +26,6 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.EntityHitResult; -import net.minecraftforge.network.NetworkHooks; - -import javax.annotation.Nonnull; public class SolidSnowballEntity extends ThrowableProjectile { private static final EntityDataAccessor SIZE = SynchedEntityData.defineId(SolidSnowballEntity.class, EntityDataSerializers.INT); @@ -91,7 +86,7 @@ protected void onHitEntity(EntityHitResult result) { if (stack.getItem() instanceof IRelicItem relic) { boolean mayContinue = false; - float damage = (float) (getSize() * relic.getAbilityValue(stack, "mold", "damage")); + float damage = (float) (getSize() * relic.getStatValue(stack, "mold", "damage")); if (this.getOwner() instanceof Player player) { if (EntityUtils.hurt(entity, level().damageSources().thrown(this, player), damage)) @@ -102,14 +97,14 @@ protected void onHitEntity(EntityHitResult result) { } if (mayContinue) - entity.addEffect(new MobEffectInstance(EffectRegistry.STUN.get(), (int) Math.round(getSize() * relic.getAbilityValue(stack, "mold", "stun")) * 20, 0, true, false)); + entity.addEffect(new MobEffectInstance(EffectRegistry.STUN, (int) Math.round(getSize() * relic.getStatValue(stack, "mold", "stun")) * 20, 0, true, false)); } this.discard(); } @Override - public void onRemovedFromWorld() { + public void onRemovedFromLevel() { ParticleUtils.createBall(ParticleTypes.SNOWFLAKE, this.position(), level(), 1 + (getSize() / 10), 0.1F + getSize() * 0.005F); if (level().isClientSide()) @@ -127,18 +122,18 @@ public void onRemovedFromWorld() { for (LivingEntity entity : level().getEntitiesOfClass(LivingEntity.class, this.getBoundingBox().inflate(getSize() / 15F))) { if (!entity.getStringUUID().equals(owner.getStringUUID())) - entity.setTicksFrozen((int) (100 + Math.round(getSize() * relic.getAbilityValue(EntityUtils.findEquippedCurio(owner, ItemRegistry.WOOL_MITTEN.get()), "mold", "freeze")))); + entity.setTicksFrozen((int) (100 + Math.round(getSize() * relic.getStatValue(EntityUtils.findEquippedCurio(owner, ItemRegistry.WOOL_MITTEN.get()), "mold", "freeze")))); } if (owner instanceof LivingEntity entity) - relic.spreadExperience(entity, stack, (int) Math.floor(getSize() / 5F)); + relic.spreadRelicExperience(entity, stack, (int) Math.floor(getSize() / 5F)); level().playSound(null, this.blockPosition(), SoundEvents.SNOW_BREAK, SoundSource.MASTER, 1F, 0.5F); } @Override - protected void defineSynchedData() { - entityData.define(SIZE, 0); + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(SIZE, 0); } @Override @@ -156,9 +151,9 @@ public boolean isPushedByFluid() { return false; } - @Nonnull - @Override - public Packet getAddEntityPacket() { - return NetworkHooks.getEntitySpawningPacket(this); - } +// @Nonnull +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/SporeEntity.java b/src/main/java/it/hurts/sskirillss/relics/entities/SporeEntity.java index c35533ec..06f4e3d4 100644 --- a/src/main/java/it/hurts/sskirillss/relics/entities/SporeEntity.java +++ b/src/main/java/it/hurts/sskirillss/relics/entities/SporeEntity.java @@ -1,74 +1,57 @@ package it.hurts.sskirillss.relics.entities; +import it.hurts.octostudios.octolib.modules.particles.OctoRenderManager; +import it.hurts.octostudios.octolib.modules.particles.trail.TrailProvider; +import it.hurts.sskirillss.relics.entities.misc.ITargetableEntity; import it.hurts.sskirillss.relics.init.EffectRegistry; -import it.hurts.sskirillss.relics.init.EntityRegistry; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.network.NetworkHandler; +import it.hurts.sskirillss.relics.network.packets.sync.S2CEntityTargetPacket; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; import it.hurts.sskirillss.relics.utils.ParticleUtils; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; -import net.minecraft.util.RandomSource; import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.effect.MobEffects; -import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.Pose; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.ThrowableProjectile; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.EntityHitResult; +import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.network.NetworkHooks; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nonnull; import java.awt.*; +import java.util.List; -public class SporeEntity extends ThrowableProjectile { - private static final EntityDataAccessor SIZE = SynchedEntityData.defineId(SporeEntity.class, EntityDataSerializers.FLOAT); - private static final EntityDataAccessor STUCK = SynchedEntityData.defineId(SporeEntity.class, EntityDataSerializers.BOOLEAN); - private static final EntityDataAccessor LIFETIME = SynchedEntityData.defineId(SporeEntity.class, EntityDataSerializers.INT); - private static final EntityDataAccessor STACK = SynchedEntityData.defineId(SporeEntity.class, EntityDataSerializers.ITEM_STACK); +public class SporeEntity extends ThrowableProjectile implements ITargetableEntity, TrailProvider { + private static final EntityDataAccessor RELIC_STACK = SynchedEntityData.defineId(SporeEntity.class, EntityDataSerializers.ITEM_STACK); + private static final EntityDataAccessor DAMAGE = SynchedEntityData.defineId(SporeEntity.class, EntityDataSerializers.FLOAT); - public void setSize(float amount) { - this.getEntityData().set(SIZE, amount); + public void setRelicStack(ItemStack stack) { + this.getEntityData().set(RELIC_STACK, stack); } - public float getSize() { - return this.getEntityData().get(SIZE); + public ItemStack getRelicStack() { + return this.getEntityData().get(RELIC_STACK); } - public void setStuck(boolean value) { - this.getEntityData().set(STUCK, value); + public void setDamage(float damage) { + this.getEntityData().set(DAMAGE, damage); } - public boolean isStuck() { - return this.getEntityData().get(STUCK); + public float getDamage() { + return this.getEntityData().get(DAMAGE); } - public void setLifetime(int amount) { - this.getEntityData().set(LIFETIME, amount); - } - - public int getLifetime() { - return this.getEntityData().get(LIFETIME); - } - - public void setStack(ItemStack stack) { - this.getEntityData().set(STACK, stack); - } - - public ItemStack getStack() { - return this.getEntityData().get(STACK); - } + private LivingEntity target; public SporeEntity(EntityType entityType, Level level) { super(entityType, level); @@ -78,144 +61,109 @@ public SporeEntity(EntityType entityType, Level l public void tick() { super.tick(); - ItemStack stack = getStack(); - - if (!(stack.getItem() instanceof IRelicItem relic)) { - this.discard(); - - return; - } + var level = getCommandSenderWorld(); + var particleCenter = this.position().add(this.getDeltaMovement().scale(-1F)); - if (this.isStuck()) - this.setDeltaMovement(0, 0, 0); + if (tickCount > 3) + for (int i = 0; i < 3; i++) + level.addParticle(ParticleUtils.constructSimpleSpark(new Color(50 + random.nextInt(100), 150 + random.nextInt(100), 0), 0.01F + random.nextFloat() * Math.min(tickCount * 0.01F, 0.1F), 5 + random.nextInt(3), 0.9F), + particleCenter.x() + MathUtils.randomFloat(random) * 0.05F, particleCenter.y() + MathUtils.randomFloat(random) * 0.05F, particleCenter.z() + MathUtils.randomFloat(random) * 0.05F, 0F, 0F, 0F); - Level level = level(); + if (target == null || target.isDeadOrDying()) { + if (level.isClientSide()) + return; - if (!level.isClientSide()) { - if (isStuck()) - setLifetime(getLifetime() + 1); + var targets = locateNearestTargets(); - if (getLifetime() > relic.getAbilityValue(stack, "spore", "duration") * 20) - this.discard(); - } + if (targets.isEmpty()) + return; - RandomSource random = level.getRandom(); + setTarget(targets.get(random.nextInt(targets.size()))); - double inlinedSize = Math.pow(Math.log10(1 + getSize()), 1D / 3D); + NetworkHandler.sendToClientsTrackingEntity(new S2CEntityTargetPacket(this.getId(), target.getId()), this); - if (isStuck()) { - ParticleUtils.createBall(ParticleUtils.constructSimpleSpark(new Color(random.nextInt(200), 255, 0), (float) (inlinedSize * 0.25F), 40, 0.95F), - this.position().add(0, inlinedSize / 6, 0), level, 0, (float) (inlinedSize * 0.025F)); - } else { - level.addParticle(ParticleUtils.constructSimpleSpark(new Color(random.nextInt(200), 255, 0), (float) (inlinedSize * 0.25F), 40, 0.9F), - this.getX(), this.getY() + (inlinedSize / 6F), this.getZ(), MathUtils.randomFloat(random) * 0.025F, - MathUtils.randomFloat(random) * 0.025F, MathUtils.randomFloat(random) * 0.025F); + return; } - if (!(this.getOwner() instanceof Player player)) - return; + var direction = target.position().subtract(this.position()).normalize(); + var motion = this.getDeltaMovement(); - if (isStuck()) { - for (LivingEntity entity : level.getEntitiesOfClass(LivingEntity.class, this.getBoundingBox())) { - if (entity.getStringUUID().equals(player.getStringUUID())) - continue; + var factor = Math.clamp(tickCount * 0.05F, 0F, 1F); - setLifetime((int) Math.max(getLifetime(), Math.round(relic.getAbilityValue(stack, "spore", "duration") * 20) - 20)); + this.setDeltaMovement(motion.x + (direction.x * factor - motion.x) * factor, motion.y, motion.z + (direction.z * factor - motion.z) * factor); + } - break; - } - } + public List locateNearestTargets() { + return EntityUtils.gatherPotentialTargets(this, LivingEntity.class, 32) + .filter(entity -> (!(this.getOwner() instanceof Player player) || !EntityUtils.isAlliedTo(player, entity))) + .toList(); } @Override - protected void onHitBlock(BlockHitResult result) { - this.setDeltaMovement(0, 0, 0); + public void onAddedToLevel() { + super.onAddedToLevel(); - this.setStuck(true); + OctoRenderManager.registerProvider(this); } @Override - public void onRemovedFromWorld() { - ItemStack stack = getStack(); - - if (!(stack.getItem() instanceof IRelicItem relic)) - return; - - level().playSound(null, this.blockPosition(), SoundEvents.PUFFER_FISH_BLOW_UP, SoundSource.MASTER, 1F, 1F + random.nextFloat()); - - double inlinedSize = Math.pow(Math.log10(1 + getSize()), 1D / 3D); - - ParticleUtils.createBall(ParticleUtils.constructSimpleSpark(new Color(100 + level().getRandom().nextInt(50), 255, 0), - (float) (inlinedSize * 0.35F), 40, 0.9F), - this.position().add(0, inlinedSize / 3, 0), level(), (int) Math.ceil(1 + inlinedSize), (float) (inlinedSize / 2D)); + public void onRemovedFromLevel() { + super.onRemovedFromLevel(); - if (this.getOwner() instanceof Player player) { - RandomSource random = player.getRandom(); + var level = getCommandSenderWorld(); + var vec = this.position(); - for (LivingEntity entity : level().getEntitiesOfClass(LivingEntity.class, this.getBoundingBox().inflate(1F + (Math.pow(Math.log10(1 + getSize()), 1D / 3D) / 2F)))) { - if (entity.getStringUUID().equals(player.getStringUUID())) - continue; + level.playSound(null, this.blockPosition(), SoundEvents.PUFFER_FISH_BLOW_UP, SoundSource.MASTER, 0.5F, 1.5F + random.nextFloat() * 0.5F); - if (EntityUtils.hurt(entity, level().damageSources().thrown(this, player), (float) (getSize() * relic.getAbilityValue(stack, "spore", "damage")))) { - entity.addEffect(new MobEffectInstance(MobEffects.POISON, 100)); - entity.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 100)); - entity.addEffect(new MobEffectInstance(EffectRegistry.ANTI_HEAL.get(), 100)); - } - } + for (int i = 0; i < 3; i++) + ParticleUtils.createBall(ParticleUtils.constructSimpleSpark(new Color(50 + random.nextInt(100), 150 + random.nextInt(100), 0), 0.1F + random.nextFloat() * 0.2F, 20 + random.nextInt(10), 0.95F), + vec, level, 1, 0.025F + random.nextFloat() * 0.15F); - if (getSize() >= 1) { - int count = (int) Math.ceil(Math.pow(getSize(), relic.getAbilityValue(stack, "multiplying", "amount"))); + } - for (int i = 0; i < count; i++) { - if (random.nextFloat() > relic.getAbilityValue(stack, "multiplying", "chance")) - break; + @Override + protected void onHit(HitResult result) { + super.onHit(result); - float mul = this.getBbHeight() / 1.5F; - float speed = 0.1F + random.nextFloat() * 0.2F; - Vec3 motion = new Vec3(MathUtils.randomFloat(random) * speed, speed, MathUtils.randomFloat(random) * speed); + if (this.getOwner() instanceof Player player && result instanceof EntityHitResult entityResult && entityResult.getEntity() instanceof LivingEntity entity && !entity.getStringUUID().equals(player.getStringUUID())) { + entity.invulnerableTime = 0; - SporeEntity spore = new SporeEntity(EntityRegistry.SPORE.get(), level()); + var stack = getRelicStack(); - spore.setOwner(player); - spore.setStack(stack); - spore.setDeltaMovement(motion); - spore.setPos(this.position().add(0, mul, 0).add(motion.normalize().scale(mul))); - spore.setSize((float) (this.getSize() * relic.getAbilityValue(stack, "multiplying", "size"))); + if (entity.hurt(getCommandSenderWorld().damageSources().thrown(this, player), getDamage())) { + if (stack.getItem() instanceof IRelicItem relic) + relic.spreadRelicExperience(player, stack, 1); - level().addFreshEntity(spore); + if (this.isOnFire()) + entity.igniteForTicks(this.getRemainingFireTicks()); - relic.spreadExperience(player, stack, 1); - } + entity.addEffect(new MobEffectInstance(EffectRegistry.ANTI_HEAL, 0, 20 * 5, false, false), player); } } - super.onRemovedFromWorld(); + this.discard(); } @Override - protected void defineSynchedData() { - entityData.define(SIZE, 0.5F); - entityData.define(LIFETIME, 0); - entityData.define(STUCK, false); - entityData.define(STACK, ItemStack.EMPTY); + protected void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(RELIC_STACK, ItemStack.EMPTY); + builder.define(DAMAGE, 1F); } @Override - protected void readAdditionalSaveData(CompoundTag compound) { - setSize(compound.getFloat("size")); - setStuck(compound.getBoolean("stuck")); - setLifetime(compound.getInt("lifetime")); + public void addAdditionalSaveData(CompoundTag tag) { + super.addAdditionalSaveData(tag); - setStack(ItemStack.of(compound.getCompound("stack"))); + tag.put("relic_stack", getRelicStack().save(this.registryAccess())); + tag.putFloat("damage", getDamage()); } @Override - protected void addAdditionalSaveData(CompoundTag compound) { - compound.putFloat("size", getSize()); - compound.putBoolean("stuck", isStuck()); - compound.putInt("lifetime", getLifetime()); + public void readAdditionalSaveData(CompoundTag tag) { + super.readAdditionalSaveData(tag); - getStack().save(compound.getCompound("stack")); + setRelicStack(ItemStack.parseOptional(this.registryAccess(), tag.getCompound("relic_stack"))); + setDamage(tag.getFloat("damage")); } @Override @@ -224,23 +172,52 @@ public boolean isPushedByFluid() { } @Override - public void onSyncedDataUpdated(EntityDataAccessor pKey) { - if (SIZE.equals(pKey)) - this.refreshDimensions(); + public @Nullable LivingEntity getTarget() { + return target; + } + + @Override + public void setTarget(LivingEntity target) { + this.target = target; + } + + @Override + public Vec3 getTrailPosition(float partialTicks) { + return getPosition(partialTicks).add(getDeltaMovement().scale(-1)); + } + + @Override + public int getTrailUpdateFrequency() { + return 1; + } - super.onSyncedDataUpdated(pKey); + @Override + public boolean isTrailAlive() { + return isAlive(); } - @Nonnull @Override - public Packet getAddEntityPacket() { - return NetworkHooks.getEntitySpawningPacket(this); + public boolean isTrailGrowing() { + return tickCount > 2; } @Override - public EntityDimensions getDimensions(Pose pPose) { - float inlinedSize = (float) Math.pow(Math.log10(1 + getSize()), 1D / 3D); + public int getTrailMaxLength() { + return 3; + } - return EntityDimensions.scalable(inlinedSize / 2F, inlinedSize / 2F); + @Override + public int getTrailFadeInColor() { + return 0xFF55FF00; + } + + @Override + public int getTrailFadeOutColor() { + return 0x8080FF00; + } + + @Override + public double getTrailScale() { + return 0.075F; } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/StalactiteEntity.java b/src/main/java/it/hurts/sskirillss/relics/entities/StalactiteEntity.java index 42d4dd99..d33f3626 100644 --- a/src/main/java/it/hurts/sskirillss/relics/entities/StalactiteEntity.java +++ b/src/main/java/it/hurts/sskirillss/relics/entities/StalactiteEntity.java @@ -8,8 +8,7 @@ import lombok.Setter; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; +import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; @@ -22,9 +21,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.EntityHitResult; -import net.minecraftforge.network.NetworkHooks; -import javax.annotation.Nonnull; import java.awt.*; public class StalactiteEntity extends ThrowableProjectile { @@ -93,13 +90,13 @@ protected void onHitEntity(EntityHitResult result) { } if (mayContinue) - entity.addEffect(new MobEffectInstance(EffectRegistry.STUN.get(), Math.round(stun), 0, true, false)); + entity.addEffect(new MobEffectInstance(EffectRegistry.STUN, Math.round(stun), 0, true, false)); this.discard(); } @Override - protected void defineSynchedData() { + protected void defineSynchedData(SynchedEntityData.Builder builder) { } @@ -120,9 +117,9 @@ public boolean isPushedByFluid() { return false; } - @Nonnull - @Override - public Packet getAddEntityPacket() { - return NetworkHooks.getEntitySpawningPacket(this); - } +// @Nonnull +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/ThrownRelicExperienceBottle.java b/src/main/java/it/hurts/sskirillss/relics/entities/ThrownRelicExperienceBottle.java index 02b4c5b3..0ac3143f 100644 --- a/src/main/java/it/hurts/sskirillss/relics/entities/ThrownRelicExperienceBottle.java +++ b/src/main/java/it/hurts/sskirillss/relics/entities/ThrownRelicExperienceBottle.java @@ -2,18 +2,15 @@ import it.hurts.sskirillss.relics.init.EntityRegistry; import it.hurts.sskirillss.relics.init.ItemRegistry; -import net.minecraft.network.protocol.Packet; -import net.minecraft.network.protocol.game.ClientGamePacketListener; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.projectile.ThrowableItemProjectile; import net.minecraft.world.item.Item; -import net.minecraft.world.item.alchemy.PotionUtils; +import net.minecraft.world.item.alchemy.PotionContents; import net.minecraft.world.item.alchemy.Potions; import net.minecraft.world.level.Level; import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.network.NetworkHooks; public class ThrownRelicExperienceBottle extends ThrowableItemProjectile { public ThrownRelicExperienceBottle(EntityType type, Level level) { @@ -26,8 +23,8 @@ protected Item getDefaultItem() { } @Override - protected float getGravity() { - return 0.07F; + protected double getDefaultGravity() { + return 0.07D; } @Override @@ -35,7 +32,7 @@ protected void onHit(HitResult result) { super.onHit(result); if (this.level() instanceof ServerLevel) { - this.level().levelEvent(2002, this.blockPosition(), PotionUtils.getColor(Potions.LUCK)); + this.level().levelEvent(2002, this.blockPosition(), PotionContents.getColor(Potions.LUCK)); int steps = 10 + random.nextInt(10); @@ -57,8 +54,8 @@ protected void onHit(HitResult result) { } } - @Override - public Packet getAddEntityPacket() { - return NetworkHooks.getEntitySpawningPacket(this); - } +// @Override +// public Packet getAddEntityPacket() { +// return NetworkHooks.getEntitySpawningPacket(this); +// } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/entities/misc/ITargetableEntity.java b/src/main/java/it/hurts/sskirillss/relics/entities/misc/ITargetableEntity.java new file mode 100644 index 00000000..af7ae7da --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/entities/misc/ITargetableEntity.java @@ -0,0 +1,12 @@ +package it.hurts.sskirillss.relics.entities.misc; + +import net.minecraft.world.entity.LivingEntity; + +import javax.annotation.Nullable; + +public interface ITargetableEntity { + @Nullable + LivingEntity getTarget(); + + void setTarget(LivingEntity target); +} diff --git a/src/main/java/it/hurts/sskirillss/relics/init/BadgeRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/BadgeRegistry.java new file mode 100644 index 00000000..c1e7436f --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/init/BadgeRegistry.java @@ -0,0 +1,31 @@ +package it.hurts.sskirillss.relics.init; + +import it.hurts.sskirillss.relics.badges.ability.*; +import it.hurts.sskirillss.relics.badges.base.AbilityBadge; +import it.hurts.sskirillss.relics.badges.base.AbstractBadge; +import it.hurts.sskirillss.relics.badges.base.RelicBadge; +import it.hurts.sskirillss.relics.badges.relic.FlawlessRelicBadge; +import it.hurts.sskirillss.relics.utils.Reference; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredRegister; + +import java.util.function.Supplier; + +public class BadgeRegistry { + public static final DeferredRegister BADGES = DeferredRegister.create(RegistryRegistry.BADGE_REGISTRY, Reference.MODID); + + public static final Supplier SILENCE = BADGES.register("silence", SilenceBadge::new); + public static final Supplier OBLIVION = BADGES.register("oblivion", OblivionBadge::new); + public static final Supplier FLAWLESS_ABILITY = BADGES.register("flawless_ability", FlawlessAbilityBadge::new); + public static final Supplier INSTANTANEOUS = BADGES.register("instantaneous", InstantaneousBadge::new); + public static final Supplier INTERRUPTIBLE = BADGES.register("interruptible", InterruptibleBadge::new); + public static final Supplier CYCLICAL = BADGES.register("cyclical", CyclicalBadge::new); + public static final Supplier TOGGLEABLE = BADGES.register("toggleable", ToggleableBadge::new); + public static final Supplier CHARGEABLE = BADGES.register("chargeable", ChargeableBadge::new); + + public static final Supplier FLAWLESS_RELIC = BADGES.register("flawless_relic", FlawlessRelicBadge::new); + + public static void register(IEventBus bus) { + BADGES.register(bus); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/BlockRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/BlockRegistry.java index 94e9a6b1..577eff5d 100644 --- a/src/main/java/it/hurts/sskirillss/relics/init/BlockRegistry.java +++ b/src/main/java/it/hurts/sskirillss/relics/init/BlockRegistry.java @@ -1,29 +1,36 @@ package it.hurts.sskirillss.relics.init; +import it.hurts.sskirillss.relics.blocks.PhantomBlock; import it.hurts.sskirillss.relics.blocks.ResearchingTableBlock; import it.hurts.sskirillss.relics.items.BlockItemBase; import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegistryObject; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; -@Mod.EventBusSubscriber(modid = Reference.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) public class BlockRegistry { - private static final DeferredRegister BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, Reference.MODID); - public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, Reference.MODID); + private static final DeferredRegister BLOCKS = DeferredRegister.create(BuiltInRegistries.BLOCK, Reference.MODID); + public static final DeferredRegister ITEMS = DeferredRegister.create(BuiltInRegistries.ITEM, Reference.MODID); - public static final RegistryObject RESEARCHING_TABLE = BLOCKS.register("researching_table", ResearchingTableBlock::new); + public static final DeferredHolder RESEARCHING_TABLE = BLOCKS.register("researching_table", () -> new ResearchingTableBlock(BlockBehaviour.Properties.of() + .lightLevel((s) -> 15) + .strength(1.5F) + .sound(SoundType.WOOD) + .noOcclusion())); - public static void register() { - BLOCKS.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static final DeferredHolder PHANTOM_BLOCK = BLOCKS.register("phantom_block", PhantomBlock::new); - for (RegistryObject block : BLOCKS.getEntries()) + public static void register(IEventBus bus) { + BLOCKS.register(bus); + + for (DeferredHolder block : BLOCKS.getEntries()) ITEMS.register(block.getId().getPath(), () -> new BlockItemBase(block.get(), new Item.Properties())); - ITEMS.register(FMLJavaModLoadingContext.get().getModEventBus()); + ITEMS.register(bus); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/CapabilityRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/CapabilityRegistry.java deleted file mode 100644 index aa0f0b04..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/init/CapabilityRegistry.java +++ /dev/null @@ -1,47 +0,0 @@ -package it.hurts.sskirillss.relics.init; - -import it.hurts.sskirillss.relics.capability.entries.IRelicsCapability; -import it.hurts.sskirillss.relics.utils.Reference; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.minecraftforge.common.capabilities.Capability; -import net.minecraftforge.common.capabilities.CapabilityManager; -import net.minecraftforge.common.capabilities.CapabilityToken; -import net.minecraftforge.common.capabilities.RegisterCapabilitiesEvent; -import net.minecraftforge.event.AttachCapabilitiesEvent; -import net.minecraftforge.event.entity.player.PlayerEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; - -@Mod.EventBusSubscriber -public class CapabilityRegistry { - public static final Capability DATA = CapabilityManager.get(new CapabilityToken<>() { - }); - - @SubscribeEvent - public static void onCapabilityRegistry(RegisterCapabilitiesEvent event) { - event.register(IRelicsCapability.RelicsCapability.class); - } - - @SubscribeEvent - public static void onCapabilityAttach(final AttachCapabilitiesEvent event) { - if (event.getObject() instanceof Player) - event.addCapability(new ResourceLocation(Reference.MODID, "data"), new IRelicsCapability.RelicsCapabilityProvider()); - } - - @SubscribeEvent - public static void onPlayerClone(PlayerEvent.Clone event) { - if (!event.isWasDeath()) - return; - - Player oldPlayer = event.getOriginal(); - Player newPlayer = event.getEntity(); - - oldPlayer.reviveCaps(); - - newPlayer.getCapability(DATA).orElse(null).deserializeNBT(oldPlayer.getCapability(DATA).orElse(null).serializeNBT()); - - oldPlayer.invalidateCaps(); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/CodecRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/CodecRegistry.java deleted file mode 100644 index 15abbf75..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/init/CodecRegistry.java +++ /dev/null @@ -1,22 +0,0 @@ -package it.hurts.sskirillss.relics.init; - -import com.mojang.serialization.Codec; -import it.hurts.sskirillss.relics.level.RelicLootModifier; -import it.hurts.sskirillss.relics.utils.Reference; -import net.minecraftforge.common.loot.IGlobalLootModifier; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegistryObject; - -@Mod.EventBusSubscriber(modid = Reference.MODID) -public class CodecRegistry { - public static final DeferredRegister> CODECS = DeferredRegister.create(ForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, Reference.MODID); - - public static final RegistryObject> RELIC_LOOT = CODECS.register("relic_loot", () -> RelicLootModifier.CODEC); - - public static void register() { - CODECS.register(FMLJavaModLoadingContext.get().getModEventBus()); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/CommandRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/CommandRegistry.java index 2bdefc9b..d86656ec 100644 --- a/src/main/java/it/hurts/sskirillss/relics/init/CommandRegistry.java +++ b/src/main/java/it/hurts/sskirillss/relics/init/CommandRegistry.java @@ -8,22 +8,22 @@ import net.minecraft.commands.synchronization.ArgumentTypeInfos; import net.minecraft.commands.synchronization.SingletonArgumentInfo; import net.minecraft.core.registries.Registries; -import net.minecraftforge.event.RegisterCommandsEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.RegistryObject; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.RegisterCommandsEvent; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; -@Mod.EventBusSubscriber(modid = Reference.MODID, bus = Mod.EventBusSubscriber.Bus.FORGE) +@EventBusSubscriber(modid = Reference.MODID, bus = EventBusSubscriber.Bus.GAME) public class CommandRegistry { private static final DeferredRegister> COMMAND_ARGUMENTS = DeferredRegister.create(Registries.COMMAND_ARGUMENT_TYPE, Reference.MODID); - public static final RegistryObject> RELIC_ABILITY = COMMAND_ARGUMENTS.register("relic_ability", () -> ArgumentTypeInfos.registerByClass(RelicAbilityArgument.class, SingletonArgumentInfo.contextFree(RelicAbilityArgument::ability))); - public static final RegistryObject> RELIC_ABILITY_STAT = COMMAND_ARGUMENTS.register("relic_ability_stat", () -> ArgumentTypeInfos.registerByClass(RelicAbilityStatArgument.class, SingletonArgumentInfo.contextFree(RelicAbilityStatArgument::abilityStat))); + public static final DeferredHolder, ArgumentTypeInfo> RELIC_ABILITY = COMMAND_ARGUMENTS.register("relic_ability", () -> ArgumentTypeInfos.registerByClass(RelicAbilityArgument.class, SingletonArgumentInfo.contextFree(RelicAbilityArgument::ability))); + public static final DeferredHolder, ArgumentTypeInfo> RELIC_ABILITY_STAT = COMMAND_ARGUMENTS.register("relic_ability_stat", () -> ArgumentTypeInfos.registerByClass(RelicAbilityStatArgument.class, SingletonArgumentInfo.contextFree(RelicAbilityStatArgument::abilityStat))); - public static void register() { - COMMAND_ARGUMENTS.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void register(IEventBus bus) { + COMMAND_ARGUMENTS.register(bus); } @SubscribeEvent diff --git a/src/main/java/it/hurts/sskirillss/relics/init/ConfigRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/ConfigRegistry.java new file mode 100644 index 00000000..ea10c882 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/init/ConfigRegistry.java @@ -0,0 +1,38 @@ +package it.hurts.sskirillss.relics.init; + +import it.hurts.octostudios.octolib.modules.config.ConfigManager; +import it.hurts.sskirillss.relics.config.LootConfigData; +import it.hurts.sskirillss.relics.config.RelicsConfigData; +import it.hurts.sskirillss.relics.config.data.RelicConfigData; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.item.Item; + +import java.util.Map; + +public class ConfigRegistry { + public static final RelicsConfigData RELICS_CONFIG = new RelicsConfigData(); + public static final LootConfigData LOOT_CONFIG = new LootConfigData(); + + public static void register() { + ConfigManager.registerConfig(Reference.MODID, RELICS_CONFIG); + + if (RELICS_CONFIG.isEnabledExtendedConfigs()) { + ConfigManager.registerConfig(Reference.MODID + "/loot", LOOT_CONFIG); + + for (Map.Entry, Item> entry : BuiltInRegistries.ITEM.entrySet()) { + if (!(entry.getValue() instanceof IRelicItem relic)) + continue; + + var data = relic.constructDefaultConfigData(new RelicConfigData(relic)); + + if (data == null) + continue; + + ConfigManager.registerConfig(relic.getConfigRoute() + "/relics/" + entry.getKey().location().getPath(), data); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/CreativeTabRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/CreativeTabRegistry.java index 32f4a836..edd8c506 100644 --- a/src/main/java/it/hurts/sskirillss/relics/init/CreativeTabRegistry.java +++ b/src/main/java/it/hurts/sskirillss/relics/init/CreativeTabRegistry.java @@ -1,46 +1,48 @@ package it.hurts.sskirillss.relics.init; -import it.hurts.sskirillss.relics.items.relics.base.ICreativeTabEntry; +import it.hurts.sskirillss.relics.items.misc.CreativeContentConstructor; +import it.hurts.sskirillss.relics.items.misc.ICreativeTabContent; import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.Item; -import net.minecraftforge.event.BuildCreativeModeTabContentsEvent; -import net.minecraftforge.eventbus.api.IEventBus; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegistryObject; - -@Mod.EventBusSubscriber +import net.neoforged.bus.api.IEventBus; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; + +@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD) public class CreativeTabRegistry { public static final DeferredRegister CREATIVE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, Reference.MODID); - public static final RegistryObject RELICS_TAB = CREATIVE_TABS.register("relics", () -> CreativeModeTab.builder() + public static final DeferredHolder RELICS_TAB = CREATIVE_TABS.register("relics", () -> CreativeModeTab.builder() .title(Component.translatable("itemGroup.relics")) .icon(() -> ItemRegistry.BASTION_RING.get().getDefaultInstance()) .build()); - public static void register() { - IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus(); - + public static void register(IEventBus bus) { CREATIVE_TABS.register(bus); - - bus.addListener(CreativeTabRegistry::fillCreativeTabs); } - private static void fillCreativeTabs(BuildCreativeModeTabContentsEvent event) { - if (event.getTab() == RELICS_TAB.get()) { - for (Item item : ForgeRegistries.ITEMS.getValues()) { - if (item instanceof ICreativeTabEntry entry) - event.acceptAll(entry.processCreativeTab()); - } + @SubscribeEvent + public static void fillCreativeTabs(BuildCreativeModeTabContentsEvent event) { + for (Item item : BuiltInRegistries.ITEM.stream().toList()) { + if (!(item instanceof ICreativeTabContent entry)) + continue; + + var constructor = new CreativeContentConstructor(); + + entry.gatherCreativeTabContent(constructor); + + for (var content : constructor.getEntries()) { + if (event.getTab() != content.getTab()) + continue; - for (RegistryObject object : BlockRegistry.ITEMS.getEntries()) { - if (object.get() instanceof ICreativeTabEntry entry) - event.acceptAll(entry.processCreativeTab()); + event.acceptAll(content.getStacks(), content.getVisibility()); } } } diff --git a/src/main/java/it/hurts/sskirillss/relics/init/DataComponentRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/DataComponentRegistry.java new file mode 100644 index 00000000..0223e9aa --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/init/DataComponentRegistry.java @@ -0,0 +1,122 @@ +package it.hurts.sskirillss.relics.init; + +import com.mojang.serialization.Codec; +import it.hurts.sskirillss.relics.components.DataComponent; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.WorldPosition; +import net.minecraft.core.component.DataComponentType; +import net.minecraft.core.registries.Registries; +import net.minecraft.world.level.block.state.BlockState; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.ModifyDefaultComponentsEvent; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; + +@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD) +public class DataComponentRegistry { + public static final DeferredRegister> DATA_COMPONENTS = DeferredRegister.create(Registries.DATA_COMPONENT_TYPE, Reference.MODID); + + // TODO: Rename to RELIC_DATA or just RELIC instead of DATA + @Deprecated(since = "1.21", forRemoval = true) + public static final DeferredHolder, DataComponentType> DATA = DATA_COMPONENTS.register("data", + () -> DataComponentType.builder() + .persistent(DataComponent.CODEC) + .build() + ); + + public static final DeferredHolder, DataComponentType> CHARGE = DATA_COMPONENTS.register("charge", + () -> DataComponentType.builder() + .persistent(Codec.INT) + .build() + ); + + public static final DeferredHolder, DataComponentType> TOGGLED = DATA_COMPONENTS.register("toggled", + () -> DataComponentType.builder() + .persistent(Codec.BOOL) + .build() + ); + + public static final DeferredHolder, DataComponentType> TIME = DATA_COMPONENTS.register("time", + () -> DataComponentType.builder() + .persistent(Codec.INT) + .build() + ); + + public static final DeferredHolder, DataComponentType> COOLDOWN = DATA_COMPONENTS.register("cooldown", + () -> DataComponentType.builder() + .persistent(Codec.INT) + .build() + ); + + public static final DeferredHolder, DataComponentType> COUNT = DATA_COMPONENTS.register("count", + () -> DataComponentType.builder() + .persistent(Codec.INT) + .build() + ); + + public static final DeferredHolder, DataComponentType> PROGRESS = DATA_COMPONENTS.register("progress", + () -> DataComponentType.builder() + .persistent(Codec.INT) + .build() + ); + + public static final DeferredHolder, DataComponentType> TARGET = DATA_COMPONENTS.register("target", + () -> DataComponentType.builder() + .persistent(Codec.STRING) + .build() + ); + + public static final DeferredHolder, DataComponentType> SPEED = DATA_COMPONENTS.register("speed", + () -> DataComponentType.builder() + .persistent(Codec.DOUBLE) + .build() + ); + + public static final DeferredHolder, DataComponentType> RADIUS = DATA_COMPONENTS.register("radius", + () -> DataComponentType.builder() + .persistent(Codec.DOUBLE) + .build() + ); + + public static final DeferredHolder, DataComponentType> HEIGHT = DATA_COMPONENTS.register("height", + () -> DataComponentType.builder() + .persistent(Codec.DOUBLE) + .build() + ); + + public static final DeferredHolder, DataComponentType> WORLD_POSITION = DATA_COMPONENTS.register("world_position", + () -> DataComponentType.builder() + .persistent(WorldPosition.CODEC) + .build() + ); + + public static final DeferredHolder, DataComponentType> PORTAL = DATA_COMPONENTS.register("portal", + () -> DataComponentType.builder() + .persistent(Codec.STRING) + .build() + ); + + public static final DeferredHolder, DataComponentType> BLOCK_STATE = DATA_COMPONENTS.register("block_state", + () -> DataComponentType.builder() + .persistent(BlockState.CODEC) + .build() + ); + + public static final DeferredHolder, DataComponentType> MODE = DATA_COMPONENTS.register("mode", + () -> DataComponentType.builder() + .persistent(Codec.INT) + .build() + ); + + public static void register(IEventBus bus) { + DATA_COMPONENTS.register(bus); + } + + @SubscribeEvent + public static void modifyComponents(ModifyDefaultComponentsEvent event) { + event.modifyMatching(item -> item instanceof IRelicItem, builder -> builder.set(DATA.get(), DataComponent.EMPTY)); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/DispenserBehaviorRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/DispenserBehaviorRegistry.java index 04afceaf..e517542b 100644 --- a/src/main/java/it/hurts/sskirillss/relics/init/DispenserBehaviorRegistry.java +++ b/src/main/java/it/hurts/sskirillss/relics/init/DispenserBehaviorRegistry.java @@ -1,34 +1,9 @@ package it.hurts.sskirillss.relics.init; -import it.hurts.sskirillss.relics.entities.ThrownRelicExperienceBottle; -import net.minecraft.Util; -import net.minecraft.core.Position; -import net.minecraft.core.dispenser.AbstractProjectileDispenseBehavior; -import net.minecraft.world.entity.projectile.Projectile; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; import net.minecraft.world.level.block.DispenserBlock; public class DispenserBehaviorRegistry { public static void register() { - DispenserBlock.registerBehavior(ItemRegistry.RELIC_EXPERIENCE_BOTTLE.get(), new AbstractProjectileDispenseBehavior() { - @Override - protected Projectile getProjectile(Level level, Position position, ItemStack stack) { - return Util.make(new ThrownRelicExperienceBottle(EntityRegistry.THROWN_RELIC_EXPERIENCE_BOTTLE.get(), level), (entity) -> { - entity.setPos(position.x(), position.y(), position.z()); - entity.setItem(stack); - }); - } - - @Override - protected float getUncertainty() { - return super.getUncertainty() * 0.5F; - } - - @Override - protected float getPower() { - return super.getPower() * 1.25F; - } - }); + DispenserBlock.registerProjectileBehavior(ItemRegistry.RELIC_EXPERIENCE_BOTTLE.get()); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/EffectRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/EffectRegistry.java index c8897a5a..0efe6f50 100644 --- a/src/main/java/it/hurts/sskirillss/relics/init/EffectRegistry.java +++ b/src/main/java/it/hurts/sskirillss/relics/init/EffectRegistry.java @@ -2,25 +2,24 @@ import it.hurts.sskirillss.relics.effects.*; import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.effect.MobEffect; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegistryObject; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; -@Mod.EventBusSubscriber(modid = Reference.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) public class EffectRegistry { - public static final DeferredRegister EFFECTS = DeferredRegister.create(ForgeRegistries.MOB_EFFECTS, Reference.MODID); + public static final DeferredRegister EFFECTS = DeferredRegister.create(BuiltInRegistries.MOB_EFFECT, Reference.MODID); - public static final RegistryObject STUN = EFFECTS.register("stun", StunEffect::new); - public static final RegistryObject CONFUSION = EFFECTS.register("confusion", ConfusionEffect::new); - public static final RegistryObject PARALYSIS = EFFECTS.register("paralysis", ParalysisEffect::new); - public static final RegistryObject VANISHING = EFFECTS.register("vanishing", VanishingEffect::new); - public static final RegistryObject ANTI_HEAL = EFFECTS.register("anti_heal", AntiHealEffect::new); - public static final RegistryObject BLEEDING = EFFECTS.register("bleeding", BleedingEffect::new); + public static final DeferredHolder IMMORTALITY = EFFECTS.register("immortality", ImmortalityEffect::new); + public static final DeferredHolder CONFUSION = EFFECTS.register("confusion", ConfusionEffect::new); + public static final DeferredHolder PARALYSIS = EFFECTS.register("paralysis", ParalysisEffect::new); + public static final DeferredHolder VANISHING = EFFECTS.register("vanishing", VanishingEffect::new); + public static final DeferredHolder ANTI_HEAL = EFFECTS.register("anti_heal", AntiHealEffect::new); + public static final DeferredHolder BLEEDING = EFFECTS.register("bleeding", BleedingEffect::new); + public static final DeferredHolder STUN = EFFECTS.register("stun", StunEffect::new); - public static void register() { - EFFECTS.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void register(IEventBus bus) { + EFFECTS.register(bus); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/EntityRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/EntityRegistry.java index adbf6087..21e220b9 100644 --- a/src/main/java/it/hurts/sskirillss/relics/init/EntityRegistry.java +++ b/src/main/java/it/hurts/sskirillss/relics/init/EntityRegistry.java @@ -1,91 +1,96 @@ package it.hurts.sskirillss.relics.init; -import it.hurts.sskirillss.relics.entities.ThrownRelicExperienceBottle; import it.hurts.sskirillss.relics.entities.*; import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.MobCategory; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegistryObject; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; public class EntityRegistry { - private static final DeferredRegister> ENTITIES = DeferredRegister.create(ForgeRegistries.ENTITY_TYPES, Reference.MODID); + private static final DeferredRegister> ENTITIES = DeferredRegister.create(BuiltInRegistries.ENTITY_TYPE, Reference.MODID); - public static final RegistryObject> SHADOW_GLAIVE = ENTITIES.register("shadow_glaive", () -> + public static final DeferredHolder, EntityType> SHADOW_GLAIVE = ENTITIES.register("shadow_glaive", () -> EntityType.Builder.of(ShadowGlaiveEntity::new, MobCategory.MISC) .sized(0.9F, 0.1F) .build("shadow_glaive") ); - public static final RegistryObject> BLOCK_SIMULATION = ENTITIES.register("block_simulation", () -> + public static final DeferredHolder, EntityType> BLOCK_SIMULATION = ENTITIES.register("block_simulation", () -> EntityType.Builder.of(BlockSimulationEntity::new, MobCategory.MISC) .sized(1F, 1F) .build("block_simulation") ); - public static final RegistryObject> SHOCKWAVE = ENTITIES.register("shockwave", () -> + public static final DeferredHolder, EntityType> SHOCKWAVE = ENTITIES.register("shockwave", () -> EntityType.Builder.of(ShockwaveEntity::new, MobCategory.MISC) .sized(1F, 0.1F) .build("shockwave") ); - public static final RegistryObject> LIFE_ESSENCE = ENTITIES.register("life_essence", () -> + public static final DeferredHolder, EntityType> LIFE_ESSENCE = ENTITIES.register("life_essence", () -> EntityType.Builder.of(LifeEssenceEntity::new, MobCategory.MISC) - .sized(0.5F, 0.5F) + .sized(0.25F, 0.25F) .build("life_essence") ); - public static final RegistryObject> STALACTITE = ENTITIES.register("stalactite", () -> + public static final DeferredHolder, EntityType> DEATH_ESSENCE = ENTITIES.register("death_essence", () -> + EntityType.Builder.of(DeathEssenceEntity::new, MobCategory.MISC) + .sized(0.25F, 0.25F) + .build("death_essence") + ); + + public static final DeferredHolder, EntityType> STALACTITE = ENTITIES.register("stalactite", () -> EntityType.Builder.of(StalactiteEntity::new, MobCategory.MISC) .sized(0.35F, 0.35F) .build("stalactite") ); - public static final RegistryObject> DISSECTION = ENTITIES.register("dissection", () -> + public static final DeferredHolder, EntityType> DISSECTION = ENTITIES.register("dissection", () -> EntityType.Builder.of(DissectionEntity::new, MobCategory.MISC) .sized(3F, 3F) .build("dissection") ); - public static final RegistryObject> SPORE = ENTITIES.register("spore", () -> + public static final DeferredHolder, EntityType> SPORE = ENTITIES.register("spore", () -> EntityType.Builder.of(SporeEntity::new, MobCategory.MISC) - .sized(0.2F, 0.2F) + .sized(0.3F, 0.3F) .build("spore") ); - public static final RegistryObject> SHADOW_SAW = ENTITIES.register("shadow_saw", () -> - EntityType.Builder.of(ShadowSawEntity::new, MobCategory.MISC) - .sized(2F, 0.5F) - .build("shadow_saw") - ); - - public static final RegistryObject> SOLID_SNOWBALL = ENTITIES.register("solid_snowball", () -> + public static final DeferredHolder, EntityType> SOLID_SNOWBALL = ENTITIES.register("solid_snowball", () -> EntityType.Builder.of(SolidSnowballEntity::new, MobCategory.MISC) .sized(0.5F, 0.5F) .build("solid_snowball") ); - public static final RegistryObject> ARROW_RAIN = ENTITIES.register("arrow_rain", () -> - EntityType.Builder.of(ArrowRainEntity::new, MobCategory.MISC) - .sized(1F, 1F) - .build("arrow_rain") - ); +// public static final DeferredHolder, EntityType> ARROW_RAIN = ENTITIES.register("arrow_rain", () -> +// EntityType.Builder.of(ArrowRainEntity::new, MobCategory.MISC) +// .sized(1F, 1F) +// .build("arrow_rain") +// ); - public static final RegistryObject> RELIC_EXPERIENCE_ORB = ENTITIES.register("relic_experience_orb", () -> + public static final DeferredHolder, EntityType> RELIC_EXPERIENCE_ORB = ENTITIES.register("relic_experience_orb", () -> EntityType.Builder.of(RelicExperienceOrbEntity::new, MobCategory.MISC) .sized(0.3F, 0.3F) .build("relic_experience_orb") ); - public static final RegistryObject> THROWN_RELIC_EXPERIENCE_BOTTLE = ENTITIES.register("thrown_relic_experience_bottle", () -> + public static final DeferredHolder, EntityType> THROWN_RELIC_EXPERIENCE_BOTTLE = ENTITIES.register("thrown_relic_experience_bottle", () -> EntityType.Builder.of(ThrownRelicExperienceBottle::new, MobCategory.MISC) .sized(0.25F, 0.25F) .build("thrown_relic_experience_bottle") ); - public static void register() { - ENTITIES.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static final DeferredHolder, EntityType> CHAIR = ENTITIES.register("chair", () -> + EntityType.Builder.of(ChairEntity::new, MobCategory.MISC) + .sized(0F, 0F) + .build("chair") + ); + + public static void register(IEventBus bus) { + ENTITIES.register(bus); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/HotkeyRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/HotkeyRegistry.java index 75f906c7..1767c154 100644 --- a/src/main/java/it/hurts/sskirillss/relics/init/HotkeyRegistry.java +++ b/src/main/java/it/hurts/sskirillss/relics/init/HotkeyRegistry.java @@ -2,21 +2,24 @@ import it.hurts.sskirillss.relics.utils.Reference; import net.minecraft.client.KeyMapping; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.RegisterKeyMappingsEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RegisterKeyMappingsEvent; import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT_ALT; +import static org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT_SHIFT; -@Mod.EventBusSubscriber(modid = Reference.MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +@EventBusSubscriber(modid = Reference.MODID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public class HotkeyRegistry { private static final String CATEGORY = "Relics"; - public static final KeyMapping ABILITY_LIST = new KeyMapping("key.relics.ability_list", GLFW_KEY_LEFT_ALT, CATEGORY); + public static final KeyMapping ACTIVE_ABILITIES_LIST = new KeyMapping("key.relics.active_abilities_list", GLFW_KEY_LEFT_ALT, CATEGORY); + public static final KeyMapping RESEARCH_RELIC = new KeyMapping("key.relics.research_relic", GLFW_KEY_LEFT_SHIFT, CATEGORY); @SubscribeEvent public static void onKeybindingRegistry(RegisterKeyMappingsEvent event) { - event.register(ABILITY_LIST); + event.register(ACTIVE_ABILITIES_LIST); + event.register(RESEARCH_RELIC); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/ItemRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/ItemRegistry.java index 4b22758e..08a16abf 100644 --- a/src/main/java/it/hurts/sskirillss/relics/init/ItemRegistry.java +++ b/src/main/java/it/hurts/sskirillss/relics/init/ItemRegistry.java @@ -3,7 +3,6 @@ import it.hurts.sskirillss.relics.items.RelicExperienceBottleItem; import it.hurts.sskirillss.relics.items.SolidSnowballItem; import it.hurts.sskirillss.relics.items.relics.*; -import it.hurts.sskirillss.relics.items.relics.back.ArrowQuiverItem; import it.hurts.sskirillss.relics.items.relics.back.ElytraBoosterItem; import it.hurts.sskirillss.relics.items.relics.back.MidnightRobeItem; import it.hurts.sskirillss.relics.items.relics.base.RelicItem; @@ -18,53 +17,57 @@ import it.hurts.sskirillss.relics.items.relics.necklace.JellyfishNecklaceItem; import it.hurts.sskirillss.relics.items.relics.necklace.ReflectionNecklaceItem; import it.hurts.sskirillss.relics.items.relics.ring.BastionRingItem; +import it.hurts.sskirillss.relics.items.relics.ring.LeafyRingItem; import it.hurts.sskirillss.relics.items.relics.ring.ChorusInhibitorItem; -import it.hurts.sskirillss.relics.items.relics.talisman.SporeSackItem; +import it.hurts.sskirillss.relics.items.relics.charm.SporeSackItem; import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.Item; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegistryObject; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; -@Mod.EventBusSubscriber(modid = Reference.MODID) public class ItemRegistry { - public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, Reference.MODID); + public static final DeferredRegister ITEMS = DeferredRegister.create(BuiltInRegistries.ITEM, Reference.MODID); - public static final RegistryObject SOLID_SNOWBALL = ITEMS.register("solid_snowball", SolidSnowballItem::new); - public static final RegistryObject RELIC_EXPERIENCE_BOTTLE = ITEMS.register("relic_experience_bottle", RelicExperienceBottleItem::new); + public static final DeferredHolder SOLID_SNOWBALL = ITEMS.register("solid_snowball", SolidSnowballItem::new); + public static final DeferredHolder RELIC_EXPERIENCE_BOTTLE = ITEMS.register("relic_experience_bottle", RelicExperienceBottleItem::new); - public static final RegistryObject SPATIAL_SIGN = ITEMS.register("spatial_sign", SpatialSignItem::new); - public static final RegistryObject REFLECTION_NECKLACE = ITEMS.register("reflection_necklace", ReflectionNecklaceItem::new); - public static final RegistryObject MAGMA_WALKER = ITEMS.register("magma_walker", MagmaWalkerItem::new); - public static final RegistryObject AQUA_WALKER = ITEMS.register("aqua_walker", AquaWalkerItem::new); - public static final RegistryObject MIDNIGHT_ROBE = ITEMS.register("midnight_robe", MidnightRobeItem::new); - public static final RegistryObject DROWNED_BELT = ITEMS.register("drowned_belt", DrownedBeltItem::new); - public static final RegistryObject JELLYFISH_NECKLACE = ITEMS.register("jellyfish_necklace", JellyfishNecklaceItem::new); - public static final RegistryObject HUNTER_BELT = ITEMS.register("hunter_belt", HunterBeltItem::new); - public static final RegistryObject RAGE_GLOVE = ITEMS.register("rage_glove", RageGloveItem::new); - public static final RegistryObject ICE_SKATES = ITEMS.register("ice_skates", IceSkatesItem::new); - public static final RegistryObject BASTION_RING = ITEMS.register("bastion_ring", BastionRingItem::new); - public static final RegistryObject CHORUS_INHIBITOR = ITEMS.register("chorus_inhibitor", ChorusInhibitorItem::new); - public static final RegistryObject ARROW_QUIVER = ITEMS.register("arrow_quiver", ArrowQuiverItem::new); - public static final RegistryObject SPACE_DISSECTOR = ITEMS.register("space_dissector", SpaceDissectorItem::new); - public static final RegistryObject HOLY_LOCKET = ITEMS.register("holy_locket", HolyLocketItem::new); - public static final RegistryObject ENDER_HAND = ITEMS.register("enders_hand", EnderHandItem::new); - public static final RegistryObject ELYTRA_BOOSTER = ITEMS.register("elytra_booster", ElytraBoosterItem::new); - public static final RegistryObject MAGIC_MIRROR = ITEMS.register("magic_mirror", MagicMirrorItem::new); - public static final RegistryObject ICE_BREAKER = ITEMS.register("ice_breaker", IceBreakerItem::new); - public static final RegistryObject BLAZING_FLASK = ITEMS.register("blazing_flask", BlazingFlaskItem::new); - public static final RegistryObject SPORE_SACK = ITEMS.register("spore_sack", SporeSackItem::new); - public static final RegistryObject SHADOW_GLAIVE = ITEMS.register("shadow_glaive", ShadowGlaiveItem::new); - public static final RegistryObject ROLLER_SKATES = ITEMS.register("roller_skates", RollerSkatesItem::new); - public static final RegistryObject INFINITY_HAM = ITEMS.register("infinity_ham", InfinityHamItem::new); - public static final RegistryObject LEATHER_BELT = ITEMS.register("leather_belt", LeatherBeltItem::new); - public static final RegistryObject HORSE_FLUTE = ITEMS.register("horse_flute", HorseFluteItem::new); - public static final RegistryObject WOOL_MITTEN = ITEMS.register("wool_mitten", WoolMittenItem::new); - public static final RegistryObject AMPHIBIAN_BOOT = ITEMS.register("amphibian_boot", AmphibianBootItem::new); + // TODO: public static final DeferredHolder SPATIAL_SIGN = ITEMS.register("spatial_sign", SpatialSignItem::new); + public static final DeferredHolder REFLECTION_NECKLACE = ITEMS.register("reflection_necklace", ReflectionNecklaceItem::new); + public static final DeferredHolder MAGMA_WALKER = ITEMS.register("magma_walker", MagmaWalkerItem::new); + public static final DeferredHolder AQUA_WALKER = ITEMS.register("aqua_walker", AquaWalkerItem::new); + public static final DeferredHolder MIDNIGHT_ROBE = ITEMS.register("midnight_robe", MidnightRobeItem::new); + public static final DeferredHolder DROWNED_BELT = ITEMS.register("drowned_belt", DrownedBeltItem::new); + public static final DeferredHolder JELLYFISH_NECKLACE = ITEMS.register("jellyfish_necklace", JellyfishNecklaceItem::new); + public static final DeferredHolder HUNTER_BELT = ITEMS.register("hunter_belt", HunterBeltItem::new); + public static final DeferredHolder RAGE_GLOVE = ITEMS.register("rage_glove", RageGloveItem::new); + public static final DeferredHolder ICE_SKATES = ITEMS.register("ice_skates", IceSkatesItem::new); + public static final DeferredHolder BASTION_RING = ITEMS.register("bastion_ring", BastionRingItem::new); + public static final DeferredHolder CHORUS_INHIBITOR = ITEMS.register("chorus_inhibitor", ChorusInhibitorItem::new); + // TODO: public static final DeferredHolder ARROW_QUIVER = ITEMS.register("arrow_quiver", ArrowQuiverItem::new); + public static final DeferredHolder SPACE_DISSECTOR = ITEMS.register("space_dissector", SpaceDissectorItem::new); + public static final DeferredHolder HOLY_LOCKET = ITEMS.register("holy_locket", HolyLocketItem::new); + public static final DeferredHolder ENDER_HAND = ITEMS.register("enders_hand", EnderHandItem::new); + public static final DeferredHolder ELYTRA_BOOSTER = ITEMS.register("elytra_booster", ElytraBoosterItem::new); + public static final DeferredHolder MAGIC_MIRROR = ITEMS.register("magic_mirror", MagicMirrorItem::new); + public static final DeferredHolder ICE_BREAKER = ITEMS.register("ice_breaker", IceBreakerItem::new); + public static final DeferredHolder BLAZING_FLASK = ITEMS.register("blazing_flask", BlazingFlaskItem::new); + public static final DeferredHolder SPORE_SACK = ITEMS.register("spore_sack", SporeSackItem::new); + public static final DeferredHolder SHADOW_GLAIVE = ITEMS.register("shadow_glaive", ShadowGlaiveItem::new); + public static final DeferredHolder ROLLER_SKATES = ITEMS.register("roller_skates", RollerSkatesItem::new); + public static final DeferredHolder INFINITY_HAM = ITEMS.register("infinity_ham", InfiniteHamItem::new); // TODO: Replace ID with "infinite_ham" + public static final DeferredHolder LEATHER_BELT = ITEMS.register("leather_belt", LeatherBeltItem::new); + // TODO: public static final DeferredHolder HORSE_FLUTE = ITEMS.register("horse_flute", HorseFluteItem::new); + public static final DeferredHolder WOOL_MITTEN = ITEMS.register("wool_mitten", WoolMittenItem::new); + public static final DeferredHolder AMPHIBIAN_BOOT = ITEMS.register("amphibian_boot", AmphibianBootItem::new); - public static void register() { - ITEMS.register(FMLJavaModLoadingContext.get().getModEventBus()); + // NEW GEN + public static final DeferredHolder LEAFY_RING = ITEMS.register("leafy_ring", LeafyRingItem::new); + public static final DeferredHolder PHANTOM_BOOT = ITEMS.register("phantom_boot", PhantomBootItem::new); + public static final DeferredHolder SPRINGY_BOOT = ITEMS.register("springy_boot", SpringyBootItem::new); + + public static void register(IEventBus bus) { + ITEMS.register(bus); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/LootCodecRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/LootCodecRegistry.java new file mode 100644 index 00000000..1cd3a2ab --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/init/LootCodecRegistry.java @@ -0,0 +1,20 @@ +package it.hurts.sskirillss.relics.init; + +import com.mojang.serialization.MapCodec; +import it.hurts.sskirillss.relics.level.RelicLootModifier; +import it.hurts.sskirillss.relics.utils.Reference; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.common.loot.IGlobalLootModifier; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; +import net.neoforged.neoforge.registries.NeoForgeRegistries; + +public class LootCodecRegistry { + public static final DeferredRegister> CODECS = DeferredRegister.create(NeoForgeRegistries.Keys.GLOBAL_LOOT_MODIFIER_SERIALIZERS, Reference.MODID); + + public static final DeferredHolder, MapCodec> RELIC_LOOT = CODECS.register("relic_loot", RelicLootModifier.CODEC); + + public static void register(IEventBus bus) { + CODECS.register(bus); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/ParticleRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/ParticleRegistry.java index 1767c8ca..d1c83ce9 100644 --- a/src/main/java/it/hurts/sskirillss/relics/init/ParticleRegistry.java +++ b/src/main/java/it/hurts/sskirillss/relics/init/ParticleRegistry.java @@ -1,25 +1,29 @@ package it.hurts.sskirillss.relics.init; +import it.hurts.sskirillss.relics.client.particles.BasicColoredParticle; import it.hurts.sskirillss.relics.utils.Reference; import net.minecraft.core.particles.ParticleType; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.RegisterParticleProvidersEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; +import net.minecraft.core.registries.BuiltInRegistries; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RegisterParticleProvidersEvent; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; -@Mod.EventBusSubscriber(modid = Reference.MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +@EventBusSubscriber(modid = Reference.MODID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public class ParticleRegistry { - public static final DeferredRegister> PARTICLES = DeferredRegister.create(ForgeRegistries.PARTICLE_TYPES, Reference.MODID); + public static final DeferredRegister> PARTICLES = DeferredRegister.create(BuiltInRegistries.PARTICLE_TYPE, Reference.MODID); - public static void register() { - PARTICLES.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static final DeferredHolder, BasicColoredParticle.Type> BASIC_COLORED = PARTICLES.register("basic_colored", BasicColoredParticle.Type::new); + + public static void register(IEventBus bus) { + PARTICLES.register(bus); } @SubscribeEvent public static void onParticleRegistry(RegisterParticleProvidersEvent event) { - + event.registerSpriteSet(BASIC_COLORED.get(), BasicColoredParticle.Factory::new); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/RegistryRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/RegistryRegistry.java new file mode 100644 index 00000000..2f477df3 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/init/RegistryRegistry.java @@ -0,0 +1,27 @@ +package it.hurts.sskirillss.relics.init; + +import it.hurts.sskirillss.relics.badges.base.AbstractBadge; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.containers.base.RelicContainer; +import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.core.Registry; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.registries.NewRegistryEvent; +import net.neoforged.neoforge.registries.RegistryBuilder; + +@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD) +public class RegistryRegistry { + public static final ResourceKey> RELIC_CONTAINER_REGISTRY_KEY = ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "relic_containers")); + public static final Registry RELIC_CONTAINER_REGISTRY = new RegistryBuilder<>(RELIC_CONTAINER_REGISTRY_KEY).create(); + + public static final ResourceKey> BADGE_REGISTRY_KEY = ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "badges")); + public static final Registry BADGE_REGISTRY = new RegistryBuilder<>(BADGE_REGISTRY_KEY).create(); + + @SubscribeEvent + public static void registerRegistries(NewRegistryEvent event) { + event.register(RELIC_CONTAINER_REGISTRY); + event.register(BADGE_REGISTRY); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/RelicContainerRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/RelicContainerRegistry.java new file mode 100644 index 00000000..c8557015 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/init/RelicContainerRegistry.java @@ -0,0 +1,21 @@ +package it.hurts.sskirillss.relics.init; + +import it.hurts.sskirillss.relics.items.relics.base.data.cast.containers.CuriosRelicContainer; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.containers.InventoryRelicContainer; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.containers.base.RelicContainer; +import it.hurts.sskirillss.relics.utils.Reference; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredRegister; + +import java.util.function.Supplier; + +public class RelicContainerRegistry { + public static final DeferredRegister RELIC_CONTAINERS = DeferredRegister.create(RegistryRegistry.RELIC_CONTAINER_REGISTRY, Reference.MODID); + + public static final Supplier CURIOS = RELIC_CONTAINERS.register("curios", CuriosRelicContainer::new); + public static final Supplier INVENTORY = RELIC_CONTAINERS.register("inventory", InventoryRelicContainer::new); + + public static void register(IEventBus bus) { + RELIC_CONTAINERS.register(bus); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/RelicsCoreShaders.java b/src/main/java/it/hurts/sskirillss/relics/init/RelicsCoreShaders.java new file mode 100644 index 00000000..be2d9282 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/init/RelicsCoreShaders.java @@ -0,0 +1,33 @@ +package it.hurts.sskirillss.relics.init; + + +import com.mojang.blaze3d.vertex.DefaultVertexFormat; +import it.hurts.sskirillss.relics.Relics; +import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.client.renderer.RenderStateShard; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ArmorMaterial; +import net.minecraft.world.item.ArmorMaterials; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.RegisterShadersEvent; + +import java.io.IOException; + +@EventBusSubscriber(modid = Reference.MODID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class RelicsCoreShaders { + + public static ShaderInstance REVEAL_SHADER = null; + public static RenderStateShard.ShaderStateShard REVEAL_SHADER_SHARD = new RenderStateShard.ShaderStateShard(()->REVEAL_SHADER); + + @SubscribeEvent + public static void register(RegisterShadersEvent event) throws IOException { + event.registerShader(new ShaderInstance(event.getResourceProvider(),ResourceLocation.tryBuild(Reference.MODID,"reveal_panel"), DefaultVertexFormat.POSITION_TEX), + (inst)->{ + REVEAL_SHADER = inst; + }); + } + +} diff --git a/src/main/java/it/hurts/sskirillss/relics/init/RemoteRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/RemoteRegistry.java index 2b94f3a6..974c5bbf 100644 --- a/src/main/java/it/hurts/sskirillss/relics/init/RemoteRegistry.java +++ b/src/main/java/it/hurts/sskirillss/relics/init/RemoteRegistry.java @@ -1,64 +1,58 @@ package it.hurts.sskirillss.relics.init; -import com.mojang.blaze3d.vertex.PoseStack; +import it.hurts.sskirillss.relics.client.gui.layers.ActiveAbilitiesLayer; +import it.hurts.sskirillss.relics.client.gui.layers.InfoTileLayer; +import it.hurts.sskirillss.relics.client.gui.layers.LeafyRingHideLayer; +import it.hurts.sskirillss.relics.client.gui.layers.PhantomBootBridgeLayer; import it.hurts.sskirillss.relics.client.models.items.CurioModel; +import it.hurts.sskirillss.relics.client.models.layers.WingsLayer; import it.hurts.sskirillss.relics.client.renderer.entities.*; import it.hurts.sskirillss.relics.client.renderer.items.items.CurioRenderer; import it.hurts.sskirillss.relics.client.renderer.tiles.ResearchingTableRenderer; -import it.hurts.sskirillss.relics.items.SolidSnowballItem; -import it.hurts.sskirillss.relics.items.relics.BlazingFlaskItem; -import it.hurts.sskirillss.relics.items.relics.InfinityHamItem; -import it.hurts.sskirillss.relics.items.relics.ShadowGlaiveItem; -import it.hurts.sskirillss.relics.items.relics.back.ArrowQuiverItem; -import it.hurts.sskirillss.relics.items.relics.back.ElytraBoosterItem; +import it.hurts.sskirillss.relics.items.relics.InfiniteHamItem; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; import it.hurts.sskirillss.relics.items.relics.base.IRenderableCurio; -import it.hurts.sskirillss.relics.items.relics.feet.AquaWalkerItem; -import it.hurts.sskirillss.relics.items.relics.feet.MagmaWalkerItem; -import it.hurts.sskirillss.relics.items.relics.feet.RollerSkatesItem; -import it.hurts.sskirillss.relics.system.casts.handlers.HUDRenderHandler; -import it.hurts.sskirillss.relics.tiles.base.IHasHUDInfo; +import it.hurts.sskirillss.relics.items.relics.necklace.HolyLocketItem; import it.hurts.sskirillss.relics.utils.EntityUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; import it.hurts.sskirillss.relics.utils.Reference; import net.minecraft.client.Minecraft; -import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.ThrownItemRenderer; +import net.minecraft.client.renderer.entity.player.PlayerRenderer; import net.minecraft.client.renderer.item.ItemProperties; -import net.minecraft.core.BlockPos; +import net.minecraft.client.resources.PlayerSkin; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.EntityRenderersEvent; -import net.minecraftforge.client.event.RegisterClientTooltipComponentFactoriesEvent; -import net.minecraftforge.client.event.RegisterGuiOverlaysEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; +import net.neoforged.neoforge.client.event.EntityRenderersEvent; +import net.neoforged.neoforge.client.event.RegisterClientTooltipComponentFactoriesEvent; +import net.neoforged.neoforge.client.event.RegisterGuiLayersEvent; import top.theillusivec4.curios.api.client.CuriosRendererRegistry; -import static it.hurts.sskirillss.relics.items.relics.back.ArrowQuiverItem.*; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.CHARGE; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.WORLD_POSITION; -@Mod.EventBusSubscriber(modid = Reference.MODID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +@EventBusSubscriber(modid = Reference.MODID, bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) public class RemoteRegistry { @SubscribeEvent public static void setupClient(final FMLClientSetupEvent event) { ItemBlockRenderTypes.setRenderLayer(BlockRegistry.RESEARCHING_TABLE.get(), RenderType.cutout()); event.enqueueWork(() -> { - ItemProperties.register(ItemRegistry.INFINITY_HAM.get(), new ResourceLocation(Reference.MODID, "pieces"), - (stack, world, entity, id) -> Math.min(10, NBTUtils.getInt(stack, InfinityHamItem.TAG_PIECES, 0))); - ItemProperties.register(ItemRegistry.SHADOW_GLAIVE.get(), new ResourceLocation(Reference.MODID, "charges"), - (stack, world, entity, id) -> Math.min(8, NBTUtils.getInt(stack, ShadowGlaiveItem.TAG_CHARGES, 0))); - ItemProperties.register(ItemRegistry.MAGIC_MIRROR.get(), new ResourceLocation(Reference.MODID, "world"), + ItemProperties.register(ItemRegistry.INFINITY_HAM.get(), ResourceLocation.fromNamespaceAndPath(Reference.MODID, "pieces"), + (stack, world, entity, id) -> ((InfiniteHamItem) stack.getItem()).getPieces(stack)); + ItemProperties.register(ItemRegistry.SHADOW_GLAIVE.get(), ResourceLocation.fromNamespaceAndPath(Reference.MODID, "charges"), + (stack, world, entity, id) -> Math.min(8, stack.getOrDefault(CHARGE, 0))); + ItemProperties.register(ItemRegistry.MAGIC_MIRROR.get(), ResourceLocation.fromNamespaceAndPath(Reference.MODID, "world"), (stack, world, entity, id) -> { Entity e = Minecraft.getInstance().getCameraEntity(); @@ -72,38 +66,40 @@ public static void setupClient(final FMLClientSetupEvent event) { default -> 0; }; }); - ItemProperties.register(ItemRegistry.SHADOW_GLAIVE.get(), new ResourceLocation(Reference.MODID, "charges"), - (stack, world, entity, id) -> Math.min(8, NBTUtils.getInt(stack, ShadowGlaiveItem.TAG_CHARGES, 0))); - ItemProperties.register(ItemRegistry.MAGMA_WALKER.get(), new ResourceLocation(Reference.MODID, "heat"), - (stack, world, entity, id) -> NBTUtils.getInt(stack, MagmaWalkerItem.TAG_HEAT, 0) >= ((IRelicItem) stack.getItem()).getAbilityValue(stack, "pace", "time") ? 1 : 0); - ItemProperties.register(ItemRegistry.AQUA_WALKER.get(), new ResourceLocation(Reference.MODID, "drench"), - (stack, world, entity, id) -> NBTUtils.getInt(stack, AquaWalkerItem.TAG_DRENCH, 0) >= ((IRelicItem) stack.getItem()).getAbilityValue(stack, "walking", "time") ? 1 : 0); - ItemProperties.register(ItemRegistry.ARROW_QUIVER.get(), new ResourceLocation(Reference.MODID, "fullness"), - (stack, world, entity, id) -> { - int maxAmount = ((ArrowQuiverItem) stack.getItem()).getSlotsAmount(stack); - int amount = getArrows(stack).size(); - - return amount > 0 ? (int) Math.floor(amount / (maxAmount / 2F)) + 1 : 0; - }); - ItemProperties.register(ItemRegistry.ELYTRA_BOOSTER.get(), new ResourceLocation(Reference.MODID, "fuel"), - (stack, world, entity, id) -> NBTUtils.getInt(stack, ElytraBoosterItem.TAG_FUEL, 0) > 0 ? 1 : 0); - ItemProperties.register(ItemRegistry.SOLID_SNOWBALL.get(), new ResourceLocation(Reference.MODID, "snow"), + ItemProperties.register(ItemRegistry.SHADOW_GLAIVE.get(), ResourceLocation.fromNamespaceAndPath(Reference.MODID, "charges"), + (stack, world, entity, id) -> Math.min(8, stack.getOrDefault(CHARGE, 0))); + ItemProperties.register(ItemRegistry.MAGMA_WALKER.get(), ResourceLocation.fromNamespaceAndPath(Reference.MODID, "heat"), + (stack, world, entity, id) -> stack.getOrDefault(CHARGE, 0) >= ((IRelicItem) stack.getItem()).getStatValue(stack, "pace", "time") ? 1 : 0); + ItemProperties.register(ItemRegistry.AQUA_WALKER.get(), ResourceLocation.fromNamespaceAndPath(Reference.MODID, "drench"), + (stack, world, entity, id) -> stack.getOrDefault(CHARGE, 0) >= ((IRelicItem) stack.getItem()).getStatValue(stack, "walking", "time") ? 1 : 0); +// ItemProperties.register(ItemRegistry.ARROW_QUIVER.get(), ResourceLocation.fromNamespaceAndPath(Reference.MODID, "fullness"), +// (stack, world, entity, id) -> { +// int maxAmount = ((ArrowQuiverItem) stack.getItem()).getSlotsAmount(stack); +// int amount = getArrows(world.registryAccess(), stack).size(); +// +// return amount > 0 ? (int) Math.floor(amount / (maxAmount / 2F)) + 1 : 0; +// }); + ItemProperties.register(ItemRegistry.ELYTRA_BOOSTER.get(), ResourceLocation.fromNamespaceAndPath(Reference.MODID, "fuel"), + (stack, world, entity, id) -> stack.getOrDefault(CHARGE, 0) > 0 ? 1 : 0); + ItemProperties.register(ItemRegistry.SOLID_SNOWBALL.get(), ResourceLocation.fromNamespaceAndPath(Reference.MODID, "snow"), (stack, world, entity, id) -> { ItemStack relic = EntityUtils.findEquippedCurio(entity, ItemRegistry.WOOL_MITTEN.get()); if (relic.isEmpty()) return 3; - return (int) Math.floor(NBTUtils.getInt(stack, SolidSnowballItem.TAG_SNOW, 0) / (((IRelicItem) relic.getItem()).getAbilityValue(relic, "mold", "size") / 3F)); + return (int) Math.floor(stack.getOrDefault(CHARGE, 0) / (((IRelicItem) relic.getItem()).getStatValue(relic, "mold", "size") / 3F)); }); - ItemProperties.register(ItemRegistry.ROLLER_SKATES.get(), new ResourceLocation(Reference.MODID, "active"), - (stack, world, entity, id) -> NBTUtils.getInt(stack, RollerSkatesItem.TAG_SKATING_DURATION, 0) > 0 ? 1 : 0); + ItemProperties.register(ItemRegistry.ROLLER_SKATES.get(), ResourceLocation.fromNamespaceAndPath(Reference.MODID, "active"), + (stack, world, entity, id) -> stack.getOrDefault(CHARGE, 0) > 0 ? 1 : 0); - ItemProperties.register(ItemRegistry.BLAZING_FLASK.get(), new ResourceLocation(Reference.MODID, "active"), - (stack, world, entity, id) -> NBTUtils.getString(stack, BlazingFlaskItem.TAG_POSITION, "").isEmpty() ? 0 : 1); + ItemProperties.register(ItemRegistry.BLAZING_FLASK.get(), ResourceLocation.fromNamespaceAndPath(Reference.MODID, "active"), + (stack, world, entity, id) -> stack.get(WORLD_POSITION) == null ? 0 : 1); + ItemProperties.register(ItemRegistry.HOLY_LOCKET.get(), ResourceLocation.fromNamespaceAndPath(Reference.MODID, "mode"), + (stack, world, entity, id) -> ((HolyLocketItem) stack.getItem()).getMode(stack).getIndex()); }); - for (Item item : ForgeRegistries.ITEMS.getValues()) { + for (Item item : BuiltInRegistries.ITEM.stream().toList()) { if (!(item instanceof IRenderableCurio)) continue; @@ -113,7 +109,7 @@ public static void setupClient(final FMLClientSetupEvent event) { @SubscribeEvent public static void registerLayers(final EntityRenderersEvent.RegisterLayerDefinitions event) { - for (Item item : ForgeRegistries.ITEMS.getValues()) { + for (Item item : BuiltInRegistries.ITEM.stream().toList()) { if (!(item instanceof IRenderableCurio renderable)) continue; @@ -121,55 +117,46 @@ public static void registerLayers(final EntityRenderersEvent.RegisterLayerDefini } } + @SubscribeEvent + public static void onPlayerRendererRegister(EntityRenderersEvent.AddLayers event) { + for (PlayerSkin.Model skinType : event.getSkins()) { + EntityRenderer renderer = event.getSkin(skinType); + + if (renderer instanceof PlayerRenderer playerRenderer) { + playerRenderer.addLayer(new WingsLayer<>(playerRenderer)); + } + } + } + @SubscribeEvent public static void entityRenderers(EntityRenderersEvent.RegisterRenderers event) { event.registerEntityRenderer(EntityRegistry.SHADOW_GLAIVE.get(), ShadowGlaiveRenderer::new); event.registerEntityRenderer(EntityRegistry.BLOCK_SIMULATION.get(), BlockSimulationRenderer::new); event.registerEntityRenderer(EntityRegistry.SHOCKWAVE.get(), NullRenderer::new); event.registerEntityRenderer(EntityRegistry.LIFE_ESSENCE.get(), NullRenderer::new); + event.registerEntityRenderer(EntityRegistry.DEATH_ESSENCE.get(), NullRenderer::new); event.registerEntityRenderer(EntityRegistry.STALACTITE.get(), StalactiteRenderer::new); event.registerEntityRenderer(EntityRegistry.DISSECTION.get(), DissectionRenderer::new); event.registerEntityRenderer(EntityRegistry.SPORE.get(), SporeRenderer::new); - event.registerEntityRenderer(EntityRegistry.SHADOW_SAW.get(), ShadowSawRenderer::new); event.registerEntityRenderer(EntityRegistry.SOLID_SNOWBALL.get(), SolidSnowballRenderer::new); - event.registerEntityRenderer(EntityRegistry.ARROW_RAIN.get(), NullRenderer::new); +// event.registerEntityRenderer(EntityRegistry.ARROW_RAIN.get(), NullRenderer::new); event.registerEntityRenderer(EntityRegistry.RELIC_EXPERIENCE_ORB.get(), RelicExperienceOrbRenderer::new); event.registerEntityRenderer(EntityRegistry.THROWN_RELIC_EXPERIENCE_BOTTLE.get(), ThrownItemRenderer::new); + event.registerEntityRenderer(EntityRegistry.CHAIR.get(), NullRenderer::new); event.registerBlockEntityRenderer(TileRegistry.RESEARCHING_TABLE.get(), ResearchingTableRenderer::new); } @SubscribeEvent public static void onTooltipRegistry(RegisterClientTooltipComponentFactoriesEvent event) { - event.register(ArrowQuiverTooltip.class, ClientArrowQuiverTooltip::new); + event.register(InfiniteHamItem.InfiniteHamTooltip.class, InfiniteHamItem.ClientInfiniteHamTooltip::new); } @SubscribeEvent - public static void onOverlayRegistry(RegisterGuiOverlaysEvent event) { - event.registerBelowAll("researching_hint", (forgeGui, guiGraphics, partialTick, screenWidth, screenHeight) -> { - Minecraft MC = Minecraft.getInstance(); - ClientLevel level = MC.level; - PoseStack poseStack = guiGraphics.pose(); - - if (level == null) - return; - - HitResult hit = MC.hitResult; - - if (hit == null || hit.getType() != HitResult.Type.BLOCK) - return; - - BlockPos pos = ((BlockHitResult) MC.hitResult).getBlockPos(); - BlockEntity tile = level.getBlockEntity(pos); - - if (!(tile instanceof IHasHUDInfo infoTile)) - return; - - infoTile.renderHUDInfo(poseStack, MC.getWindow()); - }); - - event.registerBelowAll("active_abilities", (ForgeGui, guiGraphics, partialTick, screenWidth, screenHeight) -> { - HUDRenderHandler.render(guiGraphics, partialTick); - }); + public static void onOverlayRegistry(RegisterGuiLayersEvent event) { + event.registerBelowAll(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "info_tile"), new InfoTileLayer()); + event.registerBelowAll(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "active_abilities"), new ActiveAbilitiesLayer()); + event.registerBelowAll(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "leafy_ring_hide"), new LeafyRingHideLayer()); + event.registerBelowAll(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "phantom_boot_bridge"), new PhantomBootBridgeLayer()); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/SoundRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/SoundRegistry.java index 9bc3a372..fd55b66f 100644 --- a/src/main/java/it/hurts/sskirillss/relics/init/SoundRegistry.java +++ b/src/main/java/it/hurts/sskirillss/relics/init/SoundRegistry.java @@ -1,34 +1,37 @@ package it.hurts.sskirillss.relics.init; import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegistryObject; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; -@Mod.EventBusSubscriber(modid = Reference.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) public class SoundRegistry { - public static final DeferredRegister SOUNDS = DeferredRegister.create(ForgeRegistries.SOUND_EVENTS, Reference.MODID); + public static final DeferredRegister SOUNDS = DeferredRegister.create(BuiltInRegistries.SOUND_EVENT, Reference.MODID); - public static final RegistryObject RICOCHET = SOUNDS.register("ricochet", () -> SoundEvent.createVariableRangeEvent(new ResourceLocation(Reference.MODID, "ricochet"))); - public static final RegistryObject THROW = SOUNDS.register("throw", () -> SoundEvent.createVariableRangeEvent(new ResourceLocation(Reference.MODID, "throw"))); - public static final RegistryObject ARROW_RAIN = SOUNDS.register("arrow_rain", () -> SoundEvent.createVariableRangeEvent(new ResourceLocation(Reference.MODID, "arrow_rain"))); - public static final RegistryObject SPURT = SOUNDS.register("spurt", () -> SoundEvent.createVariableRangeEvent(new ResourceLocation(Reference.MODID, "spurt"))); - public static final RegistryObject POWERED_ARROW = SOUNDS.register("powered_arrow", () -> SoundEvent.createVariableRangeEvent(new ResourceLocation(Reference.MODID, "powered_arrow"))); - public static final RegistryObject LEAP = SOUNDS.register("leap", () -> SoundEvent.createVariableRangeEvent(new ResourceLocation(Reference.MODID, "leap"))); + public static final DeferredHolder RICOCHET = SOUNDS.register("ricochet", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "ricochet"))); + public static final DeferredHolder THROW = SOUNDS.register("throw", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "throw"))); + public static final DeferredHolder ARROW_RAIN = SOUNDS.register("arrow_rain", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "arrow_rain"))); + public static final DeferredHolder SPURT = SOUNDS.register("spurt", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "spurt"))); + public static final DeferredHolder POWERED_ARROW = SOUNDS.register("powered_arrow", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "powered_arrow"))); + public static final DeferredHolder LEAP = SOUNDS.register("leap", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "leap"))); + public static final DeferredHolder SPRING_BOING = SOUNDS.register("spring_boing", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "spring_boing"))); - public static final RegistryObject TABLE_UPGRADE = SOUNDS.register("table_upgrade", () -> SoundEvent.createVariableRangeEvent(new ResourceLocation(Reference.MODID, "table_upgrade"))); - public static final RegistryObject TABLE_REROLL = SOUNDS.register("table_reroll", () -> SoundEvent.createVariableRangeEvent(new ResourceLocation(Reference.MODID, "table_reroll"))); - public static final RegistryObject TABLE_RESET = SOUNDS.register("table_reset", () -> SoundEvent.createVariableRangeEvent(new ResourceLocation(Reference.MODID, "table_reset"))); + public static final DeferredHolder TABLE_UPGRADE = SOUNDS.register("table_upgrade", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "table_upgrade"))); + public static final DeferredHolder TABLE_REROLL = SOUNDS.register("table_reroll", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "table_reroll"))); + public static final DeferredHolder TABLE_RESET = SOUNDS.register("table_reset", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "table_reset"))); - public static final RegistryObject ABILITY_LOCKED = SOUNDS.register("ability_locked", () -> SoundEvent.createVariableRangeEvent(new ResourceLocation(Reference.MODID, "ability_locked"))); - public static final RegistryObject ABILITY_COOLDOWN = SOUNDS.register("ability_cooldown", () -> SoundEvent.createVariableRangeEvent(new ResourceLocation(Reference.MODID, "ability_cooldown"))); - public static final RegistryObject ABILITY_CAST = SOUNDS.register("ability_cast", () -> SoundEvent.createVariableRangeEvent(new ResourceLocation(Reference.MODID, "ability_cast"))); + public static final DeferredHolder ABILITY_LOCKED = SOUNDS.register("ability_locked", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "ability_locked"))); + public static final DeferredHolder ABILITY_COOLDOWN = SOUNDS.register("ability_cooldown", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "ability_cooldown"))); + public static final DeferredHolder ABILITY_CAST = SOUNDS.register("ability_cast", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "ability_cast"))); - public static void register() { - SOUNDS.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static final DeferredHolder CONNECT_STARS = SOUNDS.register("connect_stars", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "connect_stars"))); + public static final DeferredHolder DISCONNECT_STARS = SOUNDS.register("disconnect_stars", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "disconnect_stars"))); + public static final DeferredHolder FINISH_RESEARCH = SOUNDS.register("finish_research", () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "finish_research"))); + + public static void register(IEventBus bus) { + SOUNDS.register(bus); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/init/TileRegistry.java b/src/main/java/it/hurts/sskirillss/relics/init/TileRegistry.java index eec33c97..a18460cc 100644 --- a/src/main/java/it/hurts/sskirillss/relics/init/TileRegistry.java +++ b/src/main/java/it/hurts/sskirillss/relics/init/TileRegistry.java @@ -2,19 +2,19 @@ import it.hurts.sskirillss.relics.tiles.ResearchingTableTile; import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.registries.DeferredRegister; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.registries.RegistryObject; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; public class TileRegistry { - private static final DeferredRegister> TILES = DeferredRegister.create(ForgeRegistries.BLOCK_ENTITY_TYPES, Reference.MODID); + private static final DeferredRegister> TILES = DeferredRegister.create(BuiltInRegistries.BLOCK_ENTITY_TYPE, Reference.MODID); - public static final RegistryObject> RESEARCHING_TABLE = TILES.register("researching_table", () -> + public static final DeferredHolder, BlockEntityType> RESEARCHING_TABLE = TILES.register("researching_table", () -> BlockEntityType.Builder.of(ResearchingTableTile::new, BlockRegistry.RESEARCHING_TABLE.get()).build(null)); - public static void register() { - TILES.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void register(IEventBus bus) { + TILES.register(bus); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/BlockItemBase.java b/src/main/java/it/hurts/sskirillss/relics/items/BlockItemBase.java index 061403b1..1aa06ac4 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/BlockItemBase.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/BlockItemBase.java @@ -1,20 +1,19 @@ package it.hurts.sskirillss.relics.items; -import com.google.common.collect.Lists; -import it.hurts.sskirillss.relics.items.relics.base.ICreativeTabEntry; +import it.hurts.sskirillss.relics.init.CreativeTabRegistry; +import it.hurts.sskirillss.relics.items.misc.CreativeContentConstructor; +import it.hurts.sskirillss.relics.items.misc.ICreativeTabContent; import net.minecraft.world.item.BlockItem; -import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.level.block.Block; -import java.util.List; - -public class BlockItemBase extends BlockItem implements ICreativeTabEntry { +public class BlockItemBase extends BlockItem implements ICreativeTabContent { public BlockItemBase(Block block, Properties properties) { super(block, properties); } @Override - public List processCreativeTab() { - return Lists.newArrayList(this.getDefaultInstance()); + public void gatherCreativeTabContent(CreativeContentConstructor constructor) { + constructor.entry(CreativeTabRegistry.RELICS_TAB.get(), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS, this); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/ItemBase.java b/src/main/java/it/hurts/sskirillss/relics/items/ItemBase.java index 82ef081c..deae7356 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/ItemBase.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/ItemBase.java @@ -1,19 +1,9 @@ package it.hurts.sskirillss.relics.items; -import com.google.common.collect.Lists; -import it.hurts.sskirillss.relics.items.relics.base.ICreativeTabEntry; import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import java.util.List; - -public class ItemBase extends Item implements ICreativeTabEntry { +public class ItemBase extends Item { public ItemBase(Properties properties) { super(properties); } - - @Override - public List processCreativeTab() { - return Lists.newArrayList(this.getDefaultInstance()); - } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/RelicExperienceBottleItem.java b/src/main/java/it/hurts/sskirillss/relics/items/RelicExperienceBottleItem.java index 2d5d301a..f7fed4da 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/RelicExperienceBottleItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/RelicExperienceBottleItem.java @@ -2,17 +2,21 @@ import it.hurts.sskirillss.relics.entities.ThrownRelicExperienceBottle; import it.hurts.sskirillss.relics.init.EntityRegistry; +import net.minecraft.core.Direction; +import net.minecraft.core.Position; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.stats.Stats; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ProjectileItem; import net.minecraft.world.item.Rarity; import net.minecraft.world.level.Level; -public class RelicExperienceBottleItem extends ItemBase { +public class RelicExperienceBottleItem extends ItemBase implements ProjectileItem { public RelicExperienceBottleItem() { super(new Properties().rarity(Rarity.UNCOMMON)); } @@ -46,4 +50,13 @@ public InteractionResultHolder use(Level level, Player player, Intera public boolean isFoil(ItemStack stack) { return true; } + + public Projectile asProjectile(Level p_338868_, Position p_338766_, ItemStack p_338321_, Direction p_338772_) { + ThrownRelicExperienceBottle thrownexperiencebottle = new ThrownRelicExperienceBottle(EntityRegistry.THROWN_RELIC_EXPERIENCE_BOTTLE.get(), p_338868_); + + thrownexperiencebottle.setPos(p_338766_.x(), p_338766_.y(), p_338766_.z()); + thrownexperiencebottle.setItem(p_338321_); + + return thrownexperiencebottle; + } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/SolidSnowballItem.java b/src/main/java/it/hurts/sskirillss/relics/items/SolidSnowballItem.java index 61446b77..0d23a70e 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/SolidSnowballItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/SolidSnowballItem.java @@ -3,7 +3,6 @@ import it.hurts.sskirillss.relics.entities.SolidSnowballEntity; import it.hurts.sskirillss.relics.init.ItemRegistry; import it.hurts.sskirillss.relics.utils.EntityUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.world.InteractionHand; @@ -15,12 +14,9 @@ import net.minecraft.world.item.Rarity; import net.minecraft.world.level.Level; -import java.util.ArrayList; -import java.util.List; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.CHARGE; public class SolidSnowballItem extends ItemBase { - public static final String TAG_SNOW = "snow"; - public SolidSnowballItem() { super(new Item.Properties() .stacksTo(1) @@ -28,11 +24,6 @@ public SolidSnowballItem() { ); } - @Override - public List processCreativeTab() { - return new ArrayList<>(); - } - @Override public void inventoryTick(ItemStack stack, Level level, Entity entity, int slotId, boolean isSelected) { if (EntityUtils.findEquippedCurio(entity, ItemRegistry.WOOL_MITTEN.get()).isEmpty()) @@ -46,8 +37,8 @@ public InteractionResultHolder use(Level level, Player player, Intera SolidSnowballEntity entity = new SolidSnowballEntity(level); entity.setOwner(player); + entity.setSize(stack.getOrDefault(CHARGE, 0)); entity.setPos(player.getX(), player.getEyeY(), player.getZ()); - entity.setSize(NBTUtils.getInt(stack, TAG_SNOW, 0)); entity.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 1.5F, 1.0F); level.addFreshEntity(entity); diff --git a/src/main/java/it/hurts/sskirillss/relics/items/misc/CreativeContentConstructor.java b/src/main/java/it/hurts/sskirillss/relics/items/misc/CreativeContentConstructor.java new file mode 100644 index 00000000..7162d4ee --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/misc/CreativeContentConstructor.java @@ -0,0 +1,36 @@ +package it.hurts.sskirillss.relics.items.misc; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ItemLike; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Getter +@NoArgsConstructor +public class CreativeContentConstructor { + private final List entries = new ArrayList<>(); + + public void entry(CreativeModeTab tab, CreativeModeTab.TabVisibility visibility, ItemStack... items) { + entries.add(new CreativeContentData(tab, visibility, Arrays.asList(items))); + } + + public void entry(CreativeModeTab tab, CreativeModeTab.TabVisibility visibility, ItemLike... items) { + this.entry(tab, visibility, Arrays.stream(items).map(ItemStack::new).toArray(ItemStack[]::new)); + } + + @Getter + @AllArgsConstructor + public static class CreativeContentData { + private final CreativeModeTab tab; + + private final CreativeModeTab.TabVisibility visibility; + + private final List stacks; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/misc/ICreativeTabContent.java b/src/main/java/it/hurts/sskirillss/relics/items/misc/ICreativeTabContent.java new file mode 100644 index 00000000..a0af543f --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/misc/ICreativeTabContent.java @@ -0,0 +1,5 @@ +package it.hurts.sskirillss.relics.items.misc; + +public interface ICreativeTabContent { + void gatherCreativeTabContent(CreativeContentConstructor constructor); +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/BlazingFlaskItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/BlazingFlaskItem.java index addadb53..a2749fd9 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/BlazingFlaskItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/BlazingFlaskItem.java @@ -8,13 +8,11 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; import it.hurts.sskirillss.relics.utils.ParticleUtils; import it.hurts.sskirillss.relics.utils.WorldUtils; +import it.hurts.sskirillss.relics.utils.data.WorldPosition; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; import net.minecraft.world.InteractionHand; @@ -32,11 +30,9 @@ import java.awt.*; import java.util.List; -public class BlazingFlaskItem extends RelicItem { - public static final String TAG_POSITION = "pos"; - public static final String TAG_COUNT = "count"; - public static final String TAG_RADIUS = "radius"; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.*; +public class BlazingFlaskItem extends RelicItem { @Override public RelicData constructDefaultRelicData() { return RelicData.builder() @@ -60,11 +56,8 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 100)) - .style(StyleData.builder() - .background(Backgrounds.NETHER) - .build()) .loot(LootData.builder() - .entry(LootCollections.NETHER) + .entry(LootEntries.THE_NETHER, LootEntries.NETHER_LIKE) .build()) .build(); } @@ -79,32 +72,31 @@ public void inventoryTick(ItemStack stack, Level level, Entity entity, int slot, int fire = getFireAround(stack, world); if (fire <= 0) { - NBTUtils.clearTag(stack, TAG_POSITION); - NBTUtils.clearTag(stack, TAG_COUNT); + stack.set(WORLD_POSITION, null); } else { - NBTUtils.setInt(stack, TAG_COUNT, fire); + stack.set(COUNT, fire); } - Vec3 center = NBTUtils.parsePosition(NBTUtils.getString(stack, TAG_POSITION, "")); + WorldPosition center = stack.get(WORLD_POSITION); if (center != null) { - double radius = NBTUtils.getDouble(stack, TAG_RADIUS, 0D); + double radius = stack.getOrDefault(RADIUS, 0D); if (!player.isCreative() && !player.isSpectator() && !player.getAbilities().flying && !player.getAbilities().mayfly) { - if (new Vec3(player.getX(), center.y(), player.getZ()).distanceTo(center) <= radius + 0.5F) { + if (new Vec3(player.getX(), center.getPos().y(), player.getZ()).distanceTo(center.getPos()) <= radius + 0.5F) { player.fallDistance = 0F; if (player.tickCount % 100 == 0) - spreadExperience(player, stack, 1); + spreadRelicExperience(player, stack, 1); - double speed = getAbilityValue(stack, "bonfire", "speed"); + double speed = getStatValue(stack, "bonfire", "speed"); if (world.isClientSide()) { if (!player.onGround() && (player.zza != 0 || player.xxa != 0)) player.move(MoverType.SELF, player.getDeltaMovement().multiply(speed, 0, speed)); if (player instanceof LocalPlayer localPlayer && localPlayer.input.jumping - && (WorldUtils.getGroundHeight(level, player.position(), 64) + getAbilityValue(stack, "bonfire", "height")) - player.getY() > 0) { + && (WorldUtils.getGroundHeight(player, player.position(), 64) + getStatValue(stack, "bonfire", "height")) - player.getY() > 0) { Vec3 motion = player.getDeltaMovement(); if (motion.y() < 0) @@ -116,7 +108,7 @@ public void inventoryTick(ItemStack stack, Level level, Entity entity, int slot, } } - double size = NBTUtils.getInt(stack, TAG_COUNT, 0) * getAbilityValue(stack, "bonfire", "step"); + double size = stack.getOrDefault(COUNT, 0) * getStatValue(stack, "bonfire", "step"); double step = 0.1D; int time = 0; @@ -128,7 +120,7 @@ public void inventoryTick(ItemStack stack, Level level, Entity entity, int slot, time = 10; - NBTUtils.setDouble(stack, TAG_RADIUS, radius); + stack.set(RADIUS, radius); } if (radius > size) { @@ -139,15 +131,15 @@ public void inventoryTick(ItemStack stack, Level level, Entity entity, int slot, time = 10; - NBTUtils.setDouble(stack, TAG_RADIUS, radius); + stack.set(RADIUS, radius); } if (radius <= step) ParticleUtils.createBall(ParticleUtils.constructSimpleSpark(new Color(255, 100, 0), 0.3F, 20, 0.9F), - center, level, 3, 0.2F); + center.getPos(), level, 3, 0.2F); ParticleUtils.createCyl(ParticleUtils.constructSimpleSpark(new Color(255, 100, 0), 0.2F, time, 0.8F), - center, level, radius, 0.15F); + center.getPos(), level, radius, 0.15F); } } @@ -158,18 +150,18 @@ public InteractionResultHolder use(Level level, Player player, Intera Vec3 view = player.getViewVector(0); Vec3 eyeVec = player.getEyePosition(0); - float distance = (float) (8F + getAbilityValue(stack, "bonfire", "height")); + float distance = (float) (8F + getStatValue(stack, "bonfire", "height")); Vec3 end = level.clip(new ClipContext(eyeVec, eyeVec.add(view.x * distance, view.y * distance, view.z * distance), ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, player)).getLocation(); if (getFireAround(stack, end, level) > 0) { - Vec3 center = NBTUtils.parsePosition(NBTUtils.getString(stack, TAG_POSITION, "")); + WorldPosition center = stack.get(WORLD_POSITION); - double radius = NBTUtils.getDouble(stack, TAG_RADIUS, 0D); + double radius = stack.getOrDefault(RADIUS, 0D); - NBTUtils.setDouble(stack, TAG_RADIUS, (center != null && end.distanceTo(center) <= radius) ? radius - center.distanceTo(end) : 0D); - NBTUtils.setString(stack, TAG_POSITION, NBTUtils.writePosition(end)); + stack.set(RADIUS, (center != null && end.distanceTo(center.getPos()) <= radius) ? radius - center.getPos().distanceTo(end) : 0D); + stack.set(WORLD_POSITION, new WorldPosition(player.level().dimension(), end)); player.getCooldowns().addCooldown(this, 20); } @@ -178,16 +170,16 @@ public InteractionResultHolder use(Level level, Player player, Intera } public int getFireAround(ItemStack stack, Level level) { - Vec3 center = NBTUtils.parsePosition(NBTUtils.getString(stack, TAG_POSITION, "")); + WorldPosition center = stack.get(WORLD_POSITION); if (center == null) return 0; - return getFireAround(stack, center, level); + return getFireAround(stack, center.getPos(), level); } public int getFireAround(ItemStack stack, Vec3 center, Level level) { - List positions = WorldUtils.getBlockSphere(new BlockPos((int) center.x, (int) center.y, (int) center.z), getAbilityValue(stack, "bonfire", "step")) + List positions = WorldUtils.getBlockSphere(new BlockPos((int) center.x, (int) center.y, (int) center.z), getStatValue(stack, "bonfire", "step")) .stream().filter(pos -> (level.getBlockState(pos).getBlock() instanceof BaseFireBlock)).toList(); return positions.size(); diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/HorseFluteItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/HorseFluteItem.java index 953c89e3..43d47ff0 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/HorseFluteItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/HorseFluteItem.java @@ -1,268 +1,268 @@ -package it.hurts.sskirillss.relics.items.relics; - -import it.hurts.sskirillss.relics.items.relics.base.RelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; -import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; -import net.minecraft.world.InteractionResultHolder; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityType; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.animal.horse.AbstractHorse; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.context.UseOnContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.Vec3; -import top.theillusivec4.curios.api.SlotContext; - -import javax.annotation.Nullable; -import java.util.Optional; -import java.util.UUID; - -public class HorseFluteItem extends RelicItem { - public static final String TAG_ENTITY = "entity"; - private static final String TAG_UUID = "uuid"; - - @Override - public RelicData constructDefaultRelicData() { - return RelicData.builder() - .abilities(AbilitiesData.builder() - .ability(AbilityData.builder("paddock") - .maxLevel(0) - .build()) - .ability(AbilityData.builder("heal") - .requiredLevel(5) - .stat(StatData.builder("amount") - .initialValue(0.01D, 0.1D) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 1D) - .formatValue(value -> MathUtils.round(value, 2)) - .build()) - .build()) - .build()) - .leveling(new LevelingData(100, 10, 100)) - .style(StyleData.builder() - .background(Backgrounds.PLAINS) - .build()) - .loot(LootData.builder() - .entry(LootCollections.VILLAGE) - .entry(LootCollections.ANTHROPOGENIC) - .build()) - .build(); - } - - @Override - public InteractionResult interactLivingEntity(ItemStack stack, Player player, LivingEntity entity, InteractionHand hand) { - if (!(entity instanceof AbstractHorse horse)) - return InteractionResult.FAIL; - - CompoundTag nbt = stack.getTagElement(TAG_ENTITY); - - if (nbt != null) { - releaseHorse(stack, player); - catchHorse(horse, player, stack); - - return InteractionResult.SUCCESS; - } - - catchHorse(horse, player, stack); - - return InteractionResult.SUCCESS; - } - - @Override - public InteractionResult useOn(UseOnContext context) { - Player player = context.getPlayer(); - ItemStack stack = context.getItemInHand(); - CompoundTag nbt = stack.getTagElement(TAG_ENTITY); - - if (player == null) - return InteractionResult.FAIL; - - if (nbt == null) { - if (player.isShiftKeyDown()) - NBTUtils.clearTag(stack, TAG_UUID); - else - catchHorse(stack, player); - - return InteractionResult.SUCCESS; - } - - releaseHorse(stack, player); - - if (player.isShiftKeyDown()) - NBTUtils.clearTag(stack, TAG_UUID); - - return InteractionResult.SUCCESS; - } - - @Override - public InteractionResultHolder use(Level world, Player player, InteractionHand hand) { - ItemStack stack = player.getItemInHand(hand); - CompoundTag nbt = stack.getTagElement(TAG_ENTITY); - - if (nbt == null) { - if (player.isShiftKeyDown()) - NBTUtils.clearTag(stack, TAG_UUID); - else - catchHorse(stack, player); - - return InteractionResultHolder.success(stack); - } - - releaseHorse(stack, player); - - if (player.isShiftKeyDown()) - NBTUtils.clearTag(stack, TAG_UUID); - - return InteractionResultHolder.success(stack); - } - - @Override - public void inventoryTick(ItemStack stack, Level level, Entity entityIn, int itemSlot, boolean isSelected) { - if (entityIn.tickCount % 20 == 0) { - AbstractHorse horse = decodeHorseData(stack, level); - if (horse != null) { - if (canUseAbility(stack, "heal")) { - horse.heal((float) getAbilityValue(stack, "heal", "amount")); - - CompoundTag nbt = new CompoundTag(); - - horse.save(nbt); - - stack.addTagElement(TAG_ENTITY, nbt); - } - } - } - - AbstractHorse horse = findHorse(level, stack); - - if (horse != null && entityIn.distanceTo(horse) > 16) - catchHorse(horse, entityIn, stack); - } - - @Nullable - private AbstractHorse findHorse(Level world, ItemStack stack) { - if (world.isClientSide()) - return null; - - ServerLevel serverLevel = (ServerLevel) world; - String uuid = NBTUtils.getString(stack, TAG_UUID, ""); - - if (uuid.equals("")) - return null; - - Entity entity = serverLevel.getEntity(UUID.fromString(uuid)); - - return entity instanceof AbstractHorse ? (AbstractHorse) entity : null; - } - - public void catchHorse(AbstractHorse horse, Entity entity, ItemStack stack) { - if (horse.isDeadOrDying() || (horse.getOwnerUUID() != null && !horse.getOwnerUUID().equals(entity.getUUID())) - || (horse.getOwnerUUID() == null && !horse.isTamed())) - return; - - Level world = horse.getCommandSenderWorld(); - CompoundTag nbt = new CompoundTag(); - Vec3 pos = horse.position(); - - if (NBTUtils.getString(stack, TAG_UUID, "").equals(horse.getUUID().toString()) && horse.walkDist > 25) { - if (entity instanceof LivingEntity living) - spreadExperience(living, stack, Math.round(horse.walkDist / 25)); - - horse.walkDist = 0; - } - - horse.save(nbt); - - NBTUtils.setCompound(stack, TAG_ENTITY, nbt); - NBTUtils.clearTag(stack, TAG_UUID); - - horse.remove(Entity.RemovalReason.KILLED); - - if (!world.isClientSide()) - ((ServerLevel) world).sendParticles(ParticleTypes.EXPLOSION, pos.x(), pos.y(), pos.z(), 1, 0F, 0F, 0F, 0F); - - world.playSound(null, horse.blockPosition(), SoundEvents.CHICKEN_EGG, SoundSource.PLAYERS, 1.0F, 1.0F); - } - - private void catchHorse(ItemStack stack, Entity player) { - Level world = player.getCommandSenderWorld(); - - AbstractHorse horse = findHorse(world, stack); - - if (horse != null) - catchHorse(horse, player, stack); - } - - public void releaseHorse(ItemStack stack, Entity player) { - Level world = player.getCommandSenderWorld(); - Vec3 pos = player.position(); - - AbstractHorse horse = decodeHorseData(stack, world); - - if (horse == null) - return; - - horse.setPos(pos.x(), pos.y(), pos.z()); - world.addFreshEntity(horse); - horse.setDeltaMovement(player.getViewVector(1.0F).normalize()); - horse.fallDistance = 0F; - - NBTUtils.clearTag(stack, TAG_ENTITY); - NBTUtils.setString(stack, TAG_UUID, horse.getUUID().toString()); - - if (!world.isClientSide()) - ((ServerLevel) world).sendParticles(ParticleTypes.EXPLOSION, pos.x(), pos.y(), pos.z(), 1, 0F, 0F, 0F, 0F); - - world.playSound(null, horse.blockPosition(), SoundEvents.BEEHIVE_EXIT, SoundSource.PLAYERS, 1.0F, 1.0F); - } - - @Nullable - private AbstractHorse decodeHorseData(ItemStack stack, Level level) { - CompoundTag data = stack.getTag(); - - if (data == null) - return null; - - Optional> type = EntityType.by(data.getCompound(TAG_ENTITY)); - - if (type.isEmpty()) - return null; - - Entity entity = type.get().create(level); - - if (!(entity instanceof AbstractHorse horse)) - return null; - - horse.load(data.getCompound(TAG_ENTITY)); - - return horse; - } - - @Override - public boolean isFoil(ItemStack stack) { - return stack.getTagElement(TAG_ENTITY) != null; - } - - @Override - public boolean canEquipFromUse(SlotContext slotContext, ItemStack stack) { - return false; - } -} \ No newline at end of file +//package it.hurts.sskirillss.relics.items.relics; +// +//import it.hurts.sskirillss.relics.items.relics.base.RelicItem; +//import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; +//import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; +//import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; +//import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; +//import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +//import it.hurts.sskirillss.relics.utils.MathUtils; +//import it.hurts.sskirillss.relics.utils.NBTUtils; +//import net.minecraft.core.particles.ParticleTypes; +//import net.minecraft.nbt.CompoundTag; +//import net.minecraft.server.level.ServerLevel; +//import net.minecraft.sounds.SoundEvents; +//import net.minecraft.sounds.SoundSource; +//import net.minecraft.world.InteractionHand; +//import net.minecraft.world.InteractionResult; +//import net.minecraft.world.InteractionResultHolder; +//import net.minecraft.world.entity.Entity; +//import net.minecraft.world.entity.EntityType; +//import net.minecraft.world.entity.LivingEntity; +//import net.minecraft.world.entity.animal.horse.AbstractHorse; +//import net.minecraft.world.entity.player.Player; +//import net.minecraft.world.item.ItemStack; +//import net.minecraft.world.item.context.UseOnContext; +//import net.minecraft.world.level.Level; +//import net.minecraft.world.phys.Vec3; +//import top.theillusivec4.curios.api.SlotContext; +// +//import javax.annotation.Nullable; +//import java.util.Optional; +//import java.util.UUID; +// +//public class HorseFluteItem extends RelicItem { +// public static final String TAG_ENTITY = "entity"; +// private static final String TAG_UUID = "uuid"; +// +// @Override +// public RelicData constructDefaultRelicData() { +// return RelicData.builder() +// .abilities(AbilitiesData.builder() +// .ability(AbilityData.builder("paddock") +// .maxLevel(0) +// .build()) +// .ability(AbilityData.builder("heal") +// .requiredLevel(5) +// .stat(StatData.builder("amount") +// .initialValue(0.01D, 0.1D) +// .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 1D) +// .formatValue(value -> MathUtils.round(value, 2)) +// .build()) +// .build()) +// .build()) +// .leveling(new LevelingData(100, 10, 100)) +// .style(StyleData.builder() +// .background(Backgrounds.PLAINS) +// .build()) +// .loot(LootData.builder() +// .entry(LootCollections.VILLAGE) +// .entry(LootCollections.ANTHROPOGENIC) +// .build()) +// .build(); +// } +// +// @Override +// public InteractionResult interactLivingEntity(ItemStack stack, Player player, LivingEntity entity, InteractionHand hand) { +// if (!(entity instanceof AbstractHorse horse)) +// return InteractionResult.FAIL; +// +// CompoundTag nbt = NBTUtils.getCompound(stack, TAG_ENTITY, new CompoundTag()); +// +// if (!nbt.isEmpty()) { +// releaseHorse(stack, player); +// catchHorse(horse, player, stack); +// +// return InteractionResult.SUCCESS; +// } +// +// catchHorse(horse, player, stack); +// +// return InteractionResult.SUCCESS; +// } +// +// @Override +// public InteractionResult useOn(UseOnContext context) { +// Player player = context.getPlayer(); +// ItemStack stack = context.getItemInHand(); +// CompoundTag nbt = NBTUtils.getCompound(stack, TAG_ENTITY, new CompoundTag()); +// +// if (player == null) +// return InteractionResult.FAIL; +// +// if (nbt.isEmpty()) { +// if (player.isShiftKeyDown()) +// NBTUtils.clearTag(stack, TAG_UUID); +// else +// catchHorse(stack, player); +// +// return InteractionResult.SUCCESS; +// } +// +// releaseHorse(stack, player); +// +// if (player.isShiftKeyDown()) +// NBTUtils.clearTag(stack, TAG_UUID); +// +// return InteractionResult.SUCCESS; +// } +// +// @Override +// public InteractionResultHolder use(Level world, Player player, InteractionHand hand) { +// ItemStack stack = player.getItemInHand(hand); +// CompoundTag nbt = NBTUtils.getCompound(stack, TAG_ENTITY, new CompoundTag()); +// +// if (nbt.isEmpty()) { +// if (player.isShiftKeyDown()) +// NBTUtils.clearTag(stack, TAG_UUID); +// else +// catchHorse(stack, player); +// +// return InteractionResultHolder.success(stack); +// } +// +// releaseHorse(stack, player); +// +// if (player.isShiftKeyDown()) +// NBTUtils.clearTag(stack, TAG_UUID); +// +// return InteractionResultHolder.success(stack); +// } +// +// @Override +// public void inventoryTick(ItemStack stack, Level level, Entity entityIn, int itemSlot, boolean isSelected) { +// if (entityIn.tickCount % 20 == 0) { +// AbstractHorse horse = decodeHorseData(stack, level); +// if (horse != null) { +// if (canUseAbility(stack, "heal")) { +// horse.heal((float) getAbilityValue(stack, "heal", "amount")); +// +// CompoundTag nbt = new CompoundTag(); +// +// horse.save(nbt); +// +// NBTUtils.getOrCreateTag(stack).put(TAG_ENTITY, nbt); +// } +// } +// } +// +// AbstractHorse horse = findHorse(level, stack); +// +// if (horse != null && entityIn.distanceTo(horse) > 16) +// catchHorse(horse, entityIn, stack); +// } +// +// @Nullable +// private AbstractHorse findHorse(Level world, ItemStack stack) { +// if (world.isClientSide()) +// return null; +// +// ServerLevel serverLevel = (ServerLevel) world; +// String uuid = NBTUtils.getString(stack, TAG_UUID, ""); +// +// if (uuid.isEmpty()) +// return null; +// +// Entity entity = serverLevel.getEntity(UUID.fromString(uuid)); +// +// return entity instanceof AbstractHorse ? (AbstractHorse) entity : null; +// } +// +// public void catchHorse(AbstractHorse horse, Entity entity, ItemStack stack) { +// if (horse.isDeadOrDying() || (horse.getOwnerUUID() != null && !horse.getOwnerUUID().equals(entity.getUUID())) +// || (horse.getOwnerUUID() == null && !horse.isTamed())) +// return; +// +// Level world = horse.getCommandSenderWorld(); +// CompoundTag nbt = new CompoundTag(); +// Vec3 pos = horse.position(); +// +// if (NBTUtils.getString(stack, TAG_UUID, "").equals(horse.getUUID().toString()) && horse.walkDist > 25) { +// if (entity instanceof LivingEntity living) +// spreadExperience(living, stack, Math.round(horse.walkDist / 25)); +// +// horse.walkDist = 0; +// } +// +// horse.save(nbt); +// +// NBTUtils.setCompound(stack, TAG_ENTITY, nbt); +// NBTUtils.clearTag(stack, TAG_UUID); +// +// horse.remove(Entity.RemovalReason.KILLED); +// +// if (!world.isClientSide()) +// ((ServerLevel) world).sendParticles(ParticleTypes.EXPLOSION, pos.x(), pos.y(), pos.z(), 1, 0F, 0F, 0F, 0F); +// +// world.playSound(null, horse.blockPosition(), SoundEvents.CHICKEN_EGG, SoundSource.PLAYERS, 1.0F, 1.0F); +// } +// +// private void catchHorse(ItemStack stack, Entity player) { +// Level world = player.getCommandSenderWorld(); +// +// AbstractHorse horse = findHorse(world, stack); +// +// if (horse != null) +// catchHorse(horse, player, stack); +// } +// +// public void releaseHorse(ItemStack stack, Entity player) { +// Level world = player.getCommandSenderWorld(); +// Vec3 pos = player.position(); +// +// AbstractHorse horse = decodeHorseData(stack, world); +// +// if (horse == null) +// return; +// +// horse.setPos(pos.x(), pos.y(), pos.z()); +// world.addFreshEntity(horse); +// horse.setDeltaMovement(player.getViewVector(1.0F).normalize()); +// horse.fallDistance = 0F; +// +// NBTUtils.clearTag(stack, TAG_ENTITY); +// NBTUtils.setString(stack, TAG_UUID, horse.getUUID().toString()); +// +// if (!world.isClientSide()) +// ((ServerLevel) world).sendParticles(ParticleTypes.EXPLOSION, pos.x(), pos.y(), pos.z(), 1, 0F, 0F, 0F, 0F); +// +// world.playSound(null, horse.blockPosition(), SoundEvents.BEEHIVE_EXIT, SoundSource.PLAYERS, 1.0F, 1.0F); +// } +// +// @Nullable +// private AbstractHorse decodeHorseData(ItemStack stack, Level level) { +// CompoundTag data = NBTUtils.getOrCreateTag(stack); +// +// if (data == null) +// return null; +// +// Optional> type = EntityType.by(data.getCompound(TAG_ENTITY)); +// +// if (type.isEmpty()) +// return null; +// +// Entity entity = type.get().create(level); +// +// if (!(entity instanceof AbstractHorse horse)) +// return null; +// +// horse.load(data.getCompound(TAG_ENTITY)); +// +// return horse; +// } +// +// @Override +// public boolean isFoil(ItemStack stack) { +// return !NBTUtils.getOrCreateTag(stack).getCompound(TAG_ENTITY).isEmpty(); +// } +// +// @Override +// public boolean canEquipFromUse(SlotContext slotContext, ItemStack stack) { +// return false; +// } +//} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/InfiniteHamItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/InfiniteHamItem.java new file mode 100644 index 00000000..e70e5471 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/InfiniteHamItem.java @@ -0,0 +1,393 @@ +package it.hurts.sskirillss.relics.items.relics; + +import it.hurts.sskirillss.relics.api.events.common.ContainerSlotClickEvent; +import it.hurts.sskirillss.relics.init.CreativeTabRegistry; +import it.hurts.sskirillss.relics.init.EffectRegistry; +import it.hurts.sskirillss.relics.items.misc.CreativeContentConstructor; +import it.hurts.sskirillss.relics.items.relics.base.RelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.*; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemColor; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemShape; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; +import it.hurts.sskirillss.relics.items.relics.base.data.research.ResearchData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.TooltipData; +import it.hurts.sskirillss.relics.utils.EntityUtils; +import it.hurts.sskirillss.relics.utils.MathUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +import net.minecraft.core.component.DataComponents; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.tags.DamageTypeTags; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.food.FoodProperties; +import net.minecraft.world.inventory.ClickAction; +import net.minecraft.world.inventory.tooltip.TooltipComponent; +import net.minecraft.world.item.*; +import net.minecraft.world.item.alchemy.PotionContents; +import net.minecraft.world.level.Level; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import top.theillusivec4.curios.api.SlotContext; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.CHARGE; + +public class InfiniteHamItem extends RelicItem { + public InfiniteHamItem() { + super(new Item.Properties() + .stacksTo(1) + .food(new FoodProperties.Builder().build()) + .rarity(Rarity.RARE)); + } + + @Override + public RelicData constructDefaultRelicData() { + return RelicData.builder() + .abilities(AbilitiesData.builder() + .ability(AbilityData.builder("regeneration") + .requiredPoints(2) + .stat(StatData.builder("cooldown") + .initialValue(30D, 15D) + .upgradeModifier(UpgradeOperation.ADD, -0.5D) + .formatValue(value -> MathUtils.round(value, 1)) + .build()) + .stat(StatData.builder("feed") + .initialValue(1D, 3D) + .upgradeModifier(UpgradeOperation.ADD, 1D) + .formatValue(value -> (int) MathUtils.round(value, 0)) + .build()) + .research(ResearchData.builder() + .star(0, 8, 7).star(1, 19, 7).star(2, 5, 15) + .star(3, 10, 16).star(4, 17, 20).star(5, 7, 24) + .link(1, 3).link(3, 0).link(3, 2).link(3, 4).link(3, 5) + .build()) + .build()) + .ability(AbilityData.builder("marinade") + .requiredLevel(5) + .stat(StatData.builder("duration") + .initialValue(1D, 3D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.2D) + .formatValue(value -> MathUtils.round(value, 1)) + .build()) + .research(ResearchData.builder() + .star(0, 18, 5).star(1, 8, 7).star(2, 4, 16) + .star(3, 17, 16).star(4, 10, 21).star(5, 17, 23) + .star(6, 5, 25).star(7, 10, 29) + .link(0, 1).link(0, 3).link(1, 3).link(1, 2).link(3, 4).link(2, 4).link(3, 5).link(4, 7).link(2, 6) + .build()) + .build()) + .ability(AbilityData.builder("meat_bat") + .requiredLevel(10) + .stat(StatData.builder("damage") + .initialValue(0.5D, 2D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.25D) + .formatValue(value -> MathUtils.round(value, 1)) + .build()) + .stat(StatData.builder("stun") + .initialValue(0.05D, 0.25D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.1D) + .formatValue(value -> MathUtils.round(value, 2)) + .build()) + .research(ResearchData.builder() + .star(0, 10, 5).star(1, 18, 7).star(2, 3, 9) + .star(3, 17, 14).star(4, 10, 17).star(5, 3, 19) + .star(6, 9, 24).star(7, 18, 24) + .link(1, 4).link(4, 0).link(4, 2).link(4, 3).link(4, 5).link(4, 6).link(4, 7) + .link(0, 3).link(3, 7).link(7, 6).link(6, 5).link(5, 2).link(2, 0).link(2, 0) + .build()) + .build()) + .build()) + .leveling(LevelingData.builder() + .initialCost(100) + .maxLevel(20) + .step(100) + .sources(LevelingSourcesData.builder() + .source(LevelingSourceData.abilityBuilder("regeneration") + .initialValue(1) + .gem(GemShape.SQUARE, GemColor.ORANGE) + .build()) + .source(LevelingSourceData.abilityBuilder("marinade") + .initialValue(1) + .gem(GemShape.SQUARE, GemColor.ORANGE) + .build()) + .source(LevelingSourceData.abilityBuilder("meat_bat") + .initialValue(1) + .gem(GemShape.SQUARE, GemColor.ORANGE) + .build()) + .build()) + .build()) + .style(StyleData.builder() + .tooltip(TooltipData.builder() + .borderTop(0xff644a41) + .borderBottom(0xff592410) + .textured(true) + .build()) + .build()) + .loot(LootData.builder() + .entry(LootEntries.VILLAGE) + .build()) + .build(); + } + + @Override + public void gatherCreativeTabContent(CreativeContentConstructor constructor) { + ItemStack stack = this.getDefaultInstance(); + + setPieces(stack, getMaxPieces()); + + constructor.entry(CreativeTabRegistry.RELICS_TAB.get(), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS, stack); + } + + @Override + public void inventoryTick(@NotNull ItemStack stack, @NotNull Level level, @NotNull Entity entityIn, int itemSlot, boolean isSelected) { + if (level.isClientSide() || !(entityIn instanceof Player player) || !canPlayerUseAbility(player, stack, "regeneration") + || entityIn.tickCount % (int) Math.max(1, getStatValue(stack, "regeneration", "cooldown") * 20) != 0 || getPieces(stack) >= getMaxPieces()) + return; + + addPieces(stack, 1); + } + + @Override + public @NotNull InteractionResultHolder use(@NotNull Level world, Player player, @NotNull InteractionHand hand) { + ItemStack stack = player.getItemInHand(hand); + + if (canPlayerUseAbility(player, stack, "regeneration") && getPieces(stack) > 0 && player.getFoodData().needsFood()) { + player.startUsingItem(hand); + + return InteractionResultHolder.consume(stack); + } + + return InteractionResultHolder.pass(stack); + } + + @Override + public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity entity) { + if (!(entity instanceof Player player) || !canPlayerUseAbility(player, stack, "regeneration")) + return stack; + + var properties = getFoodProperties(stack, entity); + + if (properties == null) + return stack; + + player.eat(level, stack.copy()); + + var eaten = (int) Math.ceil(properties.nutrition() / getStatValue(stack, "regeneration", "feed")); + + if (eaten > 0) { + addPieces(stack, -eaten); + + if (isLevelingSourceUnlocked(stack, "regeneration")) + spreadRelicExperience(player, stack, eaten); + } + + return stack; + } + + @Override + public @Nullable FoodProperties getFoodProperties(ItemStack stack, @Nullable LivingEntity entity) { + if (!(entity instanceof Player player) || !canPlayerUseAbility(player, stack, "regeneration")) + return super.getFoodProperties(stack, entity); + + var charge = getPieces(stack); + + if (charge == 0) + return null; + + var nutrition = Math.min((int) Math.ceil(charge * getStatValue(stack, "regeneration", "feed")), 20 - player.getFoodData().getFoodLevel()); + + var builder = new FoodProperties.Builder() + .nutrition(nutrition) + .saturationModifier(nutrition / 3F); + + if (canPlayerUseAbility(player, stack, "marinade")) { + var contents = stack.get(DataComponents.POTION_CONTENTS); + + if (contents != null) + contents.forEachEffect(effect -> { + var holder = effect.getEffect(); + var isInstant = holder.value().isInstantenous(); + + builder.effect(() -> new MobEffectInstance(holder, isInstant ? 1 : (int) (nutrition * getStatValue(stack, "marinade", "duration") * 20), + effect.getAmplifier(), !isInstant && effect.isAmbient(), !isInstant && effect.isVisible(), !isInstant && effect.showIcon()), 1F); + }); + } + + return builder.build(); + } + + @Override + public boolean isFoil(ItemStack stack) { + return stack.get(DataComponents.POTION_CONTENTS) != null; + } + + @Override + public int getUseDuration(@NotNull ItemStack stack, LivingEntity entity) { + return 32; + } + + @Override + public @NotNull UseAnim getUseAnimation(@NotNull ItemStack stack) { + return UseAnim.EAT; + } + + @Override + public boolean canEquipFromUse(SlotContext slotContext, ItemStack stack) { + return false; + } + + public int getMaxPieces() { + return 6; + } + + public int getPieces(ItemStack stack) { + return Math.clamp(stack.getOrDefault(CHARGE, 0), 0, getMaxPieces()); + } + + public void setPieces(ItemStack stack, int amount) { + stack.set(CHARGE, Math.clamp(amount, 0, getMaxPieces())); + } + + public void addPieces(ItemStack stack, int amount) { + setPieces(stack, getPieces(stack) + amount); + } + + @Override + public Optional getTooltipImage(ItemStack stack) { + var contents = stack.get(DataComponents.POTION_CONTENTS); + + return contents == null ? Optional.empty() : Optional.of(new InfiniteHamTooltip(StreamSupport.stream(contents.getAllEffects().spliterator(), false).collect(Collectors.toList()))); + } + + public record InfiniteHamTooltip(List effects) implements TooltipComponent { + + } + + @OnlyIn(Dist.CLIENT) + public record ClientInfiniteHamTooltip(InfiniteHamTooltip tooltip) implements ClientTooltipComponent { + @Override + public int getHeight() { + return tooltip.effects().size() * 11; + } + + @Override + public int getWidth(Font font) { + return 100; + } + + @Override + public void renderImage(Font font, int mouseX, int mouseY, GuiGraphics guiGraphics) { + var yOff = 0; + + for (MobEffectInstance effect : tooltip.effects()) { + var holder = effect.getEffect(); + + var manager = Minecraft.getInstance().getMobEffectTextures(); + + guiGraphics.blit(mouseX, mouseY + yOff, 0, 10, 10, manager.get(holder)); + + var name = Component.translatable(effect.getDescriptionId()); + + if (effect.getAmplifier() > 0) + name = Component.translatable("potion.withAmplifier", name, Component.translatable("potion.potency." + effect.getAmplifier())); + + name.withStyle(holder.value().getCategory().getTooltipFormatting()); + + guiGraphics.drawString(font, name, mouseX + 12, mouseY + 2 + yOff, 0xFFFFFF); + + yOff += 11; + } + } + } + + @EventBusSubscriber + public static class InfinityHamEvents { + @SubscribeEvent + public static void onLivingDamage(LivingIncomingDamageEvent event) { + var source = event.getSource(); + + if (!(source.getDirectEntity() instanceof Player player) || !source.is(DamageTypeTags.IS_PLAYER_ATTACK)) + return; + + var stack = player.getMainHandItem(); + + if (!(stack.getItem() instanceof InfiniteHamItem relic) || !relic.canPlayerUseAbility(player, stack, "meat_bat")) + return; + + var charge = relic.getPieces(stack); + + if (charge <= 0) + return; + + if (relic.isLevelingSourceUnlocked(stack, "meat_bat")) + relic.spreadRelicExperience(player, stack, charge); + + event.setAmount((float) (event.getAmount() + (relic.getStatValue(stack, "meat_bat", "damage") * charge))); + event.getEntity().addEffect(new MobEffectInstance(EffectRegistry.STUN, (int) Math.round(relic.getStatValue(stack, "meat_bat", "stun") * charge * 20), 0)); + + relic.setPieces(stack, 0); + } + + @SubscribeEvent + public static void onSlotClick(ContainerSlotClickEvent event) { + if (event.getAction() != ClickAction.PRIMARY) + return; + + var player = event.getEntity(); + + var heldStack = event.getHeldStack(); + var slotStack = event.getSlotStack(); + + if (!(heldStack.getItem() instanceof PotionItem) || !(slotStack.getItem() instanceof InfiniteHamItem relic) + || !relic.canPlayerUseAbility(player, slotStack, "marinade")) + return; + + var contents = heldStack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY); + var effects = StreamSupport.stream(contents.getAllEffects().spliterator(), false).toList(); + + if (effects.isEmpty()) + slotStack.set(DataComponents.POTION_CONTENTS, null); + else { + slotStack.set(DataComponents.POTION_CONTENTS, new PotionContents(Optional.empty(), Optional.empty(), effects)); + + if (relic.isLevelingSourceUnlocked(slotStack, "marinade")) + relic.spreadRelicExperience(player, slotStack, effects.size()); + } + + var bottle = new ItemStack(Items.GLASS_BOTTLE); + + if (player.containerMenu.getCarried().getCount() <= 1) + player.containerMenu.setCarried(bottle); + else { + player.containerMenu.getCarried().shrink(1); + + EntityUtils.addItem(player, bottle); + } + + player.playSound(SoundEvents.BOTTLE_FILL, 1F, 1F); + + event.setCanceled(true); + } + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/InfinityHamItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/InfinityHamItem.java deleted file mode 100644 index 5ca9b9dc..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/InfinityHamItem.java +++ /dev/null @@ -1,242 +0,0 @@ -package it.hurts.sskirillss.relics.items.relics; - -import com.google.common.collect.Lists; -import it.hurts.sskirillss.relics.api.events.common.ContainerSlotClickEvent; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; -import it.hurts.sskirillss.relics.items.relics.base.RelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; -import it.hurts.sskirillss.relics.utils.EntityUtils; -import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResultHolder; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.ClickAction; -import net.minecraft.world.item.*; -import net.minecraft.world.item.alchemy.PotionUtils; -import net.minecraft.world.level.Level; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import org.jetbrains.annotations.NotNull; -import top.theillusivec4.curios.api.SlotContext; - -import java.util.List; - -public class InfinityHamItem extends RelicItem { - public static final String TAG_PIECES = "pieces"; - private static final String TAG_CHARGE = "charge"; - private static final String TAG_POTION = "potion"; - - public InfinityHamItem() { - super(new Item.Properties() - .stacksTo(1) - .rarity(Rarity.RARE)); - } - - @Override - public RelicData constructDefaultRelicData() { - return RelicData.builder() - .abilities(AbilitiesData.builder() - .ability(AbilityData.builder("autophagy") - .stat(StatData.builder("feed") - .initialValue(1D, 2D) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.15D) - .formatValue(value -> MathUtils.round(value, 1)) - .build()) - .build()) - .ability(AbilityData.builder("infusion") - .requiredLevel(5) - .stat(StatData.builder("duration") - .initialValue(1D, 3.5D) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.5D) - .formatValue(value -> MathUtils.round(value, 1)) - .build()) - .build()) - .build()) - .leveling(new LevelingData(100, 10, 100)) - .style(StyleData.builder() - .background(Backgrounds.PLAINS) - .build()) - .loot(LootData.builder() - .entry(LootCollections.VILLAGE) - .build()) - .build(); - } - - @Override - public List processCreativeTab() { - ItemStack stack = this.getDefaultInstance(); - - NBTUtils.setInt(stack, TAG_PIECES, 10); - - return Lists.newArrayList(stack); - } - - @Override - public void inventoryTick(@NotNull ItemStack stack, @NotNull Level worldIn, @NotNull Entity entityIn, int itemSlot, boolean isSelected) { - if (entityIn.tickCount % 20 != 0 || !(entityIn instanceof Player player) - || player.isUsingItem()) - return; - - int pieces = NBTUtils.getInt(stack, TAG_PIECES, 0); - - if (pieces >= 10) - return; - - int charge = NBTUtils.getInt(stack, TAG_CHARGE, 0); - - if (charge >= 10) { - NBTUtils.setInt(stack, TAG_PIECES, pieces + 1); - NBTUtils.setInt(stack, TAG_CHARGE, 0); - } else - NBTUtils.setInt(stack, TAG_CHARGE, charge + 1); - - super.inventoryTick(stack, worldIn, entityIn, itemSlot, isSelected); - } - - @Override - public @NotNull InteractionResultHolder use(@NotNull Level world, Player player, @NotNull InteractionHand hand) { - ItemStack stack = player.getItemInHand(hand); - - if (NBTUtils.getInt(stack, TAG_PIECES, 0) > 0 - && (player.getFoodData().needsFood() || player.isCreative())) - player.startUsingItem(hand); - - return super.use(world, player, hand); - } - - @Override - public void onUseTick(Level level, LivingEntity entity, ItemStack stack, int count) { - if (!(entity instanceof Player player)) - return; - - if (!player.getFoodData().needsFood() && !player.isCreative()) { - player.stopUsingItem(); - - return; - } - - if (player.tickCount % 10 != 0) - return; - - int pieces = NBTUtils.getInt(stack, TAG_PIECES, 0); - CompoundTag nbt = stack.getOrCreateTag(); - - if (pieces > 0) { - NBTUtils.setInt(stack, TAG_PIECES, --pieces); - - int feed = (int) Math.round(getAbilityValue(stack, "autophagy", "feed")); - - player.getFoodData().eat(feed, feed); - - spreadExperience(player, stack, Math.max(1, Math.min(20 - player.getFoodData().getFoodLevel(), feed))); - - if (!canUseAbility(stack, "infusion") || !nbt.contains(TAG_POTION, 9)) - return; - - int duration = (int) Math.round(getAbilityValue(stack, "infusion", "duration") * 20); - - ListTag list = nbt.getList(TAG_POTION, 10); - - for (int i = 0; i < list.size(); ++i) { - MobEffectInstance effect = MobEffectInstance.load(list.getCompound(i)); - - if (effect == null || effect.getEffect().isInstantenous()) - continue; - - MobEffectInstance currentEffect = player.getEffect(effect.getEffect()); - - player.addEffect(new MobEffectInstance(effect.getEffect(), currentEffect == null ? duration : currentEffect.getDuration() + duration, effect.getAmplifier())); - } - - if (pieces <= 0 && nbt.contains(TAG_POTION)) - nbt.remove(TAG_POTION); - } else - player.stopUsingItem(); - } - - @Override - public boolean isFoil(ItemStack stack) { - return stack.getOrCreateTag().contains(TAG_POTION); - } - - @Override - public int getUseDuration(@NotNull ItemStack stack) { - return 50; - } - - @Override - public @NotNull UseAnim getUseAnimation(@NotNull ItemStack stack) { - return UseAnim.EAT; - } - - @Override - public boolean canEquipFromUse(SlotContext slotContext, ItemStack stack) { - return false; - } - - @Mod.EventBusSubscriber - public static class Events { - @SubscribeEvent - public static void onSlotClick(ContainerSlotClickEvent event) { - if (event.getAction() != ClickAction.PRIMARY) - return; - - Player player = event.getEntity(); - - ItemStack heldStack = event.getHeldStack(); - ItemStack slotStack = event.getSlotStack(); - - if (!(heldStack.getItem() instanceof PotionItem) || !(slotStack.getItem() instanceof InfinityHamItem relic) - || !relic.canUseAbility(slotStack, "infusion")) - return; - - CompoundTag tag = slotStack.getOrCreateTag(); - ListTag list = tag.getList(TAG_POTION, 9); - - List effects = PotionUtils.getMobEffects(heldStack); - - if (effects.isEmpty()) { - NBTUtils.clearTag(slotStack, TAG_POTION); - } else { - effects = effects.stream().filter(effect -> effect != null && !effect.getEffect().isInstantenous()).toList(); - - if (effects.isEmpty()) - return; - - for (MobEffectInstance effect : effects) - list.add(effect.save(new CompoundTag())); - - tag.put(TAG_POTION, list); - } - - ItemStack bottle = new ItemStack(Items.GLASS_BOTTLE); - - if (player.containerMenu.getCarried().getCount() <= 1) - player.containerMenu.setCarried(bottle); - else { - player.containerMenu.getCarried().shrink(1); - - EntityUtils.addItem(player, bottle); - } - - player.playSound(SoundEvents.BOTTLE_FILL, 1F, 1F); - - event.setCanceled(true); - } - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/MagicMirrorItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/MagicMirrorItem.java index 8179adb5..d2f3791f 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/MagicMirrorItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/MagicMirrorItem.java @@ -1,6 +1,5 @@ package it.hurts.sskirillss.relics.items.relics; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.init.ItemRegistry; import it.hurts.sskirillss.relics.items.relics.base.RelicItem; import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; @@ -10,8 +9,7 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.MathUtils; import it.hurts.sskirillss.relics.utils.ParticleUtils; import it.hurts.sskirillss.relics.utils.Reference; @@ -32,12 +30,13 @@ import net.minecraft.world.item.UseAnim; import net.minecraft.world.level.Level; import net.minecraft.world.level.dimension.DimensionType; +import net.minecraft.world.level.portal.DimensionTransition; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.client.event.ComputeFovModifierEvent; -import net.minecraftforge.event.entity.living.LivingHurtEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.ComputeFovModifierEvent; +import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; import org.apache.commons.lang3.tuple.Pair; import top.theillusivec4.curios.api.SlotContext; @@ -56,18 +55,15 @@ public RelicData constructDefaultRelicData() { .formatValue(value -> MathUtils.round(value, 1)) .build()) .stat(StatData.builder("cooldown") - .initialValue(60D, 120D) + .initialValue(120D, 60D) .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, -0.05D) .formatValue(value -> MathUtils.round(value, 1)) .build()) .build()) .build()) .leveling(new LevelingData(100, 10, 200)) - .style(StyleData.builder() - .background(Backgrounds.CAVE) - .build()) .loot(LootData.builder() - .entry(LootCollections.ANTHROPOGENIC) + .entry(LootEntries.CAVE, LootEntries.MINESHAFT) .build()) .build(); } @@ -104,13 +100,13 @@ public ItemStack finishUsingItem(ItemStack stack, Level world, LivingEntity enti Vec3 pos = data.getRight(); - spreadExperience(player, stack, (int) (1 + (Math.round((player.position().distanceTo(new Vec3(pos.x(), player.getY(), pos.z())) + spreadRelicExperience(player, stack, (int) (1 + (Math.round((player.position().distanceTo(new Vec3(pos.x(), player.getY(), pos.z())) * DimensionType.getTeleportationScale(player.level().dimensionType(), data.getLeft().dimensionType()))) / 50))); player.teleportTo(data.getLeft(), pos.x() + 0.5F, pos.y() + 1.0F, pos.z() + 0.5F, player.getYRot(), player.getXRot()); if (!player.isCreative()) - player.getCooldowns().addCooldown(stack.getItem(), (int) Math.round(getAbilityValue(stack, "teleport", "cooldown") * 20)); + player.getCooldowns().addCooldown(stack.getItem(), (int) Math.round(getStatValue(stack, "teleport", "cooldown") * 20)); world.playSound(null, player.blockPosition(), SoundEvents.TOTEM_USE, SoundSource.PLAYERS, 1.0F, 1.0F); @@ -126,7 +122,7 @@ public void onUseTick(Level level, LivingEntity entity, ItemStack stack, int cou ServerLevel serverLevel = (ServerLevel) level; float radius = count * 0.075F; - double extraY = entity.getY() + 1.5F - Math.log((count + getUseDuration(stack) * 0.075F) * 0.1F); + double extraY = entity.getY() + 1.5F - Math.log((count + getUseDuration(stack, entity) * 0.075F) * 0.1F); RandomSource random = level.getRandom(); @@ -143,13 +139,13 @@ public void onUseTick(Level level, LivingEntity entity, ItemStack stack, int cou double extraX = (double) (radius * Mth.sin((float) (Math.PI + angle))) + entity.getX(); double extraZ = (double) (radius * Mth.cos(angle)) + entity.getZ(); - serverLevel.sendParticles(ParticleUtils.constructSimpleSpark(color, Math.max(0.2F, (getUseDuration(stack) - count) * 0.015F), + serverLevel.sendParticles(ParticleUtils.constructSimpleSpark(color, Math.max(0.2F, (getUseDuration(stack, entity) - count) * 0.015F), 40, 0.92F), extraX, extraY, extraZ, 1, 0F, 0F, 0F, 0F); } - serverLevel.sendParticles(ParticleUtils.constructSimpleSpark(color, (getUseDuration(stack) - count) * 0.005F, 10 + random.nextInt(50), + serverLevel.sendParticles(ParticleUtils.constructSimpleSpark(color, (getUseDuration(stack, entity) - count) * 0.005F, 10 + random.nextInt(50), 0.95F), entity.getX(), entity.getY() + entity.getBbHeight() * 0.5F, entity.getZ(), - (int) ((getUseDuration(stack) - count) * 0.5F), 0.25F, entity.getBbHeight() * 0.4F, 0.25F, 0.025F); + (int) ((getUseDuration(stack, entity) - count) * 0.5F), 0.25F, entity.getBbHeight() * 0.4F, 0.25F, 0.025F); } @Override @@ -158,7 +154,7 @@ public UseAnim getUseAnimation(ItemStack pStack) { } @Override - public int getUseDuration(ItemStack pStack) { + public int getUseDuration(ItemStack pStack, LivingEntity entity) { return 40; } @@ -184,8 +180,7 @@ private Pair getHomePos(ServerPlayer player, boolean useAncho if (world == null || pos == null) return null; - return Player.findRespawnPositionAndUseSpawnBlock(world, pos, player.getRespawnAngle(), true, !useAnchor) - .map(vec3 -> Pair.of(world, vec3)).orElse(null); + return Pair.of(world, player.findRespawnPositionAndUseSpawnBlock(!useAnchor, DimensionTransition.DO_NOTHING).pos()); } private boolean canTeleport(ServerPlayer player, Pair data, ItemStack stack) { @@ -196,10 +191,10 @@ private boolean canTeleport(ServerPlayer player, Pair data, I ServerLevel level = data.getLeft(); return !(player.position().distanceTo(new Vec3(pos.x(), player.getY(), pos.z())) * DimensionType.getTeleportationScale(player.level().dimensionType(), - level.dimensionType()) > getAbilityValue(stack, "teleport", "distance")); + level.dimensionType()) > getStatValue(stack, "teleport", "distance")); } - @Mod.EventBusSubscriber(modid = Reference.MODID, value = Dist.CLIENT) + @EventBusSubscriber(modid = Reference.MODID, value = Dist.CLIENT) public static class ClientEvents { @SubscribeEvent public static void onFovUpdate(ComputeFovModifierEvent event) { @@ -217,10 +212,10 @@ public static void onFovUpdate(ComputeFovModifierEvent event) { } } - @Mod.EventBusSubscriber + @EventBusSubscriber public static class ServerEvents { @SubscribeEvent - public static void onLivingHurt(LivingHurtEvent event) { + public static void onLivingHurt(LivingIncomingDamageEvent event) { Item item = ItemRegistry.MAGIC_MIRROR.get(); if (!(event.getEntity() instanceof Player player) || !player.isUsingItem() @@ -232,4 +227,4 @@ public static void onLivingHurt(LivingHurtEvent event) { player.getCooldowns().addCooldown(item, 20); } } -} \ No newline at end of file +} diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/ShadowGlaiveItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/ShadowGlaiveItem.java index 82c52905..1a8f66a4 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/ShadowGlaiveItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/ShadowGlaiveItem.java @@ -1,212 +1,136 @@ package it.hurts.sskirillss.relics.items.relics; -import com.google.common.collect.Lists; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.entities.ShadowGlaiveEntity; -import it.hurts.sskirillss.relics.entities.ShadowSawEntity; -import it.hurts.sskirillss.relics.init.SoundRegistry; +import it.hurts.sskirillss.relics.init.EntityRegistry; +import it.hurts.sskirillss.relics.init.ItemRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; import it.hurts.sskirillss.relics.items.relics.base.RelicItem; import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.*; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemColor; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemShape; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; +import it.hurts.sskirillss.relics.items.relics.base.data.research.ResearchData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.BeamsData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.TooltipData; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.RandomSource; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResultHolder; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; +import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.EntityHitResult; -import top.theillusivec4.curios.api.SlotContext; - -import javax.annotation.Nullable; -import java.util.List; -import java.util.UUID; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.living.LivingDamageEvent; public class ShadowGlaiveItem extends RelicItem { - public static final String TAG_CHARGES = "charges"; - public static final String TAG_TIME = "time"; - public static final String TAG_SAW = "saw"; - @Override public RelicData constructDefaultRelicData() { return RelicData.builder() .abilities(AbilitiesData.builder() - .ability(AbilityData.builder("glaive") - .stat(StatData.builder("recharge") - .initialValue(30D, 10D) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, -0.09D) - .formatValue(value -> MathUtils.round(value, 1)) + .ability(AbilityData.builder("mayhem") + .stat(StatData.builder("chance") + .initialValue(0.05D, 0.15D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.065D) + .formatValue(value -> (int) MathUtils.round(value * 100, 0)) .build()) .stat(StatData.builder("bounces") - .initialValue(3D, 5D) - .upgradeModifier(UpgradeOperation.ADD, 1D) + .initialValue(2D, 4D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.15D) .formatValue(value -> (int) MathUtils.round(value, 0)) .build()) .stat(StatData.builder("damage") - .initialValue(2D, 5D) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.2D) - .formatValue(value -> MathUtils.round(value, 1)) + .initialValue(0.1D, 0.2D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.15D) + .formatValue(value -> (int) MathUtils.round(value * 100, 0)) .build()) - .stat(StatData.builder("radius") - .initialValue(2.5D, 5D) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.25D) - .formatValue(value -> MathUtils.round(value, 1)) + .research(ResearchData.builder() + .star(0, 11, 2).star(1, 3, 19).star(2, 11, 19) + .star(3, 19, 19).star(4, 11, 29) + .link(0, 2).link(2, 1).link(2, 3).link(2, 4) .build()) .build()) - .ability(AbilityData.builder("saw") + .ability(AbilityData.builder("cloning") .requiredLevel(5) - .stat(StatData.builder("speed") - .initialValue(20D, 15D) - .upgradeModifier(UpgradeOperation.ADD, -1D) - .formatValue(value -> MathUtils.round(value / 20, 2)) + .stat(StatData.builder("chance") + .initialValue(0.05D, 0.1D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.1D) + .formatValue(value -> (int) MathUtils.round(value * 100, 0)) .build()) - .stat(StatData.builder("damage") - .initialValue(0.75D, 1.5D) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.2D) - .formatValue(value -> MathUtils.round(value, 1)) + .research(ResearchData.builder() + .star(0, 12, 2).star(1, 7, 7).star(2, 17, 14) + .star(3, 6, 22).star(4, 11, 29) + .link(0, 1).link(1, 2).link(2, 3).link(3, 4) .build()) .build()) .build()) - .leveling(new LevelingData(100, 10, 100)) .style(StyleData.builder() - .background(Backgrounds.END) + .tooltip(TooltipData.builder() + .borderTop(0xff2c2430) + .borderBottom(0xff471e65) + .textured(true) + .build()) + .beams(BeamsData.builder() + .startColor(0xFFFF00FF) + .endColor(0x000000FF) + .build()) + .build()) + .leveling(LevelingData.builder() + .initialCost(100) + .maxLevel(15) + .step(100) + .sources(LevelingSourcesData.builder() + .source(LevelingSourceData.abilityBuilder("mayhem") + .initialValue(1) + .gem(GemShape.SQUARE, GemColor.PURPLE) + .build()) + .build()) .build()) .loot(LootData.builder() - .entry(LootCollections.END) - .entry(LootCollections.SCULK) + .entry(LootEntries.THE_END, LootEntries.END_LIKE) .build()) .build(); } - @Override - public List processCreativeTab() { - ItemStack stack = this.getDefaultInstance(); - - NBTUtils.setInt(stack, TAG_CHARGES, 8); - - return Lists.newArrayList(stack); - } - - @Override - public void inventoryTick(ItemStack stack, Level worldIn, Entity entityIn, int itemSlot, boolean isSelected) { - if (worldIn.isClientSide()) - return; - - int charges = NBTUtils.getInt(stack, TAG_CHARGES, 0); - - if (entityIn.tickCount % 20 != 0 || charges >= 8) - return; - - int time = NBTUtils.getInt(stack, TAG_TIME, 0); - - if (getSaw(stack, worldIn) != null) - return; - - if (time >= getAbilityValue(stack, "glaive", "recharge")) { - NBTUtils.setInt(stack, TAG_CHARGES, charges + 1); - NBTUtils.setInt(stack, TAG_TIME, 0); - } else - NBTUtils.setInt(stack, TAG_TIME, time + 1); - } - - @Override - public InteractionResultHolder use(Level worldIn, Player playerIn, InteractionHand handIn) { - ItemStack stack = playerIn.getItemInHand(handIn); - int charges = NBTUtils.getInt(stack, TAG_CHARGES, 0); - RandomSource random = playerIn.getRandom(); - - if (playerIn.getCooldowns().isOnCooldown(stack.getItem())) - return InteractionResultHolder.fail(stack); + @EventBusSubscriber + public static class ShadowGlaiveEvents { + @SubscribeEvent + public static void onLivingHurt(LivingDamageEvent.Post event) { + var damage = event.getOriginalDamage(); - ShadowSawEntity entity = getSaw(stack, worldIn); + if (damage < 1F) + return; - if (entity != null) { - if (!entity.isReturning) - entity.isReturning = true; - } else { - if (playerIn.isShiftKeyDown() && canUseAbility(stack, "saw")) { - if (charges == 8 && getSaw(stack, worldIn) == null) { - ShadowSawEntity saw = new ShadowSawEntity(stack, playerIn); + var source = event.getSource().getDirectEntity(); + var target = event.getEntity(); - saw.setStack(stack); - saw.setOwner(playerIn); - saw.teleportTo(playerIn.getX(), playerIn.getY() + playerIn.getBbHeight() * 0.5F, playerIn.getZ()); - saw.shootFromRotation(playerIn, playerIn.getXRot(), playerIn.getYRot(), 0.75F, 1, 0.0F); + if (!(source instanceof Player player) || EntityUtils.isAlliedTo(source, target)) + return; - worldIn.addFreshEntity(saw); + for (var stack : EntityUtils.findEquippedCurios(player, ItemRegistry.SHADOW_GLAIVE.get())) { + if (!(stack.getItem() instanceof IRelicItem relic) || source.getRandom().nextDouble() > relic.getStatValue(stack, "mayhem", "chance")) + continue; - worldIn.playSound(null, playerIn.getX(), playerIn.getY(), playerIn.getZ(), SoundRegistry.THROW.get(), - SoundSource.MASTER, 0.5F, 0.35F + (random.nextFloat() * 0.25F)); + var level = target.getCommandSenderWorld(); - NBTUtils.setInt(stack, TAG_CHARGES, 0); - NBTUtils.setString(stack, TAG_SAW, saw.getStringUUID()); - } - } else { - if (charges > 0) { - ShadowGlaiveEntity glaive = new ShadowGlaiveEntity(worldIn, playerIn); - - glaive.setStack(stack); - glaive.setOwner(playerIn); - glaive.teleportTo(playerIn.getX(), playerIn.getY() + playerIn.getBbHeight() * 0.5F, playerIn.getZ()); - glaive.shootFromRotation(playerIn, playerIn.getXRot(), playerIn.getYRot(), 0.75F, 1, 0.0F); - - worldIn.addFreshEntity(glaive); + var entity = new ShadowGlaiveEntity(EntityRegistry.SHADOW_GLAIVE.get(), level); - EntityHitResult result = EntityUtils.rayTraceEntity(playerIn, entry -> !EntityUtils.isAlliedTo(playerIn, entry), 32); + entity.setDamage((float) (damage * relic.getStatValue(stack, "mayhem", "damage"))); + entity.setMaxBounces((int) relic.getStatValue(stack, "mayhem", "bounces")); + entity.getBouncedTargets().add(target.getStringUUID()); + entity.setPos(target.getEyePosition()); + entity.setOwner(source); - if (result != null) { - if (result.getEntity() instanceof LivingEntity target) - glaive.setTarget(target); - } + if (relic.canPlayerUseAbility(player, stack, "cloning")) + entity.setChance((float) relic.getStatValue(stack, "cloning", "chance")); - worldIn.playSound(null, playerIn.getX(), playerIn.getY(), playerIn.getZ(), SoundRegistry.THROW.get(), - SoundSource.MASTER, 0.5F, 0.75F + (random.nextFloat() * 0.5F)); + if (entity.locateNearestTargets().size() > 1) { + level.addFreshEntity(entity); - NBTUtils.setInt(stack, TAG_CHARGES, charges - 1); + relic.spreadRelicExperience(player, stack, 1); } } } - - return InteractionResultHolder.pass(stack); - } - - @Nullable - public ShadowSawEntity getSaw(ItemStack stack, Level level) { - try { - UUID uuid = UUID.fromString(NBTUtils.getString(stack, TAG_SAW, "")); - - if (level.isClientSide()) - return null; - - ServerLevel serverLevel = (ServerLevel) level; - Entity entity = serverLevel.getEntity(uuid); - - if (entity instanceof ShadowSawEntity saw) - return saw; - - NBTUtils.clearTag(stack, TAG_SAW); - - return null; - } catch (IllegalArgumentException e) { - return null; - } - } - - @Override - public boolean canEquipFromUse(SlotContext slotContext, ItemStack stack) { - return false; } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/SpaceDissectorItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/SpaceDissectorItem.java index a1a01718..655aa5b8 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/SpaceDissectorItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/SpaceDissectorItem.java @@ -1,6 +1,5 @@ package it.hurts.sskirillss.relics.items.relics; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.entities.DissectionEntity; import it.hurts.sskirillss.relics.items.relics.base.RelicItem; import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; @@ -10,10 +9,8 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; import it.hurts.sskirillss.relics.utils.ParticleUtils; import net.minecraft.commands.arguments.EntityAnchorArgument; import net.minecraft.server.level.ServerLevel; @@ -33,9 +30,9 @@ import java.awt.*; import java.util.UUID; -public class SpaceDissectorItem extends RelicItem { - public static final String TAG_PORTAL = "portal"; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.PORTAL; +public class SpaceDissectorItem extends RelicItem { @Override public RelicData constructDefaultRelicData() { return RelicData.builder() @@ -54,11 +51,8 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 200)) - .style(StyleData.builder() - .background(Backgrounds.NETHER) - .build()) .loot(LootData.builder() - .entry(LootCollections.NETHER) + .entry(LootEntries.NETHER_LIKE, LootEntries.THE_NETHER) .build()) .build(); } @@ -67,7 +61,7 @@ public RelicData constructDefaultRelicData() { public InteractionResultHolder use(Level world, Player player, InteractionHand handIn) { ItemStack stack = player.getItemInHand(handIn); - String stringUUID = NBTUtils.getString(stack, TAG_PORTAL, ""); + String stringUUID = stack.getOrDefault(PORTAL, ""); if (!stringUUID.isEmpty()) { UUID uuid = UUID.fromString(stringUUID); @@ -80,22 +74,22 @@ public InteractionResultHolder use(Level world, Player player, Intera if (startPortal != null) startPortal.setLifeTime(20); else - spreadExperience(player, stack, 1); + spreadRelicExperience(player, stack, 1); } } else - spreadExperience(player, stack, 1); + spreadRelicExperience(player, stack, 1); Vec3 view = player.getViewVector(0); Vec3 eyeVec = player.getEyePosition(0); - float distance = Math.round(getAbilityValue(stack, "dissection", "distance")); + float distance = Math.round(getStatValue(stack, "dissection", "distance")); BlockHitResult ray = world.clip(new ClipContext(eyeVec, eyeVec.add(view.x * distance, view.y * distance, view.z * distance), ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)); DissectionEntity portal = new DissectionEntity(world); - int time = (int) Math.round(getAbilityValue(stack, "dissection", "time")) * 20; + int time = (int) Math.round(getStatValue(stack, "dissection", "time")) * 20; portal.setPos(ray.getLocation()); portal.setMaxLifeTime(time); @@ -104,7 +98,7 @@ public InteractionResultHolder use(Level world, Player player, Intera world.addFreshEntity(portal); - NBTUtils.setString(stack, TAG_PORTAL, portal.getStringUUID()); + stack.set(PORTAL, portal.getStringUUID()); player.startUsingItem(handIn); @@ -119,13 +113,13 @@ public void releaseUsing(ItemStack stack, Level world, LivingEntity pLivingEntit Vec3 view = player.getViewVector(0); Vec3 eyeVec = player.getEyePosition(0); - float distance = Math.round(getAbilityValue(stack, "dissection", "distance")); + float distance = Math.round(getStatValue(stack, "dissection", "distance")); BlockHitResult ray = world.clip(new ClipContext(eyeVec, eyeVec.add(view.x * distance, view.y * distance, view.z * distance), ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, player)); Vec3 targetVec = ray.getLocation(); - String stringUUID = NBTUtils.getString(stack, TAG_PORTAL, ""); + String stringUUID = stack.getOrDefault(PORTAL, ""); if (stringUUID.isEmpty()) return; @@ -160,7 +154,7 @@ public void onUseTick(Level level, LivingEntity entity, ItemStack stack, int cou Vec3 view = entity.getViewVector(0); Vec3 eyeVec = entity.getEyePosition(0); - float distance = Math.round(getAbilityValue(stack, "dissection", "distance")); + float distance = Math.round(getStatValue(stack, "dissection", "distance")); BlockHitResult ray = level.clip(new ClipContext(eyeVec, eyeVec.add(view.x * distance, view.y * distance, view.z * distance), ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, entity)); @@ -169,7 +163,7 @@ public void onUseTick(Level level, LivingEntity entity, ItemStack stack, int cou ParticleUtils.createBall(ParticleUtils.constructSimpleSpark(new Color(150 + random.nextInt(100), 100, 0), 0.2F + random.nextFloat() * 0.1F, 10 + random.nextInt(20), 0.9F), targetVec, level, 1, 0.25F); - String stringUUID = NBTUtils.getString(stack, TAG_PORTAL, ""); + String stringUUID = stack.getOrDefault(PORTAL, ""); if (stringUUID.isEmpty()) return; @@ -190,7 +184,7 @@ public void onUseTick(Level level, LivingEntity entity, ItemStack stack, int cou } @Override - public int getUseDuration(ItemStack pStack) { + public int getUseDuration(ItemStack pStack, LivingEntity entity) { return 72000; } diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/SpatialSignItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/SpatialSignItem.java index f55fd1ed..a0f2f264 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/SpatialSignItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/SpatialSignItem.java @@ -1,211 +1,209 @@ -package it.hurts.sskirillss.relics.items.relics; - -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; -import it.hurts.sskirillss.relics.init.EffectRegistry; -import it.hurts.sskirillss.relics.init.ItemRegistry; -import it.hurts.sskirillss.relics.items.relics.base.RelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; -import it.hurts.sskirillss.relics.utils.EntityUtils; -import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; -import it.hurts.sskirillss.relics.utils.ParticleUtils; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.RandomSource; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResultHolder; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.enchantment.Enchantment; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.event.entity.living.LivingAttackEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import top.theillusivec4.curios.api.SlotContext; - -import java.awt.*; -import java.util.ArrayList; -import java.util.List; - -public class SpatialSignItem extends RelicItem { - public static final String TAG_POSITION = "pos"; - public static final String TAG_TIME = "time"; - public static final String TAG_WORLD = "world"; - - @Override - public RelicData constructDefaultRelicData() { - return RelicData.builder() - .abilities(AbilitiesData.builder() - .ability(AbilityData.builder("seal") - .stat(StatData.builder("time") - .initialValue(2D, 4D) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.25D) - .formatValue(value -> MathUtils.round(value, 1)) - .build()) - .build()) - .build()) - .leveling(new LevelingData(100, 10, 200)) - .style(StyleData.builder() - .background(Backgrounds.CAVE) - .build()) - .loot(LootData.builder() - .entry(LootCollections.ANTHROPOGENIC) - .build()) - .build(); - } - - @Override - public InteractionResultHolder use(Level worldIn, Player playerIn, InteractionHand handIn) { - ItemStack stack = playerIn.getItemInHand(handIn); - - if (NBTUtils.getList(stack, TAG_POSITION, String.class).size() < 2 - || worldIn.isClientSide()) - return InteractionResultHolder.fail(stack); - - if (NBTUtils.getInt(stack, TAG_TIME, 0) > 0) { - NBTUtils.setInt(stack, TAG_TIME, 0); - } else { - NBTUtils.setInt(stack, TAG_TIME, (int) Math.round(getAbilityValue(stack, "seal", "time"))); - - worldIn.playSound(null, playerIn.blockPosition(), SoundEvents.EXPERIENCE_ORB_PICKUP, SoundSource.PLAYERS, 1F, 2F); - } - - return InteractionResultHolder.success(stack); - } - - @Override - public void inventoryTick(ItemStack stack, Level worldIn, Entity entityIn, int itemSlot, boolean isSelected) { - if (!(entityIn instanceof Player player)) - return; - - RandomSource random = worldIn.getRandom(); - - int time = NBTUtils.getInt(stack, TAG_TIME, -1); - List positions = NBTUtils.getList(stack, TAG_POSITION, String.class); - - if (time >= 0) { - if (player.isPassenger()) - player.stopRiding(); - - if (player.tickCount % 20 == 0 && !worldIn.isClientSide()) { - NBTUtils.setInt(stack, TAG_TIME, --time); - - spreadExperience(player, stack, 1); - } - - if (time <= 0) { - worldIn.playSound(null, player.blockPosition(), SoundEvents.EXPERIENCE_ORB_PICKUP, SoundSource.PLAYERS, 1F, 0.5F); - - player.getCooldowns().addCooldown(this, (int) (Math.ceil(getAbilityValue(stack, "seal", "time")) * 20)); - - NBTUtils.setInt(stack, TAG_TIME, -1); - - return; - } - - if (!positions.isEmpty()) { - Vec3 target = NBTUtils.parsePosition(positions.get(positions.size() - 1)); - - double distance = player.position().distanceTo(target); - - if (distance > 2) { - if (distance > 64) { - NBTUtils.setInt(stack, TAG_TIME, 0); - NBTUtils.setList(stack, TAG_POSITION, new ArrayList<>()); - } - - for (int i = 0; i < 10; i++) - worldIn.addParticle(ParticleUtils.constructSimpleSpark(new Color(255 - random.nextInt(100), 0, 255 - random.nextInt(50)), - 0.1F + random.nextFloat() * 0.25F, 100, 0.96F), player.getX(), - player.getY() + random.nextFloat() * player.getBbHeight(), player.getZ(), 0F, random.nextFloat() * 0.1F, 0F); - - player.addEffect(new MobEffectInstance(EffectRegistry.VANISHING.get(), 5, 0, false, false)); - - player.setDeltaMovement(target.add(0, 1, 0).subtract(player.position()).normalize().scale(0.75F)); - - player.fallDistance = 0; - player.noPhysics = true; - player.clearFire(); - } else { - positions.remove(positions.size() - 1); - - NBTUtils.setList(stack, TAG_POSITION, positions); - } - } else { - NBTUtils.setInt(stack, TAG_TIME, 0); - } - } - - if (player.tickCount % 20 == 0) { - if (positions.size() >= 5 * getAbilityValue(stack, "seal", "time")) - positions.remove(0); - - if (positions.isEmpty() || player.position().distanceTo(NBTUtils.parsePosition(positions.get(positions.size() - 1))) >= 2) { - if (worldIn.dimension().location().toString().equals(NBTUtils.getString(stack, TAG_WORLD, ""))) { - positions.add(NBTUtils.writePosition(player.position())); - } else { - positions.clear(); - - NBTUtils.setString(stack, TAG_WORLD, worldIn.dimension().location().toString()); - } - } - - NBTUtils.setList(stack, TAG_POSITION, positions); - } - } - - @Override - public int getMaxDamage(ItemStack stack) { - return 1; - } - - @Override - public boolean canApplyAtEnchantingTable(ItemStack stack, Enchantment enchantment) { - return false; - } - - @Override - public boolean isFoil(ItemStack stack) { - return NBTUtils.getInt(stack, TAG_TIME, 0) > 0; - } - - @Override - public boolean canEquipFromUse(SlotContext slotContext, ItemStack stack) { - return false; - } - - @Mod.EventBusSubscriber - public static class Events { - @SubscribeEvent - public static void onLivingAttack(LivingAttackEvent event) { - LivingEntity entity = event.getEntity(); - - if (!(entity instanceof Player player)) - return; - - for (int slot : EntityUtils.getSlotsWithItem(player, ItemRegistry.SPATIAL_SIGN.get()).stream() - .filter(slot -> slot != -1) - .toList()) { - ItemStack stack = player.getInventory().getItem(slot); - - if (stack.getItem() instanceof SpatialSignItem && NBTUtils.getInt(stack, TAG_TIME, 0) > 0) { - event.setCanceled(true); - - return; - } - } - } - } -} \ No newline at end of file +//package it.hurts.sskirillss.relics.items.relics; +// +//import it.hurts.sskirillss.relics.init.EffectRegistry; +//import it.hurts.sskirillss.relics.init.ItemRegistry; +//import it.hurts.sskirillss.relics.items.relics.base.RelicItem; +//import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; +//import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; +//import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; +//import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; +//import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +//import it.hurts.sskirillss.relics.utils.EntityUtils; +//import it.hurts.sskirillss.relics.utils.MathUtils; +//import it.hurts.sskirillss.relics.utils.NBTUtils; +//import it.hurts.sskirillss.relics.utils.ParticleUtils; +//import net.minecraft.network.chat.Component; +//import net.minecraft.sounds.SoundEvents; +//import net.minecraft.sounds.SoundSource; +//import net.minecraft.util.RandomSource; +//import net.minecraft.world.InteractionHand; +//import net.minecraft.world.InteractionResultHolder; +//import net.minecraft.world.effect.MobEffectInstance; +//import net.minecraft.world.entity.Entity; +//import net.minecraft.world.entity.LivingEntity; +//import net.minecraft.world.entity.player.Player; +//import net.minecraft.world.item.ItemStack; +//import net.minecraft.world.level.Level; +//import net.minecraft.world.phys.Vec3; +//import net.neoforged.bus.api.SubscribeEvent; +//import net.neoforged.fml.common.EventBusSubscriber; +//import net.neoforged.neoforge.event.entity.living.LivingAttackEvent; +//import top.theillusivec4.curios.api.SlotContext; +// +//import java.awt.*; +//import java.util.ArrayList; +//import java.util.List; +// +//public class SpatialSignItem extends RelicItem { +// public static final String TAG_POSITION = "pos"; +// public static final String TAG_TIME = "time"; +// public static final String TAG_WORLD = "world"; +// +// @Override +// public RelicData constructDefaultRelicData() { +// return RelicData.builder() +// .abilities(AbilitiesData.builder() +// .ability(AbilityData.builder("seal") +// .stat(StatData.builder("time") +// .initialValue(2D, 4D) +// .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.25D) +// .formatValue(value -> MathUtils.round(value, 1)) +// .build()) +// .build()) +// .build()) +// .leveling(new LevelingData(100, 10, 200)) +// .style(StyleData.builder() +// .background(Backgrounds.CAVE) +// .build()) +// .loot(LootData.builder() +// .entry(LootCollections.ANTHROPOGENIC) +// .build()) +// .build(); +// } +// +// @Override +// public InteractionResultHolder use(Level worldIn, Player playerIn, InteractionHand handIn) { +// ItemStack stack = playerIn.getItemInHand(handIn); +// +// if (NBTUtils.getList(stack, TAG_POSITION, String.class).size() < 2 || worldIn.isClientSide()) +// return InteractionResultHolder.fail(stack); +// +// if (NBTUtils.getInt(stack, TAG_TIME, 0) > 0) { +// NBTUtils.setInt(stack, TAG_TIME, 0); +// } else { +// NBTUtils.setInt(stack, TAG_TIME, (int) Math.round(getAbilityValue(stack, "seal", "time"))); +// +// worldIn.playSound(null, playerIn.blockPosition(), SoundEvents.EXPERIENCE_ORB_PICKUP, SoundSource.PLAYERS, 1F, 2F); +// } +// +// return InteractionResultHolder.success(stack); +// } +// +// @Override +// public void inventoryTick(ItemStack stack, Level worldIn, Entity entityIn, int itemSlot, boolean isSelected) { +// if (!(entityIn instanceof Player player)) +// return; +// +// RandomSource random = worldIn.getRandom(); +// +// int time = NBTUtils.getInt(stack, TAG_TIME, -1); +// +// if (player.level().isClientSide()) +// player.displayClientMessage(Component.literal(" " + time), true); +// +// List positions = NBTUtils.getList(stack, TAG_POSITION, String.class); +// +// if (time >= 0) { +// if (player.isPassenger()) +// player.stopRiding(); +// +// if (player.tickCount % 20 == 0 && !worldIn.isClientSide()) { +// NBTUtils.setInt(stack, TAG_TIME, --time); +// +// spreadExperience(player, stack, 1); +// } +// +// if (time <= 0) { +// worldIn.playSound(null, player.blockPosition(), SoundEvents.EXPERIENCE_ORB_PICKUP, SoundSource.PLAYERS, 1F, 0.5F); +// +// player.getCooldowns().addCooldown(this, (int) (Math.ceil(getAbilityValue(stack, "seal", "time")) * 20)); +// +// NBTUtils.setInt(stack, TAG_TIME, -1); +// +// return; +// } +// +// if (!positions.isEmpty()) { +// Vec3 target = NBTUtils.parsePosition(positions.get(positions.size() - 1)); +// +// double distance = player.position().distanceTo(target); +// +// if (distance > 2) { +// if (distance > 64) { +// NBTUtils.setInt(stack, TAG_TIME, 0); +// NBTUtils.setList(stack, TAG_POSITION, new ArrayList<>()); +// } +// +// for (int i = 0; i < 10; i++) +// worldIn.addParticle(ParticleUtils.constructSimpleSpark(new Color(255 - random.nextInt(100), 0, 255 - random.nextInt(50)), +// 0.1F + random.nextFloat() * 0.25F, 100, 0.96F), player.getX(), +// player.getY() + random.nextFloat() * player.getBbHeight(), player.getZ(), 0F, random.nextFloat() * 0.1F, 0F); +// +// player.addEffect(new MobEffectInstance(EffectRegistry.VANISHING, 5, 0, false, false)); +// +// player.setDeltaMovement(target.add(0, 1, 0).subtract(player.position()).normalize().scale(0.75F)); +// +// player.fallDistance = 0; +// player.noPhysics = true; +// player.clearFire(); +// } else { +// positions.remove(positions.size() - 1); +// +// NBTUtils.setList(stack, TAG_POSITION, positions); +// } +// } else { +// NBTUtils.setInt(stack, TAG_TIME, 0); +// } +// } +// +// if (player.tickCount % 20 == 0) { +// if (positions.size() >= 5 * getAbilityValue(stack, "seal", "time")) +// positions.remove(0); +// +// if (positions.isEmpty() || player.position().distanceTo(NBTUtils.parsePosition(positions.get(positions.size() - 1))) >= 2) { +// if (worldIn.dimension().location().toString().equals(NBTUtils.getString(stack, TAG_WORLD, ""))) { +// positions.add(NBTUtils.writePosition(player.position())); +// } else { +// positions.clear(); +// +// NBTUtils.setString(stack, TAG_WORLD, worldIn.dimension().location().toString()); +// } +// } +// +// NBTUtils.setList(stack, TAG_POSITION, positions); +// } +// } +// +// @Override +// public int getMaxDamage(ItemStack stack) { +// return 1; +// } +// +// @Override +// public boolean isFoil(ItemStack stack) { +// return NBTUtils.getInt(stack, TAG_TIME, 0) > 0; +// } +// +// @Override +// public boolean canEquipFromUse(SlotContext slotContext, ItemStack stack) { +// return false; +// } +// +// @EventBusSubscriber +// public static class Events { +// @SubscribeEvent +// public static void onLivingAttack(LivingAttackEvent event) { +// LivingEntity entity = event.getEntity(); +// +// if (!(entity instanceof Player player)) +// return; +// +// for (int slot : EntityUtils.getSlotsWithItem(player, ItemRegistry.SPATIAL_SIGN.get()).stream() +// .filter(slot -> slot != -1) +// .toList()) { +// ItemStack stack = player.getInventory().getItem(slot); +// +// if (stack.getItem() instanceof SpatialSignItem && NBTUtils.getInt(stack, TAG_TIME, 0) > 0) { +// event.setCanceled(true); +// +// return; +// } +// } +// } +// } +//} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/back/ArrowQuiverItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/back/ArrowQuiverItem.java index 12a884d4..fef853c4 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/back/ArrowQuiverItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/back/ArrowQuiverItem.java @@ -1,725 +1,724 @@ -package it.hurts.sskirillss.relics.items.relics.back; - -import com.google.common.collect.Lists; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import it.hurts.sskirillss.relics.api.events.common.ContainerSlotClickEvent; -import it.hurts.sskirillss.relics.client.models.items.CurioModel; -import it.hurts.sskirillss.relics.entities.ArrowRainEntity; -import it.hurts.sskirillss.relics.init.EffectRegistry; -import it.hurts.sskirillss.relics.init.EntityRegistry; -import it.hurts.sskirillss.relics.init.ItemRegistry; -import it.hurts.sskirillss.relics.init.SoundRegistry; -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.IRenderableCurio; -import it.hurts.sskirillss.relics.items.relics.base.RelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastStage; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; -import it.hurts.sskirillss.relics.network.NetworkHandler; -import it.hurts.sskirillss.relics.network.packets.PacketPlayerMotion; -import it.hurts.sskirillss.relics.utils.*; -import lombok.Getter; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; -import net.minecraft.client.model.EntityModel; -import net.minecraft.client.model.HumanoidModel; -import net.minecraft.client.model.geom.PartPose; -import net.minecraft.client.model.geom.builders.*; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.client.renderer.entity.RenderLayerParent; -import net.minecraft.client.renderer.texture.OverlayTexture; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.RandomSource; -import net.minecraft.world.effect.MobEffectInstance; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.entity.projectile.AbstractArrow; -import net.minecraft.world.inventory.ClickAction; -import net.minecraft.world.inventory.tooltip.TooltipComponent; -import net.minecraft.world.item.ArrowItem; -import net.minecraft.world.item.BowItem; -import net.minecraft.world.item.CrossbowItem; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.ClipContext; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.BlockHitResult; -import net.minecraft.world.phys.EntityHitResult; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.event.entity.EntityJoinLevelEvent; -import net.minecraftforge.event.entity.ProjectileImpactEvent; -import net.minecraftforge.event.entity.living.LivingGetProjectileEvent; -import net.minecraftforge.event.entity.living.LivingHurtEvent; -import net.minecraftforge.event.entity.player.ArrowLooseEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import top.theillusivec4.curios.api.SlotContext; -import top.theillusivec4.curios.api.client.ICurioRenderer; - -import java.awt.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -public class ArrowQuiverItem extends RelicItem implements IRenderableCurio { - private static final String TAG_LEAP = "leap"; - private static final String TAG_ARROWS = "arrows"; - - @Override - public RelicData constructDefaultRelicData() { - return RelicData.builder() - .abilities(AbilitiesData.builder() - .ability(AbilityData.builder("receptacle") - .maxLevel(10) - .stat(StatData.builder("slots") - .initialValue(2, 5) - .upgradeModifier(UpgradeOperation.ADD, 1) - .formatValue(value -> (int) Math.round(value)) - .build()) - .build()) - .ability(AbilityData.builder("leap") - .requiredLevel(5) - .maxLevel(10) - .active(CastData.builder() - .type(CastType.INSTANTANEOUS) - .castPredicate("target", (player, stack) -> { - Level level = player.level(); - - double maxDistance = player.getBlockReach() + 1; - - Vec3 view = player.getViewVector(0); - Vec3 eyeVec = player.getEyePosition(0); - - BlockHitResult ray = level.clip(new ClipContext(eyeVec, eyeVec.add(view.x * maxDistance, view.y * maxDistance, - view.z * maxDistance), ClipContext.Block.COLLIDER, ClipContext.Fluid.ANY, player)); - - return ray.getType() != HitResult.Type.MISS && ray.getLocation().y() < player.getEyePosition().y(); - }) - .build() - ) - .stat(StatData.builder("multiplier") - .initialValue(0.1, 0.5) - .upgradeModifier(UpgradeOperation.MULTIPLY_TOTAL, 0.15) - .formatValue(value -> (int) (MathUtils.round(value, 2) * 100)) - .build()) - .stat(StatData.builder("duration") - .initialValue(4, 6) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.1) - .formatValue(value -> MathUtils.round(value, 1)) - .build()) - .stat(StatData.builder("cooldown") - .initialValue(15, 12) - .upgradeModifier(UpgradeOperation.MULTIPLY_TOTAL, -0.1) - .formatValue(value -> MathUtils.round(value, 1)) - .build()) - .build()) - .ability(AbilityData.builder("agility") - .requiredLevel(10) - .requiredPoints(2) - .maxLevel(5) - .stat(StatData.builder("modifier") - .initialValue(1, 1) - .upgradeModifier(UpgradeOperation.ADD, 1) - .formatValue(value -> (int) ((1 + MathUtils.round(value, 0))) * 100) - .build()) - .build()) - .ability(AbilityData.builder("rain") - .requiredLevel(15) - .maxLevel(10) - .active(CastData.builder() - .type(CastType.INSTANTANEOUS) - .castPredicate("arrow", (player, stack) -> { - int count = 0; - - for (ItemStack arrow : getArrows(stack)) - count += arrow.getCount(); - - return count > 0; - } - ) - .build() - ) - .stat(StatData.builder("radius") - .initialValue(3, 5) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.15) - .formatValue(value -> MathUtils.round(value, 1)) - .build()) - .stat(StatData.builder("duration") - .initialValue(10, 15) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.25) - .formatValue(value -> MathUtils.round(value, 1)) - .build()) - .stat(StatData.builder("delay") - .initialValue(1, 0.75) - .upgradeModifier(UpgradeOperation.MULTIPLY_TOTAL, -0.15) - .formatValue(value -> MathUtils.round(value, 2)) - .build()) - .build()) - .build()) - .leveling(new LevelingData(100, 20, 100)) - .style(StyleData.builder() - .background(Backgrounds.PLAINS) - .build()) - .loot(LootData.builder() - .entry(LootCollections.VILLAGE) - .build()) - .build(); - } - - @Override - public void castActiveAbility(ItemStack stack, Player player, String ability, CastType type, CastStage stage) { - Level level = player.getCommandSenderWorld(); - RandomSource random = level.getRandom(); - - if (ability.equals("rain")) { - if (getArrows(stack).isEmpty()) - return; - - double maxDistance = 32; - - Vec3 view = player.getViewVector(0); - Vec3 eyeVec = player.getEyePosition(0); - - BlockHitResult ray = level.clip(new ClipContext(eyeVec, eyeVec.add(view.x * maxDistance, view.y * maxDistance, - view.z * maxDistance), ClipContext.Block.COLLIDER, ClipContext.Fluid.ANY, player)); - - Vec3 target = ray.getLocation(); - - int duration = (int) Math.round(getAbilityValue(stack, "rain", "duration") * 20); - - ArrowRainEntity rain = new ArrowRainEntity(EntityRegistry.ARROW_RAIN.get(), level); - - rain.setDelay((int) Math.round(getAbilityValue(stack, "rain", "delay") * 20)); - rain.setRadius((float) getAbilityValue(stack, "rain", "radius")); - rain.setQuiver(stack.copy()); - rain.setDuration(duration); - rain.setOwner(player); - rain.setPos(target); - - level.addFreshEntity(rain); - - setAbilityCooldown(stack, "rain", duration); - } - - if (ability.equals("leap")) { - double maxDistance = player.getBlockReach() + 1; - - Vec3 view = player.getViewVector(0); - Vec3 eyeVec = player.getEyePosition(0); - - BlockHitResult ray = level.clip(new ClipContext(eyeVec, eyeVec.add(view.x * maxDistance, view.y * maxDistance, - view.z * maxDistance), ClipContext.Block.COLLIDER, ClipContext.Fluid.ANY, player)); - - if (ray.getType() != HitResult.Type.MISS && ray.getLocation().y() < player.getEyePosition().y()) { - Vec3 motion = player.getLookAngle().scale(-1).normalize().scale(2F); - - for (int i = 0; i < 100; i++) { - level.addParticle(ParticleTypes.SPIT, player.getX(), player.getY(), player.getZ(), - motion.x() + MathUtils.randomFloat(random) * 0.1F, - motion.y() + MathUtils.randomFloat(random) * 0.25F, - motion.z() + MathUtils.randomFloat(random) * 0.1F); - } - - if (!level.isClientSide()) { - NetworkHandler.sendToClient(new PacketPlayerMotion(motion.x, motion.y, motion.z), (ServerPlayer) player); - - NBTUtils.setInt(stack, TAG_LEAP, 0); - - setAbilityCooldown(stack, "leap", (int) Math.round(getAbilityValue(stack, "leap", "cooldown") * 20)); - - level.playSound(null, player.blockPosition(), SoundRegistry.LEAP.get(), SoundSource.MASTER, 1F, 1F + random.nextFloat() * 0.5F); - } - } - } - } - - @Override - public void tickActiveAbilitySelection(ItemStack stack, Player player, String ability) { - Level level = player.getCommandSenderWorld(); - - if (ability.equals("rain")) { - double maxDistance = 32; - - Vec3 view = player.getViewVector(0); - Vec3 eyeVec = player.getEyePosition(0); - - BlockHitResult ray = level.clip(new ClipContext(eyeVec, eyeVec.add(view.x * maxDistance, view.y * maxDistance, - view.z * maxDistance), ClipContext.Block.COLLIDER, ClipContext.Fluid.ANY, player)); - - Vec3 target = ray.getLocation(); - - ParticleUtils.createCyl(ParticleUtils.constructSimpleSpark(new Color(255, 255, 255), 0.2F, 0, 1F), - target, level, getAbilityValue(stack, "rain", "radius"), 0.2F); - } - } - - @Override - public void curioTick(String identifier, int index, LivingEntity livingEntity, ItemStack stack) { - if (!(livingEntity instanceof Player player)) - return; - - Level level = player.level(); - - if (canUseAbility(stack, "leap")) { - int leap = NBTUtils.getInt(stack, TAG_LEAP, -1); - - if (leap >= 0) { - if (!level.isClientSide()) { - NBTUtils.setInt(stack, TAG_LEAP, ++leap); - - player.addEffect(new MobEffectInstance(EffectRegistry.VANISHING.get(), 5, 0, false, false)); - - player.fallDistance = 0F; - - if (leap >= 5 && (player.onGround() || player.getAbilities().flying - || player.isFallFlying() || player.isInWater() || player.isInLava() - || leap >= getAbilityValue(stack, "leap", "duration") * 20)) { - NBTUtils.clearTag(stack, TAG_LEAP); - } - } - - if (player.isUsingItem() && player.getMainHandItem().getItem() instanceof BowItem) { - player.setDeltaMovement(player.getDeltaMovement().multiply(0.975F, player.getDeltaMovement().y() > 0 ? 0.9F : 0F, 0.975F)); - } - } - } - - if (canUseAbility(stack, "agility")) { - if (player.isUsingItem() && player.getMainHandItem().getItem() instanceof BowItem) { - for (int i = 0; i < 1; i++) - player.updatingUsingItem(); - } - } - } - - public int getSlotsAmount(ItemStack stack) { - return (int) Math.round(getAbilityValue(stack, "receptacle", "slots")); - } - - @Override - public Optional getTooltipImage(ItemStack stack) { - return Optional.of(new ArrowQuiverTooltip(getArrows(stack), getSlotsAmount(stack))); - } - - public static List getArrows(ItemStack stack) { - CompoundTag tag = stack.getTag(); - - return tag == null ? new ArrayList<>() : tag.getList(TAG_ARROWS, 10).stream() - .map(CompoundTag.class::cast) - .map(ItemStack::of) - .collect(Collectors.toList()); - } - - public int insertStack(ItemStack stack, ItemStack arrow) { - if (!arrow.getItem().canFitInsideContainerItems()) - return 0; - - CompoundTag tag = stack.getOrCreateTag(); - - if (!tag.contains(TAG_ARROWS)) - tag.put(TAG_ARROWS, new ListTag()); - - ListTag list = tag.getList(TAG_ARROWS, 10); - - List entries = list.stream() - .filter(CompoundTag.class::isInstance) - .map(CompoundTag.class::cast) - .filter(nbt -> ItemStack.isSameItemSameTags(ItemStack.of(nbt), arrow)) - .filter(nbt -> { - ItemStack item = ItemStack.of(nbt); - - return item.getCount() < item.getMaxStackSize(); - }) - .toList(); - - int amount = 0; - - if (!entries.isEmpty()) { - for (CompoundTag entry : entries) { - ItemStack s = ItemStack.of(entry); - - int count = s.getCount() + arrow.getCount(); - - if (count <= s.getMaxStackSize()) { - amount += arrow.getCount(); - - arrow.setCount(0); - - s.grow(amount); - s.save(entry); - - list.remove(entry); - list.add(0, entry); - - break; - } else { - int step = s.getMaxStackSize() - s.getCount(); - - amount += step; - - arrow.shrink(step); - - s.grow(step); - s.save(entry); - - list.remove(entry); - list.add(0, entry); - } - } - } - - if (!arrow.isEmpty()) { - if (getSlotsAmount(stack) <= getArrows(stack).size()) - return 0; - - amount += arrow.getCount(); - - CompoundTag entry = new CompoundTag(); - - arrow.copy().save(entry); - - list.add(0, entry); - } - - return amount; - } - - public static Optional takeStack(ItemStack stack) { - CompoundTag tag = stack.getOrCreateTag(); - - if (!tag.contains(TAG_ARROWS)) - return Optional.empty(); - - ListTag list = tag.getList(TAG_ARROWS, 10); - - if (list.isEmpty()) - return Optional.empty(); - - ItemStack s = ItemStack.of(list.getCompound(0)); - - list.remove(0); - - if (list.isEmpty()) - stack.removeTagKey(TAG_ARROWS); - - return Optional.of(s); - } - - public static void takeArrow(ItemStack stack) { - CompoundTag tag = stack.getOrCreateTag(); - - if (!tag.contains(TAG_ARROWS)) - return; - - ListTag list = tag.getList(TAG_ARROWS, 10); - - if (list.isEmpty()) - return; - - CompoundTag entry = list.getCompound(0); - - ItemStack s = ItemStack.of(entry); - - s.shrink(1); - s.save(entry); - - list.remove(0); - - if (!s.isEmpty()) - list.add(0, entry); - - if (list.isEmpty()) - stack.removeTagKey(TAG_ARROWS); - } - - @Override - @OnlyIn(Dist.CLIENT) - public > void render(ItemStack stack, SlotContext slotContext, PoseStack matrixStack, RenderLayerParent renderLayerParent, MultiBufferSource renderTypeBuffer, int light, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch) { - CurioModel model = getModel(stack); - - matrixStack.pushPose(); - - LivingEntity entity = slotContext.entity(); - - model.prepareMobModel(entity, limbSwing, limbSwingAmount, partialTicks); - model.setupAnim(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch); - - ICurioRenderer.followBodyRotations(entity, model); - - VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), false, stack.hasFoil()); - - model.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY, 1.0F, 1.0F, 1.0F, 1.0F); - - matrixStack.popPose(); - } - - @Override - @OnlyIn(Dist.CLIENT) - public LayerDefinition constructLayerDefinition() { - MeshDefinition mesh = HumanoidModel.createMesh(new CubeDeformation(0.4F), 0.0F); - - PartDefinition body = mesh.getRoot().addOrReplaceChild("body", CubeListBuilder.create().texOffs(0, 0).addBox(-4.0F, 0.0F, -2.0F, 8.0F, 12.0F, 4.0F, new CubeDeformation(0.5F)), PartPose.offset(0.0F, 0.0F, 0.0F)); - - PartDefinition cube_r1 = body.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(16, 16).addBox(-1.5F, -3.0F, -1.75F, 4.0F, 1.0F, 4.0F, new CubeDeformation(0.0F)) - .texOffs(16, 21).addBox(-1.0F, -2.0F, -1.25F, 3.0F, 4.0F, 3.0F, new CubeDeformation(0.25F)) - .texOffs(0, 16).addBox(-1.5F, 2.0F, -1.75F, 4.0F, 7.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-2.5F, 2.5F, 3.5F, 0.0F, 0.0F, -0.7854F)); - - PartDefinition cube_r2 = body.addOrReplaceChild("cube_r2", CubeListBuilder.create().texOffs(27, 10).addBox(-1.2F, -0.25F, 0.175F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-8.4534F, -1.2997F, 3.75F, 2.9686F, -0.8855F, 2.0959F)); - PartDefinition cube_r3 = body.addOrReplaceChild("cube_r3", CubeListBuilder.create().texOffs(27, 10).addBox(-0.825F, -0.25F, 0.175F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-8.4534F, -1.2997F, 3.75F, 3.0018F, 0.6732F, 1.874F)); - PartDefinition cube_r4 = body.addOrReplaceChild("cube_r4", CubeListBuilder.create().texOffs(29, 12).addBox(-0.5F, -0.5F, 0.0F, 1.0F, 3.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.4534F, -0.4497F, 3.75F, 3.0018F, 0.6732F, 1.874F)); - PartDefinition cube_r5 = body.addOrReplaceChild("cube_r5", CubeListBuilder.create().texOffs(29, 12).addBox(-0.5F, -0.5F, 0.0F, 1.0F, 3.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.4534F, -0.4497F, 3.75F, 2.9686F, -0.8855F, 2.0959F)); - PartDefinition cube_r6 = body.addOrReplaceChild("cube_r6", CubeListBuilder.create().texOffs(27, 5).addBox(-1.0F, -0.5F, 0.0F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-5.7784F, -2.1997F, 5.375F, -0.5251F, -0.8705F, -0.3867F)); - PartDefinition cube_r7 = body.addOrReplaceChild("cube_r7", CubeListBuilder.create().texOffs(27, 5).addBox(-1.0F, -0.5F, 0.0F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-5.7784F, -2.1997F, 5.375F, -2.7418F, -0.5916F, 2.1065F)); - PartDefinition cube_r8 = body.addOrReplaceChild("cube_r8", CubeListBuilder.create().texOffs(29, 7).addBox(-0.5F, -0.5F, 0.0F, 1.0F, 3.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-4.4534F, -0.9497F, 4.75F, -2.7418F, -0.5916F, 2.1065F)); - PartDefinition cube_r9 = body.addOrReplaceChild("cube_r9", CubeListBuilder.create().texOffs(29, 7).addBox(-0.5F, -0.5F, 0.0F, 1.0F, 3.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-4.4534F, -0.9497F, 4.75F, -0.5251F, -0.8705F, -0.3867F)); - PartDefinition cube_r10 = body.addOrReplaceChild("cube_r10", CubeListBuilder.create().texOffs(27, 0).addBox(-1.0F, -0.5F, 0.0F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-5.3784F, -4.1997F, 2.4F, 1.0472F, -1.3526F, -1.3963F)); - PartDefinition cube_r11 = body.addOrReplaceChild("cube_r11", CubeListBuilder.create().texOffs(27, 0).addBox(-1.0F, -0.5F, 0.0F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-5.3784F, -4.1997F, 2.4F, 0.1897F, 0.1084F, -0.3387F)); - PartDefinition cube_r12 = body.addOrReplaceChild("cube_r12", CubeListBuilder.create().texOffs(29, 2).addBox(-0.5F, -0.5F, 0.0F, 1.0F, 3.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-4.7034F, -2.4497F, 2.75F, 1.0472F, -1.3526F, -1.3963F)); - PartDefinition cube_r13 = body.addOrReplaceChild("cube_r13", CubeListBuilder.create().texOffs(29, 2).addBox(-0.5F, -0.5F, 0.0F, 1.0F, 3.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-4.7034F, -2.4497F, 2.75F, 0.1897F, 0.1084F, -0.3387F)); - - return LayerDefinition.create(mesh, 32, 32); - } - - @Override - public List headParts() { - return Lists.newArrayList("body"); - } - - public record ArrowQuiverTooltip(@Getter List items, @Getter int maxAmount) implements TooltipComponent { - - } - - @OnlyIn(Dist.CLIENT) - public record ClientArrowQuiverTooltip(@Getter ArrowQuiverTooltip tooltip) implements ClientTooltipComponent { - public static final ResourceLocation TEXTURE = new ResourceLocation(Reference.MODID, "textures/gui/tooltip/arrow_quiver/empty_arrow.png"); - - @Override - public int getHeight() { - return 26; - } - - @Override - public int getWidth(Font font) { - return tooltip.getMaxAmount() * 11; - } - - @Override - public void renderImage(Font font, int mouseX, int mouseY, GuiGraphics guiGraphics) { - Minecraft MC = Minecraft.getInstance(); - PoseStack poseStack = guiGraphics.pose(); - - poseStack.pushPose(); - - poseStack.translate(0, 0, 410); - - int step = 0; - - for (ItemStack stack : tooltip.getItems()) { - guiGraphics.renderItem(stack, mouseX + step, mouseY); - - poseStack.scale(0.5F, 0.5F, 0.5F); - - guiGraphics.drawString(MC.font, String.valueOf(stack.getCount()), ((mouseX + step) * 2) + ((16 - font.width(String.valueOf(stack.getCount()))) / 2), (mouseY + 16) * 2, 0xFFFFFF); - - poseStack.scale(2F, 2F, 2F); - - step += 10; - } - - for (int i = step / 10; i < tooltip.getMaxAmount(); i++) { - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, TEXTURE); - - Minecraft.getInstance().getTextureManager().getTexture(TEXTURE).bind(); - - guiGraphics.blit(TEXTURE, mouseX + step, mouseY, 16, 16, 0, 0, 16, 16, 16, 16); - - step += 10; - } - - poseStack.translate(0, 0, -410); - - poseStack.popPose(); - } - } - - @Mod.EventBusSubscriber - public static class Events { - @SubscribeEvent - public static void onSlotClick(ContainerSlotClickEvent event) { - Player player = event.getEntity(); - - ItemStack heldStack = event.getHeldStack(); - ItemStack slotStack = event.getSlotStack(); - - if (slotStack.getItem() != ItemRegistry.ARROW_QUIVER.get() - || !((IRelicItem) slotStack.getItem()).canUseAbility(slotStack, "receptacle")) - return; - - if (event.getAction() == ClickAction.PRIMARY) { - if (!(heldStack.getItem() instanceof ArrowItem)) - return; - - int amount = ((ArrowQuiverItem) slotStack.getItem()).insertStack(slotStack, heldStack); - - if (amount <= 0) - return; - - heldStack.shrink(amount); - - player.playSound(SoundEvents.BUNDLE_INSERT, 1F, 1F); - - event.setCanceled(true); - } else { - if (!heldStack.isEmpty()) - return; - - takeStack(slotStack).ifPresent((stack) -> { - event.getContainer().setCarried(stack); - - player.playSound(SoundEvents.BUNDLE_REMOVE_ONE, 1F, 1F); - - event.setCanceled(true); - }); - } - } - - @SubscribeEvent - public static void onArrowLoose(ArrowLooseEvent event) { - Player player = event.getEntity(); - ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.ARROW_QUIVER.get()); - - if (stack.isEmpty() || !((IRelicItem) stack.getItem()).canUseAbility(stack, "receptacle") - || getArrows(stack).isEmpty() || player.isCreative()) - return; - - takeArrow(stack); - } - - @SubscribeEvent - public static void onGettingProjectile(LivingGetProjectileEvent event) { - if (!(event.getEntity() instanceof Player player)) - return; - - ItemStack weapon = event.getProjectileWeaponItemStack(); - - if (!(weapon.getItem() instanceof BowItem) || (weapon.getItem() instanceof CrossbowItem)) - return; - - ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.ARROW_QUIVER.get()); - - if (stack.isEmpty() || !((IRelicItem) stack.getItem()).canUseAbility(stack, "receptacle")) - return; - - List arrows = getArrows(stack); - - if (!arrows.isEmpty()) - event.setProjectileItemStack(arrows.get(0)); - } - - @SubscribeEvent - public static void onLivingHurt(LivingHurtEvent event) { - if (!(event.getSource().getDirectEntity() instanceof AbstractArrow arrow) - || !(arrow.getOwner() instanceof Player player)) - return; - - ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.ARROW_QUIVER.get()); - - if (stack.isEmpty() || !(stack.getItem() instanceof IRelicItem relic)) - return; - - if (relic.canUseAbility(stack, "receptacle")) { - int amount = (int) Math.min(10, Math.round(player.position().distanceTo(new Vec3(arrow.getX(), player.getY(), arrow.getZ())) * 0.1)); - - if (amount > 0) - relic.spreadExperience(player, stack, amount); - } - - if (relic.canUseAbility(stack, "leap")) { - if (arrow.getPersistentData().contains("arrow_quiver_multiplier")) - event.setAmount((float) (event.getAmount() + (event.getAmount() * relic.getAbilityValue(stack, "leap", "multiplier")))); - } - } - - @SubscribeEvent - public static void onEntitySpawned(EntityJoinLevelEvent event) { - if (event.getLevel().isClientSide() - || !(event.getEntity() instanceof AbstractArrow arrow) - || !(arrow.getOwner() instanceof Player player) - || arrow.position().distanceTo(player.position()) > 16 - || arrow.life > 0) - return; - - ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.ARROW_QUIVER.get()); - - if (stack.isEmpty() || !((IRelicItem) stack.getItem()).canUseAbility(stack, "leap") - || NBTUtils.getInt(stack, TAG_LEAP, -1) < 0) - return; - - NBTUtils.clearTag(stack, TAG_LEAP); - - if (!arrow.isCritArrow()) - return; - - Level level = player.getCommandSenderWorld(); - - level.playSound(null, player.blockPosition(), SoundRegistry.POWERED_ARROW.get(), SoundSource.MASTER, 1F, 1F + player.getRandom().nextFloat() * 0.5F); - - arrow.getPersistentData().putBoolean("arrow_quiver_multiplier", true); - arrow.setNoGravity(true); - - Vec3 motion = player.getLookAngle().scale(-1).normalize(); - - if (!level.isClientSide()) - NetworkHandler.sendToClient(new PacketPlayerMotion(motion.x, motion.y, motion.z), (ServerPlayer) player); - } - - @SubscribeEvent - public static void onProjectileImpact(ProjectileImpactEvent event) { - if (!(event.getRayTraceResult() instanceof EntityHitResult result) - || !(result.getEntity() instanceof LivingEntity entity) - || !(event.getEntity() instanceof AbstractArrow arrow) - || !(arrow.getOwner() instanceof Player player)) - return; - - ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.ARROW_QUIVER.get()); - - if (stack.isEmpty() || !((IRelicItem) stack.getItem()).canUseAbility(stack, "leap")) - return; - - CompoundTag data = arrow.getPersistentData(); - - if (data.contains("arrow_quiver_multiplier")) { - if (EntityUtils.isAlliedTo(player, entity)) - event.setCanceled(true); - else - data.remove("arrow_quiver_multiplier"); - } - } - } -} \ No newline at end of file +//package it.hurts.sskirillss.relics.items.relics.back; +// +//import com.google.common.collect.Lists; +//import com.mojang.blaze3d.systems.RenderSystem; +//import com.mojang.blaze3d.vertex.PoseStack; +//import com.mojang.blaze3d.vertex.VertexConsumer; +//import it.hurts.sskirillss.relics.api.events.common.ContainerSlotClickEvent; +//import it.hurts.sskirillss.relics.client.models.items.CurioModel; +//import it.hurts.sskirillss.relics.entities.ArrowRainEntity; +//import it.hurts.sskirillss.relics.init.*; +//import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +//import it.hurts.sskirillss.relics.items.relics.base.IRenderableCurio; +//import it.hurts.sskirillss.relics.items.relics.base.RelicItem; +//import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +//import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; +//import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastStage; +//import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; +//import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; +//import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; +//import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; +//import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; +//import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +//import it.hurts.sskirillss.relics.network.NetworkHandler; +//import it.hurts.sskirillss.relics.network.packets.PacketPlayerMotion; +//import it.hurts.sskirillss.relics.utils.*; +//import lombok.Getter; +//import net.minecraft.client.Minecraft; +//import net.minecraft.client.gui.Font; +//import net.minecraft.client.gui.GuiGraphics; +//import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; +//import net.minecraft.client.model.EntityModel; +//import net.minecraft.client.model.HumanoidModel; +//import net.minecraft.client.model.geom.PartPose; +//import net.minecraft.client.model.geom.builders.*; +//import net.minecraft.client.renderer.MultiBufferSource; +//import net.minecraft.client.renderer.RenderType; +//import net.minecraft.client.renderer.entity.ItemRenderer; +//import net.minecraft.client.renderer.entity.RenderLayerParent; +//import net.minecraft.client.renderer.texture.OverlayTexture; +//import net.minecraft.core.HolderLookup; +//import net.minecraft.core.particles.ParticleTypes; +//import net.minecraft.nbt.CompoundTag; +//import net.minecraft.nbt.ListTag; +//import net.minecraft.resources.ResourceLocation; +//import net.minecraft.server.level.ServerPlayer; +//import net.minecraft.sounds.SoundEvents; +//import net.minecraft.sounds.SoundSource; +//import net.minecraft.util.RandomSource; +//import net.minecraft.world.effect.MobEffectInstance; +//import net.minecraft.world.entity.LivingEntity; +//import net.minecraft.world.entity.player.Player; +//import net.minecraft.world.entity.projectile.AbstractArrow; +//import net.minecraft.world.inventory.ClickAction; +//import net.minecraft.world.inventory.tooltip.TooltipComponent; +//import net.minecraft.world.item.ArrowItem; +//import net.minecraft.world.item.BowItem; +//import net.minecraft.world.item.CrossbowItem; +//import net.minecraft.world.item.ItemStack; +//import net.minecraft.world.level.ClipContext; +//import net.minecraft.world.level.Level; +//import net.minecraft.world.phys.BlockHitResult; +//import net.minecraft.world.phys.EntityHitResult; +//import net.minecraft.world.phys.HitResult; +//import net.minecraft.world.phys.Vec3; +//import net.neoforged.api.distmarker.Dist; +//import net.neoforged.api.distmarker.OnlyIn; +//import net.neoforged.bus.api.SubscribeEvent; +//import net.neoforged.fml.common.EventBusSubscriber; +//import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent; +//import net.neoforged.neoforge.event.entity.ProjectileImpactEvent; +//import net.neoforged.neoforge.event.entity.living.LivingGetProjectileEvent; +//import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; +//import net.neoforged.neoforge.event.entity.player.ArrowLooseEvent; +//import top.theillusivec4.curios.api.SlotContext; +//import top.theillusivec4.curios.api.client.ICurioRenderer; +// +//import java.awt.*; +//import java.util.ArrayList; +//import java.util.List; +//import java.util.Optional; +//import java.util.stream.Collectors; +// +//import static it.hurts.sskirillss.relics.init.DataComponentRegistry.TIME; +// +//public class ArrowQuiverItem extends RelicItem implements IRenderableCurio { +// private static final String TAG_ARROWS = "arrows"; +// +// @Override +// public RelicData constructDefaultRelicData() { +// return RelicData.builder() +// .abilities(AbilitiesData.builder() +// .ability(AbilityData.builder("receptacle") +// .maxLevel(10) +// .stat(StatData.builder("slots") +// .initialValue(2, 5) +// .upgradeModifier(UpgradeOperation.ADD, 1) +// .formatValue(value -> (int) Math.round(value)) +// .build()) +// .build()) +// .ability(AbilityData.builder("leap") +// .requiredLevel(5) +// .maxLevel(10) +// .active(CastData.builder() +// .type(CastType.INSTANTANEOUS) +// .castPredicate("target", (player, stack) -> { +// Level level = player.level(); +// +// double maxDistance = player.blockInteractionRange() + 1; +// +// Vec3 view = player.getViewVector(0); +// Vec3 eyeVec = player.getEyePosition(0); +// +// BlockHitResult ray = level.clip(new ClipContext(eyeVec, eyeVec.add(view.x * maxDistance, view.y * maxDistance, +// view.z * maxDistance), ClipContext.Block.COLLIDER, ClipContext.Fluid.ANY, player)); +// +// return ray.getType() != HitResult.Type.MISS && ray.getLocation().y() < player.getEyePosition().y(); +// }) +// .build() +// ) +// .stat(StatData.builder("multiplier") +// .initialValue(0.1, 0.5) +// .upgradeModifier(UpgradeOperation.MULTIPLY_TOTAL, 0.15) +// .formatValue(value -> (int) (MathUtils.round(value, 2) * 100)) +// .build()) +// .stat(StatData.builder("duration") +// .initialValue(4, 6) +// .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.1) +// .formatValue(value -> MathUtils.round(value, 1)) +// .build()) +// .stat(StatData.builder("cooldown") +// .initialValue(15, 12) +// .upgradeModifier(UpgradeOperation.MULTIPLY_TOTAL, -0.1) +// .formatValue(value -> MathUtils.round(value, 1)) +// .build()) +// .build()) +// .ability(AbilityData.builder("agility") +// .requiredLevel(10) +// .requiredPoints(2) +// .maxLevel(5) +// .stat(StatData.builder("modifier") +// .initialValue(1, 1) +// .upgradeModifier(UpgradeOperation.ADD, 1) +// .formatValue(value -> (int) ((1 + MathUtils.round(value, 0))) * 100) +// .build()) +// .build()) +// .ability(AbilityData.builder("rain") +// .requiredLevel(15) +// .maxLevel(10) +// .active(CastData.builder() +// .type(CastType.INSTANTANEOUS) +// .castPredicate("arrow", (player, stack) -> { +// int count = 0; +// +// for (ItemStack arrow : getArrows(player.registryAccess(), stack)) +// count += arrow.getCount(); +// +// return count > 0; +// } +// ) +// .build() +// ) +// .stat(StatData.builder("radius") +// .initialValue(3, 5) +// .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.15) +// .formatValue(value -> MathUtils.round(value, 1)) +// .build()) +// .stat(StatData.builder("duration") +// .initialValue(10, 15) +// .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.25) +// .formatValue(value -> MathUtils.round(value, 1)) +// .build()) +// .stat(StatData.builder("delay") +// .initialValue(1, 0.75) +// .upgradeModifier(UpgradeOperation.MULTIPLY_TOTAL, -0.15) +// .formatValue(value -> MathUtils.round(value, 2)) +// .build()) +// .build()) +// .build()) +// .leveling(new LevelingData(100, 20, 100)) +// .style(StyleData.builder() +// .background(Backgrounds.PLAINS) +// .build()) +// .loot(LootData.builder() +// .entry(LootCollections.VILLAGE) +// .build()) +// .build(); +// } +// +// @Override +// public void castActiveAbility(ItemStack stack, Player player, String ability, CastType type, CastStage stage) { +// Level level = player.getCommandSenderWorld(); +// RandomSource random = level.getRandom(); +// +// if (ability.equals("rain")) { +// if (getArrows(level.registryAccess(), stack).isEmpty()) +// return; +// +// double maxDistance = 32; +// +// Vec3 view = player.getViewVector(0); +// Vec3 eyeVec = player.getEyePosition(0); +// +// BlockHitResult ray = level.clip(new ClipContext(eyeVec, eyeVec.add(view.x * maxDistance, view.y * maxDistance, +// view.z * maxDistance), ClipContext.Block.COLLIDER, ClipContext.Fluid.ANY, player)); +// +// Vec3 target = ray.getLocation(); +// +// int duration = (int) Math.round(getAbilityValue(stack, "rain", "duration") * 20); +// +// ArrowRainEntity rain = new ArrowRainEntity(EntityRegistry.ARROW_RAIN.get(), level); +// +// rain.setDelay((int) Math.round(getAbilityValue(stack, "rain", "delay") * 20)); +// rain.setRadius((float) getAbilityValue(stack, "rain", "radius")); +// rain.setQuiver(stack.copy()); +// rain.setDuration(duration); +// rain.setOwner(player); +// rain.setPos(target); +// +// level.addFreshEntity(rain); +// +// setAbilityCooldown(stack, "rain", duration); +// } +// +// if (ability.equals("leap")) { +// double maxDistance = player.blockInteractionRange() + 1; +// +// Vec3 view = player.getViewVector(0); +// Vec3 eyeVec = player.getEyePosition(0); +// +// BlockHitResult ray = level.clip(new ClipContext(eyeVec, eyeVec.add(view.x * maxDistance, view.y * maxDistance, +// view.z * maxDistance), ClipContext.Block.COLLIDER, ClipContext.Fluid.ANY, player)); +// +// if (ray.getType() != HitResult.Type.MISS && ray.getLocation().y() < player.getEyePosition().y()) { +// Vec3 motion = player.getLookAngle().scale(-1).normalize().scale(2F); +// +// for (int i = 0; i < 100; i++) { +// level.addParticle(ParticleTypes.SPIT, player.getX(), player.getY(), player.getZ(), +// motion.x() + MathUtils.randomFloat(random) * 0.1F, +// motion.y() + MathUtils.randomFloat(random) * 0.25F, +// motion.z() + MathUtils.randomFloat(random) * 0.1F); +// } +// +// if (!level.isClientSide()) { +// NetworkHandler.sendToClient(new PacketPlayerMotion(motion.x, motion.y, motion.z), (ServerPlayer) player); +// +// stack.set(TIME, 0); +// +// setAbilityCooldown(stack, "leap", (int) Math.round(getAbilityValue(stack, "leap", "cooldown") * 20)); +// +// level.playSound(null, player.blockPosition(), SoundRegistry.LEAP.get(), SoundSource.MASTER, 1F, 1F + random.nextFloat() * 0.5F); +// } +// } +// } +// } +// +// @Override +// public void tickActiveAbilitySelection(ItemStack stack, Player player, String ability) { +// Level level = player.getCommandSenderWorld(); +// +// if (ability.equals("rain")) { +// double maxDistance = 32; +// +// Vec3 view = player.getViewVector(0); +// Vec3 eyeVec = player.getEyePosition(0); +// +// BlockHitResult ray = level.clip(new ClipContext(eyeVec, eyeVec.add(view.x * maxDistance, view.y * maxDistance, +// view.z * maxDistance), ClipContext.Block.COLLIDER, ClipContext.Fluid.ANY, player)); +// +// Vec3 target = ray.getLocation(); +// +// ParticleUtils.createCyl(ParticleUtils.constructSimpleSpark(new Color(255, 255, 255), 0.2F, 0, 1F), +// target, level, getAbilityValue(stack, "rain", "radius"), 0.2F); +// } +// } +// +// @Override +// public void curioTick(SlotContext slotContext, ItemStack stack) { +// if (!(slotContext.entity() instanceof Player player)) +// return; +// +// Level level = player.level(); +// +// if (canUseAbility(stack, "leap")) { +// int leap = stack.getOrDefault(TIME, -1); +// +// if (leap >= 0) { +// if (!level.isClientSide()) { +// stack.set(TIME, ++leap); +// +// player.addEffect(new MobEffectInstance(EffectRegistry.VANISHING, 5, 0, false, false)); +// +// player.fallDistance = 0F; +// +// if (leap >= 5 && (player.onGround() || player.getAbilities().flying +// || player.isFallFlying() || player.isInWater() || player.isInLava() +// || leap >= getAbilityValue(stack, "leap", "duration") * 20)) { +// stack.set(TIME, -1); +// } +// } +// +// if (player.isUsingItem() && player.getMainHandItem().getItem() instanceof BowItem) { +// player.setDeltaMovement(player.getDeltaMovement().multiply(0.975F, player.getDeltaMovement().y() > 0 ? 0.9F : 0F, 0.975F)); +// } +// } +// } +// +// if (canUseAbility(stack, "agility")) { +// if (player.isUsingItem() && player.getMainHandItem().getItem() instanceof BowItem) { +// for (int i = 0; i < 1; i++) +// player.updatingUsingItem(); +// } +// } +// } +// +// public int getSlotsAmount(ItemStack stack) { +// return (int) Math.round(getAbilityValue(stack, "receptacle", "slots")); +// } +// +// @Override +// public Optional getTooltipImage(ItemStack stack) { +// return Optional.of(new ArrowQuiverTooltip(getArrows(Minecraft.getInstance().level.registryAccess(), stack), getSlotsAmount(stack))); +// } +// +// public static List getArrows(HolderLookup.Provider provider, ItemStack stack) { +// CompoundTag tag = NBTUtils.getOrCreateTag(stack); +// +// return tag == null ? new ArrayList<>() : tag.getList(TAG_ARROWS, 10).stream() +// .map(CompoundTag.class::cast) +// .map(compound -> ItemStack.parseOptional(provider, compound)) +// .collect(Collectors.toList()); +// } +// +// public int insertStack(HolderLookup.Provider provider, ItemStack stack, ItemStack arrow) { +// if (!arrow.getItem().canFitInsideContainerItems()) +// return 0; +// +// CompoundTag tag = NBTUtils.getOrCreateTag(stack); +// +// if (!tag.contains(TAG_ARROWS)) +// tag.put(TAG_ARROWS, new ListTag()); +// +// ListTag list = tag.getList(TAG_ARROWS, 10); +// +// List entries = list.stream() +// .filter(CompoundTag.class::isInstance) +// .map(CompoundTag.class::cast) +// .filter(nbt -> ItemStack.isSameItemSameComponents(ItemStack.parseOptional(provider, nbt), arrow)) +// .filter(nbt -> { +// ItemStack item = ItemStack.parseOptional(provider, nbt); +// +// return item.getCount() < item.getMaxStackSize(); +// }) +// .toList(); +// +// int amount = 0; +// +// if (!entries.isEmpty()) { +// for (CompoundTag entry : entries) { +// ItemStack s = ItemStack.parseOptional(provider, entry); +// +// int count = s.getCount() + arrow.getCount(); +// +// if (count <= s.getMaxStackSize()) { +// amount += arrow.getCount(); +// +// arrow.setCount(0); +// +// s.grow(amount); +// s.save(provider, entry); +// +// list.remove(entry); +// list.add(0, entry); +// +// break; +// } else { +// int step = s.getMaxStackSize() - s.getCount(); +// +// amount += step; +// +// arrow.shrink(step); +// +// s.grow(step); +// s.save(provider, entry); +// +// list.remove(entry); +// list.add(0, entry); +// } +// } +// } +// +// if (!arrow.isEmpty()) { +// if (getSlotsAmount(stack) <= getArrows(provider, stack).size()) +// return 0; +// +// amount += arrow.getCount(); +// +// CompoundTag entry = new CompoundTag(); +// +// arrow.copy().save(provider, entry); +// +// list.add(0, entry); +// } +// +// return amount; +// } +// +// public static Optional takeStack(HolderLookup.Provider provider, ItemStack stack) { +// CompoundTag tag = NBTUtils.getOrCreateTag(stack); +// +// if (!tag.contains(TAG_ARROWS)) +// return Optional.empty(); +// +// ListTag list = tag.getList(TAG_ARROWS, 10); +// +// if (list.isEmpty()) +// return Optional.empty(); +// +// ItemStack s = ItemStack.parseOptional(provider, list.getCompound(0)); +// +// list.remove(0); +// +// if (list.isEmpty()) +// NBTUtils.getOrCreateTag(stack).remove(TAG_ARROWS); +// +// return Optional.of(s); +// } +// +// public static void takeArrow(HolderLookup.Provider provider, ItemStack stack) { +// CompoundTag tag = NBTUtils.getOrCreateTag(stack); +// +// if (!tag.contains(TAG_ARROWS)) +// return; +// +// ListTag list = tag.getList(TAG_ARROWS, 10); +// +// if (list.isEmpty()) +// return; +// +// CompoundTag entry = list.getCompound(0); +// +// ItemStack s = ItemStack.parseOptional(provider, entry); +// +// s.shrink(1); +// s.save(provider, entry); +// +// list.remove(0); +// +// if (!s.isEmpty()) +// list.add(0, entry); +// +// if (list.isEmpty()) +// NBTUtils.getOrCreateTag(stack).remove(TAG_ARROWS); +// } +// +// @Override +// @OnlyIn(Dist.CLIENT) +// public > void render(ItemStack stack, SlotContext slotContext, PoseStack matrixStack, RenderLayerParent renderLayerParent, MultiBufferSource renderTypeBuffer, int light, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch) { +// CurioModel model = getModel(stack); +// +// matrixStack.pushPose(); +// +// LivingEntity entity = slotContext.entity(); +// +// model.prepareMobModel(entity, limbSwing, limbSwingAmount, partialTicks); +// model.setupAnim(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch); +// +// ICurioRenderer.followBodyRotations(entity, model); +// +// VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), stack.hasFoil()); +// +// model.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY); +// +// matrixStack.popPose(); +// } +// +// @Override +// @OnlyIn(Dist.CLIENT) +// public LayerDefinition constructLayerDefinition() { +// MeshDefinition mesh = HumanoidModel.createMesh(new CubeDeformation(0.4F), 0.0F); +// +// PartDefinition body = mesh.getRoot().addOrReplaceChild("body", CubeListBuilder.create().texOffs(0, 0).addBox(-4.0F, 0.0F, -2.0F, 8.0F, 12.0F, 4.0F, new CubeDeformation(0.5F)), PartPose.offset(0.0F, 0.0F, 0.0F)); +// +// PartDefinition cube_r1 = body.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(16, 16).addBox(-1.5F, -3.0F, -1.75F, 4.0F, 1.0F, 4.0F, new CubeDeformation(0.0F)) +// .texOffs(16, 21).addBox(-1.0F, -2.0F, -1.25F, 3.0F, 4.0F, 3.0F, new CubeDeformation(0.25F)) +// .texOffs(0, 16).addBox(-1.5F, 2.0F, -1.75F, 4.0F, 7.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-2.5F, 2.5F, 3.5F, 0.0F, 0.0F, -0.7854F)); +// +// PartDefinition cube_r2 = body.addOrReplaceChild("cube_r2", CubeListBuilder.create().texOffs(27, 10).addBox(-1.2F, -0.25F, 0.175F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-8.4534F, -1.2997F, 3.75F, 2.9686F, -0.8855F, 2.0959F)); +// PartDefinition cube_r3 = body.addOrReplaceChild("cube_r3", CubeListBuilder.create().texOffs(27, 10).addBox(-0.825F, -0.25F, 0.175F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-8.4534F, -1.2997F, 3.75F, 3.0018F, 0.6732F, 1.874F)); +// PartDefinition cube_r4 = body.addOrReplaceChild("cube_r4", CubeListBuilder.create().texOffs(29, 12).addBox(-0.5F, -0.5F, 0.0F, 1.0F, 3.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.4534F, -0.4497F, 3.75F, 3.0018F, 0.6732F, 1.874F)); +// PartDefinition cube_r5 = body.addOrReplaceChild("cube_r5", CubeListBuilder.create().texOffs(29, 12).addBox(-0.5F, -0.5F, 0.0F, 1.0F, 3.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-6.4534F, -0.4497F, 3.75F, 2.9686F, -0.8855F, 2.0959F)); +// PartDefinition cube_r6 = body.addOrReplaceChild("cube_r6", CubeListBuilder.create().texOffs(27, 5).addBox(-1.0F, -0.5F, 0.0F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-5.7784F, -2.1997F, 5.375F, -0.5251F, -0.8705F, -0.3867F)); +// PartDefinition cube_r7 = body.addOrReplaceChild("cube_r7", CubeListBuilder.create().texOffs(27, 5).addBox(-1.0F, -0.5F, 0.0F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-5.7784F, -2.1997F, 5.375F, -2.7418F, -0.5916F, 2.1065F)); +// PartDefinition cube_r8 = body.addOrReplaceChild("cube_r8", CubeListBuilder.create().texOffs(29, 7).addBox(-0.5F, -0.5F, 0.0F, 1.0F, 3.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-4.4534F, -0.9497F, 4.75F, -2.7418F, -0.5916F, 2.1065F)); +// PartDefinition cube_r9 = body.addOrReplaceChild("cube_r9", CubeListBuilder.create().texOffs(29, 7).addBox(-0.5F, -0.5F, 0.0F, 1.0F, 3.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-4.4534F, -0.9497F, 4.75F, -0.5251F, -0.8705F, -0.3867F)); +// PartDefinition cube_r10 = body.addOrReplaceChild("cube_r10", CubeListBuilder.create().texOffs(27, 0).addBox(-1.0F, -0.5F, 0.0F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-5.3784F, -4.1997F, 2.4F, 1.0472F, -1.3526F, -1.3963F)); +// PartDefinition cube_r11 = body.addOrReplaceChild("cube_r11", CubeListBuilder.create().texOffs(27, 0).addBox(-1.0F, -0.5F, 0.0F, 2.0F, 2.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-5.3784F, -4.1997F, 2.4F, 0.1897F, 0.1084F, -0.3387F)); +// PartDefinition cube_r12 = body.addOrReplaceChild("cube_r12", CubeListBuilder.create().texOffs(29, 2).addBox(-0.5F, -0.5F, 0.0F, 1.0F, 3.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-4.7034F, -2.4497F, 2.75F, 1.0472F, -1.3526F, -1.3963F)); +// PartDefinition cube_r13 = body.addOrReplaceChild("cube_r13", CubeListBuilder.create().texOffs(29, 2).addBox(-0.5F, -0.5F, 0.0F, 1.0F, 3.0F, 0.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-4.7034F, -2.4497F, 2.75F, 0.1897F, 0.1084F, -0.3387F)); +// +// return LayerDefinition.create(mesh, 32, 32); +// } +// +// @Override +// public List headParts() { +// return Lists.newArrayList("body"); +// } +// +// public record ArrowQuiverTooltip(@Getter List items, @Getter int maxAmount) implements TooltipComponent { +// +// } +// +// @OnlyIn(Dist.CLIENT) +// public record ClientArrowQuiverTooltip(@Getter ArrowQuiverTooltip tooltip) implements ClientTooltipComponent { +// public static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/tooltip/arrow_quiver/empty_arrow.png"); +// +// @Override +// public int getHeight() { +// return 26; +// } +// +// @Override +// public int getWidth(Font font) { +// return tooltip.getMaxAmount() * 11; +// } +// +// @Override +// public void renderImage(Font font, int mouseX, int mouseY, GuiGraphics guiGraphics) { +// Minecraft MC = Minecraft.getInstance(); +// PoseStack poseStack = guiGraphics.pose(); +// +// poseStack.pushPose(); +// +// poseStack.translate(0, 0, 410); +// +// int step = 0; +// +// for (ItemStack stack : tooltip.getItems()) { +// guiGraphics.renderItem(stack, mouseX + step, mouseY); +// +// poseStack.scale(0.5F, 0.5F, 0.5F); +// +// guiGraphics.drawString(MC.font, String.valueOf(stack.getCount()), ((mouseX + step) * 2) + ((16 - font.width(String.valueOf(stack.getCount()))) / 2), (mouseY + 16) * 2, 0xFFFFFF); +// +// poseStack.scale(2F, 2F, 2F); +// +// step += 10; +// } +// +// for (int i = step / 10; i < tooltip.getMaxAmount(); i++) { +// RenderSystem.setShaderColor(1F, 1F, 1F, 1F); +// RenderSystem.setShaderTexture(0, TEXTURE); +// +// Minecraft.getInstance().getTextureManager().getTexture(TEXTURE).bind(); +// +// guiGraphics.blit(TEXTURE, mouseX + step, mouseY, 16, 16, 0, 0, 16, 16, 16, 16); +// +// step += 10; +// } +// +// poseStack.translate(0, 0, -410); +// +// poseStack.popPose(); +// } +// } +// +// @EventBusSubscriber +// public static class Events { +// @SubscribeEvent +// public static void onSlotClick(ContainerSlotClickEvent event) { +// Player player = event.getEntity(); +// +// ItemStack heldStack = event.getHeldStack(); +// ItemStack slotStack = event.getSlotStack(); +// +// if (slotStack.getItem() != ItemRegistry.ARROW_QUIVER.get() +// || !((IRelicItem) slotStack.getItem()).canUseAbility(slotStack, "receptacle")) +// return; +// +// if (event.getAction() == ClickAction.PRIMARY) { +// if (!(heldStack.getItem() instanceof ArrowItem)) +// return; +// +// int amount = ((ArrowQuiverItem) slotStack.getItem()).insertStack(player.registryAccess(), slotStack, heldStack); +// +// if (amount <= 0) +// return; +// +// heldStack.shrink(amount); +// +// player.playSound(SoundEvents.BUNDLE_INSERT, 1F, 1F); +// +// event.setCanceled(true); +// } else { +// if (!heldStack.isEmpty()) +// return; +// +// takeStack(player.registryAccess(), slotStack).ifPresent((stack) -> { +// event.getContainer().setCarried(stack); +// +// player.playSound(SoundEvents.BUNDLE_REMOVE_ONE, 1F, 1F); +// +// event.setCanceled(true); +// }); +// } +// } +// +// @SubscribeEvent +// public static void onArrowLoose(ArrowLooseEvent event) { +// Player player = event.getEntity(); +// ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.ARROW_QUIVER.get()); +// +// if (stack.isEmpty() || !((IRelicItem) stack.getItem()).canUseAbility(stack, "receptacle") +// || getArrows(player.registryAccess(), stack).isEmpty() || player.isCreative()) +// return; +// +// takeArrow(player.registryAccess(), stack); +// } +// +// @SubscribeEvent +// public static void onGettingProjectile(LivingGetProjectileEvent event) { +// if (!(event.getEntity() instanceof Player player)) +// return; +// +// ItemStack weapon = event.getProjectileWeaponItemStack(); +// +// if (!(weapon.getItem() instanceof BowItem) || (weapon.getItem() instanceof CrossbowItem)) +// return; +// +// ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.ARROW_QUIVER.get()); +// +// if (stack.isEmpty() || !((IRelicItem) stack.getItem()).canUseAbility(stack, "receptacle")) +// return; +// +// List arrows = getArrows(player.registryAccess(), stack); +// +// if (!arrows.isEmpty()) +// event.setProjectileItemStack(arrows.get(0)); +// } +// +// @SubscribeEvent +// public static void onLivingHurt(LivingIncomingDamageEvent event) { +// if (!(event.getSource().getDirectEntity() instanceof AbstractArrow arrow) +// || !(arrow.getOwner() instanceof Player player)) +// return; +// +// ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.ARROW_QUIVER.get()); +// +// if (stack.isEmpty() || !(stack.getItem() instanceof IRelicItem relic)) +// return; +// +// if (relic.canUseAbility(stack, "receptacle")) { +// int amount = (int) Math.min(10, Math.round(player.position().distanceTo(new Vec3(arrow.getX(), player.getY(), arrow.getZ())) * 0.1)); +// +// if (amount > 0) +// relic.spreadExperience(player, stack, amount); +// } +// +// if (relic.canUseAbility(stack, "leap")) { +// if (arrow.getPersistentData().contains("arrow_quiver_multiplier")) +// event.setAmount((float) (event.getAmount() + (event.getAmount() * relic.getAbilityValue(stack, "leap", "multiplier")))); +// } +// } +// +// @SubscribeEvent +// public static void onEntitySpawned(EntityJoinLevelEvent event) { +// if (event.getLevel().isClientSide() +// || !(event.getEntity() instanceof AbstractArrow arrow) +// || !(arrow.getOwner() instanceof Player player) +// || arrow.position().distanceTo(player.position()) > 16 +// || arrow.life > 0) +// return; +// +// ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.ARROW_QUIVER.get()); +// +// if (stack.isEmpty() || !((IRelicItem) stack.getItem()).canUseAbility(stack, "leap") +// || stack.getOrDefault(TIME, -1) < 0) +// return; +// +// stack.set(TIME, -1); +// +// if (!arrow.isCritArrow()) +// return; +// +// Level level = player.getCommandSenderWorld(); +// +// level.playSound(null, player.blockPosition(), SoundRegistry.POWERED_ARROW.get(), SoundSource.MASTER, 1F, 1F + player.getRandom().nextFloat() * 0.5F); +// +// arrow.getPersistentData().putBoolean("arrow_quiver_multiplier", true); +// arrow.setNoGravity(true); +// +// Vec3 motion = player.getLookAngle().scale(-1).normalize(); +// +// if (!level.isClientSide()) +// NetworkHandler.sendToClient(new PacketPlayerMotion(motion.x, motion.y, motion.z), (ServerPlayer) player); +// } +// +// @SubscribeEvent +// public static void onProjectileImpact(ProjectileImpactEvent event) { +// if (!(event.getRayTraceResult() instanceof EntityHitResult result) +// || !(result.getEntity() instanceof LivingEntity entity) +// || !(event.getEntity() instanceof AbstractArrow arrow) +// || !(arrow.getOwner() instanceof Player player)) +// return; +// +// ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.ARROW_QUIVER.get()); +// +// if (stack.isEmpty() || !((IRelicItem) stack.getItem()).canUseAbility(stack, "leap")) +// return; +// +// CompoundTag data = arrow.getPersistentData(); +// +// if (data.contains("arrow_quiver_multiplier")) { +// if (EntityUtils.isAlliedTo(player, entity)) +// event.setCanceled(true); +// else +// data.remove("arrow_quiver_multiplier"); +// } +// } +// } +//} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/back/ElytraBoosterItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/back/ElytraBoosterItem.java index 1711ef75..047f8518 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/back/ElytraBoosterItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/back/ElytraBoosterItem.java @@ -5,23 +5,21 @@ import com.mojang.blaze3d.vertex.VertexConsumer; import it.hurts.sskirillss.relics.api.events.common.ContainerSlotClickEvent; import it.hurts.sskirillss.relics.client.models.items.CurioModel; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.items.relics.base.IRenderableCurio; import it.hurts.sskirillss.relics.items.relics.base.RelicItem; import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastStage; import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.PredicateType; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; import it.hurts.sskirillss.relics.utils.Reference; import net.minecraft.client.model.EntityModel; import net.minecraft.client.model.HumanoidModel; @@ -44,21 +42,20 @@ import net.minecraft.world.item.crafting.RecipeType; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.ForgeHooks; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; import top.theillusivec4.curios.api.SlotContext; import top.theillusivec4.curios.api.client.ICurioRenderer; import java.util.List; -@Mod.EventBusSubscriber -public class ElytraBoosterItem extends RelicItem implements IRenderableCurio { - public static final String TAG_FUEL = "fuel"; - public static final String TAG_SPEED = "speed"; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.CHARGE; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.SPEED; +@EventBusSubscriber +public class ElytraBoosterItem extends RelicItem implements IRenderableCurio { @Override public RelicData constructDefaultRelicData() { return RelicData.builder() @@ -67,8 +64,8 @@ public RelicData constructDefaultRelicData() { .maxLevel(10) .active(CastData.builder() .type(CastType.CYCLICAL) - .castPredicate("fuel", (player, stack) -> NBTUtils.getInt(stack, TAG_FUEL, 0) > 0) - .castPredicate("elytra", (player, stack) -> player.isFallFlying()) + .predicate("fuel", PredicateType.CAST, (player, stack) -> stack.getOrDefault(CHARGE, 0) > 0) + .predicate("elytra", PredicateType.CAST, (player, stack) -> player.isFallFlying()) .build()) .stat(StatData.builder("capacity") .initialValue(50, 100) @@ -83,39 +80,36 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 100)) - .style(StyleData.builder() - .background(Backgrounds.END) - .build()) .loot(LootData.builder() - .entry(LootCollections.END) + .entry(LootEntries.THE_END, LootEntries.END_LIKE) .build()) .build(); } public int getBreathCapacity(ItemStack stack) { - return (int) Math.round(getAbilityValue(stack, "boost", "capacity")); + return (int) Math.round(getStatValue(stack, "boost", "capacity")); } @Override public void castActiveAbility(ItemStack stack, Player player, String ability, CastType type, CastStage stage) { if (ability.equals("boost")) { if (stage == CastStage.TICK) { - int fuel = NBTUtils.getInt(stack, TAG_FUEL, 0); + int fuel = stack.getOrDefault(CHARGE, 0); if (fuel > 0 && player.tickCount % 20 == 0) - NBTUtils.setInt(stack, TAG_FUEL, --fuel); + stack.set(CHARGE, --fuel); - double speed = NBTUtils.getDouble(stack, TAG_SPEED, 1D); + double speed = stack.getOrDefault(SPEED, 0D); if (player.tickCount % 3 == 0) { - double maxSpeed = getAbilityValue(stack, "boost", "speed"); + double maxSpeed = getStatValue(stack, "boost", "speed"); if (speed < maxSpeed) { speed = Math.min(maxSpeed, speed + ((maxSpeed - 1D) / 100D)); - NBTUtils.setDouble(stack, TAG_SPEED, speed); + stack.set(SPEED, speed); } else { - player.startAutoSpinAttack(5); + player.startAutoSpinAttack(5, 0F, ItemStack.EMPTY); } } @@ -136,7 +130,7 @@ public void castActiveAbility(ItemStack stack, Player player, String ability, Ca 0, 0, 0); if (player.tickCount % Math.max(1, (int) Math.round((10 - speed * 2) / (player.isInWaterOrRain() ? 2 : 1))) == 0) - NBTUtils.setInt(stack, TAG_FUEL, --fuel); + stack.set(CHARGE, --fuel); } } } @@ -148,16 +142,16 @@ public void inventoryTick(ItemStack stack, Level level, Entity entity, int slot, if (!(entity instanceof Player player)) return; - double speed = NBTUtils.getDouble(stack, TAG_SPEED, 1D); - int fuel = NBTUtils.getInt(stack, TAG_FUEL, 0); + double speed = stack.getOrDefault(SPEED, 0D); + int fuel = stack.getOrDefault(CHARGE, 0); if (speed > 1 && (fuel <= 0 || !player.isFallFlying())) - NBTUtils.setDouble(stack, TAG_SPEED, 1D); + stack.set(SPEED, 1D); } @Override public ResourceLocation getTexture(ItemStack stack) { - return new ResourceLocation(Reference.MODID, "textures/models/items/elytra_booster_" + (NBTUtils.getInt(stack, ElytraBoosterItem.TAG_FUEL, 0) > 0 ? 1 : 0) + ".png"); + return ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/item/model/elytra_booster_" + (stack.getOrDefault(CHARGE, 0) > 0 ? 1 : 0) + ".png"); } @Override @@ -174,9 +168,9 @@ public > void render(ItemStack ICurioRenderer.followBodyRotations(entity, model); - VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), false, stack.hasFoil()); + VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), stack.hasFoil()); - model.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY, 1.0F, 1.0F, 1.0F, 1.0F); + model.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY); matrixStack.popPose(); } @@ -219,19 +213,19 @@ public static void onSlotClick(ContainerSlotClickEvent event) { if (!(slotStack.getItem() instanceof ElytraBoosterItem booster)) return; - int time = ForgeHooks.getBurnTime(heldStack, RecipeType.SMELTING) / 20; - int amount = NBTUtils.getInt(slotStack, TAG_FUEL, 0); + int time = heldStack.getBurnTime(RecipeType.SMELTING) / 20; + int amount = slotStack.getOrDefault(CHARGE, 0); int capacity = booster.getBreathCapacity(slotStack); int sum = amount + time; if (time <= 0) return; - NBTUtils.setInt(slotStack, TAG_FUEL, Math.min(capacity, sum)); + slotStack.set(CHARGE, Math.min(capacity, sum)); int left = sum > capacity ? time - (sum - capacity) : time; - booster.spreadExperience(player, slotStack, (int) Math.floor(left / 10F)); + booster.spreadRelicExperience(player, slotStack, (int) Math.floor(left / 10F)); ItemStack result = heldStack.getCraftingRemainingItem(); diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/back/MidnightRobeItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/back/MidnightRobeItem.java index b9f0ee05..89144030 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/back/MidnightRobeItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/back/MidnightRobeItem.java @@ -15,12 +15,9 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; import it.hurts.sskirillss.relics.utils.ParticleUtils; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.geom.PartPose; @@ -39,11 +36,11 @@ import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.VoxelShape; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.event.entity.living.LivingHurtEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; import top.theillusivec4.curios.api.SlotContext; import javax.annotation.Nullable; @@ -51,9 +48,9 @@ import java.util.List; import java.util.UUID; -public class MidnightRobeItem extends RelicItem implements IRenderableCurio { - private static final String TAG_TARGET = "target"; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.TARGET; +public class MidnightRobeItem extends RelicItem implements IRenderableCurio { @Override public RelicData constructDefaultRelicData() { return RelicData.builder() @@ -81,25 +78,25 @@ public RelicData constructDefaultRelicData() { .formatValue(value -> (int) (100 * MathUtils.round(value - 1, 1))) .build()) .stat(StatData.builder("distance") - .initialValue(15D, 20D) + .initialValue(20D, 15D) .upgradeModifier(UpgradeOperation.ADD, -0.5D) .formatValue(value -> MathUtils.round(value, 1)) .build()) .build()) .build()) .leveling(new LevelingData(100, 10, 100)) - .style(StyleData.builder() - .background(Backgrounds.CAVE) - .build()) .loot(LootData.builder() - .entry(LootCollections.ANTHROPOGENIC) + .entry(LootEntries.THE_END, LootEntries.END_LIKE) .build()) .build(); } @Override - public void curioTick(String identifier, int index, LivingEntity entity, ItemStack stack) { - Level level = entity.getCommandSenderWorld(); + public void curioTick(SlotContext slotContext, ItemStack stack) { + if (!(slotContext.entity() instanceof Player player)) + return; + + Level level = player.getCommandSenderWorld(); if (level.isClientSide()) return; @@ -108,7 +105,7 @@ public void curioTick(String identifier, int index, LivingEntity entity, ItemSta LivingEntity target = getTarget(serverLevel, stack); if (target != null) { - double radius = getAbilityValue(stack, "backstab", "distance"); + double radius = getStatValue(stack, "backstab", "distance"); double step = 0.15D; int offset = 16; @@ -166,15 +163,15 @@ public void curioTick(String identifier, int index, LivingEntity entity, ItemSta } } - if (!canHide(entity)) { - EntityUtils.removeAttribute(entity, stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.MULTIPLY_TOTAL); + if (!canHide(player)) { + EntityUtils.removeAttribute(player, stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); - if (target != null && (target.isDeadOrDying() || target.position().distanceTo(entity.position()) >= getAbilityValue(stack, "backstab", "distance"))) - NBTUtils.clearTag(stack, TAG_TARGET); + if (target != null && (target.isDeadOrDying() || target.position().distanceTo(player.position()) >= getStatValue(stack, "backstab", "distance"))) + stack.set(TARGET, ""); } else { - entity.addEffect(new MobEffectInstance(EffectRegistry.VANISHING.get(), 5, 0, false, false)); + player.addEffect(new MobEffectInstance(EffectRegistry.VANISHING, 5, 0, false, false)); - EntityUtils.applyAttribute(entity, stack, Attributes.MOVEMENT_SPEED, (float) getAbilityValue(stack, "vanish", "speed"), AttributeModifier.Operation.MULTIPLY_TOTAL); + EntityUtils.applyAttribute(player, stack, Attributes.MOVEMENT_SPEED, (float) getStatValue(stack, "vanish", "speed"), AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); } } @@ -185,13 +182,13 @@ private static LivingEntity getTarget(Level level, ItemStack stack) { ServerLevel serverLevel = (ServerLevel) level; - String string = NBTUtils.getString(stack, TAG_TARGET, ""); + String string = stack.getOrDefault(TARGET, ""); if (string.isEmpty()) return null; if (!(serverLevel.getEntity(UUID.fromString(string)) instanceof LivingEntity target) || target.isDeadOrDying()) { - NBTUtils.clearTag(stack, TAG_TARGET); + stack.set(TARGET, ""); return null; } @@ -208,15 +205,15 @@ private static boolean canHide(LivingEntity entity) { Level world = entity.getCommandSenderWorld(); BlockPos position = entity.blockPosition().above(); - double light = relic.getAbilityValue(stack, "vanish", "light"); + double light = relic.getStatValue(stack, "vanish", "light"); - return relic.isAbilityTicking(stack, "vanish") && NBTUtils.getString(stack, TAG_TARGET, "").isEmpty() + return relic.isAbilityTicking(stack, "vanish") && stack.getOrDefault(TARGET, "").isEmpty() && world.getBrightness(LightLayer.BLOCK, position) + world.getBrightness(LightLayer.SKY, position) / 2D <= (world.isNight() ? light * 1.5D : light); } @Override public void onUnequip(SlotContext slotContext, ItemStack newStack, ItemStack stack) { - EntityUtils.removeAttribute(slotContext.entity(), stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.MULTIPLY_TOTAL); + EntityUtils.removeAttribute(slotContext.entity(), stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); } @Override @@ -256,10 +253,10 @@ public List bodyParts() { return Lists.newArrayList("right_arm", "left_arm", "body"); } - @Mod.EventBusSubscriber + @EventBusSubscriber public static class ServerEvents { @SubscribeEvent - public static void onLivingHurt(LivingHurtEvent event) { + public static void onLivingHurt(LivingIncomingDamageEvent event) { LivingEntity target = event.getEntity(); Level level = target.getCommandSenderWorld(); @@ -270,14 +267,14 @@ public static void onLivingHurt(LivingHurtEvent event) { ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.MIDNIGHT_ROBE.get()); if (!(stack.getItem() instanceof IRelicItem relic) || !canHide(player) || player.position().distanceTo(new Vec3(target.getX(), - player.getY(), target.getZ())) > relic.getAbilityValue(stack, "backstab", "distance")) + player.getY(), target.getZ())) > relic.getStatValue(stack, "backstab", "distance")) return; - relic.spreadExperience(player, stack, Math.round(event.getAmount() * 0.5F)); + relic.spreadRelicExperience(player, stack, Math.round(event.getAmount() * 0.5F)); - event.setAmount((float) (event.getAmount() * relic.getAbilityValue(stack, "backstab", "damage"))); + event.setAmount((float) (event.getAmount() * relic.getStatValue(stack, "backstab", "damage"))); - NBTUtils.setString(stack, TAG_TARGET, target.getStringUUID()); + stack.set(TARGET, target.getStringUUID()); } } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/ICreativeTabEntry.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/ICreativeTabEntry.java deleted file mode 100644 index 65e06788..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/ICreativeTabEntry.java +++ /dev/null @@ -1,12 +0,0 @@ -package it.hurts.sskirillss.relics.items.relics.base; - -import net.minecraft.world.item.ItemStack; - -import java.util.ArrayList; -import java.util.List; - -public interface ICreativeTabEntry { - default List processCreativeTab() { - return new ArrayList<>(); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/IRelicItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/IRelicItem.java index 5a23f106..c9eddf03 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/IRelicItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/IRelicItem.java @@ -1,12 +1,16 @@ package it.hurts.sskirillss.relics.items.relics.base; -import it.hurts.sskirillss.octolib.config.data.ConfigContext; -import it.hurts.sskirillss.octolib.config.data.OctoConfig; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.collect.MultimapBuilder; +import io.netty.util.internal.UnstableApi; import it.hurts.sskirillss.relics.api.events.leveling.ExperienceAddEvent; -import it.hurts.sskirillss.relics.capability.utils.CapabilityUtils; -import it.hurts.sskirillss.relics.config.ConfigHelper; +import it.hurts.sskirillss.relics.components.*; +import it.hurts.sskirillss.relics.config.data.RelicConfigData; import it.hurts.sskirillss.relics.entities.RelicExperienceOrbEntity; +import it.hurts.sskirillss.relics.init.DataComponentRegistry; import it.hurts.sskirillss.relics.init.EntityRegistry; +import it.hurts.sskirillss.relics.init.RegistryRegistry; import it.hurts.sskirillss.relics.items.relics.base.data.RelicAttributeModifier; import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; import it.hurts.sskirillss.relics.items.relics.base.data.RelicSlotModifier; @@ -14,19 +18,12 @@ import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastStage; import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.RelicContainer; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.PredicateType; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.*; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; +import it.hurts.sskirillss.relics.items.relics.base.data.research.ResearchData; import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; -import it.hurts.sskirillss.relics.network.NetworkHandler; -import it.hurts.sskirillss.relics.network.packets.capability.CapabilitySyncPacket; -import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.world.entity.LivingEntity; @@ -35,14 +32,16 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.neoforge.common.NeoForge; import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.NotNull; import javax.annotation.Nullable; import java.util.*; import java.util.function.BiFunction; import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; public interface IRelicItem { @Nullable @@ -52,13 +51,11 @@ default Item getItem() { RelicData constructDefaultRelicData(); - @Nullable - default OctoConfig getConfig() { - return ConfigHelper.getRelicConfig(this); - } - - default void appendConfig(ConfigContext context) { + String getConfigRoute(); + @Nullable + default RelicConfigData constructDefaultConfigData(@NotNull RelicConfigData config) { + return config; } default void castActiveAbility(ItemStack stack, Player player, String ability, CastType type, CastStage stage) { @@ -70,7 +67,7 @@ default void tickActiveAbilitySelection(ItemStack stack, Player player, String a } @Nullable - default RelicAttributeModifier getAttributeModifiers(ItemStack stack) { + default RelicAttributeModifier getRelicAttributeModifiers(ItemStack stack) { return RelicAttributeModifier.builder().build(); } @@ -79,7 +76,6 @@ default RelicSlotModifier getSlotModifiers(ItemStack stack) { return RelicSlotModifier.builder().build(); } - default RelicData getRelicData() { if (!RelicStorage.RELICS.containsKey(this)) RelicStorage.RELICS.put(this, constructDefaultRelicData()); @@ -91,42 +87,70 @@ default void setRelicData(RelicData data) { RelicStorage.RELICS.put(this, data); } + default AbilitiesData getAbilitiesData() { + return getRelicData().getAbilities(); + } + default AbilityData getAbilityData(String ability) { - return getRelicData().getAbilities().getAbilities().get(ability); + return getAbilitiesData().getAbilities().get(ability); + } + + default ResearchData getResearchData(String ability) { + return getAbilityData(ability).getResearchData(); } default StatData getStatData(String ability, String stat) { - return getRelicData().getAbilities().getAbilities().get(ability).getStats().get(stat); + return getAbilityData(ability).getStats().get(stat); } default LevelingData getLevelingData() { return getRelicData().getLeveling(); } - default LootData getLootData() { - return getRelicData().getLoot(); + default LevelingSourcesData getLevelingSourcesData() { + return getLevelingData().getSources(); } - default StyleData getStyleData() { - return getRelicData().getStyle(); + default LevelingSourceData getLevelingSourceData(String source) { + return getLevelingSourcesData().getSources().get(source); } - default boolean isItemResearched(Player player) { - Item item = getItem(); + @UnstableApi + default boolean isLevelingSourceUnlocked(ItemStack stack, String source) { + var data = getLevelingSourceData(source); + var ability = data.getRequiredAbility(); - return item != null && CapabilityUtils.getRelicsCapability(player).getResearchData().getBoolean(ForgeRegistries.ITEMS.getKey(item).getPath() + "_researched"); + return isLevelingSourceEnabled(stack, source) && getRelicLevel(stack) >= data.getRequiredLevel() && (ability.isEmpty() || isAbilityUnlocked(stack, ability)); } - default void setItemResearched(Player player, boolean researched) { - Item item = getItem(); + @UnstableApi + default boolean isLevelingSourceEnabled(ItemStack stack, String source) { + var data = getLevelingSourceData(source); + var ability = data.getRequiredAbility(); - if (item == null) - return; + return data.getRequiredAbility().isEmpty() || isAbilityEnabled(stack, ability); + } - CapabilityUtils.getRelicsCapability(player).getResearchData().putBoolean(ForgeRegistries.ITEMS.getKey(item).getPath() + "_researched", researched); + @UnstableApi + default int getLevelingSourceValue(ItemStack stack, String source) { + var data = getLevelingSourceData(source); - if (!player.level().isClientSide()) - NetworkHandler.sendToClient(new CapabilitySyncPacket(CapabilityUtils.getRelicsCapability(player).serializeNBT()), (ServerPlayer) player); + // TODO: Use component value instead + return data.getInitialValue(); + } + + @UnstableApi + default int getLevelingSourceLevel(ItemStack stack, String source) { + // TODO: Use component value instead + return 1; + } + + default LootData getLootData() { + return getRelicData().getLoot(); + } + + default StyleData getStyleData() { + return getRelicData().getStyle(); } default int getMaxQuality() { @@ -141,7 +165,7 @@ default int getStatQuality(ItemStack stack, String ability, String stat) { Function format = statData.getFormatValue(); - double initial = format.apply(getAbilityInitialValue(stack, ability, stat)).doubleValue(); + double initial = format.apply(getStatInitialValue(stack, ability, stat)).doubleValue(); double min = format.apply(statData.getInitialValue().getKey()).doubleValue(); double max = format.apply(statData.getInitialValue().getValue()).doubleValue(); @@ -149,10 +173,16 @@ default int getStatQuality(ItemStack stack, String ability, String stat) { if (min == max) return getMaxQuality(); - return Mth.clamp((int) Math.round((initial - min) / ((max - min) / getMaxQuality())), 0, getMaxQuality()); + if (initial == min) + return 0; + + if (initial == max) + return getMaxQuality(); + + return Mth.clamp((int) Math.round((initial - min) / ((max - min) / getMaxQuality())), 1, getMaxQuality() - 1); } - default double getStatByQuality(String ability, String stat, int quality) { + default double getStatValueByQuality(String ability, String stat, int quality) { StatData statData = getStatData(ability, stat); if (statData == null) @@ -162,7 +192,7 @@ default double getStatByQuality(String ability, String stat, int quality) { double max = statData.getInitialValue().getValue(); if (min == max) - return getMaxQuality(); + return max; return MathUtils.round(min + (((max - min) / getMaxQuality()) * quality), 5); } @@ -171,27 +201,40 @@ default int getAbilityQuality(ItemStack stack, String ability) { Map stats = getAbilityData(ability).getStats(); if (stats.isEmpty()) - return 0; + return getMaxQuality(); - int sum = 0; + double sum = 0; for (String stat : stats.keySet()) sum += getStatQuality(stack, ability, stat); - return Mth.clamp(sum / stats.size(), 0, getMaxQuality()); + sum = (int) Math.floor(sum / stats.size()); + + int min = 0; + int max = getMaxQuality(); + + if (sum == min) + return min; + + if (sum == max) + return max; + + return (int) Mth.clamp(sum, min + 1, max - 1); } default int getRelicQuality(ItemStack stack) { - Map abilities = getRelicData().getAbilities().getAbilities(); + Map abilities = getAbilitiesData().getAbilities(); if (abilities.isEmpty()) return 0; int size = abilities.size(); - int sum = 0; + double sum = 0; for (Map.Entry entry : abilities.entrySet()) { - if (entry.getValue().getMaxLevel() == 0) { + var ability = entry.getKey(); + + if (!canBeUpgraded(ability) || !isAbilityUnlocked(stack, ability)) { --size; continue; @@ -200,130 +243,165 @@ default int getRelicQuality(ItemStack stack) { sum += getAbilityQuality(stack, entry.getKey()); } - return Mth.clamp(sum / size, 0, getMaxQuality()); + sum = (int) Math.floor(sum / size); + + int min = 0; + int max = getMaxQuality(); + + if (sum == min) + return min; + + if (sum == max) + return max; + + return (int) Mth.clamp(sum, min + 1, max - 1); + } + + default int getRelicLevelingPoints(ItemStack stack) { + return getLevelingComponent(stack).points(); } - default CompoundTag getLevelingTag(ItemStack stack) { - return NBTUtils.getCompound(stack, "leveling", new CompoundTag()); + default void setRelicLevelingPoints(ItemStack stack, int amount) { + setLevelingComponent(stack, getLevelingComponent(stack).toBuilder().points(Math.max(0, amount)).build()); } - default void setLevelingTag(ItemStack stack, CompoundTag data) { - NBTUtils.setCompound(stack, "leveling", data); + default void addRelicLevelingPoints(ItemStack stack, int amount) { + setRelicLevelingPoints(stack, getRelicLevelingPoints(stack) + amount); } - default int getPoints(ItemStack stack) { - return getLevelingTag(stack).getInt("points"); + default int getRelicLevel(ItemStack stack) { + return getLevelingComponent(stack).level(); } - default void setPoints(ItemStack stack, int amount) { - CompoundTag tag = getLevelingTag(stack); + default void setRelicLevel(ItemStack stack, int level) { + setLevelingComponent(stack, getLevelingComponent(stack).toBuilder().level(Math.max(0, level)).build()); + } - tag.putInt("points", Math.max(0, amount)); + default void addRelicLevel(ItemStack stack, int amount) { + if (amount > 0) + addRelicLevelingPoints(stack, Mth.clamp(amount, 0, getLevelingData().getMaxLevel() - getRelicLevel(stack))); - setLevelingTag(stack, tag); + setRelicLevel(stack, getRelicLevel(stack) + amount); } - default void addPoints(ItemStack stack, int amount) { - setPoints(stack, getPoints(stack) + amount); + default int getMaxLuck() { + return 100; } - default int getLevel(ItemStack stack) { - return getLevelingTag(stack).getInt("level"); + default double getLuckModifier() { + return 1.25D; } - default void setLevel(ItemStack stack, int level) { - CompoundTag tag = getLevelingTag(stack); + default int getRelicLuck(ItemStack stack) { + return getLevelingComponent(stack).luck(); + } - tag.putInt("level", Mth.clamp(level, 0, getLevelingData().getMaxLevel())); + default void setRelicLuck(ItemStack stack, int amount) { + setLevelingComponent(stack, getLevelingComponent(stack).toBuilder().luck(Mth.clamp(amount, 0, getMaxLuck())).build()); + } - setLevelingTag(stack, tag); + default void addRelicLuck(ItemStack stack, int amount) { + setRelicLuck(stack, getRelicLuck(stack) + amount); } - default void addLevel(ItemStack stack, int amount) { - if (amount > 0) - addPoints(stack, Mth.clamp(amount, 0, getLevelingData().getMaxLevel() - getLevel(stack))); + default int getRelicExperience(ItemStack stack) { + return getLevelingComponent(stack).experience(); + } - setLevel(stack, getLevel(stack) + amount); + default void setRelicExperience(ItemStack stack, int experience) { + setLevelingComponent(stack, getLevelingComponent(stack).toBuilder() + .experience(Math.clamp(experience, 0, getTotalRelicExperienceForLevel(getRelicLevel(stack) + 1))) + .build()); } - default int getExperience(ItemStack stack) { - return getLevelingTag(stack).getInt("experience"); + default boolean addRelicExperience(ItemStack stack, int amount) { + return addRelicExperience(null, stack, amount); } - default void setExperience(ItemStack stack, int experience) { - int level = getLevel(stack); + default boolean addRelicExperience(@Nullable LivingEntity entity, ItemStack stack, int amount) { + var event = new ExperienceAddEvent(entity instanceof LivingEntity ? entity : null, stack, amount); - if (level >= getLevelingData().getMaxLevel()) - return; + NeoForge.EVENT_BUS.post(event); - int requiredExp = getExperienceBetweenLevels(stack, level, level + 1); + if (event.isCanceled()) + return false; - CompoundTag data = getLevelingTag(stack); + var currentExperience = getRelicExperience(stack); + var currentLevel = getRelicLevel(stack); - if (experience >= requiredExp) { - int sumExp = getTotalExperienceForLevel(stack, level) + experience; - int resultLevel = getLevelFromExperience(stack, sumExp); + var toAdd = event.getAmount(); - data.putInt("experience", Math.max(0, sumExp - getTotalExperienceForLevel(stack, resultLevel))); + if (toAdd == 0) + return false; - setLevelingTag(stack, data); - addPoints(stack, resultLevel - level); - setLevel(stack, resultLevel); - } else { - data.putInt("experience", Mth.clamp(experience, 0, requiredExp)); + var resultLevel = currentLevel; + var resultExperience = 0; - setLevelingTag(stack, data); - } - } + var maxLevel = getLevelingData().getMaxLevel(); - default boolean addExperience(ItemStack stack, int amount) { - return addExperience(null, stack, amount); - } + while (toAdd > 0) { + if (resultLevel >= maxLevel) + break; + + var requiredExperience = getTotalRelicExperienceBetweenLevels(resultLevel, resultLevel + 1); - default boolean addExperience(@Nullable LivingEntity entity, ItemStack stack, int amount) { - ExperienceAddEvent event = new ExperienceAddEvent(entity instanceof LivingEntity ? entity : null, stack, amount); + var diff = requiredExperience - currentExperience; - MinecraftForge.EVENT_BUS.post(event); + if (toAdd >= diff) { + toAdd -= diff; - if (!event.isCanceled()) { - setExperience(stack, getExperience(stack) + event.getAmount()); + resultLevel++; - return true; + currentExperience = 0; + } else { + resultExperience = currentExperience + toAdd; + + break; + } } - return false; + setRelicExperience(stack, resultExperience); + + if (currentLevel != resultLevel) { + setRelicLevel(stack, resultLevel); + + addRelicLevelingPoints(stack, resultLevel - currentLevel); + } + + return true; } - default void spreadExperience(@Nullable LivingEntity entity, ItemStack stack, int experience) { - spreadExperience(entity, stack, experience, 0.25D); + default void spreadRelicExperience(@Nullable LivingEntity entity, ItemStack stack, int experience) { + spreadRelicExperience(entity, stack, experience, 0.25D); } - default void spreadExperience(@Nullable LivingEntity entity, ItemStack stack, int experience, double percentage) { - boolean isMaxLevel = isMaxLevel(stack); + default void spreadRelicExperience(@Nullable LivingEntity entity, ItemStack stack, int experience, double percentage) { + var isMaxLevel = isRelicMaxLevel(stack); - int toSpread = isMaxLevel ? experience : (int) Math.ceil(experience * percentage); + var toSpread = isMaxLevel ? 0 : (int) Math.ceil(experience * percentage); if (!isMaxLevel) - addExperience(entity, stack, experience); + addRelicExperience(entity, stack, experience); if (toSpread <= 0 || entity == null) return; - List relics = new ArrayList<>(); - - for (RelicContainer source : RelicContainer.values()) - relics.addAll(source.gatherRelics().apply(entity).stream().filter(entry -> !isMaxLevel(entry) && !stack.equals(entry, true)).toList()); + var relics = RegistryRegistry.RELIC_CONTAINER_REGISTRY.entrySet().stream() + .map(Map.Entry::getValue) + .flatMap(source -> source.gatherRelics().apply(entity).stream()) + .filter(entry -> entry.getItem() instanceof IRelicItem relic && !relic.isRelicMaxLevel(entry) && !stack.equals(entry)) + .toList(); if (relics.isEmpty()) return; - ItemStack relicStack = relics.get(entity.level().getRandom().nextInt(relics.size())); + var relicStack = relics.get(entity.level().getRandom().nextInt(relics.size())); if (relicStack.getItem() instanceof IRelicItem relic) - relic.addExperience(entity, relicStack, toSpread); + relic.addRelicExperience(entity, relicStack, toSpread); } - default void dropExperience(Level level, Vec3 pos, int amount) { + default void dropRelicExperience(Level level, Vec3 pos, int amount) { if (amount <= 0) return; @@ -347,17 +425,27 @@ default void dropExperience(Level level, Vec3 pos, int amount) { } } - default int getExperienceLeftForLevel(ItemStack stack, int level) { - int currentLevel = getLevel(stack); + default int getRelicExperienceLeftForLevelUp(ItemStack stack, int level) { + int currentLevel = getRelicLevel(stack); + + return getTotalRelicExperienceBetweenLevels(currentLevel, level) - getRelicExperience(stack); + } + + @Deprecated(forRemoval = true) + default boolean isSomethingWrongWithLevelingPoints(ItemStack stack) { + int current = getRelicLevelingPoints(stack); + + for (var data : getAbilitiesData().getAbilities().values()) + current += getAbilityComponent(stack, data.getId()).points() * data.getRequiredPoints(); - return getExperienceBetweenLevels(stack, currentLevel, level) - getExperience(stack); + return current != getRelicLevel(stack); } - default int getExperienceBetweenLevels(ItemStack stack, int from, int to) { - return getTotalExperienceForLevel(stack, to) - getTotalExperienceForLevel(stack, from); + default int getTotalRelicExperienceBetweenLevels(int from, int to) { + return getTotalRelicExperienceForLevel(to) - getTotalRelicExperienceForLevel(from); } - default int getTotalExperienceForLevel(ItemStack stack, int level) { + default int getTotalRelicExperienceForLevel(int level) { if (level <= 0) return 0; @@ -374,325 +462,626 @@ default int getTotalExperienceForLevel(ItemStack stack, int level) { return result; } - default int getLevelFromExperience(ItemStack stack, int experience) { + default int getRelicLevelFromExperience(int experience) { int result = 0; int amount; do { ++result; - amount = getTotalExperienceForLevel(stack, result); + amount = getTotalRelicExperienceForLevel(result); } while (amount <= experience); return result - 1; } - default boolean isMaxLevel(ItemStack stack) { - return getLevel(stack) >= getLevelingData().getMaxLevel(); + default boolean isRelicMaxLevel(ItemStack stack) { + return getRelicLevel(stack) >= getLevelingData().getMaxLevel(); } - default int getExchanges(ItemStack stack) { - return NBTUtils.getInt(stack, "exchanges", 0); + default boolean isRelicMaxQuality(ItemStack stack) { + return getRelicQuality(stack) >= getMaxQuality(); } - default void setExchanges(ItemStack stack, int amount) { - NBTUtils.setInt(stack, "exchanges", Math.max(0, amount)); + default boolean isRelicFlawless(ItemStack stack) { + return isRelicMaxLevel(stack) && getAbilitiesData().getAbilities().keySet().stream().filter(ability -> isAbilityEnabled(stack, ability)).allMatch(ability -> isAbilityFlawless(stack, ability)); } - default void addExchanges(ItemStack stack, int amount) { - setExchanges(stack, getExchanges(stack) + amount); + default boolean isAbilityMaxLevel(ItemStack stack, String ability) { + return getAbilityLevel(stack, ability) >= getAbilityData(ability).getMaxLevel(); } - default int getExchangeCost(ItemStack stack) { - return (int) (5 + (5 * ((getExchanges(stack)) * 0.01F))); + default boolean isAbilityMaxQuality(ItemStack stack, String ability) { + return getAbilityQuality(stack, ability) >= getMaxQuality(); } - default boolean isExchangeAvailable(Player player, ItemStack stack) { - return getExchangeCost(stack) <= EntityUtils.getPlayerTotalExperience(player); + default boolean isAbilityFlawless(ItemStack stack, String ability) { + return isAbilityUnlocked(stack, ability) && isAbilityMaxQuality(stack, ability); } default CastData getAbilityCastData(String ability) { return getAbilityData(ability).getCastData(); } - default boolean testAbilityCastPredicates(Player player, ItemStack stack, String ability) { - CastData data = getAbilityCastData(ability); + default Map>> getAbilityPredicates(String ability) { + return getAbilityCastData(ability).getPredicates(); + } + + default Map> getAbilityPredicates(String ability, PredicateType type) { + return getAbilityPredicates(ability).entrySet().stream().filter(entry -> entry.getValue().getKey() == type).collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getValue())); + } + + default boolean testAbilityPredicate(Player player, ItemStack stack, String ability, String predicate) { + return getAbilityPredicates(ability).get(predicate).getValue().apply(player, stack); + } - for (Map.Entry> entry : data.getCastPredicates().entrySet()) { - if (!entry.getValue().apply(player, stack)) + default boolean testAbilityPredicates(Player player, ItemStack stack, String ability, PredicateType type) { + for (Map.Entry> entry : getAbilityPredicates(ability, type).entrySet()) + if (!testAbilityPredicate(player, stack, ability, entry.getKey())) return false; - } return true; } - default CompoundTag getAbilitiesTag(ItemStack stack) { - return stack.getOrCreateTag().getCompound("abilities"); + default DataComponent getDataComponent(ItemStack stack) { + return stack.getOrDefault(DataComponentRegistry.DATA, DataComponent.EMPTY); + } + + default void setDataComponent(ItemStack stack, DataComponent component) { + stack.set(DataComponentRegistry.DATA, component); + } + + default LevelingComponent getLevelingComponent(ItemStack stack) { + return getDataComponent(stack).leveling(); + } + + default void setLevelingComponent(ItemStack stack, LevelingComponent component) { + setDataComponent(stack, getDataComponent(stack).toBuilder().leveling(component).build()); + } + + default AbilitiesComponent getAbilitiesComponent(ItemStack stack) { + return getDataComponent(stack).abilities(); } - default void setAbilitiesTag(ItemStack stack, CompoundTag nbt) { - stack.getOrCreateTag().put("abilities", nbt); + default void setAbilitiesComponent(ItemStack stack, AbilitiesComponent component) { + setDataComponent(stack, getDataComponent(stack).toBuilder().abilities(component).build()); } - default CompoundTag getAbilityTag(ItemStack stack, String ability) { - CompoundTag data = getAbilitiesTag(stack); + default AbilityComponent getAbilityComponent(ItemStack stack, String ability) { + AbilitiesComponent abilitiesComponent = getAbilitiesComponent(stack); + + @Nullable AbilityComponent abilityComponent = abilitiesComponent.abilities().get(ability); + + AbilityData abilityData = getAbilityData(ability); + + if (abilityComponent != null) + return abilityComponent; + else if (abilityData != null) { + AbilityComponent.AbilityComponentBuilder builder = AbilityComponent.EMPTY.toBuilder(); + + if (abilityData.getCastData().getType() == CastType.TOGGLEABLE) + builder.extender(AbilityExtenderComponent.EMPTY.toBuilder() + .ticking(true) + .build()); - if (data.isEmpty()) - return new CompoundTag(); + if (isEnoughLevel(stack, ability)) + builder.lock(LockComponent.EMPTY.toBuilder() + .unlocks(getMaxLockUnlocks()) + .build()); - return data.getCompound(ability); + abilityComponent = builder.build(); + + setAbilitiesComponent(stack, abilitiesComponent.toBuilder() + .ability(ability, abilityComponent) + .build()); + + return abilityComponent; + } else + return null; } - default void setAbilityTag(ItemStack stack, String ability, CompoundTag nbt) { - CompoundTag data = getAbilitiesTag(stack); + default void setAbilityComponent(ItemStack stack, String ability, AbilityComponent component) { + setAbilitiesComponent(stack, getAbilitiesComponent(stack).toBuilder().ability(ability, component).build()); + } - data.put(ability, nbt); + default AbilityExtenderComponent getAbilityExtenderComponent(ItemStack stack, String ability) { + return getAbilityComponent(stack, ability).extender(); + } - setAbilitiesTag(stack, data); + default void setAbilityExtenderComponent(ItemStack stack, String ability, AbilityExtenderComponent component) { + setAbilityComponent(stack, ability, getAbilityComponent(stack, ability).toBuilder() + .extender(component) + .build()); } - default CompoundTag getAbilityTempTag(ItemStack stack, String ability) { - CompoundTag data = getAbilityTag(stack, ability); + default LockComponent getLockComponent(ItemStack stack, String ability) { + return getAbilityComponent(stack, ability).lock(); + } - if (data.isEmpty()) - return new CompoundTag(); + default void setLockComponent(ItemStack stack, String ability, LockComponent component) { + setAbilityComponent(stack, ability, getAbilityComponent(stack, ability).toBuilder() + .lock(component) + .build()); + } - return data.getCompound("temp"); + default int getMaxLockUnlocks() { + return 5; } - default void setAbilityTempTag(ItemStack stack, String ability, CompoundTag nbt) { - CompoundTag data = getAbilityTag(stack, ability); + default int getLockUnlocks(ItemStack stack, String ability) { + return getLockComponent(stack, ability).unlocks(); + } - data.put("temp", nbt); + default void setLockUnlocks(ItemStack stack, String ability, int unlocks) { + setLockComponent(stack, ability, getLockComponent(stack, ability).toBuilder() + .unlocks(Mth.clamp(unlocks, 0, getMaxLockUnlocks())) + .build()); + } - setAbilityTag(stack, ability, data); + default void addLockUnlocks(ItemStack stack, String ability, int unlocks) { + setLockUnlocks(stack, ability, getLockUnlocks(stack, ability) + unlocks); } - default Map getAbilityInitialValues(ItemStack stack, String ability) { - CompoundTag abilityTag = getAbilityTag(stack, ability); + default boolean isLockUnlocked(ItemStack stack, String ability) { + return getLockUnlocks(stack, ability) >= getMaxLockUnlocks(); + } - Map result = new HashMap<>(); + default ResearchComponent getResearchComponent(ItemStack stack, String ability) { + return getAbilityComponent(stack, ability).research(); + } - if (abilityTag.isEmpty()) - return result; + default void setResearchComponent(ItemStack stack, String ability, ResearchComponent component) { + setAbilityComponent(stack, ability, getAbilityComponent(stack, ability).toBuilder() + .research(component) + .build()); + } - CompoundTag statTag = abilityTag.getCompound("stats"); + default Multimap getResearchLinks(ItemStack stack, String ability) { + return getResearchComponent(stack, ability).links().entrySet().stream() + .collect(MultimapBuilder.hashKeys().arrayListValues()::build, (multimap, entry) -> multimap.putAll(Integer.parseInt(entry.getKey()), entry.getValue()), Multimap::putAll); + } - if (statTag.isEmpty()) - return result; + default void addResearchLink(ItemStack stack, String ability, int from, int to) { + var links = getResearchLinks(stack, ability); - statTag.getAllKeys().forEach(entry -> result.put(entry, statTag.getDouble(entry))); + links.put(from, to); - return result; + setResearchComponent(stack, ability, getResearchComponent(stack, ability).toBuilder() + .links(links.asMap().entrySet().stream() + .collect(Collectors.toMap( + entry -> String.valueOf(entry.getKey()), + entry -> new ArrayList<>(entry.getValue()) + ))) + .build()); } - default double getAbilityInitialValue(ItemStack stack, String ability, String stat) { - double result; + default void removeResearchLink(ItemStack stack, String ability, int from, int to) { + var links = getResearchLinks(stack, ability); - try { - result = getAbilityInitialValues(stack, ability).get(stat); - } catch (NullPointerException exception) { - if (getStatData(ability, stat) != null) { - randomizeStats(stack, ability); + links.remove(from, to); - result = getAbilityInitialValues(stack, ability).get(stat); - } else - result = 0D; - } + setResearchComponent(stack, ability, getResearchComponent(stack, ability).toBuilder() + .links(links.asMap().entrySet().stream() + .collect(Collectors.toMap( + entry -> String.valueOf(entry.getKey()), + entry -> new ArrayList<>(entry.getValue()) + ))) + .build()); + } - return result; + default boolean isAbilityResearched(ItemStack stack, String ability) { + return getResearchData(ability).getStars().isEmpty() || getResearchComponent(stack, ability).researched(); } - default double getAbilityValue(ItemStack stack, String ability, String stat, int points) { - StatData data = getStatData(ability, stat); + default void setAbilityResearched(ItemStack stack, String ability, boolean researched) { + setResearchComponent(stack, ability, getResearchComponent(stack, ability).toBuilder() + .researched(researched) + .build()); + } - double result = 0D; + default Multimap getCorrectResearchLinks(ItemStack stack, String ability) { + Multimap schema = getResearchData(ability).getLinks(); + Multimap links = getResearchLinks(stack, ability); - if (data == null) - return result; + if (schema.isEmpty()) + return LinkedHashMultimap.create(); - double current = getAbilityInitialValue(stack, ability, stat); - double step = data.getUpgradeModifier().getValue(); + Set> bidirectionalSchema = schema.entries().stream() + .flatMap(entry -> Stream.of(Pair.of(entry.getKey(), entry.getValue()), Pair.of(entry.getValue(), entry.getKey()))) + .collect(Collectors.toSet()); - switch (data.getUpgradeModifier().getKey()) { - case ADD -> result = current + (points * step); - case MULTIPLY_BASE -> result = current + ((current * step) * points); - case MULTIPLY_TOTAL -> result = current * Math.pow(step + 1, points); - } + return links.entries().stream() + .filter(entry -> bidirectionalSchema.contains(Pair.of(entry.getKey(), entry.getValue())) + || bidirectionalSchema.contains(Pair.of(entry.getValue(), entry.getKey()))) + .collect(LinkedHashMultimap::create, (map, entry) -> map.put(entry.getKey(), entry.getValue()), Multimap::putAll); + } - Pair threshold = data.getThresholdValue(); + default Multimap getIncorrectResearchLinks(ItemStack stack, String ability) { + Multimap schema = getResearchData(ability).getLinks(); + Multimap links = getResearchLinks(stack, ability); - return MathUtils.round(Mth.clamp(result, threshold.getKey(), threshold.getValue()), 5); + if (schema.isEmpty()) + return LinkedHashMultimap.create(); + + Set> bidirectionalSchema = schema.entries().stream() + .flatMap(entry -> Stream.of(Pair.of(entry.getKey(), entry.getValue()), Pair.of(entry.getValue(), entry.getKey()))) + .collect(Collectors.toSet()); + + return links.entries().stream() + .filter(entry -> !bidirectionalSchema.contains(Pair.of(entry.getKey(), entry.getValue())) + && !bidirectionalSchema.contains(Pair.of(entry.getValue(), entry.getKey()))) + .collect(LinkedHashMultimap::create, (map, entry) -> map.put(entry.getKey(), entry.getValue()), Multimap::putAll); + } + + default double testAbilityResearchPercentage(ItemStack stack, String ability) { + Multimap schema = getResearchData(ability).getLinks(); + Multimap links = getResearchLinks(stack, ability); + + if (schema.isEmpty()) + return 0D; + + Set> bidirectionalSchema = schema.entries().stream() + .flatMap(entry -> Stream.of(Pair.of(entry.getKey(), entry.getValue()), Pair.of(entry.getValue(), entry.getKey()))) + .collect(Collectors.toSet()); + + long matchingLinks = links.entries().stream() + .filter(entry -> bidirectionalSchema.contains(Pair.of(entry.getKey(), entry.getValue())) + || bidirectionalSchema.contains(Pair.of(entry.getValue(), entry.getKey()))) + .count(); + + return (double) matchingLinks / schema.size(); + } + + default boolean testAbilityResearch(ItemStack stack, String ability) { + return testAbilityResearchPercentage(stack, ability) >= 1D; } - default double getAbilityValue(ItemStack stack, String ability, String stat) { - return getAbilityValue(stack, ability, stat, getAbilityPoints(stack, ability)); + default int getResearchHintCost(String ability) { + return 3; } - default void setAbilityValue(ItemStack stack, String ability, String stat, double value) { - CompoundTag data = getAbilitiesTag(stack); - CompoundTag abilityTag = getAbilityTag(stack, ability); - CompoundTag statTag = abilityTag.getCompound("stats"); + default StatComponent getStatComponent(ItemStack stack, String ability, String stat) { + AbilityComponent abilityComponent = getAbilityComponent(stack, ability); - statTag.putDouble(stat, value); - abilityTag.put("stats", statTag); - data.put(ability, abilityTag); + @Nullable StatComponent statComponent = abilityComponent.stats().get(stat); - setAbilitiesTag(stack, data); + StatData statData = getStatData(ability, stat); + + if (statComponent != null) + return statComponent; + else if (statData != null) { + statComponent = StatComponent.EMPTY.toBuilder() + .initialValue(MathUtils.round(MathUtils.randomBetween(new Random(), statData.getInitialValue().getKey(), statData.getInitialValue().getValue()), 5)) + .build(); + + setAbilityComponent(stack, ability, abilityComponent.toBuilder() + .stat(stat, statComponent) + .build()); + + return statComponent; + } else + return null; } - default void addAbilityValue(ItemStack stack, String ability, String stat, double value) { - setAbilityValue(stack, ability, stat, getAbilityValue(stack, ability, stat) + value); + default void setStatComponent(ItemStack stack, String ability, String stat, StatComponent component) { + setAbilityComponent(stack, ability, getAbilityComponent(stack, ability).toBuilder() + .stat(stat, component) + .build()); } - default int getAbilityPoints(ItemStack stack, String ability) { - return getAbilityTag(stack, ability).getInt("points"); + default double getStatInitialValue(ItemStack stack, String ability, String stat) { + return getStatComponent(stack, ability, stat).initialValue(); } - default void setAbilityPoints(ItemStack stack, String ability, int amount) { - getAbilityTag(stack, ability).putInt("points", Math.max(0, amount)); + default void setStatInitialValue(ItemStack stack, String ability, String stat, double value) { + setStatComponent(stack, ability, stat, getStatComponent(stack, ability, stat).toBuilder() + .initialValue(value) + .build()); } - default void addAbilityPoints(ItemStack stack, String ability, int amount) { - getAbilityTag(stack, ability).putInt("points", Math.max(0, getAbilityPoints(stack, ability) + amount)); + default void addStatInitialValue(ItemStack stack, String ability, String stat, double value) { + setStatInitialValue(stack, ability, stat, getStatInitialValue(stack, ability, stat) + value); } - default boolean canUseAbility(ItemStack stack, String ability) { - return getLevel(stack) >= getAbilityData(ability).getRequiredLevel(); + default int getAbilityLevel(ItemStack stack, String ability) { + return getAbilityComponent(stack, ability).points(); } - default boolean canSeeAbility(Player player, ItemStack stack, String ability) { - for (BiFunction predicate : getAbilityCastData(ability).getVisibilityPredicates()) { - if (!predicate.apply(player, stack)) - return false; + default void setAbilityLevel(ItemStack stack, String ability, int points) { + setAbilityComponent(stack, ability, getAbilityComponent(stack, ability).toBuilder() + .points(points) + .build()); + } + + default void addAbilityLevel(ItemStack stack, String ability, int points) { + setAbilityLevel(stack, ability, getAbilityLevel(stack, ability) + points); + } + + default AbilityComponent randomizeAbilityStats(ItemStack stack, String ability, int luck) { + Map stats = getAbilityData(ability).getStats(); + + Random random = new Random(); + + double targetQuality; + + do { + int maxQuality = getMaxQuality(); + int maxLuck = getMaxLuck(); + + // Random value in the [-1, 1] range + double randomValue = (random.nextDouble() * 2D) - 1D; + + // Luck effect modifier. Lower value = lower chance to get 5 stars + double modifier = getLuckModifier(); + + // Bias based on luck (ranging from -0.5 to 0.5), multiplied by the modifier + double bias = ((luck - (maxLuck / 2D)) / maxLuck) * modifier; + + // Apply the bias to randomValue and limit the result within the range [-1, 1] + double biasedValue = Math.tanh(randomValue + bias); + + // Convert the biased result to the range [0, maxQuality] + double weightedRandom = Math.floor((biasedValue + 1D) / 2D * (maxQuality + 1D)); + + // Clamping the value to avoid overflow + targetQuality = Mth.clamp(weightedRandom, 0, maxQuality); + } while (targetQuality == getAbilityQuality(stack, ability)); + + double sumQuality = 0; + + Map generatedQualities = new HashMap<>(); + + for (String stat : stats.keySet()) { + double randomQuality = MathUtils.randomBetween(random, 0, getMaxQuality()); + + generatedQualities.put(stat, randomQuality); + + sumQuality += randomQuality; } - return true; + double currentAverageQuality = sumQuality / stats.size(); + + while (Math.abs(currentAverageQuality - targetQuality) > 0.01) { + if (currentAverageQuality < targetQuality) { + String minStat = generatedQualities.entrySet().stream().min(Map.Entry.comparingByValue()).get().getKey(); + + double increment = Math.min((targetQuality - currentAverageQuality) * stats.size(), getMaxQuality() - generatedQualities.get(minStat)); + + generatedQualities.put(minStat, generatedQualities.get(minStat) + increment); + } else if (currentAverageQuality > targetQuality) { + String maxStat = generatedQualities.entrySet().stream().max(Map.Entry.comparingByValue()).get().getKey(); + + double decrement = Math.min((currentAverageQuality - targetQuality) * stats.size(), generatedQualities.get(maxStat)); + + generatedQualities.put(maxStat, generatedQualities.get(maxStat) - decrement); + } + + sumQuality = generatedQualities.values().stream().mapToDouble(Double::doubleValue).sum(); + + currentAverageQuality = sumQuality / stats.size(); + } + + for (Map.Entry entry : generatedQualities.entrySet()) + randomizeStat(stack, ability, entry.getKey(), (int) Math.round(entry.getValue())); + + return getAbilityComponent(stack, ability); } - default void randomizeStat(ItemStack stack, String ability, String stat) { + default StatComponent randomizeStat(ItemStack stack, String ability, String stat, int quality) { StatData entry = getStatData(ability, stat); - double result = MathUtils.round(MathUtils.randomBetween(new Random(), entry.getInitialValue().getKey(), entry.getInitialValue().getValue()), 5); + double minValue = entry.getInitialValue().getKey(); + double maxValue = entry.getInitialValue().getValue(); + + double diff = maxValue - minValue; + + double result = minValue + (diff * ((double) quality / getMaxQuality())); + + setStatInitialValue(stack, ability, stat, result); - setAbilityValue(stack, ability, stat, result); + return getStatComponent(stack, ability, stat); } - default void randomizeStats(ItemStack stack, String ability) { - AbilityData entry = getAbilityData(ability); + default StatComponent randomizeStat(ItemStack stack, String ability, String stat) { + return randomizeStat(stack, ability, stat, new Random().nextInt(getMaxQuality() + 1)); + } + + default double getRelativeStatValue(String ability, String stat, double value, int points) { + var data = getStatData(ability, stat); - for (String stat : entry.getStats().keySet()) - randomizeStat(stack, ability, stat); + var result = 0D; + + if (data == null) + return result; + + var step = data.getUpgradeModifier().getValue(); + + switch (data.getUpgradeModifier().getKey()) { + case ADD -> result = value + (points * step); + case MULTIPLY_BASE -> result = value + ((value * step) * points); + case MULTIPLY_TOTAL -> result = value * Math.pow(step + 1, points); + } + + var threshold = data.getThresholdValue(); + + return MathUtils.round(Mth.clamp(result, threshold.getKey(), threshold.getValue()), 5); } - default int getUpgradeRequiredExperience(ItemStack stack, String ability) { - AbilityData entry = getAbilityData(ability); + default double getStatValue(ItemStack stack, String ability, String stat, int points) { + return getRelativeStatValue(ability, stat, getStatInitialValue(stack, ability, stat), points); + } - int count = entry.getStats().size(); + default double getStatValue(ItemStack stack, String ability, String stat) { + return getStatValue(stack, ability, stat, getAbilityLevel(stack, ability)); + } - if (count == 0) - return 0; + default boolean isEnoughLevel(ItemStack stack, String ability) { + return getRelicLevel(stack) >= getAbilityData(ability).getRequiredLevel(); + } - return (getAbilityPoints(stack, ability) + 1) * entry.getRequiredPoints() * count * 15; + @UnstableApi + default boolean isAbilityEnabled(ItemStack stack, String ability) { + return true; } - default boolean isAbilityMaxLevel(ItemStack stack, String ability) { - AbilityData entry = getAbilityData(ability); + default boolean isAbilityUnlocked(ItemStack stack, String ability) { + return isAbilityEnabled(stack, ability) && isEnoughLevel(stack, ability) && isLockUnlocked(stack, ability) && isAbilityResearched(stack, ability); + } + + default boolean hasUnlockedUpgradeableAbility(ItemStack stack) { + return getAbilitiesData().getAbilities().keySet().stream().anyMatch(ability -> canBeUpgraded(ability) && isAbilityUnlocked(stack, ability)); + } - return entry.getStats().isEmpty() || getAbilityPoints(stack, ability) >= (entry.getMaxLevel() == -1 ? (getLevelingData().getMaxLevel() / entry.getRequiredPoints()) : entry.getMaxLevel()); + default boolean hasUnlockedAbility(ItemStack stack) { + return getAbilitiesData().getAbilities().keySet().stream().anyMatch(ability -> isAbilityUnlocked(stack, ability)); + } + + default boolean canPlayerUseAbility(Player player, ItemStack stack, String ability) { + return isAbilityUnlocked(stack, ability) && testAbilityPredicates(player, stack, ability, PredicateType.CAST) && getAbilityCooldown(stack, ability) <= 0; + } + + default boolean canPlayerSeeAbility(Player player, ItemStack stack, String ability) { + return testAbilityPredicates(player, stack, ability, PredicateType.VISIBILITY); + } + + default boolean mayResearch(ItemStack stack, String ability) { + return isEnoughLevel(stack, ability) && isLockUnlocked(stack, ability) && !isAbilityResearched(stack, ability); + } + + default int getUpgradeRequiredLevel(ItemStack stack, String ability) { + return (getAbilityLevel(stack, ability) * 2) + 5; + } + + default boolean canBeUpgraded(String ability) { + return getAbilityData(ability).getMaxLevel() > 0 && !getAbilityData(ability).getStats().isEmpty(); } default boolean mayUpgrade(ItemStack stack, String ability) { AbilityData entry = getAbilityData(ability); - return !entry.getStats().isEmpty() && !isAbilityMaxLevel(stack, ability) && getPoints(stack) >= entry.getRequiredPoints() && canUseAbility(stack, ability); + return canBeUpgraded(ability) && !isAbilityMaxLevel(stack, ability) && getRelicLevelingPoints(stack) >= entry.getRequiredPoints() && isAbilityUnlocked(stack, ability); } default boolean mayPlayerUpgrade(Player player, ItemStack stack, String ability) { - return mayUpgrade(stack, ability) && player.totalExperience >= getUpgradeRequiredExperience(stack, ability); + return mayUpgrade(stack, ability) && player.experienceLevel >= getUpgradeRequiredLevel(stack, ability); } - default int getRerollRequiredExperience(String ability) { - AbilityData entry = getAbilityData(ability); + default boolean upgrade(Player player, ItemStack stack, String ability) { + if (!mayPlayerUpgrade(player, stack, ability)) + return false; - int count = entry.getStats().size(); + player.giveExperienceLevels(-getUpgradeRequiredLevel(stack, ability)); - if (count == 0) - return 0; + setAbilityLevel(stack, ability, getAbilityLevel(stack, ability) + 1); + addRelicLevelingPoints(stack, -getAbilityData(ability).getRequiredPoints()); + + return true; + } - return 100 / count; + default int getRerollRequiredLevel(ItemStack stack, String ability) { + return (int) Math.floor(getRelicLuck(stack) / 25D) + 1; } default boolean mayReroll(ItemStack stack, String ability) { - return !getAbilityData(ability).getStats().isEmpty() && getRerollRequiredExperience(ability) > 0 && canUseAbility(stack, ability); + return !getAbilityData(ability).getStats().isEmpty() && isAbilityUnlocked(stack, ability); } default boolean mayPlayerReroll(Player player, ItemStack stack, String ability) { - return mayReroll(stack, ability) && player.totalExperience >= getRerollRequiredExperience(ability); + return mayReroll(stack, ability) && player.experienceLevel >= getRerollRequiredLevel(stack, ability); + } + + default boolean reroll(Player player, ItemStack stack, String ability) { + if (!mayPlayerReroll(player, stack, ability)) + return false; + + player.giveExperienceLevels(-getRerollRequiredLevel(stack, ability)); + + int prevQuality = getAbilityQuality(stack, ability); + + randomizeAbilityStats(stack, ability, getRelicLuck(stack)); + + int newQuality = getAbilityQuality(stack, ability); + + if (newQuality < prevQuality) + addRelicLuck(stack, (int) (Math.ceil((prevQuality - newQuality) / 2D))); + + return true; } - default int getResetRequiredExperience(ItemStack stack, String ability) { - return getAbilityPoints(stack, ability) * 50; + default int getResetRequiredLevel(ItemStack stack, String ability) { + return getAbilityLevel(stack, ability) * 5; } default boolean mayReset(ItemStack stack, String ability) { - return getResetRequiredExperience(stack, ability) > 0 && canUseAbility(stack, ability); + return getAbilityLevel(stack, ability) > 0 && isAbilityUnlocked(stack, ability); } default boolean mayPlayerReset(Player player, ItemStack stack, String ability) { - return !getAbilityData(ability).getStats().isEmpty() && mayReset(stack, ability) && player.totalExperience >= getResetRequiredExperience(stack, ability); + return !getAbilityData(ability).getStats().isEmpty() && mayReset(stack, ability) && player.experienceLevel >= getResetRequiredLevel(stack, ability); + } + + default boolean reset(Player player, ItemStack stack, String ability) { + if (!mayPlayerReset(player, stack, ability)) + return false; + + player.giveExperienceLevels(-getResetRequiredLevel(stack, ability)); + + addRelicLevelingPoints(stack, getAbilityLevel(stack, ability) * getAbilityData(ability).getRequiredPoints()); + setAbilityLevel(stack, ability, 0); + + return true; } default int getAbilityCooldownCap(ItemStack stack, String ability) { - return getAbilityTempTag(stack, ability).getInt("cooldown_cap"); + return getAbilityExtenderComponent(stack, ability).cooldownCap(); } default void setAbilityCooldownCap(ItemStack stack, String ability, int amount) { - CompoundTag data = getAbilityTempTag(stack, ability); - - data.putInt("cooldown_cap", amount); - - setAbilityTempTag(stack, ability, data); + setAbilityExtenderComponent(stack, ability, getAbilityExtenderComponent(stack, ability).toBuilder() + .cooldownCap(amount) + .build()); } default int getAbilityCooldown(ItemStack stack, String ability) { - return getAbilityTempTag(stack, ability).getInt("cooldown"); + return getAbilityExtenderComponent(stack, ability).cooldown(); } default void setAbilityCooldown(ItemStack stack, String ability, int amount) { - CompoundTag data = getAbilityTempTag(stack, ability); - - data.putInt("cooldown", amount); - data.putInt("cooldown_cap", amount); - - setAbilityTempTag(stack, ability, data); + setAbilityExtenderComponent(stack, ability, getAbilityExtenderComponent(stack, ability).toBuilder() + .cooldownCap(amount) + .cooldown(amount) + .build()); } default void addAbilityCooldown(ItemStack stack, String ability, int amount) { - CompoundTag data = getAbilityTempTag(stack, ability); - - data.putInt("cooldown", getAbilityCooldown(stack, ability) + amount); - - setAbilityTempTag(stack, ability, data); + setAbilityExtenderComponent(stack, ability, getAbilityExtenderComponent(stack, ability).toBuilder() + .cooldown(getAbilityCooldown(stack, ability) + amount) + .build()); } default void setAbilityTicking(ItemStack stack, String ability, boolean ticking) { - CompoundTag data = getAbilityTempTag(stack, ability); - - data.putBoolean("ticking", ticking); - - setAbilityTempTag(stack, ability, data); + setAbilityExtenderComponent(stack, ability, getAbilityExtenderComponent(stack, ability).toBuilder() + .ticking(ticking) + .build()); } default boolean isAbilityTicking(ItemStack stack, String ability) { - return getAbilityTempTag(stack, ability).getBoolean("ticking"); + return isAbilityUnlocked(stack, ability) && getAbilityExtenderComponent(stack, ability).ticking(); } default boolean isAbilityOnCooldown(ItemStack stack, String ability) { return getAbilityCooldown(stack, ability) > 0; } - default boolean canPlayerUseActiveAbility(Player player, ItemStack stack, String ability) { - return canUseAbility(stack, ability) && !isAbilityOnCooldown(stack, ability) && testAbilityCastPredicates(player, stack, ability); + default boolean isAbilityUpgradeEnabled(ItemStack stack, String ability) { + return isAbilityUnlocked(stack, ability) && !getAbilityData(ability).getStats().isEmpty(); + } + + default boolean isAbilityRerollEnabled(ItemStack stack, String ability) { + return isAbilityUnlocked(stack, ability) && !getAbilityData(ability).getStats().isEmpty(); + } + + default boolean isAbilityResetEnabled(ItemStack stack, String ability) { + return isAbilityUnlocked(stack, ability) && !getAbilityData(ability).getStats().isEmpty(); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/IRenderableCurio.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/IRenderableCurio.java index 708bd21c..0ce3c3df 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/IRenderableCurio.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/IRenderableCurio.java @@ -11,12 +11,12 @@ import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.client.renderer.entity.RenderLayerParent; import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import top.theillusivec4.curios.api.SlotContext; import top.theillusivec4.curios.api.client.ICurioRenderer; @@ -29,11 +29,11 @@ default CurioModel getModel(ItemStack stack) { } default ResourceLocation getTexture(ItemStack stack) { - ResourceLocation id = ForgeRegistries.ITEMS.getKey(stack.getItem()); + ResourceLocation id = BuiltInRegistries.ITEM.getKey(stack.getItem()); assert id != null; - return new ResourceLocation(id.getNamespace(), "textures/models/items/" + id.getPath() + ".png"); + return ResourceLocation.fromNamespaceAndPath(id.getNamespace(), "textures/item/model/" + id.getPath() + ".png"); } default List headParts() { @@ -60,9 +60,9 @@ default > void render(ItemStack ICurioRenderer.followBodyRotations(entity, model); - VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), false, stack.hasFoil()); + VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), stack.hasFoil()); - model.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, 1F); + model.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY); matrixStack.popPose(); } diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/RelicItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/RelicItem.java index cf65a8f3..7fb47a47 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/RelicItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/RelicItem.java @@ -2,26 +2,31 @@ import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.Multimap; +import it.hurts.sskirillss.relics.init.CreativeTabRegistry; import it.hurts.sskirillss.relics.items.ItemBase; +import it.hurts.sskirillss.relics.items.misc.CreativeContentConstructor; +import it.hurts.sskirillss.relics.items.misc.ICreativeTabContent; import it.hurts.sskirillss.relics.items.relics.base.data.RelicAttributeModifier; import it.hurts.sskirillss.relics.items.relics.base.data.RelicSlotModifier; +import it.hurts.sskirillss.relics.utils.Reference; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; -import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Rarity; -import net.minecraftforge.registries.ForgeRegistries; import top.theillusivec4.curios.api.CuriosApi; import top.theillusivec4.curios.api.SlotContext; import top.theillusivec4.curios.api.type.capability.ICurioItem; import java.util.ArrayList; import java.util.List; -import java.util.UUID; -public abstract class RelicItem extends ItemBase implements ICurioItem, IRelicItem { +public abstract class RelicItem extends ItemBase implements ICurioItem, IRelicItem, ICreativeTabContent { public RelicItem(Item.Properties properties) { super(properties); } @@ -34,21 +39,20 @@ public RelicItem() { @Override @Deprecated(forRemoval = true) - public Multimap getAttributeModifiers(SlotContext slotContext, UUID uuid, ItemStack stack) { - Multimap modifiers = LinkedHashMultimap.create(); + public Multimap, AttributeModifier> getAttributeModifiers(SlotContext slotContext, ResourceLocation id, ItemStack stack) { + Multimap, AttributeModifier> modifiers = LinkedHashMultimap.create(); - RelicAttributeModifier attributes = getAttributeModifiers(stack); + RelicAttributeModifier attributes = getRelicAttributeModifiers(stack); RelicSlotModifier slots = getSlotModifiers(stack); if (attributes != null) attributes.getAttributes().forEach(attribute -> - modifiers.put(attribute.getAttribute(), new AttributeModifier(uuid, - ForgeRegistries.ITEMS.getKey(stack.getItem()).getPath() + "_" + ForgeRegistries.ATTRIBUTES.getKey(attribute.getAttribute()).getPath(), + modifiers.put(attribute.getAttribute(), new AttributeModifier( + ResourceLocation.fromNamespaceAndPath(Reference.MODID, BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath() + "_" + BuiltInRegistries.ATTRIBUTE.getKey(attribute.getAttribute().value()).getPath() + "_" + slotContext.identifier() + "_" + slotContext.index()), attribute.getMultiplier(), attribute.getOperation()))); if (slots != null) - slots.getModifiers().forEach(slot -> - CuriosApi.addSlotModifier(modifiers, slot.getLeft(), uuid, slot.getRight(), AttributeModifier.Operation.ADDITION)); + slots.getModifiers().forEach((slot, count) -> CuriosApi.addSlotModifier(modifiers, slot, id, count, AttributeModifier.Operation.ADD_VALUE)); return modifiers; } @@ -74,12 +78,12 @@ public boolean shouldCauseReequipAnimation(ItemStack oldStack, ItemStack newStac } @Override - public boolean canBeHurtBy(DamageSource source) { - return false; + public void gatherCreativeTabContent(CreativeContentConstructor constructor) { + constructor.entry(CreativeTabRegistry.RELICS_TAB.get(), CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS, this); } @Override - public boolean isFireResistant() { - return true; + public String getConfigRoute() { + return Reference.MODID; } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/RelicAttributeModifier.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/RelicAttributeModifier.java index 9462a7ca..29abaaa3 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/RelicAttributeModifier.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/RelicAttributeModifier.java @@ -3,6 +3,7 @@ import lombok.Builder; import lombok.Data; import lombok.Singular; +import net.minecraft.core.Holder; import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.AttributeModifier; @@ -16,20 +17,20 @@ public class RelicAttributeModifier { @Data public static class Modifier { - private final Attribute attribute; + private final Holder attribute; private final float multiplier; private final AttributeModifier.Operation operation; - public Modifier(Attribute attribute, float multiplier, AttributeModifier.Operation operation) { + public Modifier(Holder attribute, float multiplier, AttributeModifier.Operation operation) { this.attribute = attribute; this.multiplier = multiplier; this.operation = operation; } - public Modifier(Attribute attribute, float multiplier) { + public Modifier(Holder attribute, float multiplier) { this.attribute = attribute; this.multiplier = multiplier; - this.operation = AttributeModifier.Operation.MULTIPLY_TOTAL; + this.operation = AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL; } } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/RelicData.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/RelicData.java index c3a3bc53..9e3f6a19 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/RelicData.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/RelicData.java @@ -1,9 +1,9 @@ package it.hurts.sskirillss.relics.items.relics.base.data; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import lombok.Builder; import lombok.Data; diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/RelicSlotModifier.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/RelicSlotModifier.java index c841a5e8..067616ad 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/RelicSlotModifier.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/RelicSlotModifier.java @@ -1,15 +1,23 @@ package it.hurts.sskirillss.relics.items.relics.base.data; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; import lombok.Builder; import lombok.Data; -import lombok.Singular; -import org.apache.commons.lang3.tuple.Pair; - -import java.util.List; @Data @Builder public class RelicSlotModifier { - @Singular("entry") - private List> modifiers; + @Builder.Default + private Multimap modifiers; + + public static class RelicSlotModifierBuilder { + Multimap modifiers = ArrayListMultimap.create(); + + public RelicSlotModifierBuilder modifier(String id, int count) { + this.modifiers.put(id, count); + + return this; + } + } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/CastData.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/CastData.java index b02bf72c..fa83ca92 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/CastData.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/CastData.java @@ -1,51 +1,46 @@ package it.hurts.sskirillss.relics.items.relics.base.data.cast; +import it.hurts.sskirillss.relics.init.RelicContainerRegistry; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.containers.base.RelicContainer; import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.IRelicContainer; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.RelicContainer; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.PredicateType; import lombok.Builder; import lombok.Data; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; +import org.apache.commons.lang3.tuple.Pair; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.function.BiFunction; @Data @Builder public class CastData { @Builder.Default - private List container; + private List containers; @Builder.Default private CastType type = CastType.NONE; @Builder.Default - private Map> castPredicates; - - @Builder.Default - private List> visibilityPredicates; + private Map>> predicates; public static class CastDataBuilder { - private Map> castPredicates = new HashMap<>(); - List> visibilityPredicates = new ArrayList<>(); - - private List container = List.of(RelicContainer.CURIOS); + private Map>> predicates = new HashMap<>(); - public CastDataBuilder castPredicate(String id, BiFunction predicate) { - castPredicates.put(id, predicate); - - return this; - } + private List containers = List.of(RelicContainerRegistry.CURIOS.get()); - public CastDataBuilder visibilityPredicate(BiFunction predicate) { - visibilityPredicates.add(predicate); + public CastDataBuilder predicate(String id, PredicateType type, BiFunction predicate) { + predicates.put(id, Pair.of(type, predicate)); return this; } - public CastDataBuilder container(RelicContainer... container) { - this.container = Arrays.asList(container); + public CastDataBuilder container(RelicContainer... containers) { + this.containers = Arrays.asList(containers); return this; } diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/containers/CuriosRelicContainer.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/containers/CuriosRelicContainer.java new file mode 100644 index 00000000..8d65388f --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/containers/CuriosRelicContainer.java @@ -0,0 +1,83 @@ +package it.hurts.sskirillss.relics.items.relics.base.data.cast.containers; + +import it.hurts.sskirillss.relics.init.RelicContainerRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.containers.base.RelicContainer; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; +import it.hurts.sskirillss.relics.system.casts.abilities.AbilityReference; +import it.hurts.sskirillss.relics.system.casts.slots.CurioSlotReference; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import top.theillusivec4.curios.api.CuriosApi; +import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +public class CuriosRelicContainer extends RelicContainer { + @Override + public Function> gatherRelics() { + return entity -> { + List relics = new ArrayList<>(); + + CuriosApi.getCuriosInventory(entity).ifPresent(itemHandler -> { + for (Map.Entry entry : itemHandler.getCurios().entrySet()) { + ICurioStacksHandler stacksHandler = entry.getValue(); + + for (int slot = 0; slot < stacksHandler.getSlots(); slot++) { + ItemStack stack = stacksHandler.getStacks().getStackInSlot(slot); + + if (stack.getItem() instanceof IRelicItem) + relics.add(stack); + } + } + }); + + return relics; + }; + } + + @Override + public Function> gatherAbilities() { + return entity -> { + List references = new ArrayList<>(); + + if (!(entity instanceof Player player)) + return references; + + CuriosApi.getCuriosInventory(entity).ifPresent(itemHandler -> { + for (Map.Entry entry : itemHandler.getCurios().entrySet()) { + ICurioStacksHandler stacksHandler = entry.getValue(); + + for (int slot = 0; slot < stacksHandler.getSlots(); slot++) { + ItemStack stack = stacksHandler.getStacks().getStackInSlot(slot); + + if (!(stack.getItem() instanceof IRelicItem relic)) + continue; + + for (AbilityData abilityData : relic.getRelicData().getAbilities().getAbilities().values()) { + String id = abilityData.getId(); + + if (!relic.isAbilityUnlocked(stack, id) || !relic.canPlayerSeeAbility(player, stack, id)) + continue; + + CastData castData = abilityData.getCastData(); + + if (castData.getType() == CastType.NONE || !castData.getContainers().contains(RelicContainerRegistry.CURIOS.get())) + continue; + + references.add(new AbilityReference(abilityData.getId(), new CurioSlotReference(slot, entry.getKey()))); + } + } + } + }); + + return references; + }; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/containers/InventoryRelicContainer.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/containers/InventoryRelicContainer.java new file mode 100644 index 00000000..5e6a540a --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/containers/InventoryRelicContainer.java @@ -0,0 +1,71 @@ +package it.hurts.sskirillss.relics.items.relics.base.data.cast.containers; + +import it.hurts.sskirillss.relics.init.RelicContainerRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.containers.base.RelicContainer; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; +import it.hurts.sskirillss.relics.system.casts.abilities.AbilityReference; +import it.hurts.sskirillss.relics.system.casts.slots.InventorySlotReference; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Function; + +public class InventoryRelicContainer extends RelicContainer { + @Override + public Function> gatherRelics() { + return entity -> { + List relics = new ArrayList<>(); + + if (!(entity instanceof Player player)) + return relics; + + for (int slot = 0; slot < player.getInventory().getContainerSize(); slot++) { + ItemStack stack = player.getInventory().getItem(slot); + + if (stack.getItem() instanceof IRelicItem) + relics.add(stack); + } + + return relics; + }; + } + + @Override + public Function> gatherAbilities() { + return entity -> { + List references = new ArrayList<>(); + + if (!(entity instanceof Player player)) + return references; + + for (int slot = 0; slot < player.getInventory().getContainerSize(); slot++) { + ItemStack stack = player.getInventory().getItem(slot); + + if (!(stack.getItem() instanceof IRelicItem relic)) + continue; + + for (AbilityData abilityData : relic.getRelicData().getAbilities().getAbilities().values()) { + String id = abilityData.getId(); + + if (!relic.isAbilityUnlocked(stack, id) || !relic.canPlayerSeeAbility(player, stack, id)) + continue; + + CastData castData = abilityData.getCastData(); + + if (castData.getType() == CastType.NONE || !castData.getContainers().contains(RelicContainerRegistry.INVENTORY.get())) + continue; + + references.add(new AbilityReference(abilityData.getId(), new InventorySlotReference(slot))); + } + } + + return references; + }; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/containers/base/RelicContainer.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/containers/base/RelicContainer.java new file mode 100644 index 00000000..1cba6b22 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/containers/base/RelicContainer.java @@ -0,0 +1,16 @@ +package it.hurts.sskirillss.relics.items.relics.base.data.cast.containers.base; + +import it.hurts.sskirillss.relics.system.casts.abilities.AbilityReference; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; + +import java.util.List; +import java.util.function.Function; + +public abstract class RelicContainer { + public abstract Function> gatherRelics(); + + // TODO: Remove and use only RelicContainer#gatherRelics + @Deprecated(since = "1.21", forRemoval = true) + public abstract Function> gatherAbilities(); +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/CastStage.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/CastStage.java index bb417a65..ad36bb23 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/CastStage.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/CastStage.java @@ -1,7 +1,19 @@ package it.hurts.sskirillss.relics.items.relics.base.data.cast.misc; +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.minecraft.util.ByIdMap; + +import java.util.function.IntFunction; + +@Getter +@AllArgsConstructor public enum CastStage { - START, - TICK, - END + START(0), + TICK(1), + END(2); + + public static final IntFunction BY_ID = ByIdMap.continuous(CastStage::getId, CastStage.values(), ByIdMap.OutOfBoundsStrategy.ZERO); + + private final int id; } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/CastType.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/CastType.java index eafa7ab1..8542e781 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/CastType.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/CastType.java @@ -1,10 +1,22 @@ package it.hurts.sskirillss.relics.items.relics.base.data.cast.misc; +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.minecraft.util.ByIdMap; + +import java.util.function.IntFunction; + +@Getter +@AllArgsConstructor public enum CastType { - NONE, - INSTANTANEOUS, - INTERRUPTIBLE, - CYCLICAL, - TOGGLEABLE, - CHARGEABLE + NONE(0), + INSTANTANEOUS(1), + INTERRUPTIBLE(2), + CYCLICAL(3), + TOGGLEABLE(4), + CHARGEABLE(5); + + public static final IntFunction BY_ID = ByIdMap.continuous(CastType::getId, CastType.values(), ByIdMap.OutOfBoundsStrategy.ZERO); + + private final int id; } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/IRelicContainer.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/IRelicContainer.java deleted file mode 100644 index abc1e174..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/IRelicContainer.java +++ /dev/null @@ -1,14 +0,0 @@ -package it.hurts.sskirillss.relics.items.relics.base.data.cast.misc; - -import it.hurts.sskirillss.relics.system.casts.abilities.AbilityReference; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.item.ItemStack; - -import java.util.List; -import java.util.function.Function; - -public interface IRelicContainer { - Function> gatherRelics(); - - Function> gatherAbilities(); -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/PredicateType.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/PredicateType.java new file mode 100644 index 00000000..23f7514d --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/PredicateType.java @@ -0,0 +1,6 @@ +package it.hurts.sskirillss.relics.items.relics.base.data.cast.misc; + +public enum PredicateType { + CAST, + VISIBILITY +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/RelicContainer.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/RelicContainer.java deleted file mode 100644 index f6e46ec3..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/cast/misc/RelicContainer.java +++ /dev/null @@ -1,136 +0,0 @@ -package it.hurts.sskirillss.relics.items.relics.base.data.cast.misc; - -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.system.casts.abilities.AbilityReference; -import it.hurts.sskirillss.relics.system.casts.slots.CurioSlotReference; -import it.hurts.sskirillss.relics.system.casts.slots.InventorySlotReference; -import net.minecraft.world.entity.LivingEntity; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import top.theillusivec4.curios.api.CuriosApi; -import top.theillusivec4.curios.api.type.inventory.ICurioStacksHandler; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - -public enum RelicContainer implements IRelicContainer { - CURIOS { - @Override - public Function> gatherRelics() { - return entity -> { - List relics = new ArrayList<>(); - - CuriosApi.getCuriosInventory(entity).ifPresent(itemHandler -> { - for (Map.Entry entry : itemHandler.getCurios().entrySet()) { - ICurioStacksHandler stacksHandler = entry.getValue(); - - for (int slot = 0; slot < stacksHandler.getSlots(); slot++) { - ItemStack stack = stacksHandler.getStacks().getStackInSlot(slot); - - if (stack.getItem() instanceof IRelicItem) - relics.add(stack); - } - } - }); - - return relics; - }; - } - - @Override - public Function> gatherAbilities() { - return entity -> { - List references = new ArrayList<>(); - - if (!(entity instanceof Player player)) - return references; - - CuriosApi.getCuriosInventory(entity).ifPresent(itemHandler -> { - for (Map.Entry entry : itemHandler.getCurios().entrySet()) { - ICurioStacksHandler stacksHandler = entry.getValue(); - - for (int slot = 0; slot < stacksHandler.getSlots(); slot++) { - ItemStack stack = stacksHandler.getStacks().getStackInSlot(slot); - - if (!(stack.getItem() instanceof IRelicItem relic)) - continue; - - for (AbilityData abilityData : relic.getRelicData().getAbilities().getAbilities().values()) { - String id = abilityData.getId(); - - if (!relic.canUseAbility(stack, id) || !relic.canSeeAbility(player, stack, id)) - continue; - - CastData castData = abilityData.getCastData(); - - if (castData.getType() == CastType.NONE || !castData.getContainer().contains(CURIOS)) - continue; - - references.add(new AbilityReference(abilityData.getId(), new CurioSlotReference(slot, entry.getKey()))); - } - } - } - }); - - return references; - }; - } - }, - INVENTORY { - @Override - public Function> gatherRelics() { - return entity -> { - List relics = new ArrayList<>(); - - if (!(entity instanceof Player player)) - return relics; - - for (int slot = 0; slot < player.getInventory().getContainerSize(); slot++) { - ItemStack stack = player.getInventory().getItem(slot); - - if (stack.getItem() instanceof IRelicItem) - relics.add(stack); - } - - return relics; - }; - } - - @Override - public Function> gatherAbilities() { - return entity -> { - List references = new ArrayList<>(); - - if (!(entity instanceof Player player)) - return references; - - for (int slot = 0; slot < player.getInventory().getContainerSize(); slot++) { - ItemStack stack = player.getInventory().getItem(slot); - - if (!(stack.getItem() instanceof IRelicItem relic)) - continue; - - for (AbilityData abilityData : relic.getRelicData().getAbilities().getAbilities().values()) { - String id = abilityData.getId(); - - if (!relic.canUseAbility(stack, id) || !relic.canSeeAbility(player, stack, id)) - continue; - - CastData castData = abilityData.getCastData(); - - if (castData.getType() == CastType.NONE || !castData.getContainer().contains(INVENTORY)) - continue; - - references.add(new AbilityReference(abilityData.getId(), new InventorySlotReference(slot))); - } - } - - return references; - }; - } - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/AbilitiesData.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/AbilitiesData.java index 5a2fd62e..ddbbb1b4 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/AbilitiesData.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/AbilitiesData.java @@ -1,10 +1,12 @@ package it.hurts.sskirillss.relics.items.relics.base.data.leveling; +import it.hurts.sskirillss.relics.config.data.AbilitiesConfigData; import lombok.Builder; import lombok.Data; import java.util.LinkedHashMap; import java.util.Map; +import java.util.stream.Collectors; @Data @Builder @@ -12,6 +14,10 @@ public class AbilitiesData { @Builder.Default private Map abilities; + public AbilitiesConfigData toConfigData() { + return new AbilitiesConfigData(abilities.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toConfigData(), (o1, o2) -> o1, LinkedHashMap::new))); + } + public static class AbilitiesDataBuilder { private Map abilities = new LinkedHashMap<>(); diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/AbilityData.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/AbilityData.java index 6f37d955..119e293a 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/AbilityData.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/AbilityData.java @@ -1,14 +1,17 @@ package it.hurts.sskirillss.relics.items.relics.base.data.leveling; import com.mojang.datafixers.util.Function3; +import it.hurts.sskirillss.relics.config.data.AbilityConfigData; import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; +import it.hurts.sskirillss.relics.items.relics.base.data.research.ResearchData; import lombok.Builder; import lombok.Data; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; +import java.util.stream.Collectors; @Data @Builder @@ -41,14 +44,32 @@ public static AbilityDataBuilder builder(String id) { @Builder.Default private CastData castData; + @Builder.Default + private ResearchData researchData; + + public AbilityConfigData toConfigData() { + return new AbilityConfigData(requiredPoints, requiredLevel, maxLevel, stats.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().toConfigData(), (o1, o2) -> o1, LinkedHashMap::new))); + } + public static class AbilityDataBuilder { - private Map stats = new HashMap<>(); + private Map stats = new LinkedHashMap<>(); private CastData castData = CastData.builder().build(); + private ResearchData researchData = ResearchData.builder().build(); private AbilityDataBuilder castData(CastData data) { return this; } + private AbilityDataBuilder researchData(ResearchData data) { + return this; + } + + public AbilityDataBuilder research(ResearchData data) { + this.researchData = data; + + return this; + } + public AbilityDataBuilder active(CastData data) { this.castData = data; @@ -56,7 +77,7 @@ public AbilityDataBuilder active(CastData data) { } public AbilityDataBuilder stat(StatData stat) { - stats.put(stat.getId(), stat); + this.stats.put(stat.getId(), stat); return this; } diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/LevelingData.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/LevelingData.java index 1c107cef..31a32e4d 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/LevelingData.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/LevelingData.java @@ -1,5 +1,6 @@ package it.hurts.sskirillss.relics.items.relics.base.data.leveling; +import it.hurts.sskirillss.relics.config.data.LevelingConfigData; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -16,4 +17,20 @@ public class LevelingData { @Builder.Default private int step = 100; + + @Builder.Default + private LevelingSourcesData sources = LevelingSourcesData.builder().build(); + + @Deprecated(forRemoval = true) + public LevelingData(int initialCost, int maxLevel, int step) { + this.initialCost = initialCost; + this.maxLevel = maxLevel; + this.step = step; + + this.sources = LevelingSourcesData.builder().build(); + } + + public LevelingConfigData toConfigData() { + return new LevelingConfigData(initialCost, maxLevel, step); + } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/LevelingSourceData.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/LevelingSourceData.java new file mode 100644 index 00000000..032be854 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/LevelingSourceData.java @@ -0,0 +1,122 @@ +package it.hurts.sskirillss.relics.items.relics.base.data.leveling; + +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionTextures; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemColor; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemShape; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.Builder; +import lombok.Data; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.function.Function; + +@Data +@Builder +public class LevelingSourceData { + private final String id; + + private static LevelingSourceDataBuilder builder(String id) { + var builder = new LevelingSourceDataBuilder(); + + builder.id(id); + + return builder; + } + + public static LevelingSourceDataBuilder genericBuilder(String id) { + var builder = builder(id); + + builder.translationPath((stack) -> "tooltip.relics.leveling_source.generic." + id); + builder.genericIcon(id); + + return builder; + } + + public static LevelingSourceDataBuilder abilityBuilder(String id, String ability) { + var builder = builder(id); + + builder.requiredAbility(ability); + builder.abilityIcon(ability); + builder.translationPath((stack) -> "tooltip.relics." + BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath() + ".leveling_source." + id); + + return builder; + } + + public static LevelingSourceDataBuilder abilityBuilder(String ability) { + return abilityBuilder(ability, ability); + } + + @Builder.Default + private int initialValue = 1; + + @Builder.Default + private Pair upgradeModifier; + + @Builder.Default + private int maxLevel = 0; + + @Builder.Default + private int cost = 0; + + @Builder.Default + private int requiredLevel = 0; + @Builder.Default + private String requiredAbility = ""; + + @Builder.Default + private Function icon; + @Builder.Default + private Function translationPath; + @Builder.Default + private GemShape shape = GemShape.SQUARE; + @Builder.Default + private GemColor color = GemColor.RED; + + public static class LevelingSourceDataBuilder { + private Function icon = (stack) -> ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/abilities/missing.png"); + private Function translationPath = (stack) -> ""; + + private Pair upgradeModifier = Pair.of(UpgradeOperation.ADD, 0); + + private LevelingSourceDataBuilder id(String id) { + this.id = id; + + return this; + } + + public LevelingSourceDataBuilder upgradeModifier(UpgradeOperation operation, int step) { + upgradeModifier = Pair.of(operation, step); + + return this; + } + + private LevelingSourceDataBuilder icon(Function icon) { + this.icon = icon; + + return this; + } + + public LevelingSourceDataBuilder manualIcon(Function icon) { + return icon(icon); + } + + public LevelingSourceDataBuilder genericIcon(String icon) { + return manualIcon((stack) -> ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/leveling_source/generic/" + icon + ".png")); + } + + public LevelingSourceDataBuilder abilityIcon(String ability) { + return manualIcon((stack) -> DescriptionTextures.getAbilityCardTexture(stack, ability)); + } + + public LevelingSourceDataBuilder gem(GemShape shape, GemColor color) { + this.shape(shape); + this.color(color); + + return this; + } + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/LevelingSourcesData.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/LevelingSourcesData.java new file mode 100644 index 00000000..47b4b4e4 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/LevelingSourcesData.java @@ -0,0 +1,38 @@ +package it.hurts.sskirillss.relics.items.relics.base.data.leveling; + +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemColor; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemShape; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +import java.util.LinkedHashMap; +import java.util.Map; + +@Data +@Builder +@AllArgsConstructor +public class LevelingSourcesData { + @Builder.Default + private Map sources; + + public static class LevelingSourcesDataBuilder { + private Map sources = new LinkedHashMap<>(); + + // TODO: Replace static init with registry entry + { + var entry = LevelingSourceData.genericBuilder("spreading") + .initialValue(25) + .gem(GemShape.OVAL, GemColor.YELLOW) + .build(); + + sources.put(entry.getId(), entry); + } + + public LevelingSourcesDataBuilder source(LevelingSourceData source) { + sources.put(source.getId(), source); + + return this; + } + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/StatData.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/StatData.java index 5b31a8b4..5afeabc1 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/StatData.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/StatData.java @@ -1,5 +1,6 @@ package it.hurts.sskirillss.relics.items.relics.base.data.leveling; +import it.hurts.sskirillss.relics.config.data.StatConfigData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import lombok.Builder; import lombok.Data; @@ -30,6 +31,10 @@ public static StatDataBuilder builder(String id) { @Builder.Default private Function formatValue = Double::doubleValue; + public StatConfigData toConfigData() { + return new StatConfigData(initialValue.getKey(), initialValue.getValue(), thresholdValue.getKey(), thresholdValue.getValue(), upgradeModifier.getKey(), upgradeModifier.getValue()); + } + public static class StatDataBuilder { private Pair upgradeModifier = Pair.of(UpgradeOperation.ADD, 0D); private Pair initialValue = Pair.of(0D, 0D); diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/misc/GemColor.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/misc/GemColor.java new file mode 100644 index 00000000..29fdb46b --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/misc/GemColor.java @@ -0,0 +1,11 @@ +package it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc; + +public enum GemColor { + RED, + ORANGE, + YELLOW, + GREEN, + CYAN, + BLUE, + PURPLE +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/misc/GemShape.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/misc/GemShape.java new file mode 100644 index 00000000..aabffde3 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/leveling/misc/GemShape.java @@ -0,0 +1,6 @@ +package it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc; + +public enum GemShape { + SQUARE, + OVAL +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/loot/LootData.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/loot/LootData.java index 3f5620c6..940b7d43 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/loot/LootData.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/loot/LootData.java @@ -1,26 +1,29 @@ package it.hurts.sskirillss.relics.items.relics.base.data.loot; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollection; +import it.hurts.sskirillss.relics.config.data.LootConfigData; +import it.hurts.sskirillss.relics.config.data.LootEntryConfigData; import lombok.Builder; import lombok.Data; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + @Data @Builder public class LootData { @Builder.Default - private LootCollection collection; - - public static class LootDataBuilder { - private LootCollection collection = LootCollection.builder().build(); + private List entries; - public LootDataBuilder entry(String lootTable, float chance) { - this.collection.getEntries().put(lootTable, chance); + public LootConfigData toConfigData() { + return new LootConfigData(entries.stream().map(entry -> new LootEntryConfigData(entry.getDimensions(), entry.getBiomes(), entry.getTables(), entry.getWeight())).toList()); + } - return this; - } + public static class LootDataBuilder { + private List entries = new ArrayList<>(); - public LootDataBuilder entry(LootCollection collection) { - this.collection.getEntries().putAll(collection.getEntries()); + public LootDataBuilder entry(LootEntry... entries) { + this.entries.addAll(Arrays.asList(entries)); return this; } diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/loot/LootEntry.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/loot/LootEntry.java new file mode 100644 index 00000000..c16ba860 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/loot/LootEntry.java @@ -0,0 +1,59 @@ +package it.hurts.sskirillss.relics.items.relics.base.data.loot; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Data +@Builder +@AllArgsConstructor +public class LootEntry { + @Builder.Default + private List dimensions; + @Builder.Default + private List biomes; + @Builder.Default + private List tables; + @Builder.Default + private int weight = 1; + + public static class LootEntryBuilder { + private List dimensions = new ArrayList<>(); + private List biomes = new ArrayList<>(); + private List tables = new ArrayList<>(); + + public LootEntryBuilder dimension(String... dimensions) { + return dimensions(Arrays.asList(dimensions)); + } + + public LootEntryBuilder dimensions(List dimensions) { + this.dimensions.addAll(dimensions); + + return this; + } + + public LootEntryBuilder biome(String... biomes) { + return biomes(Arrays.asList(biomes)); + } + + public LootEntryBuilder biomes(List biomes) { + this.biomes.addAll(biomes); + + return this; + } + + public LootEntryBuilder table(String... table) { + return tables(Arrays.asList(table)); + } + + public LootEntryBuilder tables(List tables) { + this.tables.addAll(tables); + + return this; + } + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/loot/misc/LootCollection.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/loot/misc/LootCollection.java deleted file mode 100644 index f3cf77ce..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/loot/misc/LootCollection.java +++ /dev/null @@ -1,58 +0,0 @@ -package it.hurts.sskirillss.relics.items.relics.base.data.loot.misc; - -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.Consumer; - -@Data -@Builder -@AllArgsConstructor -public class LootCollection { - public static LootCollectionBuilder builder() { - return new LootCollectionBuilder() { - @Override - public LootCollection build() { - LootCollection info = super.build(); - - info.getApplicator().accept(info); - - return info; - } - }; - } - - @Builder.Default - public Map entries; - - @Builder.Default - private Consumer applicator = (builder) -> { - - }; - - public static class LootCollectionBuilder { - public Map entries = new HashMap<>(); - - public LootCollectionBuilder entry(String lootId, float chance) { - this.entries.put(lootId, chance); - - return this; - } - - public LootCollectionBuilder entry(LootCollection collection) { - this.entries.putAll(collection.getEntries()); - - return this; - } - - public LootCollectionBuilder entry(String... lootIds) { - for (String lotId : lootIds) - this.entries.put(lotId, 0F); - - return this; - } - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/loot/misc/LootCollections.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/loot/misc/LootCollections.java deleted file mode 100644 index cbd47c7f..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/loot/misc/LootCollections.java +++ /dev/null @@ -1,56 +0,0 @@ -package it.hurts.sskirillss.relics.items.relics.base.data.loot.misc; - -public class LootCollections { - public static final LootCollection VILLAGE = LootCollection.builder() - .entry("[\\w]+:chests\\/[\\w_\\/]*village[\\w_\\/]*", 0.025F) - .build(); - - public static final LootCollection BASTION = LootCollection.builder() - .entry("[\\w]+:chests\\/[\\w_\\/]*(bastion|piglin)[\\w_\\/]*", 0.025F) - .build(); - - public static final LootCollection NETHER = LootCollection.builder() - .entry("[\\w]+:chests\\/[\\w_\\/]*(nether|hell|lava|magma|fire|burn|fortress)[\\w_\\/]*", 0.025F) - .entry("minecraft:chests/ruined_portal", 0.025F) - .entry(BASTION) - .build(); - - public static final LootCollection JUNGLE = LootCollection.builder() - .entry("[\\w]+:chests\\/[\\w_\\/]*(jungle|temple)[\\w_\\/]*", 0.025F) - .build(); - - public static final LootCollection DESERT = LootCollection.builder() - .entry("[\\w]+:chests\\/[\\w_\\/]*(desert|sand|pyramid)[\\w_\\/]*", 0.025F) - .build(); - - public static final LootCollection AQUATIC = LootCollection.builder() - .entry("[\\w]+:chests\\/[\\w_\\/]*(water|ocean|river|(? stars; + + @Builder.Default + private Multimap links; + + public List getConnectedStars(StarData star) { + List connectedStars = new ArrayList<>(); + + int starIndex = star.getIndex(); + + if (links.containsKey(starIndex)) { + for (Integer connectedIndex : links.get(starIndex)) { + connectedStars.add(stars.get(connectedIndex)); + } + } + + for (Map.Entry entry : links.entries()) { + if (entry.getValue().equals(starIndex)) { + connectedStars.add(stars.get(entry.getKey())); + } + } + + return connectedStars; + } + + public static class ResearchDataBuilder { + private Map stars = new HashMap<>(); + private Multimap links = LinkedHashMultimap.create(); + + public ResearchDataBuilder star(int index, int x, int y) { + stars.put(index, new StarData(index, x, y)); + + return this; + } + + public ResearchDataBuilder link(int first, int second) { + links.put(first > second ? first + second - (second = first) : first, second); + + return this; + } + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/research/StarData.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/research/StarData.java new file mode 100644 index 00000000..dc35a690 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/research/StarData.java @@ -0,0 +1,18 @@ +package it.hurts.sskirillss.relics.items.relics.base.data.research; + +import lombok.AllArgsConstructor; +import lombok.Data; +import net.minecraft.world.phys.Vec2; + +@Data +@AllArgsConstructor +public class StarData { + private int index; + + private int x; + private int y; + + public Vec2 getPos() { + return new Vec2(x, y); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/style/BeamsData.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/style/BeamsData.java new file mode 100644 index 00000000..9688f2ab --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/style/BeamsData.java @@ -0,0 +1,13 @@ +package it.hurts.sskirillss.relics.items.relics.base.data.style; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class BeamsData { + @Builder.Default + private int startColor = 0xFFFFFF00; + @Builder.Default + private int endColor = 0x00FF0000; +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/style/StyleData.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/style/StyleData.java index eeea8721..cc4f351c 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/style/StyleData.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/style/StyleData.java @@ -1,9 +1,7 @@ package it.hurts.sskirillss.relics.items.relics.base.data.style; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; import lombok.Builder; import lombok.Data; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; @@ -13,18 +11,17 @@ @Builder public class StyleData { @Builder.Default - private ResourceLocation background = Backgrounds.DEFAULT; + private BiFunction tooltip; @Builder.Default - private BiFunction tooltip; + private BiFunction beams; public static class StyleDataBuilder { private BiFunction tooltip = (player, stack) -> TooltipData.builder().build(); + private BiFunction beams = (player, stack) -> BeamsData.builder().build(); public StyleDataBuilder tooltip(TooltipData tooltip) { - this.tooltip = (player, stack) -> tooltip; - - return this; + return tooltip((player, stack) -> tooltip); } public StyleDataBuilder tooltip(BiFunction tooltip) { @@ -32,5 +29,15 @@ public StyleDataBuilder tooltip(BiFunction toolt return this; } + + public StyleDataBuilder beams(BeamsData beams) { + return beams((player, stack) -> beams); + } + + public StyleDataBuilder beams(BiFunction beams) { + this.beams = beams; + + return this; + } } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/style/misc/Backgrounds.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/style/misc/Backgrounds.java deleted file mode 100644 index 6af614ce..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/base/data/style/misc/Backgrounds.java +++ /dev/null @@ -1,27 +0,0 @@ -package it.hurts.sskirillss.relics.items.relics.base.data.style.misc; - -import it.hurts.sskirillss.relics.utils.Reference; -import net.minecraft.resources.ResourceLocation; - -import java.util.Locale; - -public class Backgrounds { - public static final ResourceLocation DEFAULT = background("default"); - - public static final ResourceLocation AQUATIC = background("aquatic"); - public static final ResourceLocation ICY = background("icy"); - public static final ResourceLocation NETHER = background("nether"); - public static final ResourceLocation CAVE = background("cave"); - public static final ResourceLocation PLAINS = background("plains"); - public static final ResourceLocation END = background("end"); - public static final ResourceLocation DESERT = background("desert"); - public static final ResourceLocation JUNGLE = background("jungle"); - - public static ResourceLocation background(String name) { - return background(Reference.MODID, name); - } - - public static ResourceLocation background(String modid, String name) { - return new ResourceLocation(modid, "textures/gui/description/backgrounds/" + name.toLowerCase(Locale.ROOT) + ".png"); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/belt/DrownedBeltItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/belt/DrownedBeltItem.java index 2dc0a4dc..2b6aaa32 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/belt/DrownedBeltItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/belt/DrownedBeltItem.java @@ -1,7 +1,6 @@ package it.hurts.sskirillss.relics.items.relics.belt; import com.google.common.collect.Lists; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.init.ItemRegistry; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; import it.hurts.sskirillss.relics.items.relics.base.IRenderableCurio; @@ -15,28 +14,28 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; import it.hurts.sskirillss.relics.utils.Reference; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.geom.PartPose; import net.minecraft.client.model.geom.builders.*; +import net.minecraft.core.registries.Registries; import net.minecraft.tags.FluidTags; import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; -import net.minecraft.world.item.enchantment.EnchantmentHelper; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.ForgeMod; -import net.minecraftforge.event.entity.living.LivingEntityUseItemEvent; -import net.minecraftforge.event.entity.living.LivingHurtEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import org.apache.commons.lang3.tuple.Pair; +import net.minecraft.world.item.enchantment.Enchantments; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.common.NeoForgeMod; +import net.neoforged.neoforge.event.entity.living.LivingEntityUseItemEvent; +import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; import top.theillusivec4.curios.api.SlotContext; import java.util.List; @@ -48,7 +47,7 @@ public RelicData constructDefaultRelicData() { .abilities(AbilitiesData.builder() .ability(AbilityData.builder("slots") .requiredPoints(2) - .stat(StatData.builder("talisman") + .stat(StatData.builder("charm") .initialValue(0D, 2D) .upgradeModifier(UpgradeOperation.ADD, 1D) .formatValue(value -> (int) (MathUtils.round(value, 0))) @@ -82,11 +81,8 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 100)) - .style(StyleData.builder() - .background(Backgrounds.AQUATIC) - .build()) .loot(LootData.builder() - .entry(LootCollections.AQUATIC) + .entry(LootEntries.AQUATIC) .build()) .build(); } @@ -97,27 +93,27 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { return; if (player.isEyeInFluid(FluidTags.WATER) && !player.onGround()) - EntityUtils.applyAttribute(player, stack, ForgeMod.ENTITY_GRAVITY.get(), (float) getAbilityValue(stack, "anchor", "sinking"), AttributeModifier.Operation.MULTIPLY_TOTAL); + EntityUtils.applyAttribute(player, stack, Attributes.GRAVITY, (float) getStatValue(stack, "anchor", "sinking"), AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); else - EntityUtils.removeAttribute(player, stack, ForgeMod.ENTITY_GRAVITY.get(), AttributeModifier.Operation.MULTIPLY_TOTAL); + EntityUtils.removeAttribute(player, stack, Attributes.GRAVITY, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); } @Override public void onUnequip(SlotContext slotContext, ItemStack newStack, ItemStack stack) { - EntityUtils.removeAttribute(slotContext.entity(), stack, ForgeMod.ENTITY_GRAVITY.get(), AttributeModifier.Operation.MULTIPLY_TOTAL); + EntityUtils.removeAttribute(slotContext.entity(), stack, Attributes.GRAVITY, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); } @Override public RelicSlotModifier getSlotModifiers(ItemStack stack) { return RelicSlotModifier.builder() - .entry(Pair.of("talisman", (int) Math.round(getAbilityValue(stack, "slots", "talisman")))) + .modifier("charm", (int) Math.round(getStatValue(stack, "slots", "charm"))) .build(); } @Override - public RelicAttributeModifier getAttributeModifiers(ItemStack stack) { + public RelicAttributeModifier getRelicAttributeModifiers(ItemStack stack) { return RelicAttributeModifier.builder() - .attribute(new RelicAttributeModifier.Modifier(ForgeMod.SWIM_SPEED.get(), (float) -getAbilityValue(stack, "anchor", "slowness"))) + .attribute(new RelicAttributeModifier.Modifier(NeoForgeMod.SWIM_SPEED, (float) -getStatValue(stack, "anchor", "slowness"))) .build(); } @@ -138,10 +134,10 @@ public List headParts() { return Lists.newArrayList("body"); } - @Mod.EventBusSubscriber(modid = Reference.MODID) + @EventBusSubscriber(modid = Reference.MODID) public static class Events { @SubscribeEvent - public static void onEntityHurt(LivingHurtEvent event) { + public static void onEntityHurt(LivingIncomingDamageEvent event) { if (!(event.getSource().getEntity() instanceof Player player) || !player.isUnderWater() || !event.getEntity().isUnderWater()) return; @@ -151,7 +147,7 @@ public static void onEntityHurt(LivingHurtEvent event) { if (!(stack.getItem() instanceof IRelicItem relic)) return; - event.setAmount((float) (event.getAmount() * relic.getAbilityValue(stack, "pressure", "damage"))); + event.setAmount((float) (event.getAmount() * relic.getStatValue(stack, "pressure", "damage"))); } @SubscribeEvent @@ -177,15 +173,15 @@ public static void onItemUseFinish(LivingEntityUseItemEvent.Stop event) { return; - int duration = trident.getItem().getUseDuration(trident) - event.getDuration(); - int enchantment = EnchantmentHelper.getRiptide(trident); + int duration = trident.getItem().getUseDuration(trident, player) - event.getDuration(); + int enchantment = trident.getEnchantmentLevel(player.level().holderLookup(Registries.ENCHANTMENT).getOrThrow(Enchantments.RIPTIDE)); if (duration < 10 || enchantment <= 0) return; - relic.spreadExperience(player, stack, enchantment); + relic.spreadRelicExperience(player, stack, enchantment); - player.getCooldowns().addCooldown(trident.getItem(), (int) Math.round(relic.getAbilityValue(stack, "riptide", "cooldown") * enchantment * 20)); + player.getCooldowns().addCooldown(trident.getItem(), (int) Math.round(relic.getStatValue(stack, "riptide", "cooldown") * enchantment * 20)); } } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/belt/HunterBeltItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/belt/HunterBeltItem.java index 09c14dbd..c8f77be4 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/belt/HunterBeltItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/belt/HunterBeltItem.java @@ -1,7 +1,6 @@ package it.hurts.sskirillss.relics.items.relics.belt; import com.google.common.collect.Lists; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.init.ItemRegistry; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; import it.hurts.sskirillss.relics.items.relics.base.IRenderableCurio; @@ -14,8 +13,7 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; import it.hurts.sskirillss.relics.utils.Reference; @@ -25,12 +23,11 @@ import net.minecraft.world.entity.TamableAnimal; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.event.entity.living.LivingHurtEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import org.apache.commons.lang3.tuple.Pair; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; import java.util.List; @@ -41,7 +38,7 @@ public RelicData constructDefaultRelicData() { .abilities(AbilitiesData.builder() .ability(AbilityData.builder("slots") .requiredPoints(2) - .stat(StatData.builder("talisman") + .stat(StatData.builder("charm") .initialValue(1D, 2D) .upgradeModifier(UpgradeOperation.ADD, 1D) .formatValue(value -> (int) (MathUtils.round(value, 0))) @@ -56,11 +53,8 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 100)) - .style(StyleData.builder() - .background(Backgrounds.PLAINS) - .build()) .loot(LootData.builder() - .entry(LootCollections.VILLAGE) + .entry(LootEntries.OVERWORLD) .build()) .build(); } @@ -68,7 +62,7 @@ public RelicData constructDefaultRelicData() { @Override public RelicSlotModifier getSlotModifiers(ItemStack stack) { return RelicSlotModifier.builder() - .entry(Pair.of("talisman", (int) Math.round(getAbilityValue(stack, "slots", "talisman")))) + .modifier("charm", (int) Math.round(getStatValue(stack, "slots", "charm"))) .build(); } @@ -91,10 +85,10 @@ public List headParts() { return Lists.newArrayList("body"); } - @Mod.EventBusSubscriber(modid = Reference.MODID) + @EventBusSubscriber(modid = Reference.MODID) public static class HunterBeltEvents { @SubscribeEvent - public static void onLivingDamage(LivingHurtEvent event) { + public static void onLivingDamage(LivingIncomingDamageEvent event) { if (!(event.getSource().getEntity() instanceof TamableAnimal pet) || !(pet.getOwner() instanceof Player player)) return; @@ -104,9 +98,9 @@ public static void onLivingDamage(LivingHurtEvent event) { if (!(stack.getItem() instanceof IRelicItem relic)) return; - relic.spreadExperience(player, stack, 1); + relic.spreadRelicExperience(player, stack, 1); - event.setAmount((float) (event.getAmount() * relic.getAbilityValue(stack, "training", "damage"))); + event.setAmount((float) (event.getAmount() * relic.getStatValue(stack, "training", "damage"))); } } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/belt/LeatherBeltItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/belt/LeatherBeltItem.java index 4320c1a4..b4279957 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/belt/LeatherBeltItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/belt/LeatherBeltItem.java @@ -14,9 +14,7 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; import net.minecraft.client.model.HumanoidModel; @@ -24,15 +22,14 @@ import net.minecraft.client.model.geom.builders.*; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import org.apache.commons.lang3.tuple.Pair; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; import java.util.List; -@Mod.EventBusSubscriber +@EventBusSubscriber public class LeatherBeltItem extends RelicItem implements IRenderableCurio { @Override public RelicData constructDefaultRelicData() { @@ -40,7 +37,7 @@ public RelicData constructDefaultRelicData() { .abilities(AbilitiesData.builder() .ability(AbilityData.builder("slots") .requiredPoints(2) - .stat(StatData.builder("talisman") + .stat(StatData.builder("charm") .initialValue(1D, 3D) .upgradeModifier(UpgradeOperation.ADD, 1D) .formatValue(value -> (int) (MathUtils.round(value, 1))) @@ -48,11 +45,8 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 100)) - .style(StyleData.builder() - .background(Backgrounds.PLAINS) - .build()) .loot(LootData.builder() - .entry(LootCollections.VILLAGE) + .entry(LootEntries.OVERWORLD) .build()) .build(); } @@ -60,7 +54,7 @@ public RelicData constructDefaultRelicData() { @Override public RelicSlotModifier getSlotModifiers(ItemStack stack) { return RelicSlotModifier.builder() - .entry(Pair.of("talisman", (int) Math.round(getAbilityValue(stack, "slots", "talisman")))) + .modifier("charm", (int) Math.round(getStatValue(stack, "slots", "charm"))) .build(); } @@ -72,13 +66,13 @@ public static void onExperienceAdded(ExperienceAddEvent event) { if (entity == null || sourceStack.getItem() == ItemRegistry.LEATHER_BELT.get()) return; - if (sourceStack.getTags().map(tag -> tag.location().getPath()).anyMatch(tag -> tag.equals("talisman"))) { + if (sourceStack.getTags().map(tag -> tag.location().getPath()).anyMatch(tag -> tag.equals("charm"))) { ItemStack stack = EntityUtils.findEquippedCurio(entity, ItemRegistry.LEATHER_BELT.get()); if (!(stack.getItem() instanceof IRelicItem relic)) return; - relic.addExperience(entity, stack, 1); + relic.addRelicExperience(entity, stack, 1); } } diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/charm/SporeSackItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/charm/SporeSackItem.java new file mode 100644 index 00000000..057646dc --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/charm/SporeSackItem.java @@ -0,0 +1,135 @@ +package it.hurts.sskirillss.relics.items.relics.charm; + +import it.hurts.sskirillss.relics.entities.SporeEntity; +import it.hurts.sskirillss.relics.init.DataComponentRegistry; +import it.hurts.sskirillss.relics.init.EntityRegistry; +import it.hurts.sskirillss.relics.items.relics.base.RelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.*; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemColor; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemShape; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; +import it.hurts.sskirillss.relics.items.relics.base.data.style.BeamsData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.TooltipData; +import it.hurts.sskirillss.relics.utils.MathUtils; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import top.theillusivec4.curios.api.SlotContext; + +public class SporeSackItem extends RelicItem { + @Override + public RelicData constructDefaultRelicData() { + return RelicData.builder() + .abilities(AbilitiesData.builder() + .ability(AbilityData.builder("spore_mist") + .stat(StatData.builder("amount") + .initialValue(3, 8) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.15D) + .formatValue(value -> (int) MathUtils.round(value, 0)) + .build()) + .stat(StatData.builder("damage") + .initialValue(0.1D, 0.25D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.2D) + .formatValue(value -> (int) MathUtils.round(value * 100, 0)) + .build()) + .build()) + .build()) + .leveling(LevelingData.builder() + .initialCost(100) + .maxLevel(10) + .step(100) + .sources(LevelingSourcesData.builder() + .source(LevelingSourceData.abilityBuilder("spore_mist") + .initialValue(1) + .gem(GemShape.SQUARE, GemColor.YELLOW) + .build()) + .build()) + .build()) + .style(StyleData.builder() + .tooltip(TooltipData.builder() + .borderTop(0xff582f27) + .borderBottom(0xff503f3a) + .textured(true) + .build()) + .beams(BeamsData.builder() + .startColor(0xFF00FF00) + .endColor(0x00FFFF00) + .build()) + .build()) + .loot(LootData.builder() + .entry(LootEntries.TROPIC) + .build()) + .build(); + } + + public boolean isToggled(ItemStack stack) { + return stack.getOrDefault(DataComponentRegistry.TOGGLED, false); + } + + public void setToggled(ItemStack stack, boolean isToggled) { + stack.set(DataComponentRegistry.TOGGLED, isToggled); + } + + public int getCharges(ItemStack stack) { + return stack.getOrDefault(DataComponentRegistry.CHARGE, 0); + } + + public void setCharges(ItemStack stack, int charges) { + stack.set(DataComponentRegistry.CHARGE, charges); + } + + public void addCharges(ItemStack stack, int charges) { + setCharges(stack, Math.clamp(getCharges(stack) + charges, 0, (int) Math.round(getStatValue(stack, "spore_mist", "amount")))); + } + + @Override + public void curioTick(SlotContext slotContext, ItemStack stack) { + if (!(slotContext.entity() instanceof Player player)) + return; + + var charges = getCharges(stack); + var isToggled = isToggled(stack); + + var time = player.tickCount + (slotContext.index() * 10); + + var percentageMedian = 0.5D; + var percentage = player.getHealth() / player.getMaxHealth(); + + if (isToggled) { + if (charges > 0) { + var speed = 3D; + + if (time % speed != 0) + return; + + var level = player.getCommandSenderWorld(); + + var cycle = charges * 1D; + var angle = (Math.floor(time / speed) % cycle) / cycle * 2D * Math.PI; + + var entity = new SporeEntity(EntityRegistry.SPORE.get(), level); + + entity.setOwner(player); + entity.setRelicStack(stack); + entity.setPos(player.position().add(0F, player.getBbHeight() / 2F, 0F)); + entity.setDeltaMovement(Math.cos(angle) * 0.5F, 0.35F, Math.sin(angle) * 0.5F); + entity.setDamage((float) ((player.getMaxHealth() - player.getHealth()) * getStatValue(stack, "spore_mist", "damage"))); + + level.addFreshEntity(entity); + + level.playSound(null, player.blockPosition(), SoundEvents.PUFFER_FISH_FLOP, SoundSource.MASTER, 1F, 1.5F); + + addCharges(stack, -1); + } else if (percentage > percentageMedian) + setToggled(stack, false); + } else if (percentage < percentageMedian) { + setToggled(stack, true); + setCharges(stack, (int) Math.round(getStatValue(stack, "spore_mist", "amount"))); + } + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/AmphibianBootItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/AmphibianBootItem.java index ed910e6a..7b12153b 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/AmphibianBootItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/AmphibianBootItem.java @@ -16,12 +16,9 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; import net.minecraft.client.model.EntityModel; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.geom.PartPose; @@ -36,22 +33,20 @@ import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Rarity; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.ForgeMod; -import net.minecraftforge.event.entity.living.LivingBreatheEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.common.NeoForgeMod; +import net.neoforged.neoforge.event.entity.living.LivingBreatheEvent; import top.theillusivec4.curios.api.SlotContext; import top.theillusivec4.curios.api.client.ICurioRenderer; import java.util.List; -public class AmphibianBootItem extends RelicItem implements IRenderableCurio { - private static final String TAG_SWIMMING_DURATION = "swimming_duration"; - private static final String TAG_SLIPPING_DURATION = "slipping_duration"; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.CHARGE; +public class AmphibianBootItem extends RelicItem implements IRenderableCurio { @Override public RelicData constructDefaultRelicData() { return RelicData.builder() @@ -89,11 +84,8 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 100)) - .style(StyleData.builder() - .background(Backgrounds.AQUATIC) - .build()) .loot(LootData.builder() - .entry(LootCollections.AQUATIC) + .entry(LootEntries.AQUATIC) .build()) .build(); } @@ -103,40 +95,38 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { if (!(slotContext.entity() instanceof Player player)) return; - int swimmingDuration = NBTUtils.getInt(stack, TAG_SWIMMING_DURATION, 0); + int charge = stack.getOrDefault(CHARGE, 0); if (player.isSwimming()) { if (player.tickCount % 20 == 0) - spreadExperience(player, stack, 1); - - if (swimmingDuration < getAbilityValue(stack, "swimming", "duration")) - NBTUtils.setInt(stack, TAG_SWIMMING_DURATION, swimmingDuration + 1); - } else if (swimmingDuration > 0) - NBTUtils.setInt(stack, TAG_SWIMMING_DURATION, --swimmingDuration); + spreadRelicExperience(player, stack, 1); - EntityUtils.removeAttribute(player, stack, ForgeMod.SWIM_SPEED.get(), AttributeModifier.Operation.MULTIPLY_TOTAL); + if (charge < getStatValue(stack, "swimming", "duration")) + stack.set(CHARGE, charge + 1); + } else if (charge > 0) + stack.set(CHARGE, --charge); - if (swimmingDuration > 0) - EntityUtils.applyAttribute(player, stack, ForgeMod.SWIM_SPEED.get(), (float) (swimmingDuration * getAbilityValue(stack, "swimming", "speed")), AttributeModifier.Operation.MULTIPLY_TOTAL); + EntityUtils.removeAttribute(player, stack, NeoForgeMod.SWIM_SPEED, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); - int slippingDuration = NBTUtils.getInt(stack, TAG_SLIPPING_DURATION, 0); + if (charge > 0) + EntityUtils.applyAttribute(player, stack, NeoForgeMod.SWIM_SPEED, (float) (charge * getStatValue(stack, "swimming", "speed")), AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); if (player.isSprinting() && player.level().isRainingAt(player.blockPosition()) && !player.isShiftKeyDown() && !player.isInWater() && !player.isInLava()) { if (player.tickCount % 20 == 0) - spreadExperience(player, stack, 1); + spreadRelicExperience(player, stack, 1); - if (slippingDuration < getAbilityValue(stack, "slipping", "duration") && player.tickCount % 4 == 0) - NBTUtils.setInt(stack, TAG_SLIPPING_DURATION, slippingDuration + 1); - } else if (slippingDuration > 0) - NBTUtils.setInt(stack, TAG_SLIPPING_DURATION, --slippingDuration); + if (charge < getStatValue(stack, "slipping", "duration") && player.tickCount % 4 == 0) + stack.set(CHARGE, charge + 1); + } else if (charge > 0) + stack.set(CHARGE, --charge); - EntityUtils.removeAttribute(player, stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.MULTIPLY_TOTAL); + EntityUtils.removeAttribute(player, stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); - if (slippingDuration > 0) { - EntityUtils.applyAttribute(player, stack, Attributes.MOVEMENT_SPEED, (float) (slippingDuration * getAbilityValue(stack, "slipping", "speed")), AttributeModifier.Operation.MULTIPLY_TOTAL); - EntityUtils.applyAttribute(player, stack, ForgeMod.STEP_HEIGHT_ADDITION.get(), 0.6F, AttributeModifier.Operation.ADDITION); + if (charge > 0) { + EntityUtils.applyAttribute(player, stack, Attributes.MOVEMENT_SPEED, (float) (charge * getStatValue(stack, "slipping", "speed")), AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); + EntityUtils.applyAttribute(player, stack, Attributes.STEP_HEIGHT, 0.6F, AttributeModifier.Operation.ADD_VALUE); } else - EntityUtils.removeAttribute(player, stack, ForgeMod.STEP_HEIGHT_ADDITION.get(), AttributeModifier.Operation.ADDITION); + EntityUtils.removeAttribute(player, stack, Attributes.STEP_HEIGHT, AttributeModifier.Operation.ADD_VALUE); } @Override @@ -144,14 +134,9 @@ public void onUnequip(SlotContext slotContext, ItemStack newStack, ItemStack sta if (stack.getItem() == newStack.getItem()) return; - EntityUtils.removeAttribute(slotContext.entity(), stack, ForgeMod.SWIM_SPEED.get(), AttributeModifier.Operation.MULTIPLY_TOTAL); - EntityUtils.removeAttribute(slotContext.entity(), stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.MULTIPLY_TOTAL); - EntityUtils.removeAttribute(slotContext.entity(), stack, ForgeMod.STEP_HEIGHT_ADDITION.get(), AttributeModifier.Operation.ADDITION); - } - - @Override - public Rarity getRarity(ItemStack pStack) { - return Rarity.UNCOMMON; + EntityUtils.removeAttribute(slotContext.entity(), stack, NeoForgeMod.SWIM_SPEED, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); + EntityUtils.removeAttribute(slotContext.entity(), stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); + EntityUtils.removeAttribute(slotContext.entity(), stack, Attributes.STEP_HEIGHT, AttributeModifier.Operation.ADD_VALUE); } @Override @@ -179,11 +164,11 @@ public > void render(ItemStack ICurioRenderer.followBodyRotations(entity, sidedModel); - VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), false, stack.hasFoil()); + VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), stack.hasFoil()); matrixStack.translate(0, 0, -0.025F); - sidedModel.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, 1F); + sidedModel.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY); matrixStack.popPose(); } @@ -215,7 +200,7 @@ public List bodyParts() { return Lists.newArrayList("right_leg", "left_leg"); } - @Mod.EventBusSubscriber + @EventBusSubscriber public static class Events { @SubscribeEvent public static void onLivingBreath(LivingBreatheEvent event) { @@ -226,7 +211,7 @@ public static void onLivingBreath(LivingBreatheEvent event) { if (!(stack.getItem() instanceof IRelicItem relic)) return; - double chance = relic.getAbilityValue(stack, "gills", "chance"); + double chance = relic.getStatValue(stack, "gills", "chance"); if (event.getConsumeAirAmount() > 0 && entity.getRandom().nextDouble() <= chance) event.setConsumeAirAmount(0); diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/AquaWalkerItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/AquaWalkerItem.java index 17b66b51..0291e94a 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/AquaWalkerItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/AquaWalkerItem.java @@ -6,7 +6,6 @@ import it.hurts.sskirillss.relics.api.events.common.FluidCollisionEvent; import it.hurts.sskirillss.relics.client.models.items.CurioModel; import it.hurts.sskirillss.relics.client.models.items.SidedCurioModel; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.init.ItemRegistry; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; import it.hurts.sskirillss.relics.items.relics.base.IRenderableCurio; @@ -18,12 +17,11 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; +import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.items.relics.base.data.style.TooltipData; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; import it.hurts.sskirillss.relics.utils.Reference; import net.minecraft.client.model.EntityModel; import net.minecraft.client.model.HumanoidModel; @@ -40,19 +38,19 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; import top.theillusivec4.curios.api.SlotContext; import top.theillusivec4.curios.api.client.ICurioRenderer; import java.util.List; -@Mod.EventBusSubscriber(modid = Reference.MODID) -public class AquaWalkerItem extends RelicItem implements IRenderableCurio { - public static final String TAG_DRENCH = "drench"; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.CHARGE; +@EventBusSubscriber(modid = Reference.MODID) +public class AquaWalkerItem extends RelicItem implements IRenderableCurio { @Override public RelicData constructDefaultRelicData() { return RelicData.builder() @@ -72,23 +70,22 @@ public RelicData constructDefaultRelicData() { .borderBottom(0xff163d30) .textured(true) .build()) - .background(Backgrounds.AQUATIC) .build()) .loot(LootData.builder() - .entry(LootCollections.AQUATIC) + .entry(LootEntries.AQUATIC) .build()) .build(); } @Override public void inventoryTick(ItemStack stack, Level level, Entity entity, int slot, boolean isSelected) { - int drench = NBTUtils.getInt(stack, TAG_DRENCH, 0); + int drench = stack.getOrDefault(CHARGE, 0); if (!(entity instanceof Player player) || player.tickCount % 20 != 0) return; if (drench > 0 && !player.isInWater() && !player.level().getFluidState(player.blockPosition().below()).is(FluidTags.WATER)) - NBTUtils.setInt(stack, TAG_DRENCH, --drench); + stack.set(CHARGE, --drench); } @Override @@ -116,11 +113,11 @@ public > void render(ItemStack ICurioRenderer.followBodyRotations(entity, sidedModel); - VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), false, stack.hasFoil()); + VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), stack.hasFoil()); matrixStack.translate(0, 0, -0.025F); - sidedModel.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, 1F); + sidedModel.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY); matrixStack.popPose(); } @@ -161,17 +158,17 @@ public static void onFluidCollide(FluidCollisionEvent event) { if (!(stack.getItem() instanceof IRelicItem relic)) return; - int drench = NBTUtils.getInt(stack, TAG_DRENCH, 0); + int drench = stack.getOrDefault(CHARGE, 0); - if (!(event.getEntity() instanceof Player player) || drench > relic.getAbilityValue(stack, "walking", "time") + if (!(event.getEntity() instanceof Player player) || drench > relic.getStatValue(stack, "walking", "time") || !event.getFluid().is(FluidTags.WATER) || player.isShiftKeyDown()) return; if (player.tickCount % 20 == 0) { - NBTUtils.setInt(stack, TAG_DRENCH, ++drench); + stack.set(CHARGE, ++drench); if (drench % 5 == 0) - relic.spreadExperience(player, stack, 1); + relic.spreadRelicExperience(player, stack, 1); } event.setCanceled(true); diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/IceBreakerItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/IceBreakerItem.java index ac8c015b..8ed4c7f8 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/IceBreakerItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/IceBreakerItem.java @@ -1,27 +1,26 @@ package it.hurts.sskirillss.relics.items.relics.feet; import it.hurts.sskirillss.relics.api.events.common.LivingSlippingEvent; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.entities.ShockwaveEntity; import it.hurts.sskirillss.relics.init.ItemRegistry; import it.hurts.sskirillss.relics.items.relics.base.RelicItem; import it.hurts.sskirillss.relics.items.relics.base.data.RelicAttributeModifier; import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastStage; import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.PredicateType; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; import it.hurts.sskirillss.relics.utils.Reference; +import it.hurts.sskirillss.relics.utils.data.WorldPosition; import net.minecraft.core.BlockPos; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.sounds.SoundEvents; @@ -31,13 +30,13 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; import top.theillusivec4.curios.api.SlotContext; -public class IceBreakerItem extends RelicItem { - public static final String TAG_FALLING_POINT = "point"; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.WORLD_POSITION; +public class IceBreakerItem extends RelicItem { @Override public RelicData constructDefaultRelicData() { return RelicData.builder() @@ -53,7 +52,7 @@ public RelicData constructDefaultRelicData() { .maxLevel(10) .active(CastData.builder() .type(CastType.INSTANTANEOUS) - .castPredicate("falling", (player, stack) -> !(player.onGround() || player.isSpectator())) + .predicate("falling", PredicateType.CAST, (player, stack) -> !(player.onGround() || player.isSpectator())) .build()) .stat(StatData.builder("size") .initialValue(2.5D, 5D) @@ -68,27 +67,23 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 200)) - .style(StyleData.builder() - .background(Backgrounds.ICY) - .build()) .loot(LootData.builder() - .entry(LootCollections.COLD) + .entry(LootEntries.TAIGA, LootEntries.FROST, LootEntries.MOUNTAIN) .build()) .build(); } @Override - public RelicAttributeModifier getAttributeModifiers(ItemStack stack) { + public RelicAttributeModifier getRelicAttributeModifiers(ItemStack stack) { return RelicAttributeModifier.builder() - .attribute(new RelicAttributeModifier.Modifier(Attributes.KNOCKBACK_RESISTANCE, (float) getAbilityValue(stack, "sustainability", "modifier"))) + .attribute(new RelicAttributeModifier.Modifier(Attributes.KNOCKBACK_RESISTANCE, (float) getStatValue(stack, "sustainability", "modifier"))) .build(); } @Override public void castActiveAbility(ItemStack stack, Player player, String ability, CastType type, CastStage stage) { - if (ability.equals("impact")) { - NBTUtils.setString(stack, TAG_FALLING_POINT, NBTUtils.writePosition(player.position())); - } + if (ability.equals("impact")) + stack.set(WORLD_POSITION, new WorldPosition(player)); } @Override @@ -96,16 +91,18 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { if (!(slotContext.entity() instanceof Player player)) return; - Vec3 position = NBTUtils.parsePosition(NBTUtils.getString(stack, TAG_FALLING_POINT, "")); + WorldPosition position = stack.get(WORLD_POSITION); if (position == null) return; + Vec3 pos = position.getPos(); + if (!player.onGround()) { Vec3 motion = player.getDeltaMovement(); if (player.onGround() || player.isSpectator()) { - NBTUtils.clearTag(stack, TAG_FALLING_POINT); + stack.set(WORLD_POSITION, null); return; } @@ -119,23 +116,23 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { } else { Level level = player.getCommandSenderWorld(); - double distance = (position.y() + Math.abs(level.getMinBuildHeight())) - (player.getY() + Math.abs(level.getMinBuildHeight())); + double distance = (pos.y() + Math.abs(level.getMinBuildHeight())) - (player.getY() + Math.abs(level.getMinBuildHeight())); - NBTUtils.clearTag(stack, TAG_FALLING_POINT); + stack.set(WORLD_POSITION, null); if (distance <= 0) return; - spreadExperience(player, stack, (int) Math.min(10, Math.round(distance / 3F))); + spreadRelicExperience(player, stack, (int) Math.min(10, Math.round(distance / 3F))); ShockwaveEntity shockwave = new ShockwaveEntity(level, - (int) Math.round(Math.min(getAbilityValue(stack, "impact", "size"), distance * 0.25D)), - (float) getAbilityValue(stack, "impact", "damage")); + (int) Math.round(Math.min(getStatValue(stack, "impact", "size"), distance * 0.25D)), + (float) getStatValue(stack, "impact", "damage")); - BlockPos pos = player.getOnPos(); + BlockPos blockPos = player.getOnPos(); shockwave.setOwner(player); - shockwave.setPos(pos.getX(), pos.getY(), pos.getZ()); + shockwave.setPos(blockPos.getX(), blockPos.getY(), blockPos.getZ()); level.addFreshEntity(shockwave); @@ -149,10 +146,10 @@ public void onUnequip(SlotContext slotContext, ItemStack newStack, ItemStack sta if (stack.getItem() == newStack.getItem()) return; - NBTUtils.clearTag(stack, TAG_FALLING_POINT); + stack.set(WORLD_POSITION, null); } - @Mod.EventBusSubscriber(modid = Reference.MODID) + @EventBusSubscriber(modid = Reference.MODID) public static class Events { @SubscribeEvent public static void onLivingSlipping(LivingSlippingEvent event) { diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/IceSkatesItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/IceSkatesItem.java index 309640c2..8f12d6ab 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/IceSkatesItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/IceSkatesItem.java @@ -1,6 +1,5 @@ package it.hurts.sskirillss.relics.items.relics.feet; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.items.relics.base.RelicItem; import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; @@ -9,11 +8,9 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; import it.hurts.sskirillss.relics.utils.WorldUtils; import net.minecraft.core.BlockPos; import net.minecraft.core.particles.ParticleTypes; @@ -25,12 +22,11 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraftforge.common.ForgeMod; import top.theillusivec4.curios.api.SlotContext; -public class IceSkatesItem extends RelicItem { - private static final String TAG_SKATING_DURATION = "duration"; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.CHARGE; +public class IceSkatesItem extends RelicItem { @Override public RelicData constructDefaultRelicData() { return RelicData.builder() @@ -57,11 +53,8 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 200)) - .style(StyleData.builder() - .background(Backgrounds.ICY) - .build()) .loot(LootData.builder() - .entry(LootCollections.COLD) + .entry(LootEntries.FROST) .build()) .build(); } @@ -72,33 +65,33 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { return; Level level = player.getCommandSenderWorld(); - BlockPos pos = player.blockPosition().atY((int) Math.floor(WorldUtils.getGroundHeight(level, player.position(), 16))); + BlockPos pos = player.blockPosition().atY((int) Math.floor(WorldUtils.getGroundHeight(player, player.position(), 16))); - int duration = NBTUtils.getInt(stack, TAG_SKATING_DURATION, 0); + int duration = stack.getOrDefault(CHARGE, 0); - int maxDuration = (int) Math.round(getAbilityValue(stack, "skating", "duration")); + int maxDuration = (int) Math.round(getStatValue(stack, "skating", "duration")); if (player.isSprinting() && !player.isShiftKeyDown() && !player.isInWater() && !player.isInLava() && (level.getBlockState(pos).is(BlockTags.ICE))) { if (player.tickCount % 20 == 0) - spreadExperience(player, stack, 1); + spreadRelicExperience(player, stack, 1); if (duration < maxDuration && player.tickCount % 2 == 0) { - NBTUtils.setInt(stack, TAG_SKATING_DURATION, ++duration); + stack.set(CHARGE, ++duration); } if (level.getRandom().nextInt(maxDuration) < duration) level.addParticle(ParticleTypes.CLOUD, player.getX(), player.getY() + 0.15F, player.getZ(), 0, 0.25F, 0); } else if (duration > 0) - NBTUtils.setInt(stack, TAG_SKATING_DURATION, Math.max(0, duration - 2)); + stack.set(CHARGE, Math.max(0, duration - 2)); - if (canUseAbility(stack, "ram") && duration >= 10) { + if (isAbilityUnlocked(stack, "ram") && duration >= 10) { for (LivingEntity entity : level.getEntitiesOfClass(LivingEntity.class, player.getBoundingBox())) { if (entity == player || entity.hurtTime > 0) continue; - EntityUtils.hurt(entity, level.damageSources().playerAttack(player), (float) (duration * getAbilityValue(stack, "ram", "damage"))); + EntityUtils.hurt(entity, level.damageSources().playerAttack(player), (float) (duration * getStatValue(stack, "ram", "damage"))); double factor = Mth.clamp(duration * 0.025D, 1D, 2D); @@ -106,13 +99,13 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { } } - EntityUtils.removeAttribute(player, stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.MULTIPLY_TOTAL); + EntityUtils.removeAttribute(player, stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); if (duration > 0) { - EntityUtils.applyAttribute(player, stack, Attributes.MOVEMENT_SPEED, (float) (duration * getAbilityValue(stack, "skating", "speed")), AttributeModifier.Operation.MULTIPLY_TOTAL); - EntityUtils.applyAttribute(player, stack, ForgeMod.STEP_HEIGHT_ADDITION.get(), 0.6F, AttributeModifier.Operation.ADDITION); + EntityUtils.applyAttribute(player, stack, Attributes.MOVEMENT_SPEED, (float) (duration * getStatValue(stack, "skating", "speed")), AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); + EntityUtils.applyAttribute(player, stack, Attributes.STEP_HEIGHT, 0.6F, AttributeModifier.Operation.ADD_VALUE); } else - EntityUtils.removeAttribute(player, stack, ForgeMod.STEP_HEIGHT_ADDITION.get(), AttributeModifier.Operation.ADDITION); + EntityUtils.removeAttribute(player, stack, Attributes.STEP_HEIGHT, AttributeModifier.Operation.ADD_VALUE); } @Override @@ -122,7 +115,7 @@ public void onUnequip(SlotContext slotContext, ItemStack newStack, ItemStack sta LivingEntity entity = slotContext.entity(); - EntityUtils.removeAttribute(entity, stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.MULTIPLY_TOTAL); - EntityUtils.removeAttribute(entity, stack, ForgeMod.STEP_HEIGHT_ADDITION.get(), AttributeModifier.Operation.ADDITION); + EntityUtils.removeAttribute(entity, stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); + EntityUtils.removeAttribute(entity, stack, Attributes.STEP_HEIGHT, AttributeModifier.Operation.ADD_VALUE); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/MagmaWalkerItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/MagmaWalkerItem.java index 524652de..c3dfba75 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/MagmaWalkerItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/MagmaWalkerItem.java @@ -6,7 +6,6 @@ import it.hurts.sskirillss.relics.api.events.common.FluidCollisionEvent; import it.hurts.sskirillss.relics.client.models.items.CurioModel; import it.hurts.sskirillss.relics.client.models.items.SidedCurioModel; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.init.ItemRegistry; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; import it.hurts.sskirillss.relics.items.relics.base.IRenderableCurio; @@ -18,11 +17,9 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; import it.hurts.sskirillss.relics.utils.Reference; import net.minecraft.client.model.EntityModel; import net.minecraft.client.model.HumanoidModel; @@ -39,20 +36,20 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.event.entity.living.LivingAttackEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; import top.theillusivec4.curios.api.SlotContext; import top.theillusivec4.curios.api.client.ICurioRenderer; import java.util.List; -@Mod.EventBusSubscriber(modid = Reference.MODID) -public class MagmaWalkerItem extends RelicItem implements IRenderableCurio { - public static final String TAG_HEAT = "heat"; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.CHARGE; +@EventBusSubscriber(modid = Reference.MODID) +public class MagmaWalkerItem extends RelicItem implements IRenderableCurio { @Override public RelicData constructDefaultRelicData() { return RelicData.builder() @@ -69,29 +66,26 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 200)) - .style(StyleData.builder() - .background(Backgrounds.NETHER) - .build()) .loot(LootData.builder() - .entry(LootCollections.NETHER) + .entry(LootEntries.THE_NETHER, LootEntries.NETHER_LIKE) .build()) .build(); } @Override public void inventoryTick(ItemStack stack, Level level, Entity entity, int slot, boolean isSelected) { - int heat = NBTUtils.getInt(stack, TAG_HEAT, 0); + int heat = stack.getOrDefault(CHARGE, 0); if (!(entity instanceof Player player) || player.tickCount % 20 != 0) return; if (heat > 0) { - if (heat > getAbilityValue(stack, "pace", "time")) - player.hurt(level.damageSources().hotFloor(), (float) (1F + ((heat - getAbilityValue(stack, "pace", "time")) / 10F))); + if (heat > getStatValue(stack, "pace", "time")) + player.hurt(level.damageSources().hotFloor(), (float) (1F + ((heat - getStatValue(stack, "pace", "time")) / 10F))); if (!level.getFluidState(player.blockPosition().below()).is(FluidTags.LAVA) && !level.getFluidState(player.blockPosition()).is(FluidTags.LAVA)) - NBTUtils.setInt(stack, TAG_HEAT, --heat); + stack.set(CHARGE, --heat); } } @@ -120,11 +114,11 @@ public > void render(ItemStack ICurioRenderer.followBodyRotations(entity, sidedModel); - VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), false, stack.hasFoil()); + VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), stack.hasFoil()); matrixStack.translate(0, 0, -0.025F); - sidedModel.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, 1F); + sidedModel.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY); matrixStack.popPose(); } @@ -157,11 +151,11 @@ public List bodyParts() { } @SubscribeEvent - public static void onLivingAttack(LivingAttackEvent event) { + public static void onLivingAttack(LivingIncomingDamageEvent event) { ItemStack stack = EntityUtils.findEquippedCurio(event.getEntity(), ItemRegistry.MAGMA_WALKER.get()); if (stack.getItem() instanceof IRelicItem relic && event.getSource() == event.getEntity().level().damageSources().hotFloor() - && NBTUtils.getInt(stack, TAG_HEAT, 0) <= relic.getAbilityValue(stack, "pace", "time")) { + && stack.getOrDefault(CHARGE, 0) <= relic.getStatValue(stack, "pace", "time")) { event.setCanceled(true); } } @@ -175,12 +169,12 @@ public static void onFluidCollide(FluidCollisionEvent event) { return; if (player.tickCount % 20 == 0) { - int heat = NBTUtils.getInt(stack, TAG_HEAT, 0); + int heat = stack.getOrDefault(CHARGE, 0); - NBTUtils.setInt(stack, TAG_HEAT, ++heat); + stack.set(CHARGE, ++heat); if (heat % 5 == 0) - relic.spreadExperience(player, stack, 1); + relic.spreadRelicExperience(player, stack, 1); } event.setCanceled(true); diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/PhantomBootItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/PhantomBootItem.java new file mode 100644 index 00000000..e85f0868 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/PhantomBootItem.java @@ -0,0 +1,248 @@ +package it.hurts.sskirillss.relics.items.relics.feet; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import it.hurts.sskirillss.relics.client.models.items.CurioModel; +import it.hurts.sskirillss.relics.client.models.items.SidedCurioModel; +import it.hurts.sskirillss.relics.init.BlockRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRenderableCurio; +import it.hurts.sskirillss.relics.items.relics.base.RelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastStage; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.*; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemColor; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemShape; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; +import it.hurts.sskirillss.relics.items.relics.base.data.research.ResearchData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.TooltipData; +import it.hurts.sskirillss.relics.utils.MathUtils; +import it.hurts.sskirillss.relics.utils.WorldUtils; +import net.minecraft.client.model.EntityModel; +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.model.geom.builders.*; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.client.renderer.entity.RenderLayerParent; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import top.theillusivec4.curios.api.SlotContext; +import top.theillusivec4.curios.api.client.ICurioRenderer; + +import java.util.List; + +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.TIME; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.TOGGLED; + +public class PhantomBootItem extends RelicItem implements IRenderableCurio { + @Override + public RelicData constructDefaultRelicData() { + return RelicData.builder() + .abilities(AbilitiesData.builder() + .ability(AbilityData.builder("bridge") + .active(CastData.builder() + .type(CastType.TOGGLEABLE) + .build()) + .stat(StatData.builder("duration") + .initialValue(0.25D, 1D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.5D) + .formatValue(value -> MathUtils.round(value, 1)) + .build()) + .research(ResearchData.builder() + .star(0, 11, 8).star(1, 7, 13).star(2, 15, 14) + .star(3, 11, 21).star(4, 3, 29).star(5, 19, 29) + .link(0, 1).link(0, 2).link(0, 3).link(3, 4).link(3, 5).link(4, 5) + .build()) + .build()) + .build()) + .leveling(LevelingData.builder() + .initialCost(100) + .maxLevel(10) + .step(100) + .sources(LevelingSourcesData.builder() + .source(LevelingSourceData.abilityBuilder("bridge") + .initialValue(1) + .gem(GemShape.SQUARE, GemColor.PURPLE) + .build()) + .build()) + .build()) + .style(StyleData.builder() + .tooltip(TooltipData.builder() + .borderTop(0xff5b0591) + .borderBottom(0xff3d0068) + .textured(true) + .build()) + .build()) + .loot(LootData.builder() + .entry(LootEntries.THE_END, LootEntries.END_LIKE) + .build()) + .build(); + } + + @Override + public void castActiveAbility(ItemStack stack, Player player, String ability, CastType type, CastStage stage) { + var level = player.level(); + + if (ability.equals("bridge") && isToggled(stack)) { + if (stage == CastStage.START) { + var motion = player.getDeltaMovement(); + + if (motion.y <= -0.5D) { + player.setDeltaMovement(motion.x, -motion.y, motion.z); + + var state = BlockRegistry.PHANTOM_BLOCK.get().defaultBlockState(); + + state.getBlock().fallOn(level, state, player.blockPosition(), player, player.fallDistance); + } + } + + if (!level.isClientSide() && stage == CastStage.TICK) { + var motion = player.getKnownMovement().multiply(1F, 0F, 1F); + var pos = player.position().add(motion); + var blockPos = new BlockPos((int) Math.floor(pos.x()), (int) Math.floor(pos.y()), (int) Math.floor(pos.z())); + + var radius = (int) Mth.clamp(Math.round(motion.length()), 1, 3); + + for (int x = -radius; x <= radius; x++) { + for (int z = -radius; z <= radius; z++) { + var relativePos = blockPos.offset(x, -1, z); + + if (!level.isEmptyBlock(relativePos)) + continue; + + if (level.setBlockAndUpdate(relativePos, BlockRegistry.PHANTOM_BLOCK.get().defaultBlockState()) + && level.getRandom().nextInt(10) == 0) + spreadRelicExperience(player, stack, 1); + } + } + } + } + } + + @Override + public void curioTick(SlotContext slotContext, ItemStack stack) { + if (!(slotContext.entity() instanceof Player player)) + return; + + var level = player.getCommandSenderWorld(); + + if (level.isClientSide()) + return; + + var block = BlockRegistry.PHANTOM_BLOCK.get(); + + var onBridge = level.getBlockState(player.blockPosition().atY((int) Math.floor(WorldUtils.getGroundHeight(player, player.position(), 8)))).getBlock() == block + || player.isColliding(player.blockPosition(), block.defaultBlockState()); + + var time = getTime(stack); + + if (isToggled(stack)) { + if (onBridge) { + if (player.getKnownMovement().multiply(1F, 0F, 1F).length() > 0) { + if (time > 0) + addTime(stack, -1); + } else { + if (time < getMaxTime(stack)) + addTime(stack, 1); + else setToggled(stack, false); + } + } else if (time > 0) + addTime(stack, -1); + } else { + if (player.onGround() && !onBridge) + setToggled(stack, true); + } + } + + public int getMaxTime(ItemStack stack) { + return (int) Math.round(getStatValue(stack, "bridge", "duration") * 20D); + } + + public int getTime(ItemStack stack) { + return stack.getOrDefault(TIME, 0); + } + + public void setTime(ItemStack stack, int time) { + stack.set(TIME, Mth.clamp(time, 0, getMaxTime(stack))); + } + + public void addTime(ItemStack stack, int time) { + setTime(stack, getTime(stack) + time); + } + + public boolean isToggled(ItemStack stack) { + return stack.getOrDefault(TOGGLED, true); + } + + public void setToggled(ItemStack stack, boolean toggled) { + stack.set(TOGGLED, toggled); + } + + @Override + @OnlyIn(Dist.CLIENT) + public CurioModel getModel(ItemStack stack) { + return new SidedCurioModel(stack.getItem()); + } + + @Override + @OnlyIn(Dist.CLIENT) + public > void render(ItemStack stack, SlotContext slotContext, PoseStack matrixStack, RenderLayerParent renderLayerParent, MultiBufferSource renderTypeBuffer, int light, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch) { + CurioModel model = getModel(stack); + + if (!(model instanceof SidedCurioModel sidedModel)) + return; + + sidedModel.setSlot(slotContext.index()); + + matrixStack.pushPose(); + + LivingEntity entity = slotContext.entity(); + + sidedModel.prepareMobModel(entity, limbSwing, limbSwingAmount, partialTicks); + sidedModel.setupAnim(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch); + + ICurioRenderer.followBodyRotations(entity, sidedModel); + + VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), stack.hasFoil()); + + sidedModel.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY); + + matrixStack.popPose(); + } + + @Override + @OnlyIn(Dist.CLIENT) + public LayerDefinition constructLayerDefinition() { + MeshDefinition mesh = HumanoidModel.createMesh(new CubeDeformation(0.4F), 0.0F); + + PartDefinition right_leg = mesh.getRoot().addOrReplaceChild("right_leg", CubeListBuilder.create().texOffs(0, 0).addBox(-2.5F, 5.25F, -2.5F, 5.0F, 7.0F, 5.0F, new CubeDeformation(0.0F)) + .texOffs(20, 0).addBox(-2.5F, 8.25F, -5.5F, 5.0F, 4.0F, 3.0F, new CubeDeformation(0.0F)) + .texOffs(20, 7).addBox(-2.5F, 8.25F, -5.5F, 5.0F, 4.0F, 3.0F, new CubeDeformation(0.305F)) + .texOffs(0, 12).addBox(-2.5F, 5.25F, -2.5F, 5.0F, 7.0F, 5.0F, new CubeDeformation(0.3F)), PartPose.offset(-1.0F, 11.75F, 2.5F)); + + PartDefinition left_leg = mesh.getRoot().addOrReplaceChild("left_leg", CubeListBuilder.create().texOffs(0, 0).addBox(-2.5F, 5.25F, -2.5F, 5.0F, 7.0F, 5.0F, new CubeDeformation(0.0F)) + .texOffs(20, 0).addBox(-2.5F, 8.25F, -5.5F, 5.0F, 4.0F, 3.0F, new CubeDeformation(0.0F)) + .texOffs(20, 7).addBox(-2.5F, 8.25F, -5.5F, 5.0F, 4.0F, 3.0F, new CubeDeformation(0.305F)) + .texOffs(0, 12).addBox(-2.5F, 5.25F, -2.5F, 5.0F, 7.0F, 5.0F, new CubeDeformation(0.3F)), PartPose.offset(-1.0F, 11.75F, 2.5F)); + + return LayerDefinition.create(mesh, 64, 64); + } + + @Override + public List bodyParts() { + return Lists.newArrayList("right_leg", "left_leg"); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/RollerSkatesItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/RollerSkatesItem.java index 1819a845..3424f9ea 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/RollerSkatesItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/RollerSkatesItem.java @@ -2,7 +2,6 @@ import it.hurts.sskirillss.relics.api.events.common.EntityBlockSpeedFactorEvent; import it.hurts.sskirillss.relics.api.events.common.LivingSlippingEvent; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.init.ItemRegistry; import it.hurts.sskirillss.relics.items.relics.base.RelicItem; import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; @@ -12,25 +11,22 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; import it.hurts.sskirillss.relics.utils.Reference; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.attributes.AttributeModifier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.ForgeMod; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; import top.theillusivec4.curios.api.SlotContext; -public class RollerSkatesItem extends RelicItem { - public static final String TAG_SKATING_DURATION = "duration"; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.CHARGE; +public class RollerSkatesItem extends RelicItem { @Override public RelicData constructDefaultRelicData() { return RelicData.builder() @@ -49,12 +45,8 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 200)) - .style(StyleData.builder() - .background(Backgrounds.PLAINS) - .build()) .loot(LootData.builder() - .entry(LootCollections.VILLAGE) - .entry(LootCollections.ANTHROPOGENIC) + .entry(LootEntries.OVERWORLD) .build()) .build(); } @@ -64,24 +56,24 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { if (!(slotContext.entity() instanceof Player player)) return; - int duration = NBTUtils.getInt(stack, TAG_SKATING_DURATION, 0); + int duration = stack.getOrDefault(CHARGE, 0); if (player.isSprinting() && !player.isShiftKeyDown() && !player.isInWater() && !player.isInLava()) { if (player.tickCount % 20 == 0) - spreadExperience(player, stack, 1); + spreadRelicExperience(player, stack, 1); - if (duration < getAbilityValue(stack, "skating", "duration") && player.tickCount % 4 == 0) - NBTUtils.setInt(stack, TAG_SKATING_DURATION, duration + 1); + if (duration < getStatValue(stack, "skating", "duration") && player.tickCount % 4 == 0) + stack.set(CHARGE, duration + 1); } else if (duration > 0) - NBTUtils.setInt(stack, TAG_SKATING_DURATION, --duration); + stack.set(CHARGE, --duration); - EntityUtils.removeAttribute(player, stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.MULTIPLY_TOTAL); + EntityUtils.removeAttribute(player, stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); if (duration > 0) { - EntityUtils.applyAttribute(player, stack, Attributes.MOVEMENT_SPEED, (float) (duration * getAbilityValue(stack, "skating", "speed")), AttributeModifier.Operation.MULTIPLY_TOTAL); - EntityUtils.applyAttribute(player, stack, ForgeMod.STEP_HEIGHT_ADDITION.get(), 0.6F, AttributeModifier.Operation.ADDITION); + EntityUtils.applyAttribute(player, stack, Attributes.MOVEMENT_SPEED, (float) (duration * getStatValue(stack, "skating", "speed")), AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); + EntityUtils.applyAttribute(player, stack, Attributes.STEP_HEIGHT, 0.6F, AttributeModifier.Operation.ADD_VALUE); } else - EntityUtils.removeAttribute(player, stack, ForgeMod.STEP_HEIGHT_ADDITION.get(), AttributeModifier.Operation.ADDITION); + EntityUtils.removeAttribute(player, stack, Attributes.STEP_HEIGHT, AttributeModifier.Operation.ADD_VALUE); } @Override @@ -91,11 +83,11 @@ public void onUnequip(SlotContext slotContext, ItemStack newStack, ItemStack sta LivingEntity entity = slotContext.entity(); - EntityUtils.removeAttribute(entity, stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.MULTIPLY_TOTAL); - EntityUtils.removeAttribute(entity, stack, ForgeMod.STEP_HEIGHT_ADDITION.get(), AttributeModifier.Operation.ADDITION); + EntityUtils.removeAttribute(entity, stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); + EntityUtils.removeAttribute(entity, stack, Attributes.STEP_HEIGHT, AttributeModifier.Operation.ADD_VALUE); } - @Mod.EventBusSubscriber(modid = Reference.MODID) + @EventBusSubscriber(modid = Reference.MODID) public static class Events { @SubscribeEvent public static void onLivingSlipping(LivingSlippingEvent event) { diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/SpringyBootItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/SpringyBootItem.java new file mode 100644 index 00000000..93da3c24 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/feet/SpringyBootItem.java @@ -0,0 +1,176 @@ +package it.hurts.sskirillss.relics.items.relics.feet; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import it.hurts.sskirillss.relics.client.models.items.CurioModel; +import it.hurts.sskirillss.relics.client.models.items.SidedCurioModel; +import it.hurts.sskirillss.relics.init.SoundRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRenderableCurio; +import it.hurts.sskirillss.relics.items.relics.base.RelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastStage; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.*; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemColor; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemShape; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; +import it.hurts.sskirillss.relics.items.relics.base.data.research.ResearchData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.TooltipData; +import it.hurts.sskirillss.relics.utils.MathUtils; +import net.minecraft.client.model.EntityModel; +import net.minecraft.client.model.HumanoidModel; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.model.geom.builders.*; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.client.renderer.entity.RenderLayerParent; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import top.theillusivec4.curios.api.SlotContext; +import top.theillusivec4.curios.api.client.ICurioRenderer; + +import java.util.List; + +public class SpringyBootItem extends RelicItem implements IRenderableCurio { + @Override + public RelicData constructDefaultRelicData() { + return RelicData.builder() + .abilities(AbilitiesData.builder() + .ability(AbilityData.builder("bounce") + .active(CastData.builder() + .type(CastType.TOGGLEABLE) + .build()) + .stat(StatData.builder("power") + .initialValue(0.25D, 0.5D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.1D) + .formatValue(value -> (int) MathUtils.round(value * 100, 1)) + .build()) + .research(ResearchData.builder() + .star(0, 6, 8).star(1, 16, 10).star(2, 6, 12) + .star(3, 16, 14).star(4, 6, 16).star(5, 16, 18) + .star(6, 6, 20).star(7, 16, 22).star(8, 6, 24) + .link(0, 1).link(1, 2).link(2, 3).link(3, 4).link(4, 5).link(5, 6).link(6, 7).link(7, 8) + .build()) + .build()) + .build()) + .leveling(LevelingData.builder() + .initialCost(100) + .maxLevel(10) + .step(100) + .sources(LevelingSourcesData.builder() + .source(LevelingSourceData.abilityBuilder("bounce") + .initialValue(1) + .gem(GemShape.SQUARE, GemColor.YELLOW) + .build()) + .build()) + .build()) + .style(StyleData.builder() + .tooltip(TooltipData.builder() + .borderTop(0xff8a5610) + .borderBottom(0xff275504) + .textured(true) + .build()) + .build()) + .loot(LootData.builder() + .entry(LootEntries.MOUNTAIN) + .build()) + .build(); + } + + @Override + public void castActiveAbility(ItemStack stack, Player player, String ability, CastType type, CastStage stage) { + var level = player.level(); + + if (ability.equals("bounce") && stage == CastStage.START && player.onGround()) { + var motion = player.getKnownMovement(); + + var speed = getStatValue(stack, "bounce", "power") * 1.25F; + + player.setDeltaMovement(motion.x, speed, motion.z); + + var random = level.getRandom(); + + level.playSound(player, player.blockPosition(), SoundRegistry.SPRING_BOING.get(), SoundSource.PLAYERS, (float) Math.min(2F, 0.25F + speed * 0.5F), (float) Math.max(0.1F, 2F - speed * 0.75F)); + + for (float i = 0; i < speed * 3F; i += 0.1F) + level.addParticle(ParticleTypes.CLOUD, player.getX(), player.getY(), player.getZ(), MathUtils.randomFloat(random) * speed * 0.15F, random.nextFloat() * 0.1F, MathUtils.randomFloat(random) * speed * 0.15F); + } + } + + @Override + @OnlyIn(Dist.CLIENT) + public CurioModel getModel(ItemStack stack) { + return new SidedCurioModel(stack.getItem()); + } + + @Override + @OnlyIn(Dist.CLIENT) + public > void render(ItemStack stack, SlotContext slotContext, PoseStack matrixStack, RenderLayerParent renderLayerParent, MultiBufferSource renderTypeBuffer, int light, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch) { + CurioModel model = getModel(stack); + + if (!(model instanceof SidedCurioModel sidedModel)) + return; + + sidedModel.setSlot(slotContext.index()); + + matrixStack.pushPose(); + + LivingEntity entity = slotContext.entity(); + + sidedModel.prepareMobModel(entity, limbSwing, limbSwingAmount, partialTicks); + sidedModel.setupAnim(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch); + + ICurioRenderer.followBodyRotations(entity, sidedModel); + + VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), stack.hasFoil()); + + sidedModel.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY); + + matrixStack.popPose(); + } + + @Override + @OnlyIn(Dist.CLIENT) + public LayerDefinition constructLayerDefinition() { + MeshDefinition mesh = HumanoidModel.createMesh(new CubeDeformation(0.4F), 0.0F); + + PartDefinition right_leg = mesh.getRoot().addOrReplaceChild("right_leg", CubeListBuilder.create().texOffs(40, 4).addBox(-2.5F, 5.25F, -2.5F, 5.0F, 7.0F, 5.0F, new CubeDeformation(0.305F)) + .texOffs(0, 10).addBox(-2.5F, 5.25F, -2.5F, 5.0F, 7.0F, 5.0F, new CubeDeformation(0.0F)) + .texOffs(0, 22).addBox(-2.5F, 12.25F, -5.5F, 5.0F, 2.0F, 8.0F, new CubeDeformation(0.0F)) + .texOffs(20, 16).addBox(-2.5F, 8.25F, -5.5F, 5.0F, 4.0F, 3.0F, new CubeDeformation(0.0F)) + .texOffs(20, 0).addBox(-2.5F, 8.25F, -5.5F, 5.0F, 4.0F, 3.0F, new CubeDeformation(0.3F)), PartPose.offset(-1.0F, 11.75F, 2.5F)); + + right_leg.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(2, 22).addBox(3.5F, -1.0F, 1.52F, 0.0F, 3.0F, 1.0F, new CubeDeformation(0.001F)) + .texOffs(0, 22).addBox(10.5F, -1.0F, 1.52F, 0.0F, 3.0F, 1.0F, new CubeDeformation(0.001F)) + .texOffs(20, 10).addBox(3.5F, -1.0F, -1.48F, 7.0F, 3.0F, 3.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-7.0F, 8.25F, 1.4F, 0.3491F, 0.0F, 0.0F)); + + PartDefinition left_leg = mesh.getRoot().addOrReplaceChild("left_leg", CubeListBuilder.create().texOffs(40, 4).addBox(-2.5F, 5.25F, -2.5F, 5.0F, 7.0F, 5.0F, new CubeDeformation(0.305F)) + .texOffs(0, 10).addBox(-2.5F, 5.25F, -2.5F, 5.0F, 7.0F, 5.0F, new CubeDeformation(0.0F)) + .texOffs(0, 22).addBox(-2.5F, 12.25F, -5.5F, 5.0F, 2.0F, 8.0F, new CubeDeformation(0.0F)) + .texOffs(20, 16).addBox(-2.5F, 8.25F, -5.5F, 5.0F, 4.0F, 3.0F, new CubeDeformation(0.0F)) + .texOffs(20, 0).addBox(-2.5F, 8.25F, -5.5F, 5.0F, 4.0F, 3.0F, new CubeDeformation(0.3F)), PartPose.offset(-1.0F, 11.75F, 2.5F)); + + left_leg.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(2, 22).addBox(3.5F, -1.0F, 1.52F, 0.0F, 3.0F, 1.0F, new CubeDeformation(0.001F)) + .texOffs(0, 22).addBox(10.5F, -1.0F, 1.52F, 0.0F, 3.0F, 1.0F, new CubeDeformation(0.001F)) + .texOffs(20, 10).addBox(3.5F, -1.0F, -1.48F, 7.0F, 3.0F, 3.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(-7.0F, 8.25F, 1.4F, 0.3491F, 0.0F, 0.0F)); + + return LayerDefinition.create(mesh, 64, 64); + } + + @Override + public List bodyParts() { + return Lists.newArrayList("right_leg", "left_leg"); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/hands/EnderHandItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/hands/EnderHandItem.java index 4976de30..b654723d 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/hands/EnderHandItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/hands/EnderHandItem.java @@ -12,15 +12,14 @@ import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastStage; import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.PredicateType; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; import net.minecraft.client.model.EntityModel; @@ -43,8 +42,8 @@ import net.minecraft.world.level.Level; import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import top.theillusivec4.curios.api.SlotContext; import top.theillusivec4.curios.api.client.ICurioRenderer; @@ -62,8 +61,8 @@ public RelicData constructDefaultRelicData() { .maxLevel(10) .active(CastData.builder() .type(CastType.INSTANTANEOUS) - .castPredicate("target", (player, stack) -> { - EntityHitResult result = EntityUtils.rayTraceEntity(player, (entity) -> !entity.isSpectator() && entity.isPickable(), getAbilityValue(stack, "swap", "distance")); + .predicate("target", PredicateType.CAST, (player, stack) -> { + EntityHitResult result = EntityUtils.rayTraceEntity(player, (entity) -> !entity.isSpectator() && entity.isPickable(), getStatValue(stack, "swap", "distance")); return result != null && result.getEntity() instanceof LivingEntity; }) @@ -76,11 +75,8 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 100)) - .style(StyleData.builder() - .background(Backgrounds.END) - .build()) .loot(LootData.builder() - .entry(LootCollections.END) + .entry(LootEntries.THE_END, LootEntries.END_LIKE) .build()) .build(); } @@ -93,7 +89,7 @@ public void castActiveAbility(ItemStack stack, Player player, String ability, Ca Level level = player.level(); - EntityHitResult result = EntityUtils.rayTraceEntity(player, (entity) -> !entity.isSpectator() && entity.isPickable(), getAbilityValue(stack, "swap", "distance")); + EntityHitResult result = EntityUtils.rayTraceEntity(player, (entity) -> !entity.isSpectator() && entity.isPickable(), getStatValue(stack, "swap", "distance")); if (result == null || !(result.getEntity() instanceof LivingEntity entity)) return; @@ -111,7 +107,7 @@ public void castActiveAbility(ItemStack stack, Player player, String ability, Ca int distance = (int) Math.round(targetPos.distanceTo(currentPos)); - spreadExperience(player, stack, 1 + Math.round(distance * 0.1F)); + spreadRelicExperience(player, stack, 1 + Math.round(distance * 0.1F)); } } @@ -140,11 +136,11 @@ public > void render(ItemStack ICurioRenderer.followBodyRotations(entity, sidedModel); - VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), false, stack.hasFoil()); + VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), stack.hasFoil()); matrixStack.translate(0, 0, -0.025F); - sidedModel.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, 1F); + sidedModel.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY); matrixStack.popPose(); } diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/hands/RageGloveItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/hands/RageGloveItem.java index 4a044232..24c9f6b6 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/hands/RageGloveItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/hands/RageGloveItem.java @@ -6,15 +6,14 @@ import it.hurts.sskirillss.relics.client.models.items.CurioModel; import it.hurts.sskirillss.relics.client.models.items.SidedCurioModel; import it.hurts.sskirillss.relics.client.models.items.SidedFPRCurioModel; -import it.hurts.sskirillss.relics.items.relics.base.IRenderableCurio; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.init.EffectRegistry; import it.hurts.sskirillss.relics.init.ItemRegistry; import it.hurts.sskirillss.relics.init.SoundRegistry; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.items.relics.base.IRenderableCurio; import it.hurts.sskirillss.relics.items.relics.base.RelicItem; import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastStage; import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; @@ -23,11 +22,13 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.network.NetworkHandler; import it.hurts.sskirillss.relics.network.packets.PacketPlayerMotion; -import it.hurts.sskirillss.relics.utils.*; +import it.hurts.sskirillss.relics.utils.EntityUtils; +import it.hurts.sskirillss.relics.utils.MathUtils; +import it.hurts.sskirillss.relics.utils.ParticleUtils; +import it.hurts.sskirillss.relics.utils.Reference; import net.minecraft.client.model.EntityModel; import net.minecraft.client.model.HumanoidModel; import net.minecraft.client.model.geom.PartPose; @@ -56,11 +57,11 @@ import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.event.entity.living.LivingHurtEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; import top.theillusivec4.curios.api.SlotContext; import top.theillusivec4.curios.api.client.ICurioRenderer; @@ -68,10 +69,10 @@ import java.util.ArrayList; import java.util.List; -public class RageGloveItem extends RelicItem implements IRenderableCurio { - public static final String TAG_STACKS = "stacks"; - public static final String TAG_TIME = "time"; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.CHARGE; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.TIME; +public class RageGloveItem extends RelicItem implements IRenderableCurio { @Override public RelicData constructDefaultRelicData() { return RelicData.builder() @@ -137,11 +138,8 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 20, 100)) - .style(StyleData.builder() - .background(Backgrounds.NETHER) - .build()) .loot(LootData.builder() - .entry(LootCollections.NETHER) + .entry(LootEntries.NETHER_LIKE, LootEntries.THE_NETHER) .build()) .build(); } @@ -152,9 +150,9 @@ public void castActiveAbility(ItemStack stack, Player player, String ability, Ca RandomSource random = level.getRandom(); if (ability.equals("spurt")) { - int stacks = NBTUtils.getInt(stack, TAG_STACKS, 0); + int stacks = stack.getOrDefault(CHARGE, 0); - double maxDistance = getAbilityValue(stack, "spurt", "distance"); + double maxDistance = getStatValue(stack, "spurt", "distance"); Vec3 view = player.getViewVector(0); Vec3 eyeVec = player.getEyePosition(0); @@ -177,7 +175,7 @@ public void castActiveAbility(ItemStack stack, Player player, String ability, Ca if (!level.isClientSide()) { NetworkHandler.sendToClient(new PacketPlayerMotion(motion.x, motion.y, motion.z), (ServerPlayer) player); - setAbilityCooldown(stack, "spurt", (int) Math.round(getAbilityValue(stack, "spurt", "cooldown") * 20)); + setAbilityCooldown(stack, "spurt", (int) Math.round(getStatValue(stack, "spurt", "cooldown") * 20)); } player.fallDistance = 0F; @@ -215,8 +213,8 @@ public void castActiveAbility(ItemStack stack, Player player, String ability, Ca } if (!targets.isEmpty()) { - EntityUtils.resetAttribute(player, stack, Attributes.ATTACK_SPEED, Integer.MAX_VALUE, AttributeModifier.Operation.MULTIPLY_BASE); - EntityUtils.resetAttribute(player, stack, Attributes.ATTACK_DAMAGE, (float) (getAbilityValue(stack, "spurt", "damage") * stacks), AttributeModifier.Operation.ADDITION); + EntityUtils.resetAttribute(player, stack, Attributes.ATTACK_SPEED, Integer.MAX_VALUE, AttributeModifier.Operation.ADD_MULTIPLIED_BASE); + EntityUtils.resetAttribute(player, stack, Attributes.ATTACK_DAMAGE, (float) (getStatValue(stack, "spurt", "damage") * stacks), AttributeModifier.Operation.ADD_VALUE); for (LivingEntity entity : targets) { if (entity.invulnerableTime > 0 || EntityUtils.isAlliedTo(player, entity)) @@ -224,17 +222,17 @@ public void castActiveAbility(ItemStack stack, Player player, String ability, Ca player.attack(entity); - spreadExperience(player, stack, 1); + spreadRelicExperience(player, stack, 1); - entity.addEffect(new MobEffectInstance(EffectRegistry.BLEEDING.get(), 100, 0)); - entity.setSecondsOnFire(5); + entity.addEffect(new MobEffectInstance(EffectRegistry.BLEEDING, 100, 0)); + entity.setRemainingFireTicks(5 * 20); } - EntityUtils.removeAttribute(player, stack, Attributes.ATTACK_DAMAGE, AttributeModifier.Operation.ADDITION); - EntityUtils.removeAttribute(player, stack, Attributes.ATTACK_SPEED, AttributeModifier.Operation.MULTIPLY_BASE); + EntityUtils.removeAttribute(player, stack, Attributes.ATTACK_DAMAGE, AttributeModifier.Operation.ADD_VALUE); + EntityUtils.removeAttribute(player, stack, Attributes.ATTACK_SPEED, AttributeModifier.Operation.ADD_MULTIPLIED_BASE); } - NBTUtils.clearTag(stack, TAG_STACKS); + stack.set(CHARGE, 0); } } @@ -243,25 +241,25 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { if (!(slotContext.entity() instanceof Player player)) return; - if (canUseAbility(stack, "phlebotomy")) { + if (isAbilityUnlocked(stack, "phlebotomy")) { float percentage = 100F - (player.getHealth() / player.getMaxHealth() * 100F); - player.heal((float) getAbilityValue(stack, "phlebotomy", "heal") * percentage); + player.heal((float) getStatValue(stack, "phlebotomy", "heal") * percentage); - EntityUtils.resetAttribute(player, stack, Attributes.ATTACK_SPEED, (float) (getAbilityValue(stack, "phlebotomy", "attack_speed") * percentage), AttributeModifier.Operation.MULTIPLY_TOTAL); - EntityUtils.resetAttribute(player, stack, Attributes.MOVEMENT_SPEED, (float) (getAbilityValue(stack, "phlebotomy", "movement_speed") * percentage), AttributeModifier.Operation.MULTIPLY_TOTAL); + EntityUtils.resetAttribute(player, stack, Attributes.ATTACK_SPEED, (float) (getStatValue(stack, "phlebotomy", "attack_speed") * percentage), AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); + EntityUtils.resetAttribute(player, stack, Attributes.MOVEMENT_SPEED, (float) (getStatValue(stack, "phlebotomy", "movement_speed") * percentage), AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); } - if (canUseAbility(stack, "rage")) { - int stacks = NBTUtils.getInt(stack, TAG_STACKS, 0); + if (isAbilityUnlocked(stack, "rage")) { + int stacks = stack.getOrDefault(CHARGE, 0); if (stacks > 0) { - int time = NBTUtils.getInt(stack, TAG_TIME, 0); + int time = stack.getOrDefault(TIME, 0); if (time > 0) - NBTUtils.setInt(stack, TAG_TIME, --time); + stack.set(TIME, --time); else { - NBTUtils.setInt(stack, TAG_STACKS, 0); + stack.set(CHARGE, 0); } } } @@ -273,11 +271,11 @@ public void onUnequip(SlotContext slotContext, ItemStack newStack, ItemStack sta || stack.getItem() == newStack.getItem()) return; - EntityUtils.removeAttribute(player, stack, Attributes.ATTACK_SPEED, AttributeModifier.Operation.MULTIPLY_TOTAL); - EntityUtils.removeAttribute(player, stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.MULTIPLY_TOTAL); + EntityUtils.removeAttribute(player, stack, Attributes.ATTACK_SPEED, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); + EntityUtils.removeAttribute(player, stack, Attributes.MOVEMENT_SPEED, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); - NBTUtils.clearTag(stack, TAG_STACKS); - NBTUtils.clearTag(stack, TAG_TIME); + stack.set(CHARGE, 0); + stack.set(TIME, 0); } @Override @@ -305,11 +303,11 @@ public > void render(ItemStack ICurioRenderer.followBodyRotations(entity, sidedModel); - VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), false, stack.hasFoil()); + VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), stack.hasFoil()); matrixStack.translate(0, 0, -0.025F); - sidedModel.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY, 1F, 1F, 1F, 1F); + sidedModel.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY); matrixStack.popPose(); } @@ -335,10 +333,10 @@ public List bodyParts() { return Lists.newArrayList("right_arm", "left_arm"); } - @Mod.EventBusSubscriber(modid = Reference.MODID) + @EventBusSubscriber(modid = Reference.MODID) public static class Events { @SubscribeEvent - public static void onLivingHurt(LivingHurtEvent event) { + public static void onLivingHurt(LivingIncomingDamageEvent event) { Entity source = event.getSource().getDirectEntity(); if (source instanceof Player player) { @@ -350,15 +348,15 @@ public static void onLivingHurt(LivingHurtEvent event) { if (!(stack.getItem() instanceof IRelicItem relic)) return; - if (relic.canUseAbility(stack, "rage")) { - int stacks = NBTUtils.getInt(stack, TAG_STACKS, 0); + if (relic.isAbilityUnlocked(stack, "rage")) { + int stacks = stack.getOrDefault(CHARGE, 0); - NBTUtils.setInt(stack, TAG_STACKS, ++stacks); - NBTUtils.setInt(stack, TAG_TIME, (int) Math.round(relic.getAbilityValue(stack, "rage", "duration") * 20)); + stack.set(CHARGE, ++stacks); + stack.set(TIME, (int) Math.round(relic.getStatValue(stack, "rage", "duration") * 20)); - relic.spreadExperience(player, stack, 1); + relic.spreadRelicExperience(player, stack, 1); - event.setAmount((float) (event.getAmount() + (event.getAmount() * (stacks * relic.getAbilityValue(stack, "rage", "dealt_damage"))))); + event.setAmount((float) (event.getAmount() + (event.getAmount() * (stacks * relic.getStatValue(stack, "rage", "dealt_damage"))))); } } else if (event.getEntity() instanceof Player player) { ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.RAGE_GLOVE.get()); @@ -366,13 +364,13 @@ public static void onLivingHurt(LivingHurtEvent event) { if (!(stack.getItem() instanceof IRelicItem relic)) return; - if (relic.canUseAbility(stack, "rage")) { - int stacks = NBTUtils.getInt(stack, TAG_STACKS, 0); + if (relic.isAbilityUnlocked(stack, "rage")) { + int stacks = stack.getOrDefault(CHARGE, 0); if (stacks <= 0) return; - event.setAmount((float) (event.getAmount() + (event.getAmount() * (stacks * relic.getAbilityValue(stack, "rage", "incoming_damage"))))); + event.setAmount((float) (event.getAmount() + (event.getAmount() * (stacks * relic.getStatValue(stack, "rage", "incoming_damage"))))); } } } diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/hands/WoolMittenItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/hands/WoolMittenItem.java index e4b5fa7e..d742f996 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/hands/WoolMittenItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/hands/WoolMittenItem.java @@ -1,8 +1,6 @@ package it.hurts.sskirillss.relics.items.relics.hands; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.init.ItemRegistry; -import it.hurts.sskirillss.relics.items.SolidSnowballItem; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; import it.hurts.sskirillss.relics.items.relics.base.RelicItem; import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; @@ -12,11 +10,9 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; import net.minecraft.core.BlockPos; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; @@ -26,13 +22,15 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.SnowLayerBlock; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.event.entity.player.PlayerInteractEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; import java.util.Comparator; import java.util.Optional; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.CHARGE; + public class WoolMittenItem extends RelicItem { @Override public RelicData constructDefaultRelicData() { @@ -62,16 +60,13 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 100)) - .style(StyleData.builder() - .background(Backgrounds.ICY) - .build()) .loot(LootData.builder() - .entry(LootCollections.COLD) + .entry(LootEntries.FROST, LootEntries.TAIGA, LootEntries.MOUNTAIN) .build()) .build(); } - @Mod.EventBusSubscriber + @EventBusSubscriber public static class Events { @SubscribeEvent public static void onBlockClick(PlayerInteractEvent.RightClickBlock event) { @@ -94,11 +89,11 @@ public static void onBlockClick(PlayerInteractEvent.RightClickBlock event) { Inventory inventory = player.getInventory(); - int size = (int) Math.round(relic.getAbilityValue(relicStack, "mold", "size")); + int size = (int) Math.round(relic.getStatValue(relicStack, "mold", "size")); Optional slot = EntityUtils.getSlotsWithItem(player, ItemRegistry.SOLID_SNOWBALL.get()).stream() - .filter(id -> NBTUtils.getInt(inventory.getItem(id), SolidSnowballItem.TAG_SNOW, 0) < size) - .max(Comparator.comparingInt(s -> NBTUtils.getInt(inventory.items.get(s), SolidSnowballItem.TAG_SNOW, 0))); + .filter(id -> inventory.getItem(id).getOrDefault(CHARGE, 0) < size) + .max(Comparator.comparingInt(s -> inventory.items.get(s).getOrDefault(CHARGE, 0))); if (slot.isEmpty()) { if (inventory.add(new ItemStack(ItemRegistry.SOLID_SNOWBALL.get()))) { @@ -114,9 +109,9 @@ public static void onBlockClick(PlayerInteractEvent.RightClickBlock event) { level.destroyBlock(pos, false); - int snow = NBTUtils.getInt(stack, SolidSnowballItem.TAG_SNOW, 0); + int snow = stack.getOrDefault(CHARGE, 0); - NBTUtils.setInt(stack, SolidSnowballItem.TAG_SNOW, Math.min(snow + layers, size)); + stack.set(CHARGE, Math.min(snow + layers, size)); } } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/necklace/HolyLocketItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/necklace/HolyLocketItem.java index 12493b99..9b941232 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/necklace/HolyLocketItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/necklace/HolyLocketItem.java @@ -1,149 +1,317 @@ package it.hurts.sskirillss.relics.items.relics.necklace; -import com.google.common.collect.Lists; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; -import it.hurts.sskirillss.relics.client.models.items.CurioModel; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; +import it.hurts.sskirillss.relics.entities.DeathEssenceEntity; import it.hurts.sskirillss.relics.entities.LifeEssenceEntity; +import it.hurts.sskirillss.relics.init.EffectRegistry; +import it.hurts.sskirillss.relics.init.EntityRegistry; import it.hurts.sskirillss.relics.init.ItemRegistry; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.IRenderableCurio; import it.hurts.sskirillss.relics.items.relics.base.RelicItem; import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastStage; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.*; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemColor; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.GemShape; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; +import it.hurts.sskirillss.relics.items.relics.base.data.research.ResearchData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.BeamsData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.TooltipData; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; -import net.minecraft.client.model.EntityModel; -import net.minecraft.client.model.HumanoidModel; -import net.minecraft.client.model.geom.PartPose; -import net.minecraft.client.model.geom.builders.*; -import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.entity.ItemRenderer; -import net.minecraft.client.renderer.entity.RenderLayerParent; -import net.minecraft.client.renderer.texture.OverlayTexture; +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.event.entity.living.LivingHealEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import top.theillusivec4.curios.api.SlotContext; -import top.theillusivec4.curios.api.client.ICurioRenderer; - -import java.util.List; - -public class HolyLocketItem extends RelicItem implements IRenderableCurio { +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.living.LivingDeathEvent; +import net.neoforged.neoforge.event.entity.living.LivingHealEvent; +import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; + +import java.util.Locale; + +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.MODE; + +public class HolyLocketItem extends RelicItem { @Override public RelicData constructDefaultRelicData() { return RelicData.builder() .abilities(AbilitiesData.builder() - .ability(AbilityData.builder("steal") + .ability(AbilityData.builder("faith") + .active(CastData.builder() + .type(CastType.INSTANTANEOUS) + .build()) + .icon((player, stack, ability) -> ability + "_" + getMode(stack).name().toLowerCase(Locale.ROOT)) + .stat(StatData.builder("health") + .initialValue(0.1D, 0.25D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.1D) + .formatValue(value -> (int) MathUtils.round(value * 100, 0)) + .build()) + .stat(StatData.builder("damage") + .initialValue(0.25D, 0.75D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.5D) + .formatValue(value -> (int) MathUtils.round(value * 100, 0)) + .build()) .stat(StatData.builder("radius") - .initialValue(2D, 6D) + .initialValue(5D, 10D) .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.25D) .formatValue(value -> MathUtils.round(value, 1)) .build()) + .research(ResearchData.builder() + .star(0, 13, 5).star(1, 6, 8).star(2, 10, 12) + .star(3, 4, 13).star(4, 18, 13).star(5, 8, 16) + .star(6, 14, 16).star(7, 5, 20).star(8, 17, 20) + .star(9, 11, 24).star(10, 8, 28).star(11, 14, 28) + .link(0, 2).link(0, 4).link(1, 2).link(1, 3).link(3, 5).link(4, 6).link(5, 6).link(3, 7) + .link(4, 8).link(7, 9).link(8, 9).link(9, 10).link(9, 11).link(10, 11) + .build()) + .build()) + .ability(AbilityData.builder("penitence") + .requiredLevel(5) .stat(StatData.builder("amount") - .initialValue(0.1D, 0.25D) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.2D) - .formatValue(value -> (int) (MathUtils.round(value, 3) * 100)) + .initialValue(0.25D, 0.5D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.3D) + .formatValue(value -> (int) MathUtils.round(value * 100, 0)) + .build()) + .research(ResearchData.builder() + .star(0, 7, 12).star(1, 15, 12).star(2, 6, 19) + .star(3, 16, 19).star(4, 9, 26).star(5, 13, 26) + .link(0, 1).link(0, 2).link(1, 3).link(2, 4).link(3, 5).link(4, 5) + .build()) + .build()) + .ability(AbilityData.builder("ascension") + .requiredLevel(10) + .requiredPoints(3) + .maxLevel(5) + .stat(StatData.builder("max_duration") + .initialValue(7.5D, 15D) + .upgradeModifier(UpgradeOperation.MULTIPLY_TOTAL, 0.64375D) + .formatValue(value -> MathUtils.round(value, 1)) + .build()) + .stat(StatData.builder("duration") + .initialValue(0.5D, 1D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.3D) + .formatValue(value -> MathUtils.round(value, 1)) + .build()) + .research(ResearchData.builder() + .star(0, 11, 27).star(1, 3, 19).star(2, 3, 4) + .star(3, 11, 17).star(4, 6, 13).star(5, 11, 13) + .star(6, 16, 13).star(7, 19, 19).star(8, 19, 4) + .link(0, 1).link(0, 3).link(0, 7).link(1, 2).link(2, 8).link(7, 8).link(3, 4).link(3, 5).link(3, 6) + .build()) + .build()) + .build()) + .leveling(LevelingData.builder() + .initialCost(100) + .maxLevel(20) + .step(100) + .sources(LevelingSourcesData.builder() + .source(LevelingSourceData.abilityBuilder("faith") + .initialValue(1) + .gem(GemShape.SQUARE, GemColor.ORANGE) + .build()) + .source(LevelingSourceData.abilityBuilder("penitence") + .initialValue(1) + .gem(GemShape.SQUARE, GemColor.ORANGE) + .build()) + .source(LevelingSourceData.abilityBuilder("ascension") + .initialValue(1) + .gem(GemShape.SQUARE, GemColor.ORANGE) .build()) .build()) .build()) - .leveling(new LevelingData(100, 10, 200)) .style(StyleData.builder() + .tooltip((player, stack) -> getMode(stack) == Mode.HOLINESS + ? TooltipData.builder() + .borderTop(0xFFcb4a0c) + .borderBottom(0xFF9c3309) + .textured(true) + .icon("holy_locket_holiness") + .build() + : TooltipData.builder() + .borderTop(0xFF484c51) + .borderBottom(0xFF484c51) + .textured(true) + .icon("holy_locket_wickedness") + .build()) + .beams((player, stack) -> getMode(stack) == Mode.HOLINESS + ? BeamsData.builder() + .startColor(0xFFFFFF00) + .endColor(0x00FF0000) + .build() + : BeamsData.builder() + .startColor(0xFF00FFFF) + .endColor(0x000000FF) + .build()) .build()) .loot(LootData.builder() - .entry(LootCollections.DESERT) + .entry(LootEntries.DESERT) .build()) .build(); } - @Override - @OnlyIn(Dist.CLIENT) - public > void render(ItemStack stack, SlotContext slotContext, PoseStack matrixStack, RenderLayerParent renderLayerParent, MultiBufferSource renderTypeBuffer, int light, float limbSwing, float limbSwingAmount, float partialTicks, float ageInTicks, float netHeadYaw, float headPitch) { - CurioModel model = getModel(stack); + public Mode getMode(ItemStack stack) { + return Mode.byIndex(stack.getOrDefault(MODE, Mode.HOLINESS.getIndex())); + } - matrixStack.pushPose(); + public void setMode(ItemStack stack, Mode mode) { + stack.set(MODE, mode.getIndex()); + } - LivingEntity entity = slotContext.entity(); + public void cycleMode(ItemStack stack, int steps) { + setMode(stack, getMode(stack).cycle(steps)); + } - model.prepareMobModel(entity, limbSwing, limbSwingAmount, partialTicks); - model.setupAnim(entity, limbSwing, limbSwingAmount, ageInTicks, netHeadYaw, headPitch); + @Override + public void castActiveAbility(ItemStack stack, Player player, String ability, CastType type, CastStage stage) { + if (ability.equals("faith") && stage == CastStage.END) + cycleMode(stack, 1); + } - ICurioRenderer.translateIfSneaking(matrixStack, entity); - ICurioRenderer.rotateIfSneaking(matrixStack, entity); + @Getter + @AllArgsConstructor + public enum Mode { + HOLINESS(1), + WICKEDNESS(2); - ICurioRenderer.followBodyRotations(entity, model); + private final int index; - VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), false, stack.hasFoil()); + public static Mode byIndex(int index) { + for (var mode : Mode.values()) + if (mode.getIndex() == index) + return mode; - matrixStack.scale(0.5F, 0.5F, 0.5F); + throw new IllegalArgumentException(); + } - model.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY, 1.0F, 1.0F, 1.0F, 1.0F); + public Mode cycle(int steps) { + var modes = Mode.values(); + int index = (this.ordinal() + steps) % modes.length; - matrixStack.scale(2F, 2F, 2F); + if (index < 0) + index += modes.length; - matrixStack.popPose(); + return modes[index]; + } } - @Override - @OnlyIn(Dist.CLIENT) - public LayerDefinition constructLayerDefinition() { - MeshDefinition mesh = HumanoidModel.createMesh(new CubeDeformation(0.4F), 0.0F); + @EventBusSubscriber + public static class HolyLocketEvents { + @SubscribeEvent + public static void onLivingDeath(LivingDeathEvent event) { + if (!(event.getSource().getEntity() instanceof Player player)) + return; - PartDefinition bone = mesh.getRoot().addOrReplaceChild("body", CubeListBuilder.create().texOffs(0, 3).addBox(-8.0F, -1.15F, -4.15F, 16.0F, 7.0F, 8.0F, new CubeDeformation(0.5F)), PartPose.offset(0.0F, 1.15F, 0.0F)); + for (var stack : EntityUtils.findEquippedCurios(player, ItemRegistry.HOLY_LOCKET.get())) { + if (!(stack.getItem() instanceof IRelicItem relic) || !relic.canPlayerUseAbility(player, stack, "ascension")) + continue; - bone.addOrReplaceChild("cube_r1", CubeListBuilder.create().texOffs(0, 18).addBox(-2.6096F, -0.8646F, -0.2F, 5.0F, 1.0F, 1.0F, new CubeDeformation(0.0F)), PartPose.offsetAndRotation(0.0571F, 6.6447F, -4.9F, 0.0F, 0.0F, 0.2568F)); - bone.addOrReplaceChild("cube_r2", CubeListBuilder.create().texOffs(12, 18).addBox(-1.0F, -1.0F, -0.5F, 2.0F, 2.0F, 1.0F, new CubeDeformation(-0.15F)), PartPose.offsetAndRotation(0.0877F, 6.2393F, -5.2F, 0.0F, 0.0F, 0.7854F)); - bone.addOrReplaceChild("cube_r3", CubeListBuilder.create().texOffs(0, 0).addBox(-1.0322F, -2.5947F, -0.225F, 2.0F, 6.0F, 1.0F, new CubeDeformation(0.05F)), PartPose.offsetAndRotation(0.0571F, 6.6447F, -4.9F, 0.0F, 0.0F, -0.004F)); + var effect = player.getEffect(EffectRegistry.IMMORTALITY); + var duration = effect == null ? 0 : effect.getDuration(); + var maxDuration = (int) (relic.getStatValue(stack, "ascension", "max_duration") * 20); - return LayerDefinition.create(mesh, 64, 64); - } + if (duration >= maxDuration) + continue; - @Override - public List headParts() { - return Lists.newArrayList("body"); - } + player.addEffect(new MobEffectInstance(EffectRegistry.IMMORTALITY, (int) Math.min((relic.getStatValue(stack, "ascension", "duration") * 20) + duration, maxDuration))); + + relic.spreadRelicExperience(player, stack, 1); + } + } - @Mod.EventBusSubscriber - static class Events { @SubscribeEvent - public static void onLivingHurt(LivingHealEvent event) { - LivingEntity entity = event.getEntity(); - Level level = entity.getCommandSenderWorld(); + public static void onLivingHeal(LivingHealEvent event) { + var amount = event.getAmount(); + + if (amount <= 0.5F) + return; + + var item = ItemRegistry.HOLY_LOCKET.get(); - for (Player player : level.getEntitiesOfClass(Player.class, entity.getBoundingBox().inflate(32))) { - ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.HOLY_LOCKET.get()); + var maxDistance = item.getRelativeStatValue("faith", "radius", item.getStatData("faith", "radius").getInitialValue().getValue(), item.getLevelingData().getMaxLevel()); - if (!(stack.getItem() instanceof IRelicItem relic) || relic.getAbilityValue(stack, "steal", "radius") < player.position().distanceTo(entity.position()) - || entity.getStringUUID().equals(player.getStringUUID())) + var entity = event.getEntity(); + var level = entity.getCommandSenderWorld(); + var random = level.getRandom(); + + for (var player : EntityUtils.gatherPotentialTargets(entity, Player.class, maxDistance).toList()) { + if (player.getStringUUID().equals(entity.getStringUUID())) continue; - float amount = (float) (event.getAmount() * relic.getAbilityValue(stack, "steal", "amount")); + for (var stack : EntityUtils.findEquippedCurios(player, ItemRegistry.HOLY_LOCKET.get())) { + if (!(stack.getItem() instanceof HolyLocketItem relic) || relic.getMode(stack) != Mode.HOLINESS || !relic.canPlayerUseAbility(player, stack, "faith") + || entity.position().distanceTo(player.position()) > relic.getStatValue(stack, "faith", "radius")) + continue; + + var heal = (float) (amount * relic.getStatValue(stack, "faith", "health")); + + var essence = new LifeEssenceEntity(EntityRegistry.LIFE_ESSENCE.get(), level); + + essence.setHeal(heal); + essence.setOwner(player); + essence.setTarget(player); + essence.setPos(entity.getEyePosition()); + essence.setDeltaMovement(MathUtils.randomFloat(random), random.nextFloat(), MathUtils.randomFloat(random)); - LifeEssenceEntity essence = new LifeEssenceEntity(player, amount); + level.addFreshEntity(essence); + + event.setAmount(amount - heal); + + relic.spreadRelicExperience(player, stack, 1); + } + } + + if (entity instanceof Player player && player.getHealth() < player.getMaxHealth()) { + for (var stack : EntityUtils.findEquippedCurios(player, ItemRegistry.HOLY_LOCKET.get())) { + if (!(stack.getItem() instanceof HolyLocketItem relic) || relic.getMode(stack) != Mode.WICKEDNESS || !relic.canPlayerUseAbility(player, stack, "faith")) + continue; + + for (var target : EntityUtils.gatherPotentialTargets(player, LivingEntity.class, relic.getStatValue(stack, "faith", "radius")).toList()) { + if (player.getStringUUID().equals(target.getStringUUID())) + continue; + + var essence = new DeathEssenceEntity(EntityRegistry.DEATH_ESSENCE.get(), level); + + essence.setOwner(player); + essence.setTarget(target); + essence.setPos(player.getEyePosition()); + essence.setDamage((float) (event.getAmount() * relic.getStatValue(stack, "faith", "damage"))); + essence.setDeltaMovement(MathUtils.randomFloat(random), random.nextFloat(), MathUtils.randomFloat(random)); + + level.addFreshEntity(essence); + + relic.spreadRelicExperience(player, stack, 1); + } + } + } + } + + @SubscribeEvent + public static void onLivingDamage(LivingIncomingDamageEvent event) { + var entity = event.getEntity(); + + if (!entity.isInvertedHealAndHarm() || !(event.getSource().getEntity() instanceof Player player)) + return; + + for (var stack : EntityUtils.findEquippedCurios(player, ItemRegistry.HOLY_LOCKET.get())) { + if (!(stack.getItem() instanceof HolyLocketItem relic) || !relic.canPlayerUseAbility(player, stack, "penitence")) + continue; - essence.setPos(entity.position().add(0, entity.getBbHeight() / 2, 0)); - essence.setOwner(player); + var amount = event.getAmount(); - level.addFreshEntity(essence); + if (amount >= 1F && !entity.isOnFire()) + relic.spreadRelicExperience(player, stack, 1); - if (event.getAmount() >= 1) - relic.spreadExperience(player, stack, 1 + Math.round(amount)); + event.setAmount((float) (amount + (amount * relic.getStatValue(stack, "penitence", "amount")))); - event.setAmount(event.getAmount() - amount); + entity.igniteForSeconds(10F); } } } diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/necklace/JellyfishNecklaceItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/necklace/JellyfishNecklaceItem.java index 164d7c36..c3e489b7 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/necklace/JellyfishNecklaceItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/necklace/JellyfishNecklaceItem.java @@ -16,9 +16,7 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; import net.minecraft.client.model.EntityModel; @@ -34,12 +32,12 @@ import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.ForgeMod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import top.theillusivec4.curios.api.SlotContext; import top.theillusivec4.curios.api.client.ICurioRenderer; @@ -73,11 +71,8 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 200)) - .style(StyleData.builder() - .background(Backgrounds.AQUATIC) - .build()) .loot(LootData.builder() - .entry(LootCollections.AQUATIC) + .entry(LootEntries.AQUATIC) .build()) .build(); } @@ -88,9 +83,9 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { return; if (player.isEyeInFluid(FluidTags.WATER)) - EntityUtils.applyAttribute(player, stack, ForgeMod.ENTITY_GRAVITY.get(), -1F, AttributeModifier.Operation.MULTIPLY_TOTAL); + EntityUtils.applyAttribute(player, stack, Attributes.GRAVITY, -1F, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); else - EntityUtils.removeAttribute(player, stack, ForgeMod.ENTITY_GRAVITY.get(), AttributeModifier.Operation.MULTIPLY_TOTAL); + EntityUtils.removeAttribute(player, stack, Attributes.GRAVITY, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); Level level = player.getCommandSenderWorld(); @@ -99,11 +94,11 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { if (entity == player) continue; - if (EntityUtils.hurt(entity, level.damageSources().playerAttack(player), (float) getAbilityValue(stack, "shock", "damage"))) { - spreadExperience(player, stack, 1); + if (EntityUtils.hurt(entity, level.damageSources().playerAttack(player), (float) getStatValue(stack, "shock", "damage"))) { + spreadRelicExperience(player, stack, 1); - if (canUseAbility(stack, "paralysis")) - entity.addEffect(new MobEffectInstance(EffectRegistry.PARALYSIS.get(), (int) Math.round(getAbilityValue(stack, "paralysis", "duration") * 20), 0)); + if (isAbilityUnlocked(stack, "paralysis")) + entity.addEffect(new MobEffectInstance(EffectRegistry.PARALYSIS, (int) Math.round(getStatValue(stack, "paralysis", "duration") * 20), 0)); } } } @@ -111,7 +106,7 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { @Override public void onUnequip(SlotContext slotContext, ItemStack newStack, ItemStack stack) { - EntityUtils.removeAttribute(slotContext.entity(), stack, ForgeMod.ENTITY_GRAVITY.get(), AttributeModifier.Operation.MULTIPLY_TOTAL); + EntityUtils.removeAttribute(slotContext.entity(), stack, Attributes.GRAVITY, AttributeModifier.Operation.ADD_MULTIPLIED_TOTAL); } @Override @@ -131,11 +126,11 @@ public > void render(ItemStack ICurioRenderer.followBodyRotations(entity, model); - VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), false, stack.hasFoil()); + VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), stack.hasFoil()); matrixStack.scale(0.5F, 0.5F, 0.5F); - model.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY, 1.0F, 1.0F, 1.0F, 1.0F); + model.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY); matrixStack.scale(2F, 2F, 2F); diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/necklace/ReflectionNecklaceItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/necklace/ReflectionNecklaceItem.java index 28234872..7b845179 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/necklace/ReflectionNecklaceItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/necklace/ReflectionNecklaceItem.java @@ -4,7 +4,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import it.hurts.sskirillss.relics.client.models.items.CurioModel; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.entities.StalactiteEntity; import it.hurts.sskirillss.relics.init.ItemRegistry; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; @@ -17,12 +16,11 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; +import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.items.relics.base.data.style.TooltipData; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; -import it.hurts.sskirillss.relics.utils.NBTUtils; import it.hurts.sskirillss.relics.utils.Reference; import net.minecraft.client.model.EntityModel; import net.minecraft.client.model.HumanoidModel; @@ -41,20 +39,20 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.event.entity.living.LivingHurtEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.living.LivingIncomingDamageEvent; import top.theillusivec4.curios.api.SlotContext; import top.theillusivec4.curios.api.client.ICurioRenderer; import java.util.List; -public class ReflectionNecklaceItem extends RelicItem implements IRenderableCurio { - public static final String TAG_CHARGE = "charge"; - public static final String TAG_TIME = "time"; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.CHARGE; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.TIME; +public class ReflectionNecklaceItem extends RelicItem implements IRenderableCurio { @Override public RelicData constructDefaultRelicData() { return RelicData.builder() @@ -84,10 +82,9 @@ public RelicData constructDefaultRelicData() { .borderBottom(0xff0090a9) .textured(true) .build()) - .background(Backgrounds.NETHER) .build()) .loot(LootData.builder() - .entry(LootCollections.NETHER) + .entry(LootEntries.NETHER_LIKE, LootEntries.THE_NETHER) .build()) .build(); } @@ -98,13 +95,11 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { || player.tickCount % 20 != 0) return; - int time = NBTUtils.getInt(stack, TAG_TIME, 0); - double charge = NBTUtils.getDouble(stack, TAG_CHARGE, 0); - - if (time > 0 && charge < getAbilityValue(stack, "explode", "capacity")) { - --time; + int time = stack.getOrDefault(TIME, 0); + double charge = stack.getOrDefault(CHARGE, 0); - NBTUtils.setInt(stack, TAG_TIME, time); + if (time > 0 && charge < getStatValue(stack, "explode", "capacity")) { + stack.set(TIME, --time); } else if (charge > 0) { Level level = player.level(); RandomSource random = player.getRandom(); @@ -131,8 +126,8 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { continue; StalactiteEntity stalactite = new StalactiteEntity(level, - (float) (charge * getAbilityValue(stack, "explode", "damage")), - (float) (charge * getAbilityValue(stack, "explode", "stun"))); + (float) (charge * getStatValue(stack, "explode", "damage")), + (float) (charge * getStatValue(stack, "explode", "stun"))); stalactite.setOwner(player); stalactite.setPos(pos); @@ -143,10 +138,10 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { } } - spreadExperience(player, stack, (int) Math.floor(charge / 10F)); + spreadRelicExperience(player, stack, (int) Math.floor(charge / 10F)); - NBTUtils.setDouble(stack, TAG_CHARGE, 0); - NBTUtils.setInt(stack, TAG_TIME, 0); + stack.set(CHARGE, 0); + stack.set(TIME, 0); } } @@ -167,11 +162,11 @@ public > void render(ItemStack ICurioRenderer.followBodyRotations(entity, model); - VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), false, stack.hasFoil()); + VertexConsumer vertexconsumer = ItemRenderer.getArmorFoilBuffer(renderTypeBuffer, RenderType.armorCutoutNoCull(getTexture(stack)), stack.hasFoil()); matrixStack.scale(0.5F, 0.5F, 0.5F); - model.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY, 1.0F, 1.0F, 1.0F, 1.0F); + model.renderToBuffer(matrixStack, vertexconsumer, light, OverlayTexture.NO_OVERLAY); matrixStack.scale(2F, 2F, 2F); @@ -197,10 +192,10 @@ public List headParts() { return Lists.newArrayList("body"); } - @Mod.EventBusSubscriber(modid = Reference.MODID) + @EventBusSubscriber(modid = Reference.MODID) public static class ReflectionNecklaceServerEvents { @SubscribeEvent - public static void onEntityHurt(LivingHurtEvent event) { + public static void onEntityHurt(LivingIncomingDamageEvent event) { if (!(event.getEntity() instanceof Player)) return; @@ -209,13 +204,13 @@ public static void onEntityHurt(LivingHurtEvent event) { if (!(stack.getItem() instanceof IRelicItem relic)) return; - double charge = NBTUtils.getDouble(stack, TAG_CHARGE, 0); - double capacity = relic.getAbilityValue(stack, "explode", "capacity"); + double charge = stack.getOrDefault(CHARGE, 0); + double capacity = relic.getStatValue(stack, "explode", "capacity"); if (charge < capacity) { - NBTUtils.setDouble(stack, TAG_CHARGE, Math.min(capacity, charge + (event.getAmount()))); + stack.set(CHARGE, (int) Math.min(capacity, charge + (event.getAmount()))); - NBTUtils.setInt(stack, TAG_TIME, 5); + stack.set(TIME, 5); } } } diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/ring/BastionRingItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/ring/BastionRingItem.java index a3adb62d..1be2f14c 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/ring/BastionRingItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/ring/BastionRingItem.java @@ -11,9 +11,7 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; import it.hurts.sskirillss.relics.utils.ParticleUtils; @@ -37,9 +35,9 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.levelgen.structure.Structure; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.event.entity.living.LivingDeathEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.living.LivingDeathEvent; import top.theillusivec4.curios.api.SlotContext; import java.awt.*; @@ -64,11 +62,8 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 200)) - .style(StyleData.builder() - .background(Backgrounds.NETHER) - .build()) .loot(LootData.builder() - .entry(LootCollections.BASTION) + .entry(LootEntries.BASTION) .build()) .build(); } @@ -91,10 +86,10 @@ public void curioTick(SlotContext slotContext, ItemStack stack) { ServerLevel serverLevel = (ServerLevel) world; - ResourceKey.create(Registries.STRUCTURE, new ResourceLocation("bastion_remnant")); + ResourceKey.create(Registries.STRUCTURE, ResourceLocation.parse("bastion_remnant")); Optional> optional = serverLevel.registryAccess().registryOrThrow(Registries.STRUCTURE) - .getHolder(ResourceKey.create(Registries.STRUCTURE, new ResourceLocation("bastion_remnant"))) + .getHolder(ResourceKey.create(Registries.STRUCTURE, ResourceLocation.parse("bastion_remnant"))) .map(HolderSet::direct); if (optional.isEmpty()) @@ -138,7 +133,7 @@ public boolean makesPiglinsNeutral(SlotContext slotContext, ItemStack stack) { return true; } - @Mod.EventBusSubscriber + @EventBusSubscriber public static class Events { @SubscribeEvent public static void onLivingDeath(LivingDeathEvent event) { @@ -153,13 +148,13 @@ public static void onLivingDeath(LivingDeathEvent event) { LivingEntity entity = event.getEntity(); if (entity instanceof ZombifiedPiglin) - relic.spreadExperience(player, stack, 1); + relic.spreadRelicExperience(player, stack, 1); if (entity instanceof Piglin) - relic.spreadExperience(player, stack, 5); + relic.spreadRelicExperience(player, stack, 5); if (entity instanceof PiglinBrute) - relic.spreadExperience(player, stack, 10); + relic.spreadRelicExperience(player, stack, 10); } } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/ring/ChorusInhibitorItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/ring/ChorusInhibitorItem.java index 8a4793f8..d782ebfb 100644 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/ring/ChorusInhibitorItem.java +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/ring/ChorusInhibitorItem.java @@ -1,6 +1,5 @@ package it.hurts.sskirillss.relics.items.relics.ring; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; import it.hurts.sskirillss.relics.init.ItemRegistry; import it.hurts.sskirillss.relics.items.relics.base.RelicItem; import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; @@ -10,8 +9,7 @@ import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.misc.Backgrounds; +import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootEntries; import it.hurts.sskirillss.relics.utils.EntityUtils; import it.hurts.sskirillss.relics.utils.MathUtils; import it.hurts.sskirillss.relics.utils.ParticleUtils; @@ -26,9 +24,9 @@ import net.minecraft.world.level.Level; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.event.entity.EntityTeleportEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.EntityTeleportEvent; import top.theillusivec4.curios.api.SlotContext; import javax.annotation.Nullable; @@ -53,11 +51,8 @@ public RelicData constructDefaultRelicData() { .build()) .build()) .leveling(new LevelingData(100, 10, 100)) - .style(StyleData.builder() - .background(Backgrounds.END) - .build()) .loot(LootData.builder() - .entry(LootCollections.END) + .entry(LootEntries.THE_END, LootEntries.END_LIKE) .build()) .build(); } @@ -87,7 +82,7 @@ public BlockPos getEyesPos(Player player, ItemStack stack) { Vec3 view = player.getViewVector(0); Vec3 eyeVec = player.getEyePosition(0); - double distance = getAbilityValue(stack, "blink", "distance"); + double distance = getStatValue(stack, "blink", "distance"); BlockHitResult ray = world.clip(new ClipContext(eyeVec, eyeVec.add(view.x * distance, view.y * distance, view.z * distance), ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, player)); @@ -111,7 +106,7 @@ public BlockPos getEyesPos(Player player, ItemStack stack) { return null; } - @Mod.EventBusSubscriber + @EventBusSubscriber public static class Events { @SubscribeEvent public static void onChorusTeleport(EntityTeleportEvent.ChorusFruit event) { @@ -130,11 +125,11 @@ public static void onChorusTeleport(EntityTeleportEvent.ChorusFruit event) { if (pos == null) return; - relic.spreadExperience(player, stack, (int) Math.floor(player.position().distanceTo(new Vec3(pos.getX(), pos.getY(), pos.getZ())) / 10F)); + relic.spreadRelicExperience(player, stack, (int) Math.floor(player.position().distanceTo(new Vec3(pos.getX(), pos.getY(), pos.getZ())) / 10F)); player.teleportTo(pos.getX() + 0.5D, pos.getY(), pos.getZ() + 0.5D); player.level().playSound(null, pos, SoundEvents.CHORUS_FRUIT_TELEPORT, SoundSource.PLAYERS, 1F, 1F); - player.getCooldowns().addCooldown(Items.CHORUS_FRUIT, Math.max((int) Math.round(relic.getAbilityValue(stack, "blink", "cooldown") * 20D), 0)); + player.getCooldowns().addCooldown(Items.CHORUS_FRUIT, Math.max((int) Math.round(relic.getStatValue(stack, "blink", "cooldown") * 20D), 0)); } } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/ring/LeafyRingItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/ring/LeafyRingItem.java new file mode 100644 index 00000000..695e8bde --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/items/relics/ring/LeafyRingItem.java @@ -0,0 +1,102 @@ +package it.hurts.sskirillss.relics.items.relics.ring; + +import it.hurts.sskirillss.relics.init.EffectRegistry; +import it.hurts.sskirillss.relics.items.relics.base.RelicItem; +import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; +import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; +import it.hurts.sskirillss.relics.items.relics.base.data.style.TooltipData; +import it.hurts.sskirillss.relics.utils.MathUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.BushBlock; +import top.theillusivec4.curios.api.SlotContext; + +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.PROGRESS; +import static it.hurts.sskirillss.relics.init.DataComponentRegistry.TOGGLED; + +public class LeafyRingItem extends RelicItem { + @Override + public RelicData constructDefaultRelicData() { + return RelicData.builder() + .abilities(AbilitiesData.builder() + .ability(AbilityData.builder("hide") + .stat(StatData.builder("speed") + .initialValue(0.1D, 0.35D) + .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.25D) + .formatValue(value -> MathUtils.round(value * 100, 1)) + .build()) + .build()) + .build()) + .style(StyleData.builder() + .tooltip(TooltipData.builder() + .borderTop(0xff164f00) + .borderBottom(0xff164f00) + .textured(true) + .build()) + .build()) + .leveling(new LevelingData(100, 10, 200)) + .build(); + } + + @Override + public void curioTick(SlotContext slotContext, ItemStack stack) { + if (!(slotContext.entity() instanceof Player player)) + return; + + var level = player.getCommandSenderWorld(); + + { + var progress = getCurrentProgress(stack); + var hiding = isHiding(stack); + + var pos = player.getBoundingBox().getBottomCenter().add(0F, player.getBbHeight(), 0F); + + if (player.isShiftKeyDown() && level.getBlockState(new BlockPos((int) Math.floor(pos.x()), (int) Math.floor(pos.y()), (int) Math.floor(pos.z()))).getBlock() instanceof BushBlock) { + if (!hiding) + setHiding(stack, true); + + if (progress < getMaxProgress()) + addCurrentProgress(stack, 1); + + player.addEffect(new MobEffectInstance(EffectRegistry.VANISHING, 5, 0, false, false)); + } else { + if (hiding) + setHiding(stack, false); + + if (progress > 0) + addCurrentProgress(stack, -1); + } + } + } + + public boolean isHiding(ItemStack stack) { + return stack.getOrDefault(TOGGLED, false); + } + + public void setHiding(ItemStack stack, boolean hiding) { + stack.set(TOGGLED, hiding); + } + + public int getCurrentProgress(ItemStack stack) { + return stack.getOrDefault(PROGRESS, 0); + } + + public void setCurrentProgress(ItemStack stack, int progress) { + stack.set(PROGRESS, Math.clamp(progress, 0, getMaxProgress())); + } + + public void addCurrentProgress(ItemStack stack, int progress) { + setCurrentProgress(stack, getCurrentProgress(stack) + progress); + } + + public int getMaxProgress() { + return 10; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/items/relics/talisman/SporeSackItem.java b/src/main/java/it/hurts/sskirillss/relics/items/relics/talisman/SporeSackItem.java deleted file mode 100644 index cbe21e42..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/items/relics/talisman/SporeSackItem.java +++ /dev/null @@ -1,220 +0,0 @@ -package it.hurts.sskirillss.relics.items.relics.talisman; - -import it.hurts.sskirillss.relics.entities.SporeEntity; -import it.hurts.sskirillss.relics.init.EntityRegistry; -import it.hurts.sskirillss.relics.init.ItemRegistry; -import it.hurts.sskirillss.relics.items.relics.base.RelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.CastData; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastStage; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilitiesData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.LevelingData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.misc.UpgradeOperation; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.LootData; -import it.hurts.sskirillss.relics.items.relics.base.data.loot.misc.LootCollections; -import it.hurts.sskirillss.relics.items.relics.base.data.style.StyleData; -import it.hurts.sskirillss.relics.utils.*; -import net.minecraft.core.particles.ParticleTypes; -import net.minecraft.sounds.SoundEvents; -import net.minecraft.sounds.SoundSource; -import net.minecraft.util.Mth; -import net.minecraft.util.RandomSource; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.Vec3; -import net.minecraftforge.event.entity.living.LivingHurtEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import top.theillusivec4.curios.api.SlotContext; - -import java.util.Random; - -public class SporeSackItem extends RelicItem { - private static final String TAG_SPORES = "spores"; - - @Override - public RelicData constructDefaultRelicData() { - return RelicData.builder() - .abilities(AbilitiesData.builder() - .ability(AbilityData.builder("spore") - .maxLevel(10) - .stat(StatData.builder("size") - .initialValue(0.1D, 0.5D) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.15D) - .formatValue(value -> MathUtils.round(value, 2)) - .build()) - .stat(StatData.builder("damage") - .initialValue(0.25D, 0.5D) - .upgradeModifier(UpgradeOperation.MULTIPLY_TOTAL, 0.1D) - .formatValue(value -> MathUtils.round(value, 2)) - .build()) - .stat(StatData.builder("cooldown") - .initialValue(15D, 10D) - .upgradeModifier(UpgradeOperation.MULTIPLY_TOTAL, -0.1D) - .formatValue(value -> MathUtils.round(value, 1)) - .build()) - .stat(StatData.builder("duration") - .initialValue(2D, 4D) - .upgradeModifier(UpgradeOperation.MULTIPLY_TOTAL, 0.2D) - .formatValue(value -> MathUtils.round(value, 1)) - .build()) - .build()) - .ability(AbilityData.builder("buffer") - .requiredLevel(5) - .maxLevel(10) - .stat(StatData.builder("capacity") - .initialValue(2D, 5D) - .upgradeModifier(UpgradeOperation.ADD, 1D) - .formatValue(value -> (int) MathUtils.round(value, 0)) - .build()) - .stat(StatData.builder("chance") - .initialValue(0.025D, 0.075D) - .upgradeModifier(UpgradeOperation.MULTIPLY_TOTAL, 0.1) - .formatValue(value -> MathUtils.round(value * 100, 1)) - .build()) - .build()) - .ability(AbilityData.builder("multiplying") - .requiredLevel(10) - .maxLevel(10) - .stat(StatData.builder("chance") - .initialValue(0.05D, 0.15D) - .upgradeModifier(UpgradeOperation.MULTIPLY_TOTAL, 0.128) - .formatValue(value -> (int) Math.round(MathUtils.round(value, 3) * 100)) - .build()) - .stat(StatData.builder("size") - .initialValue(0.05D, 0.1D) - .upgradeModifier(UpgradeOperation.MULTIPLY_TOTAL, 0.1775) - .formatValue(value -> (int) Math.round(MathUtils.round(value, 3) * 100)) - .build()) - .stat(StatData.builder("amount") - .initialValue(0.05D, 0.15D) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.4) - .formatValue(value -> MathUtils.round(value, 2)) - .build()) - .build()) - .ability(AbilityData.builder("explosion") - .requiredLevel(15) - .maxLevel(10) - .active(CastData.builder() - .type(CastType.INSTANTANEOUS) - .castPredicate("spore", (player, stack) -> NBTUtils.getInt(stack, TAG_SPORES, 0) > 0) - .build()) - .stat(StatData.builder("size") - .initialValue(0.05D, 0.25D) - .upgradeModifier(UpgradeOperation.MULTIPLY_BASE, 0.15D) - .formatValue(value -> MathUtils.round(value, 2)) - .build()) - .build()) - .build()) - .leveling(new LevelingData(100, 20, 100)) - .style(StyleData.builder() - .build()) - .loot(LootData.builder() - .entry(LootCollections.JUNGLE) - .build()) - .build(); - } - - public int getMaxSpores(ItemStack stack) { - return (int) Math.round(canUseAbility(stack, "buffer") ? getAbilityValue(stack, "buffer", "capacity") : 1); - } - - public int getSpores(ItemStack stack) { - return NBTUtils.getInt(stack, TAG_SPORES, 0); - } - - public void setSpores(ItemStack stack, int amount) { - NBTUtils.setInt(stack, TAG_SPORES, Mth.clamp(amount, 0, getMaxSpores(stack))); - } - - public void addSpores(ItemStack stack, int amount) { - if (canUseAbility(stack, "buffer") && amount < 0 - && new Random().nextFloat() <= getAbilityValue(stack, "buffer", "chance")) - return; - - setSpores(stack, getSpores(stack) + amount); - } - - @Override - public void castActiveAbility(ItemStack stack, Player player, String ability, CastType type, CastStage stage) { - Level level = player.getCommandSenderWorld(); - RandomSource random = level.getRandom(); - - if (ability.equals("explosion")) { - if (getSpores(stack) > 0) { - ParticleUtils.createBall(ParticleTypes.SPIT, player.position().add(0, player.getBbHeight() / 2F, 0), level, 2, 0.5F); - level.playSound(null, player.blockPosition(), SoundEvents.PUFFER_FISH_BLOW_OUT, SoundSource.MASTER, 1F, 1F); - - while (getSpores(stack) > 0) { - float mul = player.getBbHeight() / 1.5F; - float speed = 0.25F + random.nextFloat() * 0.2F; - Vec3 motion = new Vec3(MathUtils.randomFloat(random) * speed, speed, MathUtils.randomFloat(random) * speed); - - SporeEntity spore = new SporeEntity(EntityRegistry.SPORE.get(), level); - - spore.setOwner(player); - spore.setStack(stack); - spore.setDeltaMovement(motion); - spore.setPos(player.position().add(0, mul, 0).add(motion.normalize().scale(mul))); - spore.setSize((float) Math.min(player.getMaxHealth(), 0.1F + (player.getMaxHealth() - player.getHealth()) * getAbilityValue(stack, "explosion", "size"))); - - level.addFreshEntity(spore); - - addSpores(stack, -1); - } - } - } - } - - @Override - public void curioTick(SlotContext slotContext, ItemStack stack) { - if (!(slotContext.entity() instanceof Player player) || player.level().isClientSide() || getSpores(stack) >= getMaxSpores(stack) - || player.tickCount % Math.round(getAbilityValue(stack, "spore", "cooldown") * 20) != 0) - return; - - addSpores(stack, 1); - } - - @Mod.EventBusSubscriber(modid = Reference.MODID) - public static class Events { - @SubscribeEvent - public static void onLivingHurt(LivingHurtEvent event) { - if (!(event.getEntity() instanceof Player player)) - return; - - ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.SPORE_SACK.get()); - - if (!(stack.getItem() instanceof SporeSackItem relic) || relic.getSpores(stack) < 1) - return; - - Level level = player.level(); - - if (level.isClientSide()) - return; - - RandomSource random = player.getRandom(); - - float mul = player.getBbHeight() / 1.5F; - float speed = 0.25F + random.nextFloat() * 0.2F; - Vec3 motion = new Vec3(MathUtils.randomFloat(random) * speed, speed, MathUtils.randomFloat(random) * speed); - - SporeEntity spore = new SporeEntity(EntityRegistry.SPORE.get(), level); - - spore.setOwner(player); - spore.setStack(stack.copy()); - spore.setDeltaMovement(motion); - spore.setPos(player.position().add(0, mul, 0).add(motion.normalize().scale(mul))); - spore.setSize((float) Math.min(player.getMaxHealth(), 0.1F + event.getAmount() * relic.getAbilityValue(stack, "spore", "size"))); - - level.addFreshEntity(spore); - - relic.addSpores(stack, -1); - - relic.spreadExperience(player, stack, 1); - } - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/level/RelicLootModifier.java b/src/main/java/it/hurts/sskirillss/relics/level/RelicLootModifier.java index 256bb477..e3ed3599 100644 --- a/src/main/java/it/hurts/sskirillss/relics/level/RelicLootModifier.java +++ b/src/main/java/it/hurts/sskirillss/relics/level/RelicLootModifier.java @@ -1,24 +1,43 @@ package it.hurts.sskirillss.relics.level; -import com.mojang.serialization.Codec; +import com.google.common.base.Suppliers; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; -import it.hurts.sskirillss.relics.init.CodecRegistry; +import it.hurts.sskirillss.relics.init.ConfigRegistry; +import it.hurts.sskirillss.relics.init.LootCodecRegistry; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.RelicStorage; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; -import net.minecraftforge.common.loot.IGlobalLootModifier; -import net.minecraftforge.common.loot.LootModifier; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.common.loot.IGlobalLootModifier; +import net.neoforged.neoforge.common.loot.LootModifier; +import net.neoforged.neoforge.event.server.ServerStartedEvent; +import net.neoforged.neoforge.server.ServerLifecycleHooks; import org.jetbrains.annotations.NotNull; import javax.annotation.Nonnull; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; +import java.util.function.Supplier; +import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; public class RelicLootModifier extends LootModifier { - public static final Codec CODEC = RecordCodecBuilder.create(inst -> codecStart(inst).apply(inst, RelicLootModifier::new)); + public static final Supplier> CODEC = Suppliers.memoize(() -> RecordCodecBuilder.mapCodec(inst -> codecStart(inst).apply(inst, RelicLootModifier::new))); + + public static final List LOOT_ENTRIES = new ArrayList<>(); public RelicLootModifier(LootItemCondition[] conditionsIn) { super(conditionsIn); @@ -27,27 +46,49 @@ public RelicLootModifier(LootItemCondition[] conditionsIn) { @Nonnull @Override protected @NotNull ObjectArrayList doApply(ObjectArrayList generatedLoot, LootContext context) { - String lootId = context.getQueriedLootTableId().toString(); + var entity = context.getParamOrNull(LootContextParams.THIS_ENTITY); + var vec = context.getParamOrNull(LootContextParams.ORIGIN); + var table = context.getQueriedLootTableId().toString(); + + if (vec == null || entity == null) + return generatedLoot; + + var random = context.getRandom(); + + if (random.nextDouble() > ConfigRegistry.LOOT_CONFIG.getRelicGenChance()) + return generatedLoot; + + var pos = new BlockPos((int) vec.x(), (int) vec.y(), (int) vec.z()); + var level = entity.level(); + + List entries = new ArrayList<>(); - boolean isValid; + for (var entry : LOOT_ENTRIES) { + if (!(entry.getTables().stream().anyMatch(matcher -> matcher.matches(table)) + && entry.getDimensions().stream().anyMatch(matcher -> matcher.matches(level.dimension().location().toString())) + && entry.getBiomes().stream().anyMatch(matcher -> matcher.matches(level.getBiome(pos).getRegisteredName())))) + continue; - for (IRelicItem relic : RelicStorage.RELICS.keySet()) { - for (Map.Entry entry : relic.getLootData().getCollection().getEntries().entrySet()) { - String pattern = entry.getKey(); - float chance = entry.getValue(); + entries.add(entry); + } + + if (entries.isEmpty()) + return generatedLoot; + + var weight = entries.stream().mapToDouble(LootEntryCache::getWeight).sum(); - try { - isValid = lootId.matches(pattern); - } catch (PatternSyntaxException exception) { - isValid = lootId.equals(pattern); - } + if (weight <= 0D) + return generatedLoot; - if (isValid) { - if (context.getRandom().nextFloat() <= chance) - generatedLoot.add(relic.getItem().getDefaultInstance()); + var range = random.nextDouble() * weight; - break; - } + for (var entry : entries) { + range -= entry.getWeight(); + + if (range <= 0D) { + generatedLoot.add(entry.getItem().getDefaultInstance()); + + break; } } @@ -55,7 +96,95 @@ public RelicLootModifier(LootItemCondition[] conditionsIn) { } @Override - public Codec codec() { - return CodecRegistry.RELIC_LOOT.get(); + public MapCodec codec() { + return LootCodecRegistry.RELIC_LOOT.get(); + } + + public static void processRelicCache(IRelicItem relic) { + var server = ServerLifecycleHooks.getCurrentServer(); + + if (server == null) + return; + + LOOT_ENTRIES.removeIf(entry -> entry.getItem() == relic); + + for (var entry : relic.getLootData().getEntries()) { + var item = relic.getItem(); + + if (item == null) + continue; + + LOOT_ENTRIES.add(new LootEntryCache(compileRegex(entry.getDimensions()), compileRegex(entry.getBiomes()), compileRegex(entry.getTables()), entry.getWeight(), item)); + } + } + + private static List compileRegex(List patterns) { + List entries = new ArrayList<>(); + + for (var pattern : patterns) { + try { + entries.add(new RegexEntry(Pattern.compile(pattern))); + } catch (PatternSyntaxException e) { + entries.add(new StringEntry(pattern)); + } + } + + return entries; + } + + @EventBusSubscriber + public static class Events { + @SubscribeEvent + public static void onServerStarted(ServerStartedEvent event) { + if (!LOOT_ENTRIES.isEmpty()) + return; + + for (var entry : BuiltInRegistries.ITEM.entrySet()) { + if (!(entry.getValue() instanceof IRelicItem relic)) + continue; + + processRelicCache(relic); + } + } + } + + @Data + @AllArgsConstructor + public static class LootEntryCache { + private List dimensions; + private List biomes; + private List tables; + + private int weight; + + private Item item; + } + + private static sealed abstract class MatcherEntry permits RegexEntry, StringEntry { + public abstract boolean matches(String input); + } + + @Data + @AllArgsConstructor + @EqualsAndHashCode(callSuper = true) + private static non-sealed class RegexEntry extends MatcherEntry { + private Pattern entry; + + @Override + public boolean matches(String input) { + return entry.matcher(input).matches(); + } + } + + @Data + @AllArgsConstructor + @EqualsAndHashCode(callSuper = true) + private static non-sealed class StringEntry extends MatcherEntry { + private String entry; + + @Override + public boolean matches(String input) { + return entry.equals(input); + } } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/AbstractChestedHorseMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/AbstractChestedHorseMixin.java index 547f8f36..618be035 100644 --- a/src/main/java/it/hurts/sskirillss/relics/mixin/AbstractChestedHorseMixin.java +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/AbstractChestedHorseMixin.java @@ -1,36 +1,27 @@ package it.hurts.sskirillss.relics.mixin; -import it.hurts.sskirillss.relics.items.relics.HorseFluteItem; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.animal.horse.AbstractChestedHorse; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.ItemStack; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @Mixin(AbstractChestedHorse.class) public class AbstractChestedHorseMixin { - @Inject(at = @At(value = "HEAD"), method = "mobInteract", cancellable = true) - protected void onInteract(Player player, InteractionHand hand, CallbackInfoReturnable info) { - AbstractChestedHorse horse = (AbstractChestedHorse) (Object) this; - ItemStack stack = player.getItemInHand(hand); - - if (!(stack.getItem() instanceof HorseFluteItem item)) - return; - - CompoundTag nbt = stack.getTagElement(HorseFluteItem.TAG_ENTITY); - - if (nbt != null) { - item.releaseHorse(stack, player); - item.catchHorse(horse, player, stack); - } - - item.catchHorse(horse, player, stack); - - info.setReturnValue(InteractionResult.SUCCESS); - } +// @Inject(at = @At(value = "HEAD"), method = "mobInteract", cancellable = true) +// protected void onInteract(Player player, InteractionHand hand, CallbackInfoReturnable info) { +// AbstractChestedHorse horse = (AbstractChestedHorse) (Object) this; +// ItemStack stack = player.getItemInHand(hand); +// +// if (!(stack.getItem() instanceof HorseFluteItem item)) +// return; +// +// CompoundTag nbt = NBTUtils.getOrCreateTag(stack).getCompound(HorseFluteItem.TAG_ENTITY); +// +// if (nbt != null) { +// item.releaseHorse(stack, player); +// item.catchHorse(horse, player, stack); +// } +// +// item.catchHorse(horse, player, stack); +// +// info.setReturnValue(InteractionResult.SUCCESS); +// } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/AbstractContainerMenuMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/AbstractContainerMenuMixin.java index 2dcb9fb2..b0104c84 100644 --- a/src/main/java/it/hurts/sskirillss/relics/mixin/AbstractContainerMenuMixin.java +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/AbstractContainerMenuMixin.java @@ -4,7 +4,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.*; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.MinecraftForge; +import net.neoforged.neoforge.common.NeoForge; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -23,7 +23,7 @@ protected void onClick(int index, int action, ClickType clickType, Player player if (canInteract(slot, player, menu)) { ContainerSlotClickEvent event = new ContainerSlotClickEvent(player, menu, slot, action == 0 ? ClickAction.PRIMARY : ClickAction.SECONDARY, menu.getCarried(), slot.getItem()); - MinecraftForge.EVENT_BUS.post(event); + NeoForge.EVENT_BUS.post(event); if (event.isCanceled()) ci.cancel(); diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/BlockMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/BlockMixin.java new file mode 100644 index 00000000..abf03897 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/BlockMixin.java @@ -0,0 +1,81 @@ +package it.hurts.sskirillss.relics.mixin; + +import it.hurts.sskirillss.relics.init.ItemRegistry; +import it.hurts.sskirillss.relics.init.SoundRegistry; +import it.hurts.sskirillss.relics.items.relics.feet.SpringyBootItem; +import it.hurts.sskirillss.relics.utils.EntityUtils; +import it.hurts.sskirillss.relics.utils.MathUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(Block.class) +public class BlockMixin { + @Inject(method = "fallOn", at = @At("HEAD"), cancellable = true) + public void onEntityFall(Level level, BlockState state, BlockPos pos, Entity entity, float fallDistance, CallbackInfo ci) { + if (!(entity instanceof Player player)) + return; + + var stack = EntityUtils.findEquippedCurio(player, ItemRegistry.SPRINGY_BOOT.get()); + + if (!(stack.getItem() instanceof SpringyBootItem relic) || !relic.isAbilityTicking(stack, "bounce")) + return; + + var motion = player.getKnownMovement(); + var speed = motion.multiply(0F, 1F, 0F).y(); + + if (speed > -0.5D) + return; + + player.causeFallDamage(fallDistance, 0F, level.damageSources().fall()); + + ci.cancel(); + } + + @Inject(method = "updateEntityAfterFallOn", at = @At("HEAD"), cancellable = true) + public void onEntityFall(BlockGetter getter, Entity entity, CallbackInfo ci) { + if (!(entity instanceof Player player)) + return; + + var stack = EntityUtils.findEquippedCurio(player, ItemRegistry.SPRINGY_BOOT.get()); + + if (!(stack.getItem() instanceof SpringyBootItem relic) || !relic.isAbilityTicking(stack, "bounce")) + return; + + var motion = player.getKnownMovement(); + var speed = motion.multiply(0F, 1F, 0F).y(); + + if (speed > -0.5D) + return; + + var level = player.getCommandSenderWorld(); + + if (!level.isClientSide()) + relic.spreadRelicExperience(player, stack, 1); + + speed = Math.abs(speed); + + var power = relic.getStatValue(stack, "bounce", "power"); + + player.setDeltaMovement(motion.multiply(1D, -power, 1D)); + + var random = level.getRandom(); + + level.playSound(player, player.blockPosition(), SoundRegistry.SPRING_BOING.get(), SoundSource.PLAYERS, (float) Math.min(2F, 0.25F + speed * 0.5F), (float) Math.max(0.1F, 2F - speed * 0.75F)); + + for (float i = 0; i < speed * 3F; i += 0.1F) + level.addParticle(ParticleTypes.CLOUD, player.getX(), player.getY(), player.getZ(), MathUtils.randomFloat(random) * speed * 0.15F, 0F, MathUtils.randomFloat(random) * speed * 0.15F); + + ci.cancel(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/CameraMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/CameraMixin.java index df7ef40b..1b3bb0f8 100644 --- a/src/main/java/it/hurts/sskirillss/relics/mixin/CameraMixin.java +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/CameraMixin.java @@ -15,7 +15,7 @@ public class CameraMixin { public void onRotationUpdate(float yaw, float pitch, CallbackInfo ci) { Player player = Minecraft.getInstance().player; - if (player != null && player.hasEffect(EffectRegistry.STUN.get())) + if (player != null && player.hasEffect(EffectRegistry.STUN)) ci.cancel(); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/EntityMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/EntityMixin.java index 5645aee9..222a7ca9 100644 --- a/src/main/java/it/hurts/sskirillss/relics/mixin/EntityMixin.java +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/EntityMixin.java @@ -14,7 +14,7 @@ import net.minecraft.world.phys.shapes.BooleanOp; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; -import net.minecraftforge.common.MinecraftForge; +import net.neoforged.neoforge.common.NeoForge; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -68,7 +68,7 @@ public Vec3 fluidCollision(Vec3 original) { FluidCollisionEvent event = new FluidCollisionEvent(entity, highestFluid); - MinecraftForge.EVENT_BUS.post(event); + NeoForge.EVENT_BUS.post(event); if (event.isCanceled()) { entity.fallDistance = 0F; @@ -97,7 +97,7 @@ public void getBlockSpeedFactor(CallbackInfoReturnable cir) { EntityBlockSpeedFactorEvent event = new EntityBlockSpeedFactorEvent(entity, entity.level().getBlockState(entity.getOnPos()), cir.getReturnValue()); - MinecraftForge.EVENT_BUS.post(event); + NeoForge.EVENT_BUS.post(event); cir.setReturnValue(event.getSpeedFactor()); } diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/GameDataMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/GameDataMixin.java new file mode 100644 index 00000000..91ed65a4 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/GameDataMixin.java @@ -0,0 +1,27 @@ +package it.hurts.sskirillss.relics.mixin; + +import it.hurts.sskirillss.relics.init.RegistryRegistry; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.neoforge.registries.GameData; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.LinkedHashSet; +import java.util.Set; + +@Mixin(GameData.class) +public class GameDataMixin { + @Inject(method = "getRegistrationOrder", at = @At("RETURN"), cancellable = true) + private static void onGetRegistrationOrder(CallbackInfoReturnable> cir) { + Set order = new LinkedHashSet<>(); + + order.add(RegistryRegistry.RELIC_CONTAINER_REGISTRY_KEY.location()); + order.add(RegistryRegistry.BADGE_REGISTRY_KEY.location()); + + order.addAll(cir.getReturnValue()); + + cir.setReturnValue(order); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/GuiGraphicsMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/GuiGraphicsMixin.java index 6b070fcb..ad13dfcb 100644 --- a/src/main/java/it/hurts/sskirillss/relics/mixin/GuiGraphicsMixin.java +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/GuiGraphicsMixin.java @@ -1,12 +1,19 @@ package it.hurts.sskirillss.relics.mixin; +import com.mojang.math.Axis; import it.hurts.sskirillss.relics.api.events.common.TooltipDisplayEvent; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.RenderUtils; +import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipComponent; import net.minecraft.client.gui.screens.inventory.tooltip.ClientTooltipPositioner; -import net.minecraftforge.client.event.RenderTooltipEvent; -import net.minecraftforge.common.MinecraftForge; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.neoforged.neoforge.client.event.RenderTooltipEvent; +import net.neoforged.neoforge.common.NeoForge; import org.joml.Vector2ic; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -21,6 +28,40 @@ public class GuiGraphicsMixin { @Inject(method = "renderTooltipInternal", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;popPose()V", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILSOFT) public void onTooltipRender(Font font, List tooltip, int x, int y, ClientTooltipPositioner positioner, CallbackInfo info, RenderTooltipEvent.Pre event, int width, int height, int postWidth, int postHeight, Vector2ic postPos) { if (!tooltip.isEmpty()) - MinecraftForge.EVENT_BUS.post(new TooltipDisplayEvent(event.getItemStack(), (GuiGraphics) (Object) this, postWidth, postHeight, postPos.x(), postPos.y())); + NeoForge.EVENT_BUS.post(new TooltipDisplayEvent(event.getItemStack(), (GuiGraphics) (Object) this, postWidth, postHeight, postPos.x(), postPos.y())); + } + + @Inject(method = "renderItem(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/item/ItemStack;IIII)V", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/vertex/PoseStack;scale(FFF)V", shift = At.Shift.AFTER)) + public void renderItem(LivingEntity entity, Level level, ItemStack stack, int x, int y, int seed, int guiOffset, CallbackInfo ci) { + var player = Minecraft.getInstance().player; + + if (player == null || !(stack.getItem() instanceof IRelicItem relic) || !relic.isRelicFlawless(stack)) + return; + + var data = relic.getStyleData().getBeams().apply(player, stack); + + var guiGraphics = (GuiGraphics) (Object) this; + var poseStack = guiGraphics.pose(); + + var partialTicks = Minecraft.getInstance().getTimer().getGameTimeDeltaPartialTick(true); + + var beams = 8; + + var time = player.tickCount + partialTicks; + + for (int i = 0; i < beams; i++) { + float angle = (float) (i * 2F * Math.PI / beams); + + poseStack.pushPose(); + + poseStack.mulPose(Axis.ZP.rotation(angle)); + poseStack.mulPose(Axis.ZP.rotation(time * 0.025F)); + + var length = 0.85F + ((i % 2 == 0 ? Math.sin(time * 0.25F) : Math.cos(time * 0.25F)) * 0.1F); + + RenderUtils.renderFlatBeam(guiGraphics, partialTicks, (float) length, 0.45F, data.getStartColor(), data.getEndColor()); + + poseStack.popPose(); + } } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/ItemMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/ItemMixin.java index 784f50b7..3fe2c38b 100644 --- a/src/main/java/it/hurts/sskirillss/relics/mixin/ItemMixin.java +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/ItemMixin.java @@ -1,23 +1,22 @@ package it.hurts.sskirillss.relics.mixin; +import it.hurts.sskirillss.relics.init.HotkeyRegistry; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; import it.hurts.sskirillss.relics.items.relics.base.data.RelicStorage; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; +import it.hurts.sskirillss.relics.items.relics.base.data.leveling.StatData; import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.player.LocalPlayer; +import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.Entity; +import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.registries.ForgeRegistries; -import org.jetbrains.annotations.Nullable; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -51,52 +50,44 @@ public void inventoryTick(ItemStack stack, Level level, Entity entity, int slot, } @Inject(method = "appendHoverText", at = @At("HEAD")) - public void appendHoverText(ItemStack stack, @Nullable Level level, List tooltip, TooltipFlag isAdvanced, CallbackInfo ci) { - relics$processTooltip(stack, level, tooltip); + public void appendHoverText(ItemStack stack, Item.TooltipContext context, List tooltip, TooltipFlag flag, CallbackInfo ci) { + relics$processTooltip(stack, context, tooltip); } @Unique @OnlyIn(Dist.CLIENT) - private void relics$processTooltip(ItemStack stack, @Nullable Level level, List tooltip) { + private void relics$processTooltip(ItemStack stack, Item.TooltipContext context, List tooltip) { Item item = stack.getItem(); - if (!(item instanceof IRelicItem relic) || (level == null || !level.isClientSide())) + if (!(item instanceof IRelicItem)) return; - LocalPlayer player = Minecraft.getInstance().player; - tooltip.add(Component.literal(" ")); - if (relic.isItemResearched(player)) { - if (Screen.hasShiftDown()) { - RelicData relicData = relic.getRelicData(); - - if (relicData == null) - return; + if (Minecraft.getInstance().screen instanceof AbstractContainerScreen) + tooltip.add(Component.translatable("tooltip.relics.researching.info", HotkeyRegistry.RESEARCH_RELIC.getKey().getDisplayName()).withStyle(ChatFormatting.GRAY)); - Map abilities = relicData.getAbilities().getAbilities(); + tooltip.add(Component.literal(" ")); + } - tooltip.add(Component.literal("▶ ").withStyle(ChatFormatting.DARK_GREEN) - .append(Component.translatable("tooltip.relics.relic.tooltip.abilities").withStyle(ChatFormatting.GREEN))); + @Inject(method = "verifyComponentsAfterLoad", at = @At("HEAD")) + public void onVerifyComponentsAfterLoad(ItemStack stack, CallbackInfo ci) { + if (!(stack.getItem() instanceof IRelicItem relic)) + return; - for (Map.Entry entry : abilities.entrySet()) { - String id = ForgeRegistries.ITEMS.getKey(item).getPath(); - String name = entry.getKey(); + for (AbilityData abilityData : relic.getAbilitiesData().getAbilities().values()) { + String abilityId = abilityData.getId(); - if (!relic.canUseAbility(stack, name)) - continue; + if (relic.getAbilityComponent(stack, abilityId) == null) + relic.randomizeAbilityStats(stack, abilityId, 0); + else { + for (StatData statData : relic.getAbilityData(abilityId).getStats().values()) { + String statId = statData.getId(); - tooltip.add(Component.literal(" ◆ ").withStyle(ChatFormatting.GREEN) - .append(Component.translatable("tooltip.relics." + id + ".ability." + name).withStyle(ChatFormatting.YELLOW)) - .append(Component.literal(" - ").withStyle(ChatFormatting.WHITE)) - .append(Component.translatable("tooltip.relics." + id + ".ability." + name + ".description").withStyle(ChatFormatting.GRAY))); + if (relic.getStatComponent(stack, abilityId, statId) == null) + relic.randomizeStat(stack, abilityId, statId); } - } else { - tooltip.add(Component.translatable("tooltip.relics.relic.tooltip.shift").withStyle(ChatFormatting.GRAY)); } - } else - tooltip.add(Component.translatable("tooltip.relics.relic.tooltip.table").withStyle(ChatFormatting.GRAY)); - - tooltip.add(Component.literal(" ")); + } } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/ItemStackMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/ItemStackMixin.java deleted file mode 100644 index 75cc65c5..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/mixin/ItemStackMixin.java +++ /dev/null @@ -1,43 +0,0 @@ -package it.hurts.sskirillss.relics.mixin; - -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.RelicData; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; -import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.ItemLike; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import java.util.Map; - -@Mixin(ItemStack.class) -public abstract class ItemStackMixin { - @Inject(at = @At(value = "TAIL"), method = "(Lnet/minecraft/world/level/ItemLike;ILnet/minecraft/nbt/CompoundTag;)V") - protected void init(ItemLike slug, int count, CompoundTag tag, CallbackInfo ci) { - ItemStack stack = (ItemStack) (Object) this; - Item item = stack.getItem(); - - if (!(item instanceof IRelicItem relic)) - return; - - RelicData data = relic.getRelicData(); - - if (data == null) - return; - - for (Map.Entry entry : data.getAbilities().getAbilities().entrySet()) { - String id = entry.getKey(); - - relic.randomizeStats(stack, id); - relic.setAbilityPoints(stack, id, 0); - - if (relic.getAbilityCastData(id).getType() == CastType.TOGGLEABLE) - relic.setAbilityTicking(stack, id, true); - } - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/KeyboardHandlerMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/KeyboardHandlerMixin.java index 9c27996b..9d5404d4 100644 --- a/src/main/java/it/hurts/sskirillss/relics/mixin/KeyboardHandlerMixin.java +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/KeyboardHandlerMixin.java @@ -16,7 +16,7 @@ public class KeyboardHandlerMixin { public void onKeyPress(long windowPointer, int key, int scanCode, int action, int modifiers, CallbackInfo ci) { Player player = Minecraft.getInstance().player; - if (key != GLFW.GLFW_KEY_ESCAPE && player != null && player.hasEffect(EffectRegistry.STUN.get())) + if (key != GLFW.GLFW_KEY_ESCAPE && player != null && player.hasEffect(EffectRegistry.STUN)) ci.cancel(); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/LivingEntityMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/LivingEntityMixin.java index 79a96963..daaf0244 100644 --- a/src/main/java/it/hurts/sskirillss/relics/mixin/LivingEntityMixin.java +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/LivingEntityMixin.java @@ -9,8 +9,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.level.Level; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.network.PacketDistributor; +import net.neoforged.neoforge.common.NeoForge; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -26,7 +25,7 @@ protected float setBlockFriction(float original) { LivingSlippingEvent event = new LivingSlippingEvent(entity, entity.getCommandSenderWorld().getBlockState(entity.getOnPos()), original); - MinecraftForge.EVENT_BUS.post(event); + NeoForge.EVENT_BUS.post(event); return event.getFriction(); } @@ -35,10 +34,10 @@ protected float setBlockFriction(float original) { protected void onAiStep(CallbackInfoReturnable cir) { LivingEntity entity = (LivingEntity) (Object) this; - if (entity.hasEffect(EffectRegistry.STUN.get())) + if (entity.hasEffect(EffectRegistry.STUN)) cir.setReturnValue(true); - if (entity.hasEffect(EffectRegistry.PARALYSIS.get())) + if (entity.hasEffect(EffectRegistry.PARALYSIS)) cir.setReturnValue(true); } @@ -50,12 +49,7 @@ protected void onEffectAdded(MobEffectInstance effect, Entity target, CallbackIn if (level.isClientSide()) return; - CompoundTag tag = new CompoundTag(); - - effect.save(tag); - - NetworkHandler.sendToClients(PacketDistributor.TRACKING_ENTITY.with(() -> entity), - new PacketSyncEntityEffects(entity.getId(), tag, PacketSyncEntityEffects.Action.ADD)); + NetworkHandler.sendToClientsTrackingEntity(new PacketSyncEntityEffects((CompoundTag) effect.save(), PacketSyncEntityEffects.Action.ADD, entity.getId()), entity); } @Inject(method = "onEffectUpdated", at = @At("TAIL")) @@ -66,12 +60,7 @@ protected void onEffectUpdated(MobEffectInstance effect, boolean forced, Entity if (level.isClientSide()) return; - CompoundTag tag = new CompoundTag(); - - effect.save(tag); - - NetworkHandler.sendToClients(PacketDistributor.TRACKING_ENTITY.with(() -> entity), - new PacketSyncEntityEffects(entity.getId(), tag, PacketSyncEntityEffects.Action.UPDATE)); + NetworkHandler.sendToClientsTrackingEntity(new PacketSyncEntityEffects((CompoundTag) effect.save(), PacketSyncEntityEffects.Action.UPDATE, entity.getId()), entity); } @Inject(method = "onEffectRemoved", at = @At("TAIL")) @@ -82,19 +71,14 @@ protected void onEffectRemoved(MobEffectInstance effect, CallbackInfo ci) { if (level.isClientSide()) return; - CompoundTag tag = new CompoundTag(); - - effect.save(tag); - - NetworkHandler.sendToClients(PacketDistributor.TRACKING_ENTITY.with(() -> entity), - new PacketSyncEntityEffects(entity.getId(), tag, PacketSyncEntityEffects.Action.REMOVE)); + NetworkHandler.sendToClientsTrackingEntity(new PacketSyncEntityEffects((CompoundTag) effect.save(), PacketSyncEntityEffects.Action.REMOVE, entity.getId()), entity); } @Inject(method = "canBeSeenByAnyone", at = @At("HEAD"), cancellable = true) protected void canBeSeenByAnyone(CallbackInfoReturnable cir) { LivingEntity entity = (LivingEntity) (Object) this; - if (entity.hasEffect(EffectRegistry.VANISHING.get())) + if (entity.hasEffect(EffectRegistry.VANISHING)) cir.setReturnValue(false); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/MouseHandlerMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/MouseHandlerMixin.java index 1e3259d0..b4bca251 100644 --- a/src/main/java/it/hurts/sskirillss/relics/mixin/MouseHandlerMixin.java +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/MouseHandlerMixin.java @@ -15,7 +15,7 @@ public class MouseHandlerMixin { public void onKeyPress(CallbackInfo ci) { Player player = Minecraft.getInstance().player; - if (player != null && player.hasEffect(EffectRegistry.STUN.get())) + if (player != null && player.hasEffect(EffectRegistry.STUN)) ci.cancel(); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/PiglinAiMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/PiglinAiMixin.java index 5d2b982b..ed319996 100644 --- a/src/main/java/it/hurts/sskirillss/relics/mixin/PiglinAiMixin.java +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/PiglinAiMixin.java @@ -37,11 +37,11 @@ private static void tweakBartering(Piglin piglin, boolean bool, CallbackInfo ci) ItemStack stack = EntityUtils.findEquippedCurio(player, ItemRegistry.BASTION_RING.get()); if (stack.getItem() instanceof IRelicItem relic) { - for (int i = 0; i < Math.round(relic.getAbilityValue(stack, "trade", "rolls")); i++) { + for (int i = 0; i < Math.round(relic.getStatValue(stack, "trade", "rolls")); i++) { if (piglin.getRandom().nextBoolean()) { PiglinAi.throwItems(piglin, getBarterResponseItems(piglin)); - relic.spreadExperience(player, stack, 3); + relic.spreadRelicExperience(player, stack, 3); } } diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/ScreenMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/ScreenMixin.java index 0c470296..a2a7fa05 100644 --- a/src/main/java/it/hurts/sskirillss/relics/mixin/ScreenMixin.java +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/ScreenMixin.java @@ -1,7 +1,7 @@ package it.hurts.sskirillss.relics.mixin; import it.hurts.sskirillss.relics.client.screen.base.ITickingWidget; -import it.hurts.sskirillss.relics.client.screen.description.data.base.ParticleData; +import it.hurts.sskirillss.relics.client.screen.description.general.particles.base.ParticleData; import it.hurts.sskirillss.relics.client.screen.utils.ParticleStorage; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.AbstractButton; diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/compat/sophisticatedbackpacks/FeedingUpgradeWrapperMixin.java b/src/main/java/it/hurts/sskirillss/relics/mixin/compat/sophisticatedbackpacks/FeedingUpgradeWrapperMixin.java new file mode 100644 index 00000000..23aec3cd --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/compat/sophisticatedbackpacks/FeedingUpgradeWrapperMixin.java @@ -0,0 +1,29 @@ +package it.hurts.sskirillss.relics.mixin.compat.sophisticatedbackpacks; + +import it.hurts.sskirillss.relics.items.relics.InfiniteHamItem; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.p3pp3rf1y.sophisticatedcore.upgrades.feeding.FeedingUpgradeWrapper; +import net.p3pp3rf1y.sophisticatedcore.util.InventoryHelper; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(FeedingUpgradeWrapper.class) +public class FeedingUpgradeWrapperMixin { + @Inject(method = "tick", at = @At("HEAD")) + public void tick(Entity entity, Level level, BlockPos pos, CallbackInfo ci) { + if (!(entity instanceof Player)) + return; + + InventoryHelper.iterate(((UpgradeWrapperBaseAccessor) this).getStorageWrapper().getInventoryForUpgradeProcessing(), (slot, stack) -> { + if (stack.getItem() instanceof InfiniteHamItem relic) + relic.inventoryTick(stack, level, entity, slot, false); + + return true; + }, () -> false, (result) -> false); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/mixin/compat/sophisticatedbackpacks/UpgradeWrapperBaseAccessor.java b/src/main/java/it/hurts/sskirillss/relics/mixin/compat/sophisticatedbackpacks/UpgradeWrapperBaseAccessor.java new file mode 100644 index 00000000..04c2c89a --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/mixin/compat/sophisticatedbackpacks/UpgradeWrapperBaseAccessor.java @@ -0,0 +1,12 @@ +package it.hurts.sskirillss.relics.mixin.compat.sophisticatedbackpacks; + +import net.p3pp3rf1y.sophisticatedcore.api.IStorageWrapper; +import net.p3pp3rf1y.sophisticatedcore.upgrades.UpgradeWrapperBase; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(UpgradeWrapperBase.class) +public interface UpgradeWrapperBaseAccessor { + @Accessor("storageWrapper") + IStorageWrapper getStorageWrapper(); +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/network/NetworkHandler.java b/src/main/java/it/hurts/sskirillss/relics/network/NetworkHandler.java index 96e9981a..31d33e93 100644 --- a/src/main/java/it/hurts/sskirillss/relics/network/NetworkHandler.java +++ b/src/main/java/it/hurts/sskirillss/relics/network/NetworkHandler.java @@ -3,78 +3,61 @@ import it.hurts.sskirillss.relics.network.packets.PacketItemActivation; import it.hurts.sskirillss.relics.network.packets.PacketPlayerMotion; import it.hurts.sskirillss.relics.network.packets.PacketSyncEntityEffects; +import it.hurts.sskirillss.relics.network.packets.sync.S2CEntityMotionPacket; import it.hurts.sskirillss.relics.network.packets.abilities.SpellCastPacket; import it.hurts.sskirillss.relics.network.packets.capability.CapabilitySyncPacket; -import it.hurts.sskirillss.relics.network.packets.leveling.PacketExperienceExchange; +import it.hurts.sskirillss.relics.network.packets.leveling.FixLevelingPoints; import it.hurts.sskirillss.relics.network.packets.leveling.PacketRelicTweak; +import it.hurts.sskirillss.relics.network.packets.lock.PacketAbilityUnlock; +import it.hurts.sskirillss.relics.network.packets.research.PacketManageLink; +import it.hurts.sskirillss.relics.network.packets.research.PacketResearchHint; +import it.hurts.sskirillss.relics.network.packets.sync.S2CEntityTargetPacket; import it.hurts.sskirillss.relics.utils.Reference; -import net.minecraft.resources.ResourceLocation; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; import net.minecraft.server.level.ServerPlayer; -import net.minecraftforge.network.NetworkDirection; -import net.minecraftforge.network.NetworkRegistry; -import net.minecraftforge.network.PacketDistributor; -import net.minecraftforge.network.simple.SimpleChannel; - +import net.minecraft.world.entity.Entity; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.network.PacketDistributor; +import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent; +import net.neoforged.neoforge.network.registration.PayloadRegistrar; + +@EventBusSubscriber(bus = EventBusSubscriber.Bus.MOD) public class NetworkHandler { - private static SimpleChannel INSTANCE; - private static int ID = 0; - - private static int nextID() { - return ID++; + @SubscribeEvent + public static void onRegisterPayloadHandler(final RegisterPayloadHandlersEvent event) { + final PayloadRegistrar registrar = event.registrar(Reference.MODID) + .versioned("1.0") + .optional(); + + registrar.playToClient(PacketPlayerMotion.TYPE, PacketPlayerMotion.STREAM_CODEC, PacketPlayerMotion::handle); + registrar.playToClient(PacketItemActivation.TYPE, PacketItemActivation.STREAM_CODEC, PacketItemActivation::handle); + registrar.playToServer(PacketRelicTweak.TYPE, PacketRelicTweak.STREAM_CODEC, PacketRelicTweak::handle); + registrar.playToClient(PacketSyncEntityEffects.TYPE, PacketSyncEntityEffects.STREAM_CODEC, PacketSyncEntityEffects::handle); + registrar.playToClient(CapabilitySyncPacket.TYPE, CapabilitySyncPacket.STREAM_CODEC, CapabilitySyncPacket::handle); + registrar.playToServer(SpellCastPacket.TYPE, SpellCastPacket.STREAM_CODEC, SpellCastPacket::handle); + registrar.playToClient(S2CEntityTargetPacket.TYPE, S2CEntityTargetPacket.STREAM_CODEC, S2CEntityTargetPacket::handle); + registrar.playToServer(PacketAbilityUnlock.TYPE, PacketAbilityUnlock.STREAM_CODEC, PacketAbilityUnlock::handle); + registrar.playToServer(PacketManageLink.TYPE, PacketManageLink.STREAM_CODEC, PacketManageLink::handle); + registrar.playToServer(PacketResearchHint.TYPE, PacketResearchHint.STREAM_CODEC, PacketResearchHint::handle); + registrar.playToServer(FixLevelingPoints.TYPE, FixLevelingPoints.STREAM_CODEC, FixLevelingPoints::handle); + + registrar.playToClient(S2CEntityMotionPacket.TYPE, S2CEntityMotionPacket.STREAM_CODEC, S2CEntityMotionPacket::handle); } - public static void register() { - INSTANCE = NetworkRegistry.newSimpleChannel(new ResourceLocation(Reference.MODID, "network"), - () -> "1.0", - s -> true, - s -> true); - - INSTANCE.messageBuilder(PacketPlayerMotion.class, nextID()) - .encoder(PacketPlayerMotion::toBytes) - .decoder(PacketPlayerMotion::new) - .consumerMainThread(PacketPlayerMotion::handle) - .add(); - INSTANCE.messageBuilder(PacketItemActivation.class, nextID()) - .encoder(PacketItemActivation::toBytes) - .decoder(PacketItemActivation::new) - .consumerMainThread(PacketItemActivation::handle) - .add(); - INSTANCE.messageBuilder(PacketRelicTweak.class, nextID()) - .encoder(PacketRelicTweak::toBytes) - .decoder(PacketRelicTweak::new) - .consumerMainThread(PacketRelicTweak::handle) - .add(); - INSTANCE.messageBuilder(PacketSyncEntityEffects.class, nextID()) - .encoder(PacketSyncEntityEffects::toBytes) - .decoder(PacketSyncEntityEffects::new) - .consumerMainThread(PacketSyncEntityEffects::handle) - .add(); - INSTANCE.messageBuilder(CapabilitySyncPacket.class, nextID()) - .encoder(CapabilitySyncPacket::toBytes) - .decoder(CapabilitySyncPacket::new) - .consumerMainThread(CapabilitySyncPacket::handle) - .add(); - INSTANCE.messageBuilder(SpellCastPacket.class, nextID()) - .encoder(SpellCastPacket::toBytes) - .decoder(SpellCastPacket::new) - .consumerMainThread(SpellCastPacket::handle) - .add(); - INSTANCE.messageBuilder(PacketExperienceExchange.class, nextID()) - .encoder(PacketExperienceExchange::toBytes) - .decoder(PacketExperienceExchange::new) - .consumerMainThread(PacketExperienceExchange::handle) - .add(); + public static void sendToServer(MSG message) { + PacketDistributor.sendToServer(message); } - public static void sendToClient(Object packet, ServerPlayer player) { - INSTANCE.sendTo(packet, player.connection.connection, NetworkDirection.PLAY_TO_CLIENT); + public static void sendToClient(MSG message, ServerPlayer player) { + PacketDistributor.sendToPlayer(player, message); } - public static void sendToServer(Object packet) { - INSTANCE.sendToServer(packet); + public static void sendToClientsTrackingEntity(MSG message, Entity entity) { + PacketDistributor.sendToPlayersTrackingEntity(entity, message); } - public static void sendToClients(PacketDistributor.PacketTarget target, Object packet) { - INSTANCE.send(target, packet); + public static void sendToClientsTrackingEntityAndSelf(MSG message, Entity entity) { + PacketDistributor.sendToPlayersTrackingEntityAndSelf(entity, message); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/network/packets/PacketItemActivation.java b/src/main/java/it/hurts/sskirillss/relics/network/packets/PacketItemActivation.java index 210a6bc0..ffffdb56 100644 --- a/src/main/java/it/hurts/sskirillss/relics/network/packets/PacketItemActivation.java +++ b/src/main/java/it/hurts/sskirillss/relics/network/packets/PacketItemActivation.java @@ -1,29 +1,34 @@ package it.hurts.sskirillss.relics.network.packets; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.AllArgsConstructor; +import lombok.Data; import net.minecraft.client.Minecraft; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.network.NetworkEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; -import java.util.function.Supplier; - -public class PacketItemActivation { +@Data +@AllArgsConstructor +public class PacketItemActivation implements CustomPacketPayload { private final ItemStack stack; - public PacketItemActivation(FriendlyByteBuf buf) { - stack = buf.readItem(); - } + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "item_activation")); - public PacketItemActivation(ItemStack stack) { - this.stack = stack; - } + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ItemStack.STREAM_CODEC, PacketItemActivation::getStack, + PacketItemActivation::new + ); - public void toBytes(FriendlyByteBuf buf) { - buf.writeItem(stack); + @Override + public Type type() { + return TYPE; } - public boolean handle(Supplier ctx) { - ctx.get().enqueueWork(() -> Minecraft.getInstance().gameRenderer.displayItemActivation(stack)); - return true; + public void handle(IPayloadContext ctx) { + ctx.enqueueWork(() -> Minecraft.getInstance().gameRenderer.displayItemActivation(stack)); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/network/packets/PacketPlayerMotion.java b/src/main/java/it/hurts/sskirillss/relics/network/packets/PacketPlayerMotion.java index 700f0983..ea4240c0 100644 --- a/src/main/java/it/hurts/sskirillss/relics/network/packets/PacketPlayerMotion.java +++ b/src/main/java/it/hurts/sskirillss/relics/network/packets/PacketPlayerMotion.java @@ -1,41 +1,43 @@ package it.hurts.sskirillss.relics.network.packets; +import io.netty.buffer.ByteBuf; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.AllArgsConstructor; +import lombok.Data; import net.minecraft.client.Minecraft; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.network.NetworkEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; -import java.util.function.Supplier; - -public class PacketPlayerMotion { +@Data +@AllArgsConstructor +public class PacketPlayerMotion implements CustomPacketPayload { private final double motionX; private final double motionY; private final double motionZ; - public PacketPlayerMotion(FriendlyByteBuf buf) { - motionX = buf.readDouble(); - motionY = buf.readDouble(); - motionZ = buf.readDouble(); - } + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "player_motion")); - public PacketPlayerMotion(double motionX, double motionY, double motionZ) { - this.motionX = motionX; - this.motionY = motionY; - this.motionZ = motionZ; - } + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.DOUBLE, PacketPlayerMotion::getMotionX, + ByteBufCodecs.DOUBLE, PacketPlayerMotion::getMotionY, + ByteBufCodecs.DOUBLE, PacketPlayerMotion::getMotionZ, + PacketPlayerMotion::new + ); - public void toBytes(FriendlyByteBuf buf) { - buf.writeDouble(motionX); - buf.writeDouble(motionY); - buf.writeDouble(motionZ); + @Override + public Type type() { + return TYPE; } - public boolean handle(Supplier ctx) { - ctx.get().enqueueWork(() -> { + public void handle(IPayloadContext ctx) { + ctx.enqueueWork(() -> { Vec3 motion = new Vec3(this.motionX, this.motionY, this.motionZ); Minecraft.getInstance().player.setDeltaMovement(motion); }); - return true; } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/network/packets/PacketSyncEntityEffects.java b/src/main/java/it/hurts/sskirillss/relics/network/packets/PacketSyncEntityEffects.java index 084c11e2..1a275e45 100644 --- a/src/main/java/it/hurts/sskirillss/relics/network/packets/PacketSyncEntityEffects.java +++ b/src/main/java/it/hurts/sskirillss/relics/network/packets/PacketSyncEntityEffects.java @@ -1,40 +1,47 @@ package it.hurts.sskirillss.relics.network.packets; +import io.netty.buffer.ByteBuf; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.ByIdMap; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.entity.LivingEntity; -import net.minecraftforge.network.NetworkEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; -import java.util.function.Supplier; +import java.util.function.IntFunction; -public class PacketSyncEntityEffects { +@Data +@AllArgsConstructor +public class PacketSyncEntityEffects implements CustomPacketPayload { private final CompoundTag data; private final Action action; private final int entity; - public PacketSyncEntityEffects(FriendlyByteBuf buf) { - entity = buf.readInt(); - data = buf.readNbt(); - action = buf.readEnum(Action.class); - } + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "sync_entity_effect")); - public PacketSyncEntityEffects(int entity, CompoundTag data, Action action) { - this.entity = entity; - this.data = data; - this.action = action; - } + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.COMPOUND_TAG, PacketSyncEntityEffects::getData, + ByteBufCodecs.idMapper(Action.BY_ID, Action::getId), PacketSyncEntityEffects::getAction, + ByteBufCodecs.INT, PacketSyncEntityEffects::getEntity, + PacketSyncEntityEffects::new + ); - public void toBytes(FriendlyByteBuf buf) { - buf.writeInt(entity); - buf.writeNbt(data); - buf.writeEnum(action); + @Override + public CustomPacketPayload.Type type() { + return TYPE; } - public boolean handle(Supplier ctx) { - ctx.get().enqueueWork(() -> { + public void handle(IPayloadContext ctx) { + ctx.enqueueWork(() -> { Minecraft MC = Minecraft.getInstance(); ClientLevel level = MC.level; @@ -50,13 +57,17 @@ public boolean handle(Supplier ctx) { } } }); - - return true; } + @Getter + @AllArgsConstructor public enum Action { - ADD, - REMOVE, - UPDATE + ADD(0), + REMOVE(1), + UPDATE(2); + + public static final IntFunction BY_ID = ByIdMap.continuous(Action::getId, Action.values(), ByIdMap.OutOfBoundsStrategy.ZERO); + + private final int id; } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/network/packets/abilities/SpellCastPacket.java b/src/main/java/it/hurts/sskirillss/relics/network/packets/abilities/SpellCastPacket.java index 13fb427a..531bd353 100644 --- a/src/main/java/it/hurts/sskirillss/relics/network/packets/abilities/SpellCastPacket.java +++ b/src/main/java/it/hurts/sskirillss/relics/network/packets/abilities/SpellCastPacket.java @@ -1,56 +1,57 @@ package it.hurts.sskirillss.relics.network.packets.abilities; +import io.netty.buffer.ByteBuf; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastStage; import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.CastType; import it.hurts.sskirillss.relics.system.casts.abilities.AbilityReference; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.AllArgsConstructor; +import lombok.Data; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.network.NetworkEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; -import java.util.function.Supplier; - -public class SpellCastPacket { +@Data +@AllArgsConstructor +public class SpellCastPacket implements CustomPacketPayload { private final CastType type; private final CastStage stage; - private final AbilityReference ability; + private final CompoundTag ability; - public SpellCastPacket(FriendlyByteBuf buf) { - type = buf.readEnum(CastType.class); - stage = buf.readEnum(CastStage.class); - ability = new AbilityReference().deserializeNBT(buf.readNbt()); - } + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "spell_cast")); - public SpellCastPacket(CastType type, CastStage stage, AbilityReference ability) { - this.type = type; - this.stage = stage; - this.ability = ability; - } + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.idMapper(CastType.BY_ID, CastType::getId), SpellCastPacket::getType, + ByteBufCodecs.idMapper(CastStage.BY_ID, CastStage::getId), SpellCastPacket::getStage, + ByteBufCodecs.COMPOUND_TAG, SpellCastPacket::getAbility, + SpellCastPacket::new + ); - public void toBytes(FriendlyByteBuf buf) { - buf.writeEnum(type); - buf.writeEnum(stage); - buf.writeNbt(ability.serializeNBT()); + @Override + public CustomPacketPayload.Type type() { + return TYPE; } - public boolean handle(Supplier ctx) { - ctx.get().enqueueWork(() -> { - ServerPlayer player = ctx.get().getSender(); - - if (player == null) - return; - - ItemStack stack = ability.getSlot().gatherStack(player); + public void handle(IPayloadContext ctx) { + ctx.enqueueWork(() -> { + Player player = ctx.player(); + AbilityReference reference = new AbilityReference().deserializeNBT(ability); + ItemStack stack = reference.getSlot().gatherStack(player); if (!(stack.getItem() instanceof IRelicItem relic)) return; - if (!relic.canPlayerUseActiveAbility(player, stack, ability.getId())) { - if (relic.isAbilityTicking(stack, ability.getId())) { - relic.setAbilityTicking(stack, ability.getId(), false); + if (!relic.canPlayerUseAbility(player, stack, reference.getId())) { + if (relic.isAbilityTicking(stack, reference.getId())) { + relic.setAbilityTicking(stack, reference.getId(), false); - relic.castActiveAbility(stack, player, ability.getId(), type, CastStage.END); + relic.castActiveAbility(stack, player, reference.getId(), type, CastStage.END); } return; @@ -59,15 +60,13 @@ public boolean handle(Supplier ctx) { switch (type) { case CYCLICAL, TOGGLEABLE -> { switch (stage) { - case START -> relic.setAbilityTicking(stack, ability.getId(), true); - case END -> relic.setAbilityTicking(stack, ability.getId(), false); + case START -> relic.setAbilityTicking(stack, reference.getId(), true); + case END -> relic.setAbilityTicking(stack, reference.getId(), false); } } } - relic.castActiveAbility(stack, player, ability.getId(), type, stage); + relic.castActiveAbility(stack, player, reference.getId(), type, stage); }); - - return true; } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/network/packets/capability/CapabilitySyncPacket.java b/src/main/java/it/hurts/sskirillss/relics/network/packets/capability/CapabilitySyncPacket.java index f0d0c07c..00ec884f 100644 --- a/src/main/java/it/hurts/sskirillss/relics/network/packets/capability/CapabilitySyncPacket.java +++ b/src/main/java/it/hurts/sskirillss/relics/network/packets/capability/CapabilitySyncPacket.java @@ -1,33 +1,39 @@ package it.hurts.sskirillss.relics.network.packets.capability; -import it.hurts.sskirillss.relics.capability.utils.CapabilityUtils; +import io.netty.buffer.ByteBuf; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.AllArgsConstructor; +import lombok.Data; import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.network.NetworkEvent; - -import java.util.function.Supplier; - -public class CapabilitySyncPacket { +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +@Data +@AllArgsConstructor +public class CapabilitySyncPacket implements CustomPacketPayload { private final CompoundTag data; - public CapabilitySyncPacket(FriendlyByteBuf buf) { - data = buf.readNbt(); - } + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "capability_sync")); - public CapabilitySyncPacket(CompoundTag data) { - this.data = data; - } + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.COMPOUND_TAG, CapabilitySyncPacket::getData, + CapabilitySyncPacket::new + ); - public void toBytes(FriendlyByteBuf buf) { - buf.writeNbt(data); + @Override + public CustomPacketPayload.Type type() { + return TYPE; } - public boolean handle(Supplier ctx) { - ctx.get().enqueueWork(this::doSync); + public boolean handle(IPayloadContext ctx) { + ctx.enqueueWork(this::doSync); return true; } @@ -39,6 +45,6 @@ private void doSync() { if (player == null) return; - CapabilityUtils.getRelicsCapability(player).deserializeNBT(data); + // TODO: CapabilityUtils.getRelicsCapability(player).deserializeNBT(data); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/network/packets/leveling/FixLevelingPoints.java b/src/main/java/it/hurts/sskirillss/relics/network/packets/leveling/FixLevelingPoints.java new file mode 100644 index 00000000..0e639e82 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/network/packets/leveling/FixLevelingPoints.java @@ -0,0 +1,80 @@ +package it.hurts.sskirillss.relics.network.packets.leveling; + +import io.netty.buffer.ByteBuf; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.AllArgsConstructor; +import lombok.Data; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +@Data +@AllArgsConstructor +@Deprecated(forRemoval = true) +public class FixLevelingPoints implements CustomPacketPayload { + private final int container; + private final int slot; + + public static final Type TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "fix_leveling_points")); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.INT, FixLevelingPoints::getContainer, + ByteBufCodecs.INT, FixLevelingPoints::getSlot, + FixLevelingPoints::new + ); + + @Override + public Type type() { + return TYPE; + } + + public void handle(IPayloadContext ctx) { + ctx.enqueueWork(() -> { + Player player = ctx.player(); + + if (player.containerMenu.containerId != container) { + causeError(player); + + return; + } + + ItemStack stack = DescriptionUtils.gatherRelicStack(player, slot); + + if (!(stack.getItem() instanceof IRelicItem relic)) { + causeError(player); + + return; + } + + if (!relic.isSomethingWrongWithLevelingPoints(stack)) + return; + + relic.setRelicLevelingPoints(stack, relic.getRelicLevel(stack)); + + for (var data : relic.getAbilitiesData().getAbilities().values()) + relic.setAbilityLevel(stack, data.getId(), 0); + + try { + player.containerMenu.getSlot(slot).set(stack); + } catch (Exception e) { + e.printStackTrace(); + + causeError(player); + } + }); + } + + private static void causeError(Player player) { + player.displayClientMessage(Component.translatable("info.relics.researching.wrong_container").withStyle(ChatFormatting.RED), false); + + player.closeContainer(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/network/packets/leveling/PacketExperienceExchange.java b/src/main/java/it/hurts/sskirillss/relics/network/packets/leveling/PacketExperienceExchange.java deleted file mode 100644 index 6d58fc86..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/network/packets/leveling/PacketExperienceExchange.java +++ /dev/null @@ -1,85 +0,0 @@ -package it.hurts.sskirillss.relics.network.packets.leveling; - -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.tiles.ResearchingTableTile; -import it.hurts.sskirillss.relics.utils.EntityUtils; -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraftforge.network.NetworkEvent; - -import java.util.function.Supplier; - -public class PacketExperienceExchange { - private final BlockPos pos; - private final int amount; - - public PacketExperienceExchange(FriendlyByteBuf buf) { - pos = buf.readBlockPos(); - amount = buf.readInt(); - } - - public PacketExperienceExchange(BlockPos pos, int amount) { - this.pos = pos; - this.amount = amount; - } - - public void toBytes(FriendlyByteBuf buf) { - buf.writeBlockPos(pos); - buf.writeInt(amount); - } - - public boolean handle(Supplier ctx) { - ctx.get().enqueueWork(() -> { - ServerPlayer player = ctx.get().getSender(); - - if (player == null) - return; - - Level world = player.level(); - - if (!(world.getBlockEntity(pos) instanceof ResearchingTableTile tile)) - return; - - ItemStack stack = tile.getStack(); - - if (!(stack.getItem() instanceof IRelicItem relic) || relic.isMaxLevel(stack)) - return; - - int playerExperience = EntityUtils.getPlayerTotalExperience(player); - - if (playerExperience <= 0) - return; - - int exchanges = relic.getExchanges(stack); - int level = relic.getLevel(stack); - - int cost = 5; - - int toAdd = 0; - int toTake = 0; - - for (int i = 0; i < amount; i++) { - int oneCost = (int) (cost + (cost * ((exchanges + i) * 0.01F))); - - if (playerExperience < toTake + oneCost) - break; - - toAdd += (int) Math.ceil(relic.getExperienceBetweenLevels(stack, level, level + 1) / 100F); - toTake += oneCost; - - relic.addExchanges(stack, 1); - } - - player.giveExperiencePoints(-toTake); - - relic.addExperience(player, stack, toAdd); - - world.sendBlockUpdated(pos, world.getBlockState(pos), world.getBlockState(pos), 2); - }); - - return true; - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/network/packets/leveling/PacketRelicTweak.java b/src/main/java/it/hurts/sskirillss/relics/network/packets/leveling/PacketRelicTweak.java index 41f170f7..9d249e4a 100644 --- a/src/main/java/it/hurts/sskirillss/relics/network/packets/leveling/PacketRelicTweak.java +++ b/src/main/java/it/hurts/sskirillss/relics/network/packets/leveling/PacketRelicTweak.java @@ -1,100 +1,132 @@ package it.hurts.sskirillss.relics.network.packets.leveling; +import io.netty.buffer.ByteBuf; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; import it.hurts.sskirillss.relics.items.relics.base.data.leveling.AbilityData; -import it.hurts.sskirillss.relics.tiles.ResearchingTableTile; -import net.minecraft.core.BlockPos; -import net.minecraft.network.FriendlyByteBuf; -import net.minecraft.server.level.ServerPlayer; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.ByIdMap; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraftforge.network.NetworkEvent; +import net.neoforged.neoforge.network.handling.IPayloadContext; -import java.util.function.Supplier; +import java.util.function.IntFunction; -public class PacketRelicTweak { - private final BlockPos pos; +@Data +@AllArgsConstructor +public class PacketRelicTweak implements CustomPacketPayload { + private final int container; + private final int slot; private final String ability; private final Operation operation; + private final boolean withShift; - public PacketRelicTweak(FriendlyByteBuf buf) { - pos = buf.readBlockPos(); - ability = buf.readUtf(); - operation = buf.readEnum(Operation.class); + public PacketRelicTweak(int container, int slot, String ability, Operation operation) { + this(container, slot, ability, operation, false); } - public PacketRelicTweak(BlockPos pos, String ability, Operation operation) { - this.pos = pos; - this.ability = ability; - this.operation = operation; - } + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "relic_tweak")); - public void toBytes(FriendlyByteBuf buf) { - buf.writeBlockPos(pos); - buf.writeUtf(ability); - buf.writeEnum(operation); - } + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.INT, PacketRelicTweak::getContainer, + ByteBufCodecs.INT, PacketRelicTweak::getSlot, + ByteBufCodecs.STRING_UTF8, PacketRelicTweak::getAbility, + ByteBufCodecs.idMapper(Operation.BY_ID, Operation::getId), PacketRelicTweak::getOperation, + ByteBufCodecs.BOOL, PacketRelicTweak::isWithShift, + PacketRelicTweak::new + ); - public boolean handle(Supplier ctx) { - ctx.get().enqueueWork(() -> { - ServerPlayer player = ctx.get().getSender(); + @Override + public Type type() { + return TYPE; + } - if (player == null) - return; + public void handle(IPayloadContext ctx) { + ctx.enqueueWork(() -> { + Player player = ctx.player(); - Level world = player.level(); + if (player.containerMenu.containerId != container) { + causeError(player); - if (!(world.getBlockEntity(pos) instanceof ResearchingTableTile tile)) return; + } + + ItemStack stack = DescriptionUtils.gatherRelicStack(player, slot); - ItemStack stack = tile.getStack(); + if (!(stack.getItem() instanceof IRelicItem relic)) { + causeError(player); - if (!(stack.getItem() instanceof IRelicItem relic)) return; + } AbilityData entry = relic.getAbilityData(ability); if (entry == null) return; - switch (operation) { - case INCREASE -> { - if (relic.mayPlayerUpgrade(player, stack, ability)) { - player.giveExperiencePoints(-relic.getUpgradeRequiredExperience(stack, ability)); + // OMG why it works like this D: + if (!switch (operation) { + case UPGRADE -> { + boolean result = false; + + if (withShift) + for (; ; ) + if (relic.upgrade(player, stack, ability)) + result = true; + else break; + else + result = relic.upgrade(player, stack, ability); - relic.setAbilityPoints(stack, ability, relic.getAbilityPoints(stack, ability) + 1); - relic.addPoints(stack, -entry.getRequiredPoints()); - } + yield result; } case REROLL -> { - if (relic.mayPlayerReroll(player, stack, ability)) { - player.giveExperiencePoints(-relic.getRerollRequiredExperience(ability)); + boolean result = false; - relic.randomizeStats(stack, ability); - } - } - case RESET -> { - if (relic.mayPlayerReset(player, stack, ability)) { - player.giveExperiencePoints(-relic.getResetRequiredExperience(stack, ability)); + if (withShift) + while (relic.getAbilityQuality(stack, ability) != relic.getMaxQuality() && relic.reroll(player, stack, ability)) + result = true; + else + result = relic.reroll(player, stack, ability); - relic.addPoints(stack, relic.getAbilityPoints(stack, ability) * entry.getRequiredPoints()); - relic.setAbilityPoints(stack, ability, 0); - } + yield result; } - } + case RESET -> relic.reset(player, stack, ability); + }) return; - tile.setStack(stack); - tile.setChanged(); + try { + player.containerMenu.getSlot(slot).set(stack); + } catch (Exception e) { + e.printStackTrace(); - world.sendBlockUpdated(pos, world.getBlockState(pos), world.getBlockState(pos), 3); + causeError(player); + } }); + } - return true; + private static void causeError(Player player) { + player.displayClientMessage(Component.translatable("info.relics.researching.wrong_container").withStyle(ChatFormatting.RED), false); + + player.closeContainer(); } + @Getter + @AllArgsConstructor public enum Operation { - RESET, - INCREASE, - REROLL + RESET(0), + UPGRADE(1), + REROLL(2); + + public static final IntFunction BY_ID = ByIdMap.continuous(Operation::getId, Operation.values(), ByIdMap.OutOfBoundsStrategy.ZERO); + + private final int id; } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/network/packets/lock/PacketAbilityUnlock.java b/src/main/java/it/hurts/sskirillss/relics/network/packets/lock/PacketAbilityUnlock.java new file mode 100644 index 00000000..adcaf66d --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/network/packets/lock/PacketAbilityUnlock.java @@ -0,0 +1,77 @@ +package it.hurts.sskirillss.relics.network.packets.lock; + +import io.netty.buffer.ByteBuf; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.AllArgsConstructor; +import lombok.Data; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +@Data +@AllArgsConstructor +public class PacketAbilityUnlock implements CustomPacketPayload { + private final int container; + private final int slot; + private final String ability; + private final int unlocks; + + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "ability_unlock")); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.INT, PacketAbilityUnlock::getContainer, + ByteBufCodecs.INT, PacketAbilityUnlock::getSlot, + ByteBufCodecs.STRING_UTF8, PacketAbilityUnlock::getAbility, + ByteBufCodecs.INT, PacketAbilityUnlock::getUnlocks, + PacketAbilityUnlock::new + ); + + @Override + public Type type() { + return TYPE; + } + + public void handle(IPayloadContext ctx) { + ctx.enqueueWork(() -> { + Player player = ctx.player(); + + if (player.containerMenu.containerId != container) { + causeError(player); + + return; + } + + ItemStack stack = DescriptionUtils.gatherRelicStack(player, slot); + + if (!(stack.getItem() instanceof IRelicItem relic)) { + causeError(player); + + return; + } + + relic.setLockUnlocks(stack, ability, unlocks); + + try { + player.containerMenu.getSlot(slot).set(stack); + } catch (Exception e) { + e.printStackTrace(); + + causeError(player); + } + }); + } + + private static void causeError(Player player) { + player.displayClientMessage(Component.translatable("info.relics.researching.wrong_container").withStyle(ChatFormatting.RED), false); + + player.closeContainer(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/network/packets/research/PacketManageLink.java b/src/main/java/it/hurts/sskirillss/relics/network/packets/research/PacketManageLink.java new file mode 100644 index 00000000..fbab9809 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/network/packets/research/PacketManageLink.java @@ -0,0 +1,119 @@ +package it.hurts.sskirillss.relics.network.packets.research; + +import io.netty.buffer.ByteBuf; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.init.SoundRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import net.minecraft.ChatFormatting; +import net.minecraft.core.Holder; +import net.minecraft.network.chat.Component; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.network.protocol.game.ClientboundSoundPacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.ByIdMap; +import net.minecraft.util.RandomSource; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +import java.util.function.IntFunction; + +@Data +@AllArgsConstructor +public class PacketManageLink implements CustomPacketPayload { + private final int container; + private final int slot; + private final String ability; + private final Operation operation; + private final int from; + private final int to; + + public static final Type TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "manage_link")); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.INT, PacketManageLink::getContainer, + ByteBufCodecs.INT, PacketManageLink::getSlot, + ByteBufCodecs.STRING_UTF8, PacketManageLink::getAbility, + ByteBufCodecs.idMapper(Operation.BY_ID, Operation::getId), PacketManageLink::getOperation, + ByteBufCodecs.INT, PacketManageLink::getFrom, + ByteBufCodecs.INT, PacketManageLink::getTo, + PacketManageLink::new + ); + + @Override + public Type type() { + return TYPE; + } + + public void handle(IPayloadContext ctx) { + ctx.enqueueWork(() -> { + if (ctx.player().level().isClientSide()) + return; + + ServerPlayer player = (ServerPlayer) ctx.player(); + + if (player.containerMenu.containerId != container) { + causeError(player); + + return; + } + + ItemStack stack = DescriptionUtils.gatherRelicStack(player, slot); + + if (!(stack.getItem() instanceof IRelicItem relic)) { + causeError(player); + + return; + } + + RandomSource random = player.getRandom(); + + switch (operation) { + case ADD -> { + relic.addResearchLink(stack, ability, from, to); + + if (relic.testAbilityResearch(stack, ability)) { + relic.setAbilityResearched(stack, ability, true); + + player.connection.send(new ClientboundSoundPacket(Holder.direct(SoundRegistry.FINISH_RESEARCH.get()), SoundSource.PLAYERS, player.getX(), player.getY(), player.getZ(), 1F, 1F, random.nextLong())); + } else + player.connection.send(new ClientboundSoundPacket(Holder.direct(SoundRegistry.CONNECT_STARS.get()), SoundSource.PLAYERS, player.getX(), player.getY(), player.getZ(), 0.75F, 0.75F + random.nextFloat() * 0.5F, random.nextLong())); + } + case REMOVE -> relic.removeResearchLink(stack, ability, from, to); + } + + try { + player.containerMenu.getSlot(slot).set(stack); + } catch (Exception e) { + e.printStackTrace(); + + causeError(player); + } + }); + } + + private static void causeError(Player player) { + player.displayClientMessage(Component.translatable("info.relics.researching.wrong_container").withStyle(ChatFormatting.RED), false); + + player.closeContainer(); + } + + @Getter + @AllArgsConstructor + public enum Operation { + ADD(0), + REMOVE(1); + + public static final IntFunction BY_ID = ByIdMap.continuous(Operation::getId, Operation.values(), ByIdMap.OutOfBoundsStrategy.ZERO); + + private final int id; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/network/packets/research/PacketResearchHint.java b/src/main/java/it/hurts/sskirillss/relics/network/packets/research/PacketResearchHint.java new file mode 100644 index 00000000..f4aebcfb --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/network/packets/research/PacketResearchHint.java @@ -0,0 +1,141 @@ +package it.hurts.sskirillss.relics.network.packets.research; + +import com.google.common.collect.Multimap; +import io.netty.buffer.ByteBuf; +import it.hurts.sskirillss.relics.client.screen.description.misc.DescriptionUtils; +import it.hurts.sskirillss.relics.init.SoundRegistry; +import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.AllArgsConstructor; +import lombok.Data; +import net.minecraft.ChatFormatting; +import net.minecraft.core.Holder; +import net.minecraft.network.chat.Component; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.network.protocol.game.ClientboundSoundPacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.RandomSource; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +import java.util.Map; + +@Data +@AllArgsConstructor +public class PacketResearchHint implements CustomPacketPayload { + private final int container; + private final int slot; + private final String ability; + private final int amount; + + public static final Type TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "research_hint")); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.INT, PacketResearchHint::getContainer, + ByteBufCodecs.INT, PacketResearchHint::getSlot, + ByteBufCodecs.STRING_UTF8, PacketResearchHint::getAbility, + ByteBufCodecs.INT, PacketResearchHint::getAmount, + PacketResearchHint::new + ); + + @Override + public Type type() { + return TYPE; + } + + public void handle(IPayloadContext ctx) { + ctx.enqueueWork(() -> { + if (ctx.player().level().isClientSide()) + return; + + ServerPlayer player = (ServerPlayer) ctx.player(); + + if (player.containerMenu.containerId != container) { + causeError(player); + + return; + } + + ItemStack stack = DescriptionUtils.gatherRelicStack(player, slot); + + if (!(stack.getItem() instanceof IRelicItem relic)) { + causeError(player); + + return; + } + + RandomSource random = player.getRandom(); + + int cost = relic.getResearchHintCost(ability) * amount; + + if (player.experienceLevel < cost) + return; + + player.giveExperienceLevels(-cost); + + research(stack, amount); + + if (relic.testAbilityResearch(stack, ability)) { + relic.setAbilityResearched(stack, ability, true); + + player.connection.send(new ClientboundSoundPacket(Holder.direct(SoundRegistry.FINISH_RESEARCH.get()), SoundSource.PLAYERS, player.getX(), player.getY(), player.getZ(), 1F, 1F, random.nextLong())); + } else + player.connection.send(new ClientboundSoundPacket(Holder.direct(SoundRegistry.CONNECT_STARS.get()), SoundSource.PLAYERS, player.getX(), player.getY(), player.getZ(), 0.75F, 0.75F + random.nextFloat() * 0.5F, random.nextLong())); + + try { + player.containerMenu.getSlot(slot).set(stack); + } catch (Exception e) { + e.printStackTrace(); + + causeError(player); + } + }); + } + + public void research(ItemStack stack, int amount) { + if (!(stack.getItem() instanceof IRelicItem relic)) + return; + + Multimap pattern = relic.getResearchData(ability).getLinks(); + Multimap links = relic.getResearchLinks(stack, ability); + + int iteration = 0; + + for (Map.Entry entry : links.entries()) { + Integer start = entry.getKey(); + Integer end = entry.getValue(); + + if (!(pattern.containsEntry(start, end) || pattern.containsEntry(end, start))) { + relic.removeResearchLink(stack, ability, start, end); + + if (++iteration >= amount) + break; + } + } + + iteration = 0; + + for (Map.Entry entry : pattern.entries()) { + Integer start = entry.getKey(); + Integer end = entry.getValue(); + + if (!(links.containsEntry(start, end) || links.containsEntry(end, start))) { + relic.addResearchLink(stack, ability, start, end); + + if (++iteration >= amount) + break; + } + } + } + + private static void causeError(Player player) { + player.displayClientMessage(Component.translatable("info.relics.researching.wrong_container").withStyle(ChatFormatting.RED), false); + + player.closeContainer(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/network/packets/sync/S2CEntityMotionPacket.java b/src/main/java/it/hurts/sskirillss/relics/network/packets/sync/S2CEntityMotionPacket.java new file mode 100644 index 00000000..36acaade --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/network/packets/sync/S2CEntityMotionPacket.java @@ -0,0 +1,54 @@ +package it.hurts.sskirillss.relics.network.packets.sync; + +import io.netty.buffer.ByteBuf; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.AllArgsConstructor; +import lombok.Data; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.phys.Vec3; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +@Data +@AllArgsConstructor +public class S2CEntityMotionPacket implements CustomPacketPayload { + private final int id; + + private final double x; + private final double y; + private final double z; + + public S2CEntityMotionPacket(int id, Vec3 motion) { + this(id, motion.x(), motion.y(), motion.z()); + } + + public static final Type TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "entity_motion")); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.INT, S2CEntityMotionPacket::getId, + ByteBufCodecs.DOUBLE, S2CEntityMotionPacket::getX, + ByteBufCodecs.DOUBLE, S2CEntityMotionPacket::getY, + ByteBufCodecs.DOUBLE, S2CEntityMotionPacket::getZ, + S2CEntityMotionPacket::new + ); + + @Override + public Type type() { + return TYPE; + } + + public void handle(IPayloadContext ctx) { + ctx.enqueueWork(() -> { + var level = ctx.player().getCommandSenderWorld(); + + var entity = level.getEntity(id); + + if (entity == null) + return; + + entity.setDeltaMovement(x, y, z); + }); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/network/packets/sync/S2CEntityTargetPacket.java b/src/main/java/it/hurts/sskirillss/relics/network/packets/sync/S2CEntityTargetPacket.java new file mode 100644 index 00000000..fabe673c --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/network/packets/sync/S2CEntityTargetPacket.java @@ -0,0 +1,44 @@ +package it.hurts.sskirillss.relics.network.packets.sync; + +import io.netty.buffer.ByteBuf; +import it.hurts.sskirillss.relics.entities.misc.ITargetableEntity; +import it.hurts.sskirillss.relics.utils.Reference; +import lombok.AllArgsConstructor; +import lombok.Data; +import net.minecraft.client.Minecraft; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.level.Level; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +@Data +@AllArgsConstructor +public class S2CEntityTargetPacket implements CustomPacketPayload { + private final int sourceId; + private final int targetId; + + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(ResourceLocation.fromNamespaceAndPath(Reference.MODID, "entity_target")); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.INT, S2CEntityTargetPacket::getTargetId, + ByteBufCodecs.INT, S2CEntityTargetPacket::getSourceId, + S2CEntityTargetPacket::new + ); + + public void handle(IPayloadContext ctx) { + ctx.enqueueWork(() -> { + var level = ctx.player().getCommandSenderWorld(); + + if (level.getEntity(sourceId) instanceof ITargetableEntity source && level.getEntity(targetId) instanceof LivingEntity target) + source.setTarget(target); + }); + } + + @Override + public Type type() { + return TYPE; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/system/casts/handlers/CacheHandler.java b/src/main/java/it/hurts/sskirillss/relics/system/casts/handlers/CacheHandler.java index d7200747..6ede09e2 100644 --- a/src/main/java/it/hurts/sskirillss/relics/system/casts/handlers/CacheHandler.java +++ b/src/main/java/it/hurts/sskirillss/relics/system/casts/handlers/CacheHandler.java @@ -1,38 +1,38 @@ package it.hurts.sskirillss.relics.system.casts.handlers; +import it.hurts.sskirillss.relics.init.RegistryRegistry; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.RelicContainer; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.containers.base.RelicContainer; +import it.hurts.sskirillss.relics.items.relics.base.data.cast.misc.PredicateType; import it.hurts.sskirillss.relics.system.casts.abilities.AbilityCache; import it.hurts.sskirillss.relics.system.casts.abilities.AbilityReference; +import it.hurts.sskirillss.relics.utils.Reference; import net.minecraft.client.player.LocalPlayer; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.event.TickEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.LogicalSide; -import net.minecraftforge.fml.common.Mod; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.tick.PlayerTickEvent; import java.util.LinkedHashMap; import java.util.Map; import java.util.function.BiFunction; -@Mod.EventBusSubscriber +@EventBusSubscriber(modid = Reference.MODID, value = Dist.CLIENT) public class CacheHandler { public static final LinkedHashMap REFERENCES = new LinkedHashMap<>(); @SubscribeEvent - public static void onPlayerTick(TickEvent.PlayerTickEvent event) { - if (event.phase != TickEvent.Phase.END || event.side != LogicalSide.CLIENT) - return; - - Player player = event.player; + public static void onPlayerTick(PlayerTickEvent.Post event) { + Player player = event.getEntity(); if (!(player instanceof LocalPlayer)) return; LinkedHashMap references = new LinkedHashMap<>(); - for (RelicContainer source : RelicContainer.values()) { + for (RelicContainer source : RegistryRegistry.RELIC_CONTAINER_REGISTRY.entrySet().stream().map(Map.Entry::getValue).toList()) { for (AbilityReference reference : source.gatherAbilities().apply(player)) { ItemStack stack = reference.getSlot().gatherStack(player); @@ -43,8 +43,8 @@ public static void onPlayerTick(TickEvent.PlayerTickEvent event) { Map predicates = cache.getPredicates(); - for (Map.Entry> predicate : relic.getAbilityCastData(reference.getId()).getCastPredicates().entrySet()) - predicates.put(predicate.getKey(), predicate.getValue().apply(player, stack)); + for (Map.Entry> predicate : relic.getAbilityPredicates(reference.getId(), PredicateType.CAST).entrySet()) + predicates.put(predicate.getKey(), relic.testAbilityPredicate(player, stack, reference.getId(), predicate.getKey())); cache.setPredicates(predicates); diff --git a/src/main/java/it/hurts/sskirillss/relics/system/casts/handlers/HUDRenderHandler.java b/src/main/java/it/hurts/sskirillss/relics/system/casts/handlers/HUDRenderHandler.java index d10176f7..36bc2c0e 100644 --- a/src/main/java/it/hurts/sskirillss/relics/system/casts/handlers/HUDRenderHandler.java +++ b/src/main/java/it/hurts/sskirillss/relics/system/casts/handlers/HUDRenderHandler.java @@ -24,6 +24,7 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.ResourceLocation; @@ -31,15 +32,13 @@ import net.minecraft.util.Mth; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.client.event.InputEvent; -import net.minecraftforge.event.TickEvent; -import net.minecraftforge.eventbus.api.EventPriority; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.LogicalSide; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.registries.ForgeRegistries; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.bus.api.EventPriority; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.client.event.InputEvent; +import net.neoforged.neoforge.event.tick.PlayerTickEvent; import org.lwjgl.glfw.GLFW; import javax.annotation.Nullable; @@ -50,6 +49,21 @@ @OnlyIn(value = Dist.CLIENT) public class HUDRenderHandler { + public static final ResourceLocation CARD_FRAME_ACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/hud/abilities/card_frame_active.png"); + public static final ResourceLocation CARD_FRAME_INACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/hud/abilities/card_frame_inactive.png"); + + public static final ResourceLocation CARD_POINTER_ACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/hud/abilities/card_pointer_active.png"); + public static final ResourceLocation CARD_POINTER_INACTIVE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/hud/abilities/card_pointer_inactive.png"); + + public static final ResourceLocation ARROW_RIGHT = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/hud/abilities/arrow_right.png"); + public static final ResourceLocation ARROW_LEFT = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/hud/abilities/arrow_left.png"); + + public static final ResourceLocation ARROW_RIGHT_OUTLINE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/hud/abilities/arrow_right_outline.png"); + public static final ResourceLocation ARROW_LEFT_OUTLINE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/hud/abilities/arrow_left_outline.png"); + + public static final ResourceLocation STATE_TOGGLEABLE = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/hud/abilities/widgets/toggleable.png"); + public static final ResourceLocation STATE_CYCLICAL = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/hud/abilities/widgets/cyclical.png"); + private static final Minecraft MC = Minecraft.getInstance(); private static int selectedIndex = 0; @@ -81,23 +95,29 @@ public static void render(GuiGraphics guiGraphics, float partialTicks) { float shakeOffset = castShakeDelta > 0 ? ((castShakeDelta - partialTicks) * 0.25F) : 0; - drawAbility(guiGraphics, player, -2, x - 70 - shakeOffset, y, partialTicks); - drawAbility(guiGraphics, player, -1, x - 37 - shakeOffset, y, partialTicks); + drawAbility(guiGraphics, player, -2, x - 74 - shakeOffset, y, partialTicks); + drawAbility(guiGraphics, player, -1, x - 39 - shakeOffset, y, partialTicks); drawAbility(guiGraphics, player, 0, x, y, partialTicks); - drawAbility(guiGraphics, player, 1, x + 37 + shakeOffset, y, partialTicks); - drawAbility(guiGraphics, player, 2, x + 70 + shakeOffset, y, partialTicks); + drawAbility(guiGraphics, player, 1, x + 39 + shakeOffset, y, partialTicks); + drawAbility(guiGraphics, player, 2, x + 74 + shakeOffset, y, partialTicks); - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/hud/abilities/background.png")); + RenderSystem.setShaderTexture(0, ARROW_LEFT); + RenderUtils.renderTextureFromCenter(poseStack, x - 100 - shakeOffset, y + 2, 0, 0, 11, 30, 11, 30, 1F + (mouseDelta < 0 ? Math.abs(mouseDelta) * 0.01F : 0)); - RenderSystem.enableBlend(); + if (mouseDelta < 0) { + RenderSystem.setShaderTexture(0, ARROW_LEFT_OUTLINE); + + RenderUtils.renderTextureFromCenter(poseStack, x - 100 - shakeOffset, y + 2, 0, 0, 13, 32, 13, 32, 1F + Math.abs(mouseDelta) * 0.01F); + } + + RenderSystem.setShaderTexture(0, ARROW_RIGHT); + RenderUtils.renderTextureFromCenter(poseStack, x + 100 + shakeOffset, y + 2, 0, 0, 11, 30, 11, 30, 1F + (mouseDelta > 0 ? Math.abs(mouseDelta) * 0.01F : 0)); - RenderUtils.renderTextureFromCenter(poseStack, x - 96 - shakeOffset, y + 2, 43, 2, 256, 256, 11, 30, 1F + (mouseDelta < 0 ? Math.abs(mouseDelta) * 0.01F : 0)); - if (mouseDelta < 0) - RenderUtils.renderTextureFromCenter(poseStack, x - 96 - shakeOffset, y + 2, 72, 0, 256, 256, 15, 34, 1F + Math.abs(mouseDelta) * 0.01F); + if (mouseDelta > 0) { + RenderSystem.setShaderTexture(0, ARROW_RIGHT_OUTLINE); - RenderUtils.renderTextureFromCenter(poseStack, x + 96 + shakeOffset, y + 2, 31, 2, 256, 256, 11, 30, 1F + (mouseDelta > 0 ? Math.abs(mouseDelta) * 0.01F : 0)); - if (mouseDelta > 0) - RenderUtils.renderTextureFromCenter(poseStack, x + 96 + shakeOffset, y + 2, 56, 0, 256, 256, 15, 34, 1F + Math.abs(mouseDelta) * 0.01F); + RenderUtils.renderTextureFromCenter(poseStack, x + 100 + shakeOffset, y + 2, 0, 0, 13, 32, 13, 32, 1F + Math.abs(mouseDelta) * 0.01F); + } RenderSystem.disableBlend(); @@ -109,7 +129,7 @@ public static void render(GuiGraphics guiGraphics, float partialTicks) { ItemStack stack = selectedAbility.getSlot().gatherStack(player); - String registryName = ForgeRegistries.ITEMS.getKey(stack.getItem()).getPath(); + String registryName = BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath(); MutableComponent name = Component.translatable("tooltip.relics." + registryName + ".ability." + selectedAbility.getId()); @@ -130,7 +150,7 @@ public static void render(GuiGraphics guiGraphics, float partialTicks) { String predicateName = entry.getKey(); boolean isCompleted = entry.getValue(); - RenderSystem.setShaderTexture(0, isCompleted ? new ResourceLocation(Reference.MODID, "textures/gui/description/icons/completed.png") : new ResourceLocation(Reference.MODID, "textures/gui/description/icons/" + registryName + "/" + predicateName + ".png")); + RenderSystem.setShaderTexture(0, isCompleted ? ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/icons/completed.png") : ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/gui/description/icons/" + registryName + "/" + predicateName + ".png")); RenderUtils.renderTextureFromCenter(poseStack, x, y + yOff, 0, 0, 16, 16, 16, 16, 0.5F); @@ -162,9 +182,9 @@ private static void drawAbility(GuiGraphics guiGraphics, LocalPlayer player, int PoseStack poseStack = guiGraphics.pose(); - boolean isLocked = !relic.canPlayerUseActiveAbility(player, stack, ability.getId()); + boolean isLocked = !relic.canPlayerUseAbility(player, stack, ability.getId()); - ResourceLocation card = new ResourceLocation(Reference.MODID, "textures/gui/description/cards/" + ForgeRegistries.ITEMS.getKey(stack.getItem()).getPath() + "/" + relic.getAbilityData(ability.getId()).getIcon().apply(player, stack, ability.getId()) + ".png"); + ResourceLocation card = ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/abilities/" + BuiltInRegistries.ITEM.getKey(stack.getItem()).getPath() + "/" + relic.getAbilityData(ability.getId()).getIcon().apply(player, stack, ability.getId()) + ".png"); RenderSystem.setShaderTexture(0, card); @@ -175,9 +195,9 @@ private static void drawAbility(GuiGraphics guiGraphics, LocalPlayer player, int int width = 20; int height = 29; - float scale = (float) ((1F + Mth.clamp(Math.pow(13.5F, -Math.abs(realIndex)), 0F, 0.2F)) + (realIndex == 0 ? (Math.sin((player.tickCount + partialTicks) * 0.1F) * 0.05F + (castShakeDelta > 0 ? ((castShakeDelta - partialTicks) * 0.02F) : 0F)) : 0F)); + float scale = (float) ((1F + Mth.clamp(Math.pow(15F, -Math.abs(realIndex)), 0F, 0.2F)) + (realIndex == 0 ? (Math.sin((player.tickCount + partialTicks) * 0.1F) * 0.05F + (castShakeDelta > 0 ? ((castShakeDelta - partialTicks) * 0.02F) : 0F)) : 0F)); - RenderUtils.renderTextureFromCenter(poseStack, x - scale, y - scale + 2, width, height, scale + 0.025F); + RenderUtils.renderTextureFromCenter(poseStack, x - scale + 1, y - scale + 2, width, height, scale + 0.025F); int cooldown = relic.getAbilityCooldown(stack, ability.getId()); int cap = relic.getAbilityCooldownCap(stack, ability.getId()); @@ -196,33 +216,34 @@ private static void drawAbility(GuiGraphics guiGraphics, LocalPlayer player, int RenderSystem.setShaderColor(1F, 1F, 1F, 1F); } - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/hud/abilities/background.png")); + RenderSystem.setShaderTexture(0, isLocked ? CARD_FRAME_INACTIVE : CARD_FRAME_ACTIVE); - RenderUtils.renderTextureFromCenter(poseStack, x, y, 0, isLocked ? 43 : 0, 256, 256, 30, 42, scale); + RenderUtils.renderTextureFromCenter(poseStack, x, y + 1, 0, 0, 30, 41, 30, 41, scale); if (relic.isAbilityTicking(stack, ability.getId())) { CastType type = relic.getAbilityData(ability.getId()).getCastData().getType(); if (type == CastType.TOGGLEABLE) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/hud/abilities/widgets/toggleable.png")); + RenderSystem.setShaderTexture(0, STATE_TOGGLEABLE); RenderSystem.enableBlend(); - RenderUtils.renderAnimatedTextureFromCenter(poseStack, x - 0.5F, y - 0.5F, 31, 473, 31, 43, scale, AnimationData.builder() + RenderUtils.renderAnimatedTextureFromCenter(poseStack, x, y + 1, 34, 630, 34, 45, scale, AnimationData.builder() .frame(0, 1).frame(1, 1).frame(2, 1) .frame(3, 1).frame(4, 1).frame(5, 1) .frame(6, 1).frame(7, 1).frame(8, 1) - .frame(9, 1).frame(10, 1)); + .frame(9, 1).frame(10, 1).frame(11, 1) + .frame(12, 1).frame(13, 1)); RenderSystem.disableBlend(); } else { - RenderSystem.setShaderColor(1F, 1F, 1F, (float) ((Math.sin(player.tickCount * 0.25F) * 0.25F) + 0.75F)); + RenderSystem.setShaderColor(1F, 1F, 1F, (float) ((Math.sin(player.tickCount * 0.5F) * 0.25F) + 0.75F)); RenderSystem.enableBlend(); - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/hud/abilities/widgets/cyclical.png")); + RenderSystem.setShaderTexture(0, STATE_CYCLICAL); - RenderUtils.renderTextureFromCenter(poseStack, x - scale / 2F, y - scale / 2F, 31, 43, scale); + RenderUtils.renderTextureFromCenter(poseStack, x - 0.5F, y + 1, 33, 45, scale); RenderSystem.disableBlend(); @@ -231,22 +252,23 @@ private static void drawAbility(GuiGraphics guiGraphics, LocalPlayer player, int } if (realIndex == 0) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/hud/abilities/background.png")); + RenderSystem.setShaderTexture(0, isLocked ? CARD_POINTER_INACTIVE : CARD_POINTER_ACTIVE); - RenderUtils.renderTextureFromCenter(poseStack, x - 1, y - 21, isLocked ? 38 : 31, 33, 256, 256, 6, 11, scale); + RenderUtils.renderTextureFromCenter(poseStack, x, y - 20, 0, 0, 6, 11, 6, 11, scale); } if (cooldown > 0) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/hud/abilities/widgets/icons/cooldown.png")); + RenderSystem.setShaderTexture(0, ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/hud/abilities/widgets/icons/cooldown.png")); RenderSystem.enableBlend(); - drawAbilityStatusIcon(cache, guiGraphics, x - scale, y - scale, 20, 300, scale - 0.1F, AnimationData.builder() + drawAbilityStatusIcon(cache, guiGraphics, x - scale, y - scale, 22, 352, scale - 0.1F, AnimationData.builder() .frame(0, 2).frame(1, 2).frame(2, 2) .frame(3, 2).frame(4, 2).frame(5, 2) .frame(6, 2).frame(7, 2).frame(8, 2) - .frame(9, 2).frame(10, 8).frame(11, 2) - .frame(12, 2).frame(13, 2).frame(14, 2), + .frame(9, 1).frame(10, 1).frame(11, 1) + .frame(12, 1).frame(13, 1).frame(14, 1) + .frame(15, 1), cap - cooldown, partialTicks); RenderSystem.disableBlend(); @@ -267,11 +289,14 @@ private static void drawAbility(GuiGraphics guiGraphics, LocalPlayer player, int int failedPredicates = infoEntries.size() - successPredicates; if (failedPredicates > 0) { - RenderSystem.setShaderTexture(0, new ResourceLocation(Reference.MODID, "textures/hud/abilities/widgets/icons/locked.png")); + RenderSystem.setShaderTexture(0, ResourceLocation.fromNamespaceAndPath(Reference.MODID, "textures/hud/abilities/widgets/icons/locked.png")); RenderSystem.enableBlend(); - drawAbilityStatusIcon(cache, guiGraphics, x - scale, y - scale, 20, 20, scale - 0.1F, null, player.tickCount, partialTicks); + drawAbilityStatusIcon(cache, guiGraphics, x - scale, y - scale, 20, 80, scale - 0.1F, AnimationData.builder() + .frame(0, 20).frame(1, 2).frame(2, 2) + .frame(3, 2).frame(2, 2).frame(1, 2), + player.tickCount, partialTicks); RenderSystem.disableBlend(); @@ -282,9 +307,9 @@ private static void drawAbility(GuiGraphics guiGraphics, LocalPlayer player, int if (!iconDescription.isEmpty()) { poseStack.scale(0.5F, 0.5F, 0.5F); - guiGraphics.drawString(MC.font, iconDescription, (x - 1) * 2F - (MC.font.width(iconDescription) / 2F), (y - 6 + scale * 15) * 2F, 0xFFFFFF, true); + MutableComponent descriptionComponent = Component.literal(iconDescription).withStyle(ChatFormatting.BOLD); - poseStack.scale(2F, 2F, 2F); + guiGraphics.drawString(MC.font, descriptionComponent, (int) (x * 2F - (MC.font.width(descriptionComponent) / 2F)), (int) ((y - 6 + scale * 15) * 2F), 0xFFFFFF, true); } poseStack.popPose(); @@ -295,7 +320,7 @@ private static void drawAbilityStatusIcon(AbilityCache cache, GuiGraphics guiGra poseStack.pushPose(); - poseStack.translate(x, y, 0); + poseStack.translate(x + 1, y, 0); if (cache.getIconShakeDelta() != 0) { float color = cache.getIconShakeDelta() * 0.04F; @@ -349,35 +374,32 @@ private static void applyDelta(int delta) { selectedIndex = sum > max ? sum - max - 1 : sum < 0 ? max : sum; } - @Mod.EventBusSubscriber(value = Dist.CLIENT) + @EventBusSubscriber(value = Dist.CLIENT) public static class GeneralEvents { @SubscribeEvent(priority = EventPriority.HIGHEST) public static void onMouseScroll(InputEvent.MouseScrollingEvent event) { - if (!HotkeyRegistry.ABILITY_LIST.isDown() || REFERENCES.isEmpty()) + if (!HotkeyRegistry.ACTIVE_ABILITIES_LIST.isDown() || REFERENCES.isEmpty()) return; int current = selectedIndex; - applyDelta(event.getScrollDelta() > 0 ? -1 : 1); + applyDelta(event.getScrollDeltaY() > 0 ? -1 : 1); if (current != selectedIndex) { - mouseDelta = event.getScrollDelta() > 0 ? -10 : 10; + mouseDelta = event.getScrollDeltaY() > 0 ? -10 : 10; LocalPlayer player = Minecraft.getInstance().player; if (player != null) - player.playSound(SoundEvents.UI_BUTTON_CLICK.get(), 0.5F, 1.5F + player.getRandom().nextFloat() * 0.25F); + player.playSound(SoundEvents.UI_BUTTON_CLICK.value(), 0.5F, 1.5F + player.getRandom().nextFloat() * 0.25F); } event.setCanceled(true); } @SubscribeEvent - public static void onPlayerTick(TickEvent.PlayerTickEvent event) { - if (event.side != LogicalSide.CLIENT || event.phase != TickEvent.Phase.END) - return; - - Player player = event.player; + public static void onPlayerTick(PlayerTickEvent.Post event) { + Player player = event.getEntity(); if (!(player instanceof LocalPlayer)) return; @@ -390,13 +412,13 @@ public static void onPlayerTick(TickEvent.PlayerTickEvent event) { else if (mouseDelta < 0) mouseDelta++; - if (HotkeyRegistry.ABILITY_LIST.isDown()) { + if (HotkeyRegistry.ACTIVE_ABILITIES_LIST.isDown()) { AbilityReference ability = getAbilityByIndex(selectedIndex); if (ability != null) { ItemStack stack = ability.getSlot().gatherStack(player); - if (stack.getItem() instanceof IRelicItem relic && relic.getAbilityData(ability.getId()) != null && relic.canPlayerUseActiveAbility(player, stack, ability.getId())) + if (stack.getItem() instanceof IRelicItem relic && relic.getAbilityData(ability.getId()) != null && relic.canPlayerUseAbility(player, stack, ability.getId())) relic.tickActiveAbilitySelection(stack, player, ability.getId()); } @@ -419,7 +441,7 @@ else if (mouseDelta < 0) } } - @Mod.EventBusSubscriber(value = Dist.CLIENT) + @EventBusSubscriber(value = Dist.CLIENT) public static class CastEvents { @SubscribeEvent public static void onKeyPressed(InputEvent.MouseButton.Pre event) { @@ -448,7 +470,7 @@ public static void onKeyPressed(InputEvent.MouseButton.Pre event) { if (!(stack.getItem() instanceof IRelicItem relic)) return; - if (!relic.canPlayerUseActiveAbility(player, stack, ability.getId())) { + if (!relic.canPlayerUseAbility(player, stack, ability.getId())) { int delta = cache.getIconShakeDelta(); cache.setIconShakeDelta(Math.min(20, delta + (delta > 0 ? 5 : 15))); @@ -469,26 +491,26 @@ public static void onKeyPressed(InputEvent.MouseButton.Pre event) { switch (type) { case INSTANTANEOUS -> { - NetworkHandler.sendToServer(new SpellCastPacket(CastType.INSTANTANEOUS, CastStage.END, ability)); + NetworkHandler.sendToServer(new SpellCastPacket(CastType.INSTANTANEOUS, CastStage.END, ability.serializeNBT())); relic.castActiveAbility(stack, player, ability.getId(), type, CastStage.END); } case CYCLICAL -> { - NetworkHandler.sendToServer(new SpellCastPacket(CastType.CYCLICAL, CastStage.START, ability)); + NetworkHandler.sendToServer(new SpellCastPacket(CastType.CYCLICAL, CastStage.START, ability.serializeNBT())); relic.castActiveAbility(stack, player, ability.getId(), type, CastStage.START); } case INTERRUPTIBLE -> { CastStage stage = isTicking ? CastStage.END : CastStage.START; - NetworkHandler.sendToServer(new SpellCastPacket(CastType.INTERRUPTIBLE, stage, ability)); + NetworkHandler.sendToServer(new SpellCastPacket(CastType.INTERRUPTIBLE, stage, ability.serializeNBT())); relic.castActiveAbility(stack, player, ability.getId(), type, stage); } case TOGGLEABLE -> { CastStage stage = isTicking ? CastStage.END : CastStage.START; - NetworkHandler.sendToServer(new SpellCastPacket(CastType.TOGGLEABLE, stage, ability)); + NetworkHandler.sendToServer(new SpellCastPacket(CastType.TOGGLEABLE, stage, ability.serializeNBT())); relic.castActiveAbility(stack, player, ability.getId(), type, stage); } @@ -500,13 +522,10 @@ public static void onKeyPressed(InputEvent.MouseButton.Pre event) { } @SubscribeEvent - public static void onPlayerTick(TickEvent.PlayerTickEvent event) { - if (event.side != LogicalSide.CLIENT || event.phase != TickEvent.Phase.END) - return; + public static void onPlayerTick(PlayerTickEvent.Post event) { + Player player = event.getEntity(); - Player player = event.player; - - if (player == null) + if (!(player instanceof LocalPlayer)) return; AbilityReference ability = getAbilityByIndex(selectedIndex); @@ -516,7 +535,7 @@ public static void onPlayerTick(TickEvent.PlayerTickEvent event) { ItemStack stack = ability.getSlot().gatherStack(player); - if (!(stack.getItem() instanceof IRelicItem relic)) + if (!(stack.getItem() instanceof IRelicItem relic) || !relic.getAbilitiesData().getAbilities().containsKey(ability.getId())) return; boolean isTicking = relic.isAbilityTicking(stack, ability.getId()); @@ -533,11 +552,11 @@ public static void onPlayerTick(TickEvent.PlayerTickEvent event) { case CYCLICAL -> { if (isTicking) { if (isCasting) { - NetworkHandler.sendToServer(new SpellCastPacket(CastType.CYCLICAL, CastStage.TICK, ability)); + NetworkHandler.sendToServer(new SpellCastPacket(CastType.CYCLICAL, CastStage.TICK, ability.serializeNBT())); relic.castActiveAbility(stack, player, ability.getId(), type, CastStage.TICK); } else { - NetworkHandler.sendToServer(new SpellCastPacket(CastType.CYCLICAL, CastStage.END, ability)); + NetworkHandler.sendToServer(new SpellCastPacket(CastType.CYCLICAL, CastStage.END, ability.serializeNBT())); relic.castActiveAbility(stack, player, ability.getId(), type, CastStage.END); } @@ -545,14 +564,14 @@ public static void onPlayerTick(TickEvent.PlayerTickEvent event) { } case INTERRUPTIBLE -> { if (isTicking) { - NetworkHandler.sendToServer(new SpellCastPacket(CastType.INTERRUPTIBLE, CastStage.TICK, ability)); + NetworkHandler.sendToServer(new SpellCastPacket(CastType.INTERRUPTIBLE, CastStage.TICK, ability.serializeNBT())); relic.castActiveAbility(stack, player, ability.getId(), type, CastStage.TICK); } } case TOGGLEABLE -> { if (isTicking) { - NetworkHandler.sendToServer(new SpellCastPacket(CastType.TOGGLEABLE, CastStage.TICK, ability)); + NetworkHandler.sendToServer(new SpellCastPacket(CastType.TOGGLEABLE, CastStage.TICK, ability.serializeNBT())); relic.castActiveAbility(stack, player, ability.getId(), type, CastStage.TICK); } diff --git a/src/main/java/it/hurts/sskirillss/relics/system/casts/slots/CurioSlotReference.java b/src/main/java/it/hurts/sskirillss/relics/system/casts/slots/CurioSlotReference.java index 1ac52d58..be88d36e 100644 --- a/src/main/java/it/hurts/sskirillss/relics/system/casts/slots/CurioSlotReference.java +++ b/src/main/java/it/hurts/sskirillss/relics/system/casts/slots/CurioSlotReference.java @@ -20,7 +20,7 @@ public class CurioSlotReference extends SlotReference { @Override public ItemStack gatherStack(Player player) { - return CuriosApi.getCuriosInventory(player).resolve().map(itemHandler -> { + return CuriosApi.getCuriosInventory(player).map(itemHandler -> { IDynamicStackHandler stackHandler = itemHandler.getCurios().get(getType()).getStacks(); int index = getIndex(); diff --git a/src/main/java/it/hurts/sskirillss/relics/tiles/ResearchingTableTile.java b/src/main/java/it/hurts/sskirillss/relics/tiles/ResearchingTableTile.java index fdb9f302..9b72cbd7 100644 --- a/src/main/java/it/hurts/sskirillss/relics/tiles/ResearchingTableTile.java +++ b/src/main/java/it/hurts/sskirillss/relics/tiles/ResearchingTableTile.java @@ -1,31 +1,18 @@ package it.hurts.sskirillss.relics.tiles; -import com.mojang.blaze3d.platform.Window; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; import it.hurts.sskirillss.relics.init.TileRegistry; -import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; -import it.hurts.sskirillss.relics.tiles.base.IHasHUDInfo; -import it.hurts.sskirillss.relics.tiles.base.TileBase; -import it.hurts.sskirillss.relics.utils.Reference; import lombok.Getter; import lombok.Setter; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.player.LocalPlayer; -import net.minecraft.client.renderer.texture.TextureManager; import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.Connection; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; -import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -public class ResearchingTableTile extends TileBase implements IHasHUDInfo { +public class ResearchingTableTile extends BlockEntity { @Getter @Setter private ItemStack stack = ItemStack.EMPTY; @@ -44,30 +31,25 @@ public static void tick(Level level, BlockPos pos, BlockState state, Researching } @Override - public void load(CompoundTag compound) { - super.load(compound); + protected void loadAdditional(CompoundTag compound, HolderLookup.Provider provider) { + super.loadAdditional(compound, provider); - stack = ItemStack.of((CompoundTag) compound.get("stack")); + stack = ItemStack.parseOptional(provider, compound.getCompound("stack")); } @Override - protected void saveAdditional(CompoundTag compound) { - super.saveAdditional(compound); + protected void saveAdditional(CompoundTag compound, HolderLookup.Provider provider) { + super.saveAdditional(compound, provider); - if (stack != null) { - CompoundTag itemStack = new CompoundTag(); - - stack.save(itemStack); - - compound.put("stack", itemStack); - } + if (stack != null && !stack.isEmpty()) + compound.put("stack", stack.save(provider, new CompoundTag())); } @Override - public CompoundTag getUpdateTag() { - CompoundTag tag = new CompoundTag(); + public CompoundTag getUpdateTag(HolderLookup.Provider provider) { + CompoundTag tag = super.getUpdateTag(provider); - this.saveAdditional(tag); + this.saveAdditional(tag, provider); return tag; } @@ -76,73 +58,4 @@ public CompoundTag getUpdateTag() { public ClientboundBlockEntityDataPacket getUpdatePacket() { return ClientboundBlockEntityDataPacket.create(this); } - - @Override - public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) { - super.onDataPacket(net, pkt); - - this.load(pkt.getTag()); - } - - @Override - @OnlyIn(Dist.CLIENT) - public void renderHUDInfo(PoseStack poseStack, Window window) { - Minecraft MC = Minecraft.getInstance(); - LocalPlayer player = MC.player; - - GuiGraphics gui = new GuiGraphics(MC, MC.renderBuffers().bufferSource()); - - if (player == null) - return; - - TextureManager manager = MC.getTextureManager(); - - int scale = 2; - - if (!stack.isEmpty()) { - ResourceLocation texture = new ResourceLocation(Reference.MODID, "textures/hud/info/crouch_rmb.png"); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, texture); - - RenderSystem.enableBlend(); - - poseStack.pushPose(); - - int width = 99; - int height = 20; - - int x = window.getGuiScaledWidth() / 2 - width / 2 / scale; - int y = window.getGuiScaledHeight() / 2 + 10; - - manager.bindForSetup(texture); - gui.blit(texture, x, y, width / scale, height / scale, 0, 0, width, height, width, height); - - poseStack.popPose(); - - RenderSystem.disableBlend(); - } else if (player.getMainHandItem().getItem() instanceof IRelicItem) { - ResourceLocation texture = new ResourceLocation(Reference.MODID, "textures/hud/info/rmb.png"); - - RenderSystem.setShaderColor(1F, 1F, 1F, 1F); - RenderSystem.setShaderTexture(0, texture); - - RenderSystem.enableBlend(); - - poseStack.pushPose(); - - int width = 17; - int height = 20; - - int x = window.getGuiScaledWidth() / 2 - width / 2 / scale; - int y = window.getGuiScaledHeight() / 2 + 10; - - manager.bindForSetup(texture); - gui.blit(texture, x, y, width / scale, height / scale, 0, 0, width, height, width, height); - - poseStack.popPose(); - - RenderSystem.disableBlend(); - } - } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/tiles/base/TileBase.java b/src/main/java/it/hurts/sskirillss/relics/tiles/base/TileBase.java deleted file mode 100644 index 12518b0b..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/tiles/base/TileBase.java +++ /dev/null @@ -1,35 +0,0 @@ -package it.hurts.sskirillss.relics.tiles.base; - -import net.minecraft.core.BlockPos; -import net.minecraft.network.Connection; -import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityType; -import net.minecraft.world.level.block.state.BlockState; - -public abstract class TileBase extends BlockEntity { - public TileBase(BlockEntityType type, BlockPos pos, BlockState state) { - super(type, pos, state); - } - - public ClientboundBlockEntityDataPacket getUpdatePacket() { - return ClientboundBlockEntityDataPacket.create(this); - } - - public void onDataPacket(Connection net, ClientboundBlockEntityDataPacket pkt) { - if (pkt.getTag() != null) - load(pkt.getTag()); - } - - public double getX() { - return this.getBlockPos().getX(); - } - - public double getY() { - return this.getBlockPos().getY(); - } - - public double getZ() { - return this.getBlockPos().getZ(); - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/utils/Easing.java b/src/main/java/it/hurts/sskirillss/relics/utils/Easing.java new file mode 100644 index 00000000..935536a1 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/utils/Easing.java @@ -0,0 +1,156 @@ +package it.hurts.sskirillss.relics.utils; + +public class Easing { + public static float linear(float progress) { + return progress; + } + + public static float easeInSine(float progress) { + return (float) (1 - Math.cos((progress * Math.PI) / 2)); + } + + public static float easeOutSine(float progress) { + return (float) Math.sin((progress * Math.PI) / 2); + } + + public static float easeInOutSine(float progress) { + return (float) -(Math.cos(Math.PI * progress) - 1) / 2; + } + + public static float easeInQuad(float progress) { + return progress * progress; + } + + public static float easeOutQuad(float progress) { + return 1 - (1 - progress) * (1 - progress); + } + + public static float easeInOutQuad(float progress) { + return progress < 0.5 ? 2 * progress * progress : 1 - (float) Math.pow(-2 * progress + 2, 2) / 2; + } + + public static float easeInCubic(float progress) { + return progress * progress * progress; + } + + public static float easeOutCubic(float progress) { + return 1 - (float) Math.pow(1 - progress, 3); + } + + public static float easeInOutCubic(float progress) { + return progress < 0.5 ? 4 * progress * progress * progress : 1 - (float) Math.pow(-2 * progress + 2, 3) / 2; + } + + public static float easeInQuart(float progress) { + return progress * progress * progress * progress; + } + + public static float easeOutQuart(float progress) { + return 1 - (float) Math.pow(1 - progress, 4); + } + + public static float easeInOutQuart(float progress) { + return progress < 0.5 ? 8 * progress * progress * progress * progress : 1 - (float) Math.pow(-2 * progress + 2, 4) / 2; + } + + public static float easeInQuint(float progress) { + return progress * progress * progress * progress * progress; + } + + public static float easeOutQuint(float progress) { + return 1 - (float) Math.pow(1 - progress, 5); + } + + public static float easeInOutQuint(float progress) { + return progress < 0.5 ? 16 * progress * progress * progress * progress * progress : 1 - (float) Math.pow(-2 * progress + 2, 5) / 2; + } + + public static float easeInExpo(float progress) { + return progress == 0 ? 0 : (float) Math.pow(2, 10 * progress - 10); + } + + public static float easeOutExpo(float progress) { + return progress == 1 ? 1 : 1 - (float) Math.pow(2, -10 * progress); + } + + public static float easeInOutExpo(float progress) { + if (progress == 0) return 0; + if (progress == 1) return 1; + return progress < 0.5 ? (float) Math.pow(2, 20 * progress - 10) / 2 : (2 - (float) Math.pow(2, -20 * progress + 10)) / 2; + } + + public static float easeInCirc(float progress) { + return 1 - (float) Math.sqrt(1 - Math.pow(progress, 2)); + } + + public static float easeOutCirc(float progress) { + return (float) Math.sqrt(1 - Math.pow(progress - 1, 2)); + } + + public static float easeInOutCirc(float progress) { + return progress < 0.5 + ? (1 - (float) Math.sqrt(1 - Math.pow(2 * progress, 2))) / 2 + : ((float) Math.sqrt(1 - Math.pow(-2 * progress + 2, 2)) + 1) / 2; + } + + public static float easeInBack(float progress) { + final float c1 = 1.70158f; + final float c3 = c1 + 1; + return c3 * progress * progress * progress - c1 * progress * progress; + } + + public static float easeOutBack(float progress) { + final float c1 = 1.70158f; + final float c3 = c1 + 1; + return 1 + c3 * (float) Math.pow(progress - 1, 3) + c1 * (float) Math.pow(progress - 1, 2); + } + + public static float easeInOutBack(float progress) { + final float c1 = 1.70158f; + final float c2 = c1 * 1.525f; + return progress < 0.5 + ? (float) (Math.pow(2 * progress, 2) * ((c2 + 1) * 2 * progress - c2)) / 2 + : (float) (Math.pow(2 * progress - 2, 2) * ((c2 + 1) * (progress * 2 - 2) + c2) + 2) / 2; + } + + public static float easeInElastic(float progress) { + final float c4 = (2 * (float) Math.PI) / 3; + return progress == 0 ? 0 : progress == 1 ? 1 : -(float) Math.pow(2, 10 * progress - 10) * (float) Math.sin((progress * 10 - 10.75) * c4); + } + + public static float easeOutElastic(float progress) { + final float c4 = (2 * (float) Math.PI) / 3; + return progress == 0 ? 0 : progress == 1 ? 1 : (float) Math.pow(2, -10 * progress) * (float) Math.sin((progress * 10 - 0.75) * c4) + 1; + } + + public static float easeInOutElastic(float progress) { + final float c5 = (2 * (float) Math.PI) / 4.5F; + return progress == 0 ? 0 : progress == 1 ? 1 : progress < 0.5 + ? -(float) (Math.pow(2, 20 * progress - 10) * Math.sin((20 * progress - 11.125) * c5)) / 2 + : (float) (Math.pow(2, -20 * progress + 10) * Math.sin((20 * progress - 11.125) * c5)) / 2 + 1; + } + + public static float easeInBounce(float progress) { + return 1 - easeOutBounce(1 - progress); + } + + public static float easeOutBounce(float progress) { + final float n1 = 7.5625f; + final float d1 = 2.75f; + if (progress < 1 / d1) { + return n1 * progress * progress; + } else if (progress < 2 / d1) { + return n1 * (progress -= 1.5f / d1) * progress + 0.75f; + } else if (progress < 2.5 / d1) { + return n1 * (progress -= 2.25f / d1) * progress + 0.9375f; + } else { + return n1 * (progress -= 2.625f / d1) * progress + 0.984375f; + } + } + + public static float easeInOutBounce(float progress) { + return progress < 0.5 + ? (1 - easeOutBounce(1 - 2 * progress)) / 2 + : (1 + easeOutBounce(2 * progress - 1)) / 2; + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/utils/EntityUtils.java b/src/main/java/it/hurts/sskirillss/relics/utils/EntityUtils.java index 63124b6b..d59c6b57 100644 --- a/src/main/java/it/hurts/sskirillss/relics/utils/EntityUtils.java +++ b/src/main/java/it/hurts/sskirillss/relics/utils/EntityUtils.java @@ -2,14 +2,19 @@ import com.google.common.collect.Lists; import it.hurts.sskirillss.relics.items.relics.base.IRelicItem; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceLocation; import net.minecraft.util.RandomSource; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntitySelector; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.OwnableEntity; import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.Item; @@ -18,17 +23,17 @@ import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.EntityHitResult; import net.minecraft.world.phys.Vec3; -import net.minecraftforge.registries.ForgeRegistries; import org.apache.commons.lang3.tuple.ImmutableTriple; import top.theillusivec4.curios.api.CuriosApi; +import top.theillusivec4.curios.api.SlotResult; import javax.annotation.Nullable; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Optional; -import java.util.UUID; import java.util.function.Predicate; +import java.util.stream.Stream; public class EntityUtils { public static void moveTowardsPosition(Entity entity, Vec3 targetPos, double speed) { @@ -125,51 +130,41 @@ public static EntityHitResult rayTraceEntity(Entity shooter, Predicate attributeHolder, float value, AttributeModifier.Operation operation) { + Attribute attribute = attributeHolder.value(); - if (name.equals("")) - return; - - UUID uuid = UUID.nameUUIDFromBytes(name.getBytes(StandardCharsets.UTF_8)); - - AttributeInstance instance = entity.getAttribute(attribute); - AttributeModifier modifier = new AttributeModifier(uuid, name, value, operation); + ResourceLocation id = getAttributeId(stack, attribute); + AttributeInstance instance = entity.getAttribute(attributeHolder); - if (instance == null || instance.hasModifier(modifier)) + if (instance == null || instance.hasModifier(id)) return; - instance.addTransientModifier(modifier); + instance.addTransientModifier(new AttributeModifier(id, value, operation)); } - public static void removeAttribute(LivingEntity entity, ItemStack stack, Attribute attribute, AttributeModifier.Operation operation) { - String name = getAttributeName(stack, attribute); + public static void removeAttribute(LivingEntity entity, ItemStack stack, Holder attributeHolder, AttributeModifier.Operation operation) { + Attribute attribute = attributeHolder.value(); - if (name.equals("")) - return; - - UUID uuid = UUID.nameUUIDFromBytes(name.getBytes(StandardCharsets.UTF_8)); + ResourceLocation id = getAttributeId(stack, attribute); - AttributeInstance instance = entity.getAttribute(attribute); + AttributeInstance instance = entity.getAttribute(attributeHolder); if (instance == null) return; - AttributeModifier modifier = new AttributeModifier(uuid, name, instance.getValue(), operation); - - if (!instance.hasModifier(modifier)) + if (!instance.hasModifier(id)) return; - instance.removeModifier(modifier); + instance.removeModifier(new AttributeModifier(id, instance.getValue(), operation)); } - public static void resetAttribute(LivingEntity entity, ItemStack stack, Attribute attribute, float value, AttributeModifier.Operation operation) { - removeAttribute(entity, stack, attribute, operation); - applyAttribute(entity, stack, attribute, value, operation); + public static void resetAttribute(LivingEntity entity, ItemStack stack, Holder attributeHolder, float value, AttributeModifier.Operation operation) { + removeAttribute(entity, stack, attributeHolder, operation); + applyAttribute(entity, stack, attributeHolder, value, operation); } public static ItemStack findEquippedCurio(Entity entity, Item item) { @@ -184,6 +179,17 @@ public static ItemStack findEquippedCurio(Entity entity, Item item) { return optional.get().getRight(); } + public static List findEquippedCurios(Entity entity, Item item) { + if (!(entity instanceof Player player)) + return List.of(); + + return CuriosApi.getCuriosInventory(player) + .map(inventory -> inventory.findCurios(item).stream() + .map(SlotResult::stack) + .toList()) + .orElse(List.of()); + } + public static int getExperienceForLevel(int level) { return level >= 30 ? 112 + (level - 30) * 9 : level >= 15 ? 37 + (level - 15) * 5 : 7 + level * 2; } @@ -210,7 +216,8 @@ public static int getPlayerTotalExperience(Player player) { public static boolean isAlliedTo(@Nullable Entity source, @Nullable Entity target) { return (source == null || target == null) || (source.isAlliedTo(target) || target.isAlliedTo(source)) || (target.getUUID().equals(source.getUUID())) - || (target instanceof OwnableEntity ownable && ownable.getOwnerUUID() != null && ownable.getOwnerUUID().equals(source.getUUID())); + || ((target instanceof OwnableEntity ownableTarget && ownableTarget.getOwnerUUID() != null && ownableTarget.getOwnerUUID().equals(source.getUUID())) + || (source instanceof OwnableEntity ownableSource && ownableSource.getOwnerUUID() != null && ownableSource.getOwnerUUID().equals(target.getUUID()))); } public static boolean hurt(LivingEntity entity, DamageSource source, float amount) { @@ -248,4 +255,13 @@ public static List getEquippedRelics(LivingEntity entity) { return items; } + + public static Stream gatherPotentialTargets(Entity seeker, Class type, double radius) { + return seeker.getCommandSenderWorld().getEntitiesOfClass(type, seeker.getBoundingBox().inflate(radius)).stream() + .sorted(Comparator.comparing(entry -> entry.position().distanceTo(entry.position()))) + .filter(entry -> !(entry instanceof ArmorStand) + && !entry.isDeadOrDying() + && entry.hasLineOfSight(seeker) + && EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(seeker)); + } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/utils/MathUtils.java b/src/main/java/it/hurts/sskirillss/relics/utils/MathUtils.java index 1a065aa7..830ca57e 100644 --- a/src/main/java/it/hurts/sskirillss/relics/utils/MathUtils.java +++ b/src/main/java/it/hurts/sskirillss/relics/utils/MathUtils.java @@ -30,7 +30,7 @@ public static double randomBetween(Random random, double min, double max) { } public static int randomBetween(Random random, int min, int max) { - return random.nextInt() * (max - min) + min; + return (int) Math.round(randomBetween(random, (double) min, (double) max)); } public static double round(double value, int steps) { @@ -38,4 +38,22 @@ public static double round(double value, int steps) { return Math.round(value * multiplier) / multiplier; } + + @Deprecated(forRemoval = true) + public static int multicast(RandomSource random, double chance, double chanceMultiplier) { + return random.nextDouble() <= chance ? multicast(random, chance * chanceMultiplier, chanceMultiplier) + 1 : 0; + } + + public static int multicast(RandomSource random, double chance, int maxIterations) { + int count = 0; + + while (count < maxIterations && random.nextDouble() <= chance) + count++; + + return count; + } + + public static int multicast(RandomSource random, double chance) { + return multicast(random, chance, 100); + } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/utils/NBTUtils.java b/src/main/java/it/hurts/sskirillss/relics/utils/NBTUtils.java index 92d60e23..48466468 100644 --- a/src/main/java/it/hurts/sskirillss/relics/utils/NBTUtils.java +++ b/src/main/java/it/hurts/sskirillss/relics/utils/NBTUtils.java @@ -19,67 +19,71 @@ public class NBTUtils { public static void setBoolean(ItemStack stack, String tag, boolean value) { - stack.getOrCreateTag().putBoolean(tag, value); + getOrCreateTag(stack).putBoolean(tag, value); } public static void setInt(ItemStack stack, String tag, int value) { - stack.getOrCreateTag().putInt(tag, value); + getOrCreateTag(stack).putInt(tag, value); } public static void setLong(ItemStack stack, String tag, long value) { - stack.getOrCreateTag().putLong(tag, value); + getOrCreateTag(stack).putLong(tag, value); } public static void setFloat(ItemStack stack, String tag, float value) { - stack.getOrCreateTag().putFloat(tag, value); + getOrCreateTag(stack).putFloat(tag, value); } public static void setDouble(ItemStack stack, String tag, double value) { - stack.getOrCreateTag().putDouble(tag, value); + getOrCreateTag(stack).putDouble(tag, value); } public static void setString(ItemStack stack, String tag, String value) { - stack.getOrCreateTag().putString(tag, value); + getOrCreateTag(stack).putString(tag, value); } public static void setCompound(ItemStack stack, String tag, CompoundTag value) { - stack.getOrCreateTag().put(tag, value); + getOrCreateTag(stack).put(tag, value); } public static boolean getBoolean(ItemStack stack, String tag, boolean defaultValue) { - return safeCheck(stack, tag) ? stack.getTag().getBoolean(tag) : defaultValue; + return safeCheck(stack, tag) ? getOrCreateTag(stack).getBoolean(tag) : defaultValue; } public static int getInt(ItemStack stack, String tag, int defaultValue) { - return safeCheck(stack, tag) ? stack.getTag().getInt(tag) : defaultValue; + return safeCheck(stack, tag) ? getOrCreateTag(stack).getInt(tag) : defaultValue; } public static long getLong(ItemStack stack, String tag, long defaultValue) { - return safeCheck(stack, tag) ? stack.getTag().getLong(tag) : defaultValue; + return safeCheck(stack, tag) ? getOrCreateTag(stack).getLong(tag) : defaultValue; } public static float getFloat(ItemStack stack, String tag, float defaultValue) { - return safeCheck(stack, tag) ? stack.getTag().getFloat(tag) : defaultValue; + return safeCheck(stack, tag) ? getOrCreateTag(stack).getFloat(tag) : defaultValue; } public static double getDouble(ItemStack stack, String tag, double defaultValue) { - return safeCheck(stack, tag) ? stack.getTag().getDouble(tag) : defaultValue; + return safeCheck(stack, tag) ? getOrCreateTag(stack).getDouble(tag) : defaultValue; } public static String getString(ItemStack stack, String tag, String defaultValue) { - return safeCheck(stack, tag) ? stack.getTag().getString(tag) : defaultValue; + return safeCheck(stack, tag) ? getOrCreateTag(stack).getString(tag) : defaultValue; } public static CompoundTag getCompound(ItemStack stack, String tag, CompoundTag defaultValue) { - return safeCheck(stack, tag) ? stack.getTag().getCompound(tag) : defaultValue; + return safeCheck(stack, tag) ? getOrCreateTag(stack).getCompound(tag) : defaultValue; } - public static boolean safeCheck(ItemStack stack, String tag) { - return !stack.isEmpty() && stack.getTag() != null && stack.getTag().contains(tag); + public static CompoundTag getOrCreateTag(ItemStack stack) { + return new CompoundTag(); + } + + private static boolean safeCheck(ItemStack stack, String tag) { + return getOrCreateTag(stack).contains(tag); } public static void clearTag(ItemStack stack, String tag) { - stack.getOrCreateTag().remove(tag); + getOrCreateTag(stack).remove(tag); } public static String writePosition(Vec3 vec) { @@ -123,7 +127,7 @@ public static Pair parseBundledPosition(Level world, Compound @Nullable public static ServerLevel parseLevel(Level world, String value) { - return world.getServer().getLevel(ResourceKey.create(Registries.DIMENSION, new ResourceLocation(value))); + return world.getServer().getLevel(ResourceKey.create(Registries.DIMENSION, ResourceLocation.parse(value))); } private static final Gson LIST_SERIALIZER = new GsonBuilder() diff --git a/src/main/java/it/hurts/sskirillss/relics/utils/ParticleUtils.java b/src/main/java/it/hurts/sskirillss/relics/utils/ParticleUtils.java index b9ae1198..7cf20000 100644 --- a/src/main/java/it/hurts/sskirillss/relics/utils/ParticleUtils.java +++ b/src/main/java/it/hurts/sskirillss/relics/utils/ParticleUtils.java @@ -1,31 +1,30 @@ package it.hurts.sskirillss.relics.utils; -import it.hurts.sskirillss.octolib.particle.BasicColoredParticle; +import it.hurts.sskirillss.relics.client.particles.BasicColoredParticle; import net.minecraft.core.BlockPos; import net.minecraft.core.particles.ParticleOptions; import net.minecraft.util.Mth; +import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.LiquidBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.HitResult; import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; -import org.lwjgl.opengl.GL11; import java.awt.*; public class ParticleUtils { - public static BasicColoredParticle.Options constructSimpleSpark(Color color, float diameter, int lifetime, float scaleModifier) { + public static ParticleOptions constructSimpleSpark(Color color, float diameter, int lifetime, float scaleModifier) { return new BasicColoredParticle.Options(BasicColoredParticle.Constructor.builder() .color(color.getRGB()) .diameter(diameter) .lifetime(lifetime) .scaleModifier(scaleModifier) - .physical(true) - .blurred(false) - .blended(GL11.GL_SRC_ALPHA, GL11.GL_ONE) - .depthTest(true) + .physical(false) .roll(0.5F) .build()); } @@ -52,67 +51,69 @@ public static void createBall(ParticleOptions particle, Vec3 vec, Level world, i } } + @Deprecated(forRemoval = true) public static void createCyl(ParticleOptions particle, Vec3 center, Level level, double radius, float step) { - int offset = 16; + createCyl(particle, center, level, radius, step, false); + } - double len = (float) (2 * Math.PI * radius); - int num = (int) (len / step); + public static void createCyl(ParticleOptions particle, Vec3 center, Level level, double radius, float step, boolean spherical) { + int maxTries = 16; - for (int i = 0; i < num; i++) { - double angle = Math.toRadians(((360F / num) * i) + (360F * ((((len / step) - num) / num) / len))); + if (spherical) { + var result = level.clip(new ClipContext(center, center.add(0, -radius, 0), ClipContext.Block.COLLIDER, ClipContext.Fluid.ANY, CollisionContext.empty())); - double extraX = (radius * Math.sin(angle)) + center.x(); - double extraZ = (radius * Math.cos(angle)) + center.z(); - double extraY = center.y() + 0.5F; + if (result.getType() == HitResult.Type.MISS) + return; - boolean foundPos = false; + maxTries = (int) Math.ceil(radius * 2); - int tries; + radius -= result.getLocation().distanceTo(center); + } - for (tries = 0; tries < offset * 2; tries++) { - Vec3 vec = new Vec3(extraX, extraY, extraZ); - BlockPos pos = new BlockPos((int) vec.x, (int) vec.y, (int) vec.z); + int numPoints = (int) Math.ceil((2 * Math.PI * radius) / step); + double angleIncrement = (2 * Math.PI) / numPoints; - BlockState state = level.getBlockState(pos); - VoxelShape shape = state.getCollisionShape(level, pos); + for (int i = 0; i < numPoints; i++) { + double angle = i * angleIncrement; + double x = center.x() + radius * Math.cos(angle); + double z = center.z() + radius * Math.sin(angle); + double y = center.y(); - if (state.getBlock() instanceof LiquidBlock liquid) { - AABB aabb = new AABB(pos); + boolean foundSolid = false; + int tries; - aabb.inflate(-0.5); + for (tries = 0; tries < maxTries; tries++) { + BlockPos pos = new BlockPos(Mth.floor(x), Mth.floor(y), Mth.floor(z)); + BlockState state = level.getBlockState(pos); + VoxelShape shape = state.getCollisionShape(level, pos); + if (state.getBlock() instanceof LiquidBlock) shape = Shapes.block(); - } if (shape.isEmpty()) { - if (!foundPos) { - extraY -= 1; + if (!foundSolid) { + y -= 1; continue; - } + } else break; } else - foundPos = true; + foundSolid = true; - if (shape.isEmpty()) - break; + AABB bounds = shape.bounds(); - AABB aabb = shape.bounds(); - - if (!aabb.move(pos).contains(vec)) { - if (aabb.maxY >= 1F) { - extraY += 1; + if (!bounds.move(pos).contains(new Vec3(x, y, z))) { + if (bounds.maxY >= 1.0) { + y += 1; continue; - } - - break; + } else break; } - extraY += step; + y += step; } - if (tries < offset * 2) - level.addParticle(particle, extraX, extraY + 0.1F, extraZ, 0, 0, 0); + if (tries < maxTries) + level.addParticle(particle, x, y + 0.1, z, 0, 0, 0); } } diff --git a/src/main/java/it/hurts/sskirillss/relics/utils/RenderUtils.java b/src/main/java/it/hurts/sskirillss/relics/utils/RenderUtils.java index ae70b93c..89d8f931 100644 --- a/src/main/java/it/hurts/sskirillss/relics/utils/RenderUtils.java +++ b/src/main/java/it/hurts/sskirillss/relics/utils/RenderUtils.java @@ -2,21 +2,103 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.*; -import com.mojang.math.Axis; +import it.hurts.sskirillss.relics.client.screen.utils.ScreenUtils; +import it.hurts.sskirillss.relics.init.RelicsCoreShaders; import it.hurts.sskirillss.relics.utils.data.AnimationData; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.RenderType; +import net.minecraft.network.chat.MutableComponent; import net.minecraft.util.Mth; import org.apache.commons.lang3.tuple.Pair; import org.joml.Matrix4f; +import org.joml.Vector2f; -import java.awt.*; -import java.util.Random; +import java.util.List; public class RenderUtils { + public static void drawOutlinedText(GuiGraphics guiGraphics, MutableComponent text, float x, float y, int textColor, int outlineColor) { + Font font = Minecraft.getInstance().font; + + ScreenUtils.drawCenteredString(guiGraphics, font, text, x + 1, y, outlineColor, false); + ScreenUtils.drawCenteredString(guiGraphics, font, text, x - 1, y, outlineColor, false); + ScreenUtils.drawCenteredString(guiGraphics, font, text, x, y + 1, outlineColor, false); + ScreenUtils.drawCenteredString(guiGraphics, font, text, x, y - 1, outlineColor, false); + + ScreenUtils.drawCenteredString(guiGraphics, font, text, x, y, textColor, false); + } + + public static void renderRevealingPanel(PoseStack matrices, float x, float y, float sizeX, float sizeY, List points, List revealRadiuses, List noiseSpreads, float time) { + RenderSystem.enableBlend(); + + float[] arr = new float[256]; + float[] radiuses = new float[128]; + float[] noiseSpreadsArr = new float[128]; + + for (int i = 0; i < arr.length; i += 2) { + + float lmx; + float lmy; + + if (i / 2 < points.size()) { + Vector2f v = points.get(i / 2); + lmx = (v.x - x) / sizeX; + lmy = (v.y - y) / sizeY; + + radiuses[i / 2] = revealRadiuses.get(i / 2); + noiseSpreadsArr[i / 2] = noiseSpreads.get(i / 2); + + + } else { + radiuses[i / 2] = 0.0001f; + noiseSpreadsArr[i / 2] = 0.000001f; + lmx = -100; + lmy = -100; + } + arr[i] = lmx; + arr[i + 1] = lmy; + } + + + Matrix4f mat = matrices.last().pose(); + + + RenderSystem.setShader(() -> RelicsCoreShaders.REVEAL_SHADER); + RelicsCoreShaders.REVEAL_SHADER.safeGetUniform("revealRadiuses").set(radiuses); + RelicsCoreShaders.REVEAL_SHADER.safeGetUniform("noiseSpreads").set(noiseSpreadsArr); + RelicsCoreShaders.REVEAL_SHADER.safeGetUniform("positions").set(arr); + RelicsCoreShaders.REVEAL_SHADER.safeGetUniform("pixelCount").set(110F); + + + RelicsCoreShaders.REVEAL_SHADER.safeGetUniform("greenRadius").set(0.035f); + RelicsCoreShaders.REVEAL_SHADER.safeGetUniform("size").set(sizeX, sizeY); + RelicsCoreShaders.REVEAL_SHADER.safeGetUniform("time").set(time); + RelicsCoreShaders.REVEAL_SHADER.safeGetUniform("col1").set(0F, 0F, 1F); + RelicsCoreShaders.REVEAL_SHADER.safeGetUniform("col2").set(1F, 0F, 0F); + + + BufferBuilder builder = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); + + builder.addVertex(mat, x, y, 0).setUv(0, 0); + builder.addVertex(mat, x + sizeX, y, 0).setUv(1, 0); + builder.addVertex(mat, x + sizeX, y + sizeY, 0).setUv(1, 1); + builder.addVertex(mat, x, y + sizeY, 0).setUv(0, 1); + builder.addVertex(mat, x, y + sizeY, 0).setUv(0, 1); + builder.addVertex(mat, x + sizeX, y + sizeY, 0).setUv(1, 1); + builder.addVertex(mat, x + sizeX, y, 0).setUv(1, 0); + builder.addVertex(mat, x, y, 0).setUv(0, 0); + + + BufferUploader.drawWithShader(builder.buildOrThrow()); + + RenderSystem.disableBlend(); + } + + public static void renderAnimatedTextureFromCenter(PoseStack matrix, float centerX, float centerY, float texWidth, float texHeight, float patternWidth, float patternHeight, float scale, AnimationData animation) { ClientLevel level = Minecraft.getInstance().level; @@ -37,12 +119,10 @@ public static void renderTextureFromCenter(PoseStack matrix, float centerX, floa } public static void renderTextureFromCenter(PoseStack matrix, float centerX, float centerY, float texOffX, float texOffY, float texWidth, float texHeight, float width, float height, float scale) { - BufferBuilder builder = Tesselator.getInstance().getBuilder(); + BufferBuilder builder = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); RenderSystem.setShader(GameRenderer::getPositionTexShader); - builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); - matrix.pushPose(); matrix.translate(centerX, centerY, 0); @@ -58,54 +138,36 @@ public static void renderTextureFromCenter(PoseStack matrix, float centerX, floa float w2 = width / 2F; float h2 = height / 2F; - builder.vertex(m, -w2, +h2, 0).uv(u1, v2).endVertex(); - builder.vertex(m, +w2, +h2, 0).uv(u2, v2).endVertex(); - builder.vertex(m, +w2, -h2, 0).uv(u2, v1).endVertex(); - builder.vertex(m, -w2, -h2, 0).uv(u1, v1).endVertex(); + builder.addVertex(m, -w2, +h2, 0).setUv(u1, v2); + builder.addVertex(m, +w2, +h2, 0).setUv(u2, v2); + builder.addVertex(m, +w2, -h2, 0).setUv(u2, v1); + builder.addVertex(m, -w2, -h2, 0).setUv(u1, v1); matrix.popPose(); - BufferUploader.drawWithShader(builder.end()); + BufferUploader.drawWithShader(builder.buildOrThrow()); } - public static void renderBeams(PoseStack matrixStack, MultiBufferSource bufferIn, float partialTicks, int amount, float size, Color color) { - matrixStack.pushPose(); + public static void renderFlatBeam(GuiGraphics guiGraphics, float partialTicks, float length, float width, int startColor, int endColor) { + var builder = guiGraphics.bufferSource().getBuffer(RenderType.dragonRays()); + var matrix4f = guiGraphics.pose().last().pose(); - Random random = new Random(1488); + int startRed = (startColor >> 16) & 0xFF; + int startGreen = (startColor >> 8) & 0xFF; + int startBlue = startColor & 0xFF; + int startAlpha = Mth.clamp((int) (((startColor >> 24) & 0xFF) * (1F - partialTicks / 200F)), 0, 255); - for (int i = 1; i < amount; ++i) { - matrixStack.mulPose(Axis.XP.rotationDegrees(random.nextFloat() * 360.0F + partialTicks)); - matrixStack.mulPose(Axis.YP.rotationDegrees(random.nextFloat() * 360.0F + partialTicks)); - matrixStack.mulPose(Axis.ZP.rotationDegrees(random.nextFloat() * 360.0F + partialTicks)); + int endRed = (endColor >> 16) & 0xFF; + int endGreen = (endColor >> 8) & 0xFF; + int endBlue = endColor & 0xFF; + int endAlpha = Mth.clamp((int) (((endColor >> 24) & 0xFF) * (1F - partialTicks / 200F)), 0, 255); - renderBeam(matrixStack, bufferIn, partialTicks, size, color); - } - - matrixStack.popPose(); - } + builder.addVertex(matrix4f, 0F, 0F, 0F).setColor(startRed, startGreen, startBlue, startAlpha); + builder.addVertex(matrix4f, width / 2F, length, 0F).setColor(endRed, endGreen, endBlue, endAlpha); + builder.addVertex(matrix4f, -width / 2F, length, 0F).setColor(endRed, endGreen, endBlue, endAlpha); - public static void renderBeam(PoseStack matrixStack, MultiBufferSource bufferIn, float partialTicks, float size, Color color) { - VertexConsumer builder = bufferIn.getBuffer(RenderType.lightning()); - Matrix4f matrix4f = matrixStack.last().pose(); - - float length = size * 0.2F; - - int red = Mth.clamp(color.getRed(), 0, 255); - int green = Mth.clamp(color.getGreen(), 0, 255); - int blue = Mth.clamp(color.getBlue(), 0, 255); - int alpha = (int) (255.0F * (1.0F - partialTicks / 200.0F)); - - builder.vertex(matrix4f, 0.0F, 0.0F, 0.0F).color(255, 255, 255, alpha).endVertex(); - builder.vertex(matrix4f, 0.0F, 0.0F, 0.0F).color(255, 255, 255, alpha).endVertex(); - builder.vertex(matrix4f, -(float) (Math.sqrt(3.0D) / 2.0D) * length, size, -0.5F * length).color(red, green, blue, 0).endVertex(); - builder.vertex(matrix4f, (float) (Math.sqrt(3.0D) / 2.0D) * length, size, -0.5F * length).color(red, green, blue, 0).endVertex(); - builder.vertex(matrix4f, 0.0F, 0.0F, 0.0F).color(255, 255, 255, alpha).endVertex(); - builder.vertex(matrix4f, 0.0F, 0.0F, 0.0F).color(255, 255, 255, alpha).endVertex(); - builder.vertex(matrix4f, (float) (Math.sqrt(3.0D) / 2.0D) * length, size, -0.5F * length).color(red, green, blue, 0).endVertex(); - builder.vertex(matrix4f, 0.0F, size, length).color(red, green, blue, 0).endVertex(); - builder.vertex(matrix4f, 0.0F, 0.0F, 0.0F).color(255, 255, 255, alpha).endVertex(); - builder.vertex(matrix4f, 0.0F, 0.0F, 0.0F).color(255, 255, 255, alpha).endVertex(); - builder.vertex(matrix4f, 0.0F, size, length).color(red, green, blue, 0).endVertex(); - builder.vertex(matrix4f, -(float) (Math.sqrt(3.0D) / 2.0D) * length, size, -0.5F * length).color(red, green, blue, 0).endVertex(); + builder.addVertex(matrix4f, 0F, 0F, 0F).setColor(startRed, startGreen, startBlue, startAlpha); + builder.addVertex(matrix4f, -width / 2F, length, 0F).setColor(endRed, endGreen, endBlue, endAlpha); + builder.addVertex(matrix4f, width / 2F, length, 0F).setColor(endRed, endGreen, endBlue, endAlpha); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/utils/Scheduler.java b/src/main/java/it/hurts/sskirillss/relics/utils/Scheduler.java deleted file mode 100644 index 37ef886f..00000000 --- a/src/main/java/it/hurts/sskirillss/relics/utils/Scheduler.java +++ /dev/null @@ -1,49 +0,0 @@ -package it.hurts.sskirillss.relics.utils; - -import net.minecraftforge.event.TickEvent; -import net.minecraftforge.event.server.ServerStoppedEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; - -import java.util.ArrayList; -import java.util.List; - -@Mod.EventBusSubscriber -public class Scheduler { - private static final List allTasksQueue = new ArrayList<>(); - private static final List allTasks = new ArrayList<>(); - - public static void schedule(int ticks, Runnable task) { - allTasksQueue.add(new Task(ticks, task)); - } - - @SubscribeEvent - public static void serverTick(TickEvent.ServerTickEvent e) { - if (e.phase == TickEvent.Phase.START) { - while (!allTasksQueue.isEmpty()) - allTasks.add(allTasksQueue.remove(0)); - - allTasks.removeIf(Task::tick); - } - } - - @SubscribeEvent - public static void reset(ServerStoppedEvent e) { - allTasks.clear(); - } - - private static class Task { - int ticks; - Runnable task; - - public Task(int ticks, Runnable task) { - this.ticks = ticks; - this.task = task; - } - - public boolean tick() { - if (ticks == 0) task.run(); - return --ticks < 0; - } - } -} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/utils/WorldUtils.java b/src/main/java/it/hurts/sskirillss/relics/utils/WorldUtils.java index b2c8bfc5..2995d903 100644 --- a/src/main/java/it/hurts/sskirillss/relics/utils/WorldUtils.java +++ b/src/main/java/it/hurts/sskirillss/relics/utils/WorldUtils.java @@ -2,6 +2,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; import net.minecraft.world.level.ClipContext; import net.minecraft.world.level.Level; import net.minecraft.world.phys.HitResult; @@ -29,29 +30,14 @@ public static List getBlockSphere(BlockPos center, double radius) { return sphere; } - public static double getGroundHeight(Level level, Vec3 position, int iterations) { - HitResult result = level.clip(new ClipContext(position, position.add(0, -iterations, 0), ClipContext.Block.COLLIDER, ClipContext.Fluid.ANY, null)); + public static double getGroundHeight(Entity entity, Vec3 position, int iterations) { + Level level = entity.level(); - if (result.getType() == HitResult.Type.BLOCK) - return result.getLocation().y(); - - return -level.getMaxBuildHeight(); - } - - public static double getGroundDistance(Level level, Vec3 position, int iterations) { - return Math.max(0, position.y() - getGroundHeight(level, position, iterations)); - } - - public static double getCeilHeight(Level level, Vec3 position, int iterations) { - HitResult result = level.clip(new ClipContext(position, position.add(0, iterations, 0), ClipContext.Block.COLLIDER, ClipContext.Fluid.ANY, null)); + HitResult result = level.clip(new ClipContext(position, position.add(0, -iterations, 0), ClipContext.Block.COLLIDER, ClipContext.Fluid.ANY, entity)); if (result.getType() == HitResult.Type.BLOCK) return result.getLocation().y(); - return level.getMaxBuildHeight(); - } - - public static double getCeilDistance(Level level, Vec3 position, int iterations) { - return Math.max(0, getCeilHeight(level, position, iterations) - position.y()); + return -level.getMaxBuildHeight(); } } \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/utils/data/GUIRenderer.java b/src/main/java/it/hurts/sskirillss/relics/utils/data/GUIRenderer.java new file mode 100644 index 00000000..43eccf1d --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/utils/data/GUIRenderer.java @@ -0,0 +1,267 @@ +package it.hurts.sskirillss.relics.utils.data; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.*; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.Accessors; +import net.minecraft.client.Minecraft; +import net.minecraft.client.multiplayer.ClientLevel; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.resources.ResourceLocation; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import org.joml.Matrix4f; +import org.lwjgl.opengl.GL11; + +import java.awt.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.Supplier; + +@Setter +@NoArgsConstructor +@OnlyIn(Dist.CLIENT) +@Accessors(fluent = true, chain = true) +public final class GUIRenderer { + private static final GUIRenderer INSTANCE = new GUIRenderer(); + + @Setter(AccessLevel.NONE) + private ResourceLocation texture; + @Setter(AccessLevel.NONE) + private PoseStack pose; + + private float posX; + private float posY; + + private int texWidth; + private int texHeight; + + private int patternWidth; + private int patternHeight; + + private int texOffX; + private int texOffY; + + private float scale; + + private float red; + private float green; + private float blue; + private float alpha; + + private Supplier time; + private AnimationData animation; + + private SpriteAnchor anchor; + private List mirror; + + public static GUIRenderer begin(ResourceLocation texture, PoseStack pose) { + var renderer = INSTANCE; + + renderer.texture = texture; + renderer.pose = pose; + + renderer.posX = 0F; + renderer.posY = 0F; + + renderer.texWidth = -1; + renderer.texHeight = -1; + + renderer.patternWidth = -1; + renderer.patternHeight = -1; + + renderer.texOffX = 0; + renderer.texOffY = 0; + + renderer.scale = 1F; + + renderer.red = -1F; + renderer.green = -1F; + renderer.blue = -1F; + renderer.alpha = -1F; + + renderer.time = () -> { + ClientLevel level = Minecraft.getInstance().level; + + return level == null ? 0 : level.getGameTime(); + }; + renderer.animation = AnimationData.builder() + .frame(0, Integer.MAX_VALUE); + + renderer.anchor = SpriteAnchor.CENTER; + renderer.mirror = new ArrayList<>(); + + return renderer; + } + + public GUIRenderer pos(float posX, float posY) { + var renderer = INSTANCE; + + renderer.posX = posX; + renderer.posY = posY; + + return renderer; + } + + public GUIRenderer texSize(int texWidth, int texHeight) { + var renderer = INSTANCE; + + renderer.texWidth = texWidth; + renderer.texHeight = texHeight; + + return renderer; + } + + public GUIRenderer patternSize(int patternWidth, int patternHeight) { + var renderer = INSTANCE; + + renderer.patternWidth = patternWidth; + renderer.patternHeight = patternHeight; + + return renderer; + } + + public GUIRenderer texOff(int texOffX, int texOffY) { + var renderer = INSTANCE; + + renderer.texOffX = texOffX; + renderer.texOffY = texOffY; + + return renderer; + } + + public GUIRenderer color(float red, float green, float blue, float alpha) { + var renderer = INSTANCE; + + renderer.red = red; + renderer.green = green; + renderer.blue = blue; + renderer.alpha = alpha; + + return renderer; + } + + public GUIRenderer color(int red, int green, int blue, int alpha) { + return this.color(red / 255F, green / 255F, blue / 255F, alpha / 255F); + } + + public GUIRenderer color(Color color) { + return this.color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + } + + public GUIRenderer color(int color) { + return this.color(new Color(color)); + } + + public GUIRenderer mirror(SpriteMirror... mirror) { + var renderer = INSTANCE; + + renderer.mirror.addAll(Arrays.asList(mirror)); + + return renderer; + } + + public void end() { + BufferBuilder builder = Tesselator.getInstance().begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX); + + Minecraft.getInstance().getTextureManager().getTexture(texture).bind(); + + var color = Arrays.copyOf(RenderSystem.getShaderColor(), RenderSystem.getShaderColor().length); + + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.setShaderTexture(0, texture); + RenderSystem.setShaderColor(red == -1F ? color[0] : red, green == -1F ? color[1] : green, blue == -1F ? color[2] : blue, alpha == -1F ? color[3] : alpha); + RenderSystem.disableCull(); + + if (texHeight == -1) + texHeight = GlStateManager._getTexLevelParameter(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_HEIGHT); + + if (texWidth == -1) + texWidth = GlStateManager._getTexLevelParameter(GL11.GL_TEXTURE_2D, 0, GL11.GL_TEXTURE_WIDTH); + + if (patternHeight == -1) + patternHeight = texHeight; + + if (patternWidth == -1) + patternWidth = texWidth; + + texOffY = patternHeight * animation.getFrameByTime(time.get()).getKey(); + + pose.pushPose(); + + float xOff = 0F; + float yOff = 0F; + + switch (anchor) { + case CENTER -> { + xOff = patternWidth / 2F * scale; + yOff = patternHeight / 2F * scale; + } + case TOP_RIGHT -> { + xOff = patternWidth * scale; + yOff = 0F; + } + case TOP_LEFT -> { + xOff = 0F; + yOff = 0F; + } + case BOTTOM_LEFT -> { + xOff = 0F; + yOff = patternHeight * scale; + } + case BOTTOM_RIGHT -> { + xOff = patternWidth * scale; + yOff = patternHeight * scale; + } + case TOP_CENTER -> { + xOff = (patternWidth / 2F) * scale; + yOff = 0F; + } + case CENTER_LEFT -> { + xOff = 0F; + yOff = (patternHeight / 2F) * scale; + } + case CENTER_RIGHT -> { + xOff = patternWidth * scale; + yOff = (patternHeight / 2F) * scale; + } + case BOTTOM_CENTER -> { + xOff = (patternWidth / 2F) * scale; + yOff = patternHeight * scale; + } + } + + pose.translate(posX - xOff, posY - yOff, 0); + pose.scale(scale, scale, 0); + + Matrix4f m = pose.last().pose(); + + float u1 = (float) texOffX / texWidth; + float u2 = (float) (texOffX + patternWidth) / texWidth; + float v1 = (float) (texOffY + patternHeight) / texHeight; + float v2 = (float) texOffY / texHeight; + + for (SpriteMirror mirror : mirror) { + switch (mirror) { + case HORIZONTAL -> u1 = u1 + u2 - (u2 = u1); + case VERTICAL -> v1 = v1 + v2 - (v2 = v1); + } + } + + builder.addVertex(m, 0, patternHeight, 0).setUv(u1, v1); + builder.addVertex(m, patternWidth, patternHeight, 0).setUv(u2, v1); + builder.addVertex(m, patternWidth, 0, 0).setUv(u2, v2); + builder.addVertex(m, 0, 0, 0).setUv(u1, v2); + + pose.popPose(); + + BufferUploader.drawWithShader(builder.buildOrThrow()); + + RenderSystem.enableCull(); + RenderSystem.setShaderColor(color[0], color[1], color[2], color[3]); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/utils/data/GUIScissors.java b/src/main/java/it/hurts/sskirillss/relics/utils/data/GUIScissors.java new file mode 100644 index 00000000..351151fe --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/utils/data/GUIScissors.java @@ -0,0 +1,27 @@ +package it.hurts.sskirillss.relics.utils.data; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; + +public class GUIScissors { + public static void begin(int x, int y, int width, int height) { + var window = Minecraft.getInstance().getWindow(); + + float scaledWidth = window.getGuiScaledWidth(); + float scaledHeight = window.getGuiScaledHeight(); + + int realWidth = window.getWidth(); + int realHeight = window.getHeight(); + + int scissorX = (int) (realWidth * (x / scaledWidth)); + int scissorY = (int) (realHeight * (1 - (y + height) / scaledHeight)) - 2; + int scissorWidth = (int) (realWidth * (width / scaledWidth)); + int scissorHeight = (int) (realHeight * (height / scaledHeight)); + + RenderSystem.enableScissor(scissorX, scissorY, scissorWidth, scissorHeight); + } + + public static void end() { + RenderSystem.disableScissor(); + } +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/utils/data/SpriteAnchor.java b/src/main/java/it/hurts/sskirillss/relics/utils/data/SpriteAnchor.java new file mode 100644 index 00000000..ab5f0522 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/utils/data/SpriteAnchor.java @@ -0,0 +1,13 @@ +package it.hurts.sskirillss.relics.utils.data; + +public enum SpriteAnchor { + TOP_LEFT, + TOP_CENTER, + TOP_RIGHT, + CENTER_LEFT, + CENTER, + CENTER_RIGHT, + BOTTOM_LEFT, + BOTTOM_CENTER, + BOTTOM_RIGHT +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/utils/data/SpriteMirror.java b/src/main/java/it/hurts/sskirillss/relics/utils/data/SpriteMirror.java new file mode 100644 index 00000000..cdeea825 --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/utils/data/SpriteMirror.java @@ -0,0 +1,6 @@ +package it.hurts.sskirillss.relics.utils.data; + +public enum SpriteMirror { + HORIZONTAL, + VERTICAL +} \ No newline at end of file diff --git a/src/main/java/it/hurts/sskirillss/relics/utils/data/WorldPosition.java b/src/main/java/it/hurts/sskirillss/relics/utils/data/WorldPosition.java new file mode 100644 index 00000000..c7d72e5f --- /dev/null +++ b/src/main/java/it/hurts/sskirillss/relics/utils/data/WorldPosition.java @@ -0,0 +1,35 @@ +package it.hurts.sskirillss.relics.utils.data; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import lombok.AllArgsConstructor; +import lombok.Data; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +@Data +@AllArgsConstructor +public class WorldPosition { + private ResourceKey level; + private Vec3 pos; + + public WorldPosition(Entity entity) { + this.level = entity.level().dimension(); + this.pos = entity.position(); + } + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group(ResourceKey.codec(Registries.DIMENSION).fieldOf("level").forGetter(WorldPosition::getLevel), + Vec3.CODEC.fieldOf("pos").forGetter(WorldPosition::getPos)) + .apply(instance, WorldPosition::new) + ); + +// public static final StreamCodec STREAM_CODEC = StreamCodec.composite( +// ResourceKey.streamCodec(Registries.DIMENSION), WorldPosition::getLevel, +// Vec3.CODEC, WorldPosition::getPos, +// WorldPosition::new +// ); +} \ No newline at end of file diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index a78946ae..360188ca 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -1,3 +1,4 @@ -public net.minecraft.world.entity.LivingEntity m_21329_()V # updatingUsingItem -public net.minecraft.world.entity.projectile.AbstractArrow f_36697_ # life -public net.minecraft.world.entity.monster.piglin.PiglinAi m_34860_(Lnet/minecraft/world/entity/monster/piglin/Piglin;Ljava/util/List;)V # throwItems \ No newline at end of file +public net.minecraft.world.entity.LivingEntity updatingUsingItem()V # updatingUsingItem +public net.minecraft.world.entity.projectile.AbstractArrow life # life +public net.minecraft.world.entity.monster.piglin.PiglinAi throwItems(Lnet/minecraft/world/entity/monster/piglin/Piglin;Ljava/util/List;)V # throwItems +public net.minecraft.client.gui.screens.Screen rebuildWidgets()V # rebuildWidgets \ No newline at end of file diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/neoforge.mods.toml similarity index 69% rename from src/main/resources/META-INF/mods.toml rename to src/main/resources/META-INF/neoforge.mods.toml index 9f43ed34..3055e83e 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/neoforge.mods.toml @@ -1,9 +1,12 @@ modLoader = "javafml" -loaderVersion = "[47,)" +loaderVersion = "[1,)" license = "All Rights Reserved" issueTrackerURL = "https://discord.gg/pHren9yxzW" logoFile = "logo.png" +[[mixins]] +config = "${mod_id}.mixins.json" + [[mods]] modId = "${mod_id}" version = "${mod_version}" @@ -14,25 +17,25 @@ description = '''Just a mod about useful relics with unique mechanics ;)''' [[dependencies.${mod_id}]] modId = "minecraft" - mandatory = true - versionRange = "[1.20.1,1.21)" + type="required" + versionRange = "[1.21, 1.22)" ordering = "NONE" side = "BOTH" [[dependencies.${mod_id}]] - modId = "forge" - mandatory = true - versionRange = "[47,)" + modId = "neoforge" + type="required" + versionRange = "[21.0.140-beta,)" ordering = "NONE" side = "BOTH" [[dependencies.${mod_id}]] modId = "curios" - mandatory = true - versionRange = "[5.2.0+1.20.1,)" + type="required" + versionRange = "[9.0.5+1.21,)" ordering = "NONE" side = "BOTH" [[dependencies.${mod_id}]] modId = "octolib" - mandatory = true - versionRange = "[0.3,)" + type="required" + versionRange = "[0.5.0.1,)" ordering = "NONE" side = "BOTH" \ No newline at end of file diff --git a/src/main/resources/assets/relics/blockstates/phantom_block.json b/src/main/resources/assets/relics/blockstates/phantom_block.json new file mode 100644 index 00000000..60b3d47e --- /dev/null +++ b/src/main/resources/assets/relics/blockstates/phantom_block.json @@ -0,0 +1,21 @@ +{ + "variants": { + "": [ + { + "model": "relics:block/phantom_block" + }, + { + "model": "relics:block/phantom_block", + "y": 90 + }, + { + "model": "relics:block/phantom_block", + "y": 180 + }, + { + "model": "relics:block/phantom_block", + "y": 270 + } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/lang/en_us.json b/src/main/resources/assets/relics/lang/en_us.json index 61e27940..baf5c68f 100644 --- a/src/main/resources/assets/relics/lang/en_us.json +++ b/src/main/resources/assets/relics/lang/en_us.json @@ -1,64 +1,115 @@ { "itemGroup.relics": "Relics", - "curios.identifier.talisman": "Talisman", "curios.identifier.feet": "Feet", - "tooltip.relics.relic.tooltip.table": "You may learn more about this relic on the Researching Table.", - "tooltip.relics.relic.tooltip.shift": "Hold [Shift] for more info.", + "tooltip.relics.researching.info": "Hold [%1$s] to research...", "tooltip.relics.relic.tooltip.abilities": "Abilities:", - "tooltip.relics.relic.ability.tooltip.low_level": "To use you need to increase level of the relic to %1$s %2$s.", - "tooltip.relics.relic.ability.tooltip.no_stats": "The ability has no upgradeable stats and does not affect the quality of the relic.", - "tooltip.relics.relic.ability.tooltip.ready_to_upgrade": "The ability is ready to upgrade %1$s .", + "tooltip.relics.researching.badge.ability.oblivion.title": "Vulnerability to Oblivion", + "tooltip.relics.researching.badge.ability.oblivion.description": "The ability will not work under the effect of Oblivion.", + "tooltip.relics.researching.badge.ability.silence.title": "Vulnerability to Silence", + "tooltip.relics.researching.badge.ability.silence.description": "The ability will not work under the effect of Silence.", + "tooltip.relics.researching.badge.ability.flawless_ability.title": "Flawless Ability", + "tooltip.relics.researching.badge.ability.flawless_ability.description": "The ability has reached perfect parameters. Be proud of yourself!", + "tooltip.relics.researching.badge.ability.instantaneous.title": "Instantaneous Use", + "tooltip.relics.researching.badge.ability.instantaneous.description": "The ability activates immediately upon use.", + "tooltip.relics.researching.badge.ability.interruptible.title": "Interruptible Use", + "tooltip.relics.researching.badge.ability.interruptible.description": "The ability lasts for a certain time after use and can be interrupted by repeated use.", + "tooltip.relics.researching.badge.ability.cyclical.title": "Cyclical Use", + "tooltip.relics.researching.badge.ability.cyclical.description": "The ability works only with continuous use.", + "tooltip.relics.researching.badge.ability.toggleable.title": "Toggleable Use", + "tooltip.relics.researching.badge.ability.toggleable.description": "The ability can be toggled on/off when used.", + "tooltip.relics.researching.badge.ability.chargeable.title": "Chargeable Use", + "tooltip.relics.researching.badge.ability.chargeable.description": "The ability activates instantly after some time of cyclical use. The outcome may depend on the duration of use.", + "tooltip.relics.researching.badge.ability.stated.title": "Stated Use", + "tooltip.relics.researching.badge.ability.stated.description": "The ability has several modes that cycle with each use.", - "tooltip.relics.relic.leveling_points.title": "Leveling points", + "tooltip.relics.researching.badge.relic.flawless_relic.title": "Flawless Relic", + "tooltip.relics.researching.badge.relic.flawless_relic.description": "The relic has reached perfect parameters. Be proud of yourself!", - "tooltip.relics.relic.vanilla_experience.title": "Vanilla Minecraft experience", - "tooltip.relics.relic.vanilla_experience.current_amount": "Current amount: %1$s/%2$s [%3$s%%]", - "tooltip.relics.relic.vanilla_experience.total_amount": "Total amount: %1$s", + "tooltip.relics.researching.research.tip": "To unlock the ability, it is necessary to connect the stars hidden beneath the fog in such a way that the resulting constellation matches the image in the background. When the constellation is correctly aligned, the ability will be automatically researched.", - "tooltip.relics.relic.relic_experience.title": "Relic experience", - "tooltip.relics.relic.relic_experience.current_amount": "Current amount: %1$s/%2$s [%3$s%%]", + "tooltip.relics.researching.research.hint.description": "Hint", + "tooltip.relics.researching.research.hint.cost": "Cost: %1$s experience levels %2$s.", + "tooltip.relics.researching.research.hint.quick": "Hold [Shift] for fully automatic ability research.", + "tooltip.relics.researching.research.hint.locked": "The ability has already been researched!", - "tooltip.relics.relic.max_level": "MAX", + "tooltip.relics.researching.badge.ability.cast_type.hint": "Use the [%1$s] key outside any interface to call up the active abilities menu!", - "tooltip.relics.relic.ability.level": " [%1$s/%2$s]", + "tooltip.relics.researching.general.leveling_point.title": "Leveling Points:", + "tooltip.relics.researching.general.leveling_point.extra_info": "Earned when leveling up the relic and used to upgrade abilities.", + + "tooltip.relics.researching.general.player_experience.title": "Experience Level:", + "tooltip.relics.researching.general.player_experience.extra_info": "Standard player experience from the vanilla game. Obtained by killing mobs, mining ore, smelting items, etc.", + + "tooltip.relics.researching.general.luck.title": "Luck:", + "tooltip.relics.researching.general.luck.extra_info": "Gained with each unsuccessful reroll of random relic stats, increasing the chances of getting better stats in the next reroll. Increases the reroll cost by 1 experience level for every 25% of luck.", + + "tooltip.relics.researching.relic.card.low_level": "To unlock, you need to level up the relic to %1$s!", + "tooltip.relics.researching.relic.card.no_stats": "Ability has no upgradeable stats and does not affect the quality of the relic!", + "tooltip.relics.researching.relic.card.unresearched": "To use, you need to conduct the research!", + "tooltip.relics.researching.relic.card.ready_to_unlock": "Ability is ready to be unlocked! Clicks remaining: %1$s", + "tooltip.relics.researching.relic.card.ready_to_upgrade": "Ability is ready to be upgraded!", + + "tooltip.relics.researching.relic.gem.low_level": "To unlock the experience source, you need to level up the relic to %1$s!", + "tooltip.relics.researching.relic.gem.locked_ability": "To unlock the experience source, you need to unlock and research the associated ability!", + + "tooltip.relics.researching.tab.relic": "Relic", + "tooltip.relics.researching.tab.ability": "Abilities", + "tooltip.relics.researching.tab.experience": "Experience Sources", + + "tooltip.relics.researching.general.extra_info": "Hold [Shift] for more info", + + "tooltip.relics.researching.relic.info.level": "Relic Level:", + "tooltip.relics.researching.relic.info.quality": "Relic Quality:", + "tooltip.relics.researching.relic.info.extra_info": "Relic quality is the arithmetic average of all currently unlocked abilities' quality and is measured in points from 1 to 5 with a step of 0.5. It is purely a visual metric that shows how close the item's initial random characteristics are to the best possible. To improve the overall quality of the relic, each ability needs to be considered separately.", + + "tooltip.relics.researching.relic.experience.title": "Relic Experience:", + "tooltip.relics.researching.relic.experience.extra_info": "Gained by using relic abilities as intended (more details can be found on the experience sources page). Upon reaching the maximum experience value, the relic's level and the pool of upgrade points increase by 1, allowing you to unlock previously unavailable abilities or enhance existing ones.", + + "tooltip.relics.researching.ability.info.level": "Ability Level:", + "tooltip.relics.researching.ability.info.quality": "Ability Quality:", + "tooltip.relics.researching.ability.info.extra_info": "Ability quality, similar to relic quality, is the arithmetic average of all the ability's current characteristics and is measured in points from 1 to 5 with a step of 0.5. It is purely a visual metric that shows how close the ability's initial random characteristics are to the best possible. To improve the ability's quality, you need to reset its random characteristics until you get a better value.", "tooltip.relics.relic.status.positive": "§2§l[§2§l✔§2§l]", "tooltip.relics.relic.status.negative": "§4§l[§4§l✘§4§l]", - - "tooltip.relics.relic.exchange.description": "Experience exchange", - "tooltip.relics.relic.exchange.cost": "Convert %1$s Vanilla Minecraft experience to 1%% of max experience of the current relic level. Exchange cost increases after each use %2$s.", - "tooltip.relics.relic.exchange.locked": "The relic has reached its max level.", + "tooltip.relics.relic.status.unknown": "§6§l[§6§l?§6§l]", "tooltip.relics.relic.upgrade.description": "Level-up", - "tooltip.relics.relic.upgrade.cost": "Cost: %1$s leveling points %2$s, %3$s experience points %4$s.", + "tooltip.relics.relic.upgrade.cost": "Cost: %1$s leveling points %2$s, %3$s experience levels %4$s.", "tooltip.relics.relic.upgrade.locked": "The ability has reached its max level.", + "tooltip.relics.relic.upgrade.quick":"Hold [Shift] to automatically upgrade to the highest possible level.", "tooltip.relics.relic.reroll.description": "Reroll random stats", - "tooltip.relics.relic.reroll.cost": "Cost: %1$s experience points %2$s.", + "tooltip.relics.relic.reroll.cost": "Cost: %1$s experience levels %2$s.", + "tooltip.relics.relic.reroll.quick":"Hold [Shift] to automatically reroll random stats to perfect values.", + "tooltip.relics.relic.reroll.warning":"Hold [Shift] to confirm rerolling stats from perfect values to other random ones.", "tooltip.relics.relic.reset.description": "Reset leveling points", - "tooltip.relics.relic.reset.cost": "Cost: %1$s experience points %2$s.", + "tooltip.relics.relic.reset.cost": "Cost: %1$s experience levels %2$s.", "tooltip.relics.relic.reset.locked": "To use you need to level-up this ability at least 1 time.", - "item.relics.infinity_ham": "Infinity Ham", - "tooltip.relics.infinity_ham.description": "+1 experience point for each piece eaten from the ability «Regeneration».", - "tooltip.relics.infinity_ham.ability.autophagy": "Regeneration", - "tooltip.relics.infinity_ham.ability.autophagy.description": "Using a relic consumes one of the regeneratable charges, replenishing the hunger of the wearer.", - "tooltip.relics.infinity_ham.ability.autophagy.stat.feed.title": "Saturation:", - "tooltip.relics.infinity_ham.ability.autophagy.stat.feed.value": "%1$s units.", - "tooltip.relics.infinity_ham.ability.infusion": "Alchemy", - "tooltip.relics.infinity_ham.ability.infusion.description": "Using a potion on the relic in the inventory remembers its effect by spending the potion. Subsequent use of the «Regeneration» ability will impose a summable effect of the associated potion on the wearer. In the complete absence of charges, the relic loses the properties of the associated potion.", - "tooltip.relics.infinity_ham.ability.infusion.stat.duration.title": "Effect duration:", - "tooltip.relics.infinity_ham.ability.infusion.stat.duration.value": "%1$s seconds per charge.", + "item.relics.infinity_ham": "Infinite Ham", + "tooltip.relics.infinity_ham.description": "A mysterious piece of meat that smoothly regenerates to its original size, no matter how much you carve it.", + "tooltip.relics.infinity_ham.ability.regeneration": "Regeneration", + "tooltip.relics.infinity_ham.ability.regeneration.description": "Every %1$s seconds, regenerates up to 6 edible chunks, each restoring %2$s hunger points. When consumed, the relic automatically uses the required number of chunks to replenish the player's hunger.", + "tooltip.relics.infinity_ham.ability.marinade": "Marinade", + "tooltip.relics.infinity_ham.ability.marinade.description": "Allows applying potion effects to the relic by left-clicking it with a potion in the inventory. Each time the relic is consumed, it applies these effects to the player for %1$s seconds per hunger point restored. Using a water bottle clears the last applied potion effects.", + "tooltip.relics.infinity_ham.ability.meat_bat": "Meat Bat", + "tooltip.relics.infinity_ham.ability.meat_bat.description": "Allows the relic to be used as a melee weapon, dealing %1$s damage and stunning the target for %2$s seconds per chunk. Consumes all chunks when attacking, regardless of the target's remaining health.", + "tooltip.relics.infinity_ham.leveling_source.regeneration.title": "Regeneration", + "tooltip.relics.infinity_ham.leveling_source.regeneration.description": "+%1$s experience points for each chunk consumed through the %2$s ability.", + "tooltip.relics.infinity_ham.leveling_source.marinade.title": "Marinade", + "tooltip.relics.infinity_ham.leveling_source.marinade.description": "+%1$s experience points for each effect applied to the relic using the %2$s ability.", + "tooltip.relics.infinity_ham.leveling_source.meat_bat.title": "Meat Bat", + "tooltip.relics.infinity_ham.leveling_source.meat_bat.description": "+%1$s experience points for each chunk consumed during the activation of the %2$s ability.", "item.relics.enders_hand": "Ender Hand", "tooltip.relics.enders_hand.description": "+1 experience point for using the ability «End Transposition», +1 experience point for every 10 blocks from the distance to the target when using.", "tooltip.relics.enders_hand.ability.neutrality": "Neutrality", - "tooltip.relics.enders_hand.ability.neutrality.description": "Makes endermen neutral with respect to the wearer.", + "tooltip.relics.enders_hand.ability.neutrality.description": "Makes endermen neutral to the wearer.", "tooltip.relics.enders_hand.ability.swap": "End Transposition", "tooltip.relics.enders_hand.ability.swap.description": "Swaps the wearer with the target along the line of sight.", "tooltip.relics.enders_hand.ability.swap.stat.distance.title": "Distance:", @@ -66,41 +117,37 @@ "tooltip.relics.enders_hand.ability.swap.predicate.target": "Looking at the target", "item.relics.holy_locket": "Holy Locket", - "tooltip.relics.holy_locket.description": "+1 experience point for each activation of the ability «Divine Blessing», +1 experience point for each stolen healing unit.", - "tooltip.relics.holy_locket.ability.steal": "Divine Blessing", - "tooltip.relics.holy_locket.ability.steal.description": "Redirects a part of the regenerated health of nearby creatures to the wearer of the relic.", - "tooltip.relics.holy_locket.ability.steal.stat.amount.title": "Quantity:", - "tooltip.relics.holy_locket.ability.steal.stat.amount.value": "%1$s%% of regenerated health.", - "tooltip.relics.holy_locket.ability.steal.stat.radius.title": "Radius:", - "tooltip.relics.holy_locket.ability.steal.stat.radius.value": "%1$s blocks.", + "tooltip.relics.holy_locket.description": "Grants the wearer the ability to turn enemies' healing against them.", + "tooltip.relics.holy_locket.ability.faith": "Faith", + "tooltip.relics.holy_locket.ability.faith.description": "Has 2 toggleable modes: Holiness and Unholiness. In the red Holiness mode, steals %1$s%% of the healing from visible entities within a radius of %3$s blocks and transfers it to the relic's wearer. In the blue Unholiness mode, deals damage to all visible entities within the same radius equal to %2$s%% of the healing received by the relic's wearer.", + "tooltip.relics.holy_locket.ability.penitence": "Penitence", + "tooltip.relics.holy_locket.ability.penitence.description": "Ignites undead enemies for 10 seconds and increases damage dealt to them by %1$s%%.", + "tooltip.relics.holy_locket.ability.ascension": "Ascension", + "tooltip.relics.holy_locket.ability.ascension.description": "Killing a target grants the relic's wearer a temporary stacking immortality effect for %2$s seconds, up to a maximum of %1$s seconds.", + "tooltip.relics.holy_locket.leveling_source.faith.title": "Faith", + "tooltip.relics.holy_locket.leveling_source.faith.description": "+%1$s experience points for each activation of the %2$s ability.", + "tooltip.relics.holy_locket.leveling_source.penitence.title": "Penitence", + "tooltip.relics.holy_locket.leveling_source.penitence.description": "+%1$s experience points for each activation of the %2$s ability on an undead enemy that is not yet burning.", + "tooltip.relics.holy_locket.leveling_source.ascension.title": "Ascension", + "tooltip.relics.holy_locket.leveling_source.ascension.description": "+%1$s experience points for each activation of the %2$s ability.", "item.relics.magic_mirror": "Magic Mirror", "tooltip.relics.magic_mirror.description": "+1 experience point for each use of the «Wormhole» ability, +1 experience point for every 50 blocks to the teleportation point.", "tooltip.relics.magic_mirror.ability.teleport": "Wormhole", - "tooltip.relics.magic_mirror.ability.teleport.description": "After use, teleports the wearer to their respawn point.", + "tooltip.relics.magic_mirror.ability.teleport.description": "Upon using, teleports the wearer to their respawn point.", "tooltip.relics.magic_mirror.ability.teleport.stat.distance.title": "Distance:", "tooltip.relics.magic_mirror.ability.teleport.stat.distance.value": "%1$s blocks.", "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.title": "Recharge:", "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.value": "%1$s seconds.", "item.relics.shadow_glaive": "Shadow Glaive", - "tooltip.relics.shadow_glaive.description": "+1 experience point for every 2 glaive bounces from the «Blind Justice» ability.", - "tooltip.relics.shadow_glaive.ability.glaive": "Blind Justice", - "tooltip.relics.shadow_glaive.ability.glaive.description": "Usage releases one of 8 glaive charges, bouncing between nearby targets. The missing charges are restored themselves after a certain amount of time.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.damage.title": "Damage:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.damage.value": "%1$s.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.recharge.title": "Recovery time:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.recharge.value": "%1$s seconds.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.bounces.title": "Bounces:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.bounces.value": "%1$s.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.radius.title": "Bounce radius:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.radius.value": "%1$s blocks.", - "tooltip.relics.shadow_glaive.ability.saw": "Merciless punishment", - "tooltip.relics.shadow_glaive.ability.saw.description": "Usage consumes all 8 glaive charges, summoning a saw that deals damage to nearby targets. Reuse will return the saw to the wearer, restoring all charges. Automatic charge regeneration is blocked while the ability is active.", - "tooltip.relics.shadow_glaive.ability.saw.stat.speed.title": "Hit interval:", - "tooltip.relics.shadow_glaive.ability.saw.stat.speed.value": "%1$s seconds.", - "tooltip.relics.shadow_glaive.ability.saw.stat.damage.title": "Damage:", - "tooltip.relics.shadow_glaive.ability.saw.stat.damage.value": "%1$s units.", + "tooltip.relics.shadow_glaive.description": "A masterfully forged, capricious weapon. If its temper is favorable, neither horde nor legion will withstand the onslaught of its thousand blades.", + "tooltip.relics.shadow_glaive.ability.mayhem": "Mayhem", + "tooltip.relics.shadow_glaive.ability.mayhem.description": "Dealing damage has a %1$s%% chance to trigger a projectile that bounces chaotically between nearby targets within a 16-block radius, up to %2$s times, dealing %3$s%% of the triggering attack's damage.", + "tooltip.relics.shadow_glaive.ability.cloning": "Cloning", + "tooltip.relics.shadow_glaive.ability.cloning.description": "Each projectile bounce from the Mayhem ability has a %1$s%% chance to spawn an additional identical projectile.", + "tooltip.relics.shadow_glaive.leveling_source.mayhem.title": "Mayhem", + "tooltip.relics.shadow_glaive.leveling_source.mayhem.description": "+%1$s experience points for each activation of the %2$s ability.", "item.relics.arrow_quiver": "Quiver", "tooltip.relics.arrow_quiver.description": "+1 experience point for every 10 blocks to the target hit by the shot.", @@ -193,36 +240,11 @@ "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration.value": "%1$s seconds.", "item.relics.spore_sack": "Spore Sack", - "tooltip.relics.spore_sack.description": "+1 experience point for each spore released by the «Poison Synthesis» ability.\n+1 experience point for each additional spore split by the «Decomposition» ability.", - "tooltip.relics.spore_sack.ability.spore": "Poison Synthesis", - "tooltip.relics.spore_sack.ability.spore.description": "When taking damage, throws a spore in a random direction that sticks to surfaces and explodes when a target approaches, dealing damage, poisoning, slowing, and blocking healing for 5 seconds.", - "tooltip.relics.spore_sack.ability.spore.stat.size.title": "Size:", - "tooltip.relics.spore_sack.ability.spore.stat.size.value": "%1$s per unit of damage.", - "tooltip.relics.spore_sack.ability.spore.stat.damage.title": "Damage:", - "tooltip.relics.spore_sack.ability.spore.stat.damage.value": "%1$s per unit of size.", - "tooltip.relics.spore_sack.ability.spore.stat.cooldown.title": "Cooldown:", - "tooltip.relics.spore_sack.ability.spore.stat.cooldown.value": "%1$s seconds.", - "tooltip.relics.spore_sack.ability.spore.stat.duration.title": "Duration:", - "tooltip.relics.spore_sack.ability.spore.stat.duration.value": "%1$s seconds.", - "tooltip.relics.spore_sack.ability.buffer": "Poison Accumulation", - "tooltip.relics.spore_sack.ability.buffer.description": "Each time the «Poison Synthesis» ability cooldown triggers, accumulates one charge into the relic's internal buffer that can be used by other abilities to release spores. Adds a chance not to consume spores from the internal buffer when requesting charges for other abilities.", - "tooltip.relics.spore_sack.ability.buffer.stat.capacity.title": "Capacity:", - "tooltip.relics.spore_sack.ability.buffer.stat.capacity.value": "%1$s spores.", - "tooltip.relics.spore_sack.ability.buffer.stat.chance.title": "Chance:", - "tooltip.relics.spore_sack.ability.buffer.stat.chance.value": "%1$s%%.", - "tooltip.relics.spore_sack.ability.multiplying": "Decomposition", - "tooltip.relics.spore_sack.ability.multiplying.description": "Each spore can split into several smaller spores within a given range when it explodes. The maximum number of spores is determined by the degree of the main spore size, but the final number is limited by the first unsuccessful chance of spore division.", - "tooltip.relics.spore_sack.ability.multiplying.stat.chance.title": "Split chance:", - "tooltip.relics.spore_sack.ability.multiplying.stat.chance.value": "%1$s%%.", - "tooltip.relics.spore_sack.ability.multiplying.stat.size.title": "Spore size:", - "tooltip.relics.spore_sack.ability.multiplying.stat.size.value": "%1$s%% of the main spore.", - "tooltip.relics.spore_sack.ability.multiplying.stat.amount.title": "Spore size degree:", - "tooltip.relics.spore_sack.ability.multiplying.stat.amount.value": "%1$s.", - "tooltip.relics.spore_sack.ability.explosion": "Poison Release", - "tooltip.relics.spore_sack.ability.explosion.description": "Empties the relic's buffer, releasing all accumulated spore charges into the world. The size of the released spores depends on the wearer's missing health.", - "tooltip.relics.spore_sack.ability.explosion.stat.size.title": "Spore size:", - "tooltip.relics.spore_sack.ability.explosion.stat.size.value": "%1$s per missing health point.", - "tooltip.relics.spore_sack.ability.explosion.predicate.spore": "Spores in the sack", + "tooltip.relics.spore_sack.description": "A simple burlap sack filled to the brim with deadly miasma.", + "tooltip.relics.spore_sack.ability.spore_mist": "Spore Mist", + "tooltip.relics.spore_sack.ability.spore_mist.description": "When the player's health drops below 50%, releases up to %1$s homing spores around them. These spores deal damage equal to %2$s%% of the player's missing health and block healing for affected targets for 5 seconds. The ability can trigger again once the player's health rises above 50%.", + "tooltip.relics.spore_sack.leveling_source.spore_mist.title": "Spore Mist", + "tooltip.relics.spore_sack.leveling_source.spore_mist.description": "+%1$s experience points for each successful hit by a spore from the %2$s ability.", "item.relics.ice_breaker": "Ice Breaker", "tooltip.relics.ice_breaker.description": "+1 experience point for every 3 blocks in the fall before triggering the ability «Earthquake».", @@ -278,8 +300,8 @@ "tooltip.relics.drowned_belt.description": "+1 experience point for each level of enchantment «Riptide» on the trident when using it.", "tooltip.relics.drowned_belt.ability.slots": "Load Capacity", "tooltip.relics.drowned_belt.ability.slots.description": "Increases the maximum number of slots for equipping relics.", - "tooltip.relics.drowned_belt.ability.slots.stat.talisman.title": "Talismans:", - "tooltip.relics.drowned_belt.ability.slots.stat.talisman.value": "+%1$s slots.", + "tooltip.relics.drowned_belt.ability.slots.stat.charm.title": "Charms:", + "tooltip.relics.drowned_belt.ability.slots.stat.charm.value": "+%1$s slots.", "tooltip.relics.drowned_belt.ability.anchor": "Dead Weight", "tooltip.relics.drowned_belt.ability.anchor.description": "Reduces the swimming speed and increases the sinking speed of the wearer.", "tooltip.relics.drowned_belt.ability.anchor.stat.slowness.title": "Slowing down swimming:", @@ -299,19 +321,19 @@ "tooltip.relics.hunter_belt.description": "+1 experience point for each attack made by the wearer's pet.", "tooltip.relics.hunter_belt.ability.slots": "Load Capacity", "tooltip.relics.hunter_belt.ability.slots.description": "Increases the maximum number of slots for equipping relics.", - "tooltip.relics.hunter_belt.ability.slots.stat.talisman.title": "Talismans:", - "tooltip.relics.hunter_belt.ability.slots.stat.talisman.value": "+%1$s slots.", + "tooltip.relics.hunter_belt.ability.slots.stat.charm.title": "Charms:", + "tooltip.relics.hunter_belt.ability.slots.stat.charm.value": "+%1$s slots.", "tooltip.relics.hunter_belt.ability.training": "Training", "tooltip.relics.hunter_belt.ability.training.description": "Increases the damage inflicted by the wearer's pets.", "tooltip.relics.hunter_belt.ability.training.stat.damage.title": "Damage multiplier:", "tooltip.relics.hunter_belt.ability.training.stat.damage.value": "+%1$s%%.", "item.relics.leather_belt": "Leather Belt", - "tooltip.relics.leather_belt.description": "+1 experience point for each experience gained by equipped talismans.", + "tooltip.relics.leather_belt.description": "+1 experience point for each experience gained by equipped charms.", "tooltip.relics.leather_belt.ability.slots": "Load Capacity", "tooltip.relics.leather_belt.ability.slots.description": "Increases the maximum number of slots for equipping relics.", - "tooltip.relics.leather_belt.ability.slots.stat.talisman.title": "Talismans:", - "tooltip.relics.leather_belt.ability.slots.stat.talisman.value": "+%1$s slots.", + "tooltip.relics.leather_belt.ability.slots.stat.charm.title": "Charms:", + "tooltip.relics.leather_belt.ability.slots.stat.charm.value": "+%1$s slots.", "item.relics.rage_glove": "Rage Glove", "tooltip.relics.rage_glove.description": "+1 experience point for every 3 charges from the ability «Berserker Rage» when they are reset.\n+1 experience point for each target hit by the «Spurt» ability.", @@ -420,9 +442,31 @@ "tooltip.relics.space_dissector.ability.dissection.stat.time.title": "Portal lifetime:", "tooltip.relics.space_dissector.ability.dissection.stat.time.value": "%1$s seconds", + "item.relics.phantom_boot": "Phantom Boot", + "tooltip.relics.phantom_boot.description": "Condenses matter beneath the relic owner's feet, creating a path through any terrain, even where no solid ground exists.", + "tooltip.relics.phantom_boot.ability.bridge": "Phantom Bridge", + "tooltip.relics.phantom_boot.ability.bridge.description": "Creates a temporary phantom bridge beneath the player's feet that any relic owner can walk on. If the player stands still on the bridge for more than %1$s seconds, they will fall through and cannot get back up until they reach solid ground.", + "tooltip.relics.phantom_boot.leveling_source.bridge.title": "Phantom Bridge", + "tooltip.relics.phantom_boot.leveling_source.bridge.description": "+%1$s experience points with a 10%% chance each time a bridge is created using the %2$s ability.", + + "item.relics.springy_boot": "Springy Boot", + "tooltip.relics.springy_boot.description": "Grants the relic owner special elasticity, allowing them to bounce off any solid surface.", + "tooltip.relics.springy_boot.ability.bounce": "Elasticity", + "tooltip.relics.springy_boot.ability.bounce.description": "Increases the elasticity of all blocks by %1$s%% compared to slime blocks, enabling the player to bounce off them upon landing. When activated on the ground, it launches the player into the air.", + "tooltip.relics.springy_boot.leveling_source.bounce.title": "Elasticity", + "tooltip.relics.springy_boot.leveling_source.bounce.description": "+%1$s experience points for each bounce off a surface using the %2$s ability.", + + "tooltip.relics.leveling_source.generic.spreading.title": "Experience Spreading", + "tooltip.relics.leveling_source.generic.spreading.description": "Each time any relic in the inventory gains experience, regardless of the method, %1$s%% of that experience is also gained by this relic.", + + "item.relics.leafy_ring": "Leafy Ring [WIP]", + "tooltip.relics.leafy_ring.description": "[WIP]", + "item.relics.relic_experience_bottle": "Relic Experience Bottle", - "block.relics.researching_table": "Researching Table", + "block.relics.phantom_block": "Phantom Bridge Block", + + "block.relics.researching_table": "Researching Table [Removed from the mod]", "effect.relics.stun": "Stun", "effect.relics.paralysis": "Paralysis", @@ -430,8 +474,12 @@ "effect.relics.vanishing": "Vanishing", "effect.relics.anti_heal": "Anti-Heal", "effect.relics.bleeding": "Bleeding", + "effect.relics.immortality": "Immortality", "command.relics.base.not_relic": "The item in hand must be a relic!", - "key.relics.ability_list": "Show the active abilities HUD" + "info.relics.researching.wrong_container": "Working with the relic in this inventory is not possible. Move item to the player's main inventory and try again.", + + "key.relics.active_abilities_list": "Show the active abilities HUD", + "key.relics.research_relic": "Research relic under the cursor" } diff --git a/src/main/resources/assets/relics/lang/es_es.json b/src/main/resources/assets/relics/lang/es_es.json index e6912af9..99e4b8e3 100644 --- a/src/main/resources/assets/relics/lang/es_es.json +++ b/src/main/resources/assets/relics/lang/es_es.json @@ -1,283 +1,492 @@ { - "itemGroup.relics": "Reliquias", - - "curios.identifier.talisman": "Talismán", - "curios.identifier.feet": "Pies", - - "tooltip.relics.relic.level": " [%1$s/%2$s]", - "tooltip.relics.relic.max_level": "MAX", - "tooltip.relics.relic.ability.level": " [%1$s/%2$s]", - "tooltip.relics.relic.leveling.title": "Ganancia de Experiencia: \n\n", - - "tooltip.relics.relic.upgrade.description": "Mejorar habilidad.", - "tooltip.relics.relic.upgrade.cost": "Costo: %2$s lvl, %1$s exp.", - - "tooltip.relics.relic.reroll.description": "Regeneración de estadísticas de una habilidad aleatoria.", - "tooltip.relics.relic.reroll.cost": "Costo: %1$s XP.", - - "tooltip.relics.relic.reset.description": "Resetear todos los puntos de habilidad.", - "tooltip.relics.relic.reset.cost": "Costo: %1$s XP.", - - "item.relics.infinity_ham": "Jamón de la Infinidad", - "tooltip.relics.infinity_ham.description": "Gana 1EXP cada vez que consumas una carga.", - "tooltip.relics.infinity_ham.lore": "Carne infinita regenerante de un origen desconocido - sabe a cerdo.", - "tooltip.relics.infinity_ham.ability.autophagy": "Regeneración", - "tooltip.relics.infinity_ham.ability.autophagy.description": "Usar la Reliquia consume cargas para reponer el hambre del portador. Las cargas se regeneran con el tiempo.", - "tooltip.relics.infinity_ham.ability.autophagy.stat.feed": "Saturación: %1$s unidades.", - "tooltip.relics.infinity_ham.ability.infusion": "Alquimia", - "tooltip.relics.infinity_ham.ability.infusion.description": "Usar una Poción en esta Reliquia, mientras está en tu inventario, la infunde con el efecto de la Poción. La infusión es perdida con el siguiente uso.", - "tooltip.relics.infinity_ham.ability.infusion.stat.duration": "Duración: %1$s segundos.", - - "item.relics.enders_hand": "Mano de Ender", - "tooltip.relics.enders_hand.description": "Gana 1EXP cada vez que uses la habilidad de esta Reliquia. Incrementa la experiencia recibida por el 10% de la distancia recorrida con ella.", - "tooltip.relics.enders_hand.lore": "Un guantelete forjado por una civilización Ender perdida, que también trajo la perdición sobre ella.", - "tooltip.relics.enders_hand.ability.neutrality": "Neutralidad", - "tooltip.relics.enders_hand.ability.neutrality.description": "Hace a los Endermans neutrales ante el portador.", - "tooltip.relics.enders_hand.ability.swap": "Transposición del End", - "tooltip.relics.enders_hand.ability.swap.description": "Cambia la posición del portador con la de su objetivo", - "tooltip.relics.enders_hand.ability.swap.stat.distance": "Distancia: %1$s bloques.", - - "item.relics.holy_locket": "Relicario Sagrado", - "tooltip.relics.holy_locket.description": "Gana 1EXP por cada HP robada con esta habilidad. (La cantidad de HP es redondeada).", - "tooltip.relics.holy_locket.lore": "Una brillante cruz creada con los metales de Golgotha. Da fuerza a los justos, y agonía a los que no lo son.", - "tooltip.relics.holy_locket.ability.steal": "Bendición Divina", - "tooltip.relics.holy_locket.ability.steal.description": "Roba un porcentaje de vida regenerada por criaturas cercanas.", - "tooltip.relics.holy_locket.ability.steal.stat.amount": "Cantidad: %1$s %% de Vida Regenerada.", - "tooltip.relics.holy_locket.ability.steal.stat.radius": "Radio: %1$s bloques.", - - "item.relics.magic_mirror": "Espejo Mágico", - "tooltip.relics.magic_mirror.description": "Gana 1EXP cada vez que uses la habilidad de esta Reliquia. Incrementa la EXP recibida por 1 por cada 50 bloques viajados con la habilidad de esta Reliquia.", - "tooltip.relics.magic_mirror.lore": "Un espejo una vez poseído por poderosos videntes, que fue encantado con la habilidad del viaje interdimensional.", - "tooltip.relics.magic_mirror.ability.teleport": "Agujero de Gusano", - "tooltip.relics.magic_mirror.ability.teleport.description": "Teleporta al portador al lugar de reaparición al ser usado.", - "tooltip.relics.magic_mirror.ability.teleport.stat.distance": "Distancia: %1$s bloques.", - "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown": "Cooldown: %1$s segundos.", - - "item.relics.shadow_glaive": "Aguja Sombría", - "tooltip.relics.shadow_glaive.description": "Gana 1EXP por cada 2 rebotes de la Aguja.", - "tooltip.relics.shadow_glaive.lore": "Un arma creada por una civilización Ender perdida para suprimir rebeliones. Aunque los creadores nunca tuvieron la oportunidad de ponerlo en uso.", - "tooltip.relics.shadow_glaive.ability.glaive": "Justicia Ciega", - "tooltip.relics.shadow_glaive.ability.glaive.description": "Al usar una de las 8 cargas saldrán agujas que rebotarán en criaturas cercanas.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.damage": "Daño: %1$s.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.recharge": "Recarga: %1$s segundos.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.bounces": "Rebotes: %1$s.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.radius": "Radio de Rebote: %1$s bloques.", - "tooltip.relics.shadow_glaive.ability.saw": "Castigo Despiadado", - "tooltip.relics.shadow_glaive.ability.saw.description": "Consume todas las 8 cargas y deshabilita su regeneración temporalmente para invocar una sierra que daña a entidades cercanas.", - "tooltip.relics.shadow_glaive.ability.saw.stat.speed": "Velocidad de Ataque: %1$s golpes por segundo.", - "tooltip.relics.shadow_glaive.ability.saw.stat.damage": "Daño: %1$s puntos.", - - "item.relics.arrow_quiver": "Carcaj", - "tooltip.relics.arrow_quiver.description": "Gana 1EXP por cada 10 bloques entre el portador y el objetivo.", - "tooltip.relics.arrow_quiver.lore": "Un atributo esencial de un arquero. Creada con una tecnología élfica con la piel de una bestia mística extinta.", - "tooltip.relics.arrow_quiver.ability.receptacle": "Almacenamiento de Flechas", - "tooltip.relics.arrow_quiver.ability.receptacle.description": "Al disparar un arco se priorizan las flechas almacenadas en el Carcaj. Hacer click-izquierdo en un Carcaj con una flecha la almacenará dentro de este, mientras que hacer click-derecho sacará la flecha más reciente.", - "tooltip.relics.arrow_quiver.ability.receptacle.stat.slots": "Ranura: %1$s.", - "tooltip.relics.arrow_quiver.ability.agility": "Agilidad", - "tooltip.relics.arrow_quiver.ability.agility.description": "Incrementa la velocidad de tensado de la cuerda en un arco.", - "tooltip.relics.arrow_quiver.ability.agility.stat.modifier": "Multiplicador de velocidad: %1$s %%.", - - "item.relics.blazing_flask": "Frasco Flameante", - "tooltip.relics.blazing_flask.description": "Gana 1EXP por cada 5 segundos de vuelo con esta habilidad.", - "tooltip.relics.blazing_flask.lore": "La maravilla de la ingeniería de la civilización Piglin, que transformó un Bosque Carmesí en ruinas durante las pruebas.", - "tooltip.relics.blazing_flask.ability.bonfire": "Llama Eterna", - "tooltip.relics.blazing_flask.ability.bonfire.description": "Usar esta Reliquia en un bloque creará una zona de vuelo restringida basada en la cantidad de fuego cercano.", - "tooltip.relics.blazing_flask.ability.bonfire.stat.step": "Radio de dirección del fuego: %1$s bloques.", - "tooltip.relics.blazing_flask.ability.bonfire.stat.speed": "Velocidad de vuelo: %1$s bloques por segundo.", - "tooltip.relics.blazing_flask.ability.bonfire.stat.height": "Altura de vuelo: %1$s bloques.", - - "item.relics.elytra_booster": "Impulsador de Élitros", - "tooltip.relics.elytra_booster.description": "Gana 1EXP por cada 10 segundos de combustible quemado colocado en el almacenamiento interno de esta reliquia.", - "tooltip.relics.elytra_booster.lore": "El alma de la llama está encerrada de manera segura con un mecanismo desconocido.", - "tooltip.relics.elytra_booster.ability.boost" : "Impulso", - "tooltip.relics.elytra_booster.ability.boost.description": "Usando combustible en esta Reliquia, rellena su almacenamiento interno. Manteniendo pulsado [Shift] mientras vuelas con unos élitros te propulsará hacia adelante.", - "tooltip.relics.elytra_booster.ability.boost.stat.capacity": "Capacidad: %1$s unidades.", - "tooltip.relics.elytra_booster.ability.boost.stat.speed": "Velocidad: %1$s bloques por segundo.", - - "item.relics.midnight_robe": "Túnica de Medianoche", - "tooltip.relics.midnight_robe.description": "Gana 1EXP cada vez que hagas un ataque sigiloso de Desaparición.", - "tooltip.relics.midnight_robe.lore": "Túnica de un astrónomo curtido con un mapa bordado del cielo.", - "tooltip.relics.midnight_robe.ability.vanish": "Desaparición", - "tooltip.relics.midnight_robe.ability.vanish.description": "El portador se vuelve invisible al estar en completa oscuridad.", - "tooltip.relics.midnight_robe.ability.vanish.stat.light": "Nivel de Luz Mínimo: %1$s.", - "tooltip.relics.midnight_robe.ability.vanish.stat.speed": "Multiplicador de velocidad: %1$s %%.", - "tooltip.relics.midnight_robe.ability.backstab": "Traición", - "tooltip.relics.midnight_robe.ability.backstab.description": "Ataques de Desaparición hacen el doble de daño. Solo se puede volver a usar Desaparición después de salir del círculo.", - "tooltip.relics.midnight_robe.ability.backstab.stat.damage": "Multiplicador de Daño: %1$s %%.", - "tooltip.relics.midnight_robe.ability.backstab.stat.distance": "Radio del Círculo: %1$s blocks.", - - "item.relics.reflection_necklace": "Amuleto Reflectante", - "tooltip.relics.reflection_necklace.description": "Gana 1EXP por cada 20 puntos de daño acumulados en el almacenamiento interno de la habilidad Odio Infernal de esta Reliquia.", - "tooltip.relics.reflection_necklace.lore": "Forjado en las llameantes profundidades de una prisión infernal, este amuleto está infundido con la malicia y el odio de sus creadores. Una mezcla de obsidiana y escombros ancestrales la hace increíblemente resistente, mientras que el diamante incrustado permite a la Reliquia cortar carne humana como mantequilla." , - "tooltip.relics.reflection_necklace.ability.explode": "Odio Infernal", - "tooltip.relics.reflection_necklace.ability.explode.description": "Acumula daño recibido en un almacenamiento interno. 5 segundos después del último daño recibido, o cuando el almacenamiento se llena al máximo, la reliquia explota, enviando fragmentos de obsidiana en todas direcciones, haciendo daño y aturdiendo enemigos. La cantidad de daño y la duración de aturdimiento de los fragmentos depende de la cantidad de daño acumulado en el almacenamiento interno de la Reliquia.", - "tooltip.relics.reflection_necklace.ability.explode.stat.capacity": "Cantidad de Daño: %1$s unidades.", - - "item.relics.jellyfish_necklace": "Colgante de Medusa", - "tooltip.relics.jellyfish_necklace.description": "Gana 1EXP cada vez que esta Reliquia dañe a alguien.", - "tooltip.relics.jellyfish_necklace.lore": "Una Reliquia de la familia de las Sirenas. Hecha con perlas, y mantenida intacta con la voluntad de un portador de medusas cuya tortuosa agonía resuena con pulsos de electricidad.", - "tooltip.relics.jellyfish_necklace.ability.unsinkable": "Poder del Mar", - "tooltip.relics.jellyfish_necklace.ability.unsinkable.description": "El portador no se hunde en el agua.", - "tooltip.relics.jellyfish_necklace.ability.shock": "Descarga Eléctrica", - "tooltip.relics.jellyfish_necklace.ability.shock.description": "Hace daño a cualquiera que toque al portador.", - "tooltip.relics.jellyfish_necklace.ability.shock.stat.damage": "Daño: %1$s puntos.", - "tooltip.relics.jellyfish_necklace.ability.paralysis": "Parálisis", - "tooltip.relics.jellyfish_necklace.ability.paralysis.description": "Descarga Eléctrica deshabilita el movimiento del objetivo cuando es activada.", - "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration": "Duración del Efecto: %1$s segundos.", - - "item.relics.spore_sack": "Saco de Esporas", - "tooltip.relics.spore_sack.description": "Gana 1EXP por cada objetivo ralentizado en la Nube Venenosa.", - "tooltip.relics.spore_sack.lore": "Un saco de semillas que brota esporas de setas mortales.", - "tooltip.relics.spore_sack.ability.spore": "Síntesis de Veneno", - "tooltip.relics.spore_sack.ability.spore.description": "Cuando el portador es dañado, lanza esporas en una dirección aleatoria creando una Nube Venenosa al impactar contra el suelo, haciendo daño y ralentizando a objetivos en su rango.", - "tooltip.relics.spore_sack.ability.spore.stat.amount": "Cantidad de esporas: %1$s.", - "tooltip.relics.spore_sack.ability.spore.stat.resize": "Radio de reducción: %1$s %% por segundo.", - - "item.relics.ice_breaker": "Rompehielos", - "tooltip.relics.ice_breaker.description": "Gana 1EXP por cada 3 bloques caídos usando la habilidad Terremoto.", - "tooltip.relics.ice_breaker.lore": "Zapatos hechos con piel de oso pardo, reforzados con placas de acero y pinchos para atravesar glaciares y colinas heladas.", - "tooltip.relics.ice_breaker.ability.sustainability" : "Sustentabilidad", - "tooltip.relics.ice_breaker.ability.sustainability.description": "Incrementa la distancia de retroceso, remueve el resbalamiento en bloques, e incrementa la velocidad de caida.", - "tooltip.relics.ice_breaker.ability.sustainability.stat.modifier": "Resistencia al Retroceso: %1$s %%.", - "tooltip.relics.ice_breaker.ability.impact": "Terremoto", - "tooltip.relics.ice_breaker.ability.impact.description": "Manteniendo pulsado [Shift] mientras caes crea una onda de choque al aterrizar, que daña y empuja a enemigos. El radio de la onda depende de la distancia vertical que el portador haya recorrido.", - "tooltip.relics.ice_breaker.ability.impact.stat.size": "Radio máximo: %1$s bloques.", - "tooltip.relics.ice_breaker.ability.impact.stat.damage": "Daño Inicial: %1$s puntos.", - - "item.relics.bastion_ring": "Anillo del Bastión", - "tooltip.relics.bastion_ring.description": "Gana 1/5/10EXP por cada Piglin/Piglin Bruto/Piglin Zombificado asesinado.\nGana 1EXP extra por cada negociación con la habilidad Respeto.", - "tooltip.relics.bastion_ring.lore": "Un anillo brillante hecho con granito pulido y decorado con pepitas de oro", - "tooltip.relics.bastion_ring.ability.compass": "Reconocimiento", - "tooltip.relics.bastion_ring.ability.compass.description": "Hace a los Piglins neutrales ante el portador. El Piglin más cercano indicará la dirección del bastión más próximo.", - "tooltip.relics.bastion_ring.ability.trade": "Respeto", - "tooltip.relics.bastion_ring.ability.trade.description": "Cada intercambio con Piglins tiene una probabilidad de generar un resultado de intercambio adicional.", - "tooltip.relics.bastion_ring.ability.trade.stat.rolls": "Intercambios adicionales máximos: %1$s.", - - "item.relics.horse_flute": "Flauta de Caballo", - "tooltip.relics.horse_flute.description": "Gana 1EXP por cada 25 bloques recorridos por un caballo llamado con la habilidad Establo Portátil.", - "tooltip.relics.horse_flute.lore": "Una flauta mágica cuyo sonido fue capaz de controlar a todo ser viviente. Sin embargo, ahora solo los caballos pueden ser domados con ella.", - "tooltip.relics.horse_flute.ability.paddock": "Establo Portátil", - "tooltip.relics.horse_flute.ability.paddock.description": "Usar esta Reliquia en un caballo moverá al animal al almacenamiento interno. Usarla de nuevo liberará a la criatura. Si la distancia entre el dueño y el caballo invocado es demasiado grande, el animal volverá automáticamente al interior de la flauta.", - "tooltip.relics.horse_flute.ability.paddock.stat.slots": "Ranuras: %1$s.", - "tooltip.relics.horse_flute.ability.heal": "Trama Curativa", - "tooltip.relics.horse_flute.ability.heal.description": "Dentro del almacenamiento interno, el caballo regenerará su salud lentamente.", - "tooltip.relics.horse_flute.ability.heal.stat.amount": "Curando: %1$s puntos de vida por segundo.", - - "item.relics.magma_walker": "Caminantes de Lava", - "tooltip.relics.magma_walker.description": "Gana 1EXP por cada 5 de calor acumulado por la habilidad Paso Llameante.", - "tooltip.relics.magma_walker.lore": "Las botas de placas de un valiente caballero que ha caído mientras luchaba por la Fortaleza Infernal, cuyo espíritu fue condenado a rondar los valles abrasadores del Infierno por siempre. El calor y las llamas dotaron al metal con una increíble resistencia al fuego, repeliendo todo tipo de calor como los polos de un imán." , - "tooltip.relics.magma_walker.ability.pace": "Paso Llameante", - "tooltip.relics.magma_walker.ability.pace.description": "Permite al portador caminar por la superficie de la lava por un periodo de tiempo sin sumergirse en ella recibiendo daño. Después de que el tiempo expira, las botas empiezan a sobrecalentarse y empieza a dañar al portador proporcionalmente con el nivel de sobrecalentamiento. Suprime el daño de bloques calientes.", - "tooltip.relics.magma_walker.ability.pace.stat.heat": "Calor Máximo: %1$s.", - - "item.relics.aqua_walker": "Caminantes de Agua", - "tooltip.relics.aqua_walker.description": "Gana 1EXP por cada 5 mojaduras de la habilidad Impermeable.", - "tooltip.relics.aqua_walker.lore": "Botas tejidas con telas mágicas de la superficie del mar, la ligereza de estas ha permanecido incomparable ante cualquier cosa en la Tierra hasta el día de hoy.", - "tooltip.relics.aqua_walker.ability.walking" : "Impermeable", - "tooltip.relics.aqua_walker.ability.walking.description": "Te permite caminar en la superficie del agua por un tiempo determinado sin sumergirte. Después de que el tiempo expire, las botas se empezarán a hundir, tirando al portador hacia abajo.", - "tooltip.relics.aqua_walker.ability.walking.stat.time": "Duración: %1$s segundos.", - - "item.relics.drowned_belt": "Cinturón del Ahogado", - "tooltip.relics.drowned_belt.description": "Gana 1EXP por cada nivel de encantamiento del Tridente equipado.", - "tooltip.relics.drowned_belt.lore": "Fragmento de grilletes de un prisionero inundado cuyo cuerpo desfigurado flotó a tierra firme durante la procesión de los muertos bajo la luz de una luna llena de sangre.", - "tooltip.relics.drowned_belt.ability.slots": "Capacidad de Peso", - "tooltip.relics.drowned_belt.ability.slots.description": "Incrementa la cantidad de ranuras de Reliquias máxima.", - "tooltip.relics.drowned_belt.ability.slots.stat.talisman": "Reliquias: %1$s.", - "tooltip.relics.drowned_belt.ability.anchor": "Peso Muerto", - "tooltip.relics.drowned_belt.ability.anchor.description": "Decrementa la velocidad de nado mientras que incrementa la velocidad de hundimiento del portador.", - "tooltip.relics.drowned_belt.ability.anchor.stat.slowness": "Nado Lento: %1$s %%.", - "tooltip.relics.drowned_belt.ability.anchor.stat.sinking": "Radio de Hundimiento: %1$s %%.", - "tooltip.relics.drowned_belt.ability.pressure": "Corrientes de Agua", - "tooltip.relics.drowned_belt.ability.pressure.description": "Incrementa el daño bajo el agua.", - "tooltip.relics.drowned_belt.ability.pressure.stat.damage": "Multiplicador de Daño: %1$s %%.", - "tooltip.relics.drowned_belt.ability.riptide": "Tirón de Agua", - "tooltip.relics.drowned_belt.ability.riptide.description": "Permite que la habilidad Propulsión Acuática del Tridente pueda ser usada incondicionalmente, pero le añade un cooldown.", - "tooltip.relics.drowned_belt.ability.riptide.stat.cooldown": "Tiempo de Cooldown: %1$s segundos por cada nivel de encantamiento.", - - "item.relics.hunter_belt": "Cinturón de cazador", - "tooltip.relics.hunter_belt.description": "Gana 1EXP por cada ataque de la mascota del portador", - "tooltip.relics.hunter_belt.lore": "Un cinturón hecho de un material desconocido que crea un vínculo espiritual entre el portador y todas sus mascotas, otorgándoles incomparable fuerza y aguante.", - "tooltip.relics.hunter_belt.ability.slots": "Capacidad", - "tooltip.relics.hunter_belt.ability.slots.description": "Aumenta la cantidad de ranuras para Reliquias máxima.", - "tooltip.relics.hunter_belt.ability.slots.stat.talisman": "Reliquias: %1$s.", - "tooltip.relics.hunter_belt.ability.training": "Entrenando", - "tooltip.relics.hunter_belt.ability.training.description": "Incrementa el daño infligido por las mascotas de portador.", - "tooltip.relics.hunter_belt.ability.training.stat.damage": "Multiplicador de Daño: %1$s %%.", - - "item.relics.leather_belt": "Cinturón de Cuero", - "tooltip.relics.leather_belt.description": "Gana 1EXP por cada punto de experiencia ganado por Reliquias equipadas.", - "tooltip.relics.leather_belt.lore": "Una simple pieza de cuero adornado con una hebilla de oro brillante. Increíblemente cómodo y elegante al mismo tiempo.", - "tooltip.relics.leather_belt.ability.slots": "Capacidad de Peso", - "tooltip.relics.leather_belt.ability.slots.description": "Incrementa la cantidad de ranuras de Reliquias máxima.", - "tooltip.relics.leather_belt.ability.slots.stat.talisman": "Reliquias: %1$s.", - - "item.relics.rage_glove": "Guante de Furia", - "tooltip.relics.rage_glove.description": "Gana 1EXP por cada 3 cargas de Rabia del Enoquecido cuando están anuladas.", - "tooltip.relics.rage_glove.lore": "Un guantelete abrumadoramente peligroso que nubla la mente del portador. Despierta la rabia primal y sed de sangre del portador. Consume la vitalidad del portador y la drena hasta que muere, y luego espera a su siguiente víctima, quien será tentada por el incomparable poder de esta Reliquia.", - "tooltip.relics.rage_glove.ability.rage": "Rabia del Enloquecido", - "tooltip.relics.rage_glove.ability.rage.description": "Cada ataque consecutivo en un lapso de 3 segundos con el último golpe acumula 1 carga en el almacenamiento interno de la Reliquia. El daño infligido y recibido del portador, al igual que su velocidad de ataque y movimiento, son incrementados proporcionalmente. Si pasan 3 segundos, el almacenamiento interno de la reliquia quedará agotado, anulando cualquier bonus recibido.", - "tooltip.relics.rage_glove.ability.rage.stat.incoming_damage": "Multiplicador de Daño Recibido: %1$s %% por carga.", - "tooltip.relics.rage_glove.ability.rage.stat.dealt_damage": "Multiplicador de Daño: %1$s %% por carga.", - "tooltip.relics.rage_glove.ability.rage.stat.movement_speed": "Multiplicador de Velocidad de Movimiento: %1$s %% por carga.", - "tooltip.relics.rage_glove.ability.rage.stat.attack_speed": "Multiplicador de Velocidad de Ataque: %1$s %% por carga.", - - "item.relics.ice_skates": "Skates de Hielo", - "tooltip.relics.ice_skates.description": "Gana 1EXP por cada segundo resbalando con la habilidad de esta Reliquia.", - "tooltip.relics.ice_skates.lore": "Skates ordinarios que sólo revelan su verdadero potencial al ser usados, con cuchillas afiladas capaces de cortar tanto carne como hielo.", - "tooltip.relics.ice_skates.ability.skating": "Resbalando", - "tooltip.relics.ice_skates.ability.skating.description": "Incrementa la velocidad de movimiento en el Hielo basado en el tiempo que te hayas deslizado.", - "tooltip.relics.ice_skates.ability.skating.stat.speed": "Multiplicador de velocidad: %1$s %% por cada segundo de resbalamiento.", - "tooltip.relics.ice_skates.ability.skating.stat.duration": "Multiplicadores máximos: %1$s.", - "tooltip.relics.ice_skates.ability.ram": "Ariete", - "tooltip.relics.ice_skates.ability.ram.description": "Al chocar con el objetivo, infringe daño proporcional a la velocidad de deslizamiento.", - "tooltip.relics.ice_skates.ability.ram.stat.damage": "Daño: %1$s puntos por cada segundo de deslizamiento.", - - "item.relics.amphibian_boot": "Botas de Anfibio", - "tooltip.relics.amphibian_boot.description": "Gana 1EXP cada segundo que la habilidad de esta Reliquia esté activada.", - "tooltip.relics.amphibian_boot.lore": "Caminando a las costas pobladas, estas botas espera por su presa y la arrastra hacia las profundidades más profundas de las impenetrables profundidades del mar, sin dejar ninguna posibilidad de escape.", - "tooltip.relics.amphibian_boot.ability.swimming": "Aletas", - "tooltip.relics.amphibian_boot.ability.swimming.description": "Incrementa la velocidad de nado basada en la duración.", - "tooltip.relics.amphibian_boot.ability.swimming.stat.speed": "Multiplicador de velocidad: %1$s %% por segundo.", - - "item.relics.spatial_sign": "Signo Espacial", - "tooltip.relics.spatial_sign.description": "Gana 1EXP por cada segundo retornado por la Grieta del Tiempo.", - "tooltip.relics.spatial_sign.lore": "El Sello que una vez selló las puertas del Infierno se volvió una poderosa Reliquia, capaz de cortar a través del tiempo y del espacio con facilidad. No tomó mucho para aquellos en necesidad de este poder para obtener esta Reliquia, dejando las puertas del Infierno abiertas hasta el día de hoy…", - "tooltip.relics.spatial_sign.ability.seal": "Grieta del Tiempo", - "tooltip.relics.spatial_sign.ability.seal.stat.time": "La duración máxima son %1$s degundos.", - - "item.relics.chorus_inhibitor": "Inhibidor Coral", - "tooltip.relics.chorus_inhibitor.description": "Gana 1EXP por cada 10 bloques teleportados con la habilidad de esta Reliquia.", - "tooltip.relics.chorus_inhibitor.lore": "Una inflorescencia de una planta desconocida que es capaz de moverse independientemente con sus tentáculos. Adora la fruta coral. A pesar de su origen, tiene un número de rasgos de humano desfigurado.", - "tooltip.relics.chorus_inhibitor.ability.blink": "Control de Teleportación", - "tooltip.relics.chorus_inhibitor.ability.blink.description": "Al usar Fruta Coral teleporta al portador al bloque apuntado.", - "tooltip.relics.chorus_inhibitor.ability.blink.stat.distance": "Distancia máxima: %1$s bloques.", - "tooltip.relics.chorus_inhibitor.ability.blink.stat.cooldown": "Tiempo de Cooldown: %1$s segundos.", - - "item.relics.wool_mitten": "Manopla de Lana", - "item.relics.solid_snowball": "Bola de Nieve Helada", - "tooltip.relics.wool_mitten.description": "Gana 1EXP por cada nivel 5 de tamaño al ser golpeado con una bola de nieve de Esculpir.", - "tooltip.relics.wool_mitten.lore": "Un guante hecho de lana de un yeti de montaña asesinado. Manteniendo el interior cálido, puede crear frío hirviendo en el exterior.", - "tooltip.relics.wool_mitten.ability.mold": "Moldando", - "tooltip.relics.wool_mitten.ability.mold.description": "Recoger nieve con la mano vacía forma gradualmente unas duras y especiales bolas de nieve. Golpear a un objetivo con semejante bola de nieve le infringirá daño, aturdirá, y congelará. Sostener una bola de nieve sin llevar la Reliquia equipada también congelará al portador." , - "tooltip.relics.wool_mitten.ability.mold.stat.size": "Tamaño máximo: %1$s unidades.", - "tooltip.relics.wool_mitten.ability.mold.stat.damage": "Daño: %1$s por cada tamaño.", - "tooltip.relics.wool_mitten.ability.mold.stat.stun": "Aturdimiento: %1$s segundos por cada nivel de tamaño.", - "tooltip.relics.wool_mitten.ability.mold.stat.freeze": "Congelación: %1$s segundos por tamaño.", - - "item.relics.roller_skates": "Patines", - "tooltip.relics.roller_skates.description": "Gana 1EXP por cada segundo que la habilidad de esta Reliquia esté activada.", - "tooltip.relics.roller_skates.lore": "Botas regulares con ruedas que una vez aceleradas - no pararán.", - "tooltip.relics.roller_skates.ability.skating": "Overclocking", - "tooltip.relics.roller_skates.ability.skating.description": "Incrementa la velocidad de movimiento gradualmente con el tiempo mientras se esprinta.", - "tooltip.relics.roller_skates.ability.skating.stat.speed": "Multiplicador de velocidad: %1$s %% por cada segundo de overclocking.", - "tooltip.relics.roller_skates.ability.skating.stat.duration": "Multiplicadores Máximos: %1$s.", - - "block.relics.researching_table": "Mesa de Investigación", - - "effect.relics.stun": "Aturdir", - "effect.relics.paralysis": "Parálisis", - "effect.relics.confusion": "Confusión", - "effect.relics.vanishing": "Desvanecimiento", - - "command.relics.base.not_relic": "¡El objeto en la mano debe ser una Reliquia!" + "itemGroup.relics": "Reliquias", + + "curios.identifier.feet": "Pies", + + "tooltip.relics.researching.info": "Mantén [Shift] para investigar...", + + "tooltip.relics.relic.tooltip.abilities": "Habilidades:", + + "tooltip.relics.researching.badge.ability.oblivion.title": "Vulnerabilidad a la Oblivión", + "tooltip.relics.researching.badge.ability.oblivion.description": "La habilidad no funcionará bajo el efecto de Oblivión.", + "tooltip.relics.researching.badge.ability.silence.title": "Vulnerabilidad al Silencio", + "tooltip.relics.researching.badge.ability.silence.description": "La habilidad no funcionará bajo el efecto de Silencio.", + "tooltip.relics.researching.badge.ability.flawless_ability.title": "Habilidad Perfecta", + "tooltip.relics.researching.badge.ability.flawless_ability.description": "La habilidad ha alcanzado parámetros perfectos. ¡Enorgullécete de ti mismo!", + "tooltip.relics.researching.badge.ability.instantaneous.title": "Uso Instantáneo", + "tooltip.relics.researching.badge.ability.instantaneous.description": "La habilidad se activa inmediatamente al usarla.", + "tooltip.relics.researching.badge.ability.interruptible.title": "Uso Interrumpible", + "tooltip.relics.researching.badge.ability.interruptible.description": "La habilidad dura un tiempo determinado después de ser usada y puede interrumpirse con un uso repetido.", + "tooltip.relics.researching.badge.ability.cyclical.title": "Uso Cíclico", + "tooltip.relics.researching.badge.ability.cyclical.description": "La habilidad funciona únicamente con uso continuo.", + "tooltip.relics.researching.badge.ability.toggleable.title": "Uso Alternable", + "tooltip.relics.researching.badge.ability.toggleable.description": "La habilidad se puede activar o desactivar al usarse.", + "tooltip.relics.researching.badge.ability.chargeable.title": "Uso Cargable", + "tooltip.relics.researching.badge.ability.chargeable.description": "La habilidad se activa instantáneamente después de un tiempo de uso cíclico. El resultado puede depender de la duración del uso.", + "tooltip.relics.researching.badge.ability.stated.title": "Uso Modulado", + "tooltip.relics.researching.badge.ability.stated.description": "La habilidad tiene varios modos que cambian con cada uso.", + + "tooltip.relics.researching.badge.relic.flawless_relic.title": "Reliquia Perfecta", + "tooltip.relics.researching.badge.relic.flawless_relic.description": "La reliquia ha alcanzado parámetros perfectos. ¡Enorgullécete de ti mismo!", + + "tooltip.relics.researching.research.tip": "Para desbloquear la habilidad, es necesario conectar las estrellas ocultas bajo la niebla de tal manera que la constelación resultante coincida con la imagen del fondo. Cuando la constelación esté correctamente alineada, la habilidad será investigada automáticamente.", + + "tooltip.relics.researching.research.hint.description": "Pista", + "tooltip.relics.researching.research.hint.cost": "Costo: %1$s niveles de experiencia %2$s.", + "tooltip.relics.researching.research.hint.quick": "Mantén [Shift] para investigar automáticamente la habilidad.", + "tooltip.relics.researching.research.hint.locked": "¡La habilidad ya ha sido investigada!", + + "tooltip.relics.researching.badge.ability.cast_type.hint": "¡Usa la tecla [%1$s] fuera de cualquier interfaz para abrir el menú de habilidades activas!", + + "tooltip.relics.researching.general.leveling_point.title": "Puntos de Nivelación:", + "tooltip.relics.researching.general.leveling_point.extra_info": "Se obtienen al subir de nivel la reliquia y se usan para mejorar habilidades.", + + "tooltip.relics.researching.general.player_experience.title": "Nivel de Experiencia:", + "tooltip.relics.researching.general.player_experience.extra_info": "Experiencia estándar del jugador en el juego base. Se obtiene al matar mobs, minar minerales, fundir objetos, etc.", + + "tooltip.relics.researching.general.luck.title": "Suerte:", + "tooltip.relics.researching.general.luck.extra_info": "Se incrementa con cada intento fallido de volver a lanzar estadísticas aleatorias de reliquias, aumentando las probabilidades de obtener mejores estadísticas en el próximo intento. Incrementa el costo del relanzamiento en 1 nivel de experiencia por cada 25% de suerte.", + + "tooltip.relics.researching.relic.card.low_level": "¡Para desbloquear, necesitas subir la reliquia al nivel %1$s!", + "tooltip.relics.researching.relic.card.no_stats": "¡La habilidad no tiene estadísticas mejorables y no afecta la calidad de la reliquia!", + "tooltip.relics.researching.relic.card.unresearched": "¡Para usar, necesitas realizar la investigación!", + "tooltip.relics.researching.relic.card.ready_to_unlock": "¡La habilidad está lista para ser desbloqueada! Clics restantes: %1$s", + "tooltip.relics.researching.relic.card.ready_to_upgrade": "¡La habilidad está lista para ser mejorada!", + + "tooltip.relics.researching.relic.gem.low_level": "¡Para desbloquear la fuente de experiencia, necesitas subir la reliquia al nivel %1$s!", + "tooltip.relics.researching.relic.gem.locked_ability": "¡Para desbloquear la fuente de experiencia, necesitas desbloquear e investigar la habilidad asociada!", + + "tooltip.relics.researching.tab.relic": "Reliquia", + "tooltip.relics.researching.tab.ability": "Habilidades", + "tooltip.relics.researching.tab.experience": "Fuentes de Experiencia", + + "tooltip.relics.researching.general.extra_info": "Mantén [Shift] para más información", + + "tooltip.relics.researching.relic.info.level": "Nivel de la Reliquia:", + "tooltip.relics.researching.relic.info.quality": "Calidad de la Reliquia:", + "tooltip.relics.researching.relic.info.extra_info": "La calidad de la reliquia es el promedio aritmético de la calidad de todas las habilidades desbloqueadas actualmente y se mide en puntos de 1 a 5 con un paso de 0.5. Es una métrica visual que muestra qué tan cerca están las características iniciales aleatorias del objeto de las mejores posibles. Para mejorar la calidad general de la reliquia, cada habilidad debe considerarse por separado.", + + "tooltip.relics.researching.relic.experience.title": "Experiencia de la Reliquia:", + "tooltip.relics.researching.relic.experience.extra_info": "Se obtiene al usar las habilidades de la reliquia según lo previsto (más detalles se pueden encontrar en la página de fuentes de experiencia). Al alcanzar el valor máximo de experiencia, el nivel de la reliquia y el grupo de puntos de mejora aumentan en 1, permitiéndote desbloquear habilidades previamente no disponibles o mejorar las existentes.", + + "tooltip.relics.researching.ability.info.level": "Nivel de la Habilidad:", + "tooltip.relics.researching.ability.info.quality": "Calidad de la Habilidad:", + "tooltip.relics.researching.ability.info.extra_info": "La calidad de la habilidad, similar a la calidad de la reliquia, es el promedio aritmético de todas las características actuales de la habilidad y se mide en puntos de 1 a 5 con un paso de 0.5. Es una métrica visual que muestra qué tan cerca están las características iniciales aleatorias de la habilidad de las mejores posibles. Para mejorar la calidad de la habilidad, necesitas restablecer sus características aleatorias hasta obtener un mejor valor.", + + "tooltip.relics.relic.status.positive": "§2§l[§2§l✔§2§l]", + "tooltip.relics.relic.status.negative": "§4§l[§4§l✘§4§l]", + "tooltip.relics.relic.status.unknown": "§6§l[§6§l?§6§l]", + + "tooltip.relics.relic.upgrade.description": "Subir de Nivel", + "tooltip.relics.relic.upgrade.cost": "Costo: %1$s puntos de nivelación %2$s, %3$s niveles de experiencia %4$s.", + "tooltip.relics.relic.upgrade.locked": "La habilidad ha alcanzado su nivel máximo.", + "tooltip.relics.relic.upgrade.quick": "Mantén [Shift] para mejorar automáticamente al nivel más alto posible.", + + "tooltip.relics.relic.reroll.description": "Relanzar estadísticas aleatorias", + "tooltip.relics.relic.reroll.cost": "Costo: %1$s niveles de experiencia %2$s.", + "tooltip.relics.relic.reroll.quick": "Mantén [Shift] para relanzar automáticamente las estadísticas aleatorias a valores perfectos.", + "tooltip.relics.relic.reroll.warning": "Mantén [Shift] para confirmar el relanzamiento de estadísticas desde valores perfectos a otros aleatorios.", + + "tooltip.relics.relic.reset.description": "Restablecer puntos de nivelación", + "tooltip.relics.relic.reset.cost": "Costo: %1$s niveles de experiencia %2$s.", + "tooltip.relics.relic.reset.locked": "Para usar, necesitas subir de nivel esta habilidad al menos una vez.", + + "item.relics.infinity_ham": "Jamón Infinito", + "tooltip.relics.infinity_ham.description": "Un misterioso trozo de carne que se regenera suavemente hasta su tamaño original, sin importar cuánto cortes.", + "tooltip.relics.infinity_ham.ability.regeneration": "Regeneración", + "tooltip.relics.infinity_ham.ability.regeneration.description": "Cada %1$s segundos, regenera hasta 6 trozos comestibles, cada uno restaurando %2$s puntos de hambre. Al consumirse, la reliquia usa automáticamente la cantidad necesaria de trozos para reponer el hambre del jugador.", + "tooltip.relics.infinity_ham.ability.marinade": "Marinado", + "tooltip.relics.infinity_ham.ability.marinade.description": "Permite aplicar efectos de pociones a la reliquia haciendo clic izquierdo con una poción en el inventario. Cada vez que se consume la reliquia, aplica estos efectos al jugador durante %1$s segundos por cada punto de hambre restaurado. Usar una botella de agua elimina los efectos de poción aplicados previamente.", + "tooltip.relics.infinity_ham.ability.meat_bat": "Bate de Carne", + "tooltip.relics.infinity_ham.ability.meat_bat.description": "Permite usar la reliquia como un arma cuerpo a cuerpo, infligiendo %1$s de daño y aturdiendo al objetivo durante %2$s segundos por trozo. Consume todos los trozos al atacar, independientemente de la salud restante del objetivo.", + "tooltip.relics.infinity_ham.leveling_source.regeneration.title": "Regeneración", + "tooltip.relics.infinity_ham.leveling_source.regeneration.description": "+%1$s puntos de experiencia por cada trozo consumido mediante la habilidad %2$s.", + "tooltip.relics.infinity_ham.leveling_source.marinade.title": "Marinado", + "tooltip.relics.infinity_ham.leveling_source.marinade.description": "+%1$s puntos de experiencia por cada efecto aplicado a la reliquia usando la habilidad %2$s.", + "tooltip.relics.infinity_ham.leveling_source.meat_bat.title": "Bate de Carne", + "tooltip.relics.infinity_ham.leveling_source.meat_bat.description": "+%1$s puntos de experiencia por cada trozo consumido durante la activación de la habilidad %2$s.", + + "item.relics.enders_hand": "Mano del Ender", + "tooltip.relics.enders_hand.description": "+1 punto de experiencia al usar la habilidad «Transposición del End», +1 punto de experiencia por cada 10 bloques de distancia al objetivo al usarla.", + "tooltip.relics.enders_hand.ability.neutrality": "Neutralidad", + "tooltip.relics.enders_hand.ability.neutrality.description": "Hace que los enderman sean neutrales hacia el portador.", + "tooltip.relics.enders_hand.ability.swap": "Transposición del End", + "tooltip.relics.enders_hand.ability.swap.description": "Intercambia al portador con el objetivo en la línea de visión.", + "tooltip.relics.enders_hand.ability.swap.stat.distance.title": "Distancia:", + "tooltip.relics.enders_hand.ability.swap.stat.distance.value": "%1$s bloques.", + "tooltip.relics.enders_hand.ability.swap.predicate.target": "Mirando al objetivo", + + "item.relics.holy_locket": "Relicario Sagrado", + "tooltip.relics.holy_locket.description": "Otorga al portador la habilidad de convertir la curación enemiga en su contra.", + "tooltip.relics.holy_locket.ability.belief": "Fe", + "tooltip.relics.holy_locket.ability.belief.description": "Una habilidad conmutativa con dos modos: Santidad e Impiedad. Activar la habilidad en cualquier modo llena el depósito interno en 1 unidad. En modo Santidad, redirige una porción de la curación del portador como daño a los objetivos cercanos y reduce el daño recibido en un 1% por carga. En modo Impiedad, absorbe una porción de la curación de los objetivos cercanos y aumenta el daño infligido en un 1% por carga.", + "tooltip.relics.holy_locket.ability.belief.stat.radius.title": "Radio:", + "tooltip.relics.holy_locket.ability.belief.stat.radius.value": "%1$s bloques.", + "tooltip.relics.holy_locket.ability.belief.stat.amount.title": "Modificador de curación/daño:", + "tooltip.relics.holy_locket.ability.belief.stat.amount.value": "%1$s%% del valor original.", + "tooltip.relics.holy_locket.ability.belief.stat.count.title": "Número máximo de proyectiles:", + "tooltip.relics.holy_locket.ability.belief.stat.count.value": "%1$s unidades.", + "tooltip.relics.holy_locket.ability.belief.stat.capacity.title": "Capacidad del depósito:", + "tooltip.relics.holy_locket.ability.belief.stat.capacity.value": "%1$s unidades.", + "tooltip.relics.holy_locket.ability.repentance": "Arrepentimiento", + "tooltip.relics.holy_locket.ability.repentance.description": "Quema la salud de los no-muertos cercanos.", + "tooltip.relics.holy_locket.ability.repentance.stat.radius.title": "Radio:", + "tooltip.relics.holy_locket.ability.repentance.stat.radius.value": "%1$s bloques.", + "tooltip.relics.holy_locket.ability.repentance.stat.damage.title": "Daño infligido:", + "tooltip.relics.holy_locket.ability.repentance.stat.damage.value": "%1$s por carga.", + "tooltip.relics.holy_locket.ability.blessing": "Bendición", + "tooltip.relics.holy_locket.ability.blessing.description": "Otorga al portador invencibilidad temporal al activarse, consumiendo cargas del depósito interno de la reliquia cada segundo.", + "tooltip.relics.holy_locket.ability.blessing.stat.consumption.title": "Consumo de cargas:", + "tooltip.relics.holy_locket.ability.blessing.stat.consumption.value": "%1$s por segundo.", + "tooltip.relics.holy_locket.ability.blessing.predicate.blessing": "Cargas en el depósito interno", + + "item.relics.magic_mirror": "Espejo Mágico", + "tooltip.relics.magic_mirror.description": "+1 punto de experiencia por cada uso de la habilidad «Agujero de Gusano», +1 punto de experiencia por cada 50 bloques hasta el punto de teletransporte.", + "tooltip.relics.magic_mirror.ability.teleport": "Agujero de Gusano", + "tooltip.relics.magic_mirror.ability.teleport.description": "Al usarlo, teletransporta al portador a su punto de reaparición.", + "tooltip.relics.magic_mirror.ability.teleport.stat.distance.title": "Distancia:", + "tooltip.relics.magic_mirror.ability.teleport.stat.distance.value": "%1$s bloques.", + "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.title": "Recarga:", + "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.value": "%1$s segundos.", + + "item.relics.shadow_glaive": "Guja Sombría", + "tooltip.relics.shadow_glaive.description": "Un arma magistralmente forjada y caprichosa. Si su temperamento es favorable, ni la horda ni la legión resistirán el embate de sus mil hojas.", + "tooltip.relics.shadow_glaive.ability.mayhem": "Caos", + "tooltip.relics.shadow_glaive.ability.mayhem.description": "Infligir daño tiene un %1$s%% de probabilidad de disparar un proyectil que rebota caóticamente entre los objetivos cercanos dentro de un radio de 16 bloques, hasta %2$s veces, causando un %3$s%% del daño del ataque desencadenante.", + "tooltip.relics.shadow_glaive.ability.cloning": "Clonación", + "tooltip.relics.shadow_glaive.ability.cloning.description": "Cada rebote de proyectil de la habilidad Caos tiene un %1$s%% de probabilidad de generar un proyectil idéntico adicional.", + "tooltip.relics.shadow_glaive.leveling_source.mayhem.title": "Caos", + "tooltip.relics.shadow_glaive.leveling_source.mayhem.description": "+%1$s puntos de experiencia por cada activación de la habilidad %2$s.", + + "item.relics.arrow_quiver": "Carcaj", + "tooltip.relics.arrow_quiver.description": "+1 punto de experiencia por cada 10 bloques hasta el objetivo alcanzado por el disparo.", + "tooltip.relics.arrow_quiver.ability.receptacle": "Almacenamiento de Flechas", + "tooltip.relics.arrow_quiver.ability.receptacle.description": "Disparar utiliza principalmente flechas del almacenamiento interno del carcaj. Al presionar el botón izquierdo del ratón con flechas en el carcaj del inventario, estas se colocarán en el almacenamiento interno de la reliquia. Al presionar el botón derecho del ratón en el carcaj, se obtendrá la última pila de flechas colocada en él.", + "tooltip.relics.arrow_quiver.ability.receptacle.stat.slots.title": "Espacios para flechas:", + "tooltip.relics.arrow_quiver.ability.receptacle.stat.slots.value": "%1$s unidades.", + "tooltip.relics.arrow_quiver.ability.leap": "Salto", + "tooltip.relics.arrow_quiver.ability.leap.description": "Impulsa al jugador lejos de la dirección de la mirada, aplicando un efecto de desaparición hasta aterrizar. Usar un arco suspenderá al jugador en el aire, aumentando el daño e ignorando la gravedad para el próximo disparo crítico.", + "tooltip.relics.arrow_quiver.ability.leap.stat.multiplier.title": "Daño adicional:", + "tooltip.relics.arrow_quiver.ability.leap.stat.multiplier.value": "+%1$s%%.", + "tooltip.relics.arrow_quiver.ability.leap.stat.duration.title": "Duración máxima:", + "tooltip.relics.arrow_quiver.ability.leap.stat.duration.value": "%1$s segundos.", + "tooltip.relics.arrow_quiver.ability.leap.stat.cooldown.title": "Tiempo de recarga:", + "tooltip.relics.arrow_quiver.ability.leap.stat.cooldown.value": "%1$s segundos.", + "tooltip.relics.arrow_quiver.ability.leap.predicate.target": "Mirando el bloque bajo los pies", + "tooltip.relics.arrow_quiver.ability.agility": "Agilidad", + "tooltip.relics.arrow_quiver.ability.agility.description": "Aumenta la velocidad de tensión de la cuerda del arco.", + "tooltip.relics.arrow_quiver.ability.agility.stat.modifier.title": "Multiplicador de velocidad:", + "tooltip.relics.arrow_quiver.ability.agility.stat.modifier.value": "%1$s%%.", + "tooltip.relics.arrow_quiver.ability.rain": "Lluvia de Flechas", + "tooltip.relics.arrow_quiver.ability.rain.description": "Invoca en un punto de la línea de visión un área de flechas teledirigidas cayendo desde el almacenamiento interno del carcaj con la habilidad «Almacenamiento de Flechas». Las flechas en sí mismas del almacenamiento no se consumen. Solo puede existir un área de esta habilidad a la vez.", + "tooltip.relics.arrow_quiver.ability.rain.stat.radius.title": "Radio del área:", + "tooltip.relics.arrow_quiver.ability.rain.stat.radius.value": "%1$s bloques.", + "tooltip.relics.arrow_quiver.ability.rain.stat.duration.title": "Duración del área:", + "tooltip.relics.arrow_quiver.ability.rain.stat.duration.value": "%1$s segundos.", + "tooltip.relics.arrow_quiver.ability.rain.stat.delay.title": "Frecuencia de invocación de flechas:", + "tooltip.relics.arrow_quiver.ability.rain.stat.delay.value": "%1$s segundos.", + "tooltip.relics.arrow_quiver.ability.rain.predicate.arrow": "Flechas en el carcaj", + + "item.relics.blazing_flask": "Frasco Llameante", + "tooltip.relics.blazing_flask.description": "+1 punto de experiencia por cada 5 segundos de vuelo dentro del alcance de la habilidad «Fuego Eterno».", + "tooltip.relics.blazing_flask.ability.bonfire": "Fuego Eterno", + "tooltip.relics.blazing_flask.ability.bonfire.description": "Usar una reliquia en un bloque creará una zona de vuelo restringida, cuyo tamaño depende de la cantidad de fuego en cierto radio alrededor del centro.", + "tooltip.relics.blazing_flask.ability.bonfire.stat.step.title": "Radio de detección de fuego:", + "tooltip.relics.blazing_flask.ability.bonfire.stat.step.value": "%1$s bloques.", + "tooltip.relics.blazing_flask.ability.bonfire.stat.speed.title": "Velocidad de vuelo:", + "tooltip.relics.blazing_flask.ability.bonfire.stat.speed.value": "%1$s bloques por segundo.", + "tooltip.relics.blazing_flask.ability.bonfire.stat.height.title": "Altura de vuelo:", + "tooltip.relics.blazing_flask.ability.bonfire.stat.height.value": "%1$s bloques.", + + "item.relics.elytra_booster": "Impulsor de Élitros", + "tooltip.relics.elytra_booster.description": "+1 punto de experiencia por cada 10 segundos de combustión de combustible al colocarlo en el buffer interno de la reliquia desde la habilidad «Aceleración».", + "tooltip.relics.elytra_booster.ability.boost": "Aceleración", + "tooltip.relics.elytra_booster.ability.boost.description": "Usar cualquier combustible en una reliquia en el inventario recarga su buffer interno. Usar la habilidad durante el vuelo con élitros impulsa al portador hacia adelante, consumiendo combustible del buffer interno.", + "tooltip.relics.elytra_booster.ability.boost.stat.capacity.title": "Capacidad:", + "tooltip.relics.elytra_booster.ability.boost.stat.capacity.value": "%1$s unidades.", + "tooltip.relics.elytra_booster.ability.boost.stat.speed.title": "Velocidad:", + "tooltip.relics.elytra_booster.ability.boost.stat.speed.value": "%1$s bloques por segundo.", + "tooltip.relics.elytra_booster.ability.boost.predicate.elytra": "Volando con élitros", + "tooltip.relics.elytra_booster.ability.boost.predicate.fuel": "Combustible en el Impulsor", + + "item.relics.midnight_robe": "Túnica de Medianoche", + "tooltip.relics.midnight_robe.description": "+1 punto de experiencia por cada 2 unidades de daño al atacar mientras eres invisible con la habilidad «Desaparecer».", + "tooltip.relics.midnight_robe.ability.vanish": "Desaparecer", + "tooltip.relics.midnight_robe.ability.vanish.description": "Otorga al portador invisibilidad total y aumenta la velocidad de movimiento en condiciones de poca luz.", + "tooltip.relics.midnight_robe.ability.vanish.stat.light.title": "Nivel mínimo de luz:", + "tooltip.relics.midnight_robe.ability.vanish.stat.light.value": "%1$s.", + "tooltip.relics.midnight_robe.ability.vanish.stat.speed.title": "Multiplicador de velocidad:", + "tooltip.relics.midnight_robe.ability.vanish.stat.speed.value": "%1$s%%.", + "tooltip.relics.midnight_robe.ability.backstab": "Traición", + "tooltip.relics.midnight_robe.ability.backstab.description": "Un ataque con la habilidad «Desaparecer» inflige daño aumentado, dibuja un círculo alrededor del objetivo y disipa la invisibilidad del portador. Solo se puede reutilizar la habilidad «Desaparecer» al salir del círculo.", + "tooltip.relics.midnight_robe.ability.backstab.stat.damage.title": "Multiplicador de daño:", + "tooltip.relics.midnight_robe.ability.backstab.stat.damage.value": "%1$s%%.", + "tooltip.relics.midnight_robe.ability.backstab.stat.distance.title": "Radio del círculo:", + "tooltip.relics.midnight_robe.ability.backstab.stat.distance.value": "%1$s bloques.", + + "item.relics.reflection_necklace": "Collar Reflectante", + "tooltip.relics.reflection_necklace.description": "+1 punto de experiencia por cada 10 de daño acumulado en el buffer interno de la reliquia con la habilidad «Odio Infernal».", + "tooltip.relics.reflection_necklace.ability.explode": "Odio Infernal", + "tooltip.relics.reflection_necklace.ability.explode.description": "Acumula el daño recibido por el portador en el buffer interno de la reliquia. 5 segundos después del último daño o si el buffer se llena, la reliquia explota, lanzando fragmentos de obsidiana en todas las direcciones, causando daño y aturdiendo a los objetivos.", + "tooltip.relics.reflection_necklace.ability.explode.stat.capacity.title": "Buffer de daño:", + "tooltip.relics.reflection_necklace.ability.explode.stat.capacity.value": "%1$s unidades.", + "tooltip.relics.reflection_necklace.ability.explode.stat.damage.title": "Daño por unidad del buffer:", + "tooltip.relics.reflection_necklace.ability.explode.stat.damage.value": "%1$s unidades.", + "tooltip.relics.reflection_necklace.ability.explode.stat.stun.title": "Aturdimiento por unidad del buffer:", + "tooltip.relics.reflection_necklace.ability.explode.stat.stun.value": "%1$s segundos.", + + "item.relics.jellyfish_necklace": "Collar de Medusa", + "tooltip.relics.jellyfish_necklace.description": "+1 punto de experiencia por cada activación de la habilidad «Descarga Eléctrica».", + "tooltip.relics.jellyfish_necklace.ability.unsinkable": "Poder sobre el mar", + "tooltip.relics.jellyfish_necklace.ability.unsinkable.description": "El portador no se hunde en el agua.", + "tooltip.relics.jellyfish_necklace.ability.shock": "Descarga Eléctrica", + "tooltip.relics.jellyfish_necklace.ability.shock.description": "Inflige daño a los objetivos al colisionar con ellos.", + "tooltip.relics.jellyfish_necklace.ability.shock.stat.damage.title": "Daño:", + "tooltip.relics.jellyfish_necklace.ability.shock.stat.damage.value": "%1$s unidades.", + "tooltip.relics.jellyfish_necklace.ability.paralysis": "Parálisis", + "tooltip.relics.jellyfish_necklace.ability.paralysis.description": "Cuando se activa, la habilidad «Descarga Eléctrica» impone un efecto de parálisis al objetivo.", + "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration.title": "Duración del efecto:", + "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration.value": "%1$s segundos.", + + "item.relics.spore_sack": "Saco de Esporas", + "tooltip.relics.spore_sack.description": "Un simple saco de arpillera lleno hasta el tope con miasma mortal.", + "tooltip.relics.spore_sack.ability.spore_mist": "Niebla de Esporas", + "tooltip.relics.spore_sack.ability.spore_mist.description": "Cuando la salud del jugador baja por debajo del 50%, libera hasta %1$s esporas teledirigidas a su alrededor. Estas esporas causan daño igual al %2$s%% de la salud faltante del jugador y bloquean la curación para los objetivos afectados durante 5 segundos. La habilidad puede activarse de nuevo cuando la salud del jugador suba por encima del 50%.", + "tooltip.relics.spore_sack.leveling_source.spore_mist.title": "Niebla de Esporas", + "tooltip.relics.spore_sack.leveling_source.spore_mist.description": "+%1$s puntos de experiencia por cada golpe exitoso de una espora de la habilidad %2$s.", + + "item.relics.ice_breaker": "Rompehielos", + "tooltip.relics.ice_breaker.description": "+1 punto de experiencia por cada 3 bloques de caída antes de activar la habilidad «Terremoto».", + "tooltip.relics.ice_breaker.ability.sustainability": "Sostenibilidad", + "tooltip.relics.ice_breaker.ability.sustainability.description": "Aumenta la velocidad de caída, incrementa la resistencia al retroceso y elimina el deslizamiento.", + "tooltip.relics.ice_breaker.ability.sustainability.stat.modifier.title": "Resistencia al retroceso:", + "tooltip.relics.ice_breaker.ability.sustainability.stat.modifier.value": "%1$s%%.", + "tooltip.relics.ice_breaker.ability.impact": "Terremoto", + "tooltip.relics.ice_breaker.ability.impact.description": "Usar la habilidad en una caída creará una onda de choque en el sitio de aterrizaje, causando daño y lanzando a los objetivos cercanos. El poder de la onda depende de la distancia que el portador haya caído.", + "tooltip.relics.ice_breaker.ability.impact.stat.size.title": "Radio máximo:", + "tooltip.relics.ice_breaker.ability.impact.stat.size.value": "%1$s bloques.", + "tooltip.relics.ice_breaker.ability.impact.stat.damage.title": "Daño mínimo:", + "tooltip.relics.ice_breaker.ability.impact.stat.damage.value": "%1$s unidades.", + "tooltip.relics.ice_breaker.ability.impact.predicate.falling": "Caída libre", + + "item.relics.bastion_ring": "Anillo Bastión", + "tooltip.relics.bastion_ring.description": "+1/5/10 punto de experiencia por cada Zombificado Piglin / Piglin / Piglin Bruto matado.\n+1 punto de experiencia por cada intercambio adicional de la habilidad «Respeto».", + "tooltip.relics.bastion_ring.ability.compass": "Reconocimiento", + "tooltip.relics.bastion_ring.ability.compass.description": "Hace que los piglins sean neutrales en relación con el portador. El piglin más cercano indicará la ubicación de un bastión cercano.", + "tooltip.relics.bastion_ring.ability.trade": "Respeto", + "tooltip.relics.bastion_ring.ability.trade.description": "Cada intercambio con piglins tiene un 50% de probabilidad de emitir un resultado de intercambio adicional.", + "tooltip.relics.bastion_ring.ability.trade.stat.rolls.title": "Número máximo de intercambios:", + "tooltip.relics.bastion_ring.ability.trade.stat.rolls.value": "%1$s unidades.", + + "item.relics.horse_flute": "Flauta de Caballo", + "tooltip.relics.horse_flute.description": "+1 punto de experiencia por cada 25 bloques recorridos por un caballo llamado por la habilidad «Establo Portátil».", + "tooltip.relics.horse_flute.ability.paddock": "Establo Portátil", + "tooltip.relics.horse_flute.ability.paddock.description": "Usar una reliquia en el caballo moverá al animal al almacenamiento interno. Volver a usar la habilidad liberará a la criatura. Si la distancia entre el portador y el caballo invocado excede los 16 bloques, automáticamente se guardará de nuevo en la flauta.", + "tooltip.relics.horse_flute.ability.paddock.stat.slots.title": "Espacios:", + "tooltip.relics.horse_flute.ability.paddock.stat.slots.value": "%1$s.", + "tooltip.relics.horse_flute.ability.heal": "Tratamiento en el terreno", + "tooltip.relics.horse_flute.ability.heal.description": "Un caballo colocado en el almacenamiento interno restaurará salud lentamente.", + "tooltip.relics.horse_flute.ability.heal.stat.amount.title": "Restauración:", + "tooltip.relics.horse_flute.ability.heal.stat.amount.value": "%1$s unidades de salud por segundo.", + + "item.relics.magma_walker": "Caminante de Magma", + "tooltip.relics.magma_walker.description": "+1 punto de experiencia por cada 5 unidades de calentamiento de la habilidad «Huella Ardiente».", + "tooltip.relics.magma_walker.ability.pace": "Huella Ardiente", + "tooltip.relics.magma_walker.ability.pace.description": "Durante un tiempo determinado permite caminar sobre la superficie de la lava sin caer y sin recibir daño. Después de que se agote el tiempo, las botas comienzan a sobrecalentarse y causan daño al portador proporcional al grado de sobrecalentamiento.", + "tooltip.relics.magma_walker.ability.pace.stat.time.title": "Duración:", + "tooltip.relics.magma_walker.ability.pace.stat.time.value": "%1$s segundos.", + "tooltip.relics.magma_walker.ability.heat_resistance": "Resistencia al Calor", + "tooltip.relics.magma_walker.ability.heat_resistance.description": "Suprime el daño de bloques calientes.", + + "item.relics.aqua_walker": "Caminante de Aqua", + "tooltip.relics.aqua_walker.description": "+1 punto de experiencia por cada 5 unidades de humedad de la habilidad «Resistencia a la Humedad».", + "tooltip.relics.aqua_walker.ability.walking": "Resistencia a la Humedad", + "tooltip.relics.aqua_walker.ability.walking.description": "Durante un tiempo determinado permite moverse sobre la superficie del agua sin caer. Después de que se agote el tiempo, las botas comienzan a hundirse, arrastrando al portador bajo el agua.", + "tooltip.relics.aqua_walker.ability.walking.stat.time.title": "Duración:", + "tooltip.relics.aqua_walker.ability.walking.stat.time.value": "%1$s segundos.", + + "item.relics.drowned_belt": "Cinturón Ahogado", + "tooltip.relics.drowned_belt.description": "+1 punto de experiencia por cada nivel de encantamiento «Riptide» en el tridente al usarlo.", + "tooltip.relics.drowned_belt.ability.slots": "Capacidad de Carga", + "tooltip.relics.drowned_belt.ability.slots.description": "Aumenta el número máximo de ranuras para equipar reliquias.", + "tooltip.relics.drowned_belt.ability.slots.stat.charm.title": "Amuletos:", + "tooltip.relics.drowned_belt.ability.slots.stat.charm.value": "+%1$s ranuras.", + "tooltip.relics.drowned_belt.ability.anchor": "Peso Muerto", + "tooltip.relics.drowned_belt.ability.anchor.description": "Reduce la velocidad de nado y aumenta la velocidad de hundimiento del portador.", + "tooltip.relics.drowned_belt.ability.anchor.stat.slowness.title": "Reducción de la velocidad de nado:", + "tooltip.relics.drowned_belt.ability.anchor.stat.slowness.value": "+%1$s%%.", + "tooltip.relics.drowned_belt.ability.anchor.stat.sinking.title": "Tasa de hundimiento:", + "tooltip.relics.drowned_belt.ability.anchor.stat.sinking.value": "+%1$s%%.", + "tooltip.relics.drowned_belt.ability.pressure": "Flujo de Agua", + "tooltip.relics.drowned_belt.ability.pressure.description": "Aumenta el daño infligido bajo el agua.", + "tooltip.relics.drowned_belt.ability.pressure.stat.damage.title": "Multiplicador de daño:", + "tooltip.relics.drowned_belt.ability.pressure.stat.damage.value": "+%1$s%%.", + "tooltip.relics.drowned_belt.ability.riptide": "Atracción Acuática", + "tooltip.relics.drowned_belt.ability.riptide.description": "Permite usar la habilidad del tridente «Riptide» sin lluvia ni agua, añadiendo tiempo de recarga.", + "tooltip.relics.drowned_belt.ability.riptide.stat.cooldown.title": "Tiempo de recarga:", + "tooltip.relics.drowned_belt.ability.riptide.stat.cooldown.value": "%1$s segundos por nivel de encantamiento.", + + "item.relics.hunter_belt": "Cinturón del Cazador", + "tooltip.relics.hunter_belt.description": "+1 punto de experiencia por cada ataque realizado por la mascota del portador.", + "tooltip.relics.hunter_belt.ability.slots": "Capacidad de Carga", + "tooltip.relics.hunter_belt.ability.slots.description": "Aumenta el número máximo de ranuras para equipar reliquias.", + "tooltip.relics.hunter_belt.ability.slots.stat.charm.title": "Amuletos:", + "tooltip.relics.hunter_belt.ability.slots.stat.charm.value": "+%1$s ranuras.", + "tooltip.relics.hunter_belt.ability.training": "Entrenamiento", + "tooltip.relics.hunter_belt.ability.training.description": "Aumenta el daño infligido por las mascotas del portador.", + "tooltip.relics.hunter_belt.ability.training.stat.damage.title": "Multiplicador de daño:", + "tooltip.relics.hunter_belt.ability.training.stat.damage.value": "+%1$s%%.", + + "item.relics.leather_belt": "Cinturón de Cuero", + "tooltip.relics.leather_belt.description": "+1 punto de experiencia por cada experiencia ganada por los amuletos equipados.", + "tooltip.relics.leather_belt.ability.slots": "Capacidad de Carga", + "tooltip.relics.leather_belt.ability.slots.description": "Aumenta el número máximo de ranuras para equipar reliquias.", + "tooltip.relics.leather_belt.ability.slots.stat.charm.title": "Amuletos:", + "tooltip.relics.leather_belt.ability.slots.stat.charm.value": "+%1$s ranuras.", + + "item.relics.rage_glove": "Guante de Ira", + "tooltip.relics.rage_glove.description": "+1 punto de experiencia por cada 3 cargas de la habilidad «Furia Berserker» cuando se restablecen.\n+1 punto de experiencia por cada objetivo golpeado por la habilidad «Chorro».", + "tooltip.relics.rage_glove.ability.rage": "Furia Berserker", + "tooltip.relics.rage_glove.ability.rage.description": "Cada ataque realizado por el portador dentro de los 3 segundos posteriores al último acumula 1 carga en el búfer interno de la reliquia. El daño infligido y recibido por el portador, así como su velocidad de movimiento y el daño infligido, aumentan proporcionalmente a las cargas acumuladas. Después de 3 segundos, el búfer interno de la reliquia se vacía, cancelando todos los bonos recibidos.", + "tooltip.relics.rage_glove.ability.rage.stat.duration.title": "Tiempo de existencia de la carga:", + "tooltip.relics.rage_glove.ability.rage.stat.duration.value": "%1$s segundos.", + "tooltip.relics.rage_glove.ability.rage.stat.incoming_damage.title": "Multiplicador de daño recibido:", + "tooltip.relics.rage_glove.ability.rage.stat.incoming_damage.value": "%1$s%% por carga.", + "tooltip.relics.rage_glove.ability.rage.stat.dealt_damage.title": "Multiplicador de daño infligido:", + "tooltip.relics.rage_glove.ability.rage.stat.dealt_damage.value": "%1$s%% por carga.", + "tooltip.relics.rage_glove.ability.phlebotomy": "Flebotomía", + "tooltip.relics.rage_glove.ability.phlebotomy.description": "Aumenta la velocidad de ataque y movimiento del portador, además de otorgar regeneración pasiva proporcional al porcentaje de salud faltante.", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.heal.title": "Regeneración de salud:", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.heal.value": "%1$s por cada 1%% por segundo.", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.movement_speed.title": "Multiplicador de velocidad de movimiento:", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.movement_speed.value": "%1$s%% por cada 1%%.", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.attack_speed.title": "Multiplicador de velocidad de ataque:", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.attack_speed.value": "%1$s%% por cada 1%%.", + "tooltip.relics.rage_glove.ability.spurt": "Chorro", + "tooltip.relics.rage_glove.ability.spurt.description": "Se lanza hacia la dirección de la vista, incendiando a los enemigos, aplicando sangrado y atacando a cada objetivo en su camino con el objeto en la mano. Inflige daño adicional proporcional al número de cargas en el búfer interno de la reliquia de la habilidad «Furia Berserker» y lo devasta.", + "tooltip.relics.rage_glove.ability.spurt.stat.cooldown.title": "Tiempo de recarga:", + "tooltip.relics.rage_glove.ability.spurt.stat.cooldown.value": "%1$s segundos.", + "tooltip.relics.rage_glove.ability.spurt.stat.damage.title": "Daño infligido:", + "tooltip.relics.rage_glove.ability.spurt.stat.damage.value": "%1$s por carga.", + "tooltip.relics.rage_glove.ability.spurt.stat.distance.title": "Distancia:", + "tooltip.relics.rage_glove.ability.spurt.stat.distance.value": "%1$s bloques.", + + "item.relics.ice_skates": "Patines de Hielo", + "tooltip.relics.ice_skates.description": "+1 punto de experiencia por cada segundo de aceleración de la habilidad «Patinaje».", + "tooltip.relics.ice_skates.ability.skating": "Patinaje", + "tooltip.relics.ice_skates.ability.skating.description": "Aumenta la velocidad de movimiento sobre el hielo dependiendo de la duración del deslizamiento.", + "tooltip.relics.ice_skates.ability.skating.stat.speed.title": "Multiplicador de velocidad por segundo:", + "tooltip.relics.ice_skates.ability.skating.stat.speed.value": "%1$s%%.", + "tooltip.relics.ice_skates.ability.skating.stat.duration.title": "Duración máxima:", + "tooltip.relics.ice_skates.ability.skating.stat.duration.value": "%1$s segundos.", + "tooltip.relics.ice_skates.ability.ram": "Embiste", + "tooltip.relics.ice_skates.ability.ram.description": "Cuando colisiona con objetivos, inflige daño proporcional a la duración del uso de la habilidad «Patinaje».", + "tooltip.relics.ice_skates.ability.ram.stat.damage.title": "Daño por segundo:", + "tooltip.relics.ice_skates.ability.ram.stat.damage.value": "%1$s unidades.", + + "item.relics.amphibian_boot": "Bota Anfibia", + "tooltip.relics.amphibian_boot.description": "+1 punto de experiencia por cada segundo de aceleración de la habilidad «Aletas».\n+1 punto de experiencia por cada segundo de aceleración de la habilidad «Resbalón».", + "tooltip.relics.amphibian_boot.ability.swimming": "Aletas", + "tooltip.relics.amphibian_boot.ability.swimming.description": "Acelera la velocidad de nado dependiendo de su duración.", + "tooltip.relics.amphibian_boot.ability.swimming.stat.speed.title": "Multiplicador de velocidad:", + "tooltip.relics.amphibian_boot.ability.swimming.stat.speed.value": "%1$s%% por cada segundo.", + "tooltip.relics.amphibian_boot.ability.swimming.stat.duration.title": "Duración máxima:", + "tooltip.relics.amphibian_boot.ability.swimming.stat.duration.value": "%1$s segundos.", + "tooltip.relics.amphibian_boot.ability.slipping": "Resbalón", + "tooltip.relics.amphibian_boot.ability.slipping.description": "Aumenta la velocidad de movimiento bajo la lluvia dependiendo de su duración.", + "tooltip.relics.amphibian_boot.ability.slipping.stat.speed.title": "Multiplicador de velocidad por segundo:", + "tooltip.relics.amphibian_boot.ability.slipping.stat.speed.value": "%1$s%%.", + "tooltip.relics.amphibian_boot.ability.slipping.stat.duration.title": "Duración máxima:", + "tooltip.relics.amphibian_boot.ability.slipping.stat.duration.value": "%1$s segundos.", + "tooltip.relics.amphibian_boot.ability.gills": "Branquias", + "tooltip.relics.amphibian_boot.ability.gills.description": "Otorga al jugador la habilidad de no consumir aire mientras está bajo el agua.", + "tooltip.relics.amphibian_boot.ability.gills.stat.chance.title": "Probabilidad de activación:", + "tooltip.relics.amphibian_boot.ability.gills.stat.chance.value": "%1$s%%.", + + "item.relics.spatial_sign": "Signo Espacial", + "tooltip.relics.spatial_sign.description": "+1 punto de experiencia por cada segundo de retorno de la habilidad «Rift temporal».", + "tooltip.relics.spatial_sign.ability.seal": "Rift Temporal", + "tooltip.relics.spatial_sign.ability.seal.description": "Cuando se usa, devuelve al portador a lo largo de la ruta recorrida después de un cierto tiempo. El uso repetido terminará con la habilidad.", + "tooltip.relics.spatial_sign.ability.seal.stat.time.title": "Duración máxima:", + "tooltip.relics.spatial_sign.ability.seal.stat.time.value": "%1$s segundos.", + + "item.relics.chorus_inhibitor": "Inhibidor de Coro", + "tooltip.relics.chorus_inhibitor.description": "+1 punto de experiencia por cada 10 bloques hasta el punto de teletransportación de la habilidad «Control de Teletransportación».", + "tooltip.relics.chorus_inhibitor.ability.blink": "Control de Teletransportación", + "tooltip.relics.chorus_inhibitor.ability.blink.description": "Usando la fruta del coro, teletransporta al portador al bloque en la línea de visión dentro del alcance.", + "tooltip.relics.chorus_inhibitor.ability.blink.stat.distance.title": "Distancia máxima:", + "tooltip.relics.chorus_inhibitor.ability.blink.stat.distance.value": "%1$s bloques.", + "tooltip.relics.chorus_inhibitor.ability.blink.stat.cooldown.title": "Tiempo de recarga:", + "tooltip.relics.chorus_inhibitor.ability.blink.stat.cooldown.value": "%1$s segundos.", + + "item.relics.wool_mitten": "Mitón de Lana", + "item.relics.solid_snowball": "Bola de nieve congelada", + "tooltip.relics.wool_mitten.description": "+1 punto de experiencia por cada 5 unidades de tamaño cuando es golpeado por una bola de nieve de la habilidad «Moldear».", + "tooltip.relics.wool_mitten.ability.mold": "Moldear", + "tooltip.relics.wool_mitten.ability.mold.description": "Recolectando nieve con el botón derecho del ratón con la mano vacía, se forman gradualmente bolas de nieve sólidas especiales. Golpear un objetivo con una bola de nieve causará daño y lo aturdirá, además de congelar a los objetivos cercanos. Sostener una bola de nieve sin una reliquia equipada también congela al portador.", + "tooltip.relics.wool_mitten.ability.mold.stat.size.title": "Tamaño máximo:", + "tooltip.relics.wool_mitten.ability.mold.stat.size.value": "%1$s unidades.", + "tooltip.relics.wool_mitten.ability.mold.stat.damage.title": "Daño:", + "tooltip.relics.wool_mitten.ability.mold.stat.damage.value": "%1$s por unidad de tamaño.", + "tooltip.relics.wool_mitten.ability.mold.stat.stun.title": "Aturdimiento:", + "tooltip.relics.wool_mitten.ability.mold.stat.stun.value": "%1$s segundos por unidad de tamaño.", + "tooltip.relics.wool_mitten.ability.mold.stat.freeze.title": "Congelación:", + "tooltip.relics.wool_mitten.ability.mold.stat.freeze.value": "%1$s segundos por unidad de tamaño.", + + "item.relics.roller_skates": "Patines de Ruedas", + "tooltip.relics.roller_skates.description": "+1 punto de experiencia por cada segundo de aceleración de la habilidad «Aceleración».", + "tooltip.relics.roller_skates.ability.skating": "Aceleración", + "tooltip.relics.roller_skates.ability.skating.description": "Aumenta la velocidad de movimiento dependiendo de su duración. Todos los bloques se vuelven resbaladizos para el portador.", + "tooltip.relics.roller_skates.ability.skating.stat.speed.title": "Multiplicador de velocidad por segundo:", + "tooltip.relics.roller_skates.ability.skating.stat.speed.value": "%1$s%%.", + "tooltip.relics.roller_skates.ability.skating.stat.duration.title": "Duración máxima:", + "tooltip.relics.roller_skates.ability.skating.stat.duration.value": "%1$s segundos.", + + "item.relics.space_dissector": "Disector Espacial", + "tooltip.relics.space_dissector.description": "+1 punto de experiencia por cada portal creado si no hay ninguno existente.", + "tooltip.relics.space_dissector.ability.dissection": "Disecar", + "tooltip.relics.space_dissector.ability.dissection.description": "Mantener el botón derecho crea un portal en un punto a lo largo de la línea de visión, soltar el botón derecho crea un segundo portal utilizando el mismo principio, conectándolo con el primero. Llevar una criatura viva a uno de los portales la moverá al portal vinculado. Los portales no funcionan si hay bloques sólidos en su camino.", + "tooltip.relics.space_dissector.ability.dissection.stat.distance.title": "Distancia máxima:", + "tooltip.relics.space_dissector.ability.dissection.stat.distance.value": "%1$s bloques.", + "tooltip.relics.space_dissector.ability.dissection.stat.time.title": "Duración del portal:", + "tooltip.relics.space_dissector.ability.dissection.stat.time.value": "%1$s segundos", + + "item.relics.phantom_boot": "Bota Fantasmal", + "tooltip.relics.phantom_boot.description": "Condensa la materia bajo los pies del portador de la reliquia, creando un camino a través de cualquier terreno, incluso donde no exista suelo sólido.", + "tooltip.relics.phantom_boot.ability.bridge": "Puente Fantasmal", + "tooltip.relics.phantom_boot.ability.bridge.description": "Crea un puente fantasmal temporal bajo los pies del jugador que cualquier portador de reliquia puede atravesar. Si el jugador permanece inmóvil en el puente por más de %1$s segundos, caerá y no podrá regresar hasta llegar a un suelo sólido.", + "tooltip.relics.phantom_boot.leveling_source.bridge.title": "Puente Fantasmal", + "tooltip.relics.phantom_boot.leveling_source.bridge.description": "+%1$s puntos de experiencia con un 10%% de probabilidad cada vez que se crea un puente usando la habilidad %2$s.", + + "item.relics.springy_boot": "Bota Elástica", + "tooltip.relics.springy_boot.description": "Otorga al portador de la reliquia elasticidad especial, permitiéndole rebotar sobre cualquier superficie sólida.", + "tooltip.relics.springy_boot.ability.bounce": "Elasticidad", + "tooltip.relics.springy_boot.ability.bounce.description": "Aumenta la elasticidad de todos los bloques en %1$s%% en comparación con los bloques de slime, permitiendo al jugador rebotar sobre ellos al aterrizar. Al activarse en el suelo, lanza al jugador al aire.", + "tooltip.relics.springy_boot.leveling_source.bounce.title": "Elasticidad", + "tooltip.relics.springy_boot.leveling_source.bounce.description": "+%1$s puntos de experiencia por cada rebote sobre una superficie usando la habilidad %2$s.", + + "tooltip.relics.leveling_source.generic.spreading.title": "Distribución de Experiencia", + "tooltip.relics.leveling_source.generic.spreading.description": "Cada vez que cualquier reliquia en el inventario gane experiencia, independientemente del método, el %1$s%% de esa experiencia también será ganado por esta reliquia.", + + "item.relics.leafy_ring": "Anillo Hoja [En proceso]", + "tooltip.relics.leafy_ring.description": "[En proceso]", + + "item.relics.relic_experience_bottle": "Botella de Experiencia de Reliquia", + + "block.relics.phantom_block": "Bloque de Puente Fantasmal", + + "block.relics.researching_table": "Mesa de Investigación [Eliminada del mod]", + + "effect.relics.stun": "Aturdimiento", + "effect.relics.paralysis": "Parálisis", + "effect.relics.confusion": "Confusión", + "effect.relics.vanishing": "Desvanecimiento", + "effect.relics.anti_heal": "Anti-Curación", + "effect.relics.bleeding": "Sangrado", + + "command.relics.base.not_relic": "¡El objeto en la mano debe ser una reliquia!", + + "info.relics.researching.wrong_container": "Trabajar con la reliquia en este inventario no es posible. Mueve el objeto al inventario principal del jugador y vuelve a intentarlo.", + + "key.relics.ability_list": "Mostrar el HUD de habilidades activas" } diff --git a/src/main/resources/assets/relics/lang/ko_kr.json b/src/main/resources/assets/relics/lang/ko_kr.json index 8142255b..9ef14724 100644 --- a/src/main/resources/assets/relics/lang/ko_kr.json +++ b/src/main/resources/assets/relics/lang/ko_kr.json @@ -1,425 +1,523 @@ -{ - "itemGroup.relics": "렐릭", - - "curios.identifier.talisman": "부적", - "curios.identifier.feet": "피트", - - "tooltip.relics.relic.tooltip.table": "이 유물에 대한 자세한 정보는 연구 탁자에서 확인할 수 있을 것 같다.", - "tooltip.relics.relic.tooltip.shift": "쉬프트를 눌러 자세한 내용 확인", - - "tooltip.relics.relic.tooltip.abilities": "능력:", - - "tooltip.relics.relic.ability.tooltip.low_level": "사용하려면 유물의 레벨을 높여야 할 것 같다. %1$s %2$s.", - "tooltip.relics.relic.ability.tooltip.no_stats": "능력에는 업그레이드 가능한 스텟이 없으며 유물의 품질에 영향을 주지 않습니다.", - "tooltip.relics.relic.ability.tooltip.ready_to_upgrade": "능력을 업그레이드 할 준비가 되어있습니다. %1$s .", - - "tooltip.relics.relic.leveling_points.title": "레벨링 포인트", - - "tooltip.relics.relic.vanilla_experience.title": "플레이어 경험치", - "tooltip.relics.relic.vanilla_experience.current_amount": "현재 경험치: %1$s/%2$s [%3$s%%]", - "tooltip.relics.relic.vanilla_experience.total_amount": "총 경험치: %1$s", - - "tooltip.relics.relic.relic_experience.title": "유물 경험치", - "tooltip.relics.relic.relic_experience.current_amount": "현재 경험치: %1$s/%2$s [%3$s%%]", - - "tooltip.relics.relic.max_level": "최대", - - "tooltip.relics.relic.ability.level": " [%1$s/%2$s]", - - "tooltip.relics.relic.status.positive": "§2§l[§2§l✔§2§l]", - "tooltip.relics.relic.status.negative": "§4§l[§4§l✘§4§l]", - - "tooltip.relics.relic.exchange.description": "경험치 교환", - "tooltip.relics.relic.exchange.cost": "%1$s 플레이어의 경험치를 현재 유물 경험치의 최대 1%로 변환합니다. 변환할수록 비용이 증가합니다 %2$s.", - "tooltip.relics.relic.exchange.locked": "유뮬의 레벨이 최대치에 도달했습니다.", - - "tooltip.relics.relic.upgrade.description": "레벨업", - "tooltip.relics.relic.upgrade.cost": "비용: %1$s 레벨링 포인트 %2$s, %3$s 경험치 포인트 %4$s.", - "tooltip.relics.relic.upgrade.locked": "능력이 최대 레벨에 도달했습니다.", - - "tooltip.relics.relic.reroll.description": "스텟 재분배", - "tooltip.relics.relic.reroll.cost": "비용: %1$s 경험치 포인트 %2$s.", - - "tooltip.relics.relic.reset.description": "레벨링 포인트 초기화", - "tooltip.relics.relic.reset.cost": "비용: %1$s 경험치 포인트 %2$s.", - "tooltip.relics.relic.reset.locked": "이 능력을 사용하려면 최소 1회 이상 레벨업 해야 합니다.", - - "item.relics.infinity_ham": "Infinity Ham", - "tooltip.relics.infinity_ham.description": "섭취 한 각 조각마다 경험치 +1", - "tooltip.relics.infinity_ham.ability.autophagy": "재생", - "tooltip.relics.infinity_ham.ability.autophagy.description": "사용시 재생 가능한 조각 중 한조각을 소비하여 사용자의 배고픔을 보충합니다.", - "tooltip.relics.infinity_ham.ability.autophagy.stat.feed.title": "포화:", - "tooltip.relics.infinity_ham.ability.autophagy.stat.feed.value": "%1$s 칸", - "tooltip.relics.infinity_ham.ability.infusion": "연금술", - "tooltip.relics.infinity_ham.ability.infusion.description": "인벤토리에 있는 유물에 물약을 사용하면 유물에 해당 포션 효과를 부여합니다. 이후 섭취시 부여된 물약의 능력을 사용자에게 적용합니다. 충전된 고기가 하나도 없다면 유물에 부여된 물약 능력을 잃게 됩니다.", - "tooltip.relics.infinity_ham.ability.infusion.stat.duration.title": "효과지속시간:", - "tooltip.relics.infinity_ham.ability.infusion.stat.duration.value": "초당 재생 %1$s ", - - "item.relics.enders_hand": "Ender Hand", - "tooltip.relics.enders_hand.description": "«End Transposition»능력 사용시 경험치 +1, 타겟과 사용자 사이 거리 10블럭마다 경험치 +1", - "tooltip.relics.enders_hand.ability.neutrality": "중립", - "tooltip.relics.enders_hand.ability.neutrality.description": "엔더맨이 사용자에 대해 중립적으로 만듭니다.", - "tooltip.relics.enders_hand.ability.swap": "End Transposition", - "tooltip.relics.enders_hand.ability.swap.description": "사용자에 시선에 있는 타겟과 자리를 맞바꿉니다..", - "tooltip.relics.enders_hand.ability.swap.stat.distance.title": "거리:", - "tooltip.relics.enders_hand.ability.swap.stat.distance.value": "%1$s 블록", - "tooltip.relics.enders_hand.ability.swap.predicate.target": "타겟을 바라보세요", - - "item.relics.holy_locket": "Holy Locket", - "tooltip.relics.holy_locket.description": "«신성한 축복»능력을 활성화 할 때마다 경험치 +1, 빼앗은 치유 칸당 경험치 +1", - "tooltip.relics.holy_locket.ability.steal": "신성한 축복", - "tooltip.relics.holy_locket.ability.steal.description": "주변 생물의 재생된 체력 중 일부를 유물 사용자의 체력으로 전환합니다.", - "tooltip.relics.holy_locket.ability.steal.stat.amount.title": "회복량:", - "tooltip.relics.holy_locket.ability.steal.stat.amount.value": "재생된 체력당 %1$s%%", - "tooltip.relics.holy_locket.ability.steal.stat.radius.title": "범위:", - "tooltip.relics.holy_locket.ability.steal.stat.radius.value": "%1$s 블록", - - "item.relics.magic_mirror": "Magic Mirror", - "tooltip.relics.magic_mirror.description": "«웜홀»능력 사용당 경험치 +1 순간이동 지점까지 50블록마다 경험치 +1", - "tooltip.relics.magic_mirror.ability.teleport": "웜홀", - "tooltip.relics.magic_mirror.ability.teleport.description": "사용시 사용자를 리스폰 지점으로 순간이동 시킵니다.", - "tooltip.relics.magic_mirror.ability.teleport.stat.distance.title": "거리:", - "tooltip.relics.magic_mirror.ability.teleport.stat.distance.value": "%1$s 블록.", - "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.title": "충전:", - "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.value": "%1$s 초", - - "item.relics.shadow_glaive": "Shadow Glaive", - "tooltip.relics.shadow_glaive.description": "«맹목적인 정의»능력으로 글레이브가 2회 튕길때마다 경험치 +1 ", - "tooltip.relics.shadow_glaive.ability.glaive": "맹목적인 정의", - "tooltip.relics.shadow_glaive.ability.glaive.description": "사용하면 근처 대상 사이를 튕겨내는 글레이브 8개중 하나를 던집니다. 던진 글레이브는 일정 시간이 지나면 복원됩니다.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.damage.title": "데미지:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.damage.value": "%1$s.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.recharge.title": "회복 시간:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.recharge.value": "%1$s 초", - "tooltip.relics.shadow_glaive.ability.glaive.stat.bounces.title": "튕김:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.bounces.value": "%1$s.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.radius.title": "튕기는 거리:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.radius.value": "%1$s 블록", - "tooltip.relics.shadow_glaive.ability.saw": "무자비한 처형", - "tooltip.relics.shadow_glaive.ability.saw.description": "사용 시 글레이브 충전량 8개를 모두 소모하여 근처 대상에게 피해를 주는 톱을 던집니다. 재사용하면 톱을 사용자에게 돌려주고 모든 충전량을 회복합니다. 능력이 활성화되는 동안 자동 충전이 차단됩니다.", - "tooltip.relics.shadow_glaive.ability.saw.stat.speed.title": "공격속도:", - "tooltip.relics.shadow_glaive.ability.saw.stat.speed.value": "초당 타수 %1$s ", - "tooltip.relics.shadow_glaive.ability.saw.stat.damage.title": "데미지:", - "tooltip.relics.shadow_glaive.ability.saw.stat.damage.value": "%1$s 칸", - - "item.relics.arrow_quiver": "Quiver", - "tooltip.relics.arrow_quiver.description": "화살로 명중한 대상과의 거리 10블록당 경험치 +1", - "tooltip.relics.arrow_quiver.ability.receptacle": "화살 보관", - "tooltip.relics.arrow_quiver.ability.receptacle.description": "활은 화살통 내부에 존재하는 화살을 우선적으로 사용합니다. 인벤토리에 있는 화살통에 화살을 들고 좌클릭을 누르면 화살통 내부에 화살이 저장됩니다. 우클릭을 누르면 화살통 마지막 칸에 있는 화살이 꺼내집니다.", - "tooltip.relics.arrow_quiver.ability.receptacle.stat.slots.title": "화살 슬롯:", - "tooltip.relics.arrow_quiver.ability.receptacle.stat.slots.value": "%1$s 칸", - "tooltip.relics.arrow_quiver.ability.leap": "도약", - "tooltip.relics.arrow_quiver.ability.leap.description": "사용자를 바라보는 방향에서 멀어지게 만듭니다. 착지 할때까지 투명화 효과를 적용합니다. 공중에서 활을 조준할 시 공중에 고정되며 피해가 증가하고 다음 치명타에 대한 중력이 무효화 됩니다.", - "tooltip.relics.arrow_quiver.ability.leap.stat.multiplier.title": "추가피해:", - "tooltip.relics.arrow_quiver.ability.leap.stat.multiplier.value": "+%1$s%%.", - "tooltip.relics.arrow_quiver.ability.leap.stat.duration.title": "최대 시간:", - "tooltip.relics.arrow_quiver.ability.leap.stat.duration.value": "%1$s 초", - "tooltip.relics.arrow_quiver.ability.leap.stat.cooldown.title": "쿨타임:", - "tooltip.relics.arrow_quiver.ability.leap.stat.cooldown.value": "%1$s 초", - "tooltip.relics.arrow_quiver.ability.leap.predicate.target": "발밑 블록을 바라보세요", - "tooltip.relics.arrow_quiver.ability.agility": "재치", - "tooltip.relics.arrow_quiver.ability.agility.description": "현재 장력의 속도를 증가시킵니다.", - "tooltip.relics.arrow_quiver.ability.agility.stat.modifier.title": "최대 속도:", - "tooltip.relics.arrow_quiver.ability.agility.stat.modifier.value": "%1$s%%.", - "tooltip.relics.arrow_quiver.ability.rain": "화살비", - "tooltip.relics.arrow_quiver.ability.rain.description": "«화살 저장»능력으로 내부 화살을 이용해 시선방향에 화살비를 내립니다. 이 능력의 영역은 하나만 존재할 수 있습니다.", - "tooltip.relics.arrow_quiver.ability.rain.stat.radius.title": "영역 크기:", - "tooltip.relics.arrow_quiver.ability.rain.stat.radius.value": "%1$s 블록", - "tooltip.relics.arrow_quiver.ability.rain.stat.duration.title": "영역 지속시간:", - "tooltip.relics.arrow_quiver.ability.rain.stat.duration.value": "%1$s 초", - "tooltip.relics.arrow_quiver.ability.rain.stat.delay.title": "화살 소환 빈도:", - "tooltip.relics.arrow_quiver.ability.rain.stat.delay.value": "%1$s 초", - "tooltip.relics.arrow_quiver.ability.rain.predicate.arrow": "화살통의 화살", - - "item.relics.blazing_flask": "Blazing Flask", - "tooltip.relics.blazing_flask.description": "«영원한 불»능력 범위 내에서 비행 5초마다 경험치 +1", - "tooltip.relics.blazing_flask.ability.bonfire": "영원한 불", - "tooltip.relics.blazing_flask.ability.bonfire.description": "블록에 유물을 사용하면 비행가능 구역이 생성되며, 그 크기는 중앙 주변 특정 반경의 불 양에 따라 달라집니다.", - "tooltip.relics.blazing_flask.ability.bonfire.stat.step.title": "불 감지 범위:", - "tooltip.relics.blazing_flask.ability.bonfire.stat.step.value": "%1$s 블록", - "tooltip.relics.blazing_flask.ability.bonfire.stat.speed.title": "비행 속도:", - "tooltip.relics.blazing_flask.ability.bonfire.stat.speed.value": "%1$s 초당 블록", - "tooltip.relics.blazing_flask.ability.bonfire.stat.height.title": "비행 고도:", - "tooltip.relics.blazing_flask.ability.bonfire.stat.height.value": "%1$s 블록", - - "item.relics.elytra_booster": "Elytra Booster", - "tooltip.relics.elytra_booster.description": "«가속»능력을 통해 유물 내부 버퍼에 연료를 넣을때 연소되는 연로 10초당 경험치 +1", - "tooltip.relics.elytra_booster.ability.boost": "가속", - "tooltip.relics.elytra_booster.ability.boost.description": "인벤토리에 있는 유물에 가연성 연료를 사용하면 내부 버퍼가 보충됩니다. 비행 중에 부스터의 능력을 사용하면 사용자가 부스팅 되며 내부 버퍼에 연료가 소모됩니다.", - "tooltip.relics.elytra_booster.ability.boost.stat.capacity.title": "용량:", - "tooltip.relics.elytra_booster.ability.boost.stat.capacity.value": "%1$s 유닛", - "tooltip.relics.elytra_booster.ability.boost.stat.speed.title": "속도:", - "tooltip.relics.elytra_booster.ability.boost.stat.speed.value": "%1$s 초당 블록", - "tooltip.relics.elytra_booster.ability.boost.predicate.elytra": "겉날개를 이용해 날고있는 상태여야 합니다.", - "tooltip.relics.elytra_booster.ability.boost.predicate.fuel": "부스터 내에 연료가 있어야합니다.", - - "item.relics.midnight_robe": "Midnight Robe", - "tooltip.relics.midnight_robe.description": "«사라짐»능력으로투명 상태에서 공격할 때 피해 2단위당 경험치 +1", - "tooltip.relics.midnight_robe.ability.vanish": "사라짐", - "tooltip.relics.midnight_robe.ability.vanish.description": "사용자에게 완전한 투명효과를 부여하고 낮은 조명 수준에서 이동속도를 높입니다.", - "tooltip.relics.midnight_robe.ability.vanish.stat.light.title": "최소 조명 레벨:", - "tooltip.relics.midnight_robe.ability.vanish.stat.light.value": "%1$s.", - "tooltip.relics.midnight_robe.ability.vanish.stat.speed.title": "최대 속도:", - "tooltip.relics.midnight_robe.ability.vanish.stat.speed.value": "%1$s%%.", - "tooltip.relics.midnight_robe.ability.backstab": "배신", - "tooltip.relics.midnight_robe.ability.backstab.description": "«사라짐»능력의 공격은 피해를 증가시켜 대상 주위에 원의 윤곽을 그리며 착용자의 투명 효과를 해제합니다. «사라짐»능력의 재사용은 착용자가 원을 떠난 후에만 가능합니다.", - "tooltip.relics.midnight_robe.ability.backstab.stat.damage.title": "데미지 계수:", - "tooltip.relics.midnight_robe.ability.backstab.stat.damage.value": "%1$s%%.", - "tooltip.relics.midnight_robe.ability.backstab.stat.distance.title": "원 크기:", - "tooltip.relics.midnight_robe.ability.backstab.stat.distance.value": "%1$s 블록", - - "item.relics.reflection_necklace": "Reflecting Necklace", - "tooltip.relics.reflection_necklace.description": "«불지옥의 증오»능력으로 인해 유물 내부 버퍼에 누적된 피해 10당 경험치 +1", - "tooltip.relics.reflection_necklace.ability.explode": "불지옥의 증오", - "tooltip.relics.reflection_necklace.ability.explode.description": "사용자가 받은 데미지를 유물 내부 버퍼에 축적합니다. 마지막 피해 후 5초 또는 버퍼 오버플로우 시 유물이 폭발하며 흑요석 조각을 사방으로 퍼트리며 피해를 주고 대상을 기절시킵니다.", - "tooltip.relics.reflection_necklace.ability.explode.stat.capacity.title": "데미지 용량:", - "tooltip.relics.reflection_necklace.ability.explode.stat.capacity.value": "%1$s 유닛", - "tooltip.relics.reflection_necklace.ability.explode.stat.damage.title": "용량 단위당 데미지:", - "tooltip.relics.reflection_necklace.ability.explode.stat.damage.value": "%1$s 유닛.", - "tooltip.relics.reflection_necklace.ability.explode.stat.stun.title": "용량 단위당 기절:", - "tooltip.relics.reflection_necklace.ability.explode.stat.stun.value": "%1$s 초", - - "item.relics.jellyfish_necklace": "Jellyfish Necklace", - "tooltip.relics.jellyfish_necklace.description": "«방전»능력 활성화 시 마다 경험치 +1", - "tooltip.relics.jellyfish_necklace.ability.unsinkable": "바다 위의 힘", - "tooltip.relics.jellyfish_necklace.ability.unsinkable.description": "사용자는 물에 가라앉지 않습니다 ", - "tooltip.relics.jellyfish_necklace.ability.shock": "방전", - "tooltip.relics.jellyfish_necklace.ability.shock.description": "대상과 충돌하면 피해를 입힙니다.", - "tooltip.relics.jellyfish_necklace.ability.shock.stat.damage.title": "데미지:", - "tooltip.relics.jellyfish_necklace.ability.shock.stat.damage.value": "%1$s 유닛", - "tooltip.relics.jellyfish_necklace.ability.paralysis": "마비", - "tooltip.relics.jellyfish_necklace.ability.paralysis.description": "능력이 발동되면 «방전»능력이 대상에게 마비 효과를 부여합니다.", - "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration.title": "효과 지속시간:", - "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration.value": "%1$s 초", - - "item.relics.spore_sack": "Spore Sack", - "tooltip.relics.spore_sack.description": "«독 합성»능력에 의해 방출된 각 포자에 대해 경험치 +1 \n «분해» 능력에 의해 분할된 각 추가 포자 마다 경험치 +1", - "tooltip.relics.spore_sack.ability.spore": "독 합성", - "tooltip.relics.spore_sack.ability.spore.description": "피해를 입을 때 무작위 방향으로 포자를 방출합니다. 이 포자는 표면에 달라붙어 대상이 접근하면 폭팔하며 피해를 주고, 중독시키고, 둔화시키고, 5초동안 치유를 차단합니다.", - "tooltip.relics.spore_sack.ability.spore.stat.size.title": "크기:", - "tooltip.relics.spore_sack.ability.spore.stat.size.value": "받은 데미지 당 %1$s ", - "tooltip.relics.spore_sack.ability.spore.stat.damage.title": "데미지:", - "tooltip.relics.spore_sack.ability.spore.stat.damage.value": "크기당 %1$s ", - "tooltip.relics.spore_sack.ability.spore.stat.cooldown.title": "쿨타임:", - "tooltip.relics.spore_sack.ability.spore.stat.cooldown.value": "%1$s 초", - "tooltip.relics.spore_sack.ability.spore.stat.duration.title": "지속 시간:", - "tooltip.relics.spore_sack.ability.spore.stat.duration.value": "%1$s 초", - "tooltip.relics.spore_sack.ability.buffer": "독 축적", - "tooltip.relics.spore_sack.ability.buffer.description": "«독 합성»능력의 재사용 대기시간이 발생 할 때마다 다른 능력에서 포자를 방출하는 데 사용할 수 있는 유물의 내부 버퍼에 하나의 충전이 축적됩니다. 다른 능력에 대한 충전 요청 시 내부 버퍼에서 포자를 소모하지 않을 확률을 추가합니다.", - "tooltip.relics.spore_sack.ability.buffer.stat.capacity.title": "용량:", - "tooltip.relics.spore_sack.ability.buffer.stat.capacity.value": "%1$s 포자.", - "tooltip.relics.spore_sack.ability.buffer.stat.chance.title": "확률:", - "tooltip.relics.spore_sack.ability.buffer.stat.chance.value": "%1$s%%.", - "tooltip.relics.spore_sack.ability.multiplying": "분해", - "tooltip.relics.spore_sack.ability.multiplying.description": "각 포자는 폭발 시 주어진 범위 내에서 여러 개의 작은 포자로 분할될 수 있습니다. 최대 포자 수는 주 포자 크기의 정도에 따라 결정되지만, 최종 수는 포자 분열이 실패할 첫 번째 기회에 따라 제한됩니다.", - "tooltip.relics.spore_sack.ability.multiplying.stat.chance.title": "분할 기회:", - "tooltip.relics.spore_sack.ability.multiplying.stat.chance.value": "%1$s%%.", - "tooltip.relics.spore_sack.ability.multiplying.stat.size.title": "포자 크기:", - "tooltip.relics.spore_sack.ability.multiplying.stat.size.value": "%1$s%% 주요 포자.", - "tooltip.relics.spore_sack.ability.multiplying.stat.amount.title": "포자 크기 정도:", - "tooltip.relics.spore_sack.ability.multiplying.stat.amount.value": "%1$s.", - "tooltip.relics.spore_sack.ability.explosion": "독 방출", - "tooltip.relics.spore_sack.ability.explosion.description": "유물의 버퍼를 비워 축정된 포자 전하를 모두 방출합니다. 방출되는 포자의 크기는 사용자의 잃어버린 체력에 따라 달라집니다.", - "tooltip.relics.spore_sack.ability.explosion.stat.size.title": "포자 크기:", - "tooltip.relics.spore_sack.ability.explosion.stat.size.value": "잃어버린 체력 당 %1$s ", - "tooltip.relics.spore_sack.ability.explosion.predicate.spore": "자루의 포자", - - "item.relics.ice_breaker": "Ice Breaker", - "tooltip.relics.ice_breaker.description": "«지진»능력을 발동하기 전 떨어진 3블록 마다 경험치 +1", - "tooltip.relics.ice_breaker.ability.sustainability": "지속 가능성", - "tooltip.relics.ice_breaker.ability.sustainability.description": "낙하 속도가 증가하고 넉백 저항이 증가하며 미끄러지는 블록을 제거합니다.", - "tooltip.relics.ice_breaker.ability.sustainability.stat.modifier.title": "넉백 저항:", - "tooltip.relics.ice_breaker.ability.sustainability.stat.modifier.value": "%1$s%%.", - "tooltip.relics.ice_breaker.ability.impact": "지진", - "tooltip.relics.ice_breaker.ability.impact.description": "낙하 시 능력을 사용 하면 착지 지점에 충격파가 발생하여 주변 대상에게 피해를 입히고 던져버립니다. 충격파의 힘은 착용자가 떨어진 거리에 따라 달라집니다.", - "tooltip.relics.ice_breaker.ability.impact.stat.size.title": "최대 사거리:", - "tooltip.relics.ice_breaker.ability.impact.stat.size.value": "%1$s 블록", - "tooltip.relics.ice_breaker.ability.impact.stat.damage.title": "최소 데미지:", - "tooltip.relics.ice_breaker.ability.impact.stat.damage.value": "%1$s 유닛.", - "tooltip.relics.ice_breaker.ability.impact.predicate.falling": "자유 낙하", - - "item.relics.bastion_ring": "Bastion Ring", - "tooltip.relics.bastion_ring.description": "좀비 피글린/피글린/난폭한 피글린을 죽였을 때 마다 경험치 +1/5/10 \n «존중» 능력으로 추가 거래할때마다 경험치 +1", - "tooltip.relics.bastion_ring.ability.compass": "인식", - "tooltip.relics.bastion_ring.ability.compass.description": "피글린을 사용자에 대해 중립으로 만듭니다. 가장 가까운 피글린은 근처 요새의 위치를 나타냅니다.", - "tooltip.relics.bastion_ring.ability.trade": "존중", - "tooltip.relics.bastion_ring.ability.trade.description": "피글린과의 거래 중 50%의 확률로 추가 거래가 발생할 수 있습니다.", - "tooltip.relics.bastion_ring.ability.trade.stat.rolls.title": "최대 거래 수:", - "tooltip.relics.bastion_ring.ability.trade.stat.rolls.value": "%1$s 유닛.", - - "item.relics.horse_flute": "Horse Flute", - "tooltip.relics.horse_flute.description": "«Portable Stall»능력으로 불리는 말이 블록 25개를 이동할때 마다 경험치 +1", - "tooltip.relics.horse_flute.ability.paddock": "휴대용 스톨", - "tooltip.relics.horse_flute.ability.paddock.description": "말에게 유물을 사용하면 동물이 내부 창고로 이동합니다. 재사용 시 말을 내보냅니다. 사용자와 소환된 말 사이의 거리가 16블록을 초과하면 자동으로 피리에 다시 들어옵니다.", - "tooltip.relics.horse_flute.ability.paddock.stat.slots.title": "슬롯:", - "tooltip.relics.horse_flute.ability.paddock.stat.slots.value": "%1$s.", - "tooltip.relics.horse_flute.ability.heal": "플롯 치유", - "tooltip.relics.horse_flute.ability.heal.description": "내부 저장소에 있는 말은 천천히 체력을 회복합니다.", - "tooltip.relics.horse_flute.ability.heal.stat.amount.title": "회복량:", - "tooltip.relics.horse_flute.ability.heal.stat.amount.value": "%1$s 초당 체력", - - "item.relics.magma_walker": "Magma Walker", - "tooltip.relics.magma_walker.description": "«불 같은 트레드»능력으로 가열 5단위당 경험치 +1", - "tooltip.relics.magma_walker.ability.pace": "불 같은 트레드", - "tooltip.relics.magma_walker.ability.pace.description": "일정 시간 동안 가라앉거나 피해를 입지 않고 용암 표면을 걸을 수 있습니다. 제한 시간이 지나면 부츠가 과열되기 시작하며 과열 정도에 비례하여 착용자에게 피해를 입힙니다.", - "tooltip.relics.magma_walker.ability.pace.stat.time.title": "지속:", - "tooltip.relics.magma_walker.ability.pace.stat.time.value": "%1$s 초", - "tooltip.relics.magma_walker.ability.heat_resistance": "내열성", - "tooltip.relics.magma_walker.ability.heat_resistance.description": "뜨거운 블록으로 인한 손상을 억제합니다.", - - "item.relics.aqua_walker": "Aqua Walker", - "tooltip.relics.aqua_walker.description": "«습기 저항»능력으로 인해 젖는 5단위당 경험치 +1", - "tooltip.relics.aqua_walker.ability.walking": "습기 저항", - "tooltip.relics.aqua_walker.ability.walking.description": "일정 시간 동안 가라앉지 않고 물 표면에서 이동할 수 있습니다. 제한 시간이 지나면 부츠가 가라앉기 시작하여 착용자를 물속으로 끌고 갑니다.", - "tooltip.relics.aqua_walker.ability.walking.stat.time.title": "지속:", - "tooltip.relics.aqua_walker.ability.walking.stat.time.value": "%1$s 초", - - "item.relics.drowned_belt": "Drowned Belt", - "tooltip.relics.drowned_belt.description": "삼지창을 사용 할 때 인첸트 «급류»레벨 당 +1 경험치를 얻습니다.", - "tooltip.relics.drowned_belt.ability.slots": "부하 용량", - "tooltip.relics.drowned_belt.ability.slots.description": "장비 유물의 최대 슬롯 수가 증가합니다.", - "tooltip.relics.drowned_belt.ability.slots.stat.talisman.title": "유물:", - "tooltip.relics.drowned_belt.ability.slots.stat.talisman.value": "+%1$s 슬롯", - "tooltip.relics.drowned_belt.ability.anchor": "사하중", - "tooltip.relics.drowned_belt.ability.anchor.description": "착용자의 수영 속도가 감소가혹 가라앉는 속도가 증가합니다", - "tooltip.relics.drowned_belt.ability.anchor.stat.slowness.title": "느려지는 수영 속도:", - "tooltip.relics.drowned_belt.ability.anchor.stat.slowness.value": "+%1$s%%.", - "tooltip.relics.drowned_belt.ability.anchor.stat.sinking.title": "가라앉는 속도:", - "tooltip.relics.drowned_belt.ability.anchor.stat.sinking.value": "+%1$s%%.", - "tooltip.relics.drowned_belt.ability.pressure": "물의 흐름", - "tooltip.relics.drowned_belt.ability.pressure.description": "수중 피해량이 증가합니다.", - "tooltip.relics.drowned_belt.ability.pressure.stat.damage.title": "피해량:", - "tooltip.relics.drowned_belt.ability.pressure.stat.damage.value": "+%1$s%%.", - "tooltip.relics.drowned_belt.ability.riptide": "워터 어트렉션", - "tooltip.relics.drowned_belt.ability.riptide.description": "비나 물 없이도 삼지창 «급류»능력을 사용할 수 있으며 재충전 시간이 추가됩니다.", - "tooltip.relics.drowned_belt.ability.riptide.stat.cooldown.title": "재충전 시간:", - "tooltip.relics.drowned_belt.ability.riptide.stat.cooldown.value": "인첸트 레벨당 %1$s초", - - "item.relics.hunter_belt": "Hunter Belt", - "tooltip.relics.hunter_belt.description": "사용자의 애완동물이 공격할 때마다 경험치 +1", - "tooltip.relics.hunter_belt.ability.slots": "부하 용량", - "tooltip.relics.hunter_belt.ability.slots.description": "부적 장착을 위한 최대 슬롯 수가 증가합니다.", - "tooltip.relics.hunter_belt.ability.slots.stat.talisman.title": "유물:", - "tooltip.relics.hunter_belt.ability.slots.stat.talisman.value": "+%1$s 슬롯", - "tooltip.relics.hunter_belt.ability.training": "훈련", - "tooltip.relics.hunter_belt.ability.training.description": "사용자의 애완동물이 입히는 피해가 증가합니다.", - "tooltip.relics.hunter_belt.ability.training.stat.damage.title": "데미지 계수:", - "tooltip.relics.hunter_belt.ability.training.stat.damage.value": "+%1$s%%.", - - "item.relics.leather_belt": "Leather Belt", - "tooltip.relics.leather_belt.description": "유물을 장착하여 얻은 경험치당 경험치+1", - "tooltip.relics.leather_belt.ability.slots": "부하 용량", - "tooltip.relics.leather_belt.ability.slots.description": "부적 장착을 위한 최대 슬롯 수가 증가합니다.", - "tooltip.relics.leather_belt.ability.slots.stat.talisman.title": "부적:", - "tooltip.relics.leather_belt.ability.slots.stat.talisman.value": "+%1$s 슬롯", - - "item.relics.rage_glove": "Rage Glove", - "tooltip.relics.rage_glove.description": "«버서커의 분노»능력이 3회 충전될 때마다 경험치 +1, «스퍼트»능력으로 적중한 각 대상마다 경험치 +1", - "tooltip.relics.rage_glove.ability.rage": "버서커의 분노", - "tooltip.relics.rage_glove.ability.rage.description": "마지막 피격 후 3초 이내에 사용자가 공격 할 때마다 유물 내부 버퍼에 1개의 충전이 축적됩니다. 누적된 충전량에 비례하여 사용자가 입히고 받는 피해, 이동 속도, 입피는 피해가 증가합니다. 3초 후 유물 내부 버퍼가 비워지고, 받는 보너스가 모두 제거됩니다.", - "tooltip.relics.rage_glove.ability.rage.stat.duration.title": "충전 유효 시간:", - "tooltip.relics.rage_glove.ability.rage.stat.duration.value": "%1$s 초", - "tooltip.relics.rage_glove.ability.rage.stat.incoming_damage.title": "받는 피해 비율:", - "tooltip.relics.rage_glove.ability.rage.stat.incoming_damage.value": "충전당 %1$s%% ", - "tooltip.relics.rage_glove.ability.rage.stat.dealt_damage.title": "피해량 배율:", - "tooltip.relics.rage_glove.ability.rage.stat.dealt_damage.value": "충전당 %1$s%% ", - "tooltip.relics.rage_glove.ability.phlebotomy": "정맥 절개", - "tooltip.relics.rage_glove.ability.phlebotomy.description": "사용자의 공격 속도와 이동 속도가 증가하고, 잃은 체력 비율에 비례하여 재생이 부여됩니다.", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.heal.title": "체력 재생:", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.heal.value": "1$s 초당 %1%% 회복", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.movement_speed.title": "이동 속도 배수:", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.movement_speed.value": "%1$s%% for 1%%.", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.attack_speed.title": "공격 속도 배율:", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.attack_speed.value": "%1$s%% for 1%%.", - "tooltip.relics.rage_glove.ability.spurt": "스퍼트", - "tooltip.relics.rage_glove.ability.spurt.description": "시야 방향을 향해 돌진해 불을 붙이고 출혈을 가하며 손에 든 아이템을 들고 경로상의 각 대상을 공격합니다. «버서커의 분노»능력으로 유물 내부 버퍼에 충전 된 횟수에 비례하여 추가 피해를 주며 파괴합니다.", - "tooltip.relics.rage_glove.ability.spurt.stat.cooldown.title": "쿨타임:", - "tooltip.relics.rage_glove.ability.spurt.stat.cooldown.value": "%1$s 초", - "tooltip.relics.rage_glove.ability.spurt.stat.damage.title": "피해량 배율:", - "tooltip.relics.rage_glove.ability.spurt.stat.damage.value": "충전당 %1$s ", - "tooltip.relics.rage_glove.ability.spurt.stat.distance.title": "거리:", - "tooltip.relics.rage_glove.ability.spurt.stat.distance.value": "%1$s 블록", - - "item.relics.ice_skates": "Ice Skates", - "tooltip.relics.ice_skates.description": "«스케이팅»능력으로 가속 1초마다 경험치 +1", - "tooltip.relics.ice_skates.ability.skating": "스케이팅", - "tooltip.relics.ice_skates.ability.skating.description": "미끄러지는 시간에 따라 얼음 위의 이동 속도가 증가합니다.", - "tooltip.relics.ice_skates.ability.skating.stat.speed.title": "초당 속도 배율:", - "tooltip.relics.ice_skates.ability.skating.stat.speed.value": "%1$s%%.", - "tooltip.relics.ice_skates.ability.skating.stat.duration.title": "최대 시간:", - "tooltip.relics.ice_skates.ability.skating.stat.duration.value": "%1$s 초 ", - "tooltip.relics.ice_skates.ability.ram": "염소", - "tooltip.relics.ice_skates.ability.ram.description": "대상과 충돌 시 «스케이팅» 능력 사용 시간에 비례하여 피해를 입힙니다.", - "tooltip.relics.ice_skates.ability.ram.stat.damage.title": "초당 피해:", - "tooltip.relics.ice_skates.ability.ram.stat.damage.value": "%1$s 유닛", - - "item.relics.amphibian_boot": "Amphibian Boot", - "tooltip.relics.amphibian_boot.description": "«지느러미»능력으로 인해 매초 가속할 때 마다 경험치 +1", - "tooltip.relics.amphibian_boot.ability.swimming": "지느러미", - "tooltip.relics.amphibian_boot.ability.swimming.description": "지속 시간에 따라 수영 속도가 빨라집니다..", - "tooltip.relics.amphibian_boot.ability.swimming.stat.speed.title": "속도 배율:", - "tooltip.relics.amphibian_boot.ability.swimming.stat.speed.value": "초당 %1$s%%", - "tooltip.relics.amphibian_boot.ability.swimming.stat.duration.title": "최대 시간:", - "tooltip.relics.amphibian_boot.ability.swimming.stat.duration.value": "%1$s 초", - - "item.relics.spatial_sign": "Spatial Sign", - "tooltip.relics.spatial_sign.description": "«타임 리프트»능력으로 복귀할 때 마다 경험치 +1", - "tooltip.relics.spatial_sign.ability.seal": "타임 리프트", - "tooltip.relics.spatial_sign.ability.seal.description": "사용 시 일정 시간 동안 이동한 경로를 다라 사용자를 되돌린다. 재사용 시 능력이 종료됩니다.", - "tooltip.relics.spatial_sign.ability.seal.stat.time.title": "최대 거리:", - "tooltip.relics.spatial_sign.ability.seal.stat.time.value": "%1$s 초", - - "item.relics.chorus_inhibitor": "Chorus Inhibitor", - "tooltip.relics.chorus_inhibitor.description": "«순간이동 제어»능력으로 순간이동 지점까지 10블록마다 경험치 +1", - "tooltip.relics.chorus_inhibitor.ability.blink": "순간이동 제어", - "tooltip.relics.chorus_inhibitor.ability.blink.description": "후렴과를 사용하면 사용자가 바라보는 지점으로 순간이동 한다.", - "tooltip.relics.chorus_inhibitor.ability.blink.stat.distance.title": "최대 거리:", - "tooltip.relics.chorus_inhibitor.ability.blink.stat.distance.value": "%1$s 블록.", - "tooltip.relics.chorus_inhibitor.ability.blink.stat.cooldown.title": "재사용 시간:", - "tooltip.relics.chorus_inhibitor.ability.blink.stat.cooldown.value": "%1$s 초", - - "item.relics.wool_mitten": "Wool Mitten", - "item.relics.solid_snowball": "얼어붙은 눈덩이", - "tooltip.relics.wool_mitten.description": "«몰드»능력으로 눈덩이를 맞추면 크기 5단위당 경험치 +1", - "tooltip.relics.wool_mitten.ability.mold": "몰드", - "tooltip.relics.wool_mitten.ability.mold.description": "빈손으로 우클릭에 눈을 모으면 점차 특별한 단단한 눈덩이가 형성됩니다. 눈덩이를 목표물에 맞히면 피해를 입히고 기절시킬 뿐만 아니라 근처의 목표물도 얼어 붙습니다. 유물을 장착하지 않은 상태에서 눈덩이를 들고 있으면 사용자가 얼어붙습니다.", - "tooltip.relics.wool_mitten.ability.mold.stat.size.title": "최대 크기:", - "tooltip.relics.wool_mitten.ability.mold.stat.size.value": "%1$s 유닛", - "tooltip.relics.wool_mitten.ability.mold.stat.damage.title": "데미지:", - "tooltip.relics.wool_mitten.ability.mold.stat.damage.value": "크기당 %1$s ", - "tooltip.relics.wool_mitten.ability.mold.stat.stun.title": "스턴:", - "tooltip.relics.wool_mitten.ability.mold.stat.stun.value": "크기당 %1$s초", - "tooltip.relics.wool_mitten.ability.mold.stat.freeze.title": "동상:", - "tooltip.relics.wool_mitten.ability.mold.stat.freeze.value": "크기당 %1$s초", - - "item.relics.roller_skates": "Roller Skates", - "tooltip.relics.roller_skates.description": "«가속»능력으로 가속 1초당 경험치 +1", - "tooltip.relics.roller_skates.ability.skating": "가속", - "tooltip.relics.roller_skates.ability.skating.description": "지속시간에 따라 이동 속도가 증가합니다. 모든 블록은 사용자가 미끄러지게 합니다.", - "tooltip.relics.roller_skates.ability.skating.stat.speed.title": "초당 속도 배율:", - "tooltip.relics.roller_skates.ability.skating.stat.speed.value": "%1$s%%.", - "tooltip.relics.roller_skates.ability.skating.stat.duration.title": "최대 시간:", - "tooltip.relics.roller_skates.ability.skating.stat.duration.value": "%1$s 초", - - "item.relics.space_dissector": "Space Dissector", - "tooltip.relics.space_dissector.description": "기존 포탈이 없는 경우 생성된 포탈 마다 경험치 +1", - "tooltip.relics.space_dissector.ability.dissection": "해부", - "tooltip.relics.space_dissector.ability.dissection.description": "우클릭을 누르고 있으면 시선을 따라 있는 지점에 포탈이 생성되고 우클릭을 떼면 동일안 원리에 따라 두번째 포탈이 생성되어 첫번째 포탈과 연결됩니다. 살아있는 생명체를 포탈 중 하나로 데려오면 연결된 포탈로 이동합니다. 경로에 단단한 블록이 있으면 포탈이 작동하지 않습니다 ", - "tooltip.relics.space_dissector.ability.dissection.stat.distance.title": "최대 거리:", - "tooltip.relics.space_dissector.ability.dissection.stat.distance.value": "%1$s 블록", - "tooltip.relics.space_dissector.ability.dissection.stat.time.title": "포탈 지속시간:", - "tooltip.relics.space_dissector.ability.dissection.stat.time.value": "%1$s 초", - - "block.relics.researching_table": "연구 탁자", - - "effect.relics.stun": "스턴", - "effect.relics.paralysis": "마비", - "effect.relics.confusion": "혼란", - "effect.relics.vanishing": "사라지다", - "effect.relics.anti_heal": "안티 힐", - "effect.relics.bleeding": "출혈", - - "command.relics.base.not_relic": "손에 유물을 들고 있어야 합니다!", - - "key.relics.ability_list": "액티브 스킬 보기" -} \ No newline at end of file +{ + "itemGroup.relics": "Relics", + + "curios.identifier.feet": "피트", + + "tooltip.relics.researching.info": "연구하려면 [Shift]를 누르세요...", + + "tooltip.relics.relic.tooltip.abilities": "능력:", + + "tooltip.relics.researching.badge.ability.oblivion.title": "오블리비언에 약함", + "tooltip.relics.researching.badge.ability.oblivion.description": "본 능력은 오블리비언에 영향을 받을 시 사용이 제한됩니다.", + "tooltip.relics.researching.badge.ability.silence.title": "침묵에 약함", + "tooltip.relics.researching.badge.ability.silence.description": "본 능력은 침묵에 영향을 받을 시 사용이 제한됩니다.", + "tooltip.relics.researching.badge.ability.flawless_ability.title": "무결점 능력", + "tooltip.relics.researching.badge.ability.flawless_ability.description": "본 능력이 완벽한 수준에 도달했습니다. 자랑스러워하세요!", + "tooltip.relics.researching.badge.ability.instantaneous.title": "즉시 사용", + "tooltip.relics.researching.badge.ability.instantaneous.description": "본 능력은 사용 즉시 발동됩니다.", + "tooltip.relics.researching.badge.ability.interruptible.title": "중단 가능", + "tooltip.relics.researching.badge.ability.interruptible.description": "본 능력은 사용 후 일정 시간 동안 지속되며, 한번 더 사용하면 중단 시킬 수 있습니다.", + "tooltip.relics.researching.badge.ability.cyclical.title": "반복 사용", + "tooltip.relics.researching.badge.ability.cyclical.description": "본 능력은 계속해서 사용해야 유지됩니다.", + "tooltip.relics.researching.badge.ability.toggleable.title": "ON/OFF 가능", + "tooltip.relics.researching.badge.ability.toggleable.description": "본 능력은 ON/OFF 할 수 있습니다.", + "tooltip.relics.researching.badge.ability.chargeable.title": "충전 후 사용가능", + "tooltip.relics.researching.badge.ability.chargeable.description": "본 능력은 일정 시간마다 주기적으로 사용 가능 횟수가 충전되며, 사용한 시간에 따라 효과가 달라질 수 있습니다.", + "tooltip.relics.researching.badge.ability.stated.title": "순환 사용", + "tooltip.relics.researching.badge.ability.stated.description": "본 능력은 사용할 때마다 순환하는 여러 모드를 가지고 있습니다.", + + "tooltip.relics.researching.badge.relic.flawless_relic.title": "완벽한 유물", + "tooltip.relics.researching.badge.relic.flawless_relic.description": "유물이 완벽한 수치에 도달했습니다. 자랑스러워하세요!", + + "tooltip.relics.researching.research.tip": "능력을 잠금 해제하려면 안개 아래에 숨겨진 별들을 연결하여 별자리를 만들어야 합니다. 별자리가 올바르게 연결되면 능력이 자동으로 연구됩니다.", + + "tooltip.relics.researching.research.hint.description": "Hint", + "tooltip.relics.researching.research.hint.cost": "비용: %1$s 경험치 레벨 %2$s.", + "tooltip.relics.researching.research.hint.quick": "[Shift] 키를 누르고 있으면 능력 연구가 완전 자동으로 진행됩니다.", + "tooltip.relics.researching.research.hint.locked": "이미 연구된 능력입니다!", + + "tooltip.relics.researching.badge.ability.cast_type.hint": "[%1$s] 키를 인터페이스 외부에서 누르면 사용 가능한 능력 메뉴가 나타납니다!", + + "tooltip.relics.researching.general.leveling_point.title": "레벨 포인트:", + "tooltip.relics.researching.general.leveling_point.extra_info": "유물의 레벨이 오를 때 획득되며 능력 업그레이드에 사용됩니다.", + + "tooltip.relics.researching.general.player_experience.title": "경험치 레벨:", + "tooltip.relics.researching.general.player_experience.extra_info": "마인크래프트 기본 레벨을 뜻하며 몹을 죽이고, 광물을 캐고, 아이템을 화로에 넣고 녹이거나 했을 때 얻을 수 있습니다.", + + "tooltip.relics.researching.general.luck.title": "운:", + "tooltip.relics.researching.general.luck.extra_info": "유물 스탯 재분배를 실패할때마다 올라가며, 다음 재분배에서 더 좋은 스탯을 얻을 확률이 증가합니다. 행운이 25% 증가할 때마다 재분배 비용이 경험치 레벨 1만큼 증가합니다.", + + "tooltip.relics.researching.relic.card.low_level": "이 유물을 사용하려면 레벨 %1$s로 업그레이드해야 합니다!", + "tooltip.relics.researching.relic.card.no_stats": "이 능력은 업그레이드 가능한 스탯이 없으며 유물의 품질에 영향을 주지 않습니다!", + "tooltip.relics.researching.relic.card.unresearched": "사용하려면 연구를 진행해야 합니다!", + "tooltip.relics.researching.relic.card.ready_to_unlock": "능력을 잠금 해제할 수 있습니다! 남은 클릭 횟수: %1$s", + "tooltip.relics.researching.relic.card.ready_to_upgrade": "이 능력은 업그레이드할 준비가 되었습니다!", + + "tooltip.relics.researching.relic.gem.low_level": "유물 경험치를 활성화하려면 최소 %1$s 레벨까지 올려야 합니다!", + "tooltip.relics.researching.relic.gem.locked_ability": "유물 경험치를 활성화하려면 관련된 능력을 잠금 해제하고 연구해야 합니다!", + + "tooltip.relics.researching.tab.relic": "유물", + "tooltip.relics.researching.tab.ability": "능력", + "tooltip.relics.researching.tab.experience": "유물 경험치", + + "tooltip.relics.researching.general.extra_info": "[Shift] 키를 누르면 추가 정보를 볼 수 있습니다.", + + "tooltip.relics.researching.relic.info.level": "유물 레벨:", + "tooltip.relics.researching.relic.info.quality": "유물 품질:", + "tooltip.relics.researching.relic.info.extra_info": "유물 품질은 현재 잠금 해제된 모든 능력의 품질의 산술 평균으로 1에서 5까지 0.5 단위로 측정됩니다. 이는 순전히 시각적 지표로, 아이템의 초기 무작위 특성이 최상의 상태에 얼마나 가까운지를 나타냅니다. 유물의 전체 품질을 향상시키려면 각 능력을 개별적으로 고려해야 합니다.", + + "tooltip.relics.researching.relic.experience.title": "유물 경험치:", + "tooltip.relics.researching.relic.experience.extra_info": "유물의 능력을 의도된 용도로 사용할 때, 또는 다른 유물로부터 경험치를 획득할 때 얻습니다. 최대 경험치에 도달하면 유물 레벨과 레벨 포인트가 1 증가하여 잠금 해제되지 않은 능력을 잠금 해제하거나 기존 능력을 업그레이드할 수 있습니다.", + + "tooltip.relics.researching.ability.info.level": "능력 레벨:", + "tooltip.relics.researching.ability.info.quality": "능력 품질:", + "tooltip.relics.researching.ability.info.extra_info": "능력 품질은 유물 품질과 유사하게, 현재 능력의 모든 특성의 산술 평균으로 1에서 5까지 0.5 단위로 측정됩니다. 이는 순전히 시각적 지표로, 능력의 초기 무작위 특성이 최상의 상태에 얼마나 가까운지를 나타냅니다. 능력의 품질을 향상시키려면 무작위 특성을 재분배하여 더 나은 값을 얻어야 합니다.", + + "tooltip.relics.relic.status.positive": "§2§l[§2§l✔§2§l]", + "tooltip.relics.relic.status.negative": "§4§l[§4§l✘§4§l]", + "tooltip.relics.relic.status.unknown": "§6§l[§6§l?§6§l]", + + "tooltip.relics.relic.upgrade.description": "레벨업", + "tooltip.relics.relic.upgrade.cost": "비용: %1$s 레벨링 포인트 %2$s, %3$s 경험치 포인트 %4$s.", + "tooltip.relics.relic.upgrade.locked": "능력이 최대 레벨에 도달했습니다.", + "tooltip.relics.relic.upgrade.quick": "[Shift] 키를 누른 상태로 클릭 시 자동으로 가능한 최고 레벨까지 업그레이드됩니다.", + + "tooltip.relics.relic.reroll.description": "스텟 재분배", + "tooltip.relics.relic.reroll.cost": "비용: %1$s 경험치 포인트 %2$s.", + "tooltip.relics.relic.reroll.quick": "[Shift] 키를 누른 상태로 클릭 시 자동으로 완벽한 수치까지 랜덤 스탯을 재분배합니다.", + "tooltip.relics.relic.reroll.warning": "[Shift] 키를 누른 상태로 클릭 시 지금의 완벽한 수치가 랜덤 수치로 스탯이 재분배 됩니다.", + + "tooltip.relics.relic.reset.description": "레벨링 포인트 초기화", + "tooltip.relics.relic.reset.cost": "비용: %1$s 경험치 포인트 %2$s.", + "tooltip.relics.relic.reset.locked": "이 능력을 사용하려면 최소 1회 이상 레벨업 해야 합니다.", + + "item.relics.infinity_ham": "무한한 햄", + "tooltip.relics.infinity_ham.description": "«재생» 능력으로 먹은 각 조각당 경험치 +1", + "tooltip.relics.infinity_ham.ability.autophagy": "재생", + "tooltip.relics.infinity_ham.ability.autophagy.description": "유물을 사용하면 재생 가능한 고기 중 하나를 소모하여 사용자의 포만감을 채웁니다.", + "tooltip.relics.infinity_ham.ability.autophagy.stat.feed.title": "포만감:", + "tooltip.relics.infinity_ham.ability.autophagy.stat.feed.value": "%1$s 칸", + "tooltip.relics.infinity_ham.ability.infusion": "연금술", + "tooltip.relics.infinity_ham.ability.infusion.description": "인벤토리에서 유물에 포션을 사용하면 포션을 소모하고 그 효과를 기억합니다. 이후 «재생» 능력을 사용할 때 사용자에게 해당 포션의 효과가 부여됩니다. 고기가 전혀 없을 경우 유물은 해당 포션 효과를 잃게 됩니다.", + "tooltip.relics.infinity_ham.ability.infusion.stat.duration.title": "효과 지속 시간:", + "tooltip.relics.infinity_ham.ability.infusion.stat.duration.value": "충전당 %1$s초", + + "item.relics.enders_hand": "엔더 핸드", + "tooltip.relics.enders_hand.description": "«엔드 전이» 능력 사용 시 경험치 +1\n타겟과 사용자 사이 거리 10블록마다 경험치 +1", + "tooltip.relics.enders_hand.ability.neutrality": "중립", + "tooltip.relics.enders_hand.ability.neutrality.description": "사용자에 대해 엔더맨을 중립 상태로 만듭니다.", + "tooltip.relics.enders_hand.ability.swap": "엔드 전이", + "tooltip.relics.enders_hand.ability.swap.description": "시야 내의 대상과 사용자의 위치를 바꿉니다.", + "tooltip.relics.enders_hand.ability.swap.stat.distance.title": "거리:", + "tooltip.relics.enders_hand.ability.swap.stat.distance.value": "%1$s 블록", + "tooltip.relics.enders_hand.ability.swap.predicate.target": "대상을 바라보세요", + + "item.relics.holy_locket": "성스러운 로켓", + "tooltip.relics.holy_locket.description": "사용자가 적의 치유를 역이용할 수 있는 능력을 부여합니다.", + "tooltip.relics.holy_locket.ability.belief": "신념", + "tooltip.relics.holy_locket.ability.belief.description": "두 가지 모드를 가진 전환 가능한 능력: 성결과 부정. 어떤 모드에서든 능력을 활성화하면 내부 버퍼가 1 단위씩 채워집니다. 성결 모드에서는 사용자의 치유 일부를 근처 대상에게 피해로 돌리고, 충전당 받는 피해를 1% 감소시킵니다. 부정 모드에서는 근처 대상의 치유 일부를 흡수하고, 충전당 입히는 피해를 1% 증가시킵니다.", + "tooltip.relics.holy_locket.ability.belief.stat.radius.title": "범위:", + "tooltip.relics.holy_locket.ability.belief.stat.radius.value": "%1$s 블록", + "tooltip.relics.holy_locket.ability.belief.stat.amount.title": "치유/피해 수정치:", + "tooltip.relics.holy_locket.ability.belief.stat.amount.value": "원래 값의 %1$s%%", + "tooltip.relics.holy_locket.ability.belief.stat.count.title": "최대 발사체 수:", + "tooltip.relics.holy_locket.ability.belief.stat.count.value": "%1$s개", + "tooltip.relics.holy_locket.ability.belief.stat.capacity.title": "버퍼 용량:", + "tooltip.relics.holy_locket.ability.belief.stat.capacity.value": "%1$s개", + "tooltip.relics.holy_locket.ability.repentance": "참회", + "tooltip.relics.holy_locket.ability.repentance.description": "근처 언데드의 체력을 태웁니다.", + "tooltip.relics.holy_locket.ability.repentance.stat.radius.title": "범위:", + "tooltip.relics.holy_locket.ability.repentance.stat.radius.value": "%1$s 블록", + "tooltip.relics.holy_locket.ability.repentance.stat.damage.title": "입히는 피해:", + "tooltip.relics.holy_locket.ability.repentance.stat.damage.value": "충전당 %1$s", + "tooltip.relics.holy_locket.ability.blessing": "축복", + "tooltip.relics.holy_locket.ability.blessing.description": "활성화 시 사용자에게 일시적 무적을 부여하며, 매 초 유물의 내부 버퍼에서 충전량을 소모합니다.", + "tooltip.relics.holy_locket.ability.blessing.stat.consumption.title": "충전 소모량:", + "tooltip.relics.holy_locket.ability.blessing.stat.consumption.value": "초당 %1$s", + "tooltip.relics.holy_locket.ability.blessing.predicate.blessing": "내부 버퍼의 충전량", + + "item.relics.magic_mirror": "매직 미러", + "tooltip.relics.magic_mirror.description": "«웜홀» 능력 사용 시마다 경험치 +1\n순간이동 지점까지 50블록마다 경험치 +1", + "tooltip.relics.magic_mirror.ability.teleport": "웜홀", + "tooltip.relics.magic_mirror.ability.teleport.description": "사용 후 사용자를 리스폰 지점으로 순간이동 시킵니다.", + "tooltip.relics.magic_mirror.ability.teleport.stat.distance.title": "거리:", + "tooltip.relics.magic_mirror.ability.teleport.stat.distance.value": "%1$s 블록", + "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.title": "재충전:", + "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.value": "%1$s초", + + "item.relics.shadow_glaive": "섀도우 글레이브", + "tooltip.relics.shadow_glaive.description": "«맹목적인 정의» 능력에서 글레이브가 2회 튕길 때마다 경험치 +1", + "tooltip.relics.shadow_glaive.ability.glaive": "맹목적인 정의", + "tooltip.relics.shadow_glaive.ability.glaive.description": "사용 시 근처 대상 사이를 튕겨내는 글레이브 8개중 하나를 던집니다. 던진 글레이브는 일정 시간이 지나면 복원됩니다.", + "tooltip.relics.shadow_glaive.ability.glaive.stat.damage.title": "데미지:", + "tooltip.relics.shadow_glaive.ability.glaive.stat.damage.value": "%1$s.", + "tooltip.relics.shadow_glaive.ability.glaive.stat.recharge.title": "회복 시간:", + "tooltip.relics.shadow_glaive.ability.glaive.stat.recharge.value": "%1$s초.", + "tooltip.relics.shadow_glaive.ability.glaive.stat.bounces.title": "튕김:", + "tooltip.relics.shadow_glaive.ability.glaive.stat.bounces.value": "%1$s.", + "tooltip.relics.shadow_glaive.ability.glaive.stat.radius.title": "튕기는 거리:", + "tooltip.relics.shadow_glaive.ability.glaive.stat.radius.value": "%1$s 블록.", + "tooltip.relics.shadow_glaive.ability.saw": "무자비한 처형", + "tooltip.relics.shadow_glaive.ability.saw.description": "사용 시 글레이브 충전량 8개를 모두 소모하여 근처 대상에게 피해를 주는 톱을 소환합니다. 다시 사용하면 톱이 착용자에게 돌아오며, 모든 충전량을 회복됩니다. 능력이 활성화되어 있는 동안 자동 충전이 차단됩니다.", + "tooltip.relics.shadow_glaive.ability.saw.stat.speed.title": "타격 간격:", + "tooltip.relics.shadow_glaive.ability.saw.stat.speed.value": "%1$s초.", + "tooltip.relics.shadow_glaive.ability.saw.stat.damage.title": "데미지:", + "tooltip.relics.shadow_glaive.ability.saw.stat.damage.value": "%1$s 칸", + + "item.relics.arrow_quiver": "화살통", + "tooltip.relics.arrow_quiver.description": "화살로 명중한 대상과의 거리 10블록당 경험치 +1", + "tooltip.relics.arrow_quiver.ability.receptacle": "화살 보관", + "tooltip.relics.arrow_quiver.ability.receptacle.description": "활은 화살통 내부에 존재하는 화살을 우선적으로 사용합니다. 인벤토리에 있는 화살통에 화살을 들고 좌클릭을 누르면 화살통 내부에 화살이 저장됩니다. 우클릭을 누르면 화살통 마지막 칸에 있는 화살이 꺼내집니다.", + "tooltip.relics.arrow_quiver.ability.receptacle.stat.slots.title": "화살 슬롯:", + "tooltip.relics.arrow_quiver.ability.receptacle.stat.slots.value": "%1$s 칸", + "tooltip.relics.arrow_quiver.ability.leap": "도약", + "tooltip.relics.arrow_quiver.ability.leap.description": "사용자를 바라보는 방향으로 밀쳐내며, 착지할 때까지 투명화 효과를 부여합니다. 공중에서 활을 조준할 시 공중에 고정되며 피해가 증가하고 다음 치명타에 대한 중력이 무효화 됩니다.", + "tooltip.relics.arrow_quiver.ability.leap.stat.multiplier.title": "추가 데미지:", + "tooltip.relics.arrow_quiver.ability.leap.stat.multiplier.value": "+%1$s%%.", + "tooltip.relics.arrow_quiver.ability.leap.stat.duration.title": "최대 지속 시간:", + "tooltip.relics.arrow_quiver.ability.leap.stat.duration.value": "%1$s 초.", + "tooltip.relics.arrow_quiver.ability.leap.stat.cooldown.title": "쿨타임:", + "tooltip.relics.arrow_quiver.ability.leap.stat.cooldown.value": "%1$s 초.", + "tooltip.relics.arrow_quiver.ability.leap.predicate.target": "발밑 블록을 바라보세요", + "tooltip.relics.arrow_quiver.ability.agility": "민첩성", + "tooltip.relics.arrow_quiver.ability.agility.description": "활 시위 당기는 속도를 증가시킵니다.", + "tooltip.relics.arrow_quiver.ability.agility.stat.modifier.title": "속도 계수:", + "tooltip.relics.arrow_quiver.ability.agility.stat.modifier.value": "%1$s%%.", + "tooltip.relics.arrow_quiver.ability.rain": "화살 비", + "tooltip.relics.arrow_quiver.ability.rain.description": "«화살 저장» 능력의 내부 화살통에서 화살을 소모하지 않고 시선방향에 화살 비를 내립니다. 이 능력의 영역은 하나만 존재할 수 있습니다.", + "tooltip.relics.arrow_quiver.ability.rain.stat.radius.title": "영역 크기:", + "tooltip.relics.arrow_quiver.ability.rain.stat.radius.value": "%1$s 블록.", + "tooltip.relics.arrow_quiver.ability.rain.stat.duration.title": "영역 지속 시간:", + "tooltip.relics.arrow_quiver.ability.rain.stat.duration.value": "%1$s 초.", + "tooltip.relics.arrow_quiver.ability.rain.stat.delay.title": "화살 소환 빈도:", + "tooltip.relics.arrow_quiver.ability.rain.stat.delay.value": "%1$s 초.", + "tooltip.relics.arrow_quiver.ability.rain.predicate.arrow": "화살통의 화살", + + "item.relics.blazing_flask": "블레이징 플라스크", + "tooltip.relics.blazing_flask.description": "«영원한 불» 능력 범위 내에서 비행 5초마다 경험치 +1", + "tooltip.relics.blazing_flask.ability.bonfire": "영원한 불", + "tooltip.relics.blazing_flask.ability.bonfire.description": "블록에 유물을 사용하면 제한된 비행 구역이 생성되며, 그 크기는 중심 주변의 불의 양에 따라 달라집니다.", + "tooltip.relics.blazing_flask.ability.bonfire.stat.step.title": "불 감지 범위:", + "tooltip.relics.blazing_flask.ability.bonfire.stat.step.value": "%1$s 블록", + "tooltip.relics.blazing_flask.ability.bonfire.stat.speed.title": "비행 속도:", + "tooltip.relics.blazing_flask.ability.bonfire.stat.speed.value": "%1$s 초당 블록", + "tooltip.relics.blazing_flask.ability.bonfire.stat.height.title": "비행 고도:", + "tooltip.relics.blazing_flask.ability.bonfire.stat.height.value": "%1$s 블록", + + "item.relics.elytra_booster": "겉날개 부스터", + "tooltip.relics.elytra_booster.description": "«가속» 능력을 통해 유물 내부 버퍼에 연료를 넣을때 연소되는 연로 10초당 경험치 +1", + "tooltip.relics.elytra_booster.ability.boost": "가속", + "tooltip.relics.elytra_booster.ability.boost.description": "인벤토리에서 가연성 연료를 유물에 사용하면 내부 버퍼가 채워집니다. 비행 중 능력을 사용하면 내부 버퍼의 연료를 소모하며 착용자를 앞으로 돌진시킵니다.", + "tooltip.relics.elytra_booster.ability.boost.stat.capacity.title": "용량:", + "tooltip.relics.elytra_booster.ability.boost.stat.capacity.value": "%1$s 칸", + "tooltip.relics.elytra_booster.ability.boost.stat.speed.title": "속도:", + "tooltip.relics.elytra_booster.ability.boost.stat.speed.value": "%1$s 초당 블록", + "tooltip.relics.elytra_booster.ability.boost.predicate.elytra": "겉날개를 이용해 날고있는 상태여야 합니다.", + "tooltip.relics.elytra_booster.ability.boost.predicate.fuel": "부스터 내에 연료가 있어야합니다.", + + "item.relics.midnight_robe": "미드나이트 로브", + "tooltip.relics.midnight_robe.description": "«은폐» 능력으로 투명 상태에서 공격할 때 데미지 2단위당 경험치 +1", + "tooltip.relics.midnight_robe.ability.vanish": "은폐", + "tooltip.relics.midnight_robe.ability.vanish.description": "착용자에게 완전한 투명 효과를 부여하며, 충분히 낮은 조명 레벨에서 이동 속도를 증가시킵니다.", + "tooltip.relics.midnight_robe.ability.vanish.stat.light.title": "최소 조명 레벨:", + "tooltip.relics.midnight_robe.ability.vanish.stat.light.value": "%1$s", + "tooltip.relics.midnight_robe.ability.vanish.stat.speed.title": "속도:", + "tooltip.relics.midnight_robe.ability.vanish.stat.speed.value": "%1$s%%", + "tooltip.relics.midnight_robe.ability.backstab": "배신", + "tooltip.relics.midnight_robe.ability.backstab.description": "«은폐» 능력으로 공격 시 피해량이 증가하며, 목표 주위에 원을 표시하고 착용자의 투명 효과를 해제합니다. «은폐» 능력의 재사용은 착용자가 원을 떠난 후에만 가능합니다.", + "tooltip.relics.midnight_robe.ability.backstab.stat.damage.title": "데미지:", + "tooltip.relics.midnight_robe.ability.backstab.stat.damage.value": "%1$s%%", + "tooltip.relics.midnight_robe.ability.backstab.stat.distance.title": "원 반경:", + "tooltip.relics.midnight_robe.ability.backstab.stat.distance.value": "%1$s 블록", + + "item.relics.reflection_necklace": "반사 목걸이", + "tooltip.relics.reflection_necklace.description": "«지옥의 증오» 능력으로 인해 유물 내부 버퍼에 누적된 피해 10당 경험치 +1", + "tooltip.relics.reflection_necklace.ability.explode": "지옥의 증오", + "tooltip.relics.reflection_necklace.ability.explode.description": "착용자가 받은 데미지를 유물 내부 버퍼에 축적합니다. 마지막 피격 후 5초 또는 버퍼가 초과될 경우, 유물이 폭발하여 흑요석 조각을 사방으로 퍼트리며 피해를 주며 대상을 기절시킵니다.", + "tooltip.relics.reflection_necklace.ability.explode.stat.capacity.title": "데미지 용량:", + "tooltip.relics.reflection_necklace.ability.explode.stat.capacity.value": "%1$s", + "tooltip.relics.reflection_necklace.ability.explode.stat.damage.title": "용량 단위당 데미지:", + "tooltip.relics.reflection_necklace.ability.explode.stat.damage.value": "%1$s", + "tooltip.relics.reflection_necklace.ability.explode.stat.stun.title": "용량 단위당 기절:", + "tooltip.relics.reflection_necklace.ability.explode.stat.stun.value": "%1$s 초", + + "item.relics.jellyfish_necklace": "해파리 목걸이", + "tooltip.relics.jellyfish_necklace.description": "«방전» 능력을 활성화할 때마다 경험치 +1", + "tooltip.relics.jellyfish_necklace.ability.unsinkable": "바다의 힘", + "tooltip.relics.jellyfish_necklace.ability.unsinkable.description": "착용자는 물에 가라앉지 않습니다.", + "tooltip.relics.jellyfish_necklace.ability.shock": "방전", + "tooltip.relics.jellyfish_necklace.ability.shock.description": "대상과 충돌할 때 피해를 입힙니다.", + "tooltip.relics.jellyfish_necklace.ability.shock.stat.damage.title": "데미지:", + "tooltip.relics.jellyfish_necklace.ability.shock.stat.damage.value": "%1$s", + "tooltip.relics.jellyfish_necklace.ability.paralysis": "마비", + "tooltip.relics.jellyfish_necklace.ability.paralysis.description": "능력이 발동하면 «방전»이 대상에게 마비 효과를 부여합니다.", + "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration.title": "효과 지속 시간:", + "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration.value": "%1$s 초", + + "item.relics.spore_sack": "포자 주머니", + "tooltip.relics.spore_sack.description": "«독 합성» 능력으로 방출된 각 포자에 대해 경험치 +1\n«분해» 능력으로 분할된 추가 포자에 대해 경험치 +1", + "tooltip.relics.spore_sack.ability.spore": "독 합성", + "tooltip.relics.spore_sack.ability.spore.description": "피해를 입을 때 무작위 방향으로 포자를 방출합니다. 이 포자는 표면에 달라붙어 대상이 접근하면 폭팔하며 피해를 주고, 중독시키며, 둔화시키고, 5초 동안 치유를 차단합니다.", + "tooltip.relics.spore_sack.ability.spore.stat.size.title": "크기:", + "tooltip.relics.spore_sack.ability.spore.stat.size.value": "받은 데미지 당 %1$s", + "tooltip.relics.spore_sack.ability.spore.stat.damage.title": "데미지:", + "tooltip.relics.spore_sack.ability.spore.stat.damage.value": "크기당 %1$s", + "tooltip.relics.spore_sack.ability.spore.stat.cooldown.title": "쿨타임:", + "tooltip.relics.spore_sack.ability.spore.stat.cooldown.value": "%1$s 초", + "tooltip.relics.spore_sack.ability.spore.stat.duration.title": "지속 시간:", + "tooltip.relics.spore_sack.ability.spore.stat.duration.value": "%1$s 초", + "tooltip.relics.spore_sack.ability.buffer": "독 축적", + "tooltip.relics.spore_sack.ability.buffer.description": "«독 합성» 능력의 쿨타임이 발생할 때마다, 다른 능력에서 포자를 방출하는 데 사용할 수 있는 유물의 내부 버퍼에 하나의 충전이 축적됩니다. 다른 능력에 대한 충전 요청 시 내부 버퍼에서 포자를 소모하지 않을 확률을 추가합니다.", + "tooltip.relics.spore_sack.ability.buffer.stat.capacity.title": "용량:", + "tooltip.relics.spore_sack.ability.buffer.stat.capacity.value": "%1$s 포자", + "tooltip.relics.spore_sack.ability.buffer.stat.chance.title": "확률:", + "tooltip.relics.spore_sack.ability.buffer.stat.chance.value": "%1$s%%", + "tooltip.relics.spore_sack.ability.multiplying": "분해", + "tooltip.relics.spore_sack.ability.multiplying.description": "각 포자는 폭발 시 일정 범위 내에서 여러 개의 작은 포자로 분할될 수 있습니다. 최대 포자 수는 주 포자의 크기에 의해 결정되지만, 최종 수는 포자 분할의 첫 번째 실패 확률로 제한됩니다.", + "tooltip.relics.spore_sack.ability.multiplying.stat.chance.title": "분할 확률:", + "tooltip.relics.spore_sack.ability.multiplying.stat.chance.value": "%1$s%%", + "tooltip.relics.spore_sack.ability.multiplying.stat.size.title": "포자 크기:", + "tooltip.relics.spore_sack.ability.multiplying.stat.size.value": "%1$s%% 주요 포자", + "tooltip.relics.spore_sack.ability.multiplying.stat.amount.title": "포자 크기:", + "tooltip.relics.spore_sack.ability.multiplying.stat.amount.value": "%1$s", + "tooltip.relics.spore_sack.ability.explosion": "독 방출", + "tooltip.relics.spore_sack.ability.explosion.description": "내부 버퍼를 비우고, 축적된 모든 포자를 방출합니다. 방출된 포자의 크기는 착용자의 잃은 체력에 따라 달라집니다.", + "tooltip.relics.spore_sack.ability.explosion.stat.size.title": "포자 크기:", + "tooltip.relics.spore_sack.ability.explosion.stat.size.value": "잃은 체력 당 %1$s", + "tooltip.relics.spore_sack.ability.explosion.predicate.spore": "주머니의 포자", + + "item.relics.ice_breaker": "아이스 브레이커", + "tooltip.relics.ice_breaker.description": "«지진» 능력을 발동하기 전, 떨어진 거리 3 블록마다 경험치 +1", + "tooltip.relics.ice_breaker.ability.sustainability": "지속성", + "tooltip.relics.ice_breaker.ability.sustainability.description": "낙하 속도를 증가시키고, 넉백 저항이 증가하며, 미끄러짐을 무효화합니다.", + "tooltip.relics.ice_breaker.ability.sustainability.stat.modifier.title": "넉백 저항:", + "tooltip.relics.ice_breaker.ability.sustainability.stat.modifier.value": "%1$s%%", + "tooltip.relics.ice_breaker.ability.impact": "지진", + "tooltip.relics.ice_breaker.ability.impact.description": "낙하 중 능력을 사용하면 착지 지점에 충격파를 생성하여 주변 대상에게 피해를 입히고 던져버립니다. 충격파의 강도는 착용자가 낙하한 거리에 따라 달라집니다.", + "tooltip.relics.ice_breaker.ability.impact.stat.size.title": "최대 반경:", + "tooltip.relics.ice_breaker.ability.impact.stat.size.value": "%1$s 블록", + "tooltip.relics.ice_breaker.ability.impact.stat.damage.title": "최소 데미지:", + "tooltip.relics.ice_breaker.ability.impact.stat.damage.value": "%1$s", + "tooltip.relics.ice_breaker.ability.impact.predicate.falling": "자유 낙하", + + "item.relics.bastion_ring": "바스티온 링", + "tooltip.relics.bastion_ring.description": "좀비 피글린/피글린/난폭한 피글린을 죽였을 때 마다 경험치 +1/5/10\n«존중» 능력으로 추가 거래마다 경험치 +1", + "tooltip.relics.bastion_ring.ability.compass": "인식", + "tooltip.relics.bastion_ring.ability.compass.description": "피글린을 착용자에 대해 중립으로 만듭니다. 가장 가까운 피글린은 근처 보루 잔해 위치를 가리킵니다.", + "tooltip.relics.bastion_ring.ability.trade": "존중", + "tooltip.relics.bastion_ring.ability.trade.description": "피글린과의 거래 중 50%의 확률로 추가 거래가 발생합니다.", + "tooltip.relics.bastion_ring.ability.trade.stat.rolls.title": "최대 거래 수:", + "tooltip.relics.bastion_ring.ability.trade.stat.rolls.value": "%1$s", + + "item.relics.horse_flute": "말 피리", + "tooltip.relics.horse_flute.description": "«휴대용 마구간» 능력으로 호출된 말이 25 블록을 이동할 때마다 경험치 +1", + "tooltip.relics.horse_flute.ability.paddock": "휴대용 마구간", + "tooltip.relics.horse_flute.ability.paddock.description": "유물 사용 시 말을 내부 저장소로 이동시킵니다. 재사용 시 말을 내보냅니다. 사용자와 호출된 말 사이의 거리가 16 블록을 초과하면 자동으로 피리로 돌아갑니다.", + "tooltip.relics.horse_flute.ability.paddock.stat.slots.title": "슬롯:", + "tooltip.relics.horse_flute.ability.paddock.stat.slots.value": "%1$s.", + "tooltip.relics.horse_flute.ability.heal": "치료", + "tooltip.relics.horse_flute.ability.heal.description": "내부 저장소에 배치된 말은 천천히 체력을 회복합니다.", + "tooltip.relics.horse_flute.ability.heal.stat.amount.title": "회복량:", + "tooltip.relics.horse_flute.ability.heal.stat.amount.value": "%1$s 초당 체력", + + "item.relics.magma_walker": "마그마 워커", + "tooltip.relics.magma_walker.description": "«불타는 발자국» 능력으로 가열 5 단위당 경험치 +1", + "tooltip.relics.magma_walker.ability.pace": "불타는 발자국", + "tooltip.relics.magma_walker.ability.pace.description": "일정 시간 동안 용암 표면을 걷게 해주며, 떨어지거나 피해를 입지 않습니다. 제한 시간이 지나면 부츠가 과열되기 시작하며 과열 정도에 비례하여 착용자에게 피해를 입힙니다.", + "tooltip.relics.magma_walker.ability.pace.stat.time.title": "지속 시간:", + "tooltip.relics.magma_walker.ability.pace.stat.time.value": "%1$s 초", + "tooltip.relics.magma_walker.ability.heat_resistance": "내열성", + "tooltip.relics.magma_walker.ability.heat_resistance.description": "뜨거운 블록으로 인한 손상을 억제합니다.", + + "item.relics.aqua_walker": "아쿠아 워커", + "tooltip.relics.aqua_walker.description": "«습기 저항» 능력에서 저는 5단위당 경험치 +1", + "tooltip.relics.aqua_walker.ability.walking": "습기 저항", + "tooltip.relics.aqua_walker.ability.walking.description": "일정 시간 동안 물 표면을 걷게 해주며, 떨어지지 않습니다. 제한 시간이 지나면 부츠가 가라앉기 시작하여 착용자를 물속으로 끌고 갑니다.", + "tooltip.relics.aqua_walker.ability.walking.stat.time.title": "지속 시간:", + "tooltip.relics.aqua_walker.ability.walking.stat.time.value": "%1$s 초", + + "item.relics.drowned_belt": "드라운드 벨트", + "tooltip.relics.drowned_belt.description": "삼지창을 사용할 때 «급류» 인챈트 레벨당 경험치 +1", + "tooltip.relics.drowned_belt.ability.slots": "부하 용량", + "tooltip.relics.drowned_belt.ability.slots.description": "유물 장착을 위한 최대 슬롯 수를 증가시킵니다.", + "tooltip.relics.drowned_belt.ability.slots.stat.charm.title": "장착 슬롯:", + "tooltip.relics.drowned_belt.ability.slots.stat.charm.value": "+%1$s 슬롯", + "tooltip.relics.drowned_belt.ability.anchor": "사하중", + "tooltip.relics.drowned_belt.ability.anchor.description": "착용자의 수영 속도를 줄이고 가라앉는 속도를 증가시킵니다.", + "tooltip.relics.drowned_belt.ability.anchor.stat.slowness.title": "수영 속도 감소:", + "tooltip.relics.drowned_belt.ability.anchor.stat.slowness.value": "+%1$s%%.", + "tooltip.relics.drowned_belt.ability.anchor.stat.sinking.title": "가라앉는 속도:", + "tooltip.relics.drowned_belt.ability.anchor.stat.sinking.value": "+%1$s%%", + "tooltip.relics.drowned_belt.ability.pressure": "물의 흐름", + "tooltip.relics.drowned_belt.ability.pressure.description": "수중 피해량이 증가합니다.", + "tooltip.relics.drowned_belt.ability.pressure.stat.damage.title": "데미지 계수:", + "tooltip.relics.drowned_belt.ability.pressure.stat.damage.value": "+%1$s%%", + "tooltip.relics.drowned_belt.ability.riptide": "물의 유인", + "tooltip.relics.drowned_belt.ability.riptide.description": "비나 물 없이도 삼지창의 «급류» 능력을 사용할 수 있으며, 재충전 시간이 추가됩니다.", + "tooltip.relics.drowned_belt.ability.riptide.stat.cooldown.title": "재충전 시간:", + "tooltip.relics.drowned_belt.ability.riptide.stat.cooldown.value": "인첸트 레벨당 %1$s초", + + "item.relics.hunter_belt": "헌터 벨트", + "tooltip.relics.hunter_belt.description": "착용자의 애완동물이 공격할 때마다 경험치 +1", + "tooltip.relics.hunter_belt.ability.slots": "부하 용량", + "tooltip.relics.hunter_belt.ability.slots.description": "유물 장착을 위한 최대 슬롯 수를 증가시킵니다.", + "tooltip.relics.hunter_belt.ability.slots.stat.charm.title": "장착 슬롯:", + "tooltip.relics.hunter_belt.ability.slots.stat.charm.value": "+%1$s 슬롯", + "tooltip.relics.hunter_belt.ability.training": "훈련", + "tooltip.relics.hunter_belt.ability.training.description": "착용자의 애완동물이 가하는 피해가 증가합니다.", + "tooltip.relics.hunter_belt.ability.training.stat.damage.title": "데미지:", + "tooltip.relics.hunter_belt.ability.training.stat.damage.value": "+%1$s%%", + + "item.relics.leather_belt": "가죽 벨트", + "tooltip.relics.leather_belt.description": "장착된 부적에서 얻은 경험치마다 경험치 +1", + "tooltip.relics.leather_belt.ability.slots": "부하 용량", + "tooltip.relics.leather_belt.ability.slots.description": "부적 장착을 위한 최대 슬롯 수가 증가합니다.", + "tooltip.relics.leather_belt.ability.slots.stat.charm.title": "부적:", + "tooltip.relics.leather_belt.ability.slots.stat.charm.value": "+%1$s 슬롯", + + "item.relics.rage_glove": "분노의 장갑", + "tooltip.relics.rage_glove.description": "«광전사의 분노» 능력의 충전이 리셋될 때마다 3회 충전당 경험치 +1\n«분출» 능력으로 타격한 대상마다 경험치 +1", + "tooltip.relics.rage_glove.ability.rage": "광전사의 분노", + "tooltip.relics.rage_glove.ability.rage.description": "마지막 공격 후 3초 이내에 이루어진 각 공격은 유물의 내부 버퍼에 1 충전을 축적합니다. 축적된 충전 비율에 따라 타격 피해, 피격 피해 및 이동 속도가 증가합니다. 3초 후 유물 내부 버퍼가 비워지고, 받는 보너스가 모두 제거됩니다.", + "tooltip.relics.rage_glove.ability.rage.stat.duration.title": "충전 유효 시간:", + "tooltip.relics.rage_glove.ability.rage.stat.duration.value": "%1$s 초", + "tooltip.relics.rage_glove.ability.rage.stat.incoming_damage.title": "받는 피해:", + "tooltip.relics.rage_glove.ability.rage.stat.incoming_damage.value": "충전 당 %1$s%%", + "tooltip.relics.rage_glove.ability.rage.stat.dealt_damage.title": "데미지:", + "tooltip.relics.rage_glove.ability.rage.stat.dealt_damage.value": "충전 당 %1$s%%", + "tooltip.relics.rage_glove.ability.phlebotomy": "정맥 절개", + "tooltip.relics.rage_glove.ability.phlebotomy.description": "착용자의 공격 및 이동 속도를 증가시키고, 잃은 체력 비율에 비례하여 재생이 부여됩니다.", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.heal.title": "체력 회복:", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.heal.value": "초당 최대 체력의 1%%인 %1$s만큼 체력 회복", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.movement_speed.title": "이동 속도:", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.movement_speed.value": "1%% 당 %1$s%%", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.attack_speed.title": "공격 속도:", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.attack_speed.value": "1%% 당 %1$s%%", + "tooltip.relics.rage_glove.ability.spurt": "분출", + "tooltip.relics.rage_glove.ability.spurt.description": "시야 방향으로 돌진하며 적을 불태우고 출혈을 적용하며, 손에 든 아이템으로 경로상의 각 대상을 공격합니다. «광전사의 분노» 능력의 내부 버퍼에 있는 충전 수에 비례하여 추가 피해를 입히고 이를 파괴합니다.", + "tooltip.relics.rage_glove.ability.spurt.stat.cooldown.title": "쿨타임:", + "tooltip.relics.rage_glove.ability.spurt.stat.cooldown.value": "%1$s 초", + "tooltip.relics.rage_glove.ability.spurt.stat.damage.title": "데미지:", + "tooltip.relics.rage_glove.ability.spurt.stat.damage.value": "충전 당 %1$s", + "tooltip.relics.rage_glove.ability.spurt.stat.distance.title": "거리:", + "tooltip.relics.rage_glove.ability.spurt.stat.distance.value": "%1$s 블록", + + "item.relics.ice_skates": "아이스 스케이트", + "tooltip.relics.ice_skates.description": "«스케이팅» 능력으로 가속 1초마다 경험치 +1", + "tooltip.relics.ice_skates.ability.skating": "스케이팅", + "tooltip.relics.ice_skates.ability.skating.description": "얼음 위에서 미끄러지는 동안 이동 속도를 증가시킵니다.", + "tooltip.relics.ice_skates.ability.skating.stat.speed.title": "초당 속도:", + "tooltip.relics.ice_skates.ability.skating.stat.speed.value": "%1$s%%", + "tooltip.relics.ice_skates.ability.skating.stat.duration.title": "최대 지속 시간:", + "tooltip.relics.ice_skates.ability.skating.stat.duration.value": "%1$s 초", + "tooltip.relics.ice_skates.ability.ram": "염소", + "tooltip.relics.ice_skates.ability.ram.description": "대상과 충돌 시 «스케이팅» 능력 사용 시간에 비례하여 피해를 입힙니다.", + "tooltip.relics.ice_skates.ability.ram.stat.damage.title": "초당 데미지:", + "tooltip.relics.ice_skates.ability.ram.stat.damage.value": "%1$s", + + "item.relics.amphibian_boot": "양서류 부츠", + "tooltip.relics.amphibian_boot.description": "«지느러미» 능력으로 가속 1초마다 경험치 +1\n«미끄러짐» 능력으로 가속 1초마다 경험치 +1", + "tooltip.relics.amphibian_boot.ability.swimming": "지느러미", + "tooltip.relics.amphibian_boot.ability.swimming.description": "지속 시간에 따라 수영 속도가 증가합니다.", + "tooltip.relics.amphibian_boot.ability.swimming.stat.speed.title": "속도:", + "tooltip.relics.amphibian_boot.ability.swimming.stat.speed.value": "초당 %1$s%%", + "tooltip.relics.amphibian_boot.ability.swimming.stat.duration.title": "최대 지속 시간:", + "tooltip.relics.amphibian_boot.ability.swimming.stat.duration.value": "%1$s 초", + "tooltip.relics.amphibian_boot.ability.slipping": "미끄러짐", + "tooltip.relics.amphibian_boot.ability.slipping.description": "비 오는 날, 지속 시간에 따라 이동 속도가 증가합니다.", + "tooltip.relics.amphibian_boot.ability.slipping.stat.speed.title": "속도:", + "tooltip.relics.amphibian_boot.ability.slipping.stat.speed.value": "%1$s%%", + "tooltip.relics.amphibian_boot.ability.slipping.stat.duration.title": "최대 지속 시간:", + "tooltip.relics.amphibian_boot.ability.slipping.stat.duration.value": "%1$s 초", + "tooltip.relics.amphibian_boot.ability.gills": "아가미", + "tooltip.relics.amphibian_boot.ability.gills.description": "물 속에서 공기를 소비하지 않게 해줍니다.", + "tooltip.relics.amphibian_boot.ability.gills.stat.chance.title": "발동 확률:", + "tooltip.relics.amphibian_boot.ability.gills.stat.chance.value": "%1$s%%", + + "item.relics.spatial_sign": "공간의 표식", + "tooltip.relics.spatial_sign.description": "«시간 균열» 능력으로 반환 시간마다 경험치 +1", + "tooltip.relics.spatial_sign.ability.seal": "시간 균열", + "tooltip.relics.spatial_sign.ability.seal.description": "사용 시. 일정 시간이 지난 후 사용자를 이동한 경로를 따라 원위치로 되돌려줍니다. 재사용 시 능력이 종료됩니다.", + "tooltip.relics.spatial_sign.ability.seal.stat.time.title": "최대 지속 시간:", + "tooltip.relics.spatial_sign.ability.seal.stat.time.value": "%1$s 초", + + "item.relics.chorus_inhibitor": "후렴 억제기", + "tooltip.relics.chorus_inhibitor.description": "«순간이동 제어» 능력으로 순간이동 지점까지 10블록마다 경험치 +1", + "tooltip.relics.chorus_inhibitor.ability.blink": "순간이동 제어", + "tooltip.relics.chorus_inhibitor.ability.blink.description": "후렴과를 사용하면 착용자가 바라보는 지점으로 순간이동합니다.", + "tooltip.relics.chorus_inhibitor.ability.blink.stat.distance.title": "최대 거리:", + "tooltip.relics.chorus_inhibitor.ability.blink.stat.distance.value": "%1$s 블록", + "tooltip.relics.chorus_inhibitor.ability.blink.stat.cooldown.title": "재사용 시간:", + "tooltip.relics.chorus_inhibitor.ability.blink.stat.cooldown.value": "%1$s 초", + + "item.relics.wool_mitten": "양모 장갑", + "item.relics.solid_snowball": "얼어붙은 눈덩이", + "tooltip.relics.wool_mitten.description": "«몰드» 능력으로 눈덩이를 맞추면 크기 5단위당 경험치 +1", + "tooltip.relics.wool_mitten.ability.mold": "몰드", + "tooltip.relics.wool_mitten.ability.mold.description": "빈 손으로 우클릭에 눈을 모으면 점차 특별한 단단한 눈덩이가 형성됩니다. 이러한 눈덩이를 목표물에 맞히면 피해를 입히고 기절시킬 뿐만 아니라 주변의 적들도 얼립니다. 유물을 장착하지 않은 상태에서 눈덩이를 들고 있으면 사용자가 얼어붙습니다.", + "tooltip.relics.wool_mitten.ability.mold.stat.size.title": "최대 크기:", + "tooltip.relics.wool_mitten.ability.mold.stat.size.value": "%1$s", + "tooltip.relics.wool_mitten.ability.mold.stat.damage.title": "데미지:", + "tooltip.relics.wool_mitten.ability.mold.stat.damage.value": "크기 당 %1$s", + "tooltip.relics.wool_mitten.ability.mold.stat.stun.title": "기절:", + "tooltip.relics.wool_mitten.ability.mold.stat.stun.value": "크기 당 %1$s 초", + "tooltip.relics.wool_mitten.ability.mold.stat.freeze.title": "동상:", + "tooltip.relics.wool_mitten.ability.mold.stat.freeze.value": "크기 당 %1$s 초", + + "item.relics.roller_skates": "롤러 스케이트", + "tooltip.relics.roller_skates.description": "«가속» 능력으로 가속 1초당 경험치 +1", + "tooltip.relics.roller_skates.ability.skating": "가속", + "tooltip.relics.roller_skates.ability.skating.description": "지속 시간에 따라 이동 속도가 증가합니다. 모든 블록이 착용자에게 미끄럽게 변합니다.", + "tooltip.relics.roller_skates.ability.skating.stat.speed.title": "속도:", + "tooltip.relics.roller_skates.ability.skating.stat.speed.value": "%1$s%%", + "tooltip.relics.roller_skates.ability.skating.stat.duration.title": "최대 지속 시간:", + "tooltip.relics.roller_skates.ability.skating.stat.duration.value": "%1$s 초", + + "item.relics.space_dissector": "공간 해체기", + "tooltip.relics.space_dissector.description": "기존 포탈이 없는 경우 생성된 포탈마다 경험치 +1", + "tooltip.relics.space_dissector.ability.dissection": "해부", + "tooltip.relics.space_dissector.ability.dissection.description": "우클릭을 누르고 있으면 시선에 있는 지점에 포탈이 생성되고 우클릭을 놓으면 동일안 원리에 따라 두 번째 포탈이 생성되어 첫 번째 포탈과 연결됩니다. 생명체를 포탈 중 하나로 데려오면 연결된 포탈로 이동됩니다. 경로에 단단한 블록이 있으면 포탈이 작동하지 않습니다.", + "tooltip.relics.space_dissector.ability.dissection.stat.distance.title": "최대 거리:", + "tooltip.relics.space_dissector.ability.dissection.stat.distance.value": "%1$s 블록", + "tooltip.relics.space_dissector.ability.dissection.stat.time.title": "포탈 지속시간:", + "tooltip.relics.space_dissector.ability.dissection.stat.time.value": "%1$s 초", + + "item.relics.phantom_boot": "팬텀 부츠", + "tooltip.relics.phantom_boot.description": "유물의 소유자 발 아래에서 물질이 응축되어, 고체 바닥이 없는 공간에서도 길을 만들어냅니다.", + "tooltip.relics.phantom_boot.ability.bridge": "팬텀 구름다리", + "tooltip.relics.phantom_boot.ability.bridge.description": "이 능력이 활성화되면, 플레이어의 발 아래에 일시적인 팬텀 구름다리가 형성되어 유물의 소유자가 그 위를 건널 수 있습니다. 이 구름다리는 미끄럽고 뛰어오를 수 있는 블록의 특성을 가지고 있어서 낙하 데미지를 완전히 흡수합니다. 플레이어가 다리 위에서 너무 오랫동안 가만히 서 있으면 다리 밑으로 떨어지게 되고, 단단한 땅 위에 서기 전에는 다시 올라갈 수 없습니다.", + "tooltip.relics.phantom_boot.leveling_source.bridge.title": "팬텀 구름다리", + "tooltip.relics.phantom_boot.leveling_source.bridge.description": "%2$s 능력으로 구름다리를 생성할 때마다 10%%의 확률로 +%1$s 경험치를 얻습니다.", + + "item.relics.springy_boot": "스프링 부츠", + "tooltip.relics.springy_boot.description": "유물 소유자에게 특수한 탄력을 부여하여,모든 단단한 표면에서 튕겨 나갈 수 있게 합니다.", + "tooltip.relics.springy_boot.ability.bounce": "콩콩이", + "tooltip.relics.springy_boot.ability.bounce.description": "능력이 활성화되면 모든 단단한 블록에 떨어졌을 때 탄력을 얻어 튕겨 나오게 됩니다. 튕겨 나올 때 플레이어는 떨어진 높이에 기반한 힘으로 공중으로 발사됩니다", + "tooltip.relics.springy_boot.leveling_source.bounce.title": "탄성", + "tooltip.relics.springy_boot.leveling_source.bounce.description": "%2$s 능력으로 표면에 튕길 때마다 +%1$s 경험치를 얻습니다.", + + "tooltip.relics.leveling_source.generic.spreading.title": "경험치 공유", + "tooltip.relics.leveling_source.generic.spreading.description": "소지하고 있는 다른 유물이 경험치를 얻을 때마다, 해당 경험치의 %1$s%%가 이 유물에도 추가로 획득됩니다.", + + "item.relics.leafy_ring": "잎사귀 반지 [WIP]", + "tooltip.relics.leafy_ring.description": "[WIP]", + + "item.relics.relic_experience_bottle": "유물 경험치 병", + + "block.relics.phantom_block": "팬텀 구름다리 블록", + + "block.relics.researching_table": "연구 탁자 [모드에서 제거됨]", + + "effect.relics.stun": "기절", + "effect.relics.paralysis": "마비", + "effect.relics.confusion": "혼란", + "effect.relics.vanishing": "은폐", + "effect.relics.anti_heal": "치유 방지", + "effect.relics.bleeding": "출혈", + + "command.relics.base.not_relic": "손에 유물을 들고 있어야 합니다!", + + "info.relics.researching.wrong_container": "이 인벤토리에서 유물 작업이 불가능합니다. 아이템을 플레이어의 주요 인벤토리로 이동시킨 후 다시 시도하세요.", + + "key.relics.ability_list": "액티브 스킬 보기" +} diff --git a/src/main/resources/assets/relics/lang/pt_br.json b/src/main/resources/assets/relics/lang/pt_br.json deleted file mode 100644 index 8bbbab74..00000000 --- a/src/main/resources/assets/relics/lang/pt_br.json +++ /dev/null @@ -1,412 +0,0 @@ -{ - "itemGroup.relics": "Relics", - - "curios.identifier.talisman": "Talismã", - "curios.identifier.feet": "Pés", - - "tooltip.relics.relic.tooltip.table": "Você pode saber mais sobre este relicário na Mesa de Pesquisa.", - "tooltip.relics.relic.tooltip.shift": "Pressione [Shift] para mais informações.", - - "tooltip.relics.relic.tooltip.abilities": "Habilidades:", - - "tooltip.relics.relic.ability.tooltip.level": "Nível: %1$s/%2$s", - "tooltip.relics.relic.ability.tooltip.rarity": "Raridade:", - "tooltip.relics.relic.ability.tooltip.low_level": "Para usar, você precisa aumentar o nível da relíquia para %1$s %2$s.", - "tooltip.relics.relic.ability.tooltip.no_stats": "Esta habilidade não possui estatísticas atualizáveis e não afeta a qualidade do relicário.", - - "tooltip.relics.relic.max_level": "-= MÁX =-", - "tooltip.relics.relic.ability.level": " [%1$s/%2$s]", - - "tooltip.relics.relic.status.positive": "§2§l[§2§l✔§2§l]", - "tooltip.relics.relic.status.negative": "§4§l[§4§l✘§4§l]", - - "tooltip.relics.relic.upgrade.description": "Aprimorar Nível", - "tooltip.relics.relic.upgrade.cost": "Custo: %1$s pontos de aprimoramento %2$s, %3$s pontos de experiência %4$s.", - "tooltip.relics.relic.upgrade.locked": "A habilidade atingiu seu nível máximo.", - - "tooltip.relics.relic.reroll.description": "Rerrolar estatísticas aleatórias", - "tooltip.relics.relic.reroll.cost": "Custo: %1$s pontos de experiência %2$s.", - - "tooltip.relics.relic.reset.description": "Redefinir pontos de aprimoramento", - "tooltip.relics.relic.reset.cost": "Custo: %1$s pontos de experiência %2$s.", - "tooltip.relics.relic.reset.locked": "Para usar, você precisa aprimorar esta habilidade pelo menos 1 vez.", - - "item.relics.infinity_ham": "Presunto Infinito", - "tooltip.relics.infinity_ham.description": "+1 ponto de experiência para cada peça comida da habilidade «Regeneração».", - "tooltip.relics.infinity_ham.ability.autophagy": "Regeneração", - "tooltip.relics.infinity_ham.ability.autophagy.description": "O uso de uma relíquia consome uma das cargas regeneráveis, restaurando a fome do usuário.", - "tooltip.relics.infinity_ham.ability.autophagy.stat.feed.title": "Saturação:", - "tooltip.relics.infinity_ham.ability.autophagy.stat.feed.value": "%1$s unidades.", - "tooltip.relics.infinity_ham.ability.infusion": "Alquimia", - "tooltip.relics.infinity_ham.ability.infusion.description": "O uso de uma poção na relíquia no inventário a faz lembrar de seu efeito, gastando a poção. O uso subsequente da habilidade «Regeneração» imporá um efeito acumulativo da poção associada ao usuário. Na completa ausência de cargas, a relíquia perde as propriedades da poção associada.", - "tooltip.relics.infinity_ham.ability.infusion.stat.duration.title": "Duração do efeito:", - "tooltip.relics.infinity_ham.ability.infusion.stat.duration.value": "%1$s segundos por carga.", - - "item.relics.enders_hand": "Mão de Ender", - "tooltip.relics.enders_hand.description": "+1 ponto de experiência ao usar a habilidade «Transposição Ender» +1 ponto de experiência a cada 10 blocos de distância até o alvo ao usar.", - "tooltip.relics.enders_hand.ability.neutrality": "Neutralidade", - "tooltip.relics.enders_hand.ability.neutrality.description": "Torna os endermans neutros em relação ao usuário.", - "tooltip.relics.enders_hand.ability.swap": "Transposição de Ender", - "tooltip.relics.enders_hand.ability.swap.description": "Troca o usuário com o alvo ao longo da linha de visão.", - "tooltip.relics.enders_hand.ability.swap.stat.distance.title": "Distância:", - "tooltip.relics.enders_hand.ability.swap.stat.distance.value": "%1$s blocos.", - "tooltip.relics.enders_hand.ability.swap.predicate.target": "Olhando para o alvo", - - "item.relics.holy_locket": "Medalhão Sagrado", - "tooltip.relics.holy_locket.description": "+1 ponto de experiência para cada ativação da habilidade «Bênção Divina» +1 ponto de experiência para cada unidade de cura roubada.", - "tooltip.relics.holy_locket.ability.steal": "Bênção Divina", - "tooltip.relics.holy_locket.ability.steal.description": "Redireciona parte da saúde regenerada de criaturas próximas para o usuário da relíquia.", - "tooltip.relics.holy_locket.ability.steal.stat.amount.title": "Quantidade:", - "tooltip.relics.holy_locket.ability.steal.stat.amount.value": "%1$s%% da saúde regenerada.", - "tooltip.relics.holy_locket.ability.steal.stat.radius.title": "Raio:", - "tooltip.relics.holy_locket.ability.steal.stat.radius.value": "%1$s blocos.", - - "item.relics.magic_mirror": "Espelho Mágico", - "tooltip.relics.magic_mirror.description": "+1 ponto de experiência para cada uso da habilidade «Buraco de Minhoca» +1 ponto de experiência para cada 50 blocos até o ponto de teletransporte.", - "tooltip.relics.magic_mirror.ability.teleport": "Buraco de Minhoca", - "tooltip.relics.magic_mirror.ability.teleport.description": "Após o uso, teletransporta o usuário para o ponto de ressurgimento dele.", - "tooltip.relics.magic_mirror.ability.teleport.stat.distance.title": "Distância:", - "tooltip.relics.magic_mirror.ability.teleport.stat.distance.value": "%1$s blocos.", - "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.title": "Recarga:", - "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.value": "%1$s segundos.", - - "item.relics.shadow_glaive": "Glaive das Sombras", - "tooltip.relics.shadow_glaive.description": "+1 ponto de experiência para cada 2 rebatidas do glaive da habilidade «Justiça Cega».", - "tooltip.relics.shadow_glaive.ability.glaive": "Justiça Cega", - "tooltip.relics.shadow_glaive.ability.glaive.description": "O uso libera uma das 8 cargas do glaive que ricocheteia entre alvos próximos. As cargas ausentes são restauradas automaticamente após um certo tempo.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.damage.title": "Dano:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.damage.value": "%1$s.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.recharge.title": "Tempo de recarga:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.recharge.value": "%1$s segundos.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.bounces.title": "Ricochetes:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.bounces.value": "%1$s.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.radius.title": "Raio de Ricocheteio:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.radius.value": "%1$s blocos.", - "tooltip.relics.shadow_glaive.ability.saw": "Punição Impiedosa", - "tooltip.relics.shadow_glaive.ability.saw.description": "O uso consome todas as 8 cargas do glaive, invocando uma serra que causa dano aos alvos próximos. Reutilizar a habilidade trará a serra de volta ao usuário, restaurando todas as cargas. A regeneração automática de cargas é bloqueada enquanto a habilidade está ativa.", - "tooltip.relics.shadow_glaive.ability.saw.stat.speed.title": "Velocidade de ataque:", - "tooltip.relics.shadow_glaive.ability.saw.stat.speed.value": "%1$s golpes por segundo.", - "tooltip.relics.shadow_glaive.ability.saw.stat.damage.title": "Dano:", - "tooltip.relics.shadow_glaive.ability.saw.stat.damage.value": "%1$s unidades.", - - "item.relics.arrow_quiver": "Aljava", - "tooltip.relics.arrow_quiver.description": "+1 ponto de experiência para cada 10 blocos atingidos pelo disparo.", - "tooltip.relics.arrow_quiver.ability.receptacle": "Armazenamento de Flechas", - "tooltip.relics.arrow_quiver.ability.receptacle.description": "O arqueiro usa principalmente flechas do armazenamento interno da aljava. Ao pressionar com o LMB na aljava no inventário, a flecha será colocada no armazenamento interno da relíquia. Pressionando com o RMB na aljava, você pegará o último conjunto de flechas colocado nela.", - "tooltip.relics.arrow_quiver.ability.receptacle.stat.slots.title": "Espaços para flechas:", - "tooltip.relics.arrow_quiver.ability.receptacle.stat.slots.value": "%1$s unidades.", - "tooltip.relics.arrow_quiver.ability.leap": "Salto", - "tooltip.relics.arrow_quiver.ability.leap.description": "Impulsiona o jogador para longe da direção para onde ele está olhando, causando um efeito de desaparecimento até aterrissar. Usar um arco suspenderá o jogador no ar, aumentando o dano e anulando a gravidade para o próximo tiro crítico.", - "tooltip.relics.arrow_quiver.ability.leap.stat.multiplier.title": "Dano adicional:", - "tooltip.relics.arrow_quiver.ability.leap.stat.multiplier.value": "+%1$s%%.", - "tooltip.relics.arrow_quiver.ability.leap.stat.duration.title": "Duração máxima:", - "tooltip.relics.arrow_quiver.ability.leap.stat.duration.value": "%1$s segundos.", - "tooltip.relics.arrow_quiver.ability.leap.stat.cooldown.title": "Tempo de Recarga:", - "tooltip.relics.arrow_quiver.ability.leap.stat.cooldown.value": "%1$s segundos.", - "tooltip.relics.arrow_quiver.ability.leap.predicate.target": "Olhando para o bloco sob os pés", - "tooltip.relics.arrow_quiver.ability.agility": "Destreza", - "tooltip.relics.arrow_quiver.ability.agility.description": "Aumenta a velocidade de tensão da corda do arco.", - "tooltip.relics.arrow_quiver.ability.agility.stat.modifier.title": "Multiplicador de Velocidade:", - "tooltip.relics.arrow_quiver.ability.agility.stat.modifier.value": "+%1$s%%.", - "tooltip.relics.arrow_quiver.ability.rain": "Chuva de Flechas", - "tooltip.relics.arrow_quiver.ability.rain.description": "Invoca em um ponto ao longo da linha de visão uma área de flechas que caem e perseguem alvos a partir do armazenamento interno da aljava da habilidade «Armazenamento de Flechas». As flechas do próprio armazenamento não são consumidas. Apenas uma área dessa habilidade pode existir de cada vez.", - "tooltip.relics.arrow_quiver.ability.rain.stat.radius.title": "Raio da Área:", - "tooltip.relics.arrow_quiver.ability.rain.stat.radius.value": "%1$s blocos.", - "tooltip.relics.arrow_quiver.ability.rain.stat.duration.title": "Tempo de Vida da Área:", - "tooltip.relics.arrow_quiver.ability.rain.stat.duration.value": "%1$s segundos.", - "tooltip.relics.arrow_quiver.ability.rain.stat.delay.title": "Frequência de Invocação das Flechas:", - "tooltip.relics.arrow_quiver.ability.rain.stat.delay.value": "%1$s segundos.", - "tooltip.relics.arrow_quiver.ability.rain.predicate.arrow": "Flechas na aljava", - - "item.relics.blazing_flask": "Frasco Flamejante", - "tooltip.relics.blazing_flask.description": "+1 ponto de experiência para cada 5 segundos de voo dentro do alcance da habilidade «Fogo Eterno».", - "tooltip.relics.blazing_flask.ability.bonfire": "Fogo Eterno", - "tooltip.relics.blazing_flask.ability.bonfire.description": "Usar a relíquia em um bloco criará uma zona de voo restrita, cujo tamanho depende da quantidade de fogo em um raio específico ao redor do centro.", - "tooltip.relics.blazing_flask.ability.bonfire.stat.step.title": "Raio de detecção de fogo:", - "tooltip.relics.blazing_flask.ability.bonfire.stat.step.value": "%1$s blocos.", - "tooltip.relics.blazing_flask.ability.bonfire.stat.speed.title": "Velocidade de Voo:", - "tooltip.relics.blazing_flask.ability.bonfire.stat.speed.value": "%1$s blocos por segundo.", - "tooltip.relics.blazing_flask.ability.bonfire.stat.height.title": "Altitude de Voo:", - "tooltip.relics.blazing_flask.ability.bonfire.stat.height.value": "%1$s blocos.", - - "item.relics.elytra_booster": "Potencializador de Élitros", - "tooltip.relics.elytra_booster.description": "+1 ponto de experiência para cada 10 segundos de queima de combustível ao colocá-lo no buffer interno da relíquia da habilidade «Aceleração».", - "tooltip.relics.elytra_booster.ability.boost": "Aceleração", - "tooltip.relics.elytra_booster.ability.boost.description": "Usar qualquer combustível inflamável em uma relíquia no inventário recarrega seu buffer interno. Usar a habilidade durante o voo com Élitros faz com que o usuário avance rapidamente, consumindo combustível do buffer interno.", - "tooltip.relics.elytra_booster.ability.boost.stat.capacity.title": "Capacidade:", - "tooltip.relics.elytra_booster.ability.boost.stat.capacity.value": "%1$s unidades.", - "tooltip.relics.elytra_booster.ability.boost.stat.speed.title": "Velocidade:", - "tooltip.relics.elytra_booster.ability.boost.stat.speed.value": "%1$s blocos por segundo.", - "tooltip.relics.elytra_booster.ability.boost.predicate.elytra": "Voando com elytra", - "tooltip.relics.elytra_booster.ability.boost.predicate.fuel": "Combustível no Potencializador", - - "item.relics.midnight_robe": "Manto da Meia-Noite", - "tooltip.relics.midnight_robe.description": "+1 ponto de experiência para cada 2 unidades de dano ao atacar estando invisível com a habilidade «Desaparecer».", - "tooltip.relics.midnight_robe.ability.vanish": "Desaparecer", - "tooltip.relics.midnight_robe.ability.vanish.description": "Dá ao usuário completa invisibilidade e aumenta a velocidade de movimento dele em condições de baixa luminosidade.", - "tooltip.relics.midnight_robe.ability.vanish.stat.light.title": "Nível mínimo de luminosidade:", - "tooltip.relics.midnight_robe.ability.vanish.stat.light.value": "%1$s.", - "tooltip.relics.midnight_robe.ability.vanish.stat.speed.title": "Multiplicador de Velocidade:", - "tooltip.relics.midnight_robe.ability.vanish.stat.speed.value": "+%1$s%%.", - "tooltip.relics.midnight_robe.ability.backstab": "Traição", - "tooltip.relics.midnight_robe.ability.backstab.description": "Um ataque da habilidade «Desaparecer» causa dano aumentado, delineando um círculo ao redor do alvo e dissipando o efeito de invisibilidade do usuário. A reutilização da habilidade «Desaparecer» só é possível depois que o usuário sair do círculo.", - "tooltip.relics.midnight_robe.ability.backstab.stat.damage.title": "Multiplicador de Dano:", - "tooltip.relics.midnight_robe.ability.backstab.stat.damage.value": "+%1$s%%.", - "tooltip.relics.midnight_robe.ability.backstab.stat.distance.title": "Raio do Círculo:", - "tooltip.relics.midnight_robe.ability.backstab.stat.distance.value": "%1$s blocos.", - - "item.relics.reflection_necklace": "Colar Reflexivo", - "tooltip.relics.reflection_necklace.description": "+1 ponto de experiência para cada 10 de dano acumulado no buffer interno da relíquia a partir da habilidade «Ódio Infernal».", - "tooltip.relics.reflection_necklace.ability.explode": "Ódio Infernal", - "tooltip.relics.reflection_necklace.ability.explode.description": "Acumula o dano recebido pelo usuário no buffer interno da relíquia. Após 5 segundos do último dano ou em caso de estouro do buffer, a relíquia explode, lançando fragmentos de obsidiana em todas as direções, causando dano e atordoando os alvos.", - "tooltip.relics.reflection_necklace.ability.explode.stat.capacity.title": "Buffer de Dano:", - "tooltip.relics.reflection_necklace.ability.explode.stat.capacity.value": "%1$s unidades.", - "tooltip.relics.reflection_necklace.ability.explode.stat.damage.title": "Dano por unidade de buffer:", - "tooltip.relics.reflection_necklace.ability.explode.stat.damage.value": "%1$s unidades.", - "tooltip.relics.reflection_necklace.ability.explode.stat.stun.title": "Atordoamento por unidade de buffer:", - "tooltip.relics.reflection_necklace.ability.explode.stat.stun.value": "%1$s segundos.", - - "item.relics.jellyfish_necklace": "Colar de Água-viva", - "tooltip.relics.jellyfish_necklace.description": "+1 ponto de experiência para cada ativação da habilidade «Descarga Elétrica».", - "tooltip.relics.jellyfish_necklace.ability.unsinkable": "Domínio Sobre o Mar", - "tooltip.relics.jellyfish_necklace.ability.unsinkable.description": "O usuário não afunda na água.", - "tooltip.relics.jellyfish_necklace.ability.shock": "Descarga Elétrica", - "tooltip.relics.jellyfish_necklace.ability.shock.description": "Causa dano aos alvos ao colidir com eles.", - "tooltip.relics.jellyfish_necklace.ability.shock.stat.damage.title": "Dano:", - "tooltip.relics.jellyfish_necklace.ability.shock.stat.damage.value": "%1$s unidades.", - "tooltip.relics.jellyfish_necklace.ability.paralysis": "Paralisia", - "tooltip.relics.jellyfish_necklace.ability.paralysis.description": "Quando a habilidade é acionada, a «Descarga Elétrica» impõe um efeito de paralisia ao alvo.", - "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration.title": "Duração do efeito:", - "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration.value": "%1$s segundos.", - - "item.relics.spore_sack": "Saco de Esporos", - "tooltip.relics.spore_sack.description": "+1 ponto de experiência para cada esporo liberado pela habilidade «Síntese de Veneno».\n+1 ponto de experiência para cada esporo adicional dividido pela habilidade «Decomposição».", - "tooltip.relics.spore_sack.ability.spore": "Síntese de Veneno", - "tooltip.relics.spore_sack.ability.spore.description": "Ao sofrer dano, lança um esporo em uma direção aleatória que adere a superfícies e explode quando um alvo se aproxima, causando dano, envenenamento, desaceleração e bloqueando a cura por 5 segundos.", - "tooltip.relics.spore_sack.ability.spore.stat.size.title": "Tamanho:", - "tooltip.relics.spore_sack.ability.spore.stat.size.value": "%1$s por unidade de dano.", - "tooltip.relics.spore_sack.ability.spore.stat.damage.title": "Dano:", - "tooltip.relics.spore_sack.ability.spore.stat.damage.value": "%1$s por unidade de tamanho.", - "tooltip.relics.spore_sack.ability.spore.stat.cooldown.title": "Tempo de Recarga:", - "tooltip.relics.spore_sack.ability.spore.stat.cooldown.value": "%1$s segundos.", - "tooltip.relics.spore_sack.ability.spore.stat.duration.title": "Duração:", - "tooltip.relics.spore_sack.ability.spore.stat.duration.value": "%1$s segundos.", - "tooltip.relics.spore_sack.ability.buffer": "Acúmulo de Veneno", - "tooltip.relics.spore_sack.ability.buffer.description": "Cada vez que o tempo de recarga da habilidade «Síntese de Veneno» é acionado, acumula uma carga no buffer interno da relíquia que pode ser usada por outras habilidades para liberar esporos. Adiciona uma chance de não consumir esporos do buffer interno ao solicitar cargas para outras habilidades.", - "tooltip.relics.spore_sack.ability.buffer.stat.capacity.title": "Capacidade:", - "tooltip.relics.spore_sack.ability.buffer.stat.capacity.value": "%1$s esporos.", - "tooltip.relics.spore_sack.ability.buffer.stat.chance.title": "Chance:", - "tooltip.relics.spore_sack.ability.buffer.stat.chance.value": "%1$s%%.", - "tooltip.relics.spore_sack.ability.multiplying": "Decomposição", - "tooltip.relics.spore_sack.ability.multiplying.description": "Cada esporo pode se dividir em vários esporos menores em um determinado alcance quando explode. O número máximo de esporos é determinado pelo grau do tamanho do esporo principal, mas o número final é limitado pela primeira chance malsucedida de divisão de esporo.", - "tooltip.relics.spore_sack.ability.multiplying.stat.chance.title": "Chance de Divisão:", - "tooltip.relics.spore_sack.ability.multiplying.stat.chance.value": "%1$s%%.", - "tooltip.relics.spore_sack.ability.multiplying.stat.size.title": "Tamanho do Esporo:", - "tooltip.relics.spore_sack.ability.multiplying.stat.size.value": "%1$s%% do esporo principal.", - "tooltip.relics.spore_sack.ability.multiplying.stat.amount.title": "Grau de Tamanho do Esporo:", - "tooltip.relics.spore_sack.ability.multiplying.stat.amount.value": "%1$s.", - "tooltip.relics.spore_sack.ability.explosion": "Liberação de Veneno", - "tooltip.relics.spore_sack.ability.explosion.description": "Esvazia o buffer da relíquia, liberando todas as cargas de esporos acumuladas no mundo. O tamanho dos esporos liberados depende da quantidade de vida que falta ao usuário.", - "tooltip.relics.spore_sack.ability.explosion.stat.size.title": "Tamanho do Esporo:", - "tooltip.relics.spore_sack.ability.explosion.stat.size.value": "%1$s por ponto de vida que falta.", - "tooltip.relics.spore_sack.ability.explosion.predicate.spore": "Esporos no saco", - - "item.relics.ice_breaker": "Quebra-Gelo", - "tooltip.relics.ice_breaker.description": "+1 ponto de experiência para cada 3 blocos de queda antes de acionar a habilidade «Terremoto».", - "tooltip.relics.ice_breaker.ability.sustainability": "Sustentabilidade", - "tooltip.relics.ice_breaker.ability.sustainability.description": "Aumenta a velocidade de queda, aumenta a resistência ao empurrão e remove o escorregamento de blocos.", - "tooltip.relics.ice_breaker.ability.sustainability.stat.modifier.title": "Resistência ao Empurrão:", - "tooltip.relics.ice_breaker.ability.sustainability.stat.modifier.value": "%1$s%%.", - "tooltip.relics.ice_breaker.ability.impact": "Terremoto", - "tooltip.relics.ice_breaker.ability.impact.description": "Usar a habilidade durante uma queda criará uma onda de choque no local de aterrissagem, causando dano e lançando alvos próximos para longe. A força da onda depende da distância que o usuário percorreu na queda.", - "tooltip.relics.ice_breaker.ability.impact.stat.size.title": "Raio Máximo:", - "tooltip.relics.ice_breaker.ability.impact.stat.size.value": "%1$s blocos.", - "tooltip.relics.ice_breaker.ability.impact.stat.damage.title": "Dano Mínimo:", - "tooltip.relics.ice_breaker.ability.impact.stat.damage.value": "%1$s unidades.", - "tooltip.relics.ice_breaker.ability.impact.predicate.falling": "Queda Livre", - - "item.relics.bastion_ring": "Anel do Bastião", - "tooltip.relics.bastion_ring.description": "+1/5/10 ponto(s) de experiência para cada Piglin-Zumbi/Piglin/Piglin Bruto morto.\n+1 ponto de experiência para cada negociação adicional da habilidade «Respeito».", - "tooltip.relics.bastion_ring.ability.compass": "Reconhecimento", - "tooltip.relics.bastion_ring.ability.compass.description": "Torna os piglins neutros em relação ao usuário. O piglin mais próximo indicará a localização do bastião nas proximidades.", - "tooltip.relics.bastion_ring.ability.trade": "Respeito", - "tooltip.relics.bastion_ring.ability.trade.description": "Cada negociação com piglins tem uma chance múltipla de 50% de resultar em uma negociação adicional.", - "tooltip.relics.bastion_ring.ability.trade.stat.rolls.title": "Número máximo de negociações:", - "tooltip.relics.bastion_ring.ability.trade.stat.rolls.value": "%1$s unidades.", - - "item.relics.horse_flute": "Flauta de Cavalo", - "tooltip.relics.horse_flute.description": "+1 ponto de experiência para cada 25 blocos percorridos por um cavalo convocado pela habilidade «Estábulo Portátil».", - "tooltip.relics.horse_flute.ability.paddock": "Estábulo Portátil", - "tooltip.relics.horse_flute.ability.paddock.description": "Ao usar o relicário no cavalo, você move o animal para o armazenamento interno. Reutilizar liberará a criatura. Se a distância entre o usuário e o cavalo convocado exceder 16 blocos, ele se encaixará automaticamente de volta na flauta.", - "tooltip.relics.horse_flute.ability.paddock.stat.slots.title": "Espaços:", - "tooltip.relics.horse_flute.ability.paddock.stat.slots.value": "%1$s.", - "tooltip.relics.horse_flute.ability.heal": "Tratamento em Campo", - "tooltip.relics.horse_flute.ability.heal.description": "Um cavalo colocado no armazenamento interno se recuperará lentamente de sua saúde.", - "tooltip.relics.horse_flute.ability.heal.stat.amount.title": "Tratamento:", - "tooltip.relics.horse_flute.ability.heal.stat.amount.value": "%1$s unidades de saúde por segundo.", - - "item.relics.magma_walker": "Botas Magmaticas", - "tooltip.relics.magma_walker.description": "+1 ponto de experiência para cada 5 unidades de aquecimento da habilidade «Passo Ardente».", - "tooltip.relics.magma_walker.ability.pace": "Passo Ardente", - "tooltip.relics.magma_walker.ability.pace.description": "Por um certo tempo, permite andar sobre a superfície de lava sem cair e sem sofrer dano. Após o término do limite de tempo, as botas começam a superaquecer e causam dano ao usuário proporcional ao grau de superaquecimento.", - "tooltip.relics.magma_walker.ability.pace.stat.time.title": "Duração:", - "tooltip.relics.magma_walker.ability.pace.stat.time.value": "%1$s segundos.", - "tooltip.relics.magma_walker.ability.heat_resistance": "Resistência ao Calor", - "tooltip.relics.magma_walker.ability.heat_resistance.description": "Suprime o dano de blocos quentes.", - - "item.relics.aqua_walker": "Botas Aquáticas", - "tooltip.relics.aqua_walker.description": "+1 ponto de experiência para cada 5 unidades de umidade da habilidade «Resistência à Umidade».", - "tooltip.relics.aqua_walker.ability.walking": "Resistência à Umidade", - "tooltip.relics.aqua_walker.ability.walking.description": "Permite, por um certo período de tempo, andar sobre a superfície da água sem afundar. Após o término do tempo, as botas começam a afundar, arrastando o usuário para debaixo d'água.", - "tooltip.relics.aqua_walker.ability.walking.stat.time.title": "Duração:", - "tooltip.relics.aqua_walker.ability.walking.stat.time.value": "%1$s segundos.", - - "item.relics.drowned_belt": "Cinto do Afogado", - "tooltip.relics.drowned_belt.description": "+1 ponto de experiência para cada nível de encantamento «Correnteza» no tridente ao usá-lo.", - "tooltip.relics.drowned_belt.ability.slots": "Capacidade de Carga", - "tooltip.relics.drowned_belt.ability.slots.description": "Aumenta o número máximo de espaços para relíquias de equipamento.", - "tooltip.relics.drowned_belt.ability.slots.stat.talisman.title": "Talismãs:", - "tooltip.relics.drowned_belt.ability.slots.stat.talisman.value": "+%1$s espaços.", - "tooltip.relics.drowned_belt.ability.anchor": "Peso Morto", - "tooltip.relics.drowned_belt.ability.anchor.description": "Reduz a velocidade de natação e aumenta a velocidade de afundamento do usuário.", - "tooltip.relics.drowned_belt.ability.anchor.stat.slowness.title": "Redução de Velocidade na Natação:", - "tooltip.relics.drowned_belt.ability.anchor.stat.slowness.value": "+%1$s%%.", - "tooltip.relics.drowned_belt.ability.anchor.stat.sinking.title": "Taxa de Afundamento:", - "tooltip.relics.drowned_belt.ability.anchor.stat.sinking.value": "+%1$s%%.", - "tooltip.relics.drowned_belt.ability.pressure": "Fluxos de Água", - "tooltip.relics.drowned_belt.ability.pressure.description": "Aumenta o dano causado debaixo d'água.", - "tooltip.relics.drowned_belt.ability.pressure.stat.damage.title": "Multiplicador de Dano:", - "tooltip.relics.drowned_belt.ability.pressure.stat.damage.value": "+%1$s%%.", - "tooltip.relics.drowned_belt.ability.riptide": "Atração pela Água", - "tooltip.relics.drowned_belt.ability.riptide.description": "Permite usar a habilidade «Riptide» do tridente sem chuva ou água, adicionando tempo de recarga a ela.", - "tooltip.relics.drowned_belt.ability.riptide.stat.cooldown.title": "Tempo de Recarga:", - "tooltip.relics.drowned_belt.ability.riptide.stat.cooldown.value": "%1$s segundos por nível de encantamento.", - - "item.relics.hunter_belt": "Cinto do Caçador", - "tooltip.relics.hunter_belt.description": "+1 ponto de experiência para cada ataque feito pelo animal de estimação do usuário.", - "tooltip.relics.hunter_belt.ability.slots": "Capacidade de Carga", - "tooltip.relics.hunter_belt.ability.slots.description": "Aumenta o número máximo de espaços para equipar relíquias.", - "tooltip.relics.hunter_belt.ability.slots.stat.talisman.title": "Talismãs:", - "tooltip.relics.hunter_belt.ability.slots.stat.talisman.value": "+%1$s espaços.", - "tooltip.relics.hunter_belt.ability.training": "Treinamento", - "tooltip.relics.hunter_belt.ability.training.description": "Aumenta o dano causado pelos animais de estimação do usuário.", - "tooltip.relics.hunter_belt.ability.training.stat.damage.title": "Multiplicador de Dano:", - "tooltip.relics.hunter_belt.ability.training.stat.damage.value": "+%1$s%%.", - - "item.relics.leather_belt": "Cinto de Couro", - "tooltip.relics.leather_belt.description": "+1 ponto de experiência para cada experiência adquirida pelos talismãs equipados.", - "tooltip.relics.leather_belt.ability.slots": "Capacidade de Carga", - "tooltip.relics.leather_belt.ability.slots.description": "Aumenta o número máximo de espaços para equipar relíquias.", - "tooltip.relics.leather_belt.ability.slots.stat.talisman.title": "Talismãs:", - "tooltip.relics.leather_belt.ability.slots.stat.talisman.value": "+%1$s espaços.", - - "item.relics.rage_glove": "Luva da Fúria", - "tooltip.relics.rage_glove.description": "+1 ponto de experiência para cada 3 cargas da habilidade «Fúria Berserk» quando elas são resetadas.\n+1 ponto de experiência para cada alvo atingido pela habilidade «Investida».", - "tooltip.relics.rage_glove.ability.rage": "Fúria do Berserker", - "tooltip.relics.rage_glove.ability.rage.description": "Cada ataque feito pelo usuário dentro de 3 segundos após o último acumula 1 carga no buffer interno da relíquia. O dano causado e recebido pelo usuário, bem como a velocidade de movimento e o dano causado aumentam proporcionalmente às cargas acumuladas. Após 3 segundos, o buffer interno da relíquia é esvaziado, cancelando todos os bônus recebidos.", - "tooltip.relics.rage_glove.ability.rage.stat.duration.title": "Tempo de existência da carga:", - "tooltip.relics.rage_glove.ability.rage.stat.duration.value": "%1$s segundos.", - "tooltip.relics.rage_glove.ability.rage.stat.incoming_damage.title": "Multiplicador de dano recebido:", - "tooltip.relics.rage_glove.ability.rage.stat.incoming_damage.value": "%1$s%% por carga.", - "tooltip.relics.rage_glove.ability.rage.stat.dealt_damage.title": "Multiplicador de dano causado:", - "tooltip.relics.rage_glove.ability.rage.stat.dealt_damage.value": "%1$s%% por carga.", - "tooltip.relics.rage_glove.ability.phlebotomy": "Flebotomia", - "tooltip.relics.rage_glove.ability.phlebotomy.description": "Aumenta a velocidade de ataque e movimento do usuário, além de conceder regeneração passiva proporcional ao percentual de vida faltante.", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.heal.title": "Regeneração de vida:", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.heal.value": "%1$s para cada 1%% por segundo.", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.movement_speed.title": "Multiplicador de velocidade de movimento:", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.movement_speed.value": "%1$s%% para cada 1%%.", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.attack_speed.title": "Multiplicador de velocidade de ataque:", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.attack_speed.value": "%1$s%% para cada 1%%.", - "tooltip.relics.rage_glove.ability.spurt": "Investida", - "tooltip.relics.rage_glove.ability.spurt.description": "Investe na direção da visão, colocando fogo, causando sangramento e atacando cada alvo em seu caminho com o item na mão. Causa dano adicional proporcional ao número de cargas no buffer interno da relíquia da habilidade «Fúria Berserk» e esvazia-o.", - "tooltip.relics.rage_glove.ability.spurt.stat.cooldown.title": "Tempo de recarga:", - "tooltip.relics.rage_glove.ability.spurt.stat.cooldown.value": "%1$s segundos.", - "tooltip.relics.rage_glove.ability.spurt.stat.damage.title": "Dano causado:", - "tooltip.relics.rage_glove.ability.spurt.stat.damage.value": "%1$s por carga.", - "tooltip.relics.rage_glove.ability.spurt.stat.distance.title": "Distância:", - "tooltip.relics.rage_glove.ability.spurt.stat.distance.value": "%1$s blocos.", - - "item.relics.ice_skates": "Patins de Gelo", - "tooltip.relics.ice_skates.description": "+1 ponto de experiência para cada segundo de aceleração da habilidade «Patinação».", - "tooltip.relics.ice_skates.ability.skating": "Patinação", - "tooltip.relics.ice_skates.ability.skating.description": "Aumenta a velocidade de movimento no gelo dependendo da duração do deslizamento.", - "tooltip.relics.ice_skates.ability.skating.stat.speed.title": "Multiplicador de velocidade por segundo:", - "tooltip.relics.ice_skates.ability.skating.stat.speed.value": "+%1$s%%.", - "tooltip.relics.ice_skates.ability.skating.stat.duration.title": "Duração máxima:", - "tooltip.relics.ice_skates.ability.skating.stat.duration.value": "%1$s segundos.", - "tooltip.relics.ice_skates.ability.ram": "Investida", - "tooltip.relics.ice_skates.ability.ram.description": "Ao colidir com alvos, causa dano proporcional à duração do uso da habilidade «Patinação».", - "tooltip.relics.ice_skates.ability.ram.stat.damage.title": "Dano por segundo:", - "tooltip.relics.ice_skates.ability.ram.stat.damage.value": "%1$s unidades.", - - "item.relics.amphibian_boot": "Bota Anfíbia", - "tooltip.relics.amphibian_boot.description": "+1 ponto de experiência para cada segundo de aceleração da habilidade «Barbatanas».", - "tooltip.relics.amphibian_boot.ability.swimming": "Barbatanas", - "tooltip.relics.amphibian_boot.ability.swimming.description": "Acelera a velocidade de natação dependendo da sua duração.", - "tooltip.relics.amphibian_boot.ability.swimming.stat.speed.title": "Multiplicador de velocidade:", - "tooltip.relics.amphibian_boot.ability.swimming.stat.speed.value": "+%1$s%% para cada segundo.", - "tooltip.relics.amphibian_boot.ability.swimming.stat.duration.title": "Duração máxima:", - "tooltip.relics.amphibian_boot.ability.swimming.stat.duration.value": "%1$s segundos.", - - "item.relics.spatial_sign": "Selo Espacial", - "tooltip.relics.spatial_sign.description": "+1 ponto de experiência para cada segundo de retorno da habilidade «Fenda Temporal».", - "tooltip.relics.spatial_sign.ability.seal": "Fenda Temporal", - "tooltip.relics.spatial_sign.ability.seal.description": "Ao ser usada, retorna o usuário ao longo da rota percorrida durante um certo período de tempo. O uso repetido encerrará a habilidade.", - "tooltip.relics.spatial_sign.ability.seal.stat.time.title": "Duração máxima:", - "tooltip.relics.spatial_sign.ability.seal.stat.time.value": "%1$s segundos.", - - "item.relics.chorus_inhibitor": "Inibidor do Coro", - "tooltip.relics.chorus_inhibitor.description": "+1 ponto de experiência para cada 10 blocos até o ponto de teletransporte da habilidade «Controle de Teletransporte».", - "tooltip.relics.chorus_inhibitor.ability.blink": "Controle de Teletransporte", - "tooltip.relics.chorus_inhibitor.ability.blink.description": "Ao usar a fruta do coro, teleporta o usuário para o bloco dentro do alcance da linha de visão.", - "tooltip.relics.chorus_inhibitor.ability.blink.stat.distance.title": "Distância Máxima:", - "tooltip.relics.chorus_inhibitor.ability.blink.stat.distance.value": "%1$s blocos.", - "tooltip.relics.chorus_inhibitor.ability.blink.stat.cooldown.title": "Tempo de Recarga:", - "tooltip.relics.chorus_inhibitor.ability.blink.stat.cooldown.value": "%1$s segundos.", - - "item.relics.wool_mitten": "Luva de Lã", - "item.relics.solid_snowball": "Bola de Neve Congelada", - "tooltip.relics.wool_mitten.description": "+1 ponto de experiência para cada 5 unidades de tamanho quando atingido por uma bola de neve da habilidade «Moldar».", - "tooltip.relics.wool_mitten.ability.mold": "Moldar", - "tooltip.relics.wool_mitten.ability.mold.description": "Coletar neve pressionando o botão direito do mouse com as mãos vazias gradualmente forma bolas de neve sólidas especiais. Ao atingir uma bola de neve dessas em um alvo, causará dano e o atordoará, além de congelar alvos próximos. Segurar uma bola de neve sem um relicário equipado também congela o usuário.", - "tooltip.relics.wool_mitten.ability.mold.stat.size.title": "Tamanho Máximo:", - "tooltip.relics.wool_mitten.ability.mold.stat.size.value": "%1$s unidades.", - "tooltip.relics.wool_mitten.ability.mold.stat.damage.title": "Dano:", - "tooltip.relics.wool_mitten.ability.mold.stat.damage.value": "%1$s por unidade de tamanho.", - "tooltip.relics.wool_mitten.ability.mold.stat.stun.title": "Atordoamento:", - "tooltip.relics.wool_mitten.ability.mold.stat.stun.value": "%1$s segundos por unidade de tamanho.", - "tooltip.relics.wool_mitten.ability.mold.stat.freeze.title": "Congelamento:", - "tooltip.relics.wool_mitten.ability.mold.stat.freeze.value": "%1$s segundos por unidade de tamanho.", - - "item.relics.roller_skates": "Patins", - "tooltip.relics.roller_skates.description": "+1 ponto de experiência para cada segundo de aceleração da habilidade «Aceleração».", - "tooltip.relics.roller_skates.ability.skating": "Aceleração", - "tooltip.relics.roller_skates.ability.skating.description": "Aumenta a velocidade de movimento dependendo da sua duração. Todos os blocos se tornam escorregadios para o usuário.", - "tooltip.relics.roller_skates.ability.skating.stat.speed.title": "Multiplicador de Velocidade por Segundo:", - "tooltip.relics.roller_skates.ability.skating.stat.speed.value": "%1$s%%.", - "tooltip.relics.roller_skates.ability.skating.stat.duration.title": "Duração Máxima:", - "tooltip.relics.roller_skates.ability.skating.stat.duration.value": "%1$s segundos.", - - "item.relics.space_dissector": "Dissectador Espacial", - "tooltip.relics.space_dissector.description": "+1 ponto de experiência para cada portal criado, se não houver nenhum portal existente", - "tooltip.relics.space_dissector.ability.dissection": "Dissecção", - "tooltip.relics.space_dissector.ability.dissection.description": "Ao segurar o botão direito do mouse (RMB), cria um portal em um ponto ao longo da linha de visão; parar de segurar o RMB cria um segundo portal seguindo o mesmo princípio, vinculando-o ao primeiro. Trazer uma criatura viva para um dos portais a moverá para o portal vinculado. Os portais não funcionam se houver blocos sólidos em seu caminho.", - "tooltip.relics.space_dissector.ability.dissection.stat.distance.title": "Distância Máxima:", - "tooltip.relics.space_dissector.ability.dissection.stat.distance.value": "%1$s blocos.", - "tooltip.relics.space_dissector.ability.dissection.stat.time.title": "Tempo de Vida do Portal:", - "tooltip.relics.space_dissector.ability.dissection.stat.time.value": "%1$s segundos.", - - "block.relics.researching_table": "Mesa de Pesquisa", - - "effect.relics.stun": "Atordoamento", - "effect.relics.paralysis": "Paralisia", - "effect.relics.confusion": "Confusão", - "effect.relics.vanishing": "Desvanecimento", - "effect.relics.anti_heal": "Anti-Cura", - "effect.relics.bleeding": "Sangramento", - - "command.relics.base.not_relic": "O item na mão deve ser uma relíquia!", - - "key.relics.ability_list": "Mostrar a HUD de habilidades ativas" -} diff --git a/src/main/resources/assets/relics/lang/ru_ru.json b/src/main/resources/assets/relics/lang/ru_ru.json index 9d78855b..391482e3 100644 --- a/src/main/resources/assets/relics/lang/ru_ru.json +++ b/src/main/resources/assets/relics/lang/ru_ru.json @@ -1,59 +1,109 @@ { "itemGroup.relics": "Реликвии", - "curios.identifier.talisman": "Талисман", "curios.identifier.feet": "Ноги", - "tooltip.relics.relic.tooltip.table": "Узнать о реликвии больше можно на столе исследователя.", - "tooltip.relics.relic.tooltip.shift": "Удерживай [Шифт] для подробной информации.", + "tooltip.relics.researching.info": "Удерживай [%1$s] для исследования...", "tooltip.relics.relic.tooltip.abilities": "Способности:", - "tooltip.relics.relic.ability.tooltip.low_level": "Для использования необходимо повысить уровень реликвии до %1$s %2$s.", - "tooltip.relics.relic.ability.tooltip.no_stats": "Способность не имеет улучшаемых характеристик и не влияет на качество реликвии.", - "tooltip.relics.relic.ability.tooltip.ready_to_upgrade": "Способность готова к улучшению %1$s .", + "tooltip.relics.researching.badge.ability.oblivion.title": "Подверженность забвению", + "tooltip.relics.researching.badge.ability.oblivion.description": "Способность не будет работать под эффектом забвения.", + "tooltip.relics.researching.badge.ability.silence.title": "Подверженность безмолвию", + "tooltip.relics.researching.badge.ability.silence.description": "Способность не будет работать под эффектом безмолвия.", + "tooltip.relics.researching.badge.ability.flawless_ability.title": "Совершенная способность", + "tooltip.relics.researching.badge.ability.flawless_ability.description": "Способность достигла максимальных идеальных параметров. Гордись собой!", + "tooltip.relics.researching.badge.ability.instantaneous.title": "Мгновенное применение", + "tooltip.relics.researching.badge.ability.instantaneous.description": "Способность срабатывает сразу же после использования.", + "tooltip.relics.researching.badge.ability.interruptible.title": "Прерываемое применение", + "tooltip.relics.researching.badge.ability.interruptible.description": "Способность действует какое-то время после использования и прерывается повторным использованием.", + "tooltip.relics.researching.badge.ability.cyclical.title": "Цикличное применение", + "tooltip.relics.researching.badge.ability.cyclical.description": "Способность действует только при непрерывном использовании.", + "tooltip.relics.researching.badge.ability.toggleable.title": "Переключаемое применения", + "tooltip.relics.researching.badge.ability.toggleable.description": "Способность может быть включена/выключена при использовании.", + "tooltip.relics.researching.badge.ability.chargeable.title": "Заряжаемое применение", + "tooltip.relics.researching.badge.ability.chargeable.description": "Способность срабатывает мгновенно спустя некоторое время цикличного использования. Результат срабатывания может зависеть от продолжительности использования.", + "tooltip.relics.researching.badge.ability.stated.title": "Режимное применение", + "tooltip.relics.researching.badge.ability.stated.description": "Способность имеет несколько циклично переключаемых режимов, сменяемых её использованием.", - "tooltip.relics.relic.leveling_points.title": "Очки прокачки", + "tooltip.relics.researching.badge.relic.flawless_relic.title": "Совершенная реликвия", + "tooltip.relics.researching.badge.relic.flawless_relic.description": "Реликвия достигла максимальных идеальных параметров. Гордись собой!", - "tooltip.relics.relic.vanilla_experience.title": "Ванильный опыт Minecraft", - "tooltip.relics.relic.vanilla_experience.current_amount": "Текущее количество: %1$s/%2$s [%3$s%%]", - "tooltip.relics.relic.vanilla_experience.total_amount": "Общее количество: %1$s", + "tooltip.relics.researching.research.tip": "Чтобы разблокировать способность, необходимо соединить звезды, скрытые под туманом, так, чтобы образованное созвездие совпало с изображением на фоне. Когда созвездие будет подобрано правильно, способность будет исследована автоматически.", - "tooltip.relics.relic.relic_experience.title": "Опыт реликвии", - "tooltip.relics.relic.relic_experience.current_amount": "Текущее количество: %1$s/%2$s [%3$s%%]", + "tooltip.relics.researching.research.hint.description": "Подсказка", + "tooltip.relics.researching.research.hint.cost": "Стоимость: %1$s уровней опыта %2$s.", + "tooltip.relics.researching.research.hint.quick": "Удерживай [Шифт] для полного автоматического исследования способности.", + "tooltip.relics.researching.research.hint.locked": "Способность уже исследована!", - "tooltip.relics.relic.max_level": "MAX", + "tooltip.relics.researching.badge.ability.cast_type.hint": "Используй клавишу [%1$s] вне любого интерфейса для вызова меню активных способностей!", - "tooltip.relics.relic.ability.level": " [%1$s/%2$s]", + "tooltip.relics.researching.general.leveling_point.title": "Очки улучшения:", + "tooltip.relics.researching.general.leveling_point.extra_info": "Получается при повышении уровня реликвии и используется для повышения уровня способностей.", + + "tooltip.relics.researching.general.player_experience.title": "Уровень опыта:", + "tooltip.relics.researching.general.player_experience.extra_info": "Стандартный опыт игрока из оригинальной игры. Получается при убийстве мобов, добыче руды, плавке предметов и т.п.", + + "tooltip.relics.researching.general.luck.title": "Удача:", + "tooltip.relics.researching.general.luck.extra_info": "Получается при каждом неудачном сбросе случайных характеристик реликвии и повышает вероятность получения лучших значений при их следующем сбросе. Увеличивает стоимость сброса на 1 уровень опыта за каждые 25% удачи.", + + "tooltip.relics.researching.relic.card.low_level": "Для разблокировки способности необходимо повысить уровень реликвии до %1$s!", + "tooltip.relics.researching.relic.card.unresearched": "Для использования способности необходимо завершить исследование!", + "tooltip.relics.researching.relic.card.ready_to_unlock": "Способность готова к разблокировке! Кликов осталось: %1$s", + "tooltip.relics.researching.relic.card.ready_to_upgrade": "Способность готова к улучшению!", + + "tooltip.relics.researching.relic.gem.low_level": "Для разблокировки источника получения опыта необходимо повысить уровень реликвии до %1$s!", + "tooltip.relics.researching.relic.gem.locked_ability": "Для разблокировки источника получения опыта необходимо разблокировать и исследовать связанную способность!", + + "tooltip.relics.researching.tab.relic": "Реликвия", + "tooltip.relics.researching.tab.ability": "Способности", + "tooltip.relics.researching.tab.experience": "Источники получения опыта", + + "tooltip.relics.researching.general.extra_info": "Удерживай [Шифт] для подробной информации", + + "tooltip.relics.researching.relic.info.level": "Уровень реликвии:", + "tooltip.relics.researching.relic.info.quality": "Качество реликвии:", + "tooltip.relics.researching.relic.info.extra_info": "Качество реликвии представляет собой среднее арифметическое качества всех разблокированных на данный момент способностей и измеряется в виде очков от 1 до 5 с шагом в 0.5. Является исключительно визуальной метрикой и показывает насколько стартовые случайные характеристики предмета близки к идеально возможным. Для повышения общего качества реликвии необходимо рассматривать каждую способность по отдельности.", + + "tooltip.relics.researching.relic.experience.title": "Опыт реликвии:", + "tooltip.relics.researching.relic.experience.extra_info": "Получается при использовании способностей реликвии по прямому назначению (подробнее можно узнать в разделе источников получения опыта). При достижении максимального значения опыта уровень реликвии и запас очков улучшения увеличивается на 1, позволяя разблокировать ранее недоступные способности или улучшить уже существующие.", + + "tooltip.relics.researching.ability.info.level": "Уровень способности:", + "tooltip.relics.researching.ability.info.quality": "Качество способности:", + "tooltip.relics.researching.ability.info.extra_info": "Качество способности, по аналогии с качеством реликвии, представляет собой среднее арифметическое качества всех имеющихся у способности характеристик и измеряется в виде очков от 1 до 5 с шагом в 0.5. Является исключительно визуальной метрикой и показывает насколько стартовые случайные характеристики способности близки к идеально возможным. Для повышения качества способности необходимо сбрасывать её случайные характеристики до получения лучшего значения.", "tooltip.relics.relic.status.positive": "§2§l[§2§l✔§2§l]", "tooltip.relics.relic.status.negative": "§4§l[§4§l✘§4§l]", - - "tooltip.relics.relic.exchange.description": "Конвертация опыта", - "tooltip.relics.relic.exchange.cost": "Преобразовать %1$s ванильного опыта Minecraft в 1%% от максимального опыта для текущего уровня реликвии. Стоимость обмена увеличивается за каждое использование %2$s.", - "tooltip.relics.relic.exchange.locked": "Реликвия достигла максимального уровня.", + "tooltip.relics.relic.status.unknown": "§6§l[§6§l?§6§l]", "tooltip.relics.relic.upgrade.description": "Повышение уровня", - "tooltip.relics.relic.upgrade.cost": "Стоимость: %1$s очков прокачки %2$s, %3$s единиц опыта %4$s.", + "tooltip.relics.relic.upgrade.cost": "Стоимость: %1$s очков улучшения %2$s, %3$s уровней опыта %4$s.", "tooltip.relics.relic.upgrade.locked": "Способность достигла максимального уровня.", + "tooltip.relics.relic.upgrade.quick": "Удерживай [Шифт] для автоматического повышения до максимально возможного уровня.", "tooltip.relics.relic.reroll.description": "Сброс случайных характеристик", - "tooltip.relics.relic.reroll.cost": "Стоимость: %1$s единиц опыта %2$s.", + "tooltip.relics.relic.reroll.cost": "Стоимость: %1$s уровней опыта %2$s.", + "tooltip.relics.relic.reroll.quick": "Удерживай [Шифт] для автоматического сброса случайных характеристик до идеальных значений.", + "tooltip.relics.relic.reroll.warning": "Удерживай [Шифт] для подтверждения сброса характеристик с идеальных значений на другие случайные.", - "tooltip.relics.relic.reset.description": "Сброс очков прокачки", - "tooltip.relics.relic.reset.cost": "Стоимость: %1$s единиц опыта %2$s.", + "tooltip.relics.relic.reset.description": "Сброс очков улучшения", + "tooltip.relics.relic.reset.cost": "Стоимость: %1$s уровней опыта %2$s.", "tooltip.relics.relic.reset.locked": "Для использования необходимо улучшить способность хотя бы 1 раз.", "item.relics.infinity_ham": "Бесконечный окорок", - "tooltip.relics.infinity_ham.description": "+1 ед. опыта за каждый съеденный кусок от способности «Регенерация».", - "tooltip.relics.infinity_ham.ability.autophagy": "Регенерация", - "tooltip.relics.infinity_ham.ability.autophagy.description": "Использование реликвии расходует один из регенерируемых зарядов, восполняя голод носителя.", - "tooltip.relics.infinity_ham.ability.autophagy.stat.feed.title": "Насыщение:", - "tooltip.relics.infinity_ham.ability.autophagy.stat.feed.value": "%1$s единиц.", - "tooltip.relics.infinity_ham.ability.infusion": "Алхимия", - "tooltip.relics.infinity_ham.ability.infusion.description": "Использование зелья на реликвии в инвентаре запоминает его эффект, расходуя зелье. Последующее использование способности «Регенерация» будет накладывать на носителя суммируемый эффект связанного зелья. При полном отсутствии зарядов реликвия теряет свойства связанного зелья.", - "tooltip.relics.infinity_ham.ability.infusion.stat.duration.title": "Продолжительность эффекта:", - "tooltip.relics.infinity_ham.ability.infusion.stat.duration.value": "%1$s секунд за заряд.", + "tooltip.relics.infinity_ham.description": "Таинственный кусок мяса, плавно разрастающийся до прежних размеров, сколько его ни кромсай.", + "tooltip.relics.infinity_ham.ability.regeneration": "Регенерация", + "tooltip.relics.infinity_ham.ability.regeneration.description": "Каждые %1$s секунд регенерирует до 6 съедобных кусочков, восполняющих %2$s единиц голода каждый. При поедании реликвии автоматически расходует необходимое количество кусочков для восполнения голода игрока.", + "tooltip.relics.infinity_ham.ability.marinade": "Маринад", + "tooltip.relics.infinity_ham.ability.marinade.description": "При нажатии ЛКМ зельем по реликвии в инвентаре позволяет применить на неё эффекты этого зелья. При каждом поедании реликвии применяет на игрока эти эффекты на %1$s секунд за каждую восполненную единицу голода. Применение бутылочки с водой очистит последние эффекты зелья.", + "tooltip.relics.infinity_ham.ability.meat_bat": "Мясная бита", + "tooltip.relics.infinity_ham.ability.meat_bat.description": "Позволяет использовать реликвию как оружие ближнего боя, нанося %1$s единиц урона и оглушая цель на %2$s секунд за каждый кусочек. Расходует все кусочки при совершении атаки вне зависимости от того, сколько здоровья было у моба.", + "tooltip.relics.infinity_ham.leveling_source.regeneration.title": "Регенерация", + "tooltip.relics.infinity_ham.leveling_source.regeneration.description": "+%1$s единиц опыта за каждый съеденный кусочек от способности %2$s.", + "tooltip.relics.infinity_ham.leveling_source.marinade.title": "Маринад", + "tooltip.relics.infinity_ham.leveling_source.marinade.description": "+%1$s единиц опыта за каждый эффект при применении зелья на реликвии при помощи способности %2$s.", + "tooltip.relics.infinity_ham.leveling_source.meat_bat.title": "Мясная бита", + "tooltip.relics.infinity_ham.leveling_source.meat_bat.description": "+%1$s единиц опыта за каждый кусочек при срабатывании способности %2$s.", "item.relics.enders_hand": "Рука Края", "tooltip.relics.enders_hand.description": "+1 ед. опыта за использование способности «Транспозиция Края» + 1 ед. опыта за каждые 10 блоков от расстояния до цели при использовании.", @@ -66,13 +116,19 @@ "tooltip.relics.enders_hand.ability.swap.predicate.target": "Взгляд на цель", "item.relics.holy_locket": "Священный медальон", - "tooltip.relics.holy_locket.description": "+1 ед. опыта за каждое срабатывание способности «Божественное благословение» + 1 ед. опыта за каждую украденную единицу исцеления.", - "tooltip.relics.holy_locket.ability.steal": "Божественное благословение", - "tooltip.relics.holy_locket.ability.steal.description": "Перенаправляет часть регенерируемого здоровья ближайших существ носителю реликвии.", - "tooltip.relics.holy_locket.ability.steal.stat.amount.title": "Количество:", - "tooltip.relics.holy_locket.ability.steal.stat.amount.value": "%1$s%% от регенерируемого здоровья.", - "tooltip.relics.holy_locket.ability.steal.stat.radius.title": "Радиус:", - "tooltip.relics.holy_locket.ability.steal.stat.radius.value": "%1$s блоков.", + "tooltip.relics.holy_locket.description": "Наделяет носителя способностью обращать исцеление противников против них самих.", + "tooltip.relics.holy_locket.ability.faith": "Верование", + "tooltip.relics.holy_locket.ability.faith.description": "Имеет 2 переключаемых режима: святость и нечестивость. В красном режиме святости крадёт %1$s%% исцеления видимых существ в радиусе %3$s блоков носителю реликвии. В синем режиме нечестивости наносит всем видимым существам в том же радиусе урон в размере %2$s%% от получаемого носителем реликвии исцеления.", + "tooltip.relics.holy_locket.ability.penitence": "Покаяние", + "tooltip.relics.holy_locket.ability.penitence.description": "Поджигает атакуемую нежить на 10 секунд и увеличивает наносимый по ней урон на %1$s%%.", + "tooltip.relics.holy_locket.ability.ascension": "Вознесение", + "tooltip.relics.holy_locket.ability.ascension.description": "Убийство цели наделяет носителя реликвии временным суммирующимся вплоть до %1$s секунд эффектом бессмертия на %2$s секунд.", + "tooltip.relics.holy_locket.leveling_source.faith.title": "Верование", + "tooltip.relics.holy_locket.leveling_source.faith.description": "+%1$s единиц опыта за каждое срабатывание способности %2$s.", + "tooltip.relics.holy_locket.leveling_source.penitence.title": "Покаяние", + "tooltip.relics.holy_locket.leveling_source.penitence.description": "+%1$s единиц опыта за каждое срабатывание способности %2$s на ещё не горящей нежити.", + "tooltip.relics.holy_locket.leveling_source.ascension.title": "Вознесение", + "tooltip.relics.holy_locket.leveling_source.ascension.description": "+%1$s единиц опыта за каждое срабатывание способности %2$s.", "item.relics.magic_mirror": "Волшебное зеркало", "tooltip.relics.magic_mirror.description": "+1 ед. опыта за каждое использование способности «Кротовая нора» + 1 ед. опыта за каждые 50 блоков до точки телепортации.", @@ -84,23 +140,13 @@ "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.value": "%1$s секунд.", "item.relics.shadow_glaive": "Теневая глефа", - "tooltip.relics.shadow_glaive.description": "+1 ед. опыта за каждые 2 отскока глефы от способности «Слепое правосудие».", - "tooltip.relics.shadow_glaive.ability.glaive": "Слепое правосудие", - "tooltip.relics.shadow_glaive.ability.glaive.description": "Использование выпускает один из 8 зарядов глефы, отскакивающий между ближайшими целями. Отсутствующие заряды восстанавливаются сами спустя определённое время.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.damage.title": "Урон:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.damage.value": "%1$s.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.recharge.title": "Время восстановления:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.recharge.value": "%1$s секунд.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.bounces.title": "Отскоки:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.bounces.value": "%1$s.", - "tooltip.relics.shadow_glaive.ability.glaive.stat.radius.title": "Радиус отскока:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.radius.value": "%1$s блоков.", - "tooltip.relics.shadow_glaive.ability.saw": "Безжалостное наказание", - "tooltip.relics.shadow_glaive.ability.saw.description": "Использование расходует все 8 зарядов глефы, призывая пилу, наносящую урон целям поблизости. Повторное использование возвратит пилу носителю, восстановив все заряды. Автоматическая регенерация зарядов блокируется, пока способность активна.", - "tooltip.relics.shadow_glaive.ability.saw.stat.speed.title": "Интервал урона:", - "tooltip.relics.shadow_glaive.ability.saw.stat.speed.value": "%1$s секунд.", - "tooltip.relics.shadow_glaive.ability.saw.stat.damage.title": "Урон:", - "tooltip.relics.shadow_glaive.ability.saw.stat.damage.value": "%1$s единиц.", + "tooltip.relics.shadow_glaive.description": "Искусно выкованное своенравное оружие. И если нрав его будет благосклонен - ни орда, ни легион не выстоят под натиском тысячи его лезвий.", + "tooltip.relics.shadow_glaive.ability.mayhem": "Разгром", + "tooltip.relics.shadow_glaive.ability.mayhem.description": "Нанесение урона игроком с вероятностью в %1$s%% спровоцирует появление снаряда, хаотично отскакивающего между ближайшими целями в радиусе 16 блоков до %2$s раз, нанося им %3$s%% от урона спровоцировавшей атаки.", + "tooltip.relics.shadow_glaive.ability.cloning": "Клонирование", + "tooltip.relics.shadow_glaive.ability.cloning.description": "Каждый отскок снаряда от способности «Разгром» с вероятностью в %1$s%% может создать ещё один такой же снаряд.", + "tooltip.relics.shadow_glaive.leveling_source.mayhem.title": "Разгром", + "tooltip.relics.shadow_glaive.leveling_source.mayhem.description": "+%1$s единиц опыта за каждое срабатывание способности %2$s.", "item.relics.arrow_quiver": "Колчан", "tooltip.relics.arrow_quiver.description": "+1 ед. опыта за каждые 10 блоков до поражённой выстрелом цели.", @@ -193,36 +239,11 @@ "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration.value": "%1$s секунд.", "item.relics.spore_sack": "Мешок со спорами", - "tooltip.relics.spore_sack.description": "+1 ед. опыта за каждый выброс споры от способности «Синтез яда».\n+1 ед. опыта за каждое дополнительное разделение споры от способности «Разложение».", - "tooltip.relics.spore_sack.ability.spore": "Синтез яда", - "tooltip.relics.spore_sack.ability.spore.description": "При получении урона выбрасывает в случайном направлении спору, прилипающую к поверхностям и взрывающуюся при приближении цели, нанося ей урон, а также отравляя, замедляя и блокируя исцеление на 5 секунд.", - "tooltip.relics.spore_sack.ability.spore.stat.size.title": "Размер:", - "tooltip.relics.spore_sack.ability.spore.stat.size.value": "%1$s за единицу урона.", - "tooltip.relics.spore_sack.ability.spore.stat.damage.title": "Урон:", - "tooltip.relics.spore_sack.ability.spore.stat.damage.value": "%1$s за единицу размера.", - "tooltip.relics.spore_sack.ability.spore.stat.cooldown.title": "Время перезарядки:", - "tooltip.relics.spore_sack.ability.spore.stat.cooldown.value": "%1$s секунд.", - "tooltip.relics.spore_sack.ability.spore.stat.duration.title": "Время жизни:", - "tooltip.relics.spore_sack.ability.spore.stat.duration.value": "%1$s секунд.", - "tooltip.relics.spore_sack.ability.buffer": "Аккумуляция яда", - "tooltip.relics.spore_sack.ability.buffer.description": "Каждый раз, когда срабатывает время перезарядки способности «Синтез яда», накапливает во внутренний буфер реликвии по одному заряду, который в дальнейшем может быть использован другими способностями для выброса спор. Добавляет шанс не расходовать спору из внутреннего буфера при запросе заряда другими способностями.", - "tooltip.relics.spore_sack.ability.buffer.stat.capacity.title": "Вместимость:", - "tooltip.relics.spore_sack.ability.buffer.stat.capacity.value": "%1$s спор.", - "tooltip.relics.spore_sack.ability.buffer.stat.chance.title": "Шанс:", - "tooltip.relics.spore_sack.ability.buffer.stat.chance.value": "%1$s%%.", - "tooltip.relics.spore_sack.ability.multiplying": "Разложение", - "tooltip.relics.spore_sack.ability.multiplying.description": "Каждая спора при взрыве может разделиться на ещё несколько уменьшенных спор в заданном диапазоне. Максимальное количество спор определяется степенью размера главной споры, но итоговое количество ограничивается первым неудачным срабатыванием шанса разделения споры.", - "tooltip.relics.spore_sack.ability.multiplying.stat.chance.title": "Шанс разделения:", - "tooltip.relics.spore_sack.ability.multiplying.stat.chance.value": "%1$s%%.", - "tooltip.relics.spore_sack.ability.multiplying.stat.size.title": "Размер спор:", - "tooltip.relics.spore_sack.ability.multiplying.stat.size.value": "%1$s%% от главной споры.", - "tooltip.relics.spore_sack.ability.multiplying.stat.amount.title": "Степень размера споры:", - "tooltip.relics.spore_sack.ability.multiplying.stat.amount.value": "%1$s.", - "tooltip.relics.spore_sack.ability.explosion": "Высвобождение яда", - "tooltip.relics.spore_sack.ability.explosion.description": "Опустошает буфер реликвии, выбрасывая все накопленные заряды спор в мир. Размер выбрасываемых спор зависит от отсутствующего у носителя здоровья.", - "tooltip.relics.spore_sack.ability.explosion.stat.size.title": "Размер споры:", - "tooltip.relics.spore_sack.ability.explosion.stat.size.value": "%1$s за единицу здоровья.", - "tooltip.relics.spore_sack.ability.explosion.predicate.spore": "Споры в мешке", + "tooltip.relics.spore_sack.description": "Самый обыкновенный холщевый мешок, доверху набитый смертельными миазмами.", + "tooltip.relics.spore_sack.ability.spore_mist": "Споровый туман", + "tooltip.relics.spore_sack.ability.spore_mist.description": "Когда здоровье игрока опускается ниже отметки в 50%, распыляет вокруг до %1$s самонаводящихся спор, наносящих урон в размере %2$s%% от отсутствующего у игрока здоровья и блокирующих исцеление целей на 5 секунд. Повторное срабатывание способности станет возможным как только здоровье игрока поднимется выше отметки в 50%.", + "tooltip.relics.spore_sack.leveling_source.spore_mist.title": "Споровый туман", + "tooltip.relics.spore_sack.leveling_source.spore_mist.description": "+%1$s единиц опыта за каждое попадание в цель споры от способности %2$s.", "item.relics.ice_breaker": "Ледоколы", "tooltip.relics.ice_breaker.description": "+1 ед. опыта за каждые 3 блока в падении перед срабатыванием способности «Землетрясение».", @@ -278,8 +299,8 @@ "tooltip.relics.drowned_belt.description": "+1 ед. опыта за каждый уровень зачарования «Тягун» на трезубце при его использовании.", "tooltip.relics.drowned_belt.ability.slots": "Грузоподъемность", "tooltip.relics.drowned_belt.ability.slots.description": "Увеличивает максимальное количество слотов для экипировки реликвий.", - "tooltip.relics.drowned_belt.ability.slots.stat.talisman.title": "Талисманы:", - "tooltip.relics.drowned_belt.ability.slots.stat.talisman.value": "+%1$s слотов.", + "tooltip.relics.drowned_belt.ability.slots.stat.charm.title": "Амулеты:", + "tooltip.relics.drowned_belt.ability.slots.stat.charm.value": "+%1$s слотов.", "tooltip.relics.drowned_belt.ability.anchor": "Мёртвый груз", "tooltip.relics.drowned_belt.ability.anchor.description": "Уменьшает скорость плаванья и увеличивает скорость потопления носителя.", "tooltip.relics.drowned_belt.ability.anchor.stat.slowness.title": "Замедление плаванья:", @@ -299,19 +320,19 @@ "tooltip.relics.hunter_belt.description": "+1 ед. опыта за каждую атаку, совершённую питомцем.", "tooltip.relics.hunter_belt.ability.slots": "Грузоподъемность", "tooltip.relics.hunter_belt.ability.slots.description": "Увеличивает максимальное количество слотов для экипировки реликвий.", - "tooltip.relics.hunter_belt.ability.slots.stat.talisman.title": "Талисманы:", - "tooltip.relics.hunter_belt.ability.slots.stat.talisman.value": "+%1$s слотов.", + "tooltip.relics.hunter_belt.ability.slots.stat.charm.title": "Амулеты:", + "tooltip.relics.hunter_belt.ability.slots.stat.charm.value": "+%1$s слотов.", "tooltip.relics.hunter_belt.ability.training": "Дрессировка", "tooltip.relics.hunter_belt.ability.training.description": "Повышает наносимый питомцами носителя урон.", "tooltip.relics.hunter_belt.ability.training.stat.damage.title": "Множитель урона:", "tooltip.relics.hunter_belt.ability.training.stat.damage.value": "+%1$s%%.", "item.relics.leather_belt": "Кожаный пояс", - "tooltip.relics.leather_belt.description": "+1 ед. опыта за каждое получение опыта экипированными талисманами.", + "tooltip.relics.leather_belt.description": "+1 ед. опыта за каждое получение опыта экипированными амулетами.", "tooltip.relics.leather_belt.ability.slots": "Грузоподъемность", "tooltip.relics.leather_belt.ability.slots.description": "Увеличивает максимальное количество слотов для экипировки реликвий.", - "tooltip.relics.leather_belt.ability.slots.stat.talisman.title": "Талисманы:", - "tooltip.relics.leather_belt.ability.slots.stat.talisman.value": "+%1$s слотов.", + "tooltip.relics.leather_belt.ability.slots.stat.charm.title": "Амулеты:", + "tooltip.relics.leather_belt.ability.slots.stat.charm.value": "+%1$s слотов.", "item.relics.rage_glove": "Перчатка ярости", "tooltip.relics.rage_glove.description": "+1 ед. опыта за каждые 3 заряда от способности «Ярость берсерка» при их обнулении.\n+1 ед. опыта за каждую цель, поражённую способностью «Рывок».", @@ -420,9 +441,28 @@ "tooltip.relics.space_dissector.ability.dissection.stat.time.title": "Время жизни портала:", "tooltip.relics.space_dissector.ability.dissection.stat.time.value": "%1$s секунд.", + "item.relics.phantom_boot": "Фантомный ботинок", + "tooltip.relics.phantom_boot.description": "Сгущает материю под ногами владельца реликвии, прокладывая ему путь через любые пространства, даже там, где нет твёрдой земли под ногами.", + "tooltip.relics.phantom_boot.ability.bridge": "Фантомный мост", + "tooltip.relics.phantom_boot.ability.bridge.description": "Создаёт под ногами игрока временный фантомный мост, по которому может перемещаться любой владелец реликвии. Если игрок будет стоять на мосту неподвижно более %1$s секунд, он провалится сквозь него и не сможет подняться обратно, пока не окажется на твёрдой поверхности.", + "tooltip.relics.phantom_boot.leveling_source.bridge.title": "Фантомный мост", + "tooltip.relics.phantom_boot.leveling_source.bridge.description": "+%1$s единиц опыта с вероятностью 10%% при каждом создании моста от способности %2$s.", + + "item.relics.springy_boot": "Пружинный ботинок", + "tooltip.relics.springy_boot.description": "Наделяет владельца реликвии особой упругостью, позволяющей ему отпрыгивать от любых твёрдых поверхностей.", + "tooltip.relics.springy_boot.ability.bounce": "Упругость", + "tooltip.relics.springy_boot.ability.bounce.description": "Повышает упругость всех блоков на %1$s%% относительно блока слизи, позволяя игроку отпрыгивать от них при падении. При активации на земле подбрасывает игрока в воздух.", + "tooltip.relics.springy_boot.leveling_source.bounce.title": "Упругость", + "tooltip.relics.springy_boot.leveling_source.bounce.description": "+%1$s единиц опыта за каждый совершённый отскок от поверхности при помощи способности %2$s.", + + "tooltip.relics.leveling_source.generic.spreading.title": "Распределение опыта", + "tooltip.relics.leveling_source.generic.spreading.description": "Каждый раз, когда любая реликвия в инвентаре получает опыт вне зависимости от способа, %1$s%% от этого опыта также получает и эта реликвия.", + "item.relics.relic_experience_bottle": "Пузырёк опыта реликвии", - "block.relics.researching_table": "Стол исследователя", + "block.relics.phantom_block": "Блок фантомного моста", + + "block.relics.researching_table": "Стол исследователя [Удалено из мода]", "effect.relics.stun": "Оглушение", "effect.relics.paralysis": "Паралич", @@ -430,8 +470,12 @@ "effect.relics.vanishing": "Исчезновение", "effect.relics.anti_heal": "Анти-регенерация", "effect.relics.bleeding": "Кровотечение", + "effect.relics.immortality": "Бессмертие", "command.relics.base.not_relic": "Предмет в руке должен являться реликвией!", - "key.relics.ability_list": "Открыть интерфейс активных способностей" + "info.relics.researching.wrong_container": "Работа с реликвией в этом инвентаре невозможна. Перемести предмет в обычный инвентарь игрока и попробуй ещё раз.", + + "key.relics.active_abilities_list": "Открыть интерфейс активных способностей", + "key.relics.research_relic": "Исследовать реликвию под курсором" } \ No newline at end of file diff --git a/src/main/resources/assets/relics/lang/zh_cn.json b/src/main/resources/assets/relics/lang/zh_cn.json index 55823ad8..120cf2b3 100644 --- a/src/main/resources/assets/relics/lang/zh_cn.json +++ b/src/main/resources/assets/relics/lang/zh_cn.json @@ -1,412 +1,493 @@ { - "itemGroup.relics": "遗物", + "itemGroup.relics": "Relics", - "curios.identifier.talisman": "护符", - "curios.identifier.feet": "足饰", + "curios.identifier.feet": "Feet", - "tooltip.relics.relic.tooltip.table": "用研究台查看更多信息", - "tooltip.relics.relic.tooltip.shift": "按住【Shift】查看更多信息", + "tooltip.relics.researching.info": "按住 [%1$s] 进行研究...", - "tooltip.relics.relic.tooltip.abilities": "技能:", + "tooltip.relics.relic.tooltip.abilities": "能力:", - "tooltip.relics.relic.ability.tooltip.level": "等级:%1$s/%2$s", - "tooltip.relics.relic.ability.tooltip.rarity": "稀有度:", - "tooltip.relics.relic.ability.tooltip.low_level": "使用该技能需要遗物的等级提高到%1$s %2$s。", - "tooltip.relics.relic.ability.tooltip.no_stats": "该技能没有可改变的属性,不会影响遗物的质量。", + "tooltip.relics.researching.badge.ability.oblivion.title": "遗忘易感", + "tooltip.relics.researching.badge.ability.oblivion.description": "在遗忘效果下,该能力无法使用。", + "tooltip.relics.researching.badge.ability.silence.title": "沉默易感", + "tooltip.relics.researching.badge.ability.silence.description": "在沉默效果下,该能力无法使用。", + "tooltip.relics.researching.badge.ability.flawless_ability.title": "完美能力", + "tooltip.relics.researching.badge.ability.flawless_ability.description": "该能力已达到完美参数。为自己感到骄傲吧!", + "tooltip.relics.researching.badge.ability.instantaneous.title": "瞬时使用", + "tooltip.relics.researching.badge.ability.instantaneous.description": "该能力在使用时立即激活。", + "tooltip.relics.researching.badge.ability.interruptible.title": "可中断使用", + "tooltip.relics.researching.badge.ability.interruptible.description": "该能力在使用后持续一段时间,可以通过重复使用来中断。", + "tooltip.relics.researching.badge.ability.cyclical.title": "循环使用", + "tooltip.relics.researching.badge.ability.cyclical.description": "该能力仅在持续使用时有效。", + "tooltip.relics.researching.badge.ability.toggleable.title": "可切换使用", + "tooltip.relics.researching.badge.ability.toggleable.description": "该能力可以在使用时切换开/关。", + "tooltip.relics.researching.badge.ability.chargeable.title": "可充能使用", + "tooltip.relics.researching.badge.ability.chargeable.description": "该能力在循环使用一段时间后立即激活。结果可能取决于使用的持续时间。", + "tooltip.relics.researching.badge.ability.stated.title": "状态使用", + "tooltip.relics.researching.badge.ability.stated.description": "该能力有多种模式,每次使用时循环切换。", - "tooltip.relics.relic.max_level": "-= 满级 =-", + "tooltip.relics.researching.badge.relic.flawless_relic.title": "完美遗物", + "tooltip.relics.researching.badge.relic.flawless_relic.description": "该遗物已达到完美参数。为自己感到骄傲吧!", - "tooltip.relics.relic.ability.level": " 【%1$s/%2$s】", + "tooltip.relics.researching.research.tip": "要解锁能力,需要将隐藏在雾中的星星连接起来,使生成的星座与背景图像匹配。当星座正确对齐时,能力将自动研究。", - "tooltip.relics.relic.status.positive": "§2§l【§2§l✔§2§l】", - "tooltip.relics.relic.status.negative": "§4§l【§4§l✘§4§l】", + "tooltip.relics.researching.research.hint.description": "提示", + "tooltip.relics.researching.research.hint.cost": "成本: %1$s 经验等级 %2$s。", + "tooltip.relics.researching.research.hint.quick": "按住 [Shift] 进行全自动能力研究。", + "tooltip.relics.researching.research.hint.locked": "该能力已被研究!", + + "tooltip.relics.researching.badge.ability.cast_type.hint": "在任何界面外使用 [%1$s] 键调出活动能力菜单!", + + "tooltip.relics.researching.general.leveling_point.title": "升级点数:", + "tooltip.relics.researching.general.leveling_point.extra_info": "在升级遗物时获得,用于升级能力。", + + "tooltip.relics.researching.general.player_experience.title": "经验等级:", + "tooltip.relics.researching.general.player_experience.extra_info": "来自原版游戏的标准玩家经验。通过杀死怪物、挖矿、熔炼物品等获得。", + + "tooltip.relics.researching.general.luck.title": "幸运:", + "tooltip.relics.researching.general.luck.extra_info": "每次重新随机遗物属性失败时获得,增加下次重新随机时获得更好属性的几率。每增加25%的幸运值,重新随机的成本增加1个经验等级。", + + "tooltip.relics.researching.relic.card.low_level": "要解锁,您需要将遗物升级到 %1$s!", + "tooltip.relics.researching.relic.card.no_stats": "能力没有可升级的属性,不影响遗物的质量!", + "tooltip.relics.researching.relic.card.unresearched": "要使用,您需要进行研究!", + "tooltip.relics.researching.relic.card.ready_to_unlock": "能力已准备好解锁!剩余点击次数: %1$s", + "tooltip.relics.researching.relic.card.ready_to_upgrade": "能力已准备好升级!", + + "tooltip.relics.researching.relic.gem.low_level": "要解锁经验来源,您需要将遗物升级到 %1$s!", + "tooltip.relics.researching.relic.gem.locked_ability": "要解锁经验来源,您需要解锁并研究相关能力!", + + "tooltip.relics.researching.tab.relic": "遗物", + "tooltip.relics.researching.tab.ability": "能力", + "tooltip.relics.researching.tab.experience": "经验来源", + + "tooltip.relics.researching.general.extra_info": "按住 [Shift] 查看更多信息", + + "tooltip.relics.researching.relic.info.level": "遗物等级:", + "tooltip.relics.researching.relic.info.quality": "遗物质量:", + "tooltip.relics.researching.relic.info.extra_info": "遗物质量是所有当前解锁能力质量的算术平均值,分数从1到5,步长为0.5。这是一个纯粹的视觉指标,显示物品的初始随机特性与最佳可能特性有多接近。要提高遗物的整体质量,需要分别考虑每个能力。", + + "tooltip.relics.researching.relic.experience.title": "遗物经验:", + "tooltip.relics.researching.relic.experience.extra_info": "通过按预期使用遗物能力获得(更多详细信息可以在经验来源页面找到)。达到最大经验值后,遗物的等级和升级点数池增加1,允许您解锁以前不可用的能力或增强现有能力。", + + "tooltip.relics.researching.ability.info.level": "能力等级:", + "tooltip.relics.researching.ability.info.quality": "能力质量:", + "tooltip.relics.researching.ability.info.extra_info": "能力质量与遗物质量类似,是所有能力当前特性的算术平均值,分数从1到5,步长为0.5。这是一个纯粹的视觉指标,显示能力的初始随机特性与最佳可能特性有多接近。要提高能力的质量,您需要重置其随机特性,直到获得更好的值。", + + "tooltip.relics.relic.status.positive": "§2§l[§2§l✔§2§l]", + "tooltip.relics.relic.status.negative": "§4§l[§4§l✘§4§l]", + "tooltip.relics.relic.status.unknown": "§6§l[§6§l?§6§l]", "tooltip.relics.relic.upgrade.description": "升级", - "tooltip.relics.relic.upgrade.cost": "消耗:%1$s个技能点 %2$s,%3$s点经验 %4$s.", - "tooltip.relics.relic.upgrade.locked": "技能已达到满级。", + "tooltip.relics.relic.upgrade.cost": "成本: %1$s 升级点数 %2$s, %3$s 经验等级 %4$s。", + "tooltip.relics.relic.upgrade.locked": "该能力已达到最大等级。", + "tooltip.relics.relic.upgrade.quick":"按住 [Shift] 自动升级到最高可能等级。", - "tooltip.relics.relic.reroll.description": "重铸", - "tooltip.relics.relic.reroll.cost": "消耗:%1$s点经验 %2$s。", + "tooltip.relics.relic.reroll.description": "重置随机属性", + "tooltip.relics.relic.reroll.cost": "成本: %1$s 经验等级 %2$s。", + "tooltip.relics.relic.reroll.quick":"按住 [Shift] 自动重置随机属性到完美值。", + "tooltip.relics.relic.reroll.warning":"按住 [Shift] 确认从完美值重置随机属性到其他随机值。", - "tooltip.relics.relic.reset.description": "重置", - "tooltip.relics.relic.reset.cost": "消耗:%1$s点经验 %2$s。", - "tooltip.relics.relic.reset.locked": "使用该能力需要升级一次技能", + "tooltip.relics.relic.reset.description": "重置升级点数", + "tooltip.relics.relic.reset.cost": "成本: %1$s 经验等级 %2$s。", + "tooltip.relics.relic.reset.locked": "要使用,您需要至少升级该能力1次。", "item.relics.infinity_ham": "无限火腿", - "tooltip.relics.infinity_ham.description": "使用“再生”时增加1点经验", - "tooltip.relics.infinity_ham.ability.autophagy": "再生", - "tooltip.relics.infinity_ham.ability.autophagy.description": "使用遗物时回复使用者的饱食度。", - "tooltip.relics.infinity_ham.ability.autophagy.stat.feed.title": "饱食度:", - "tooltip.relics.infinity_ham.ability.autophagy.stat.feed.value": "%1$s点。", - "tooltip.relics.infinity_ham.ability.infusion": "炼金", - "tooltip.relics.infinity_ham.ability.infusion.description": "把药水倒在遗物上面,遗物会记录药水的效果,之后再次使用“再生”会把记录的药水效果释放给使用者。如果遗物没有充能,将失去记录的药水效果", - "tooltip.relics.infinity_ham.ability.infusion.stat.duration.title": "药水效果持续时间:", - "tooltip.relics.infinity_ham.ability.infusion.stat.duration.value": "%1$s秒。", + "tooltip.relics.infinity_ham.description": "一块神秘的肉,无论你切多少,它都会不可思议的恢复到原来的大小。", + "tooltip.relics.infinity_ham.ability.regeneration": "再生", + "tooltip.relics.infinity_ham.ability.regeneration.description": "每 %1$s 秒,最多储存6个肉块,每个恢复 %2$s 饥饿值。食用时,遗物会自动使用所需数量的肉来补充玩家的饥饿值。", + "tooltip.relics.infinity_ham.ability.marinade": "腌制", + "tooltip.relics.infinity_ham.ability.marinade.description": "允许通过在库存中左键点击药水来将药水效果应用于遗物。每次食用遗物时,这些效果会按每恢复的饥饿点持续 %1$s 秒。使用水瓶可以清除最后应用的药水效果。", + "tooltip.relics.infinity_ham.ability.meat_bat": "肉棒", + "tooltip.relics.infinity_ham.ability.meat_bat.description": "允许将遗物用作近战武器,造成 %1$s 伤害并使目标昏迷 %2$s 秒/肉块。攻击时消耗所有肉,无论目标的剩余生命值多少。", + "tooltip.relics.infinity_ham.leveling_source.regeneration.title": "再生", + "tooltip.relics.infinity_ham.leveling_source.regeneration.description": "每通过 %2$s 能力消耗的块获得 +%1$s 经验点。", + "tooltip.relics.infinity_ham.leveling_source.marinade.title": "腌制", + "tooltip.relics.infinity_ham.leveling_source.marinade.description": "每次使用 %2$s 能力应用效果于遗物时获得 +%1$s 经验点。", + "tooltip.relics.infinity_ham.leveling_source.meat_bat.title": "肉棒", + "tooltip.relics.infinity_ham.leveling_source.meat_bat.description": "每次在激活 %2$s 能力期间消耗的块获得 +%1$s 经验点。", "item.relics.enders_hand": "末影之手", - "tooltip.relics.enders_hand.description": "使用“移行换位”时增加1点经验,距离目标10格远使用技能额外增加1点经验", + "tooltip.relics.enders_hand.description": "使用 «末影置换» 能力获得 +1 经验点,使用时距离目标每10格获得 +1 经验点。", "tooltip.relics.enders_hand.ability.neutrality": "中立", - "tooltip.relics.enders_hand.ability.neutrality.description": "把末影人变为中立生物。", - "tooltip.relics.enders_hand.ability.swap": "移行换位", - "tooltip.relics.enders_hand.ability.swap.description": "将使用者和目标换位。", - "tooltip.relics.enders_hand.ability.swap.stat.distance.title": "距离:", - "tooltip.relics.enders_hand.ability.swap.stat.distance.value": "%1$s格方块。", - "tooltip.relics.enders_hand.ability.swap.predicate.target": "选择一个生物", - - "item.relics.holy_locket": "神圣吊坠", - "tooltip.relics.holy_locket.description": "“祝福”触发时增加1点经验,每治疗1点血增加1点经验。", - "tooltip.relics.holy_locket.ability.steal": "祝福", - "tooltip.relics.holy_locket.ability.steal.description": "附近的生物恢复生命时,佩戴者有概率同时恢复生命。", - "tooltip.relics.holy_locket.ability.steal.stat.amount.title": "概率:", - "tooltip.relics.holy_locket.ability.steal.stat.amount.value": "%1$s%%的概率恢复生命。", - "tooltip.relics.holy_locket.ability.steal.stat.radius.title": "范围:", - "tooltip.relics.holy_locket.ability.steal.stat.radius.value": "%1$s格方块。", - - "item.relics.magic_mirror": "魔镜", - "tooltip.relics.magic_mirror.description": "使用“虫洞”时增加1点经验,距离重生点50格方块传送时增加1点经验。", + "tooltip.relics.enders_hand.ability.neutrality.description": "使末影人对佩戴者中立。", + "tooltip.relics.enders_hand.ability.swap": "末影置换", + "tooltip.relics.enders_hand.ability.swap.description": "将佩戴者与视线中的目标交换位置。", + "tooltip.relics.enders_hand.ability.swap.stat.distance.title": "距离:", + "tooltip.relics.enders_hand.ability.swap.stat.distance.value": "%1$s 格。", + "tooltip.relics.enders_hand.ability.swap.predicate.target": "看着目标", + + "item.relics.holy_locket": "圣锁", + "tooltip.relics.holy_locket.description": "赋予佩戴者将敌人的治疗转化为伤害的能力。", + "tooltip.relics.holy_locket.ability.belief": "信仰", + "tooltip.relics.holy_locket.ability.belief.description": "一个可切换的能力,有两种模式:圣洁和不洁。在任何模式下激活能力都会填充1充能。在圣洁模式下,将佩戴者的一部分治疗转化为对附近目标的伤害,并按每个充能减少1%的受到伤害。在不洁模式下,吸收附近目标的一部分治疗并按每个充能增加1%的造成伤害。", + "tooltip.relics.holy_locket.ability.belief.stat.radius.title": "半径:", + "tooltip.relics.holy_locket.ability.belief.stat.radius.value": "%1$s 格。", + "tooltip.relics.holy_locket.ability.belief.stat.amount.title": "治疗/伤害修正:", + "tooltip.relics.holy_locket.ability.belief.stat.amount.value": "原始值的 %1$s%%。", + "tooltip.relics.holy_locket.ability.belief.stat.count.title": "最大投射物数量:", + "tooltip.relics.holy_locket.ability.belief.stat.count.value": "%1$s 单位。", + "tooltip.relics.holy_locket.ability.belief.stat.capacity.title": "缓冲区容量:", + "tooltip.relics.holy_locket.ability.belief.stat.capacity.value": "%1$s 单位。", + "tooltip.relics.holy_locket.ability.repentance": "忏悔", + "tooltip.relics.holy_locket.ability.repentance.description": "燃烧附近亡灵生物。", + "tooltip.relics.holy_locket.ability.repentance.stat.radius.title": "半径:", + "tooltip.relics.holy_locket.ability.repentance.stat.radius.value": "%1$s 格。", + "tooltip.relics.holy_locket.ability.repentance.stat.damage.title": "造成伤害:", + "tooltip.relics.holy_locket.ability.repentance.stat.damage.value": "每个充能 %1$s。", + "tooltip.relics.holy_locket.ability.blessing": "祝福", + "tooltip.relics.holy_locket.ability.blessing.description": "激活时赋予佩戴者临时无敌状态,每秒消耗遗物内部的充能。", + "tooltip.relics.holy_locket.ability.blessing.stat.consumption.title": "充能消耗:", + "tooltip.relics.holy_locket.ability.blessing.stat.consumption.value": "每秒 %1$s。", + "tooltip.relics.holy_locket.ability.blessing.predicate.blessing": "充能", + + "item.relics.magic_mirror": "魔法镜", + "tooltip.relics.magic_mirror.description": "每次使用 «虫洞» 能力获得 +1 经验点,每传送距离50格获得 +1 经验点。", "tooltip.relics.magic_mirror.ability.teleport": "虫洞", - "tooltip.relics.magic_mirror.ability.teleport.description": "将使用者传送至重生点。", - "tooltip.relics.magic_mirror.ability.teleport.stat.distance.title": "距离:", - "tooltip.relics.magic_mirror.ability.teleport.stat.distance.value": "%1$s格方块。", - "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.title": "冷却:", - "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.value": "%1$s秒。", - - "item.relics.shadow_glaive": "暗影飞刃", - "tooltip.relics.shadow_glaive.description": "当“盲正”发射出飞刃反弹时增加1点经验。", - "tooltip.relics.shadow_glaive.ability.glaive": "盲正", - "tooltip.relics.shadow_glaive.ability.glaive.description": "发射出8片刀刃中的一个,发射出的刀刃会在生物之间弹射。发射的刀刃会在一段时间后自动恢复。", - "tooltip.relics.shadow_glaive.ability.glaive.stat.damage.title": "伤害:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.damage.value": "%1$s。", - "tooltip.relics.shadow_glaive.ability.glaive.stat.recharge.title": "恢复时间:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.recharge.value": "%1$s秒。", - "tooltip.relics.shadow_glaive.ability.glaive.stat.bounces.title": "弹射次数:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.bounces.value": "%1$s。", - "tooltip.relics.shadow_glaive.ability.glaive.stat.radius.title": "弹射范围:", - "tooltip.relics.shadow_glaive.ability.glaive.stat.radius.value": "%1$s格方块", - "tooltip.relics.shadow_glaive.ability.saw": "惩戒", - "tooltip.relics.shadow_glaive.ability.saw.description": "使用时消耗全部刀刃,召唤出暗影飞刃,在范围内持续对生物造成伤害,再次使用将会把暗影飞刃收回。当该技能激活时无法自动恢复刀刃。", - "tooltip.relics.shadow_glaive.ability.saw.stat.speed.title": "攻速:", - "tooltip.relics.shadow_glaive.ability.saw.stat.speed.value": "%1$s每秒击中数", - "tooltip.relics.shadow_glaive.ability.saw.stat.damage.title": "伤害:", - "tooltip.relics.shadow_glaive.ability.saw.stat.damage.value": "%1$s点伤害", + "tooltip.relics.magic_mirror.ability.teleport.description": "使用时,将佩戴者传送到其重生点。", + "tooltip.relics.magic_mirror.ability.teleport.stat.distance.title": "距离:", + "tooltip.relics.magic_mirror.ability.teleport.stat.distance.value": "%1$s 格。", + "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.title": "冷却:", + "tooltip.relics.magic_mirror.ability.teleport.stat.cooldown.value": "%1$s 秒。", + + "item.relics.shadow_glaive": "影子长矛", + "tooltip.relics.shadow_glaive.description": "一件精心锻造的武器。如果它愿意,无论是独狼还是军团都无法抵挡它的千刀万剐。", + "tooltip.relics.shadow_glaive.ability.mayhem": "混乱", + "tooltip.relics.shadow_glaive.ability.mayhem.description": "造成伤害时有 %1$s%% 的几率触发一个在16格范围内的附近目标之间混乱弹跳的投射物,最多弹跳 %2$s 次,造成触发攻击伤害的 %3$s%%。", + "tooltip.relics.shadow_glaive.ability.cloning": "克隆", + "tooltip.relics.shadow_glaive.ability.cloning.description": "每次混乱能力的投射物弹跳时有 %1$s%% 的几率生成一个额外的相同投射物。", + "tooltip.relics.shadow_glaive.leveling_source.mayhem.title": "混乱", + "tooltip.relics.shadow_glaive.leveling_source.mayhem.description": "每次激活 %2$s 能力时获得 +%1$s 经验点。", "item.relics.arrow_quiver": "箭袋", - "tooltip.relics.arrow_quiver.description": "距离至少10格远击中生物时增加1点经验。", - "tooltip.relics.arrow_quiver.ability.receptacle": "储箭", - "tooltip.relics.arrow_quiver.ability.receptacle.description": "在背包内把箭放到箭袋里。", - "tooltip.relics.arrow_quiver.ability.receptacle.stat.slots.title": "储箭量:", - "tooltip.relics.arrow_quiver.ability.receptacle.stat.slots.value": "%1$s组。", - "tooltip.relics.arrow_quiver.ability.leap": "飞跃", - "tooltip.relics.arrow_quiver.ability.leap.description": "将玩家冲击至空中并隐身,落地解除隐身。如果在飞跃期间使用弓会将玩家暂时悬浮在空中,悬浮时增加箭矢的伤害。", - "tooltip.relics.arrow_quiver.ability.leap.stat.multiplier.title": "额外伤害:", - "tooltip.relics.arrow_quiver.ability.leap.stat.multiplier.value": "增加%1$s%%。", - "tooltip.relics.arrow_quiver.ability.leap.stat.duration.title": "持续时间:", - "tooltip.relics.arrow_quiver.ability.leap.stat.duration.value": "%1$s秒。", - "tooltip.relics.arrow_quiver.ability.leap.stat.cooldown.title": "冷却:", - "tooltip.relics.arrow_quiver.ability.leap.stat.cooldown.value": "%1$s秒。", - "tooltip.relics.arrow_quiver.ability.leap.predicate.target": "看向脚下的方块", - "tooltip.relics.arrow_quiver.ability.agility": "灵敏", - "tooltip.relics.arrow_quiver.ability.agility.description": "增加拉弓时的速度", - "tooltip.relics.arrow_quiver.ability.agility.stat.modifier.title": "速度:", + "tooltip.relics.arrow_quiver.description": "每射击命中目标时,若相距10格距离获得 +1 经验点。", + "tooltip.relics.arrow_quiver.ability.receptacle": "箭矢储存", + "tooltip.relics.arrow_quiver.ability.receptacle.description": "射击时优先使用箭袋内部储存的箭矢。在库存中按住左键点击箭袋将箭矢放入遗物的内部储存中。按住右键点击箭袋将取出最后放入的一组箭矢。", + "tooltip.relics.arrow_quiver.ability.receptacle.stat.slots.title": "箭矢槽位:", + "tooltip.relics.arrow_quiver.ability.receptacle.stat.slots.value": "%1$s 单位。", + "tooltip.relics.arrow_quiver.ability.leap": "跳跃", + "tooltip.relics.arrow_quiver.ability.leap.description": "将玩家从视线方向击退,施加消失效果直到着陆。使用弓将使玩家悬浮在空中,增加伤害并在下一次射击时取消重力。", + "tooltip.relics.arrow_quiver.ability.leap.stat.multiplier.title": "额外伤害:", + "tooltip.relics.arrow_quiver.ability.leap.stat.multiplier.value": "+%1$s%%。", + "tooltip.relics.arrow_quiver.ability.leap.stat.duration.title": "最大持续时间:", + "tooltip.relics.arrow_quiver.ability.leap.stat.duration.value": "%1$s 秒。", + "tooltip.relics.arrow_quiver.ability.leap.stat.cooldown.title": "冷却时间:", + "tooltip.relics.arrow_quiver.ability.leap.stat.cooldown.value": "%1$s 秒。", + "tooltip.relics.arrow_quiver.ability.leap.predicate.target": "看着脚下", + "tooltip.relics.arrow_quiver.ability.agility": "敏捷", + "tooltip.relics.arrow_quiver.ability.agility.description": "增加弓弦拉紧的速度。", + "tooltip.relics.arrow_quiver.ability.agility.stat.modifier.title": "速度倍增:", "tooltip.relics.arrow_quiver.ability.agility.stat.modifier.value": "%1$s%%。", - "tooltip.relics.arrow_quiver.ability.rain": "天女散花", - "tooltip.relics.arrow_quiver.ability.rain.description": "召唤一个圆形区域射下箭雨,从“储箭”技能内的箭不会消耗。该技能只能存在一个圆形区域。", - "tooltip.relics.arrow_quiver.ability.rain.stat.radius.title": "半径:", - "tooltip.relics.arrow_quiver.ability.rain.stat.radius.value": "%1$s格方块。", - "tooltip.relics.arrow_quiver.ability.rain.stat.duration.title": "区域持续时间:", - "tooltip.relics.arrow_quiver.ability.rain.stat.duration.value": "%1$s秒。", - "tooltip.relics.arrow_quiver.ability.rain.stat.delay.title": "箭矢召唤频率", - "tooltip.relics.arrow_quiver.ability.rain.stat.delay.value": "%1$s秒。", - "tooltip.relics.arrow_quiver.ability.rain.predicate.arrow": "箭袋里有箭", - - "item.relics.blazing_flask": "烈焰瓶", - "tooltip.relics.blazing_flask.description": "在“永恒真火”范围内飞行5秒增加1点经验。", - "tooltip.relics.blazing_flask.ability.bonfire": "永恒真火", - "tooltip.relics.blazing_flask.ability.bonfire.description": "对火焰使用会召唤出一个飘浮区域大小取决于火焰的数量。", - "tooltip.relics.blazing_flask.ability.bonfire.stat.step.title": "火焰半径:", - "tooltip.relics.blazing_flask.ability.bonfire.stat.step.value": "%1$s格方块", - "tooltip.relics.blazing_flask.ability.bonfire.stat.speed.title": "飘浮速度:", - "tooltip.relics.blazing_flask.ability.bonfire.stat.speed.value": "每秒%1$s格方块", - "tooltip.relics.blazing_flask.ability.bonfire.stat.height.title": "飘浮高度", - "tooltip.relics.blazing_flask.ability.bonfire.stat.height.value": "%1$s格方块", - - "item.relics.elytra_booster": "助推器", - "tooltip.relics.elytra_booster.description": "当使用“加速”在空中飞行10秒时增加1点经验。", + "tooltip.relics.arrow_quiver.ability.rain": "箭雨", + "tooltip.relics.arrow_quiver.ability.rain.description": "在视线方向的一个点召唤一个从内部箭袋储存中掉落追踪箭矢的区域。储存中的箭矢不会被消耗。一次只能存在一个此区域。", + "tooltip.relics.arrow_quiver.ability.rain.stat.radius.title": "区域半径:", + "tooltip.relics.arrow_quiver.ability.rain.stat.radius.value": "%1$s 格。", + "tooltip.relics.arrow_quiver.ability.rain.stat.duration.title": "区域持续时间:", + "tooltip.relics.arrow_quiver.ability.rain.stat.duration.value": "%1$s 秒。", + "tooltip.relics.arrow_quiver.ability.rain.stat.delay.title": "箭矢召唤频率:", + "tooltip.relics.arrow_quiver.ability.rain.stat.delay.value": "%1$s 秒。", + "tooltip.relics.arrow_quiver.ability.rain.predicate.arrow": "箭袋中的箭矢", + + "item.relics.blazing_flask": "炽热烧瓶", + "tooltip.relics.blazing_flask.description": "使用能力「永恒之火」,每5秒飞行时间获得1点经验值。", + "tooltip.relics.blazing_flask.ability.bonfire": "永恒之火", + "tooltip.relics.blazing_flask.ability.bonfire.description": "在方块上使用遗物会创建一个限制飞行区域,其大小取决于中心周围一定半径内的火焰数量。", + "tooltip.relics.blazing_flask.ability.bonfire.stat.step.title": "火焰检测半径:", + "tooltip.relics.blazing_flask.ability.bonfire.stat.step.value": "%1$s 格。", + "tooltip.relics.blazing_flask.ability.bonfire.stat.speed.title": "飞行速度:", + "tooltip.relics.blazing_flask.ability.bonfire.stat.speed.value": "%1$s 格/秒。", + "tooltip.relics.blazing_flask.ability.bonfire.stat.height.title": "飞行高度:", + "tooltip.relics.blazing_flask.ability.bonfire.stat.height.value": "%1$s 格。", + + "item.relics.elytra_booster": "鞘翅助推器", + "tooltip.relics.elytra_booster.description": "将燃料放入遗物的充能区,使用能力「加速」,每燃烧10秒燃料获得1点经验值。", "tooltip.relics.elytra_booster.ability.boost": "加速", - "tooltip.relics.elytra_booster.ability.boost.description": "在背包内把任意燃料放到内部。穿戴鞘翅飞行时使用该技能会消耗放置的燃料助推。", - "tooltip.relics.elytra_booster.ability.boost.stat.capacity.title": "燃料量:", - "tooltip.relics.elytra_booster.ability.boost.stat.capacity.value": "%1$s", - "tooltip.relics.elytra_booster.ability.boost.stat.speed.title": "速度:", - "tooltip.relics.elytra_booster.ability.boost.stat.speed.value": "每秒%1$s格方块。", - "tooltip.relics.elytra_booster.ability.boost.predicate.elytra": "正在使用鞘翅", - "tooltip.relics.elytra_booster.ability.boost.predicate.fuel": "内部含有燃料", - - "item.relics.midnight_robe": "午夜斗篷", - "tooltip.relics.midnight_robe.description": "使用“消声觅迹”每造成2次攻击增加1点经验。", - "tooltip.relics.midnight_robe.ability.vanish": "消声觅迹", - "tooltip.relics.midnight_robe.ability.vanish.description": "穿戴时进入阴影,在亮度较低时提高移速。", - "tooltip.relics.midnight_robe.ability.vanish.stat.light.title": "最低亮度:", + "tooltip.relics.elytra_booster.ability.boost.description": "在库存中对遗物使用任何燃料可补充其充能。在鞘翅飞行期间使用该能力会消耗充能,将佩戴者向前推进。", + "tooltip.relics.elytra_booster.ability.boost.stat.capacity.title": "容量:", + "tooltip.relics.elytra_booster.ability.boost.stat.capacity.value": "%1$s 单位。", + "tooltip.relics.elytra_booster.ability.boost.stat.speed.title": "速度:", + "tooltip.relics.elytra_booster.ability.boost.stat.speed.value": "%1$s 格/秒。", + "tooltip.relics.elytra_booster.ability.boost.predicate.elytra": "鞘翅飞行", + "tooltip.relics.elytra_booster.ability.boost.predicate.fuel": "助推器中的燃料", + + "item.relics.midnight_robe": "午夜长袍", + "tooltip.relics.midnight_robe.description": "当使用「消失」能力隐身攻击时,每2点伤害获得1点经验值。", + "tooltip.relics.midnight_robe.ability.vanish": "消失", + "tooltip.relics.midnight_robe.ability.vanish.description": "在光线足够低的情况下,赋予佩戴者完全隐身并增加其移动速度。", + "tooltip.relics.midnight_robe.ability.vanish.stat.light.title": "最低光照等级:", "tooltip.relics.midnight_robe.ability.vanish.stat.light.value": "%1$s。", - "tooltip.relics.midnight_robe.ability.vanish.stat.speed.title": "速度倍率:", + "tooltip.relics.midnight_robe.ability.vanish.stat.speed.title": "速度倍增:", "tooltip.relics.midnight_robe.ability.vanish.stat.speed.value": "%1$s%%。", - "tooltip.relics.midnight_robe.ability.backstab": "背刺", - "tooltip.relics.midnight_robe.ability.backstab.description": "在生物周围划出一个区域,在区域内阴影解除并将“消声觅迹”的伤害翻倍。", - "tooltip.relics.midnight_robe.ability.backstab.stat.damage.title": "伤害系数:", + "tooltip.relics.midnight_robe.ability.backstab": "背叛", + "tooltip.relics.midnight_robe.ability.backstab.description": "「消失」能力的攻击造成额外伤害,在目标周围画出一个圆圈并驱散佩戴者的隐身效果。只有在佩戴者离开圆圈后才能再次使用「消失」能力。", + "tooltip.relics.midnight_robe.ability.backstab.stat.damage.title": "伤害倍增:", "tooltip.relics.midnight_robe.ability.backstab.stat.damage.value": "%1$s%%。", - "tooltip.relics.midnight_robe.ability.backstab.stat.distance.title": "半径:", - "tooltip.relics.midnight_robe.ability.backstab.stat.distance.value": "%1$s格方块。", - - "item.relics.reflection_necklace": "弹反项链", - "tooltip.relics.reflection_necklace.description": "用“痛苦循环”造成10点伤害时增加1点经验。", - "tooltip.relics.reflection_necklace.ability.explode": "痛苦循环", - "tooltip.relics.reflection_necklace.ability.explode.description": "受到伤害时积累本次伤害,在伤害积累到极限或5秒没有受到任何伤害时,向周围发射黑曜石碎片伤害附近生物。", - "tooltip.relics.reflection_necklace.ability.explode.stat.capacity.title": "伤害积累数:", - "tooltip.relics.reflection_necklace.ability.explode.stat.capacity.value": "%1$s次。", - "tooltip.relics.reflection_necklace.ability.explode.stat.damage.title": "返还伤害:", - "tooltip.relics.reflection_necklace.ability.explode.stat.damage.value": "%1$s倍。", - "tooltip.relics.reflection_necklace.ability.explode.stat.stun.title": "眩晕时间", - "tooltip.relics.reflection_necklace.ability.explode.stat.stun.value": "%1$s秒。", + "tooltip.relics.midnight_robe.ability.backstab.stat.distance.title": "圆圈半径:", + "tooltip.relics.midnight_robe.ability.backstab.stat.distance.value": "%1$s 格。", + + "item.relics.reflection_necklace": "反射项链", + "tooltip.relics.reflection_necklace.description": "每积累10点伤害到遗物的充能时获得+1经验点。", + "tooltip.relics.reflection_necklace.ability.explode": "地狱之怒", + "tooltip.relics.reflection_necklace.ability.explode.description": "将佩戴者受到的伤害积累到遗物的充能当中。最后一次受到伤害5秒后或充能全满的情况下,遗物会爆炸,向四周抛出黑曜石碎片,造成伤害并使目标昏迷。", + "tooltip.relics.reflection_necklace.ability.explode.stat.capacity.title": "充能:", + "tooltip.relics.reflection_necklace.ability.explode.stat.capacity.value": "%1$s 单位。", + "tooltip.relics.reflection_necklace.ability.explode.stat.damage.title": "每点充能的伤害:", + "tooltip.relics.reflection_necklace.ability.explode.stat.damage.value": "%1$s 点。", + "tooltip.relics.reflection_necklace.ability.explode.stat.stun.title": "每点充能的昏迷时间:", + "tooltip.relics.reflection_necklace.ability.explode.stat.stun.value": "%1$s 秒。", "item.relics.jellyfish_necklace": "水母项链", - "tooltip.relics.jellyfish_necklace.description": "使用“电蛰”时增加1点经验。", - "tooltip.relics.jellyfish_necklace.ability.unsinkable": "波涌", - "tooltip.relics.jellyfish_necklace.ability.unsinkable.description": "穿戴时在水中不会下沉。", - "tooltip.relics.jellyfish_necklace.ability.shock": "电蛰", - "tooltip.relics.jellyfish_necklace.ability.shock.description": "触碰到生物时对它造成伤害。", - "tooltip.relics.jellyfish_necklace.ability.shock.stat.damage.title": "伤害:", - "tooltip.relics.jellyfish_necklace.ability.shock.stat.damage.value": "%1$s点。", - "tooltip.relics.jellyfish_necklace.ability.paralysis": "瘫痪", - "tooltip.relics.jellyfish_necklace.ability.paralysis.description": "使“电蛰”施加麻痹效果。", - "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration.title": "持续时间:", - "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration.value": "%1$s秒", - - "item.relics.spore_sack": "孢子囊", - "tooltip.relics.spore_sack.description": "“合毒”释放孢子时增加1点经验\n“分裂”生效时增加1点经验。", - "tooltip.relics.spore_sack.ability.spore": "合毒", - "tooltip.relics.spore_sack.ability.spore.description": "受到伤害时,向随机方向发射一个孢子,与方块接触时产生一片毒气云,在范围内的生物获得中毒、缓慢、治疗阻断效果。", - "tooltip.relics.spore_sack.ability.spore.stat.size.title": "大小:", - "tooltip.relics.spore_sack.ability.spore.stat.size.value": "每秒伤害%1$s点。", - "tooltip.relics.spore_sack.ability.spore.stat.damage.title": "伤害:", - "tooltip.relics.spore_sack.ability.spore.stat.damage.value": "每单位大小%1$s。", - "tooltip.relics.spore_sack.ability.spore.stat.cooldown.title": "冷却:", - "tooltip.relics.spore_sack.ability.spore.stat.cooldown.value": "%1$s秒", - "tooltip.relics.spore_sack.ability.spore.stat.duration.title": "持续时间:", - "tooltip.relics.spore_sack.ability.spore.stat.duration.value": "%1$s秒。", - "tooltip.relics.spore_sack.ability.buffer": "蓄毒", - "tooltip.relics.spore_sack.ability.buffer.description": "当“合毒”进入冷却时,将会积累一次能量用于给其他技能。", - "tooltip.relics.spore_sack.ability.buffer.stat.capacity.title": "容量:", - "tooltip.relics.spore_sack.ability.buffer.stat.capacity.value": "%1$s。", - "tooltip.relics.spore_sack.ability.buffer.stat.chance.title": "几率:", - "tooltip.relics.spore_sack.ability.buffer.stat.chance.value": "%1$s%%。", - "tooltip.relics.spore_sack.ability.multiplying": "分裂", - "tooltip.relics.spore_sack.ability.multiplying.description": "当孢子爆炸时会分裂出几个小孢子,小孢子数量由孢子大小决定。", - "tooltip.relics.spore_sack.ability.multiplying.stat.chance.title": "分裂几率:", - "tooltip.relics.spore_sack.ability.multiplying.stat.chance.value": "%1$s%%。", - "tooltip.relics.spore_sack.ability.multiplying.stat.size.title": "孢子大小:", - "tooltip.relics.spore_sack.ability.multiplying.stat.size.value": "%1$s%%个", - "tooltip.relics.spore_sack.ability.multiplying.stat.amount.title": "孢子大小程度", - "tooltip.relics.spore_sack.ability.multiplying.stat.amount.value": "%1$s。", - "tooltip.relics.spore_sack.ability.explosion": "释毒", - "tooltip.relics.spore_sack.ability.explosion.description": "清空所有能量,将所有的孢子放出,孢子大小由玩家失去的生命值决定。", - "tooltip.relics.spore_sack.ability.explosion.stat.size.title": "孢子大小:", - "tooltip.relics.spore_sack.ability.explosion.stat.size.value": "每秒伤害%1$s点", - "tooltip.relics.spore_sack.ability.explosion.predicate.spore": "囊袋里含有孢子", - - "item.relics.ice_breaker": "破冰靴", - "tooltip.relics.ice_breaker.description": "使用“地震”时每降落三格方块增加1点经验。", - "tooltip.relics.ice_breaker.ability.sustainability": "猛站", - "tooltip.relics.ice_breaker.ability.sustainability.description": "增加下落速度和击退抗性。", - "tooltip.relics.ice_breaker.ability.sustainability.stat.modifier.title": "击退抗性:", + "tooltip.relics.jellyfish_necklace.description": "每次激活能力「电击放电」获得 +1 经验点。", + "tooltip.relics.jellyfish_necklace.ability.unsinkable": "海洋之力", + "tooltip.relics.jellyfish_necklace.ability.unsinkable.description": "佩戴者在水中不会下沉。", + "tooltip.relics.jellyfish_necklace.ability.shock": "电击放电", + "tooltip.relics.jellyfish_necklace.ability.shock.description": "与目标碰撞时对其造成伤害。", + "tooltip.relics.jellyfish_necklace.ability.shock.stat.damage.title": "伤害:", + "tooltip.relics.jellyfish_necklace.ability.shock.stat.damage.value": "%1$s 点。", + "tooltip.relics.jellyfish_necklace.ability.paralysis": "麻痹", + "tooltip.relics.jellyfish_necklace.ability.paralysis.description": "当能力触发时,「电击放电」对目标施加麻痹效果。", + "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration.title": "效果持续时间:", + "tooltip.relics.jellyfish_necklace.ability.paralysis.stat.duration.value": "%1$s 秒。", + + "item.relics.spore_sack": "孢子袋", + "tooltip.relics.spore_sack.description": "一个装满致命瘴气的简单袋子。", + "tooltip.relics.spore_sack.ability.spore_mist": "孢子雾", + "tooltip.relics.spore_sack.ability.spore_mist.description": "当玩家的生命值下降到50%以下时,会释放最多 %1$s 个追踪孢子。这些孢子造成相当于玩家缺失生命值 %2$s%% 的伤害,并使受影响的目标在5秒内无法恢复生命值。玩家的生命值恢复到50%以上后,该能力可以再次触发。", + "tooltip.relics.spore_sack.leveling_source.spore_mist.title": "孢子雾", + "tooltip.relics.spore_sack.leveling_source.spore_mist.description": "每次 %2$s 能力的孢子成功命中时获得 +%1$s 经验点。", + + "item.relics.ice_breaker": "破冰者", + "tooltip.relics.ice_breaker.description": "每次在触发能力「地震」前下落3格获得 +1 经验点。", + "tooltip.relics.ice_breaker.ability.sustainability": "可持续性", + "tooltip.relics.ice_breaker.ability.sustainability.description": "增加下落速度,提高击退抗性。", + "tooltip.relics.ice_breaker.ability.sustainability.stat.modifier.title": "击退抗性:", "tooltip.relics.ice_breaker.ability.sustainability.stat.modifier.value": "%1$s%%。", "tooltip.relics.ice_breaker.ability.impact": "地震", - "tooltip.relics.ice_breaker.ability.impact.description": "使坠落加快并在落点产生冲击波,伤害以及击退附近的生物,冲击波的强弱由玩家的坠落的高度决定。", - "tooltip.relics.ice_breaker.ability.impact.stat.size.title": "最大半径:", - "tooltip.relics.ice_breaker.ability.impact.stat.size.value": "%1$s格方块。", - "tooltip.relics.ice_breaker.ability.impact.stat.damage.title": "最小伤害:", - "tooltip.relics.ice_breaker.ability.impact.stat.damage.value": "%1$s点伤害。", + "tooltip.relics.ice_breaker.ability.impact.description": "在下落过程中使用该能力会在着陆点产生冲击波,造成伤害并击退附近目标。冲击波的威力取决于佩戴者的下落距离。", + "tooltip.relics.ice_breaker.ability.impact.stat.size.title": "最大半径:", + "tooltip.relics.ice_breaker.ability.impact.stat.size.value": "%1$s 格。", + "tooltip.relics.ice_breaker.ability.impact.stat.damage.title": "最小伤害:", + "tooltip.relics.ice_breaker.ability.impact.stat.damage.value": "%1$s 单位。", "tooltip.relics.ice_breaker.ability.impact.predicate.falling": "自由落体", "item.relics.bastion_ring": "堡垒戒指", - "tooltip.relics.bastion_ring.description": "杀死僵尸猪灵、猪灵以及疣猪兽时增加1~10点经验。\n“尊敬”触发时增加1点经验。", - "tooltip.relics.bastion_ring.ability.compass": "外交", - "tooltip.relics.bastion_ring.ability.compass.description": "把猪灵变为中立生物,猪灵会为你指出附近堡垒遗迹的位置。", - "tooltip.relics.bastion_ring.ability.trade": "尊敬", - "tooltip.relics.bastion_ring.ability.trade.description": "与猪灵交易有50%的概率获得额外物品。", - "tooltip.relics.bastion_ring.ability.trade.stat.rolls.title": "最大交易数:", - "tooltip.relics.bastion_ring.ability.trade.stat.rolls.value": "%1$s。", + "tooltip.relics.bastion_ring.description": "每杀死一个僵尸猪灵 / 猪灵 / 猪灵蛮兵分别获得 +1/5/10 经验点。\n每次使用能力「尊重」进行额外交易获得 +1 经验点。", + "tooltip.relics.bastion_ring.ability.compass": "识别", + "tooltip.relics.bastion_ring.ability.compass.description": "使猪灵对佩戴者保持中立。最近的猪灵会指示附近堡垒的位置。", + "tooltip.relics.bastion_ring.ability.trade": "尊重", + "tooltip.relics.bastion_ring.ability.trade.description": "每次与猪灵交易时有50%的几率获得额外的交易结果。", + "tooltip.relics.bastion_ring.ability.trade.stat.rolls.title": "最大交易次数:", + "tooltip.relics.bastion_ring.ability.trade.stat.rolls.value": "%1$s 次。", "item.relics.horse_flute": "马笛", - "tooltip.relics.horse_flute.description": "骑着“千里唤马”召唤出的马,行走25格方块增加1点经验。", - "tooltip.relics.horse_flute.ability.paddock": "千里唤马", - "tooltip.relics.horse_flute.ability.paddock.description": "对马使用,将马放进马笛里,再次使用将召唤出马。如果召唤出的马与玩家的距离超过16格方块时,马将自动传送至马笛里。", - "tooltip.relics.horse_flute.ability.paddock.stat.slots.title": "栏位:", + "tooltip.relics.horse_flute.description": "每次通过能力「便携马厩」召唤的马移动25格获得 +1 经验点。", + "tooltip.relics.horse_flute.ability.paddock": "便携马厩", + "tooltip.relics.horse_flute.ability.paddock.description": "在马匹上使用遗物会将其移动到内部存储中。再次使用会释放它。如果佩戴者与召唤的马之间的距离超过16格,它会自动回到笛子中。", + "tooltip.relics.horse_flute.ability.paddock.stat.slots.title": "槽位:", "tooltip.relics.horse_flute.ability.paddock.stat.slots.value": "%1$s。", - "tooltip.relics.horse_flute.ability.heal": "治愈", - "tooltip.relics.horse_flute.ability.heal.description": "当马在马笛里时恢复生命值。", - "tooltip.relics.horse_flute.ability.heal.stat.amount.title": "恢复:", - "tooltip.relics.horse_flute.ability.heal.stat.amount.value": "每秒恢复%1$s点生命。", - - "item.relics.magma_walker": "岩浆靴", - "tooltip.relics.magma_walker.description": "“熔岩行者”过热值增加5点时增加1点经验。", - "tooltip.relics.magma_walker.ability.pace": "熔岩行者", - "tooltip.relics.magma_walker.ability.pace.description": "穿戴时可暂时在熔岩上行走,一段时间后,靴将会过热。对玩家造成伤害", - "tooltip.relics.magma_walker.ability.pace.stat.time.title": "持续时间:", - "tooltip.relics.magma_walker.ability.pace.stat.time.value": "%1$s秒。", + "tooltip.relics.horse_flute.ability.heal": "愈疗", + "tooltip.relics.horse_flute.ability.heal.description": "存储于遗物中的小马会慢慢恢复健康。", + "tooltip.relics.horse_flute.ability.heal.stat.amount.title": "治疗:", + "tooltip.relics.horse_flute.ability.heal.stat.amount.value": "每秒 %1$s 生命值单位。", + + "item.relics.magma_walker": "熔岩漫步者", + "tooltip.relics.magma_walker.description": "每次使用能力「炽热步伐」获得5单位加热值获得 +1 经验点。", + "tooltip.relics.magma_walker.ability.pace": "炽热步伐", + "tooltip.relics.magma_walker.ability.pace.description": "在一定时间内允许你在熔岩表面行走而不会掉落或受到伤害。当到达时间上限时,靴子会开始过热并对佩戴者造成与过热程度成比例的伤害。", + "tooltip.relics.magma_walker.ability.pace.stat.time.title": "持续时间:", + "tooltip.relics.magma_walker.ability.pace.stat.time.value": "%1$s 秒。", "tooltip.relics.magma_walker.ability.heat_resistance": "耐热", - "tooltip.relics.magma_walker.ability.heat_resistance.description": "免疫岩浆块的伤害。", - - "item.relics.aqua_walker": "深海靴", - "tooltip.relics.aqua_walker.description": "“潮涌”潮湿值增加5点时增加1点经验。", - "tooltip.relics.aqua_walker.ability.walking": "水上漂", - "tooltip.relics.aqua_walker.ability.walking.description": "穿戴时可暂时在水面上行者,一段时间后,靴将会潮湿,玩家将会下沉。", - "tooltip.relics.aqua_walker.ability.walking.stat.time.title": "持续时间:", - "tooltip.relics.aqua_walker.ability.walking.stat.time.value": "%1$s秒。", - - "item.relics.drowned_belt": "溺尸腰带", - "tooltip.relics.drowned_belt.description": "使用三叉戟的“激流”时获得1点经验。", - "tooltip.relics.drowned_belt.ability.slots": "附加", - "tooltip.relics.drowned_belt.ability.slots.description": "增加饰品栏。", - "tooltip.relics.drowned_belt.ability.slots.stat.talisman.title": "护符栏:", - "tooltip.relics.drowned_belt.ability.slots.stat.talisman.value": "增加%1$s个。", - "tooltip.relics.drowned_belt.ability.anchor": "沉降", - "tooltip.relics.drowned_belt.ability.anchor.description": "降低游泳速度,增加下沉速度。", - "tooltip.relics.drowned_belt.ability.anchor.stat.slowness.title": "游泳速度:", - "tooltip.relics.drowned_belt.ability.anchor.stat.slowness.value": "减少%1$s%%。", - "tooltip.relics.drowned_belt.ability.anchor.stat.sinking.title": "下沉速度:", - "tooltip.relics.drowned_belt.ability.anchor.stat.sinking.value": "增加%1$s%%。", - "tooltip.relics.drowned_belt.ability.pressure": "波动", - "tooltip.relics.drowned_belt.ability.pressure.description": "在水中时增加伤害。", - "tooltip.relics.drowned_belt.ability.pressure.stat.damage.title": "伤害系数:", - "tooltip.relics.drowned_belt.ability.pressure.stat.damage.value": "增加%1$s%%。", - "tooltip.relics.drowned_belt.ability.riptide": "引水", - "tooltip.relics.drowned_belt.ability.riptide.description": "允许你在没有雨或水的情况使用三叉戟的“激流”。增加激流的冷却时间。", - "tooltip.relics.drowned_belt.ability.riptide.stat.cooldown.title": "冷却:", - "tooltip.relics.drowned_belt.ability.riptide.stat.cooldown.value": "增加%1$s秒。", + "tooltip.relics.magma_walker.ability.heat_resistance.description": "免疫来自岩浆块的伤害。", + + "item.relics.aqua_walker": "水行者", + "tooltip.relics.aqua_walker.description": "每次使用能力「防潮」获得5单位湿润值获得 +1 经验点。", + "tooltip.relics.aqua_walker.ability.walking": "防潮", + "tooltip.relics.aqua_walker.ability.walking.description": "在一定时间内允许你在水面上行走而不会掉落。当时间到上限时,靴子会因渗水过多而开始下沉,将佩戴者拖入水下。", + "tooltip.relics.aqua_walker.ability.walking.stat.time.title": "持续时间:", + "tooltip.relics.aqua_walker.ability.walking.stat.time.value": "%1$s 秒。", + + "item.relics.drowned_belt": "溺水腰带", + "tooltip.relics.drowned_belt.description": "每次使用附魔「激流」的三叉戟时,每级附魔获得 +1 经验点。", + "tooltip.relics.drowned_belt.ability.slots": "负载能力", + "tooltip.relics.drowned_belt.ability.slots.description": "增加装备遗物的最大槽位数。", + "tooltip.relics.drowned_belt.ability.slots.stat.charm.title": "护符:", + "tooltip.relics.drowned_belt.ability.slots.stat.charm.value": "+%1$s 槽位。", + "tooltip.relics.drowned_belt.ability.anchor": "死重", + "tooltip.relics.drowned_belt.ability.anchor.description": "减少佩戴者的游泳速度并增加下沉速度。", + "tooltip.relics.drowned_belt.ability.anchor.stat.slowness.title": "游泳减速:", + "tooltip.relics.drowned_belt.ability.anchor.stat.slowness.value": "+%1$s%%。", + "tooltip.relics.drowned_belt.ability.anchor.stat.sinking.title": "下沉速度:", + "tooltip.relics.drowned_belt.ability.anchor.stat.sinking.value": "+%1$s%%。", + "tooltip.relics.drowned_belt.ability.pressure": "水流", + "tooltip.relics.drowned_belt.ability.pressure.description": "增加水下造成的伤害。", + "tooltip.relics.drowned_belt.ability.pressure.stat.damage.title": "伤害倍增:", + "tooltip.relics.drowned_belt.ability.pressure.stat.damage.value": "+%1$s%%。", + "tooltip.relics.drowned_belt.ability.riptide": "水吸引", + "tooltip.relics.drowned_belt.ability.riptide.description": "允许你在没有雨或水的情况下使用三叉戟的「激流」能力,增加其冷却时间。", + "tooltip.relics.drowned_belt.ability.riptide.stat.cooldown.title": "冷却时间:", + "tooltip.relics.drowned_belt.ability.riptide.stat.cooldown.value": "每级附魔 %1$s 秒。", "item.relics.hunter_belt": "猎人腰带", - "tooltip.relics.hunter_belt.description": "宠物攻击时增加1点经验。", - "tooltip.relics.hunter_belt.ability.slots": "附加", - "tooltip.relics.hunter_belt.ability.slots.description": "增加饰品栏。", - "tooltip.relics.hunter_belt.ability.slots.stat.talisman.title": "护符栏:", - "tooltip.relics.hunter_belt.ability.slots.stat.talisman.value": "增加%1$s个。", - "tooltip.relics.hunter_belt.ability.training": "友谊", - "tooltip.relics.hunter_belt.ability.training.description": "穿戴时增加宠物伤害。", - "tooltip.relics.hunter_belt.ability.training.stat.damage.title": "伤害系数:", - "tooltip.relics.hunter_belt.ability.training.stat.damage.value": "增加%1$s%%。", - - "item.relics.leather_belt": "皮革腰带", - "tooltip.relics.leather_belt.description": "装备护身符时获得1点经验", - "tooltip.relics.leather_belt.ability.slots": "附加", - "tooltip.relics.leather_belt.ability.slots.description": "增加饰品栏。", - "tooltip.relics.leather_belt.ability.slots.stat.talisman.title": "护符栏:", - "tooltip.relics.leather_belt.ability.slots.stat.talisman.value": "增加%1$s个。", + "tooltip.relics.hunter_belt.description": "每次佩戴者的宠物攻击时获得 +1 经验点。", + "tooltip.relics.hunter_belt.ability.slots": "负载能力", + "tooltip.relics.hunter_belt.ability.slots.description": "增加装备遗物的最大槽位数。", + "tooltip.relics.hunter_belt.ability.slots.stat.charm.title": "护符:", + "tooltip.relics.hunter_belt.ability.slots.stat.charm.value": "+%1$s 槽位。", + "tooltip.relics.hunter_belt.ability.training": "训练", + "tooltip.relics.hunter_belt.ability.training.description": "增加佩戴者宠物造成的伤害。", + "tooltip.relics.hunter_belt.ability.training.stat.damage.title": "伤害倍增:", + "tooltip.relics.hunter_belt.ability.training.stat.damage.value": "+%1$s%%。", + + "item.relics.leather_belt": "皮带", + "tooltip.relics.leather_belt.description": "每次装备的护符获得经验时获得 +1 经验点。", + "tooltip.relics.leather_belt.ability.slots": "负载能力", + "tooltip.relics.leather_belt.ability.slots.description": "增加装备遗物的最大槽位数。", + "tooltip.relics.leather_belt.ability.slots.stat.charm.title": "护符:", + "tooltip.relics.leather_belt.ability.slots.stat.charm.value": "+%1$s 槽位。", + "item.relics.rage_glove": "狂怒手套", - "tooltip.relics.rage_glove.description": "“狂暴”充能3次时增加1点经验。\n“蛮撞”每击中1个生物增加1点经验。", - "tooltip.relics.rage_glove.ability.rage": "狂暴", - "tooltip.relics.rage_glove.ability.rage.description": "攻击后的3秒内每攻击一次会充能一次,如果受到伤害,增加移动速度和伤害。", - "tooltip.relics.rage_glove.ability.rage.stat.duration.title": "持续时间:", - "tooltip.relics.rage_glove.ability.rage.stat.duration.value": "%1$s秒。", - "tooltip.relics.rage_glove.ability.rage.stat.incoming_damage.title": "受到的伤害系数:", - "tooltip.relics.rage_glove.ability.rage.stat.incoming_damage.value": "每次充能%1$s%%。", - "tooltip.relics.rage_glove.ability.rage.stat.dealt_damage.title": "伤害倍增:", - "tooltip.relics.rage_glove.ability.rage.stat.dealt_damage.value": "每次充能%1$s%%。", - "tooltip.relics.rage_glove.ability.phlebotomy": "刺骼", - "tooltip.relics.rage_glove.ability.phlebotomy.description": "穿戴时提升攻击和移速,并根据生命损失的百分比获得生命恢复。", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.heal.title": "生命恢复:", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.heal.value": "%1$s%%的概率恢复1%%。", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.movement_speed.title": "移速系数:", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.movement_speed.value": "%1$s%%的概率加成1%%。", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.attack_speed.title": "攻速系数:", - "tooltip.relics.rage_glove.ability.phlebotomy.stat.attack_speed.value": "%1$s%%的概率加成1%%。", - "tooltip.relics.rage_glove.ability.spurt": "蛮撞", - "tooltip.relics.rage_glove.ability.spurt.description": "冲向所看的方向,对经过的生物造成燃烧,流血效果。对“狂暴”的充能的比例造成额外伤害。", - "tooltip.relics.rage_glove.ability.spurt.stat.cooldown.title": "冷却:", - "tooltip.relics.rage_glove.ability.spurt.stat.cooldown.value": "%1$s秒。", - "tooltip.relics.rage_glove.ability.spurt.stat.damage.title": "处理伤害:", - "tooltip.relics.rage_glove.ability.spurt.stat.damage.value": "%1$s点。", - "tooltip.relics.rage_glove.ability.spurt.stat.distance.title": "冲刺距离:", - "tooltip.relics.rage_glove.ability.spurt.stat.distance.value": "%1$s格方块。", - - "item.relics.ice_skates": "溜冰鞋", - "tooltip.relics.ice_skates.description": "“滑冰”每滑行1秒时增加1点经验。", + "tooltip.relics.rage_glove.description": "每当「狂战士之怒」能力的充能重置时,每3个充能获得 +1 经验点。\n每次「冲刺」能力命中目标时获得 +1 经验点。", + "tooltip.relics.rage_glove.ability.rage": "狂战士之怒", + "tooltip.relics.rage_glove.ability.rage.description": "佩戴者每次攻击在上次攻击后的3秒内积累1个充能。佩戴者造成和受到的伤害以及移动速度和造成的伤害会随着积累的充能成比例增加。3秒后,充能会被清空,失去所有获得的加成。", + "tooltip.relics.rage_glove.ability.rage.stat.duration.title": "充能存在时间:", + "tooltip.relics.rage_glove.ability.rage.stat.duration.value": "%1$s 秒。", + "tooltip.relics.rage_glove.ability.rage.stat.incoming_damage.title": "受到伤害增加:", + "tooltip.relics.rage_glove.ability.rage.stat.incoming_damage.value": "每点充能 %1$s%%。", + "tooltip.relics.rage_glove.ability.rage.stat.dealt_damage.title": "造成伤害增加:", + "tooltip.relics.rage_glove.ability.rage.stat.dealt_damage.value": "每点充能 %1$s%%。", + "tooltip.relics.rage_glove.ability.phlebotomy": "放血", + "tooltip.relics.rage_glove.ability.phlebotomy.description": "增加佩戴者的攻击和移动速度,并根据已损失生命值百分比提供被动再生。", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.heal.title": "生命恢复:", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.heal.value": "每秒每1%% %1$s。", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.movement_speed.title": "移动速度倍增:", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.movement_speed.value": "每1%% %1$s%%。", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.attack_speed.title": "攻击速度倍增:", + "tooltip.relics.rage_glove.ability.phlebotomy.stat.attack_speed.value": "每1%% %1$s%%。", + "tooltip.relics.rage_glove.ability.spurt": "冲刺", + "tooltip.relics.rage_glove.ability.spurt.description": "朝视线方向冲刺,点燃敌人,施加流血效果,并用手中的物品攻击路径上的每个目标。造成的额外伤害与「狂战士之怒」能力的充能比例有关,并清空充能。", + "tooltip.relics.rage_glove.ability.spurt.stat.cooldown.title": "冷却时间:", + "tooltip.relics.rage_glove.ability.spurt.stat.cooldown.value": "%1$s 秒。", + "tooltip.relics.rage_glove.ability.spurt.stat.damage.title": "造成伤害:", + "tooltip.relics.rage_glove.ability.spurt.stat.damage.value": "每个充能 %1$s。", + "tooltip.relics.rage_glove.ability.spurt.stat.distance.title": "距离:", + "tooltip.relics.rage_glove.ability.spurt.stat.distance.value": "%1$s 格。", + + "item.relics.ice_skates": "冰刀", + "tooltip.relics.ice_skates.description": "使用能力「滑冰」,每秒加速获得1点经验值。", "tooltip.relics.ice_skates.ability.skating": "滑冰", - "tooltip.relics.ice_skates.ability.skating.description": "在冰上滑行越久速度越快。", - "tooltip.relics.ice_skates.ability.skating.stat.speed.title": "每秒速度系数:", + "tooltip.relics.ice_skates.ability.skating.description": "在冰上滑行时,根据滑行时间增加移动速度。", + "tooltip.relics.ice_skates.ability.skating.stat.speed.title": "每秒速度增加:", "tooltip.relics.ice_skates.ability.skating.stat.speed.value": "%1$s%%。", - "tooltip.relics.ice_skates.ability.skating.stat.duration.title": "持续时间:", - "tooltip.relics.ice_skates.ability.skating.stat.duration.value": "%1$s秒。", - "tooltip.relics.ice_skates.ability.ram": "猛撞", - "tooltip.relics.ice_skates.ability.ram.description": "“滑冰”撞击到生物会造成伤害。", - "tooltip.relics.ice_skates.ability.ram.stat.damage.title": "每秒伤害:", - "tooltip.relics.ice_skates.ability.ram.stat.damage.value": "%1$s点。", + "tooltip.relics.ice_skates.ability.skating.stat.duration.title": "最大持续时间:", + "tooltip.relics.ice_skates.ability.skating.stat.duration.value": "%1$s 秒。", + "tooltip.relics.ice_skates.ability.ram": "冲撞", + "tooltip.relics.ice_skates.ability.ram.description": "与目标碰撞时,根据「滑冰」能力的使用时间造成伤害。", + "tooltip.relics.ice_skates.ability.ram.stat.damage.title": "每秒伤害:", + "tooltip.relics.ice_skates.ability.ram.stat.damage.value": "%1$s 单位。", "item.relics.amphibian_boot": "两栖靴", - "tooltip.relics.amphibian_boot.description": "“蛙泳”每加速1秒时增加1点经验。", - "tooltip.relics.amphibian_boot.ability.swimming": "蛙泳", - "tooltip.relics.amphibian_boot.ability.swimming.description": "穿戴时增加游泳速度。", - "tooltip.relics.amphibian_boot.ability.swimming.stat.speed.title": "速度倍率:", - "tooltip.relics.amphibian_boot.ability.swimming.stat.speed.value": "每秒%1$s%%。", - "tooltip.relics.amphibian_boot.ability.swimming.stat.duration.title": "持续时间:", - "tooltip.relics.amphibian_boot.ability.swimming.stat.duration.value": "%1$s秒。", - - "item.relics.spatial_sign": "空间符文", - "tooltip.relics.spatial_sign.description": "“时空回溯”每回溯1秒时增加1点经验。", - "tooltip.relics.spatial_sign.ability.seal": "时空回溯", - "tooltip.relics.spatial_sign.ability.seal.description": "使用后,将玩家回溯走过的路线,回溯期间再次使用将中止回溯。", - "tooltip.relics.spatial_sign.ability.seal.stat.time.title": "持续时间:", - "tooltip.relics.spatial_sign.ability.seal.stat.time.value": "%1$s秒。", - - "item.relics.chorus_inhibitor": "控颂器", - "tooltip.relics.chorus_inhibitor.description": "“可控传送”每传送10格方块时增加1点经验。", - "tooltip.relics.chorus_inhibitor.ability.blink": "可控传送", - "tooltip.relics.chorus_inhibitor.ability.blink.description": "吃掉紫颂果时,玩家可传送到虚线的方块上。", - "tooltip.relics.chorus_inhibitor.ability.blink.stat.distance.title": "最远距离:", - "tooltip.relics.chorus_inhibitor.ability.blink.stat.distance.value": "%1$s格方块。", - "tooltip.relics.chorus_inhibitor.ability.blink.stat.cooldown.title": "冷却:", - "tooltip.relics.chorus_inhibitor.ability.blink.stat.cooldown.value": "%1$s秒", + "tooltip.relics.amphibian_boot.description": "每秒加速获得1点经验值,来自能力「鳍」和「滑行」。", + "tooltip.relics.amphibian_boot.ability.swimming": "鳍", + "tooltip.relics.amphibian_boot.ability.swimming.description": "根据游泳时间加速游泳速度。", + "tooltip.relics.amphibian_boot.ability.swimming.stat.speed.title": "速度倍增:", + "tooltip.relics.amphibian_boot.ability.swimming.stat.speed.value": "每秒 %1$s%%。", + "tooltip.relics.amphibian_boot.ability.swimming.stat.duration.title": "最大持续时间:", + "tooltip.relics.amphibian_boot.ability.swimming.stat.duration.value": "%1$s 秒。", + "tooltip.relics.amphibian_boot.ability.slipping": "滑行", + "tooltip.relics.amphibian_boot.ability.slipping.description": "在雨中根据持续时间增加移动速度。", + "tooltip.relics.amphibian_boot.ability.slipping.stat.speed.title": "每秒速度倍增:", + "tooltip.relics.amphibian_boot.ability.slipping.stat.speed.value": "%1$s%%。", + "tooltip.relics.amphibian_boot.ability.slipping.stat.duration.title": "最大持续时间:", + "tooltip.relics.amphibian_boot.ability.slipping.stat.duration.value": "%1$s 秒。", + "tooltip.relics.amphibian_boot.ability.gills": "鳃", + "tooltip.relics.amphibian_boot.ability.gills.description": "赋予玩家在水下不消耗空气的能力。", + "tooltip.relics.amphibian_boot.ability.gills.stat.chance.title": "激活几率:", + "tooltip.relics.amphibian_boot.ability.gills.stat.chance.value": "%1$s%%。", + + "item.relics.spatial_sign": "空间锚定器", + "tooltip.relics.spatial_sign.description": "使用能力「时间裂缝」返回时每秒获得+1经验点。", + "tooltip.relics.spatial_sign.ability.seal": "时间裂缝", + "tooltip.relics.spatial_sign.ability.seal.description": "使用时,在一定时间后将佩戴者沿着行进路线返回。重复使用将终止该能力。", + "tooltip.relics.spatial_sign.ability.seal.stat.time.title": "最大持续时间:", + "tooltip.relics.spatial_sign.ability.seal.stat.time.value": "%1$s 秒。", + + "item.relics.chorus_inhibitor": "紫颂果抑制器", + "tooltip.relics.chorus_inhibitor.description": "使用「传送控制」能力每传送10格获得+1经验点。", + "tooltip.relics.chorus_inhibitor.ability.blink": "传送控制", + "tooltip.relics.chorus_inhibitor.ability.blink.description": "使用紫颂果将佩戴者传送到视野内的方块。", + "tooltip.relics.chorus_inhibitor.ability.blink.stat.distance.title": "最大距离:", + "tooltip.relics.chorus_inhibitor.ability.blink.stat.distance.value": "%1$s 格。", + "tooltip.relics.chorus_inhibitor.ability.blink.stat.cooldown.title": "冷却时间:", + "tooltip.relics.chorus_inhibitor.ability.blink.stat.cooldown.value": "%1$s 秒。", "item.relics.wool_mitten": "羊毛手套", - "item.relics.solid_snowball": "冰雪球", - "tooltip.relics.wool_mitten.description": "“塑形”的冰雪球每增加5点大小并击中生物时增加1点经验。", + "item.relics.solid_snowball": "冰冻雪球", + "tooltip.relics.wool_mitten.description": "每次使用来自「塑形」能力的雪球命中目标时,每5级大小获得+1经验点。", "tooltip.relics.wool_mitten.ability.mold": "塑形", - "tooltip.relics.wool_mitten.ability.mold.description": "对雪右键可收集到冰雪球,击中生物会造成伤害和眩晕并让周围的生物被冻结。如果玩家没有装备该遗物,冰雪球将会冻结自己。", - "tooltip.relics.wool_mitten.ability.mold.stat.size.title": "最大尺寸:", - "tooltip.relics.wool_mitten.ability.mold.stat.size.value": "%1$s。", - "tooltip.relics.wool_mitten.ability.mold.stat.damage.title": "伤害:", - "tooltip.relics.wool_mitten.ability.mold.stat.damage.value": "每额外尺寸造成%1$s。", - "tooltip.relics.wool_mitten.ability.mold.stat.stun.title": "眩晕时间:", - "tooltip.relics.wool_mitten.ability.mold.stat.stun.value": "每额外尺寸造成%1$s。", - "tooltip.relics.wool_mitten.ability.mold.stat.freeze.title": "冻结", - "tooltip.relics.wool_mitten.ability.mold.stat.freeze.value": "每额外尺寸造成%1$s。", - - "item.relics.roller_skates": "轮滑靴", - "tooltip.relics.roller_skates.description": "“轮滑”每加速1秒时增加1点经验", - "tooltip.relics.roller_skates.ability.skating": "轮滑", - "tooltip.relics.roller_skates.ability.skating.description": "穿戴时所有方块都会打滑,移动时间越久速度越快。", - "tooltip.relics.roller_skates.ability.skating.stat.speed.title": "速度倍率:", + "tooltip.relics.wool_mitten.ability.mold.description": "使用空手按住右键收集雪逐渐形成特殊的冰冻雪球。击中目标会造成伤害并使其昏迷,同时冻结附近的目标。持有雪球而不装备遗物也会冻结佩戴者。", + "tooltip.relics.wool_mitten.ability.mold.stat.size.title": "最大大小:", + "tooltip.relics.wool_mitten.ability.mold.stat.size.value": "%1$s 级。", + "tooltip.relics.wool_mitten.ability.mold.stat.damage.title": "伤害:", + "tooltip.relics.wool_mitten.ability.mold.stat.damage.value": "每级大小 %1$s。", + "tooltip.relics.wool_mitten.ability.mold.stat.stun.title": "昏迷:", + "tooltip.relics.wool_mitten.ability.mold.stat.stun.value": "每级大小 %1$s 秒。", + "tooltip.relics.wool_mitten.ability.mold.stat.freeze.title": "冻伤:", + "tooltip.relics.wool_mitten.ability.mold.stat.freeze.value": "每级大小 %1$s 秒。", + + "item.relics.roller_skates": "轮滑鞋", + "tooltip.relics.roller_skates.description": "每秒加速来自能力「加速」获得+1经验点。", + "tooltip.relics.roller_skates.ability.skating": "加速", + "tooltip.relics.roller_skates.ability.skating.description": "根据朝向方向持续移动时增加移动速度。所有方块对佩戴者而言变得如同冰面。", + "tooltip.relics.roller_skates.ability.skating.stat.speed.title": "每秒速度增加:", "tooltip.relics.roller_skates.ability.skating.stat.speed.value": "%1$s%%。", - "tooltip.relics.roller_skates.ability.skating.stat.duration.title": "持续时间:", - "tooltip.relics.roller_skates.ability.skating.stat.duration.value": "%1$s秒。", + "tooltip.relics.roller_skates.ability.skating.stat.duration.title": "最大持续时间:", + "tooltip.relics.roller_skates.ability.skating.stat.duration.value": "%1$s 秒。", + + "item.relics.space_dissector": "空间", + "tooltip.relics.space_dissector.description": "每次创建相连的时空门时获得+1经验点", + "tooltip.relics.space_dissector.ability.dissection": "链接", + "tooltip.relics.space_dissector.ability.dissection.description": "按住右键在面朝方向的发光点创建一个链接点,松开右键创建第二个链接点,两个链接点会自动连结。如果有生物接触到任意一个链接点就会被传送到对应的另一个链接点。如果路径中有任何实心方块,链接将无法工作。", + "tooltip.relics.space_dissector.ability.dissection.stat.distance.title": "最大距离:", + "tooltip.relics.space_dissector.ability.dissection.stat.distance.value": "%1$s 格。", + "tooltip.relics.space_dissector.ability.dissection.stat.time.title": "持续时间:", + "tooltip.relics.space_dissector.ability.dissection.stat.time.value": "%1$s 秒", + + "item.relics.phantom_boot": "幻影靴", + "tooltip.relics.phantom_boot.description": "在遗物拥有者的脚下凝聚物质,创造一条穿越任何地形的路径,即使没有坚实的地面。", + "tooltip.relics.phantom_boot.ability.bridge": "幻影桥", + "tooltip.relics.phantom_boot.ability.bridge.description": "在玩家脚下创建一个临时的幻影桥,任何遗物拥有者都可以在上面行走。如果玩家在桥上静止超过 %1$s 秒,他们将会掉下去,直到到达地面才能重新站起来。", + "tooltip.relics.phantom_boot.leveling_source.bridge.title": "幻影桥", + "tooltip.relics.phantom_boot.leveling_source.bridge.description": "每次使用 %2$s 能力创建桥时有10%%的几率获得 +%1$s 经验点。", - "item.relics.space_dissector": "空间传送器", - "tooltip.relics.space_dissector.description": "创建传送门时增加1点经验。", - "tooltip.relics.space_dissector.ability.dissection": "穿梭", - "tooltip.relics.space_dissector.ability.dissection.description": "使用时创建一个传送门,停止使用时创建第二个传送门,当生物进入传送门时会飞跃到另一个传送门,如果传送门的路径含有实体方块,传送门失效。", - "tooltip.relics.space_dissector.ability.dissection.stat.distance.title": "最远距离:", - "tooltip.relics.space_dissector.ability.dissection.stat.distance.value": "%1$s格方块。", - "tooltip.relics.space_dissector.ability.dissection.stat.time.title": "传送门存在时间:", - "tooltip.relics.space_dissector.ability.dissection.stat.time.value": "%1$s秒。", + "item.relics.springy_boot": "弹簧靴", + "tooltip.relics.springy_boot.description": "赋予遗物拥有者特殊的弹性,使佩戴者脚底就像粘上了粘液块。", + "tooltip.relics.springy_boot.ability.bounce": "弹性", + "tooltip.relics.springy_boot.ability.bounce.description": "将所有方块的弹性增加 %1$s%%,使玩家在着陆时能够从它们上面弹跳。激活时会将玩家弹射到空中。", + "tooltip.relics.springy_boot.leveling_source.bounce.title": "弹性", + "tooltip.relics.springy_boot.leveling_source.bounce.description": "每次使用 %2$s 能力从表面弹跳时获得 +%1$s 经验点。", - "block.relics.researching_table": "研究台", + "tooltip.relics.leveling_source.generic.spreading.title": "经验传播", + "tooltip.relics.leveling_source.generic.spreading.description": "每次库存中的任何遗物获得经验,无论方法如何,此遗物也会获得 %1$s%% 的经验。", - "effect.relics.stun": "眩晕", + "item.relics.leafy_ring": "叶环 [WIP]", + "tooltip.relics.leafy_ring.description": "[WIP]", + + "item.relics.relic_experience_bottle": "遗物经验瓶", + + "block.relics.phantom_block": "幻影桥方块", + + "block.relics.researching_table": "研究桌 [已从模组中移除]", + + "effect.relics.stun": "昏迷", "effect.relics.paralysis": "麻痹", "effect.relics.confusion": "混乱", "effect.relics.vanishing": "消失", - "effect.relics.anti_heal": "抗体", + "effect.relics.anti_heal": "反治疗", "effect.relics.bleeding": "流血", - "command.relics.base.not_relic": "手上的物品必须时遗物!", + "command.relics.base.not_relic": "手中的物品必须是遗物!", + + "info.relics.researching.wrong_container": "在此库存中无法操作遗物。将物品移动到玩家的主库存中再试一次。", - "key.relics.ability_list": "显示HUD" -} + "key.relics.active_abilities_list": "显示活动能力HUD", + "key.relics.research_relic": "研究光标下的遗物" +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/block/phantom_block.json b/src/main/resources/assets/relics/models/block/phantom_block.json new file mode 100644 index 00000000..09c38e31 --- /dev/null +++ b/src/main/resources/assets/relics/models/block/phantom_block.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "relics:block/phantom_block" + }, + "render_type": "translucent" +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/camouflage_ring.json b/src/main/resources/assets/relics/models/item/camouflage_ring.json deleted file mode 100644 index 5ece33b3..00000000 --- a/src/main/resources/assets/relics/models/item/camouflage_ring.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "parent": "item/generated", - "textures": { - "layer0": "relics:item/camouflage_ring" - }, - "overrides": [ - { "predicate": { "relics:broken": 1 }, "model": "relics:item/camouflage_ring_broken" } - ] -} - diff --git a/src/main/resources/assets/relics/models/item/holy_locket.json b/src/main/resources/assets/relics/models/item/holy_locket.json index 16958bbf..3cdfbe6e 100644 --- a/src/main/resources/assets/relics/models/item/holy_locket.json +++ b/src/main/resources/assets/relics/models/item/holy_locket.json @@ -1,10 +1,10 @@ { "parent": "item/generated", "textures": { - "layer0": "relics:item/holy_locket" + "layer0": "relics:item/holy_locket_holiness" }, "overrides": [ - { "predicate": { "relics:broken": 1 }, "model": "relics:item/holy_locket_broken" } + { "predicate": { "relics:mode": 1 }, "model": "relics:item/holy_locket_holiness" }, + { "predicate": { "relics:mode": 2 }, "model": "relics:item/holy_locket_wickedness" } ] } - diff --git a/src/main/resources/assets/relics/models/item/holy_locket_broken.json b/src/main/resources/assets/relics/models/item/holy_locket_holiness.json similarity index 52% rename from src/main/resources/assets/relics/models/item/holy_locket_broken.json rename to src/main/resources/assets/relics/models/item/holy_locket_holiness.json index 9b9616cc..0aa96cbe 100644 --- a/src/main/resources/assets/relics/models/item/holy_locket_broken.json +++ b/src/main/resources/assets/relics/models/item/holy_locket_holiness.json @@ -1,7 +1,7 @@ { "parent": "item/generated", "textures": { - "layer0": "relics:item/holy_locket_broken" + "layer0": "relics:item/holy_locket_holiness" } } diff --git a/src/main/resources/assets/relics/models/item/camouflage_ring_broken.json b/src/main/resources/assets/relics/models/item/holy_locket_wickedness.json similarity index 51% rename from src/main/resources/assets/relics/models/item/camouflage_ring_broken.json rename to src/main/resources/assets/relics/models/item/holy_locket_wickedness.json index 1f1ca18d..6661efad 100644 --- a/src/main/resources/assets/relics/models/item/camouflage_ring_broken.json +++ b/src/main/resources/assets/relics/models/item/holy_locket_wickedness.json @@ -1,7 +1,7 @@ { "parent": "item/generated", "textures": { - "layer0": "relics:item/camouflage_ring_broken" + "layer0": "relics:item/holy_locket_wickedness" } } diff --git a/src/main/resources/assets/relics/models/item/infinity_ham.json b/src/main/resources/assets/relics/models/item/infinity_ham.json index b97386e2..70aaeb95 100644 --- a/src/main/resources/assets/relics/models/item/infinity_ham.json +++ b/src/main/resources/assets/relics/models/item/infinity_ham.json @@ -1,19 +1,15 @@ { "parent": "item/generated", "textures": { - "layer0": "relics:item/infinity_ham_3" + "layer0": "relics:item/infinity_ham_0" }, "overrides": [ - { "predicate": { "relics:broken": 1 }, "model": "relics:item/infinity_ham_broken" }, { "predicate": { "relics:pieces": 0 }, "model": "relics:item/infinity_ham_0" }, { "predicate": { "relics:pieces": 1 }, "model": "relics:item/infinity_ham_1" }, { "predicate": { "relics:pieces": 2 }, "model": "relics:item/infinity_ham_2" }, { "predicate": { "relics:pieces": 3 }, "model": "relics:item/infinity_ham_3" }, { "predicate": { "relics:pieces": 4 }, "model": "relics:item/infinity_ham_4" }, { "predicate": { "relics:pieces": 5 }, "model": "relics:item/infinity_ham_5" }, - { "predicate": { "relics:pieces": 6 }, "model": "relics:item/infinity_ham_6" }, - { "predicate": { "relics:pieces": 7 }, "model": "relics:item/infinity_ham_7" }, - { "predicate": { "relics:pieces": 8 }, "model": "relics:item/infinity_ham_8" }, - { "predicate": { "relics:pieces": 9 }, "model": "relics:item/infinity_ham_9" } + { "predicate": { "relics:pieces": 6 }, "model": "relics:item/infinity_ham_6" } ] } \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_0.json b/src/main/resources/assets/relics/models/item/infinity_ham_0.json index fb1b7813..f409bf6c 100644 --- a/src/main/resources/assets/relics/models/item/infinity_ham_0.json +++ b/src/main/resources/assets/relics/models/item/infinity_ham_0.json @@ -1,7 +1,21 @@ { - "parent": "item/generated", - "textures": { - "layer0": "relics:item/infinity_ham_0" + "parent": "neoforge:item/default", + "base": { + "parent": "relics:item/infinity_ham_0_3d" + }, + "textures": { + "particle": "relics:item/infinity_ham_0" + }, + "loader": "neoforge:separate_transforms", + "perspectives": { + "ground": { + "parent": "relics:item/infinity_ham_0_2d" + }, + "gui": { + "parent": "relics:item/infinity_ham_0_2d" + }, + "fixed": { + "parent": "relics:item/infinity_ham_0_2d" } -} - + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_9.json b/src/main/resources/assets/relics/models/item/infinity_ham_0_2d.json similarity index 55% rename from src/main/resources/assets/relics/models/item/infinity_ham_9.json rename to src/main/resources/assets/relics/models/item/infinity_ham_0_2d.json index 2d3cb332..fb1b7813 100644 --- a/src/main/resources/assets/relics/models/item/infinity_ham_9.json +++ b/src/main/resources/assets/relics/models/item/infinity_ham_0_2d.json @@ -1,7 +1,7 @@ { "parent": "item/generated", "textures": { - "layer0": "relics:item/infinity_ham_9" + "layer0": "relics:item/infinity_ham_0" } } diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_0_3d.json b/src/main/resources/assets/relics/models/item/infinity_ham_0_3d.json new file mode 100644 index 00000000..c14a3472 --- /dev/null +++ b/src/main/resources/assets/relics/models/item/infinity_ham_0_3d.json @@ -0,0 +1,71 @@ +{ + "credit": "Made with Blockbench", + "texture_size": [128, 128], + "textures": { + "2": "relics:item/model/infinity_ham", + "particle": "relics:item/model/infinity_ham" + }, + "elements": [ + { + "name": "bone", + "from": [7, 4, 0], + "to": [9, 6, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [1.75, 8.75, 2, 9], "texture": "#2"}, + "east": {"uv": [0, 8.75, 1.75, 9], "texture": "#2"}, + "south": {"uv": [3.75, 8.75, 4, 9], "texture": "#2"}, + "west": {"uv": [2, 8.75, 3.75, 9], "texture": "#2"}, + "up": {"uv": [2, 8.75, 1.75, 7], "texture": "#2"}, + "down": {"uv": [2.25, 7, 2, 8.75], "texture": "#2"} + } + }, + { + "name": "bone", + "from": [7, 3, 14], + "to": [9, 7, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [4.25, 8, 4.5, 8.5], "texture": "#2"}, + "east": {"uv": [4, 8, 4.25, 8.5], "texture": "#2"}, + "south": {"uv": [4.75, 8, 5, 8.5], "texture": "#2"}, + "west": {"uv": [4.5, 8, 4.75, 8.5], "texture": "#2"}, + "up": {"uv": [4.5, 8, 4.25, 7.75], "texture": "#2"}, + "down": {"uv": [4.75, 7.75, 4.5, 8], "texture": "#2"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [90, 0, 0], + "translation": [0, 4, 4.25] + }, + "thirdperson_lefthand": { + "rotation": [90, 0, 0], + "translation": [0, 4, 4.25] + }, + "firstperson_righthand": { + "rotation": [78, 22, 26], + "translation": [0.25, -1, 4], + "scale": [0.68, 0.68, 0.68] + }, + "firstperson_lefthand": { + "rotation": [78, 22, 26], + "translation": [0.25, -1, 4], + "scale": [0.68, 0.68, 0.68] + }, + "ground": { + "translation": [0, 3.5, 0], + "scale": [0.6, 0.6, 0.6] + }, + "gui": { + "rotation": [30, 130, 0], + "translation": [1, 3.5, 0], + "scale": [0.9, 0.9, 0.9] + }, + "fixed": { + "rotation": [-90, 0, 0], + "translation": [0, 0.25, -3.75] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_1.json b/src/main/resources/assets/relics/models/item/infinity_ham_1.json index 8daeea6b..d1fcf399 100644 --- a/src/main/resources/assets/relics/models/item/infinity_ham_1.json +++ b/src/main/resources/assets/relics/models/item/infinity_ham_1.json @@ -1,7 +1,21 @@ { - "parent": "item/generated", - "textures": { - "layer0": "relics:item/infinity_ham_1" + "parent": "neoforge:item/default", + "base": { + "parent": "relics:item/infinity_ham_1_3d" + }, + "textures": { + "particle": "relics:item/infinity_ham_1" + }, + "loader": "neoforge:separate_transforms", + "perspectives": { + "ground": { + "parent": "relics:item/infinity_ham_1_2d" + }, + "gui": { + "parent": "relics:item/infinity_ham_1_2d" + }, + "fixed": { + "parent": "relics:item/infinity_ham_1_2d" } -} - + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_7.json b/src/main/resources/assets/relics/models/item/infinity_ham_1_2d.json similarity index 55% rename from src/main/resources/assets/relics/models/item/infinity_ham_7.json rename to src/main/resources/assets/relics/models/item/infinity_ham_1_2d.json index 7b621f4c..8daeea6b 100644 --- a/src/main/resources/assets/relics/models/item/infinity_ham_7.json +++ b/src/main/resources/assets/relics/models/item/infinity_ham_1_2d.json @@ -1,7 +1,7 @@ { "parent": "item/generated", "textures": { - "layer0": "relics:item/infinity_ham_7" + "layer0": "relics:item/infinity_ham_1" } } diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_1_3d.json b/src/main/resources/assets/relics/models/item/infinity_ham_1_3d.json new file mode 100644 index 00000000..163d8986 --- /dev/null +++ b/src/main/resources/assets/relics/models/item/infinity_ham_1_3d.json @@ -0,0 +1,97 @@ +{ + "credit": "Made with Blockbench", + "texture_size": [128, 128], + "textures": { + "2": "relics:item/model/infinity_ham", + "particle": "relics:item/model/infinity_ham" + }, + "elements": [ + { + "name": "bone", + "from": [7, 4, 0], + "to": [9, 6, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [1.75, 8.75, 2, 9], "texture": "#2"}, + "east": {"uv": [0, 8.75, 1.75, 9], "texture": "#2"}, + "south": {"uv": [3.75, 8.75, 4, 9], "texture": "#2"}, + "west": {"uv": [2, 8.75, 3.75, 9], "texture": "#2"}, + "up": {"uv": [2, 8.75, 1.75, 7], "texture": "#2"}, + "down": {"uv": [2.25, 7, 2, 8.75], "texture": "#2"} + } + }, + { + "name": "bone", + "from": [7, 3, 14], + "to": [9, 7, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [4.25, 8, 4.5, 8.5], "texture": "#2"}, + "east": {"uv": [4, 8, 4.25, 8.5], "texture": "#2"}, + "south": {"uv": [4.75, 8, 5, 8.5], "texture": "#2"}, + "west": {"uv": [4.5, 8, 4.75, 8.5], "texture": "#2"}, + "up": {"uv": [4.5, 8, 4.25, 7.75], "texture": "#2"}, + "down": {"uv": [4.75, 7.75, 4.5, 8], "texture": "#2"} + } + }, + { + "from": [5, 2, 4.005], + "to": [11, 8, 10.005], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [7.375, 10.875, 8.125, 11.625], "texture": "#2"}, + "east": {"uv": [6.625, 10.875, 7.375, 11.625], "texture": "#2"}, + "south": {"uv": [8.875, 10.875, 9.625, 11.625], "texture": "#2"}, + "west": {"uv": [8.125, 10.875, 8.875, 11.625], "texture": "#2"}, + "up": {"uv": [8.125, 10.875, 7.375, 10.125], "texture": "#2"}, + "down": {"uv": [8.875, 10.125, 8.125, 10.875], "texture": "#2"} + } + }, + { + "from": [6, 3, 10.005], + "to": [11, 7, 12.005], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 1]}, + "faces": { + "north": {"uv": [10.5, 2.5, 11.125, 3], "texture": "#2"}, + "east": {"uv": [10.25, 2.5, 10.5, 3], "texture": "#2"}, + "south": {"uv": [11.375, 2.5, 12, 3], "texture": "#2"}, + "west": {"uv": [11.125, 2.5, 11.375, 3], "texture": "#2"}, + "up": {"uv": [11.125, 2.5, 10.5, 2.25], "texture": "#2"}, + "down": {"uv": [11.75, 2.25, 11.125, 2.5], "texture": "#2"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [90, 0, 0], + "translation": [0, 4, 4.25] + }, + "thirdperson_lefthand": { + "rotation": [90, 0, 0], + "translation": [0, 4, 4.25] + }, + "firstperson_righthand": { + "rotation": [78, 22, 26], + "translation": [0.25, -1, 4], + "scale": [0.68, 0.68, 0.68] + }, + "firstperson_lefthand": { + "rotation": [78, 22, 26], + "translation": [0.25, -1, 4], + "scale": [0.68, 0.68, 0.68] + }, + "ground": { + "translation": [0, 3.5, 0], + "scale": [0.6, 0.6, 0.6] + }, + "gui": { + "rotation": [30, 130, 0], + "translation": [1, 3.5, 0], + "scale": [0.9, 0.9, 0.9] + }, + "fixed": { + "rotation": [-90, 0, 0], + "translation": [0, 0.25, -3.75] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_2.json b/src/main/resources/assets/relics/models/item/infinity_ham_2.json index 0c4c798a..0f8335f0 100644 --- a/src/main/resources/assets/relics/models/item/infinity_ham_2.json +++ b/src/main/resources/assets/relics/models/item/infinity_ham_2.json @@ -1,7 +1,21 @@ { - "parent": "item/generated", - "textures": { - "layer0": "relics:item/infinity_ham_2" + "parent": "neoforge:item/default", + "base": { + "parent": "relics:item/infinity_ham_2_3d" + }, + "textures": { + "particle": "relics:item/infinity_ham_2" + }, + "loader": "neoforge:separate_transforms", + "perspectives": { + "ground": { + "parent": "relics:item/infinity_ham_2_2d" + }, + "gui": { + "parent": "relics:item/infinity_ham_2_2d" + }, + "fixed": { + "parent": "relics:item/infinity_ham_2_2d" } -} - + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_8.json b/src/main/resources/assets/relics/models/item/infinity_ham_2_2d.json similarity index 55% rename from src/main/resources/assets/relics/models/item/infinity_ham_8.json rename to src/main/resources/assets/relics/models/item/infinity_ham_2_2d.json index ae6a56c6..0c4c798a 100644 --- a/src/main/resources/assets/relics/models/item/infinity_ham_8.json +++ b/src/main/resources/assets/relics/models/item/infinity_ham_2_2d.json @@ -1,7 +1,7 @@ { "parent": "item/generated", "textures": { - "layer0": "relics:item/infinity_ham_8" + "layer0": "relics:item/infinity_ham_2" } } diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_2_3d.json b/src/main/resources/assets/relics/models/item/infinity_ham_2_3d.json new file mode 100644 index 00000000..40f0dc68 --- /dev/null +++ b/src/main/resources/assets/relics/models/item/infinity_ham_2_3d.json @@ -0,0 +1,97 @@ +{ + "credit": "Made with Blockbench", + "texture_size": [128, 128], + "textures": { + "2": "relics:item/model/infinity_ham", + "particle": "relics:item/model/infinity_ham" + }, + "elements": [ + { + "name": "bone", + "from": [7, 4, 0], + "to": [9, 6, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [1.75, 8.75, 2, 9], "texture": "#2"}, + "east": {"uv": [0, 8.75, 1.75, 9], "texture": "#2"}, + "south": {"uv": [3.75, 8.75, 4, 9], "texture": "#2"}, + "west": {"uv": [2, 8.75, 3.75, 9], "texture": "#2"}, + "up": {"uv": [2, 8.75, 1.75, 7], "texture": "#2"}, + "down": {"uv": [2.25, 7, 2, 8.75], "texture": "#2"} + } + }, + { + "name": "bone", + "from": [7, 3, 14], + "to": [9, 7, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [4.25, 8, 4.5, 8.5], "texture": "#2"}, + "east": {"uv": [4, 8, 4.25, 8.5], "texture": "#2"}, + "south": {"uv": [4.75, 8, 5, 8.5], "texture": "#2"}, + "west": {"uv": [4.5, 8, 4.75, 8.5], "texture": "#2"}, + "up": {"uv": [4.5, 8, 4.25, 7.75], "texture": "#2"}, + "down": {"uv": [4.75, 7.75, 4.5, 8], "texture": "#2"} + } + }, + { + "from": [5, 2, 2.005], + "to": [11, 8, 10.005], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [7.375, 6, 8.125, 6.75], "texture": "#2"}, + "east": {"uv": [6.375, 6, 7.375, 6.75], "texture": "#2"}, + "south": {"uv": [9.125, 6, 9.875, 6.75], "texture": "#2"}, + "west": {"uv": [8.125, 6, 9.125, 6.75], "texture": "#2"}, + "up": {"uv": [8.125, 6, 7.375, 5], "texture": "#2"}, + "down": {"uv": [8.875, 5, 8.125, 6], "texture": "#2"} + } + }, + { + "from": [6, 3, 10.005], + "to": [11, 7, 12.005], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 1]}, + "faces": { + "north": {"uv": [10.5, 2.5, 11.125, 3], "texture": "#2"}, + "east": {"uv": [10.25, 2.5, 10.5, 3], "texture": "#2"}, + "south": {"uv": [11.375, 2.5, 12, 3], "texture": "#2"}, + "west": {"uv": [11.125, 2.5, 11.375, 3], "texture": "#2"}, + "up": {"uv": [11.125, 2.5, 10.5, 2.25], "texture": "#2"}, + "down": {"uv": [11.75, 2.25, 11.125, 2.5], "texture": "#2"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [90, 0, 0], + "translation": [0, 4, 4.25] + }, + "thirdperson_lefthand": { + "rotation": [90, 0, 0], + "translation": [0, 4, 4.25] + }, + "firstperson_righthand": { + "rotation": [78, 22, 26], + "translation": [0.25, -1, 4], + "scale": [0.68, 0.68, 0.68] + }, + "firstperson_lefthand": { + "rotation": [78, 22, 26], + "translation": [0.25, -1, 4], + "scale": [0.68, 0.68, 0.68] + }, + "ground": { + "translation": [0, 3.5, 0], + "scale": [0.6, 0.6, 0.6] + }, + "gui": { + "rotation": [30, 130, 0], + "translation": [1, 3.5, 0], + "scale": [0.9, 0.9, 0.9] + }, + "fixed": { + "rotation": [-90, 0, 0], + "translation": [0, 0.25, -3.75] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_3.json b/src/main/resources/assets/relics/models/item/infinity_ham_3.json index 9b486ae3..a63566f0 100644 --- a/src/main/resources/assets/relics/models/item/infinity_ham_3.json +++ b/src/main/resources/assets/relics/models/item/infinity_ham_3.json @@ -1,7 +1,21 @@ { - "parent": "item/generated", - "textures": { - "layer0": "relics:item/infinity_ham_3" + "parent": "neoforge:item/default", + "base": { + "parent": "relics:item/infinity_ham_3_3d" + }, + "textures": { + "particle": "relics:item/infinity_ham_3" + }, + "loader": "neoforge:separate_transforms", + "perspectives": { + "ground": { + "parent": "relics:item/infinity_ham_3_2d" + }, + "gui": { + "parent": "relics:item/infinity_ham_3_2d" + }, + "fixed": { + "parent": "relics:item/infinity_ham_3_2d" } -} - + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/shadow_glaive_0.json b/src/main/resources/assets/relics/models/item/infinity_ham_3_2d.json similarity index 55% rename from src/main/resources/assets/relics/models/item/shadow_glaive_0.json rename to src/main/resources/assets/relics/models/item/infinity_ham_3_2d.json index dcf37c06..9b486ae3 100644 --- a/src/main/resources/assets/relics/models/item/shadow_glaive_0.json +++ b/src/main/resources/assets/relics/models/item/infinity_ham_3_2d.json @@ -1,7 +1,7 @@ { "parent": "item/generated", "textures": { - "layer0": "relics:item/shadow_glaive_0" + "layer0": "relics:item/infinity_ham_3" } } diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_3_3d.json b/src/main/resources/assets/relics/models/item/infinity_ham_3_3d.json new file mode 100644 index 00000000..79b7ef84 --- /dev/null +++ b/src/main/resources/assets/relics/models/item/infinity_ham_3_3d.json @@ -0,0 +1,97 @@ +{ + "credit": "Made with Blockbench", + "texture_size": [128, 128], + "textures": { + "2": "relics:item/model/infinity_ham", + "particle": "relics:item/model/infinity_ham" + }, + "elements": [ + { + "name": "bone", + "from": [7, 4, 0], + "to": [9, 6, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [1.75, 8.75, 2, 9], "texture": "#2"}, + "east": {"uv": [0, 8.75, 1.75, 9], "texture": "#2"}, + "south": {"uv": [3.75, 8.75, 4, 9], "texture": "#2"}, + "west": {"uv": [2, 8.75, 3.75, 9], "texture": "#2"}, + "up": {"uv": [2, 8.75, 1.75, 7], "texture": "#2"}, + "down": {"uv": [2.25, 7, 2, 8.75], "texture": "#2"} + } + }, + { + "name": "bone", + "from": [7, 3, 14], + "to": [9, 7, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [4.25, 8, 4.5, 8.5], "texture": "#2"}, + "east": {"uv": [4, 8, 4.25, 8.5], "texture": "#2"}, + "south": {"uv": [4.75, 8, 5, 8.5], "texture": "#2"}, + "west": {"uv": [4.5, 8, 4.75, 8.5], "texture": "#2"}, + "up": {"uv": [4.5, 8, 4.25, 7.75], "texture": "#2"}, + "down": {"uv": [4.75, 7.75, 4.5, 8], "texture": "#2"} + } + }, + { + "from": [4, 2, 2.005], + "to": [12, 8, 10.005], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [7.25, 1.25, 8.25, 2], "texture": "#2"}, + "east": {"uv": [6.25, 1.25, 7.25, 2], "texture": "#2"}, + "south": {"uv": [9.25, 1.25, 10.25, 2], "texture": "#2"}, + "west": {"uv": [8.25, 1.25, 9.25, 2], "texture": "#2"}, + "up": {"uv": [8.25, 1.25, 7.25, 0.25], "texture": "#2"}, + "down": {"uv": [9.25, 0.25, 8.25, 1.25], "texture": "#2"} + } + }, + { + "from": [6, 3, 10.005], + "to": [11, 7, 12.005], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 1]}, + "faces": { + "north": {"uv": [10.5, 2.5, 11.125, 3], "texture": "#2"}, + "east": {"uv": [10.25, 2.5, 10.5, 3], "texture": "#2"}, + "south": {"uv": [11.375, 2.5, 12, 3], "texture": "#2"}, + "west": {"uv": [11.125, 2.5, 11.375, 3], "texture": "#2"}, + "up": {"uv": [11.125, 2.5, 10.5, 2.25], "texture": "#2"}, + "down": {"uv": [11.75, 2.25, 11.125, 2.5], "texture": "#2"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [90, 0, 0], + "translation": [0, 4, 4.25] + }, + "thirdperson_lefthand": { + "rotation": [90, 0, 0], + "translation": [0, 4, 4.25] + }, + "firstperson_righthand": { + "rotation": [78, 22, 26], + "translation": [0.25, -1, 4], + "scale": [0.68, 0.68, 0.68] + }, + "firstperson_lefthand": { + "rotation": [78, 22, 26], + "translation": [0.25, -1, 4], + "scale": [0.68, 0.68, 0.68] + }, + "ground": { + "translation": [0, 3.5, 0], + "scale": [0.6, 0.6, 0.6] + }, + "gui": { + "rotation": [30, 130, 0], + "translation": [1, 3.5, 0], + "scale": [0.9, 0.9, 0.9] + }, + "fixed": { + "rotation": [-90, 0, 0], + "translation": [0, 0.25, -3.75] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_4.json b/src/main/resources/assets/relics/models/item/infinity_ham_4.json index 5fe0566a..91de553f 100644 --- a/src/main/resources/assets/relics/models/item/infinity_ham_4.json +++ b/src/main/resources/assets/relics/models/item/infinity_ham_4.json @@ -1,7 +1,21 @@ { - "parent": "item/generated", - "textures": { - "layer0": "relics:item/infinity_ham_4" + "parent": "neoforge:item/default", + "base": { + "parent": "relics:item/infinity_ham_4_3d" + }, + "textures": { + "particle": "relics:item/infinity_ham_4" + }, + "loader": "neoforge:separate_transforms", + "perspectives": { + "ground": { + "parent": "relics:item/infinity_ham_4_2d" + }, + "gui": { + "parent": "relics:item/infinity_ham_4_2d" + }, + "fixed": { + "parent": "relics:item/infinity_ham_4_2d" } -} - + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_4_2d.json b/src/main/resources/assets/relics/models/item/infinity_ham_4_2d.json new file mode 100644 index 00000000..5fe0566a --- /dev/null +++ b/src/main/resources/assets/relics/models/item/infinity_ham_4_2d.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "relics:item/infinity_ham_4" + } +} + diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_4_3d.json b/src/main/resources/assets/relics/models/item/infinity_ham_4_3d.json new file mode 100644 index 00000000..2968435b --- /dev/null +++ b/src/main/resources/assets/relics/models/item/infinity_ham_4_3d.json @@ -0,0 +1,97 @@ +{ + "credit": "Made with Blockbench", + "texture_size": [128, 128], + "textures": { + "2": "relics:item/model/infinity_ham", + "particle": "relics:item/model/infinity_ham" + }, + "elements": [ + { + "name": "bone", + "from": [7, 4, 0], + "to": [9, 6, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [1.75, 8.75, 2, 9], "texture": "#2"}, + "east": {"uv": [0, 8.75, 1.75, 9], "texture": "#2"}, + "south": {"uv": [3.75, 8.75, 4, 9], "texture": "#2"}, + "west": {"uv": [2, 8.75, 3.75, 9], "texture": "#2"}, + "up": {"uv": [2, 8.75, 1.75, 7], "texture": "#2"}, + "down": {"uv": [2.25, 7, 2, 8.75], "texture": "#2"} + } + }, + { + "name": "bone", + "from": [7, 3, 14], + "to": [9, 7, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [4.25, 8, 4.5, 8.5], "texture": "#2"}, + "east": {"uv": [4, 8, 4.25, 8.5], "texture": "#2"}, + "south": {"uv": [4.75, 8, 5, 8.5], "texture": "#2"}, + "west": {"uv": [4.5, 8, 4.75, 8.5], "texture": "#2"}, + "up": {"uv": [4.5, 8, 4.25, 7.75], "texture": "#2"}, + "down": {"uv": [4.75, 7.75, 4.5, 8], "texture": "#2"} + } + }, + { + "from": [4, 2, 2.005], + "to": [12, 8, 10.005], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [1.25, 10.875, 2.25, 11.625], "texture": "#2"}, + "east": {"uv": [0.25, 10.875, 1.25, 11.625], "texture": "#2"}, + "south": {"uv": [3.25, 10.875, 4.25, 11.625], "texture": "#2"}, + "west": {"uv": [2.25, 10.875, 3.25, 11.625], "texture": "#2"}, + "up": {"uv": [2.25, 10.875, 1.25, 9.875], "texture": "#2"}, + "down": {"uv": [3.25, 9.875, 2.25, 10.875], "texture": "#2"} + } + }, + { + "from": [6, 3, 10.005], + "to": [11, 7, 12.005], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 1]}, + "faces": { + "north": {"uv": [4.5, 12.125, 5.125, 12.625], "texture": "#2"}, + "east": {"uv": [4.25, 12.125, 4.5, 12.625], "texture": "#2"}, + "south": {"uv": [5.375, 12.125, 6, 12.625], "texture": "#2"}, + "west": {"uv": [5.125, 12.125, 5.375, 12.625], "texture": "#2"}, + "up": {"uv": [5.125, 12.125, 4.5, 11.875], "texture": "#2"}, + "down": {"uv": [5.75, 11.875, 5.125, 12.125], "texture": "#2"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [90, 0, 0], + "translation": [0, 4, 4.25] + }, + "thirdperson_lefthand": { + "rotation": [90, 0, 0], + "translation": [0, 4, 4.25] + }, + "firstperson_righthand": { + "rotation": [78, 22, 26], + "translation": [0.25, -1, 4], + "scale": [0.68, 0.68, 0.68] + }, + "firstperson_lefthand": { + "rotation": [78, 22, 26], + "translation": [0.25, -1, 4], + "scale": [0.68, 0.68, 0.68] + }, + "ground": { + "translation": [0, 3.5, 0], + "scale": [0.6, 0.6, 0.6] + }, + "gui": { + "rotation": [30, 130, 0], + "translation": [1, 3.5, 0], + "scale": [0.9, 0.9, 0.9] + }, + "fixed": { + "rotation": [-90, 0, 0], + "translation": [0, 0.25, -3.75] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_5.json b/src/main/resources/assets/relics/models/item/infinity_ham_5.json index 1c32db6d..be3443f4 100644 --- a/src/main/resources/assets/relics/models/item/infinity_ham_5.json +++ b/src/main/resources/assets/relics/models/item/infinity_ham_5.json @@ -1,7 +1,21 @@ { - "parent": "item/generated", - "textures": { - "layer0": "relics:item/infinity_ham_5" + "parent": "neoforge:item/default", + "base": { + "parent": "relics:item/infinity_ham_5_3d" + }, + "textures": { + "particle": "relics:item/infinity_ham_5" + }, + "loader": "neoforge:separate_transforms", + "perspectives": { + "ground": { + "parent": "relics:item/infinity_ham_5_2d" + }, + "gui": { + "parent": "relics:item/infinity_ham_5_2d" + }, + "fixed": { + "parent": "relics:item/infinity_ham_5_2d" } -} - + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_5_2d.json b/src/main/resources/assets/relics/models/item/infinity_ham_5_2d.json new file mode 100644 index 00000000..1c32db6d --- /dev/null +++ b/src/main/resources/assets/relics/models/item/infinity_ham_5_2d.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "relics:item/infinity_ham_5" + } +} + diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_5_3d.json b/src/main/resources/assets/relics/models/item/infinity_ham_5_3d.json new file mode 100644 index 00000000..10f113f3 --- /dev/null +++ b/src/main/resources/assets/relics/models/item/infinity_ham_5_3d.json @@ -0,0 +1,97 @@ +{ + "credit": "Made with Blockbench", + "texture_size": [128, 128], + "textures": { + "2": "relics:item/model/infinity_ham", + "particle": "relics:item/model/infinity_ham" + }, + "elements": [ + { + "name": "bone", + "from": [7, 4, 0], + "to": [9, 6, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [1.75, 8.75, 2, 9], "texture": "#2"}, + "east": {"uv": [0, 8.75, 1.75, 9], "texture": "#2"}, + "south": {"uv": [3.75, 8.75, 4, 9], "texture": "#2"}, + "west": {"uv": [2, 8.75, 3.75, 9], "texture": "#2"}, + "up": {"uv": [2, 8.75, 1.75, 7], "texture": "#2"}, + "down": {"uv": [2.25, 7, 2, 8.75], "texture": "#2"} + } + }, + { + "name": "bone", + "from": [7, 3, 14], + "to": [9, 7, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [4.25, 8, 4.5, 8.5], "texture": "#2"}, + "east": {"uv": [4, 8, 4.25, 8.5], "texture": "#2"}, + "south": {"uv": [4.75, 8, 5, 8.5], "texture": "#2"}, + "west": {"uv": [4.5, 8, 4.75, 8.5], "texture": "#2"}, + "up": {"uv": [4.5, 8, 4.25, 7.75], "texture": "#2"}, + "down": {"uv": [4.75, 7.75, 4.5, 8], "texture": "#2"} + } + }, + { + "from": [4, 1, 0.005], + "to": [12, 8, 10.005], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [1.25, 6, 2.25, 6.875], "texture": "#2"}, + "east": {"uv": [0, 6, 1.25, 6.875], "texture": "#2"}, + "south": {"uv": [3.5, 6, 4.5, 6.875], "texture": "#2"}, + "west": {"uv": [2.25, 6, 3.5, 6.875], "texture": "#2"}, + "up": {"uv": [2.25, 6, 1.25, 4.75], "texture": "#2"}, + "down": {"uv": [3.25, 4.75, 2.25, 6], "texture": "#2"} + } + }, + { + "from": [5, 3, 10.005], + "to": [11, 7, 12.005], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 1]}, + "faces": { + "north": {"uv": [4.25, 7.25, 5, 7.75], "texture": "#2"}, + "east": {"uv": [4, 7.25, 4.25, 7.75], "texture": "#2"}, + "south": {"uv": [5.25, 7.25, 6, 7.75], "texture": "#2"}, + "west": {"uv": [5, 7.25, 5.25, 7.75], "texture": "#2"}, + "up": {"uv": [5, 7.25, 4.25, 7], "texture": "#2"}, + "down": {"uv": [5.75, 7, 5, 7.25], "texture": "#2"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [90, 0, 0], + "translation": [0, 4, 4.25] + }, + "thirdperson_lefthand": { + "rotation": [90, 0, 0], + "translation": [0, 4, 4.25] + }, + "firstperson_righthand": { + "rotation": [78, 22, 26], + "translation": [0.25, -1, 4], + "scale": [0.68, 0.68, 0.68] + }, + "firstperson_lefthand": { + "rotation": [78, 22, 26], + "translation": [0.25, -1, 4], + "scale": [0.68, 0.68, 0.68] + }, + "ground": { + "translation": [0, 3.5, 0], + "scale": [0.6, 0.6, 0.6] + }, + "gui": { + "rotation": [30, 130, 0], + "translation": [1, 3.5, 0], + "scale": [0.9, 0.9, 0.9] + }, + "fixed": { + "rotation": [-90, 0, 0], + "translation": [0, 0.25, -3.75] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_6.json b/src/main/resources/assets/relics/models/item/infinity_ham_6.json index fffb6171..65f2532b 100644 --- a/src/main/resources/assets/relics/models/item/infinity_ham_6.json +++ b/src/main/resources/assets/relics/models/item/infinity_ham_6.json @@ -1,7 +1,21 @@ { - "parent": "item/generated", - "textures": { - "layer0": "relics:item/infinity_ham_6" + "parent": "neoforge:item/default", + "base": { + "parent": "relics:item/infinity_ham_6_3d" + }, + "textures": { + "particle": "relics:item/infinity_ham_6" + }, + "loader": "neoforge:separate_transforms", + "perspectives": { + "ground": { + "parent": "relics:item/infinity_ham_6_2d" + }, + "gui": { + "parent": "relics:item/infinity_ham_6_2d" + }, + "fixed": { + "parent": "relics:item/infinity_ham_6_2d" } -} - + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_6_2d.json b/src/main/resources/assets/relics/models/item/infinity_ham_6_2d.json new file mode 100644 index 00000000..fffb6171 --- /dev/null +++ b/src/main/resources/assets/relics/models/item/infinity_ham_6_2d.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "relics:item/infinity_ham_6" + } +} + diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_6_3d.json b/src/main/resources/assets/relics/models/item/infinity_ham_6_3d.json new file mode 100644 index 00000000..a1914fd7 --- /dev/null +++ b/src/main/resources/assets/relics/models/item/infinity_ham_6_3d.json @@ -0,0 +1,96 @@ +{ + "credit": "Made with Blockbench", + "texture_size": [128, 128], + "textures": { + "2": "relics:item/model/infinity_ham" + }, + "elements": [ + { + "from": [4, 1, 0.005], + "to": [12, 9, 10.005], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [1.25, 1.25, 2.25, 2.25], "texture": "#2"}, + "east": {"uv": [0, 1.25, 1.25, 2.25], "texture": "#2"}, + "south": {"uv": [3.5, 1.25, 4.5, 2.25], "texture": "#2"}, + "west": {"uv": [2.25, 1.25, 3.5, 2.25], "texture": "#2"}, + "up": {"uv": [2.25, 1.25, 1.25, 0], "texture": "#2"}, + "down": {"uv": [3.25, 0, 2.25, 1.25], "texture": "#2"} + } + }, + { + "name": "bone", + "from": [7, 4, 0], + "to": [9, 6, 14], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [1.75, 8.75, 2, 9], "texture": "#2"}, + "east": {"uv": [0, 8.75, 1.75, 9], "texture": "#2"}, + "south": {"uv": [3.75, 8.75, 4, 9], "texture": "#2"}, + "west": {"uv": [2, 8.75, 3.75, 9], "texture": "#2"}, + "up": {"uv": [2, 8.75, 1.75, 7], "texture": "#2"}, + "down": {"uv": [2.25, 7, 2, 8.75], "texture": "#2"} + } + }, + { + "name": "bone", + "from": [7, 3, 14], + "to": [9, 7, 16], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 0]}, + "faces": { + "north": {"uv": [4.25, 8, 4.5, 8.5], "texture": "#2"}, + "east": {"uv": [4, 8, 4.25, 8.5], "texture": "#2"}, + "south": {"uv": [4.75, 8, 5, 8.5], "texture": "#2"}, + "west": {"uv": [4.5, 8, 4.75, 8.5], "texture": "#2"}, + "up": {"uv": [4.5, 8, 4.25, 7.75], "texture": "#2"}, + "down": {"uv": [4.75, 7.75, 4.5, 8], "texture": "#2"} + } + }, + { + "from": [5, 3, 10.005], + "to": [11, 7, 12.005], + "rotation": {"angle": 0, "axis": "y", "origin": [7, 4, 1]}, + "faces": { + "north": {"uv": [4.25, 2.5, 5, 3], "texture": "#2"}, + "east": {"uv": [4, 2.5, 4.25, 3], "texture": "#2"}, + "south": {"uv": [5.25, 2.5, 6, 3], "texture": "#2"}, + "west": {"uv": [5, 2.5, 5.25, 3], "texture": "#2"}, + "up": {"uv": [5, 2.5, 4.25, 2.25], "texture": "#2"}, + "down": {"uv": [5.75, 2.25, 5, 2.5], "texture": "#2"} + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [90, 0, 0], + "translation": [0, 4, 4.25] + }, + "thirdperson_lefthand": { + "rotation": [90, 0, 0], + "translation": [0, 4, 4.25] + }, + "firstperson_righthand": { + "rotation": [78, 22, 26], + "translation": [0.25, -1, 4], + "scale": [0.68, 0.68, 0.68] + }, + "firstperson_lefthand": { + "rotation": [78, 22, 26], + "translation": [0.25, -1, 4], + "scale": [0.68, 0.68, 0.68] + }, + "ground": { + "translation": [0, 3.5, 0], + "scale": [0.6, 0.6, 0.6] + }, + "gui": { + "rotation": [30, 130, 0], + "translation": [1, 3.5, 0], + "scale": [0.9, 0.9, 0.9] + }, + "fixed": { + "rotation": [-90, 0, 0], + "translation": [0, 0.25, -3.75] + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/infinity_ham_broken.json b/src/main/resources/assets/relics/models/item/infinity_ham_broken.json deleted file mode 100644 index d3183cd7..00000000 --- a/src/main/resources/assets/relics/models/item/infinity_ham_broken.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "item/generated", - "textures": { - "layer0": "relics:item/infinity_ham_broken" - } -} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/leafy_ring.json b/src/main/resources/assets/relics/models/item/leafy_ring.json new file mode 100644 index 00000000..68da66dd --- /dev/null +++ b/src/main/resources/assets/relics/models/item/leafy_ring.json @@ -0,0 +1,7 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "relics:item/leafy_ring" + } +} + diff --git a/src/main/resources/assets/relics/models/item/phantom_block.json b/src/main/resources/assets/relics/models/item/phantom_block.json new file mode 100644 index 00000000..07586260 --- /dev/null +++ b/src/main/resources/assets/relics/models/item/phantom_block.json @@ -0,0 +1,3 @@ +{ + "parent": "relics:block/phantom_block" +} diff --git a/src/main/resources/assets/relics/models/item/phantom_boot.json b/src/main/resources/assets/relics/models/item/phantom_boot.json new file mode 100644 index 00000000..bbf8421d --- /dev/null +++ b/src/main/resources/assets/relics/models/item/phantom_boot.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "relics:item/phantom_boot" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/shadow_glaive.json b/src/main/resources/assets/relics/models/item/shadow_glaive.json index 89a4100b..974ff329 100644 --- a/src/main/resources/assets/relics/models/item/shadow_glaive.json +++ b/src/main/resources/assets/relics/models/item/shadow_glaive.json @@ -1,18 +1,6 @@ { "parent": "item/generated", "textures": { - "layer0": "relics:item/shadow_glaive_8" - }, - "overrides": [ - { "predicate": { "relics:broken": 1 }, "model": "relics:item/shadow_glaive_broken" }, - { "predicate": { "relics:charges": 0 }, "model": "relics:item/shadow_glaive_0" }, - { "predicate": { "relics:charges": 1 }, "model": "relics:item/shadow_glaive_1" }, - { "predicate": { "relics:charges": 2 }, "model": "relics:item/shadow_glaive_2" }, - { "predicate": { "relics:charges": 3 }, "model": "relics:item/shadow_glaive_3" }, - { "predicate": { "relics:charges": 4 }, "model": "relics:item/shadow_glaive_4" }, - { "predicate": { "relics:charges": 5 }, "model": "relics:item/shadow_glaive_5" }, - { "predicate": { "relics:charges": 6 }, "model": "relics:item/shadow_glaive_6" }, - { "predicate": { "relics:charges": 7 }, "model": "relics:item/shadow_glaive_7" }, - { "predicate": { "relics:charges": 8 }, "model": "relics:item/shadow_glaive_8" } - ] + "layer0": "relics:item/shadow_glaive" + } } \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/shadow_glaive_1.json b/src/main/resources/assets/relics/models/item/shadow_glaive_1.json deleted file mode 100644 index caab85c1..00000000 --- a/src/main/resources/assets/relics/models/item/shadow_glaive_1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "item/generated", - "textures": { - "layer0": "relics:item/shadow_glaive_1" - } -} - diff --git a/src/main/resources/assets/relics/models/item/shadow_glaive_2.json b/src/main/resources/assets/relics/models/item/shadow_glaive_2.json deleted file mode 100644 index c4031da3..00000000 --- a/src/main/resources/assets/relics/models/item/shadow_glaive_2.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "item/generated", - "textures": { - "layer0": "relics:item/shadow_glaive_2" - } -} - diff --git a/src/main/resources/assets/relics/models/item/shadow_glaive_3.json b/src/main/resources/assets/relics/models/item/shadow_glaive_3.json deleted file mode 100644 index ce7f314d..00000000 --- a/src/main/resources/assets/relics/models/item/shadow_glaive_3.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "item/generated", - "textures": { - "layer0": "relics:item/shadow_glaive_3" - } -} - diff --git a/src/main/resources/assets/relics/models/item/shadow_glaive_4.json b/src/main/resources/assets/relics/models/item/shadow_glaive_4.json deleted file mode 100644 index d836f700..00000000 --- a/src/main/resources/assets/relics/models/item/shadow_glaive_4.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "item/generated", - "textures": { - "layer0": "relics:item/shadow_glaive_4" - } -} - diff --git a/src/main/resources/assets/relics/models/item/shadow_glaive_5.json b/src/main/resources/assets/relics/models/item/shadow_glaive_5.json deleted file mode 100644 index f524fdc1..00000000 --- a/src/main/resources/assets/relics/models/item/shadow_glaive_5.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "item/generated", - "textures": { - "layer0": "relics:item/shadow_glaive_5" - } -} - diff --git a/src/main/resources/assets/relics/models/item/shadow_glaive_6.json b/src/main/resources/assets/relics/models/item/shadow_glaive_6.json deleted file mode 100644 index 5c4ac73d..00000000 --- a/src/main/resources/assets/relics/models/item/shadow_glaive_6.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "item/generated", - "textures": { - "layer0": "relics:item/shadow_glaive_6" - } -} - diff --git a/src/main/resources/assets/relics/models/item/shadow_glaive_7.json b/src/main/resources/assets/relics/models/item/shadow_glaive_7.json deleted file mode 100644 index 747b54aa..00000000 --- a/src/main/resources/assets/relics/models/item/shadow_glaive_7.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "item/generated", - "textures": { - "layer0": "relics:item/shadow_glaive_7" - } -} - diff --git a/src/main/resources/assets/relics/models/item/shadow_glaive_8.json b/src/main/resources/assets/relics/models/item/shadow_glaive_8.json deleted file mode 100644 index acb42ce8..00000000 --- a/src/main/resources/assets/relics/models/item/shadow_glaive_8.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "parent": "item/generated", - "textures": { - "layer0": "relics:item/shadow_glaive_8" - } -} - diff --git a/src/main/resources/assets/relics/models/item/shadow_glaive_broken.json b/src/main/resources/assets/relics/models/item/shadow_glaive_broken.json deleted file mode 100644 index 7cb17c78..00000000 --- a/src/main/resources/assets/relics/models/item/shadow_glaive_broken.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "item/generated", - "textures": { - "layer0": "relics:item/shadow_glaive_broken" - } -} \ No newline at end of file diff --git a/src/main/resources/assets/relics/models/item/springy_boot.json b/src/main/resources/assets/relics/models/item/springy_boot.json new file mode 100644 index 00000000..73278a04 --- /dev/null +++ b/src/main/resources/assets/relics/models/item/springy_boot.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "relics:item/springy_boot" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/particles/basic_colored.json b/src/main/resources/assets/relics/particles/basic_colored.json new file mode 100644 index 00000000..f8c571bf --- /dev/null +++ b/src/main/resources/assets/relics/particles/basic_colored.json @@ -0,0 +1,3 @@ +{ + "textures": [ "relics:spark", "relics:spark1" ] +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/shaders/core/reveal_panel.fsh b/src/main/resources/assets/relics/shaders/core/reveal_panel.fsh new file mode 100644 index 00000000..88aa4c32 --- /dev/null +++ b/src/main/resources/assets/relics/shaders/core/reveal_panel.fsh @@ -0,0 +1,195 @@ +#version 330 +#define PI 3.14 +#define POINT_COUNT 256 +uniform float revealRadiuses[POINT_COUNT/2]; // 0 -> 1 +uniform float noiseSpreads[POINT_COUNT/2]; +uniform float positions[POINT_COUNT]; +uniform float greenRadius; +//uniform vec4 color; +uniform vec2 size; +uniform float time; +uniform float pixelCount; +uniform vec3 col1; +uniform vec3 col2; + +uniform sampler2D Sampler0; + +in vec2 texCoord0; + +out vec4 fragColor; + + + + +float hash1(float p){ + p *= 434.0; + p = fract(p * .1031); + p *= p + 33.33; + p *= p + p; + return fract(p); +} + +const uint k = 1103515245U; + +vec3 hashwithoutsine33( uvec3 x ) +{ + x = ((x>>8U)^x.yzx)*k; + x = ((x>>8U)^x.yzx)*k; + x = ((x>>8U)^x.yzx)*k; + + return vec3(x)*(1.0/float(0xffffffffU)); +} + +vec3 generateGradientVector(float x,float y,float z){ + + return normalize((hashwithoutsine33(uvec3(x*2329.,y*1209.,z*2239.)) -0.5) * 2.); + +} + +float dotPr(float dx, float dy, float dz,float lx,float ly,float lz,float xo,float yo,float zo){ + + vec3 gradient = generateGradientVector( + dx + xo, + dy + yo, + dz + zo + ); + + vec3 toLocal = vec3( + lx - xo, + ly - yo, + lz - zo + ); + + return dot(toLocal,gradient); +} + +float fade(float t) { + return t * t * t * (t * (t * 6.0 - 15.0) + 10.0); +} + +float perlinNoise3d(float x,float y,float z,float sections){ + + x = x * sections; + y = y * sections; + z = z * sections; + + float dx = floor(x); + float dy = floor(y); + float dz = floor(z); + + float lx = fract(x); + float ly = fract(y); + float lz = fract(z); + + float val1 = dotPr(dx,dy,dz,lx,ly,lz,0.,0.,0.); + float val2 = dotPr(dx,dy,dz,lx,ly,lz,1.,0.,0.); + + float val3 = dotPr(dx,dy,dz,lx,ly,lz,0.,1.,0.); + float val4 = dotPr(dx,dy,dz,lx,ly,lz,1.,1.,0.); + + float val5 = dotPr(dx,dy,dz,lx,ly,lz,0.,0.,1.); + float val6 = dotPr(dx,dy,dz,lx,ly,lz,1.,0.,1.); + + float val7 = dotPr(dx,dy,dz,lx,ly,lz,0.,1.,1.); + float val8 = dotPr(dx,dy,dz,lx,ly,lz,1.,1.,1.); + + + lx = fade(lx); + ly = fade(ly); + lz = fade(lz); + + float val9 = mix(val1,val2,lx); + float val10 = mix(val3,val4,lx); + float val11 = mix(val5,val6,lx); + float val12 = mix(val7,val8,lx); + + float val13 = mix(val9,val10,ly); + float val14 = mix(val11,val12,ly); + + float final = mix(val13,val14,lz); + + return final; +} + + + +vec2 normalizeCoords(vec2 coord){ + float m = size.y / size.x; + coord.y = coord.y * m; + return coord; +} + + + +void main(){ + + vec2 ptc = floor(normalizeCoords(texCoord0) * pixelCount); + float dist = 1000000; + float revealRadius = 0; + vec2 point; + int pointid; + float mod; + float noisePixelSpread = 5; + + for (int i = 0; i < POINT_COUNT;i += 2){ + float x = positions[i]; + float y = positions[i + 1]; + vec2 v = vec2(x,y); + + + v = floor(normalizeCoords(v) * pixelCount); + vec2 b = ptc - v; + + float rad = revealRadiuses[i / 2]; + float nSpread = noiseSpreads[i / 2]; + + + float additionalLength = 0; + if (length(b) > 0){ + vec2 bn = normalize(b); + vec2 b1 = bn * rad; + additionalLength = perlinNoise3d(b1.x + 0.143223,b1.y + 0.143223,time + 0.22343 * i,10) * nSpread; + additionalLength = round(additionalLength); + } + + + float l = (length(b) + additionalLength) / rad; + if (l < dist){ + noisePixelSpread = nSpread; + revealRadius = rad; + dist = l; + point = v; + pointid = i; + mod = additionalLength; + } + } + + + vec2 pms = point; + + + + vec2 b = ptc - pms; + + float len = (length(b) + mod) / pixelCount; + float v = 0; + float coefficient = 0; + if (len > revealRadius){ + v = 1; + float dist = len - revealRadius; + coefficient = max(0,greenRadius - dist) / greenRadius; + } + + + vec4 color = texture(Sampler0,texCoord0); + vec4 col = color * v; + + mod = (mod / noisePixelSpread + 1) / 2; + + vec3 additiveCol = mix(col1,col2,mod); + + col.rgb += additiveCol * coefficient; + + + fragColor = col; +} diff --git a/src/main/resources/assets/relics/shaders/core/reveal_panel.json b/src/main/resources/assets/relics/shaders/core/reveal_panel.json new file mode 100644 index 00000000..0aa16992 --- /dev/null +++ b/src/main/resources/assets/relics/shaders/core/reveal_panel.json @@ -0,0 +1,56 @@ +{ + "blend": { + "func": "add", + "srcrgb": "srcalpha", + "dstrgb": "1-srcalpha" + }, + "vertex": "position_tex", + "fragment": "relics:reveal_panel", + "attributes": [ + "Position", + "UV0" + ], + "samplers": [ + { "name": "Sampler0" } + ], + "uniforms": [ + { "name": "ModelViewMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "ProjMat", "type": "matrix4x4", "count": 16, "values": [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0 ] }, + { "name": "ColorModulator", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0, 1.0 ] }, + { "name": "color", "type": "float", "count": 4, "values": [ 1.0, 1.0, 1.0 , 1.0] }, + { "name": "time", "type": "float", "count": 1, "values": [ 1.0 ] }, + { "name": "pixelCount", "type": "float", "count": 1, "values": [ 60.0 ] }, + { + "name": "positions", + "type": "float", + "count": 256, + "values": [ + -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, + -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, + -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, + -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, + + -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, + -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, + -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, + -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0, -100.0 + ] + }, + { "name": "revealRadiuses", "type": "float", "count": 128, "values": [ + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 + ] }, + { "name": "noiseSpreads", "type": "float", "count": 128, "values": [ + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 + ] }, + { "name": "greenRadius", "type": "float", "count": 1, "values": [ 0.02 ] }, + { "name": "size", "type": "float", "count": 2, "values": [ 1.0, 1.0 ] }, + { "name": "col1", "type": "float", "count": 3, "values": [ 1.0, 1.0, 1.0 ] }, + { "name": "col2", "type": "float", "count": 3, "values": [ 1.0, 1.0, 1.0 ] } + ] +} diff --git a/src/main/resources/assets/relics/sounds.json b/src/main/resources/assets/relics/sounds.json index cdf3c859..efb20bbb 100644 --- a/src/main/resources/assets/relics/sounds.json +++ b/src/main/resources/assets/relics/sounds.json @@ -46,5 +46,21 @@ "ability_cast": { "category": "master", "sounds": [ { "name": "relics:ability_cast" } ] + }, + "disconnect_stars": { + "category": "master", + "sounds": [ { "name": "relics:disconnect_stars" } ] + }, + "connect_stars": { + "category": "master", + "sounds": [ { "name": "relics:connect_stars" } ] + }, + "finish_research": { + "category": "master", + "sounds": [ { "name": "relics:finish_research" } ] + }, + "spring_boing": { + "category": "master", + "sounds": [ { "name": "relics:spring_boing" } ] } } \ No newline at end of file diff --git a/src/main/resources/assets/relics/sounds/connect_stars.ogg b/src/main/resources/assets/relics/sounds/connect_stars.ogg new file mode 100644 index 00000000..cd162c04 Binary files /dev/null and b/src/main/resources/assets/relics/sounds/connect_stars.ogg differ diff --git a/src/main/resources/assets/relics/sounds/disconnect_stars.ogg b/src/main/resources/assets/relics/sounds/disconnect_stars.ogg new file mode 100644 index 00000000..c1a07bca Binary files /dev/null and b/src/main/resources/assets/relics/sounds/disconnect_stars.ogg differ diff --git a/src/main/resources/assets/relics/sounds/finish_research.ogg b/src/main/resources/assets/relics/sounds/finish_research.ogg new file mode 100644 index 00000000..57db6ea3 Binary files /dev/null and b/src/main/resources/assets/relics/sounds/finish_research.ogg differ diff --git a/src/main/resources/assets/relics/sounds/spring_boing.ogg b/src/main/resources/assets/relics/sounds/spring_boing.ogg new file mode 100644 index 00000000..2c36ec1c Binary files /dev/null and b/src/main/resources/assets/relics/sounds/spring_boing.ogg differ diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/amphibian_boot/gills.png b/src/main/resources/assets/relics/textures/abilities/amphibian_boot/gills.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/amphibian_boot/gills.png rename to src/main/resources/assets/relics/textures/abilities/amphibian_boot/gills.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/amphibian_boot/slipping.png b/src/main/resources/assets/relics/textures/abilities/amphibian_boot/slipping.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/amphibian_boot/slipping.png rename to src/main/resources/assets/relics/textures/abilities/amphibian_boot/slipping.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/amphibian_boot/swimming.png b/src/main/resources/assets/relics/textures/abilities/amphibian_boot/swimming.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/amphibian_boot/swimming.png rename to src/main/resources/assets/relics/textures/abilities/amphibian_boot/swimming.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/aqua_walker/walking.png b/src/main/resources/assets/relics/textures/abilities/aqua_walker/walking.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/aqua_walker/walking.png rename to src/main/resources/assets/relics/textures/abilities/aqua_walker/walking.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/arrow_quiver/agility.png b/src/main/resources/assets/relics/textures/abilities/arrow_quiver/agility.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/arrow_quiver/agility.png rename to src/main/resources/assets/relics/textures/abilities/arrow_quiver/agility.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/arrow_quiver/leap.png b/src/main/resources/assets/relics/textures/abilities/arrow_quiver/leap.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/arrow_quiver/leap.png rename to src/main/resources/assets/relics/textures/abilities/arrow_quiver/leap.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/arrow_quiver/rain.png b/src/main/resources/assets/relics/textures/abilities/arrow_quiver/rain.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/arrow_quiver/rain.png rename to src/main/resources/assets/relics/textures/abilities/arrow_quiver/rain.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/arrow_quiver/receptacle.png b/src/main/resources/assets/relics/textures/abilities/arrow_quiver/receptacle.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/arrow_quiver/receptacle.png rename to src/main/resources/assets/relics/textures/abilities/arrow_quiver/receptacle.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/bastion_ring/compass.png b/src/main/resources/assets/relics/textures/abilities/bastion_ring/compass.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/bastion_ring/compass.png rename to src/main/resources/assets/relics/textures/abilities/bastion_ring/compass.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/bastion_ring/trade.png b/src/main/resources/assets/relics/textures/abilities/bastion_ring/trade.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/bastion_ring/trade.png rename to src/main/resources/assets/relics/textures/abilities/bastion_ring/trade.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/blazing_flask/bonfire.png b/src/main/resources/assets/relics/textures/abilities/blazing_flask/bonfire.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/blazing_flask/bonfire.png rename to src/main/resources/assets/relics/textures/abilities/blazing_flask/bonfire.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/chorus_inhibitor/blink.png b/src/main/resources/assets/relics/textures/abilities/chorus_inhibitor/blink.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/chorus_inhibitor/blink.png rename to src/main/resources/assets/relics/textures/abilities/chorus_inhibitor/blink.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/drowned_belt/anchor.png b/src/main/resources/assets/relics/textures/abilities/drowned_belt/anchor.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/drowned_belt/anchor.png rename to src/main/resources/assets/relics/textures/abilities/drowned_belt/anchor.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/drowned_belt/pressure.png b/src/main/resources/assets/relics/textures/abilities/drowned_belt/pressure.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/drowned_belt/pressure.png rename to src/main/resources/assets/relics/textures/abilities/drowned_belt/pressure.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/drowned_belt/riptide.png b/src/main/resources/assets/relics/textures/abilities/drowned_belt/riptide.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/drowned_belt/riptide.png rename to src/main/resources/assets/relics/textures/abilities/drowned_belt/riptide.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/drowned_belt/slots.png b/src/main/resources/assets/relics/textures/abilities/drowned_belt/slots.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/drowned_belt/slots.png rename to src/main/resources/assets/relics/textures/abilities/drowned_belt/slots.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/elytra_booster/boost.png b/src/main/resources/assets/relics/textures/abilities/elytra_booster/boost.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/elytra_booster/boost.png rename to src/main/resources/assets/relics/textures/abilities/elytra_booster/boost.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/enders_hand/neutrality.png b/src/main/resources/assets/relics/textures/abilities/enders_hand/neutrality.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/enders_hand/neutrality.png rename to src/main/resources/assets/relics/textures/abilities/enders_hand/neutrality.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/enders_hand/swap.png b/src/main/resources/assets/relics/textures/abilities/enders_hand/swap.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/enders_hand/swap.png rename to src/main/resources/assets/relics/textures/abilities/enders_hand/swap.png diff --git a/src/main/resources/assets/relics/textures/abilities/holy_locket/ascension.png b/src/main/resources/assets/relics/textures/abilities/holy_locket/ascension.png new file mode 100644 index 00000000..556db7ea Binary files /dev/null and b/src/main/resources/assets/relics/textures/abilities/holy_locket/ascension.png differ diff --git a/src/main/resources/assets/relics/textures/abilities/holy_locket/faith_holiness.png b/src/main/resources/assets/relics/textures/abilities/holy_locket/faith_holiness.png new file mode 100644 index 00000000..8f876d0c Binary files /dev/null and b/src/main/resources/assets/relics/textures/abilities/holy_locket/faith_holiness.png differ diff --git a/src/main/resources/assets/relics/textures/abilities/holy_locket/faith_wickedness.png b/src/main/resources/assets/relics/textures/abilities/holy_locket/faith_wickedness.png new file mode 100644 index 00000000..3188e770 Binary files /dev/null and b/src/main/resources/assets/relics/textures/abilities/holy_locket/faith_wickedness.png differ diff --git a/src/main/resources/assets/relics/textures/abilities/holy_locket/penitence.png b/src/main/resources/assets/relics/textures/abilities/holy_locket/penitence.png new file mode 100644 index 00000000..d215cf88 Binary files /dev/null and b/src/main/resources/assets/relics/textures/abilities/holy_locket/penitence.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/horse_flute/heal.png b/src/main/resources/assets/relics/textures/abilities/horse_flute/heal.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/horse_flute/heal.png rename to src/main/resources/assets/relics/textures/abilities/horse_flute/heal.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/horse_flute/paddock.png b/src/main/resources/assets/relics/textures/abilities/horse_flute/paddock.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/horse_flute/paddock.png rename to src/main/resources/assets/relics/textures/abilities/horse_flute/paddock.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/hunter_belt/slots.png b/src/main/resources/assets/relics/textures/abilities/hunter_belt/slots.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/hunter_belt/slots.png rename to src/main/resources/assets/relics/textures/abilities/hunter_belt/slots.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/hunter_belt/training.png b/src/main/resources/assets/relics/textures/abilities/hunter_belt/training.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/hunter_belt/training.png rename to src/main/resources/assets/relics/textures/abilities/hunter_belt/training.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/ice_breaker/impact.png b/src/main/resources/assets/relics/textures/abilities/ice_breaker/impact.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/ice_breaker/impact.png rename to src/main/resources/assets/relics/textures/abilities/ice_breaker/impact.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/ice_breaker/sustainability.png b/src/main/resources/assets/relics/textures/abilities/ice_breaker/sustainability.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/ice_breaker/sustainability.png rename to src/main/resources/assets/relics/textures/abilities/ice_breaker/sustainability.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/ice_skates/ram.png b/src/main/resources/assets/relics/textures/abilities/ice_skates/ram.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/ice_skates/ram.png rename to src/main/resources/assets/relics/textures/abilities/ice_skates/ram.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/ice_skates/skating.png b/src/main/resources/assets/relics/textures/abilities/ice_skates/skating.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/ice_skates/skating.png rename to src/main/resources/assets/relics/textures/abilities/ice_skates/skating.png diff --git a/src/main/resources/assets/relics/textures/abilities/infinity_ham/marinade.png b/src/main/resources/assets/relics/textures/abilities/infinity_ham/marinade.png new file mode 100644 index 00000000..68c9f588 Binary files /dev/null and b/src/main/resources/assets/relics/textures/abilities/infinity_ham/marinade.png differ diff --git a/src/main/resources/assets/relics/textures/abilities/infinity_ham/meat_bat.png b/src/main/resources/assets/relics/textures/abilities/infinity_ham/meat_bat.png new file mode 100644 index 00000000..e21822f3 Binary files /dev/null and b/src/main/resources/assets/relics/textures/abilities/infinity_ham/meat_bat.png differ diff --git a/src/main/resources/assets/relics/textures/abilities/infinity_ham/regeneration.png b/src/main/resources/assets/relics/textures/abilities/infinity_ham/regeneration.png new file mode 100644 index 00000000..5e6c8c30 Binary files /dev/null and b/src/main/resources/assets/relics/textures/abilities/infinity_ham/regeneration.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/jellyfish_necklace/paralysis.png b/src/main/resources/assets/relics/textures/abilities/jellyfish_necklace/paralysis.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/jellyfish_necklace/paralysis.png rename to src/main/resources/assets/relics/textures/abilities/jellyfish_necklace/paralysis.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/jellyfish_necklace/shock.png b/src/main/resources/assets/relics/textures/abilities/jellyfish_necklace/shock.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/jellyfish_necklace/shock.png rename to src/main/resources/assets/relics/textures/abilities/jellyfish_necklace/shock.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/jellyfish_necklace/unsinkable.png b/src/main/resources/assets/relics/textures/abilities/jellyfish_necklace/unsinkable.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/jellyfish_necklace/unsinkable.png rename to src/main/resources/assets/relics/textures/abilities/jellyfish_necklace/unsinkable.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/leather_belt/slots.png b/src/main/resources/assets/relics/textures/abilities/leather_belt/slots.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/leather_belt/slots.png rename to src/main/resources/assets/relics/textures/abilities/leather_belt/slots.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/magic_mirror/teleport.png b/src/main/resources/assets/relics/textures/abilities/magic_mirror/teleport.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/magic_mirror/teleport.png rename to src/main/resources/assets/relics/textures/abilities/magic_mirror/teleport.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/magma_walker/heat_resistance.png b/src/main/resources/assets/relics/textures/abilities/magma_walker/heat_resistance.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/magma_walker/heat_resistance.png rename to src/main/resources/assets/relics/textures/abilities/magma_walker/heat_resistance.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/magma_walker/pace.png b/src/main/resources/assets/relics/textures/abilities/magma_walker/pace.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/magma_walker/pace.png rename to src/main/resources/assets/relics/textures/abilities/magma_walker/pace.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/midnight_robe/backstab.png b/src/main/resources/assets/relics/textures/abilities/midnight_robe/backstab.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/midnight_robe/backstab.png rename to src/main/resources/assets/relics/textures/abilities/midnight_robe/backstab.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/midnight_robe/vanish.png b/src/main/resources/assets/relics/textures/abilities/midnight_robe/vanish.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/midnight_robe/vanish.png rename to src/main/resources/assets/relics/textures/abilities/midnight_robe/vanish.png diff --git a/src/main/resources/assets/relics/textures/abilities/missing.png b/src/main/resources/assets/relics/textures/abilities/missing.png new file mode 100644 index 00000000..20e408dd Binary files /dev/null and b/src/main/resources/assets/relics/textures/abilities/missing.png differ diff --git a/src/main/resources/assets/relics/textures/abilities/phantom_boot/bridge.png b/src/main/resources/assets/relics/textures/abilities/phantom_boot/bridge.png new file mode 100644 index 00000000..9328c171 Binary files /dev/null and b/src/main/resources/assets/relics/textures/abilities/phantom_boot/bridge.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/rage_glove/phlebotomy.png b/src/main/resources/assets/relics/textures/abilities/rage_glove/phlebotomy.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/rage_glove/phlebotomy.png rename to src/main/resources/assets/relics/textures/abilities/rage_glove/phlebotomy.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/rage_glove/rage.png b/src/main/resources/assets/relics/textures/abilities/rage_glove/rage.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/rage_glove/rage.png rename to src/main/resources/assets/relics/textures/abilities/rage_glove/rage.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/rage_glove/spurt.png b/src/main/resources/assets/relics/textures/abilities/rage_glove/spurt.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/rage_glove/spurt.png rename to src/main/resources/assets/relics/textures/abilities/rage_glove/spurt.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/reflection_necklace/explode.png b/src/main/resources/assets/relics/textures/abilities/reflection_necklace/explode.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/reflection_necklace/explode.png rename to src/main/resources/assets/relics/textures/abilities/reflection_necklace/explode.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/roller_skates/skating.png b/src/main/resources/assets/relics/textures/abilities/roller_skates/skating.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/roller_skates/skating.png rename to src/main/resources/assets/relics/textures/abilities/roller_skates/skating.png diff --git a/src/main/resources/assets/relics/textures/abilities/shadow_glaive/cloning.png b/src/main/resources/assets/relics/textures/abilities/shadow_glaive/cloning.png new file mode 100644 index 00000000..ad5f3d95 Binary files /dev/null and b/src/main/resources/assets/relics/textures/abilities/shadow_glaive/cloning.png differ diff --git a/src/main/resources/assets/relics/textures/abilities/shadow_glaive/mayhem.png b/src/main/resources/assets/relics/textures/abilities/shadow_glaive/mayhem.png new file mode 100644 index 00000000..03e74770 Binary files /dev/null and b/src/main/resources/assets/relics/textures/abilities/shadow_glaive/mayhem.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/space_dissector/dissection.png b/src/main/resources/assets/relics/textures/abilities/space_dissector/dissection.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/space_dissector/dissection.png rename to src/main/resources/assets/relics/textures/abilities/space_dissector/dissection.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/spatial_sign/seal.png b/src/main/resources/assets/relics/textures/abilities/spatial_sign/seal.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/spatial_sign/seal.png rename to src/main/resources/assets/relics/textures/abilities/spatial_sign/seal.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/spore_sack/buffer.png b/src/main/resources/assets/relics/textures/abilities/spore_sack/buffer.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/spore_sack/buffer.png rename to src/main/resources/assets/relics/textures/abilities/spore_sack/buffer.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/spore_sack/explosion.png b/src/main/resources/assets/relics/textures/abilities/spore_sack/explosion.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/spore_sack/explosion.png rename to src/main/resources/assets/relics/textures/abilities/spore_sack/explosion.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/spore_sack/multiplying.png b/src/main/resources/assets/relics/textures/abilities/spore_sack/multiplying.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/spore_sack/multiplying.png rename to src/main/resources/assets/relics/textures/abilities/spore_sack/multiplying.png diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/spore_sack/spore.png b/src/main/resources/assets/relics/textures/abilities/spore_sack/spore.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/spore_sack/spore.png rename to src/main/resources/assets/relics/textures/abilities/spore_sack/spore.png diff --git a/src/main/resources/assets/relics/textures/abilities/springy_boot/bounce.png b/src/main/resources/assets/relics/textures/abilities/springy_boot/bounce.png new file mode 100644 index 00000000..72423f20 Binary files /dev/null and b/src/main/resources/assets/relics/textures/abilities/springy_boot/bounce.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/wool_mitten/mold.png b/src/main/resources/assets/relics/textures/abilities/wool_mitten/mold.png similarity index 100% rename from src/main/resources/assets/relics/textures/gui/description/cards/wool_mitten/mold.png rename to src/main/resources/assets/relics/textures/abilities/wool_mitten/mold.png diff --git a/src/main/resources/assets/relics/textures/block/phantom_block.png b/src/main/resources/assets/relics/textures/block/phantom_block.png new file mode 100644 index 00000000..0c2675db Binary files /dev/null and b/src/main/resources/assets/relics/textures/block/phantom_block.png differ diff --git a/src/main/resources/assets/relics/textures/entities/life_essence.png b/src/main/resources/assets/relics/textures/entities/life_essence.png new file mode 100644 index 00000000..a53e17be Binary files /dev/null and b/src/main/resources/assets/relics/textures/entities/life_essence.png differ diff --git a/src/main/resources/assets/relics/textures/entities/shadow_glaive.png b/src/main/resources/assets/relics/textures/entities/shadow_glaive.png index 37390cf7..e2dd4258 100644 Binary files a/src/main/resources/assets/relics/textures/entities/shadow_glaive.png and b/src/main/resources/assets/relics/textures/entities/shadow_glaive.png differ diff --git a/src/main/resources/assets/relics/textures/entities/shadow_saw.png b/src/main/resources/assets/relics/textures/entities/shadow_saw.png deleted file mode 100644 index e23c902c..00000000 Binary files a/src/main/resources/assets/relics/textures/entities/shadow_saw.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/ability/action_button_outline.png b/src/main/resources/assets/relics/textures/gui/description/ability/action_button_outline.png new file mode 100644 index 00000000..c0e3342f Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/ability/action_button_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/ability/reroll_button_active.png b/src/main/resources/assets/relics/textures/gui/description/ability/reroll_button_active.png new file mode 100644 index 00000000..b2424ab8 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/ability/reroll_button_active.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/ability/reroll_button_active_quick.png b/src/main/resources/assets/relics/textures/gui/description/ability/reroll_button_active_quick.png new file mode 100644 index 00000000..5463b3b5 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/ability/reroll_button_active_quick.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/ability/reroll_button_active_warning.png b/src/main/resources/assets/relics/textures/gui/description/ability/reroll_button_active_warning.png new file mode 100644 index 00000000..52dd0b29 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/ability/reroll_button_active_warning.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/ability/reroll_button_inactive.png b/src/main/resources/assets/relics/textures/gui/description/ability/reroll_button_inactive.png new file mode 100644 index 00000000..d1b9344c Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/ability/reroll_button_inactive.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/ability/reset_button_active.png b/src/main/resources/assets/relics/textures/gui/description/ability/reset_button_active.png new file mode 100644 index 00000000..863f4bd3 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/ability/reset_button_active.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/ability/reset_button_active_quick.png b/src/main/resources/assets/relics/textures/gui/description/ability/reset_button_active_quick.png new file mode 100644 index 00000000..5b03d51e Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/ability/reset_button_active_quick.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/ability/reset_button_active_warning.png b/src/main/resources/assets/relics/textures/gui/description/ability/reset_button_active_warning.png new file mode 100644 index 00000000..1ed7babf Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/ability/reset_button_active_warning.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/ability/reset_button_inactive.png b/src/main/resources/assets/relics/textures/gui/description/ability/reset_button_inactive.png new file mode 100644 index 00000000..37ce7a79 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/ability/reset_button_inactive.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/ability/upgrade_button_active.png b/src/main/resources/assets/relics/textures/gui/description/ability/upgrade_button_active.png new file mode 100644 index 00000000..cedcfc1f Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/ability/upgrade_button_active.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/ability/upgrade_button_active_quick.png b/src/main/resources/assets/relics/textures/gui/description/ability/upgrade_button_active_quick.png new file mode 100644 index 00000000..a0c11910 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/ability/upgrade_button_active_quick.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/ability/upgrade_button_active_warning.png b/src/main/resources/assets/relics/textures/gui/description/ability/upgrade_button_active_warning.png new file mode 100644 index 00000000..b9a11260 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/ability/upgrade_button_active_warning.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/ability/upgrade_button_inactive.png b/src/main/resources/assets/relics/textures/gui/description/ability/upgrade_button_inactive.png new file mode 100644 index 00000000..2cf669b9 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/ability/upgrade_button_inactive.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/ability_background.png b/src/main/resources/assets/relics/textures/gui/description/ability_background.png deleted file mode 100644 index bec9978a..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/ability_background.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/backgrounds/aquatic.png b/src/main/resources/assets/relics/textures/gui/description/backgrounds/aquatic.png deleted file mode 100644 index 43dd17c0..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/backgrounds/aquatic.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/backgrounds/cave.png b/src/main/resources/assets/relics/textures/gui/description/backgrounds/cave.png deleted file mode 100644 index aeac3560..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/backgrounds/cave.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/backgrounds/default.png b/src/main/resources/assets/relics/textures/gui/description/backgrounds/default.png deleted file mode 100644 index cb9ec1d0..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/backgrounds/default.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/backgrounds/desert.png b/src/main/resources/assets/relics/textures/gui/description/backgrounds/desert.png deleted file mode 100644 index e7da3cef..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/backgrounds/desert.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/backgrounds/end.png b/src/main/resources/assets/relics/textures/gui/description/backgrounds/end.png deleted file mode 100644 index a33bd79e..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/backgrounds/end.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/backgrounds/icy.png b/src/main/resources/assets/relics/textures/gui/description/backgrounds/icy.png deleted file mode 100644 index 70a4861e..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/backgrounds/icy.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/backgrounds/jungle.png b/src/main/resources/assets/relics/textures/gui/description/backgrounds/jungle.png deleted file mode 100644 index 5deec6ce..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/backgrounds/jungle.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/backgrounds/nether.png b/src/main/resources/assets/relics/textures/gui/description/backgrounds/nether.png deleted file mode 100644 index 36ca396d..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/backgrounds/nether.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/backgrounds/plains.png b/src/main/resources/assets/relics/textures/gui/description/backgrounds/plains.png deleted file mode 100644 index a6ea7e7d..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/backgrounds/plains.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/card_highlight_locked.png b/src/main/resources/assets/relics/textures/gui/description/card_highlight_locked.png deleted file mode 100644 index 76beb3de..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/card_highlight_locked.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/card_highlight_unlocked.png b/src/main/resources/assets/relics/textures/gui/description/card_highlight_unlocked.png deleted file mode 100644 index ba39bd2f..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/card_highlight_unlocked.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/holy_locket/steal.png b/src/main/resources/assets/relics/textures/gui/description/cards/holy_locket/steal.png deleted file mode 100644 index c72ec02c..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/cards/holy_locket/steal.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/infinity_ham/autophagy.png b/src/main/resources/assets/relics/textures/gui/description/cards/infinity_ham/autophagy.png deleted file mode 100644 index 72d6538c..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/cards/infinity_ham/autophagy.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/infinity_ham/infusion.png b/src/main/resources/assets/relics/textures/gui/description/cards/infinity_ham/infusion.png deleted file mode 100644 index 980eb9a1..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/cards/infinity_ham/infusion.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/shadow_glaive/glaive.png b/src/main/resources/assets/relics/textures/gui/description/cards/shadow_glaive/glaive.png deleted file mode 100644 index b026b075..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/cards/shadow_glaive/glaive.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/cards/shadow_glaive/saw.png b/src/main/resources/assets/relics/textures/gui/description/cards/shadow_glaive/saw.png deleted file mode 100644 index aabb2ba9..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/cards/shadow_glaive/saw.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/exchange_highlight_locked.png b/src/main/resources/assets/relics/textures/gui/description/exchange_highlight_locked.png deleted file mode 100644 index 2198331c..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/exchange_highlight_locked.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/exchange_highlight_unlocked.png b/src/main/resources/assets/relics/textures/gui/description/exchange_highlight_unlocked.png deleted file mode 100644 index 68e4a794..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/exchange_highlight_unlocked.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/filters/blue.png b/src/main/resources/assets/relics/textures/gui/description/experience/filters/blue.png new file mode 100644 index 00000000..f326fcaa Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/filters/blue.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/filters/cyan.png b/src/main/resources/assets/relics/textures/gui/description/experience/filters/cyan.png new file mode 100644 index 00000000..dad24413 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/filters/cyan.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/filters/green.png b/src/main/resources/assets/relics/textures/gui/description/experience/filters/green.png new file mode 100644 index 00000000..3749b449 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/filters/green.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/filters/orange.png b/src/main/resources/assets/relics/textures/gui/description/experience/filters/orange.png new file mode 100644 index 00000000..2eab4cb4 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/filters/orange.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/filters/purple.png b/src/main/resources/assets/relics/textures/gui/description/experience/filters/purple.png new file mode 100644 index 00000000..d05c4487 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/filters/purple.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/filters/red.png b/src/main/resources/assets/relics/textures/gui/description/experience/filters/red.png new file mode 100644 index 00000000..3c597a8e Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/filters/red.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/filters/yellow.png b/src/main/resources/assets/relics/textures/gui/description/experience/filters/yellow.png new file mode 100644 index 00000000..6102742c Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/filters/yellow.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/blue.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/blue.png new file mode 100644 index 00000000..a91a8ff5 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/blue.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/cyan.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/cyan.png new file mode 100644 index 00000000..6f668a93 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/cyan.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/frame_locked.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/frame_locked.png new file mode 100644 index 00000000..a6c448cd Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/frame_locked.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/frame_unlocked.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/frame_unlocked.png new file mode 100644 index 00000000..6a5d0a40 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/frame_unlocked.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/green.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/green.png new file mode 100644 index 00000000..41b21a27 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/green.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/orange.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/orange.png new file mode 100644 index 00000000..707e65af Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/orange.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/purple.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/purple.png new file mode 100644 index 00000000..70a5ecd2 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/purple.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/red.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/red.png new file mode 100644 index 00000000..fb13db29 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/red.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/yellow.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/yellow.png new file mode 100644 index 00000000..a728454c Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/oval/yellow.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/blue.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/blue.png new file mode 100644 index 00000000..38ec8df6 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/blue.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/cyan.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/cyan.png new file mode 100644 index 00000000..b1f5190a Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/cyan.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/frame_locked.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/frame_locked.png new file mode 100644 index 00000000..a920017c Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/frame_locked.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/frame_unlocked.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/frame_unlocked.png new file mode 100644 index 00000000..d5fd9746 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/frame_unlocked.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/green.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/green.png new file mode 100644 index 00000000..71afecec Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/green.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/orange.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/orange.png new file mode 100644 index 00000000..a62ce955 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/orange.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/purple.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/purple.png new file mode 100644 index 00000000..dc1ecf8a Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/purple.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/red.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/red.png new file mode 100644 index 00000000..ed732bd6 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/red.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/yellow.png b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/yellow.png new file mode 100644 index 00000000..b94f4aa2 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/experience/gems/square/yellow.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience_highlight.png b/src/main/resources/assets/relics/textures/gui/description/experience_highlight.png deleted file mode 100644 index bfd3487b..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/experience_highlight.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/experience_particle.png b/src/main/resources/assets/relics/textures/gui/description/experience_particle.png deleted file mode 100644 index 1169109f..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/experience_particle.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/background.png b/src/main/resources/assets/relics/textures/gui/description/general/background.png new file mode 100644 index 00000000..1b48c803 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/background.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/chargeable.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/chargeable.png new file mode 100644 index 00000000..7e590d43 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/chargeable.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/chargeable_outline.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/chargeable_outline.png new file mode 100644 index 00000000..c1486e15 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/chargeable_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/cyclical.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/cyclical.png new file mode 100644 index 00000000..9be9a0e0 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/cyclical.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/cyclical_outline.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/cyclical_outline.png new file mode 100644 index 00000000..7d78d71d Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/cyclical_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/flawless_ability.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/flawless_ability.png new file mode 100644 index 00000000..087f7cba Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/flawless_ability.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/flawless_ability_outline.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/flawless_ability_outline.png new file mode 100644 index 00000000..2b6e1595 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/flawless_ability_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/instantaneous.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/instantaneous.png new file mode 100644 index 00000000..430a8495 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/instantaneous.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/instantaneous_outline.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/instantaneous_outline.png new file mode 100644 index 00000000..41255d32 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/instantaneous_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/interruptible.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/interruptible.png new file mode 100644 index 00000000..a282ede2 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/interruptible.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/interruptible_outline.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/interruptible_outline.png new file mode 100644 index 00000000..41255d32 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/interruptible_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/oblivion.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/oblivion.png new file mode 100644 index 00000000..e296b6a6 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/oblivion.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/oblivion_outline.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/oblivion_outline.png new file mode 100644 index 00000000..bf3ba9da Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/oblivion_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/silence.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/silence.png new file mode 100644 index 00000000..c0c14d52 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/silence.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/silence_outline.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/silence_outline.png new file mode 100644 index 00000000..fcd9cd0a Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/silence_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/stated.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/stated.png new file mode 100644 index 00000000..98b9abe2 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/stated.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/stated_outline.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/stated_outline.png new file mode 100644 index 00000000..6327954e Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/stated_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/toggleable.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/toggleable.png new file mode 100644 index 00000000..2736de10 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/toggleable.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/toggleable_outline.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/toggleable_outline.png new file mode 100644 index 00000000..94472543 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/ability/toggleable_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/relic/flawless_relic.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/relic/flawless_relic.png new file mode 100644 index 00000000..087f7cba Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/relic/flawless_relic.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/badges/relic/flawless_relic_outline.png b/src/main/resources/assets/relics/textures/gui/description/general/badges/relic/flawless_relic_outline.png new file mode 100644 index 00000000..2b6e1595 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/badges/relic/flawless_relic_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/big_card_background.png b/src/main/resources/assets/relics/textures/gui/description/general/big_card_background.png new file mode 100644 index 00000000..990679e5 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/big_card_background.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_locked_active.png b/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_locked_active.png new file mode 100644 index 00000000..3a40d6fe Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_locked_active.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_locked_inactive.png b/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_locked_inactive.png new file mode 100644 index 00000000..8cec6998 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_locked_inactive.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_outline.png b/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_outline.png new file mode 100644 index 00000000..d10856e4 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_unlocked_active.png b/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_unlocked_active.png new file mode 100644 index 00000000..e6c3d79c Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_unlocked_active.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_unlocked_inactive.png b/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_unlocked_inactive.png new file mode 100644 index 00000000..8ac3fa5d Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/big_card_frame_unlocked_inactive.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/big_star_active.png b/src/main/resources/assets/relics/textures/gui/description/general/big_star_active.png new file mode 100644 index 00000000..36a7035d Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/big_star_active.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/big_star_hole.png b/src/main/resources/assets/relics/textures/gui/description/general/big_star_hole.png new file mode 100644 index 00000000..628f4542 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/big_star_hole.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/big_star_inactive.png b/src/main/resources/assets/relics/textures/gui/description/general/big_star_inactive.png new file mode 100644 index 00000000..fd145579 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/big_star_inactive.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/bottom_background.png b/src/main/resources/assets/relics/textures/gui/description/general/bottom_background.png new file mode 100644 index 00000000..ab1532ef Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/bottom_background.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/fix.png b/src/main/resources/assets/relics/textures/gui/description/general/fix.png new file mode 100644 index 00000000..5d67dc5d Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/fix.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/icons/leveling_point.png b/src/main/resources/assets/relics/textures/gui/description/general/icons/leveling_point.png new file mode 100644 index 00000000..57444c84 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/icons/leveling_point.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/icons/luck.png b/src/main/resources/assets/relics/textures/gui/description/general/icons/luck.png new file mode 100644 index 00000000..2001893f Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/icons/luck.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/icons/pilgrim_point.png b/src/main/resources/assets/relics/textures/gui/description/general/icons/pilgrim_point.png new file mode 100644 index 00000000..6b0976c4 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/icons/pilgrim_point.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/icons/player_experience.png b/src/main/resources/assets/relics/textures/gui/description/general/icons/player_experience.png new file mode 100644 index 00000000..d77dc7dd Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/icons/player_experience.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/logo.png b/src/main/resources/assets/relics/textures/gui/description/general/logo.png new file mode 100644 index 00000000..6558b31e Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/logo.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/particles/pixel.png b/src/main/resources/assets/relics/textures/gui/description/general/particles/pixel.png new file mode 100644 index 00000000..54c786fb Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/particles/pixel.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/plate_background.png b/src/main/resources/assets/relics/textures/gui/description/general/plate_background.png new file mode 100644 index 00000000..07d6f1a3 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/plate_background.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/plate_outline.png b/src/main/resources/assets/relics/textures/gui/description/general/plate_outline.png new file mode 100644 index 00000000..49b74d42 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/plate_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/plate_player_experience_background.png b/src/main/resources/assets/relics/textures/gui/description/general/plate_player_experience_background.png new file mode 100644 index 00000000..4ef7ac49 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/plate_player_experience_background.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/plate_player_experience_filler.png b/src/main/resources/assets/relics/textures/gui/description/general/plate_player_experience_filler.png new file mode 100644 index 00000000..9abc8e64 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/plate_player_experience_filler.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/small_star_active.png b/src/main/resources/assets/relics/textures/gui/description/general/small_star_active.png new file mode 100644 index 00000000..207b7fa3 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/small_star_active.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/small_star_hole.png b/src/main/resources/assets/relics/textures/gui/description/general/small_star_hole.png new file mode 100644 index 00000000..07e0079d Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/small_star_hole.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/small_star_inactive.png b/src/main/resources/assets/relics/textures/gui/description/general/small_star_inactive.png new file mode 100644 index 00000000..2e436f13 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/small_star_inactive.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/tab.png b/src/main/resources/assets/relics/textures/gui/description/general/tab.png new file mode 100644 index 00000000..075bcb93 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/tab.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/tab_outline.png b/src/main/resources/assets/relics/textures/gui/description/general/tab_outline.png new file mode 100644 index 00000000..19a45ef9 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/tab_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/tabs/ability.png b/src/main/resources/assets/relics/textures/gui/description/general/tabs/ability.png new file mode 100644 index 00000000..051dc2e0 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/tabs/ability.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/tabs/experience.png b/src/main/resources/assets/relics/textures/gui/description/general/tabs/experience.png new file mode 100644 index 00000000..ec10731f Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/tabs/experience.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/tabs/relic.png b/src/main/resources/assets/relics/textures/gui/description/general/tabs/relic.png new file mode 100644 index 00000000..1cac5da3 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/tabs/relic.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/tooltip.png b/src/main/resources/assets/relics/textures/gui/description/general/tooltip.png new file mode 100644 index 00000000..14fffc61 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/tooltip.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/general/top_background.png b/src/main/resources/assets/relics/textures/gui/description/general/top_background.png new file mode 100644 index 00000000..e24b3726 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/general/top_background.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/icons/holy_locket/blessing.png b/src/main/resources/assets/relics/textures/gui/description/icons/holy_locket/blessing.png new file mode 100644 index 00000000..87c73a36 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/icons/holy_locket/blessing.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/leveling_point.png b/src/main/resources/assets/relics/textures/gui/description/leveling_point.png deleted file mode 100644 index 8c718af3..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/leveling_point.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/leveling_point_highlight.png b/src/main/resources/assets/relics/textures/gui/description/leveling_point_highlight.png deleted file mode 100644 index 73260512..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/leveling_point_highlight.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_0.png b/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_0.png new file mode 100644 index 00000000..7fc03ab9 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_0.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_1.png b/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_1.png new file mode 100644 index 00000000..869303c8 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_1.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_2.png b/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_2.png new file mode 100644 index 00000000..c1b0ed75 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_2.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_3.png b/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_3.png new file mode 100644 index 00000000..5af214f0 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_3.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_4.png b/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_4.png new file mode 100644 index 00000000..e5d29ae8 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/chains_active_4.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/chains_inactive.png b/src/main/resources/assets/relics/textures/gui/description/relic/chains_inactive.png new file mode 100644 index 00000000..4750512b Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/chains_inactive.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_0.png b/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_0.png new file mode 100644 index 00000000..98867dd1 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_0.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_1.png b/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_1.png new file mode 100644 index 00000000..b8fadaf7 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_1.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_2.png b/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_2.png new file mode 100644 index 00000000..90766be6 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_2.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_3.png b/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_3.png new file mode 100644 index 00000000..e97a0654 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_3.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_4.png b/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_4.png new file mode 100644 index 00000000..503592b6 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_active_4.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_inactive.png b/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_inactive.png new file mode 100644 index 00000000..a9dc3db2 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/icons/lock_inactive.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/icons/research.png b/src/main/resources/assets/relics/textures/gui/description/relic/icons/research.png new file mode 100644 index 00000000..83166a03 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/icons/research.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/icons/upgrade.png b/src/main/resources/assets/relics/textures/gui/description/relic/icons/upgrade.png new file mode 100644 index 00000000..a7c7afc5 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/icons/upgrade.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/particles/chain.png b/src/main/resources/assets/relics/textures/gui/description/relic/particles/chain.png new file mode 100644 index 00000000..0920e79b Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/particles/chain.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/particles/smoke.png b/src/main/resources/assets/relics/textures/gui/description/relic/particles/smoke.png new file mode 100644 index 00000000..2abbe717 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/particles/smoke.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/relic_experience_background.png b/src/main/resources/assets/relics/textures/gui/description/relic/relic_experience_background.png new file mode 100644 index 00000000..d8b07c96 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/relic_experience_background.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/relic_experience_filler.png b/src/main/resources/assets/relics/textures/gui/description/relic/relic_experience_filler.png new file mode 100644 index 00000000..bd8e7f52 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/relic_experience_filler.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/relic_experience_outline.png b/src/main/resources/assets/relics/textures/gui/description/relic/relic_experience_outline.png new file mode 100644 index 00000000..3e0ff035 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/relic_experience_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_locked_active.png b/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_locked_active.png new file mode 100644 index 00000000..02b67602 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_locked_active.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_locked_inactive.png b/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_locked_inactive.png new file mode 100644 index 00000000..0f1d048f Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_locked_inactive.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_outline.png b/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_outline.png new file mode 100644 index 00000000..b710c2ae Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_unlocked_active.png b/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_unlocked_active.png new file mode 100644 index 00000000..92e91bb5 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_unlocked_active.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_unlocked_inactive.png b/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_unlocked_inactive.png new file mode 100644 index 00000000..49c5b473 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/small_card_frame_unlocked_inactive.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/small_card_lock_background.png b/src/main/resources/assets/relics/textures/gui/description/relic/small_card_lock_background.png new file mode 100644 index 00000000..8549abd8 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/small_card_lock_background.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic/small_card_research_background.png b/src/main/resources/assets/relics/textures/gui/description/relic/small_card_research_background.png new file mode 100644 index 00000000..f4e11def Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/relic/small_card_research_background.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic_background.png b/src/main/resources/assets/relics/textures/gui/description/relic_background.png deleted file mode 100644 index efeee58b..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/relic_background.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/relic_experience_highlight.png b/src/main/resources/assets/relics/textures/gui/description/relic_experience_highlight.png deleted file mode 100644 index 4935784e..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/relic_experience_highlight.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/reroll_highlight_locked.png b/src/main/resources/assets/relics/textures/gui/description/reroll_highlight_locked.png deleted file mode 100644 index 6e2cbdf7..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/reroll_highlight_locked.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/reroll_highlight_unlocked.png b/src/main/resources/assets/relics/textures/gui/description/reroll_highlight_unlocked.png deleted file mode 100644 index 3380b58d..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/reroll_highlight_unlocked.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/research/bulb.png b/src/main/resources/assets/relics/textures/gui/description/research/bulb.png new file mode 100644 index 00000000..80f1daae Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/research/bulb.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/research/bulb_broken.png b/src/main/resources/assets/relics/textures/gui/description/research/bulb_broken.png new file mode 100644 index 00000000..b274b808 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/research/bulb_broken.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/research/bulb_burning.png b/src/main/resources/assets/relics/textures/gui/description/research/bulb_burning.png new file mode 100644 index 00000000..55540870 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/research/bulb_burning.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/research/bulb_glowing.png b/src/main/resources/assets/relics/textures/gui/description/research/bulb_glowing.png new file mode 100644 index 00000000..94eecbbd Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/research/bulb_glowing.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/research/dot.png b/src/main/resources/assets/relics/textures/gui/description/research/dot.png new file mode 100644 index 00000000..6527668b Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/research/dot.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/research/hint_background.png b/src/main/resources/assets/relics/textures/gui/description/research/hint_background.png new file mode 100644 index 00000000..191aaef1 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/research/hint_background.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/research/hint_outline.png b/src/main/resources/assets/relics/textures/gui/description/research/hint_outline.png new file mode 100644 index 00000000..5c346f64 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/research/hint_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/research/line.png b/src/main/resources/assets/relics/textures/gui/description/research/line.png new file mode 100644 index 00000000..b82ebc48 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/research/line.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/research/research_background.png b/src/main/resources/assets/relics/textures/gui/description/research/research_background.png new file mode 100644 index 00000000..2a27ffd7 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/research/research_background.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/research/research_fog.png b/src/main/resources/assets/relics/textures/gui/description/research/research_fog.png new file mode 100644 index 00000000..35805019 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/research/research_fog.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/research/star.png b/src/main/resources/assets/relics/textures/gui/description/research/star.png new file mode 100644 index 00000000..e67459f0 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/research/star.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/research/tip_background.png b/src/main/resources/assets/relics/textures/gui/description/research/tip_background.png new file mode 100644 index 00000000..18d5119a Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/research/tip_background.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/research/tip_outline.png b/src/main/resources/assets/relics/textures/gui/description/research/tip_outline.png new file mode 100644 index 00000000..ee0260b4 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/description/research/tip_outline.png differ diff --git a/src/main/resources/assets/relics/textures/gui/description/reset_highlight_locked.png b/src/main/resources/assets/relics/textures/gui/description/reset_highlight_locked.png deleted file mode 100644 index a5a95c87..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/reset_highlight_locked.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/reset_highlight_unlocked.png b/src/main/resources/assets/relics/textures/gui/description/reset_highlight_unlocked.png deleted file mode 100644 index 3d102211..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/reset_highlight_unlocked.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/upgrade_available.png b/src/main/resources/assets/relics/textures/gui/description/upgrade_available.png deleted file mode 100644 index b2ac2317..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/upgrade_available.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/upgrade_highlight_locked.png b/src/main/resources/assets/relics/textures/gui/description/upgrade_highlight_locked.png deleted file mode 100644 index 8f29c4ee..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/upgrade_highlight_locked.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/description/upgrade_highlight_unlocked.png b/src/main/resources/assets/relics/textures/gui/description/upgrade_highlight_unlocked.png deleted file mode 100644 index a9680111..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/description/upgrade_highlight_unlocked.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/border/paper.png b/src/main/resources/assets/relics/textures/gui/tooltip/border/paper.png deleted file mode 100644 index 33fb1d5f..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/tooltip/border/paper.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/border/wood.png b/src/main/resources/assets/relics/textures/gui/tooltip/border/wood.png deleted file mode 100644 index 39685f2c..00000000 Binary files a/src/main/resources/assets/relics/textures/gui/tooltip/border/wood.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/holy_locket_holiness_frame.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/holy_locket_holiness_frame.png new file mode 100644 index 00000000..64892199 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/holy_locket_holiness_frame.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/holy_locket_holiness_star.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/holy_locket_holiness_star.png new file mode 100644 index 00000000..6bc0360e Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/holy_locket_holiness_star.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/holy_locket_wickedness_frame.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/holy_locket_wickedness_frame.png new file mode 100644 index 00000000..fa8c4938 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/holy_locket_wickedness_frame.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/holy_locket_wickedness_star.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/holy_locket_wickedness_star.png new file mode 100644 index 00000000..c6756b4f Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/holy_locket_wickedness_star.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/infinity_ham_frame.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/infinity_ham_frame.png new file mode 100644 index 00000000..b48a161f Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/infinity_ham_frame.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/infinity_ham_star.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/infinity_ham_star.png new file mode 100644 index 00000000..e1e1a93b Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/infinity_ham_star.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/leafy_ring_frame.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/leafy_ring_frame.png new file mode 100644 index 00000000..a262e992 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/leafy_ring_frame.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/leafy_ring_star.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/leafy_ring_star.png new file mode 100644 index 00000000..1f014e7d Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/leafy_ring_star.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/phantom_boot_frame.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/phantom_boot_frame.png new file mode 100644 index 00000000..27f3a4ec Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/phantom_boot_frame.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/phantom_boot_star.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/phantom_boot_star.png new file mode 100644 index 00000000..63beb613 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/phantom_boot_star.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/shadow_glaive_frame.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/shadow_glaive_frame.png new file mode 100644 index 00000000..a5608aa9 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/shadow_glaive_frame.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/shadow_glaive_star.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/shadow_glaive_star.png new file mode 100644 index 00000000..8e9ef4d1 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/shadow_glaive_star.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/spore_sack_frame.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/spore_sack_frame.png new file mode 100644 index 00000000..44c0a1a8 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/spore_sack_frame.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/spore_sack_star.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/spore_sack_star.png new file mode 100644 index 00000000..57a25e97 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/spore_sack_star.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/springy_boot_frame.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/springy_boot_frame.png new file mode 100644 index 00000000..4fabc09f Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/springy_boot_frame.png differ diff --git a/src/main/resources/assets/relics/textures/gui/tooltip/frame/springy_boot_star.png b/src/main/resources/assets/relics/textures/gui/tooltip/frame/springy_boot_star.png new file mode 100644 index 00000000..e06c4f02 Binary files /dev/null and b/src/main/resources/assets/relics/textures/gui/tooltip/frame/springy_boot_star.png differ diff --git a/src/main/resources/assets/relics/textures/hud/abilities/arrow_left.png b/src/main/resources/assets/relics/textures/hud/abilities/arrow_left.png new file mode 100644 index 00000000..c53976dd Binary files /dev/null and b/src/main/resources/assets/relics/textures/hud/abilities/arrow_left.png differ diff --git a/src/main/resources/assets/relics/textures/hud/abilities/arrow_left_outline.png b/src/main/resources/assets/relics/textures/hud/abilities/arrow_left_outline.png new file mode 100644 index 00000000..35bd9da7 Binary files /dev/null and b/src/main/resources/assets/relics/textures/hud/abilities/arrow_left_outline.png differ diff --git a/src/main/resources/assets/relics/textures/hud/abilities/arrow_right.png b/src/main/resources/assets/relics/textures/hud/abilities/arrow_right.png new file mode 100644 index 00000000..0821d352 Binary files /dev/null and b/src/main/resources/assets/relics/textures/hud/abilities/arrow_right.png differ diff --git a/src/main/resources/assets/relics/textures/hud/abilities/arrow_right_outline.png b/src/main/resources/assets/relics/textures/hud/abilities/arrow_right_outline.png new file mode 100644 index 00000000..e1736d13 Binary files /dev/null and b/src/main/resources/assets/relics/textures/hud/abilities/arrow_right_outline.png differ diff --git a/src/main/resources/assets/relics/textures/hud/abilities/background.png b/src/main/resources/assets/relics/textures/hud/abilities/background.png deleted file mode 100644 index 62603ad6..00000000 Binary files a/src/main/resources/assets/relics/textures/hud/abilities/background.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/hud/abilities/card_frame_active.png b/src/main/resources/assets/relics/textures/hud/abilities/card_frame_active.png new file mode 100644 index 00000000..590ce1f5 Binary files /dev/null and b/src/main/resources/assets/relics/textures/hud/abilities/card_frame_active.png differ diff --git a/src/main/resources/assets/relics/textures/hud/abilities/card_frame_inactive.png b/src/main/resources/assets/relics/textures/hud/abilities/card_frame_inactive.png new file mode 100644 index 00000000..9377cf77 Binary files /dev/null and b/src/main/resources/assets/relics/textures/hud/abilities/card_frame_inactive.png differ diff --git a/src/main/resources/assets/relics/textures/hud/abilities/card_pointer_active.png b/src/main/resources/assets/relics/textures/hud/abilities/card_pointer_active.png new file mode 100644 index 00000000..61277b0e Binary files /dev/null and b/src/main/resources/assets/relics/textures/hud/abilities/card_pointer_active.png differ diff --git a/src/main/resources/assets/relics/textures/hud/abilities/card_pointer_inactive.png b/src/main/resources/assets/relics/textures/hud/abilities/card_pointer_inactive.png new file mode 100644 index 00000000..71646614 Binary files /dev/null and b/src/main/resources/assets/relics/textures/hud/abilities/card_pointer_inactive.png differ diff --git a/src/main/resources/assets/relics/textures/hud/abilities/widgets/cyclical.png b/src/main/resources/assets/relics/textures/hud/abilities/widgets/cyclical.png index a85b9c67..f58e2cb4 100644 Binary files a/src/main/resources/assets/relics/textures/hud/abilities/widgets/cyclical.png and b/src/main/resources/assets/relics/textures/hud/abilities/widgets/cyclical.png differ diff --git a/src/main/resources/assets/relics/textures/hud/abilities/widgets/icons/cooldown.png b/src/main/resources/assets/relics/textures/hud/abilities/widgets/icons/cooldown.png index 2e7e4335..3b645cf6 100644 Binary files a/src/main/resources/assets/relics/textures/hud/abilities/widgets/icons/cooldown.png and b/src/main/resources/assets/relics/textures/hud/abilities/widgets/icons/cooldown.png differ diff --git a/src/main/resources/assets/relics/textures/hud/abilities/widgets/icons/locked.png b/src/main/resources/assets/relics/textures/hud/abilities/widgets/icons/locked.png index debc8c70..a8140f7e 100644 Binary files a/src/main/resources/assets/relics/textures/hud/abilities/widgets/icons/locked.png and b/src/main/resources/assets/relics/textures/hud/abilities/widgets/icons/locked.png differ diff --git a/src/main/resources/assets/relics/textures/hud/abilities/widgets/icons/silence.png b/src/main/resources/assets/relics/textures/hud/abilities/widgets/icons/silence.png index 55c391d0..c55101e9 100644 Binary files a/src/main/resources/assets/relics/textures/hud/abilities/widgets/icons/silence.png and b/src/main/resources/assets/relics/textures/hud/abilities/widgets/icons/silence.png differ diff --git a/src/main/resources/assets/relics/textures/hud/abilities/widgets/toggleable.png b/src/main/resources/assets/relics/textures/hud/abilities/widgets/toggleable.png index d1c622e7..66081e91 100644 Binary files a/src/main/resources/assets/relics/textures/hud/abilities/widgets/toggleable.png and b/src/main/resources/assets/relics/textures/hud/abilities/widgets/toggleable.png differ diff --git a/src/main/resources/assets/relics/textures/hud/info/crouch_rmb.png b/src/main/resources/assets/relics/textures/hud/info/crouch_rmb.png deleted file mode 100644 index 3127f220..00000000 Binary files a/src/main/resources/assets/relics/textures/hud/info/crouch_rmb.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/hud/info/rmb.png b/src/main/resources/assets/relics/textures/hud/info/rmb.png deleted file mode 100644 index 289c41da..00000000 Binary files a/src/main/resources/assets/relics/textures/hud/info/rmb.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/hud/leafy_ring_hide.png b/src/main/resources/assets/relics/textures/hud/leafy_ring_hide.png new file mode 100644 index 00000000..0d34e7f1 Binary files /dev/null and b/src/main/resources/assets/relics/textures/hud/leafy_ring_hide.png differ diff --git a/src/main/resources/assets/relics/textures/item/camouflage_ring.png b/src/main/resources/assets/relics/textures/item/camouflage_ring.png deleted file mode 100644 index 8b2457ca..00000000 Binary files a/src/main/resources/assets/relics/textures/item/camouflage_ring.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/item/holy_locket.png b/src/main/resources/assets/relics/textures/item/holy_locket.png deleted file mode 100644 index f0a23ccd..00000000 Binary files a/src/main/resources/assets/relics/textures/item/holy_locket.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/item/holy_locket.png.mcmeta b/src/main/resources/assets/relics/textures/item/holy_locket.png.mcmeta deleted file mode 100644 index ec0f869c..00000000 --- a/src/main/resources/assets/relics/textures/item/holy_locket.png.mcmeta +++ /dev/null @@ -1,145 +0,0 @@ -{ - "animation": { - "interpolate": false, - "frames": [ - - {"index": 0, "time": 200}, - {"index": 7, "time": 2}, - {"index": 8, "time": 2}, - {"index": 9, "time": 2}, - - {"index": 0, "time": 100}, - {"index": 1, "time": 2}, - {"index": 2, "time": 2}, - {"index": 3, "time": 2}, - {"index": 4, "time": 2}, - {"index": 5, "time": 2}, - {"index": 6, "time": 2}, - - {"index": 10, "time": 150}, - {"index": 11, "time": 2}, - {"index": 12, "time": 2}, - {"index": 13, "time": 2}, - {"index": 14, "time": 2}, - {"index": 15, "time": 2}, - {"index": 16, "time": 2}, - - {"index": 0, "time": 200}, - {"index": 1, "time": 2}, - {"index": 2, "time": 2}, - {"index": 3, "time": 2}, - {"index": 4, "time": 2}, - {"index": 5, "time": 2}, - {"index": 6, "time": 2}, - - {"index": 10, "time": 2}, - {"index": 17, "time": 2}, - {"index": 18, "time": 2}, - {"index": 19, "time": 2}, - {"index": 20, "time": 2}, - - {"index": 21, "time": 200}, - {"index": 22, "time": 2}, - {"index": 23, "time": 2}, - {"index": 24, "time": 2}, - {"index": 25, "time": 2}, - {"index": 26, "time": 2}, - {"index": 27, "time": 2}, - {"index": 28, "time": 150}, - {"index": 31, "time": 2}, - {"index": 32, "time": 2}, - {"index": 33, "time": 2}, - {"index": 34, "time": 2}, - {"index": 35, "time": 2}, - {"index": 36, "time": 2}, - {"index": 37, "time": 2}, - {"index": 21, "time": 100}, - {"index": 22, "time": 2}, - {"index": 23, "time": 2}, - {"index": 24, "time": 2}, - {"index": 25, "time": 2}, - {"index": 26, "time": 2}, - {"index": 27, "time": 2}, - {"index": 21, "time": 200}, - {"index": 22, "time": 2}, - {"index": 29, "time": 2}, - {"index": 30, "time": 2}, - {"index": 21, "time": 150}, - {"index": 22, "time": 2}, - {"index": 23, "time": 2}, - {"index": 24, "time": 2}, - {"index": 25, "time": 2}, - {"index": 26, "time": 2}, - {"index": 27, "time": 2}, - {"index": 21, "time": 100}, - {"index": 38, "time": 2}, - {"index": 39, "time": 2}, - {"index": 40, "time": 2}, - {"index": 41, "time": 2}, - - {"index": 10, "time": 250}, - {"index": 11, "time": 2}, - {"index": 12, "time": 2}, - {"index": 13, "time": 2}, - {"index": 14, "time": 2}, - {"index": 15, "time": 2}, - {"index": 16, "time": 2}, - - {"index": 0, "time": 150}, - {"index": 1, "time": 2}, - {"index": 2, "time": 2}, - {"index": 3, "time": 2}, - {"index": 4, "time": 2}, - {"index": 5, "time": 2}, - {"index": 6, "time": 2}, - - {"index": 0, "time": 200}, - {"index": 7, "time": 2}, - {"index": 8, "time": 2}, - {"index": 9, "time": 2}, - - {"index": 10, "time": 100}, - {"index": 17, "time": 2}, - {"index": 18, "time": 2}, - {"index": 19, "time": 2}, - {"index": 20, "time": 2}, - - {"index": 21, "time": 200}, - {"index": 22, "time": 2}, - {"index": 23, "time": 2}, - {"index": 24, "time": 2}, - {"index": 25, "time": 2}, - {"index": 26, "time": 2}, - {"index": 27, "time": 2}, - - {"index": 21, "time": 250}, - {"index": 22, "time": 2}, - {"index": 29, "time": 2}, - {"index": 30, "time": 2}, - - {"index": 28, "time": 150}, - {"index": 31, "time": 2}, - {"index": 32, "time": 2}, - {"index": 33, "time": 2}, - {"index": 34, "time": 2}, - {"index": 35, "time": 2}, - {"index": 36, "time": 2}, - {"index": 37, "time": 2}, - - {"index": 21, "time": 100}, - {"index": 22, "time": 2}, - {"index": 23, "time": 2}, - {"index": 24, "time": 2}, - {"index": 25, "time": 2}, - {"index": 26, "time": 2}, - {"index": 27, "time": 2}, - - {"index": 28, "time": 2}, - {"index": 38, "time": 2}, - {"index": 39, "time": 2}, - {"index": 40, "time": 2}, - {"index": 41, "time": 2} - - ] - } -} \ No newline at end of file diff --git a/src/main/resources/assets/relics/textures/item/holy_locket_holiness.png b/src/main/resources/assets/relics/textures/item/holy_locket_holiness.png new file mode 100644 index 00000000..ce259385 Binary files /dev/null and b/src/main/resources/assets/relics/textures/item/holy_locket_holiness.png differ diff --git a/src/main/resources/assets/relics/textures/item/holy_locket_holiness.png.mcmeta b/src/main/resources/assets/relics/textures/item/holy_locket_holiness.png.mcmeta new file mode 100644 index 00000000..ab2fb7c3 --- /dev/null +++ b/src/main/resources/assets/relics/textures/item/holy_locket_holiness.png.mcmeta @@ -0,0 +1,146 @@ +{ + "animation": { + "interpolate": false, + "frames": [ + { + "index": 0, + "time": 80 + }, { + "index": 1, + "time": 2 + }, { + "index": 2, + "time": 2 + }, { + "index": 3, + "time": 2 + }, { + "index": 4, + "time": 2 + }, { + "index": 5, + "time": 2 + }, { + "index": 6, + "time": 2 + }, { + "index": 7, + "time": 2 + }, { + "index": 8, + "time": 2 + }, { + "index": 9, + "time": 2 + }, { + "index": 10, + "time": 2 + }, { + "index": 11, + "time": 2 + }, { + "index": 12, + "time": 2 + }, { + "index": 13, + "time": 2 + }, { + "index": 14, + "time": 2 + }, { + "index": 15, + "time": 2 + }, { + "index": 16, + "time": 2 + }, { + "index": 17, + "time": 2 + }, { + "index": 18, + "time": 2 + }, { + "index": 19, + "time": 2 + }, { + "index": 20, + "time": 2 + }, { + "index": 21, + "time": 2 + }, { + "index": 22, + "time": 2 + }, { + "index": 23, + "time": 2 + }, { + "index": 24, + "time": 2 + }, { + "index": 25, + "time": 2 + }, { + "index": 26, + "time": 2 + }, { + "index": 27, + "time": 2 + }, { + "index": 28, + "time": 2 + }, { + "index": 29, + "time": 2 + }, { + "index": 30, + "time": 2 + }, { + "index": 31, + "time": 2 + }, { + "index": 31, + "time": 2 + }, { + "index": 32, + "time": 2 + }, { + "index": 33, + "time": 2 + }, { + "index": 34, + "time": 2 + }, { + "index": 35, + "time": 2 + }, { + "index": 36, + "time": 2 + }, { + "index": 37, + "time": 2 + }, { + "index": 38, + "time": 2 + }, { + "index": 39, + "time": 2 + }, { + "index": 40, + "time": 2 + }, { + "index": 41, + "time": 2 + }, { + "index": 42, + "time": 2 + }, { + "index": 43, + "time": 2 + }, { + "index": 44, + "time": 2 + } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/textures/item/holy_locket_wickedness.png b/src/main/resources/assets/relics/textures/item/holy_locket_wickedness.png new file mode 100644 index 00000000..55cdedc1 Binary files /dev/null and b/src/main/resources/assets/relics/textures/item/holy_locket_wickedness.png differ diff --git a/src/main/resources/assets/relics/textures/item/holy_locket_wickedness.png.mcmeta b/src/main/resources/assets/relics/textures/item/holy_locket_wickedness.png.mcmeta new file mode 100644 index 00000000..ab2fb7c3 --- /dev/null +++ b/src/main/resources/assets/relics/textures/item/holy_locket_wickedness.png.mcmeta @@ -0,0 +1,146 @@ +{ + "animation": { + "interpolate": false, + "frames": [ + { + "index": 0, + "time": 80 + }, { + "index": 1, + "time": 2 + }, { + "index": 2, + "time": 2 + }, { + "index": 3, + "time": 2 + }, { + "index": 4, + "time": 2 + }, { + "index": 5, + "time": 2 + }, { + "index": 6, + "time": 2 + }, { + "index": 7, + "time": 2 + }, { + "index": 8, + "time": 2 + }, { + "index": 9, + "time": 2 + }, { + "index": 10, + "time": 2 + }, { + "index": 11, + "time": 2 + }, { + "index": 12, + "time": 2 + }, { + "index": 13, + "time": 2 + }, { + "index": 14, + "time": 2 + }, { + "index": 15, + "time": 2 + }, { + "index": 16, + "time": 2 + }, { + "index": 17, + "time": 2 + }, { + "index": 18, + "time": 2 + }, { + "index": 19, + "time": 2 + }, { + "index": 20, + "time": 2 + }, { + "index": 21, + "time": 2 + }, { + "index": 22, + "time": 2 + }, { + "index": 23, + "time": 2 + }, { + "index": 24, + "time": 2 + }, { + "index": 25, + "time": 2 + }, { + "index": 26, + "time": 2 + }, { + "index": 27, + "time": 2 + }, { + "index": 28, + "time": 2 + }, { + "index": 29, + "time": 2 + }, { + "index": 30, + "time": 2 + }, { + "index": 31, + "time": 2 + }, { + "index": 31, + "time": 2 + }, { + "index": 32, + "time": 2 + }, { + "index": 33, + "time": 2 + }, { + "index": 34, + "time": 2 + }, { + "index": 35, + "time": 2 + }, { + "index": 36, + "time": 2 + }, { + "index": 37, + "time": 2 + }, { + "index": 38, + "time": 2 + }, { + "index": 39, + "time": 2 + }, { + "index": 40, + "time": 2 + }, { + "index": 41, + "time": 2 + }, { + "index": 42, + "time": 2 + }, { + "index": 43, + "time": 2 + }, { + "index": 44, + "time": 2 + } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_0.png b/src/main/resources/assets/relics/textures/item/infinity_ham_0.png index 15d5e99f..e62ff902 100644 Binary files a/src/main/resources/assets/relics/textures/item/infinity_ham_0.png and b/src/main/resources/assets/relics/textures/item/infinity_ham_0.png differ diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_0.png.mcmeta b/src/main/resources/assets/relics/textures/item/infinity_ham_0.png.mcmeta deleted file mode 100644 index f5d578cc..00000000 --- a/src/main/resources/assets/relics/textures/item/infinity_ham_0.png.mcmeta +++ /dev/null @@ -1,32 +0,0 @@ -{ - "animation": { - "interpolate": false, - "frames": [ - { - "index": 0, - "time": 200 - }, { - "index": 1, - "time": 2 - }, { - "index": 2, - "time": 2 - }, { - "index": 3, - "time": 2 - }, { - "index": 4, - "time": 2 - }, { - "index": 5, - "time": 2 - }, { - "index": 6, - "time": 2 - }, { - "index": 7, - "time": 2 - } - ] - } -} diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_1.png b/src/main/resources/assets/relics/textures/item/infinity_ham_1.png index 57f4a87b..6f690f1e 100644 Binary files a/src/main/resources/assets/relics/textures/item/infinity_ham_1.png and b/src/main/resources/assets/relics/textures/item/infinity_ham_1.png differ diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_1.png.mcmeta b/src/main/resources/assets/relics/textures/item/infinity_ham_1.png.mcmeta index f5d578cc..03064fa1 100644 --- a/src/main/resources/assets/relics/textures/item/infinity_ham_1.png.mcmeta +++ b/src/main/resources/assets/relics/textures/item/infinity_ham_1.png.mcmeta @@ -4,7 +4,7 @@ "frames": [ { "index": 0, - "time": 200 + "time": 2 }, { "index": 1, "time": 2 @@ -20,13 +20,34 @@ }, { "index": 5, "time": 2 - }, { + }, { "index": 6, "time": 2 }, { "index": 7, "time": 2 + }, { + "index": 8, + "time": 2 + }, { + "index": 9, + "time": 2 + }, { + "index": 10, + "time": 2 + }, { + "index": 11, + "time": 2 + }, { + "index": 12, + "time": 2 + }, { + "index": 13, + "time": 2 + }, { + "index": 14, + "time": 2 } - ] - } -} + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_2.png b/src/main/resources/assets/relics/textures/item/infinity_ham_2.png index 48d51c55..a9c2e734 100644 Binary files a/src/main/resources/assets/relics/textures/item/infinity_ham_2.png and b/src/main/resources/assets/relics/textures/item/infinity_ham_2.png differ diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_2.png.mcmeta b/src/main/resources/assets/relics/textures/item/infinity_ham_2.png.mcmeta index f5d578cc..03064fa1 100644 --- a/src/main/resources/assets/relics/textures/item/infinity_ham_2.png.mcmeta +++ b/src/main/resources/assets/relics/textures/item/infinity_ham_2.png.mcmeta @@ -4,7 +4,7 @@ "frames": [ { "index": 0, - "time": 200 + "time": 2 }, { "index": 1, "time": 2 @@ -20,13 +20,34 @@ }, { "index": 5, "time": 2 - }, { + }, { "index": 6, "time": 2 }, { "index": 7, "time": 2 + }, { + "index": 8, + "time": 2 + }, { + "index": 9, + "time": 2 + }, { + "index": 10, + "time": 2 + }, { + "index": 11, + "time": 2 + }, { + "index": 12, + "time": 2 + }, { + "index": 13, + "time": 2 + }, { + "index": 14, + "time": 2 } - ] - } -} + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_3.png b/src/main/resources/assets/relics/textures/item/infinity_ham_3.png index 1e43f11e..c7647478 100644 Binary files a/src/main/resources/assets/relics/textures/item/infinity_ham_3.png and b/src/main/resources/assets/relics/textures/item/infinity_ham_3.png differ diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_3.png.mcmeta b/src/main/resources/assets/relics/textures/item/infinity_ham_3.png.mcmeta index f5d578cc..03064fa1 100644 --- a/src/main/resources/assets/relics/textures/item/infinity_ham_3.png.mcmeta +++ b/src/main/resources/assets/relics/textures/item/infinity_ham_3.png.mcmeta @@ -4,7 +4,7 @@ "frames": [ { "index": 0, - "time": 200 + "time": 2 }, { "index": 1, "time": 2 @@ -20,13 +20,34 @@ }, { "index": 5, "time": 2 - }, { + }, { "index": 6, "time": 2 }, { "index": 7, "time": 2 + }, { + "index": 8, + "time": 2 + }, { + "index": 9, + "time": 2 + }, { + "index": 10, + "time": 2 + }, { + "index": 11, + "time": 2 + }, { + "index": 12, + "time": 2 + }, { + "index": 13, + "time": 2 + }, { + "index": 14, + "time": 2 } - ] - } -} + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_4.png b/src/main/resources/assets/relics/textures/item/infinity_ham_4.png index 47877b6f..ba2d3042 100644 Binary files a/src/main/resources/assets/relics/textures/item/infinity_ham_4.png and b/src/main/resources/assets/relics/textures/item/infinity_ham_4.png differ diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_4.png.mcmeta b/src/main/resources/assets/relics/textures/item/infinity_ham_4.png.mcmeta index f5d578cc..03064fa1 100644 --- a/src/main/resources/assets/relics/textures/item/infinity_ham_4.png.mcmeta +++ b/src/main/resources/assets/relics/textures/item/infinity_ham_4.png.mcmeta @@ -4,7 +4,7 @@ "frames": [ { "index": 0, - "time": 200 + "time": 2 }, { "index": 1, "time": 2 @@ -20,13 +20,34 @@ }, { "index": 5, "time": 2 - }, { + }, { "index": 6, "time": 2 }, { "index": 7, "time": 2 + }, { + "index": 8, + "time": 2 + }, { + "index": 9, + "time": 2 + }, { + "index": 10, + "time": 2 + }, { + "index": 11, + "time": 2 + }, { + "index": 12, + "time": 2 + }, { + "index": 13, + "time": 2 + }, { + "index": 14, + "time": 2 } - ] - } -} + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_5.png b/src/main/resources/assets/relics/textures/item/infinity_ham_5.png index 0220476c..b7c9b44b 100644 Binary files a/src/main/resources/assets/relics/textures/item/infinity_ham_5.png and b/src/main/resources/assets/relics/textures/item/infinity_ham_5.png differ diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_5.png.mcmeta b/src/main/resources/assets/relics/textures/item/infinity_ham_5.png.mcmeta index f5d578cc..03064fa1 100644 --- a/src/main/resources/assets/relics/textures/item/infinity_ham_5.png.mcmeta +++ b/src/main/resources/assets/relics/textures/item/infinity_ham_5.png.mcmeta @@ -4,7 +4,7 @@ "frames": [ { "index": 0, - "time": 200 + "time": 2 }, { "index": 1, "time": 2 @@ -20,13 +20,34 @@ }, { "index": 5, "time": 2 - }, { + }, { "index": 6, "time": 2 }, { "index": 7, "time": 2 + }, { + "index": 8, + "time": 2 + }, { + "index": 9, + "time": 2 + }, { + "index": 10, + "time": 2 + }, { + "index": 11, + "time": 2 + }, { + "index": 12, + "time": 2 + }, { + "index": 13, + "time": 2 + }, { + "index": 14, + "time": 2 } - ] - } -} + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_6.png b/src/main/resources/assets/relics/textures/item/infinity_ham_6.png index 332f7f70..154fc0f3 100644 Binary files a/src/main/resources/assets/relics/textures/item/infinity_ham_6.png and b/src/main/resources/assets/relics/textures/item/infinity_ham_6.png differ diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_6.png.mcmeta b/src/main/resources/assets/relics/textures/item/infinity_ham_6.png.mcmeta index f5d578cc..03064fa1 100644 --- a/src/main/resources/assets/relics/textures/item/infinity_ham_6.png.mcmeta +++ b/src/main/resources/assets/relics/textures/item/infinity_ham_6.png.mcmeta @@ -4,7 +4,7 @@ "frames": [ { "index": 0, - "time": 200 + "time": 2 }, { "index": 1, "time": 2 @@ -20,13 +20,34 @@ }, { "index": 5, "time": 2 - }, { + }, { "index": 6, "time": 2 }, { "index": 7, "time": 2 + }, { + "index": 8, + "time": 2 + }, { + "index": 9, + "time": 2 + }, { + "index": 10, + "time": 2 + }, { + "index": 11, + "time": 2 + }, { + "index": 12, + "time": 2 + }, { + "index": 13, + "time": 2 + }, { + "index": 14, + "time": 2 } - ] - } -} + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_7.png b/src/main/resources/assets/relics/textures/item/infinity_ham_7.png deleted file mode 100644 index 094c7909..00000000 Binary files a/src/main/resources/assets/relics/textures/item/infinity_ham_7.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_7.png.mcmeta b/src/main/resources/assets/relics/textures/item/infinity_ham_7.png.mcmeta deleted file mode 100644 index f5d578cc..00000000 --- a/src/main/resources/assets/relics/textures/item/infinity_ham_7.png.mcmeta +++ /dev/null @@ -1,32 +0,0 @@ -{ - "animation": { - "interpolate": false, - "frames": [ - { - "index": 0, - "time": 200 - }, { - "index": 1, - "time": 2 - }, { - "index": 2, - "time": 2 - }, { - "index": 3, - "time": 2 - }, { - "index": 4, - "time": 2 - }, { - "index": 5, - "time": 2 - }, { - "index": 6, - "time": 2 - }, { - "index": 7, - "time": 2 - } - ] - } -} diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_8.png b/src/main/resources/assets/relics/textures/item/infinity_ham_8.png deleted file mode 100644 index c9311b87..00000000 Binary files a/src/main/resources/assets/relics/textures/item/infinity_ham_8.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_8.png.mcmeta b/src/main/resources/assets/relics/textures/item/infinity_ham_8.png.mcmeta deleted file mode 100644 index f5d578cc..00000000 --- a/src/main/resources/assets/relics/textures/item/infinity_ham_8.png.mcmeta +++ /dev/null @@ -1,32 +0,0 @@ -{ - "animation": { - "interpolate": false, - "frames": [ - { - "index": 0, - "time": 200 - }, { - "index": 1, - "time": 2 - }, { - "index": 2, - "time": 2 - }, { - "index": 3, - "time": 2 - }, { - "index": 4, - "time": 2 - }, { - "index": 5, - "time": 2 - }, { - "index": 6, - "time": 2 - }, { - "index": 7, - "time": 2 - } - ] - } -} diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_9.png b/src/main/resources/assets/relics/textures/item/infinity_ham_9.png deleted file mode 100644 index d282fd84..00000000 Binary files a/src/main/resources/assets/relics/textures/item/infinity_ham_9.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/item/infinity_ham_9.png.mcmeta b/src/main/resources/assets/relics/textures/item/infinity_ham_9.png.mcmeta deleted file mode 100644 index f5d578cc..00000000 --- a/src/main/resources/assets/relics/textures/item/infinity_ham_9.png.mcmeta +++ /dev/null @@ -1,32 +0,0 @@ -{ - "animation": { - "interpolate": false, - "frames": [ - { - "index": 0, - "time": 200 - }, { - "index": 1, - "time": 2 - }, { - "index": 2, - "time": 2 - }, { - "index": 3, - "time": 2 - }, { - "index": 4, - "time": 2 - }, { - "index": 5, - "time": 2 - }, { - "index": 6, - "time": 2 - }, { - "index": 7, - "time": 2 - } - ] - } -} diff --git a/src/main/resources/assets/relics/textures/item/leafy_ring.png b/src/main/resources/assets/relics/textures/item/leafy_ring.png new file mode 100644 index 00000000..21812039 Binary files /dev/null and b/src/main/resources/assets/relics/textures/item/leafy_ring.png differ diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_3.png.mcmeta b/src/main/resources/assets/relics/textures/item/leafy_ring.png.mcmeta similarity index 78% rename from src/main/resources/assets/relics/textures/item/shadow_glaive_3.png.mcmeta rename to src/main/resources/assets/relics/textures/item/leafy_ring.png.mcmeta index f7e7e3ae..5dead7e3 100644 --- a/src/main/resources/assets/relics/textures/item/shadow_glaive_3.png.mcmeta +++ b/src/main/resources/assets/relics/textures/item/leafy_ring.png.mcmeta @@ -20,25 +20,25 @@ }, { "index": 5, "time": 2 - }, { + }, { "index": 6, - "time": 6 + "time": 2 }, { "index": 7, - "time": 1 + "time": 2 }, { "index": 8, - "time": 1 + "time": 2 }, { "index": 9, - "time": 1 + "time": 2 }, { "index": 10, - "time": 1 + "time": 2 }, { "index": 11, - "time": 1 - } - ] - } -} + "time": 2 + } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/textures/models/items/amphibian_boot.png b/src/main/resources/assets/relics/textures/item/model/amphibian_boot.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/amphibian_boot.png rename to src/main/resources/assets/relics/textures/item/model/amphibian_boot.png diff --git a/src/main/resources/assets/relics/textures/models/items/aqua_walker.png b/src/main/resources/assets/relics/textures/item/model/aqua_walker.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/aqua_walker.png rename to src/main/resources/assets/relics/textures/item/model/aqua_walker.png diff --git a/src/main/resources/assets/relics/textures/models/items/arrow_quiver.png b/src/main/resources/assets/relics/textures/item/model/arrow_quiver.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/arrow_quiver.png rename to src/main/resources/assets/relics/textures/item/model/arrow_quiver.png diff --git a/src/main/resources/assets/relics/textures/models/items/drowned_belt.png b/src/main/resources/assets/relics/textures/item/model/drowned_belt.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/drowned_belt.png rename to src/main/resources/assets/relics/textures/item/model/drowned_belt.png diff --git a/src/main/resources/assets/relics/textures/models/items/elytra_booster_0.png b/src/main/resources/assets/relics/textures/item/model/elytra_booster_0.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/elytra_booster_0.png rename to src/main/resources/assets/relics/textures/item/model/elytra_booster_0.png diff --git a/src/main/resources/assets/relics/textures/models/items/elytra_booster_1.png b/src/main/resources/assets/relics/textures/item/model/elytra_booster_1.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/elytra_booster_1.png rename to src/main/resources/assets/relics/textures/item/model/elytra_booster_1.png diff --git a/src/main/resources/assets/relics/textures/models/items/enders_hand.png b/src/main/resources/assets/relics/textures/item/model/enders_hand.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/enders_hand.png rename to src/main/resources/assets/relics/textures/item/model/enders_hand.png diff --git a/src/main/resources/assets/relics/textures/models/items/holy_locket.png b/src/main/resources/assets/relics/textures/item/model/holy_locket.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/holy_locket.png rename to src/main/resources/assets/relics/textures/item/model/holy_locket.png diff --git a/src/main/resources/assets/relics/textures/models/items/hunter_belt.png b/src/main/resources/assets/relics/textures/item/model/hunter_belt.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/hunter_belt.png rename to src/main/resources/assets/relics/textures/item/model/hunter_belt.png diff --git a/src/main/resources/assets/relics/textures/item/model/infinity_ham.png b/src/main/resources/assets/relics/textures/item/model/infinity_ham.png new file mode 100644 index 00000000..592f376a Binary files /dev/null and b/src/main/resources/assets/relics/textures/item/model/infinity_ham.png differ diff --git a/src/main/resources/assets/relics/textures/models/items/jellyfish_necklace.png b/src/main/resources/assets/relics/textures/item/model/jellyfish_necklace.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/jellyfish_necklace.png rename to src/main/resources/assets/relics/textures/item/model/jellyfish_necklace.png diff --git a/src/main/resources/assets/relics/textures/models/items/leather_belt.png b/src/main/resources/assets/relics/textures/item/model/leather_belt.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/leather_belt.png rename to src/main/resources/assets/relics/textures/item/model/leather_belt.png diff --git a/src/main/resources/assets/relics/textures/models/items/magma_walker.png b/src/main/resources/assets/relics/textures/item/model/magma_walker.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/magma_walker.png rename to src/main/resources/assets/relics/textures/item/model/magma_walker.png diff --git a/src/main/resources/assets/relics/textures/models/items/midnight_robe.png b/src/main/resources/assets/relics/textures/item/model/midnight_robe.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/midnight_robe.png rename to src/main/resources/assets/relics/textures/item/model/midnight_robe.png diff --git a/src/main/resources/assets/relics/textures/item/model/phantom_boot.png b/src/main/resources/assets/relics/textures/item/model/phantom_boot.png new file mode 100644 index 00000000..58605afa Binary files /dev/null and b/src/main/resources/assets/relics/textures/item/model/phantom_boot.png differ diff --git a/src/main/resources/assets/relics/textures/models/items/rage_glove.png b/src/main/resources/assets/relics/textures/item/model/rage_glove.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/rage_glove.png rename to src/main/resources/assets/relics/textures/item/model/rage_glove.png diff --git a/src/main/resources/assets/relics/textures/models/items/reflection_necklace.png b/src/main/resources/assets/relics/textures/item/model/reflection_necklace.png similarity index 100% rename from src/main/resources/assets/relics/textures/models/items/reflection_necklace.png rename to src/main/resources/assets/relics/textures/item/model/reflection_necklace.png diff --git a/src/main/resources/assets/relics/textures/item/model/springy_boot.png b/src/main/resources/assets/relics/textures/item/model/springy_boot.png new file mode 100644 index 00000000..65b5248f Binary files /dev/null and b/src/main/resources/assets/relics/textures/item/model/springy_boot.png differ diff --git a/src/main/resources/assets/relics/textures/item/phantom_boot.png b/src/main/resources/assets/relics/textures/item/phantom_boot.png new file mode 100644 index 00000000..c05c14cf Binary files /dev/null and b/src/main/resources/assets/relics/textures/item/phantom_boot.png differ diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_4.png.mcmeta b/src/main/resources/assets/relics/textures/item/phantom_boot.png.mcmeta similarity index 73% rename from src/main/resources/assets/relics/textures/item/shadow_glaive_4.png.mcmeta rename to src/main/resources/assets/relics/textures/item/phantom_boot.png.mcmeta index 37ace6d4..1daa53f0 100644 --- a/src/main/resources/assets/relics/textures/item/shadow_glaive_4.png.mcmeta +++ b/src/main/resources/assets/relics/textures/item/phantom_boot.png.mcmeta @@ -4,7 +4,7 @@ "frames": [ { "index": 0, - "time": 200 + "time": 100 }, { "index": 1, "time": 2 @@ -13,38 +13,35 @@ "time": 2 }, { "index": 3, - "time": 2 + "time": 4 }, { "index": 4, "time": 2 }, { "index": 5, "time": 2 - }, { + }, { "index": 6, "time": 2 }, { "index": 7, - "time": 6 + "time": 2 }, { "index": 8, - "time": 1 + "time": 2 }, { "index": 9, - "time": 1 + "time": 2 }, { "index": 10, - "time": 1 + "time": 2 }, { "index": 11, - "time": 1 + "time": 2 }, { "index": 12, - "time": 1 - }, { - "index": 13, - "time": 1 + "time": 2 } - ] - } -} + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive.png b/src/main/resources/assets/relics/textures/item/shadow_glaive.png new file mode 100644 index 00000000..97ddb777 Binary files /dev/null and b/src/main/resources/assets/relics/textures/item/shadow_glaive.png differ diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_5.png.mcmeta b/src/main/resources/assets/relics/textures/item/shadow_glaive.png.mcmeta similarity index 66% rename from src/main/resources/assets/relics/textures/item/shadow_glaive_5.png.mcmeta rename to src/main/resources/assets/relics/textures/item/shadow_glaive.png.mcmeta index 18b803ed..0e618d2a 100644 --- a/src/main/resources/assets/relics/textures/item/shadow_glaive_5.png.mcmeta +++ b/src/main/resources/assets/relics/textures/item/shadow_glaive.png.mcmeta @@ -4,7 +4,7 @@ "frames": [ { "index": 0, - "time": 200 + "time": 80 }, { "index": 1, "time": 2 @@ -20,7 +20,7 @@ }, { "index": 5, "time": 2 - }, { + }, { "index": 6, "time": 2 }, { @@ -28,29 +28,20 @@ "time": 2 }, { "index": 8, - "time": 6 + "time": 2 }, { "index": 9, - "time": 1 + "time": 2 }, { "index": 10, - "time": 1 + "time": 2 }, { "index": 11, - "time": 1 + "time": 2 }, { "index": 12, - "time": 1 - }, { - "index": 13, - "time": 1 - }, { - "index": 14, - "time": 1 - }, { - "index": 15, - "time": 1 + "time": 2 } - ] - } -} + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_0.png b/src/main/resources/assets/relics/textures/item/shadow_glaive_0.png deleted file mode 100644 index 1268fbe7..00000000 Binary files a/src/main/resources/assets/relics/textures/item/shadow_glaive_0.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_0.png.mcmeta b/src/main/resources/assets/relics/textures/item/shadow_glaive_0.png.mcmeta deleted file mode 100644 index cb1d66ba..00000000 --- a/src/main/resources/assets/relics/textures/item/shadow_glaive_0.png.mcmeta +++ /dev/null @@ -1,53 +0,0 @@ -{ - "animation": { - "interpolate": false, - "frames": [ - { - "index": 0, - "time": 200 - }, { - "index": 1, - "time": 1 - }, { - "index": 2, - "time": 1 - }, { - "index": 3, - "time": 1 - }, { - "index": 4, - "time": 1 - }, { - "index": 5, - "time": 1 - }, { - "index": 6, - "time": 1 - }, { - "index": 7, - "time": 1 - }, { - "index": 1, - "time": 2 - }, { - "index": 2, - "time": 2 - }, { - "index": 3, - "time": 2 - }, { - "index": 4, - "time": 2 - }, { - "index": 5, - "time": 2 - }, { - "index": 6, - "time": 2 - }, { - "index": 7, - "time": 2 - } - ] - } -} diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_1.png b/src/main/resources/assets/relics/textures/item/shadow_glaive_1.png deleted file mode 100644 index 364bc25d..00000000 Binary files a/src/main/resources/assets/relics/textures/item/shadow_glaive_1.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_1.png.mcmeta b/src/main/resources/assets/relics/textures/item/shadow_glaive_1.png.mcmeta deleted file mode 100644 index fa33b92e..00000000 --- a/src/main/resources/assets/relics/textures/item/shadow_glaive_1.png.mcmeta +++ /dev/null @@ -1,32 +0,0 @@ -{ - "animation": { - "interpolate": false, - "frames": [ - { - "index": 0, - "time": 200 - }, { - "index": 1, - "time": 2 - }, { - "index": 2, - "time": 2 - }, { - "index": 3, - "time": 2 - }, { - "index": 4, - "time": 6 - }, { - "index": 5, - "time": 1 - }, { - "index": 6, - "time": 1 - }, { - "index": 7, - "time": 1 - } - ] - } -} diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_2.png b/src/main/resources/assets/relics/textures/item/shadow_glaive_2.png deleted file mode 100644 index a42710ba..00000000 Binary files a/src/main/resources/assets/relics/textures/item/shadow_glaive_2.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_2.png.mcmeta b/src/main/resources/assets/relics/textures/item/shadow_glaive_2.png.mcmeta deleted file mode 100644 index 5754d371..00000000 --- a/src/main/resources/assets/relics/textures/item/shadow_glaive_2.png.mcmeta +++ /dev/null @@ -1,38 +0,0 @@ -{ - "animation": { - "interpolate": false, - "frames": [ - { - "index": 0, - "time": 200 - }, { - "index": 1, - "time": 2 - }, { - "index": 2, - "time": 2 - }, { - "index": 3, - "time": 2 - }, { - "index": 4, - "time": 2 - }, { - "index": 5, - "time": 6 - }, { - "index": 6, - "time": 1 - }, { - "index": 7, - "time": 1 - }, { - "index": 8, - "time": 1 - }, { - "index": 9, - "time": 1 - } - ] - } -} diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_3.png b/src/main/resources/assets/relics/textures/item/shadow_glaive_3.png deleted file mode 100644 index 2e51f52a..00000000 Binary files a/src/main/resources/assets/relics/textures/item/shadow_glaive_3.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_4.png b/src/main/resources/assets/relics/textures/item/shadow_glaive_4.png deleted file mode 100644 index 504e143e..00000000 Binary files a/src/main/resources/assets/relics/textures/item/shadow_glaive_4.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_5.png b/src/main/resources/assets/relics/textures/item/shadow_glaive_5.png deleted file mode 100644 index 09f804ae..00000000 Binary files a/src/main/resources/assets/relics/textures/item/shadow_glaive_5.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_6.png b/src/main/resources/assets/relics/textures/item/shadow_glaive_6.png deleted file mode 100644 index 2c52be0e..00000000 Binary files a/src/main/resources/assets/relics/textures/item/shadow_glaive_6.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_6.png.mcmeta b/src/main/resources/assets/relics/textures/item/shadow_glaive_6.png.mcmeta deleted file mode 100644 index b80d09b4..00000000 --- a/src/main/resources/assets/relics/textures/item/shadow_glaive_6.png.mcmeta +++ /dev/null @@ -1,59 +0,0 @@ -{ - "animation": { - "interpolate": false, - "frames": [ - { - "index": 0, - "time": 200 - }, { - "index": 1, - "time": 2 - }, { - "index": 2, - "time": 2 - }, { - "index": 3, - "time": 2 - }, { - "index": 4, - "time": 2 - }, { - "index": 5, - "time": 2 - }, { - "index": 6, - "time": 2 - }, { - "index": 7, - "time": 2 - }, { - "index": 8, - "time": 6 - }, { - "index": 9, - "time": 1 - }, { - "index": 10, - "time": 1 - }, { - "index": 11, - "time": 1 - }, { - "index": 12, - "time": 1 - }, { - "index": 13, - "time": 1 - }, { - "index": 14, - "time": 1 - }, { - "index": 15, - "time": 1 - }, { - "index": 16, - "time": 1 - } - ] - } -} diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_7.png b/src/main/resources/assets/relics/textures/item/shadow_glaive_7.png deleted file mode 100644 index 636846c2..00000000 Binary files a/src/main/resources/assets/relics/textures/item/shadow_glaive_7.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_7.png.mcmeta b/src/main/resources/assets/relics/textures/item/shadow_glaive_7.png.mcmeta deleted file mode 100644 index 846bb483..00000000 --- a/src/main/resources/assets/relics/textures/item/shadow_glaive_7.png.mcmeta +++ /dev/null @@ -1,65 +0,0 @@ -{ - "animation": { - "interpolate": false, - "frames": [ - { - "index": 0, - "time": 200 - }, { - "index": 1, - "time": 2 - }, { - "index": 2, - "time": 2 - }, { - "index": 3, - "time": 2 - }, { - "index": 4, - "time": 2 - }, { - "index": 5, - "time": 2 - }, { - "index": 6, - "time": 2 - }, { - "index": 7, - "time": 2 - }, { - "index": 8, - "time": 2 - }, { - "index": 9, - "time": 6 - }, { - "index": 10, - "time": 1 - }, { - "index": 11, - "time": 1 - }, { - "index": 12, - "time": 1 - }, { - "index": 13, - "time": 1 - }, { - "index": 14, - "time": 1 - }, { - "index": 15, - "time": 1 - }, { - "index": 16, - "time": 1 - }, { - "index": 17, - "time": 1 - }, { - "index": 18, - "time": 1 - } - ] - } -} diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_8.png b/src/main/resources/assets/relics/textures/item/shadow_glaive_8.png deleted file mode 100644 index 14114de2..00000000 Binary files a/src/main/resources/assets/relics/textures/item/shadow_glaive_8.png and /dev/null differ diff --git a/src/main/resources/assets/relics/textures/item/shadow_glaive_8.png.mcmeta b/src/main/resources/assets/relics/textures/item/shadow_glaive_8.png.mcmeta deleted file mode 100644 index a773257f..00000000 --- a/src/main/resources/assets/relics/textures/item/shadow_glaive_8.png.mcmeta +++ /dev/null @@ -1,56 +0,0 @@ -{ - "animation": { - "interpolate": false, - "frames": [ - { - "index": 0, - "time": 200 - }, { - "index": 1, - "time": 1 - }, { - "index": 2, - "time": 1 - }, { - "index": 3, - "time": 1 - }, { - "index": 1, - "time": 1 - }, { - "index": 2, - "time": 1 - }, { - "index": 3, - "time": 1 - }, { - "index": 1, - "time": 1 - }, { - "index": 2, - "time": 1 - }, { - "index": 3, - "time": 1 - }, { - "index": 1, - "time": 1 - }, { - "index": 2, - "time": 1 - }, { - "index": 3, - "time": 1 - }, { - "index": 1, - "time": 2 - }, { - "index": 2, - "time": 2 - }, { - "index": 3, - "time": 2 - } - ] - } -} diff --git a/src/main/resources/assets/relics/textures/item/spore_sack.png b/src/main/resources/assets/relics/textures/item/spore_sack.png index 688499e9..35be3116 100644 Binary files a/src/main/resources/assets/relics/textures/item/spore_sack.png and b/src/main/resources/assets/relics/textures/item/spore_sack.png differ diff --git a/src/main/resources/assets/relics/textures/item/spore_sack.png.mcmeta b/src/main/resources/assets/relics/textures/item/spore_sack.png.mcmeta index 521e0a3d..e984f4fd 100644 --- a/src/main/resources/assets/relics/textures/item/spore_sack.png.mcmeta +++ b/src/main/resources/assets/relics/textures/item/spore_sack.png.mcmeta @@ -2,25 +2,25 @@ "animation": { "interpolate": false, "frames": [ - { + { "index": 0, - "time": 200 + "time": 60 }, { "index": 1, "time": 2 }, { "index": 2, - "time": 2 + "time": 4 }, { "index": 3, - "time": 2 + "time": 6 }, { "index": 4, - "time": 2 + "time": 10 }, { "index": 5, "time": 2 - }, { + }, { "index": 6, "time": 2 }, { @@ -33,7 +33,7 @@ "index": 9, "time": 2 }, { - "index": 1, + "index": 10, "time": 2 }, { "index": 11, @@ -43,26 +43,14 @@ "time": 2 }, { "index": 13, - "time": 2 - }, { + "time": 4 + }, { "index": 14, - "time": 2 + "time": 4 }, { "index": 15, - "time": 2 - }, { - "index": 16, - "time": 2 - }, { - "index": 17, - "time": 2 - }, { - "index": 18, - "time": 2 - }, { - "index": 19, - "time": 2 + "time": 4 } - ] + ] } } \ No newline at end of file diff --git a/src/main/resources/assets/relics/textures/item/springy_boot.png b/src/main/resources/assets/relics/textures/item/springy_boot.png new file mode 100644 index 00000000..b705d2d0 Binary files /dev/null and b/src/main/resources/assets/relics/textures/item/springy_boot.png differ diff --git a/src/main/resources/assets/relics/textures/item/camouflage_ring.png.mcmeta b/src/main/resources/assets/relics/textures/item/springy_boot.png.mcmeta similarity index 79% rename from src/main/resources/assets/relics/textures/item/camouflage_ring.png.mcmeta rename to src/main/resources/assets/relics/textures/item/springy_boot.png.mcmeta index fca111b2..00a01201 100644 --- a/src/main/resources/assets/relics/textures/item/camouflage_ring.png.mcmeta +++ b/src/main/resources/assets/relics/textures/item/springy_boot.png.mcmeta @@ -4,13 +4,13 @@ "frames": [ { "index": 0, - "time": 200 + "time": 80 }, { "index": 1, - "time": 2 + "time": 4 }, { "index": 2, - "time": 2 + "time": 4 }, { "index": 3, "time": 2 @@ -20,7 +20,7 @@ }, { "index": 5, "time": 2 - }, { + }, { "index": 6, "time": 2 }, { @@ -29,7 +29,13 @@ }, { "index": 8, "time": 2 + }, { + "index": 9, + "time": 2 + }, { + "index": 10, + "time": 2 } - ] - } -} + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/relics/textures/leveling_source/generic/spreading.png b/src/main/resources/assets/relics/textures/leveling_source/generic/spreading.png new file mode 100644 index 00000000..df3cfaa4 Binary files /dev/null and b/src/main/resources/assets/relics/textures/leveling_source/generic/spreading.png differ diff --git a/src/main/resources/assets/relics/textures/mob_effect/immortality.png b/src/main/resources/assets/relics/textures/mob_effect/immortality.png new file mode 100644 index 00000000..9e78ccdd Binary files /dev/null and b/src/main/resources/assets/relics/textures/mob_effect/immortality.png differ diff --git a/src/main/resources/assets/relics/textures/particle/spark.png b/src/main/resources/assets/relics/textures/particle/spark.png new file mode 100644 index 00000000..5f860b9a Binary files /dev/null and b/src/main/resources/assets/relics/textures/particle/spark.png differ diff --git a/src/main/resources/assets/relics/textures/particle/spark1.png b/src/main/resources/assets/relics/textures/particle/spark1.png new file mode 100644 index 00000000..5f860b9a Binary files /dev/null and b/src/main/resources/assets/relics/textures/particle/spark1.png differ diff --git a/src/main/resources/assets/relics/textures/parts/halo.png b/src/main/resources/assets/relics/textures/parts/halo.png new file mode 100644 index 00000000..4918216d Binary files /dev/null and b/src/main/resources/assets/relics/textures/parts/halo.png differ diff --git a/src/main/resources/assets/relics/textures/parts/wings.png b/src/main/resources/assets/relics/textures/parts/wings.png new file mode 100644 index 00000000..b3c0bc01 Binary files /dev/null and b/src/main/resources/assets/relics/textures/parts/wings.png differ diff --git a/src/main/resources/assets/relics/textures/slot/empty_talisman_slot.png b/src/main/resources/assets/relics/textures/slot/empty_talisman_slot.png deleted file mode 100644 index a3da6369..00000000 Binary files a/src/main/resources/assets/relics/textures/slot/empty_talisman_slot.png and /dev/null differ diff --git a/src/main/resources/data/curios/tags/items/back.json b/src/main/resources/data/curios/tags/item/back.json similarity index 78% rename from src/main/resources/data/curios/tags/items/back.json rename to src/main/resources/data/curios/tags/item/back.json index a7375d8e..7c0c5038 100644 --- a/src/main/resources/data/curios/tags/items/back.json +++ b/src/main/resources/data/curios/tags/item/back.json @@ -2,7 +2,6 @@ "replace": false, "values": [ "relics:midnight_robe", - "relics:arrow_quiver", "relics:elytra_booster" ] } \ No newline at end of file diff --git a/src/main/resources/data/curios/tags/items/belt.json b/src/main/resources/data/curios/tags/item/belt.json similarity index 100% rename from src/main/resources/data/curios/tags/items/belt.json rename to src/main/resources/data/curios/tags/item/belt.json diff --git a/src/main/resources/data/curios/tags/item/charm.json b/src/main/resources/data/curios/tags/item/charm.json new file mode 100644 index 00000000..4afa4f61 --- /dev/null +++ b/src/main/resources/data/curios/tags/item/charm.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "relics:spore_sack", + "relics:shadow_glaive" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/curios/tags/items/feet.json b/src/main/resources/data/curios/tags/item/feet.json similarity index 67% rename from src/main/resources/data/curios/tags/items/feet.json rename to src/main/resources/data/curios/tags/item/feet.json index 173e7f18..1dbb6f9d 100644 --- a/src/main/resources/data/curios/tags/items/feet.json +++ b/src/main/resources/data/curios/tags/item/feet.json @@ -6,6 +6,8 @@ "relics:ice_skates", "relics:ice_breaker", "relics:roller_skates", - "relics:amphibian_boot" + "relics:amphibian_boot", + "relics:phantom_boot", + "relics:springy_boot" ] } \ No newline at end of file diff --git a/src/main/resources/data/curios/tags/items/hands.json b/src/main/resources/data/curios/tags/item/hands.json similarity index 100% rename from src/main/resources/data/curios/tags/items/hands.json rename to src/main/resources/data/curios/tags/item/hands.json diff --git a/src/main/resources/data/curios/tags/items/necklace.json b/src/main/resources/data/curios/tags/item/necklace.json similarity index 100% rename from src/main/resources/data/curios/tags/items/necklace.json rename to src/main/resources/data/curios/tags/item/necklace.json diff --git a/src/main/resources/data/curios/tags/items/ring.json b/src/main/resources/data/curios/tags/item/ring.json similarity index 58% rename from src/main/resources/data/curios/tags/items/ring.json rename to src/main/resources/data/curios/tags/item/ring.json index 5cb71e02..d8b4dcda 100644 --- a/src/main/resources/data/curios/tags/items/ring.json +++ b/src/main/resources/data/curios/tags/item/ring.json @@ -2,6 +2,7 @@ "replace": false, "values": [ "relics:chorus_inhibitor", - "relics:bastion_ring" + "relics:bastion_ring", + "relics:leafy_ring" ] } \ No newline at end of file diff --git a/src/main/resources/data/curios/tags/items/talisman.json b/src/main/resources/data/curios/tags/items/talisman.json deleted file mode 100644 index 7ef5e1ea..00000000 --- a/src/main/resources/data/curios/tags/items/talisman.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "relics:spore_sack" - ] -} \ No newline at end of file diff --git a/src/main/resources/data/minecraft/tags/mineable/axe.json b/src/main/resources/data/minecraft/tags/mineable/axe.json deleted file mode 100644 index c6c9f0f8..00000000 --- a/src/main/resources/data/minecraft/tags/mineable/axe.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "replace": false, - "values": [ - "relics:researching_table" - ] -} \ No newline at end of file diff --git a/src/main/resources/data/forge/loot_modifiers/global_loot_modifiers.json b/src/main/resources/data/neoforge/loot_modifiers/global_loot_modifiers.json similarity index 100% rename from src/main/resources/data/forge/loot_modifiers/global_loot_modifiers.json rename to src/main/resources/data/neoforge/loot_modifiers/global_loot_modifiers.json diff --git a/src/main/resources/data/relics/curios/entities/modifier.json b/src/main/resources/data/relics/curios/entities/modifier.json index 80c19a05..624918f6 100644 --- a/src/main/resources/data/relics/curios/entities/modifier.json +++ b/src/main/resources/data/relics/curios/entities/modifier.json @@ -3,13 +3,13 @@ "player" ], "slots": [ - "talisman", "feet", "back", "belt", "feet", "hands", "necklace", - "ring" + "ring", + "charm" ] } \ No newline at end of file diff --git a/src/main/resources/data/relics/curios/slots/charm.json b/src/main/resources/data/relics/curios/slots/charm.json new file mode 100644 index 00000000..9c538eb5 --- /dev/null +++ b/src/main/resources/data/relics/curios/slots/charm.json @@ -0,0 +1,3 @@ +{ + "size": 1 +} \ No newline at end of file diff --git a/src/main/resources/data/relics/curios/slots/curio.json b/src/main/resources/data/relics/curios/slots/curio.json new file mode 100644 index 00000000..9c538eb5 --- /dev/null +++ b/src/main/resources/data/relics/curios/slots/curio.json @@ -0,0 +1,3 @@ +{ + "size": 1 +} \ No newline at end of file diff --git a/src/main/resources/data/relics/curios/slots/talisman.json b/src/main/resources/data/relics/curios/slots/talisman.json deleted file mode 100644 index c44310b0..00000000 --- a/src/main/resources/data/relics/curios/slots/talisman.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "order": 220, - "size": 0, - "icon": "relics:slot/empty_talisman_slot" -} \ No newline at end of file diff --git a/src/main/resources/data/relics/loot_tables/blocks/researching_table.json b/src/main/resources/data/relics/loot_tables/blocks/researching_table.json deleted file mode 100644 index 61a3b170..00000000 --- a/src/main/resources/data/relics/loot_tables/blocks/researching_table.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "minecraft:block", - "pools": [ - { - "rolls": 1, - "bonus_rolls": 0, - "entries": [ - { - "type": "minecraft:item", - "name": "relics:researching_table" - } - ], - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ] - } - ] -} diff --git a/src/main/resources/data/relics/recipes/researching_table.json b/src/main/resources/data/relics/recipes/researching_table.json deleted file mode 100644 index ab9e54d7..00000000 --- a/src/main/resources/data/relics/recipes/researching_table.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "type": "minecraft:crafting_shaped", - "group": "relics", - "pattern": [ - "ABA", - " C ", - "EDE" - ], - "key": { - "A": { - "item": "minecraft:red_wool" - }, - "B": { - "item": "minecraft:glowstone" - }, - "C": { - "item": "minecraft:gold_block" - }, - "D": { - "tag": "minecraft:planks" - }, - "E": { - "tag": "minecraft:wooden_slabs" - } - }, - "result": { - "item": "relics:researching_table", - "count": 1 - } -} \ No newline at end of file diff --git a/src/main/resources/relics.mixins.json b/src/main/resources/relics.mixins.json index 0c82725c..46d70f24 100644 --- a/src/main/resources/relics.mixins.json +++ b/src/main/resources/relics.mixins.json @@ -1,19 +1,22 @@ { "required": true, "package": "it.hurts.sskirillss.relics.mixin", - "compatibilityLevel": "JAVA_8", + "compatibilityLevel": "JAVA_21", "refmap": "relics.refmap.json", "mixins": [ "AbstractChestedHorseMixin", "AbstractContainerMenuMixin", + "BlockMixin", "EnderManMixin", "EntityMixin", + "GameDataMixin", "ItemMixin", - "ItemStackMixin", "LivingEntityMixin", "PiglinAiMixin", "PowderSnowBlockMixin", - "ScreenMixin" + "ScreenMixin", + "compat.sophisticatedbackpacks.FeedingUpgradeWrapperMixin", + "compat.sophisticatedbackpacks.UpgradeWrapperBaseAccessor" ], "minVersion": "0.8", "client": [