From 11444946cb07bb8ba89cd184f90966dea362fad7 Mon Sep 17 00:00:00 2001 From: somehussar <148253652+somehussar@users.noreply.github.com> Date: Tue, 3 Feb 2026 03:27:32 +0100 Subject: [PATCH 01/14] Go back to reflections --- dependencies.gradle | 2 +- .../java/kamkeel/npcs/util/BukkitUtil.java | 142 +++++++++++------- .../java/kamkeel/npcs/util/VaultUtil.java | 6 +- 3 files changed, 91 insertions(+), 59 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index b2e1aedea..287ae0e20 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -38,7 +38,7 @@ dependencies { runtimeOnlyNonPublishable("com.github.GTNewHorizons:NotEnoughItems:2.5.4-GTNH:dev") runtimeOnlyNonPublishable("curse.maven:Nashorn-374413:2924946") - compileOnly(files("./tools/bukkit-api/spigot-api-ONLY.jar")) +// compileOnly(files("./tools/bukkit-api/spigot-api-ONLY.jar")) // compileOnly(files("./tools/bukkit-api/Vault-1.4.1.jar")) shadowImplementation(project.files("tools/standalone-JaninoLoader-1.0.1-ALPHA.jar")) diff --git a/src/main/java/kamkeel/npcs/util/BukkitUtil.java b/src/main/java/kamkeel/npcs/util/BukkitUtil.java index 14f6b3609..29f4a522f 100644 --- a/src/main/java/kamkeel/npcs/util/BukkitUtil.java +++ b/src/main/java/kamkeel/npcs/util/BukkitUtil.java @@ -2,8 +2,8 @@ package kamkeel.npcs.util; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.plugin.RegisteredServiceProvider; + +import java.lang.reflect.Method; /** * Utility class for Bukkit integration detection and common operations. @@ -15,6 +15,26 @@ public class BukkitUtil { private static boolean initialized = false; private static boolean bukkitEnabled = false; + // Bukkit classes + private static Class bukkitClass; + private static Class serverClass; + private static Class servicesManagerClass; + private static Class registeredServiceProviderClass; + private static Class offlinePlayerClass; + private static Class playerClass; + + // Bukkit methods + private static Method getServer; + private static Method getServicesManager; + private static Method getRegistration; + private static Method getProvider; + private static Method getOfflinePlayer; + private static Method getPlayer; + private static Method getPluginManager; + private static Method isPluginEnabled; + + private static Method getPlugin; + /** * Initializes Bukkit integration using reflection. * Should be called during FMLServerStartedEvent to ensure Bukkit is fully loaded. @@ -26,24 +46,26 @@ public class BukkitUtil { initialized = true; try { - // Make sure all necessary bukkit methods and classes are available. - Class bukkitClass = Class.forName("org.bukkit.Bukkit"); - Class.forName("org.bukkit.Server"); - Class servicesManagerClass =Class.forName("org.bukkit.plugin.ServicesManager"); - Class registeredServiceProviderClass = Class.forName("org.bukkit.plugin.RegisteredServiceProvider"); - Class.forName("org.bukkit.OfflinePlayer"); - Class.forName("org.bukkit.entity.Player"); + // Load Bukkit classes + bukkitClass = Class.forName("org.bukkit.Bukkit"); + serverClass = Class.forName("org.bukkit.Server"); + servicesManagerClass = Class.forName("org.bukkit.plugin.ServicesManager"); + registeredServiceProviderClass = Class.forName("org.bukkit.plugin.RegisteredServiceProvider"); + offlinePlayerClass = Class.forName("org.bukkit.OfflinePlayer"); + playerClass = Class.forName("org.bukkit.entity.Player"); - bukkitClass.getMethod("getServer"); - bukkitClass.getMethod("getServicesManager"); - servicesManagerClass.getMethod("getRegistration", Class.class); - registeredServiceProviderClass.getMethod("getProvider"); - bukkitClass.getMethod("getOfflinePlayer", String.class); - bukkitClass.getMethod("getPlayer", String.class); - bukkitClass.getMethod("getPluginManager"); + // Get Bukkit methods + getServer = bukkitClass.getMethod("getServer"); + getServicesManager = bukkitClass.getMethod("getServicesManager"); + getRegistration = servicesManagerClass.getMethod("getRegistration", Class.class); + getProvider = registeredServiceProviderClass.getMethod("getProvider"); + getOfflinePlayer = bukkitClass.getMethod("getOfflinePlayer", String.class); + getPlayer = bukkitClass.getMethod("getPlayer", String.class); + getPluginManager = bukkitClass.getMethod("getPluginManager"); Class pluginManagerClass = Class.forName("org.bukkit.plugin.PluginManager"); - pluginManagerClass.getMethod("isPluginEnabled", String.class); + isPluginEnabled = pluginManagerClass.getMethod("isPluginEnabled", String.class); + getPlugin = pluginManagerClass.getMethod("getPlugin", String.class); bukkitEnabled = true; logger.info("Bukkit integration enabled"); @@ -51,7 +73,7 @@ public class BukkitUtil { // Initialize Vault after Bukkit is confirmed VaultUtil.init(); - } catch (ClassNotFoundException | NoClassDefFoundError e) { + } catch (ClassNotFoundException e) { logger.debug("Bukkit not found, Bukkit integration disabled"); } catch (NoSuchMethodException e) { logger.error("Bukkit API method not found", e); @@ -76,87 +98,99 @@ public class BukkitUtil { /** * Checks if a specific Bukkit plugin is enabled. - * * @param pluginName the plugin name to check * @return true if the plugin is enabled */ public static boolean isPluginEnabled(String pluginName) { - if (!isEnabled()) return false; + if (!bukkitEnabled) return false; try { - return Bukkit.getPluginManager().isPluginEnabled(pluginName); + Object pluginManager = getPluginManager.invoke(null); + return (Boolean) isPluginEnabled.invoke(pluginManager, pluginName); } catch (Exception e) { - logger.error("Error checking if plugin is enabled: {}", pluginName, e); + logger.error("Error checking if plugin is enabled: " + pluginName, e); return false; } } - /** - * @param pluginName name of the plugin to get. - * @return {@linkplain org.bukkit.plugin.Plugin Plugin} object for the name. Cast to correct class manually. - */ - public static Object getPlugin(String pluginName) { - if (!isEnabled()) return null; - - try { - return Bukkit.getPluginManager().getPlugin(pluginName); - } catch (Exception e) { - logger.error("Error getting plugin object: {}", pluginName, e); - return null; - } - } - /** * Gets a Bukkit OfflinePlayer by name. - * * @param playerName the player name - * @return the {@link org.bukkit.OfflinePlayer} object, or null if not available + * @return the OfflinePlayer object, or null if not available */ - @SuppressWarnings({"deprecation"}) public static Object getOfflinePlayer(String playerName) { - if (!isEnabled()) return null; + if (!bukkitEnabled) return null; try { - return Bukkit.getOfflinePlayer(playerName); + return getOfflinePlayer.invoke(null, playerName); } catch (Exception e) { - logger.error("Error getting OfflinePlayer: {}", playerName, e); + logger.error("Error getting OfflinePlayer: " + playerName, e); return null; } } /** * Gets a Bukkit Player by name (online players only). - * * @param playerName the player name - * @return the {@link org.bukkit.entity.Player} object, or null if not online or not available + * @return the Player object, or null if not online or not available */ public static Object getPlayer(String playerName) { - if (!isEnabled()) return null; + if (!bukkitEnabled) return null; try { - return Bukkit.getPlayer(playerName); + return getPlayer.invoke(null, playerName); } catch (Exception e) { - logger.error("Error getting Player: {}", playerName, e); + logger.error("Error getting Player: " + playerName, e); return null; } } /** * Gets a service provider from Bukkit's ServicesManager. - * * @param serviceClass the service class to get * @return the service provider, or null if not available */ - public static T getServiceProvider(Class serviceClass) { - if (!isEnabled()) return null; + public static Object getServiceProvider(Class serviceClass) { + if (!bukkitEnabled) return null; try { - RegisteredServiceProvider registration = Bukkit.getServicesManager().getRegistration(serviceClass); + Object servicesManager = getServicesManager.invoke(null); + Object registration = getRegistration.invoke(servicesManager, serviceClass); if (registration != null) { - return registration.getProvider(); + return getProvider.invoke(registration); } } catch (Exception e) { - logger.error("Error getting service provider: {}", serviceClass.getName(), e); + logger.error("Error getting service provider: " + serviceClass.getName(), e); + } + return null; + } + + // Getters for classes (for use by other utils like VaultUtil) + public static Class getBukkitClass() { + return bukkitClass; + } + + public static Class getServicesManagerClass() { + return servicesManagerClass; + } + + public static Class getRegisteredServiceProviderClass() { + return registeredServiceProviderClass; + } + + public static Class getOfflinePlayerClass() { + return offlinePlayerClass; + } + + public static Class getPlayerClass() { + return playerClass; + } + + public static Object getPlugin(String plugin) { + try { + return getPlugin.invoke(getPluginManager.invoke(null), plugin); + } catch (Throwable ignored) { + } return null; } diff --git a/src/main/java/kamkeel/npcs/util/VaultUtil.java b/src/main/java/kamkeel/npcs/util/VaultUtil.java index ab485e186..c25ea3f3a 100644 --- a/src/main/java/kamkeel/npcs/util/VaultUtil.java +++ b/src/main/java/kamkeel/npcs/util/VaultUtil.java @@ -3,8 +3,6 @@ package kamkeel.npcs.util; import net.minecraft.entity.player.EntityPlayer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; import java.lang.reflect.Method; @@ -70,14 +68,14 @@ public class VaultUtil { } try { - Class offlinePlayerClass = Class.forName("org.bukkit.OfflinePlayer"); + Class offlinePlayerClass = BukkitUtil.getOfflinePlayerClass(); if (offlinePlayerClass == null) { logger.error("Could not get OfflinePlayer class from BukkitUtil"); return; } // Load Vault classes - Plugin vault = Bukkit.getPluginManager().getPlugin("Vault"); + Object vault = BukkitUtil.getPlugin("Vault"); if (vault == null) return; ClassLoader vaultLoader = vault.getClass().getClassLoader(); From 2c6ec0ce3438b470ec47d7df1fbb32748d03ac49 Mon Sep 17 00:00:00 2001 From: Kam Date: Mon, 2 Feb 2026 21:51:21 -0500 Subject: [PATCH 02/14] Better GUI handling for Ability Making System --- .../controllers/data/ability/Ability.java | 51 ++--- .../data/ability/gui/AbilityFieldBuilder.java | 65 +++++++ .../data/ability/type/AbilityBeamDual.java | 85 +++++---- .../data/ability/type/AbilityCharge.java | 13 +- .../data/ability/type/AbilityCutter.java | 13 +- .../data/ability/type/AbilityDash.java | 7 +- .../data/ability/type/AbilityDisc.java | 39 ++-- .../data/ability/type/AbilityDiscDual.java | 75 +++++--- .../data/ability/type/AbilityEnergyBeam.java | 49 +++-- .../data/ability/type/AbilityGuard.java | 11 +- .../data/ability/type/AbilityHazard.java | 19 +- .../data/ability/type/AbilityHeal.java | 17 +- .../data/ability/type/AbilityHeavyHit.java | 7 +- .../data/ability/type/AbilityLaserShot.java | 40 ++-- .../data/ability/type/AbilityOrb.java | 39 ++-- .../data/ability/type/AbilityOrbDual.java | 75 +++++--- .../data/ability/type/AbilityProjectile.java | 7 +- .../data/ability/type/AbilityShockwave.java | 7 +- .../data/ability/type/AbilitySlam.java | 13 +- .../data/ability/type/AbilitySweeper.java | 29 +-- .../data/ability/type/AbilityTeleport.java | 27 +-- .../data/ability/type/AbilityTrap.java | 19 +- .../data/ability/type/AbilityVortex.java | 13 +- .../gui/advanced/SubGuiAbilityConfig.java | 159 +++------------- .../npcs/client/gui/builder/ColumnHint.java | 11 -- .../npcs/client/gui/builder/FieldDef.java | 32 ++-- .../npcs/client/gui/builder/FieldType.java | 3 +- .../client/gui/builder/GuiFieldBuilder.java | 179 ++++++++++++++---- .../npcs/client/gui/util/GuiNpcLabel.java | 135 ++++++++++++- .../npcs/client/gui/util/GuiScrollWindow.java | 8 + .../assets/customnpcs/lang/en_US.lang | 9 +- 31 files changed, 792 insertions(+), 464 deletions(-) delete mode 100644 src/main/java/noppes/npcs/client/gui/builder/ColumnHint.java diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java index c75d7d5d6..007e4f2f4 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java @@ -29,7 +29,6 @@ import noppes.npcs.scripted.NpcAPI; import noppes.npcs.scripted.event.AbilityEvent; import noppes.npcs.scripted.event.player.PlayerAbilityEvent; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import java.util.ArrayList; @@ -362,20 +361,25 @@ public abstract class Ability implements IAbility { // General tab defs.add(FieldDef.stringField("gui.name", this::getName, this::setName) .tab("General")); - defs.add(FieldDef.intField("ability.weight", this::getWeight, this::setWeight) - .tab("General").range(1, 1000).column(ColumnHint.LEFT)); - defs.add(FieldDef.boolField("gui.enabled", this::isEnabled, this::setEnabled) - .tab("General").column(ColumnHint.RIGHT)); + defs.add(FieldDef.row( + FieldDef.intField("ability.weight", this::getWeight, this::setWeight).range(1, 1000), + FieldDef.boolField("gui.enabled", this::isEnabled, this::setEnabled) + ).tab("General")); defs.add(FieldDef.section("ability.section.timing").tab("General")); + // WindUp: 3 mutually exclusive entries based on animation/sync state defs.add(FieldDef.intField("ability.windUpTicks", this::getRawWindUpTicks, this::setWindUpTicks) - .tab("General").range(0, 1000).column(ColumnHint.LEFT) - .visibleWhen(() -> !hasWindUpAnimation() || !isSyncWindupWithAnimation())); - defs.add(FieldDef.labelField("ability.windUpTicks", () -> getWindUpTicks() + "t") - .tab("General").column(ColumnHint.LEFT) - .visibleWhen(() -> hasWindUpAnimation() && isSyncWindupWithAnimation())); - defs.add(FieldDef.boolField("ability.syncWindup", this::isSyncWindupWithAnimation, this::setSyncWindupWithAnimation) - .tab("General").hover("ability.hover.sync").column(ColumnHint.RIGHT) - .visibleWhen(this::hasWindUpAnimation)); + .tab("General").range(0, 1000) + .visibleWhen(() -> !hasWindUpAnimation())); + defs.add(FieldDef.row( + FieldDef.intField("ability.windUpTicks", this::getRawWindUpTicks, this::setWindUpTicks).range(0, 1000), + FieldDef.boolField("ability.syncWindup", this::isSyncWindupWithAnimation, this::setSyncWindupWithAnimation) + .hover("ability.hover.sync") + ).tab("General").visibleWhen(() -> hasWindUpAnimation() && !isSyncWindupWithAnimation())); + defs.add(FieldDef.row( + FieldDef.labelField("ability.windUpTicks", () -> getWindUpTicks() + "t"), + FieldDef.boolField("ability.syncWindup", this::isSyncWindupWithAnimation, this::setSyncWindupWithAnimation) + .hover("ability.hover.sync") + ).tab("General").visibleWhen(() -> hasWindUpAnimation() && isSyncWindupWithAnimation())); defs.add(FieldDef.intField("ability.cooldownTicks", this::getCooldownTicks, this::setCooldownTicks) .tab("General").range(0, 10000)); defs.add(FieldDef.section("ability.section.movement").tab("General")); @@ -388,17 +392,18 @@ public abstract class Ability implements IAbility { } }) .tab("General").hover("ability.hover.lockMove")); - defs.add(FieldDef.boolField("ability.interruptible", this::isInterruptible, this::setInterruptible) - .tab("General").hover("ability.hover.interruptible").column(ColumnHint.LEFT)); - defs.add(FieldDef.intField("ability.dazedTicks", this::getDazedTicks, this::setDazedTicks) - .tab("General").range(0, 1000) - .visibleWhen(this::isInterruptible).column(ColumnHint.RIGHT)); + defs.add(FieldDef.row( + FieldDef.boolField("ability.interruptible", this::isInterruptible, this::setInterruptible) + .hover("ability.hover.interruptible"), + FieldDef.intField("ability.dazedTicks", this::getDazedTicks, this::setDazedTicks) + .range(0, 1000).visibleWhen(this::isInterruptible) + ).tab("General")); // Target tab - defs.add(FieldDef.intField("ability.minRange", () -> (int) getMinRange(), v -> setMinRange(v)) - .tab("Target").range(0, 100).column(ColumnHint.LEFT)); - defs.add(FieldDef.intField("ability.maxRange", () -> (int) getMaxRange(), v -> setMaxRange(v)) - .tab("Target").range(1, 100).column(ColumnHint.RIGHT)); + defs.add(FieldDef.row( + FieldDef.intField("ability.minRange", () -> (int) getMinRange(), v -> setMinRange(v)).range(0, 100), + FieldDef.intField("ability.maxRange", () -> (int) getMaxRange(), v -> setMaxRange(v)).range(1, 100) + ).tab("Target")); if (!isTargetingModeLocked()) { defs.add(FieldDef.enumField("ability.targetingMode", TargetingMode.class, this::getTargetingMode, this::setTargetingMode) @@ -426,7 +431,7 @@ public abstract class Ability implements IAbility { TelegraphType tType = getTelegraphType(); if (tType != null && tType != TelegraphType.NONE) { defs.add(FieldDef.section("ability.section.telegraph").tab("Effects") - .tooltip("telegraph." + tType.name().toLowerCase())); + .hover("telegraph." + tType.name().toLowerCase())); defs.add(FieldDef.boolField("ability.showTelegraph", this::isShowTelegraph, this::setShowTelegraph) .tab("Effects").hover("ability.hover.showTelegraph")); defs.add(FieldDef.colorSubGui("ability.windUpColor", this::getWindUpColor, this::setWindUpColor) diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/gui/AbilityFieldBuilder.java b/src/main/java/kamkeel/npcs/controllers/data/ability/gui/AbilityFieldBuilder.java index a044e1cf4..5edd0a718 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/gui/AbilityFieldBuilder.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/gui/AbilityFieldBuilder.java @@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import kamkeel.npcs.controllers.data.ability.AbilityEffect; import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiButton; import noppes.npcs.client.gui.builder.FieldDef; import noppes.npcs.client.gui.builder.FieldType; import noppes.npcs.client.gui.builder.GuiFieldBuilder; @@ -111,5 +112,69 @@ public class AbilityFieldBuilder extends GuiFieldBuilder { return y; } + // ═══════════════════════════════════════════════════════════════════ + // EVENT HANDLING OVERRIDES + // ═══════════════════════════════════════════════════════════════════ + + @Override + @SuppressWarnings("unchecked") + public boolean handleButtonEvent(int buttonId, GuiButton button) { + // Check effects list buttons via metadata + int[] meta = effectWidgetMeta.get(buttonId); + if (meta != null) { + FieldDef def = buttonFieldMap.get(buttonId); + if (def == null) def = clearFieldMap.get(buttonId); + if (def != null && def.getType() == FieldType.EFFECTS_LIST) { + List effects = (List) def.getValue(); + if (effects == null) return false; + int effectIdx = meta[0]; + int action = meta[1]; + + switch (action) { + case 0: // Type changed + if (effectIdx < effects.size()) { + effects.get(effectIdx).setType(AbilityEffect.EffectType.fromOrdinal(((GuiNpcButton) button).getValue())); + } + return true; + case 2: // Amp changed + if (effectIdx < effects.size()) { + effects.get(effectIdx).setAmplifier(((GuiNpcButton) button).getValue()); + } + return true; + case 3: // Delete + if (effectIdx < effects.size()) { + effects.remove(effectIdx); + } + return true; + case 4: // Add + if (effects.size() < 5) { + effects.add(new AbilityEffect(AbilityEffect.EffectType.SLOWNESS, 60, 0)); + } + return true; + } + } + } + + return super.handleButtonEvent(buttonId, button); + } + + @Override + @SuppressWarnings("unchecked") + public boolean handleTextFieldEvent(int textFieldId, GuiNpcTextField field) { + int[] meta = effectWidgetMeta.get(textFieldId); + if (meta != null && meta[1] == 1) { // duration field + FieldDef def = textFieldMap.get(textFieldId); + if (def != null && def.getType() == FieldType.EFFECTS_LIST) { + List effects = (List) def.getValue(); + if (effects != null && meta[0] < effects.size()) { + effects.get(meta[0]).setDurationTicks(field.getInteger()); + } + return true; + } + } + + return super.handleTextFieldEvent(textFieldId, field); + } + public Map getEffectWidgetMeta() { return effectWidgetMeta; } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java index 690930987..955fa1a42 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java @@ -7,7 +7,6 @@ import kamkeel.npcs.controllers.data.ability.AnchorPoint; import kamkeel.npcs.controllers.data.ability.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.ability.data.*; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import kamkeel.npcs.controllers.data.telegraph.Telegraph; @@ -381,14 +380,20 @@ public class AbilityBeamDual extends Ability { public List getFieldDefinitions() { return Arrays.asList( // Type tab - FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage).column(ColumnHint.LEFT), - FieldDef.floatField("stats.speed", this::getSpeed, this::setSpeed).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.floatField("stats.speed", this::getSpeed, this::setSpeed) + ), FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback), FieldDef.section("ability.section.beam"), - FieldDef.floatField("ability.beamWidth", this::getBeamWidth, this::setBeamWidth).column(ColumnHint.LEFT), - FieldDef.floatField("ability.headSize", this::getHeadSize, this::setHeadSize).column(ColumnHint.RIGHT), - FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance).column(ColumnHint.LEFT), - FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.beamWidth", this::getBeamWidth, this::setBeamWidth), + FieldDef.floatField("ability.headSize", this::getHeadSize, this::setHeadSize) + ), + FieldDef.row( + FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance), + FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime) + ), FieldDef.section("ability.section.dual"), FieldDef.boolField("ability.dualFire", this::isDualFire, this::setDualFire), FieldDef.intField("ability.dualFireDelay", this::getDualFireDelay, this::setDualFireDelay) @@ -396,10 +401,12 @@ public class AbilityBeamDual extends Ability { FieldDef.section("ability.section.homing"), FieldDef.boolField("gui.enabled", this::isHoming, this::setHoming) .hover("ability.hover.homing"), - FieldDef.floatField("gui.strength", this::getHomingStrength, this::setHomingStrength) - .visibleWhen(this::isHoming).column(ColumnHint.LEFT), - FieldDef.floatField("gui.range", this::getHomingRange, this::setHomingRange) - .visibleWhen(this::isHoming).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("gui.strength", this::getHomingStrength, this::setHomingStrength) + .visibleWhen(this::isHoming), + FieldDef.floatField("gui.range", this::getHomingRange, this::setHomingRange) + .visibleWhen(this::isHoming) + ), FieldDef.section("ability.section.explosive"), FieldDef.boolField("gui.enabled", this::isExplosive, this::setExplosive) .hover("ability.hover.explosive"), @@ -420,24 +427,28 @@ public class AbilityBeamDual extends Ability { FieldDef.colorSubGui("ability.outerColor", () -> getOuterColor(0), v -> setOuterColor(0, v)) .tab("ability.tab.visual").visibleWhen(() -> isOuterColorEnabled(0)), - FieldDef.floatField("ability.outerWidth", - () -> getOuterColorWidth(0), v -> setOuterColorWidth(0, v)) - .tab("ability.tab.visual").visibleWhen(() -> isOuterColorEnabled(0)).column(ColumnHint.LEFT), - FieldDef.floatField("ability.outerAlpha", - () -> getOuterColorAlpha(0), v -> setOuterColorAlpha(0, v)) - .tab("ability.tab.visual").range(0, 1).visibleWhen(() -> isOuterColorEnabled(0)).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.outerWidth", + () -> getOuterColorWidth(0), v -> setOuterColorWidth(0, v)) + .visibleWhen(() -> isOuterColorEnabled(0)), + FieldDef.floatField("ability.outerAlpha", + () -> getOuterColorAlpha(0), v -> setOuterColorAlpha(0, v)) + .range(0, 1).visibleWhen(() -> isOuterColorEnabled(0)) + ).tab("ability.tab.visual"), FieldDef.floatField("ability.rotationSpeed", () -> getRotationSpeed(0), v -> setRotationSpeed(0, v)) .tab("ability.tab.visual"), FieldDef.boolField("ability.lightning", () -> hasLightningEffect(0), v -> setLightningEffect(0, v)) .tab("ability.tab.visual"), - FieldDef.floatField("gui.density", - () -> getLightningDensity(0), v -> setLightningDensity(0, v)) - .tab("ability.tab.visual").range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(0)).column(ColumnHint.LEFT), - FieldDef.floatField("gui.radius", - () -> getLightningRadius(0), v -> setLightningRadius(0, v)) - .tab("ability.tab.visual").range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(0)).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("gui.density", + () -> getLightningDensity(0), v -> setLightningDensity(0, v)) + .range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(0)), + FieldDef.floatField("gui.radius", + () -> getLightningRadius(0), v -> setLightningRadius(0, v)) + .range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(0)) + ).tab("ability.tab.visual"), // Visual tab - Beam 2 FieldDef.enumField("ability.anchorPoint", AnchorPoint.class, () -> getAnchorPointEnum(1), v -> setAnchorPointEnum(1, v)) @@ -452,24 +463,28 @@ public class AbilityBeamDual extends Ability { FieldDef.colorSubGui("ability.outerColor", () -> getOuterColor(1), v -> setOuterColor(1, v)) .tab("ability.tab.visual").visibleWhen(() -> isOuterColorEnabled(1)), - FieldDef.floatField("ability.outerWidth", - () -> getOuterColorWidth(1), v -> setOuterColorWidth(1, v)) - .tab("ability.tab.visual").visibleWhen(() -> isOuterColorEnabled(1)).column(ColumnHint.LEFT), - FieldDef.floatField("ability.outerAlpha", - () -> getOuterColorAlpha(1), v -> setOuterColorAlpha(1, v)) - .tab("ability.tab.visual").range(0, 1).visibleWhen(() -> isOuterColorEnabled(1)).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.outerWidth", + () -> getOuterColorWidth(1), v -> setOuterColorWidth(1, v)) + .visibleWhen(() -> isOuterColorEnabled(1)), + FieldDef.floatField("ability.outerAlpha", + () -> getOuterColorAlpha(1), v -> setOuterColorAlpha(1, v)) + .range(0, 1).visibleWhen(() -> isOuterColorEnabled(1)) + ).tab("ability.tab.visual"), FieldDef.floatField("ability.rotationSpeed", () -> getRotationSpeed(1), v -> setRotationSpeed(1, v)) .tab("ability.tab.visual"), FieldDef.boolField("ability.lightning", () -> hasLightningEffect(1), v -> setLightningEffect(1, v)) .tab("ability.tab.visual"), - FieldDef.floatField("gui.density", - () -> getLightningDensity(1), v -> setLightningDensity(1, v)) - .tab("ability.tab.visual").range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(1)).column(ColumnHint.LEFT), - FieldDef.floatField("gui.radius", - () -> getLightningRadius(1), v -> setLightningRadius(1, v)) - .tab("ability.tab.visual").range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(1)).column(ColumnHint.RIGHT) + FieldDef.row( + FieldDef.floatField("gui.density", + () -> getLightningDensity(1), v -> setLightningDensity(1, v)) + .range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(1)), + FieldDef.floatField("gui.radius", + () -> getLightningRadius(1), v -> setLightningRadius(1, v)) + .range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(1)) + ).tab("ability.tab.visual") ); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCharge.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCharge.java index d8cc3408d..d149dc3ad 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCharge.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCharge.java @@ -16,7 +16,6 @@ import net.minecraft.util.Vec3; import net.minecraft.world.World; import noppes.npcs.entity.EntityNPCInterface; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import noppes.npcs.api.ability.type.IAbilityCharge; @@ -400,10 +399,14 @@ public class AbilityCharge extends Ability implements IAbilityCharge { @Override public List getFieldDefinitions() { return Arrays.asList( - FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage).column(ColumnHint.LEFT), - FieldDef.floatField("ability.chargeSpeed", this::getChargeSpeed, this::setChargeSpeed).column(ColumnHint.RIGHT), - FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback).column(ColumnHint.LEFT), - FieldDef.floatField("ability.hitWidth", this::getHitWidth, this::setHitWidth).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.floatField("ability.chargeSpeed", this::getChargeSpeed, this::setChargeSpeed) + ), + FieldDef.row( + FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback), + FieldDef.floatField("ability.hitWidth", this::getHitWidth, this::setHitWidth) + ), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) ); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java index f8419a1b8..ba0962356 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java @@ -13,7 +13,6 @@ import noppes.npcs.entity.EntityNPCInterface; import noppes.npcs.api.ability.type.IAbilityCutter; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; @@ -319,14 +318,18 @@ public class AbilityCutter extends Ability implements IAbilityCutter { @Override public List getFieldDefinitions() { return Arrays.asList( - FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage).column(ColumnHint.LEFT), - FieldDef.floatField("gui.range", this::getRange, this::setRange).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.floatField("gui.range", this::getRange, this::setRange) + ), FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback), FieldDef.section("ability.section.sweep"), FieldDef.enumField("ability.sweepMode", SweepMode.class, this::getSweepModeEnum, this::setSweepModeEnum) .hover("ability.hover.sweepMode"), - FieldDef.floatField("ability.arcAngle", this::getArcAngle, this::setArcAngle).column(ColumnHint.LEFT), - FieldDef.floatField("ability.innerRadius", this::getInnerRadius, this::setInnerRadius).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.arcAngle", this::getArcAngle, this::setArcAngle), + FieldDef.floatField("ability.innerRadius", this::getInnerRadius, this::setInnerRadius) + ), FieldDef.floatField("ability.sweepSpeed", this::getSweepSpeed, this::setSweepSpeed), FieldDef.intField("ability.spinDuration", this::getSpinDurationTicks, this::setSpinDurationTicks) .range(1, 1000) diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java index b045620a4..fb5d59f0e 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java @@ -14,7 +14,6 @@ import net.minecraft.util.Vec3; import net.minecraft.world.World; import noppes.npcs.entity.EntityNPCInterface; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import noppes.npcs.api.ability.type.IAbilityDash; @@ -356,8 +355,10 @@ public class AbilityDash extends Ability implements IAbilityDash { return Arrays.asList( FieldDef.enumField("ability.dashMode", DashMode.class, this::getDashModeEnum, this::setDashModeEnum) .hover("ability.hover.dashMode"), - FieldDef.floatField("ability.dashDistance", this::getDashDistance, this::setDashDistance).column(ColumnHint.LEFT), - FieldDef.floatField("ability.dashSpeed", this::getDashSpeed, this::setDashSpeed).column(ColumnHint.RIGHT) + FieldDef.row( + FieldDef.floatField("ability.dashDistance", this::getDashDistance, this::setDashDistance), + FieldDef.floatField("ability.dashSpeed", this::getDashSpeed, this::setDashSpeed) + ) ); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java index a7d00eb90..f44270c14 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java @@ -17,7 +17,6 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.Vec3; import net.minecraft.world.World; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import noppes.npcs.api.ability.type.IAbilityDisc; @@ -277,14 +276,20 @@ public class AbilityDisc extends Ability implements IAbilityDisc { public List getFieldDefinitions() { return Arrays.asList( // Type tab - FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage).column(ColumnHint.LEFT), - FieldDef.floatField("stats.speed", this::getSpeed, this::setSpeed).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.floatField("stats.speed", this::getSpeed, this::setSpeed) + ), FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback), FieldDef.section("ability.section.disc"), - FieldDef.floatField("gui.radius", this::getDiscRadius, this::setDiscRadius).column(ColumnHint.LEFT), - FieldDef.floatField("gui.thickness", this::getDiscThickness, this::setDiscThickness).column(ColumnHint.RIGHT), - FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance).column(ColumnHint.LEFT), - FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("gui.radius", this::getDiscRadius, this::setDiscRadius), + FieldDef.floatField("gui.thickness", this::getDiscThickness, this::setDiscThickness) + ), + FieldDef.row( + FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance), + FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime) + ), FieldDef.section("ability.section.homing"), FieldDef.boolField("gui.enabled", this::isHoming, this::setHoming) .hover("ability.hover.homing"), @@ -311,19 +316,23 @@ public class AbilityDisc extends Ability implements IAbilityDisc { .tab("ability.tab.visual"), FieldDef.colorSubGui("ability.outerColor", this::getOuterColor, this::setOuterColor) .tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled), - FieldDef.floatField("ability.outerWidth", this::getOuterColorWidth, this::setOuterColorWidth) - .tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled).column(ColumnHint.LEFT), - FieldDef.floatField("ability.outerAlpha", this::getOuterColorAlpha, this::setOuterColorAlpha) - .tab("ability.tab.visual").range(0, 1).visibleWhen(this::isOuterColorEnabled).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.outerWidth", this::getOuterColorWidth, this::setOuterColorWidth) + .visibleWhen(this::isOuterColorEnabled), + FieldDef.floatField("ability.outerAlpha", this::getOuterColorAlpha, this::setOuterColorAlpha) + .range(0, 1).visibleWhen(this::isOuterColorEnabled) + ).tab("ability.tab.visual"), FieldDef.section("ability.section.effects").tab("ability.tab.visual"), FieldDef.floatField("ability.rotationSpeed", this::getRotationSpeed, this::setRotationSpeed) .tab("ability.tab.visual"), FieldDef.boolField("ability.lightning", this::hasLightningEffect, this::setLightningEffect) .tab("ability.tab.visual"), - FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity) - .tab("ability.tab.visual").range(0.01f, 5.0f).visibleWhen(this::hasLightningEffect).column(ColumnHint.LEFT), - FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) - .tab("ability.tab.visual").range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect).column(ColumnHint.RIGHT) + FieldDef.row( + FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity) + .range(0.01f, 5.0f).visibleWhen(this::hasLightningEffect), + FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) + .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) + ).tab("ability.tab.visual") ); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java index b7b3383c0..cf57498c3 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java @@ -7,7 +7,6 @@ import kamkeel.npcs.controllers.data.ability.AnchorPoint; import kamkeel.npcs.controllers.data.ability.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.ability.data.*; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import kamkeel.npcs.controllers.data.telegraph.Telegraph; @@ -390,14 +389,20 @@ public class AbilityDiscDual extends Ability { public List getFieldDefinitions() { return Arrays.asList( // Type tab - FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage).column(ColumnHint.LEFT), - FieldDef.floatField("stats.speed", this::getSpeed, this::setSpeed).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.floatField("stats.speed", this::getSpeed, this::setSpeed) + ), FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback), FieldDef.section("ability.section.disc"), - FieldDef.floatField("gui.radius", this::getDiscRadius, this::setDiscRadius).column(ColumnHint.LEFT), - FieldDef.floatField("gui.thickness", this::getDiscThickness, this::setDiscThickness).column(ColumnHint.RIGHT), - FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance).column(ColumnHint.LEFT), - FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("gui.radius", this::getDiscRadius, this::setDiscRadius), + FieldDef.floatField("gui.thickness", this::getDiscThickness, this::setDiscThickness) + ), + FieldDef.row( + FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance), + FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime) + ), FieldDef.section("ability.section.dual"), FieldDef.boolField("ability.dualFire", this::isDualFire, this::setDualFire), FieldDef.intField("ability.dualFireDelay", this::getDualFireDelay, this::setDualFireDelay) @@ -432,24 +437,28 @@ public class AbilityDiscDual extends Ability { FieldDef.colorSubGui("ability.outerColor", () -> getOuterColor(0), v -> setOuterColor(0, v)) .tab("ability.tab.visual").visibleWhen(() -> isOuterColorEnabled(0)), - FieldDef.floatField("ability.outerWidth", - () -> getOuterColorWidth(0), v -> setOuterColorWidth(0, v)) - .tab("ability.tab.visual").visibleWhen(() -> isOuterColorEnabled(0)).column(ColumnHint.LEFT), - FieldDef.floatField("ability.outerAlpha", - () -> getOuterColorAlpha(0), v -> setOuterColorAlpha(0, v)) - .tab("ability.tab.visual").range(0, 1).visibleWhen(() -> isOuterColorEnabled(0)).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.outerWidth", + () -> getOuterColorWidth(0), v -> setOuterColorWidth(0, v)) + .visibleWhen(() -> isOuterColorEnabled(0)), + FieldDef.floatField("ability.outerAlpha", + () -> getOuterColorAlpha(0), v -> setOuterColorAlpha(0, v)) + .range(0, 1).visibleWhen(() -> isOuterColorEnabled(0)) + ).tab("ability.tab.visual"), FieldDef.floatField("ability.rotationSpeed", () -> getRotationSpeed(0), v -> setRotationSpeed(0, v)) .tab("ability.tab.visual"), FieldDef.boolField("ability.lightning", () -> hasLightningEffect(0), v -> setLightningEffect(0, v)) .tab("ability.tab.visual"), - FieldDef.floatField("gui.density", - () -> getLightningDensity(0), v -> setLightningDensity(0, v)) - .tab("ability.tab.visual").range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(0)).column(ColumnHint.LEFT), - FieldDef.floatField("gui.radius", - () -> getLightningRadius(0), v -> setLightningRadius(0, v)) - .tab("ability.tab.visual").range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(0)).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("gui.density", + () -> getLightningDensity(0), v -> setLightningDensity(0, v)) + .range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(0)), + FieldDef.floatField("gui.radius", + () -> getLightningRadius(0), v -> setLightningRadius(0, v)) + .range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(0)) + ).tab("ability.tab.visual"), // Visual tab - Disc 2 FieldDef.enumField("ability.anchorPoint", AnchorPoint.class, () -> getAnchorPointEnum(1), v -> setAnchorPointEnum(1, v)) @@ -464,24 +473,28 @@ public class AbilityDiscDual extends Ability { FieldDef.colorSubGui("ability.outerColor", () -> getOuterColor(1), v -> setOuterColor(1, v)) .tab("ability.tab.visual").visibleWhen(() -> isOuterColorEnabled(1)), - FieldDef.floatField("ability.outerWidth", - () -> getOuterColorWidth(1), v -> setOuterColorWidth(1, v)) - .tab("ability.tab.visual").visibleWhen(() -> isOuterColorEnabled(1)).column(ColumnHint.LEFT), - FieldDef.floatField("ability.outerAlpha", - () -> getOuterColorAlpha(1), v -> setOuterColorAlpha(1, v)) - .tab("ability.tab.visual").range(0, 1).visibleWhen(() -> isOuterColorEnabled(1)).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.outerWidth", + () -> getOuterColorWidth(1), v -> setOuterColorWidth(1, v)) + .visibleWhen(() -> isOuterColorEnabled(1)), + FieldDef.floatField("ability.outerAlpha", + () -> getOuterColorAlpha(1), v -> setOuterColorAlpha(1, v)) + .range(0, 1).visibleWhen(() -> isOuterColorEnabled(1)) + ).tab("ability.tab.visual"), FieldDef.floatField("ability.rotationSpeed", () -> getRotationSpeed(1), v -> setRotationSpeed(1, v)) .tab("ability.tab.visual"), FieldDef.boolField("ability.lightning", () -> hasLightningEffect(1), v -> setLightningEffect(1, v)) .tab("ability.tab.visual"), - FieldDef.floatField("gui.density", - () -> getLightningDensity(1), v -> setLightningDensity(1, v)) - .tab("ability.tab.visual").range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(1)).column(ColumnHint.LEFT), - FieldDef.floatField("gui.radius", - () -> getLightningRadius(1), v -> setLightningRadius(1, v)) - .tab("ability.tab.visual").range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(1)).column(ColumnHint.RIGHT) + FieldDef.row( + FieldDef.floatField("gui.density", + () -> getLightningDensity(1), v -> setLightningDensity(1, v)) + .range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(1)), + FieldDef.floatField("gui.radius", + () -> getLightningRadius(1), v -> setLightningRadius(1, v)) + .range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(1)) + ).tab("ability.tab.visual") ); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java index 2918a4b08..03182d847 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java @@ -17,7 +17,6 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.Vec3; import net.minecraft.world.World; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import noppes.npcs.api.ability.type.IAbilityEnergyBeam; @@ -280,21 +279,29 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { public List getFieldDefinitions() { return Arrays.asList( // Type tab - FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage).column(ColumnHint.LEFT), - FieldDef.floatField("stats.speed", this::getSpeed, this::setSpeed).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.floatField("stats.speed", this::getSpeed, this::setSpeed) + ), FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback), FieldDef.section("ability.section.beam"), - FieldDef.floatField("ability.beamWidth", this::getBeamWidth, this::setBeamWidth).column(ColumnHint.LEFT), - FieldDef.floatField("ability.headSize", this::getHeadSize, this::setHeadSize).column(ColumnHint.RIGHT), - FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance).column(ColumnHint.LEFT), - FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.beamWidth", this::getBeamWidth, this::setBeamWidth), + FieldDef.floatField("ability.headSize", this::getHeadSize, this::setHeadSize) + ), + FieldDef.row( + FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance), + FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime) + ), FieldDef.section("ability.section.homing"), FieldDef.boolField("gui.enabled", this::isHoming, this::setHoming) .hover("ability.hover.homing"), - FieldDef.floatField("gui.strength", this::getHomingStrength, this::setHomingStrength) - .visibleWhen(this::isHoming).column(ColumnHint.LEFT), - FieldDef.floatField("gui.range", this::getHomingRange, this::setHomingRange) - .visibleWhen(this::isHoming).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("gui.strength", this::getHomingStrength, this::setHomingStrength) + .visibleWhen(this::isHoming), + FieldDef.floatField("gui.range", this::getHomingRange, this::setHomingRange) + .visibleWhen(this::isHoming) + ), FieldDef.section("ability.section.explosive"), FieldDef.boolField("gui.enabled", this::isExplosive, this::setExplosive) .hover("ability.hover.explosive"), @@ -311,19 +318,23 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { .tab("ability.tab.visual"), FieldDef.colorSubGui("ability.outerColor", this::getOuterColor, this::setOuterColor) .tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled), - FieldDef.floatField("ability.outerWidth", this::getOuterColorWidth, this::setOuterColorWidth) - .tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled).column(ColumnHint.LEFT), - FieldDef.floatField("ability.outerAlpha", this::getOuterColorAlpha, this::setOuterColorAlpha) - .tab("ability.tab.visual").range(0, 1).visibleWhen(this::isOuterColorEnabled).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.outerWidth", this::getOuterColorWidth, this::setOuterColorWidth) + .visibleWhen(this::isOuterColorEnabled), + FieldDef.floatField("ability.outerAlpha", this::getOuterColorAlpha, this::setOuterColorAlpha) + .range(0, 1).visibleWhen(this::isOuterColorEnabled) + ).tab("ability.tab.visual"), FieldDef.section("ability.section.effects").tab("ability.tab.visual"), FieldDef.floatField("ability.rotationSpeed", this::getRotationSpeed, this::setRotationSpeed) .tab("ability.tab.visual"), FieldDef.boolField("ability.lightning", this::hasLightningEffect, this::setLightningEffect) .tab("ability.tab.visual"), - FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity) - .tab("ability.tab.visual").range(0.01f, 5.0f).visibleWhen(this::hasLightningEffect).column(ColumnHint.LEFT), - FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) - .tab("ability.tab.visual").range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect).column(ColumnHint.RIGHT) + FieldDef.row( + FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity) + .range(0.01f, 5.0f).visibleWhen(this::hasLightningEffect), + FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) + .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) + ).tab("ability.tab.visual") ); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java index b545d32d9..9e420741f 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java @@ -13,7 +13,6 @@ import noppes.npcs.entity.EntityNPCInterface; import noppes.npcs.api.ability.type.IAbilityGuard; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; @@ -306,10 +305,12 @@ public class AbilityGuard extends Ability implements IAbilityGuard { FieldDef.boolField("gui.enabled", this::isCanCounter, this::setCanCounter).hover("ability.hover.canCounter"), FieldDef.enumField("gui.type", CounterType.class, this::getCounterTypeEnum, this::setCounterTypeEnum) .hover("ability.hover.counterType").visibleWhen(this::isCanCounter), - FieldDef.floatField("gui.value", this::getCounterValue, this::setCounterValue) - .visibleWhen(this::isCanCounter).column(ColumnHint.LEFT), - FieldDef.floatField("gui.chance", this::getCounterChance, this::setCounterChance) - .visibleWhen(this::isCanCounter).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("gui.value", this::getCounterValue, this::setCounterValue) + .visibleWhen(this::isCanCounter), + FieldDef.floatField("gui.chance", this::getCounterChance, this::setCounterChance) + .visibleWhen(this::isCanCounter) + ), FieldDef.stringField("gui.sound", this::getCounterSound, this::setCounterSound) .visibleWhen(this::isCanCounter), FieldDef.intField("gui.animation", this::getCounterAnimationId, this::setCounterAnimationId) diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHazard.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHazard.java index a5996d487..d98110faf 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHazard.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHazard.java @@ -16,7 +16,6 @@ import noppes.npcs.entity.EntityNPCInterface; import noppes.npcs.api.ability.type.IAbilityHazard; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; @@ -639,14 +638,20 @@ public class AbilityHazard extends Ability implements IAbilityHazard { FieldDef.enumField("ability.placement", PlacementMode.class, this::getPlacementEnum, this::setPlacementEnum) .hover("ability.hover.placement"), FieldDef.section("ability.section.area"), - FieldDef.floatField("gui.radius", this::getRadius, this::setRadius).column(ColumnHint.LEFT), - FieldDef.floatField("ability.innerRadius", this::getInnerRadius, this::setInnerRadius).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("gui.radius", this::getRadius, this::setRadius), + FieldDef.floatField("ability.innerRadius", this::getInnerRadius, this::setInnerRadius) + ), FieldDef.section("ability.section.damage"), - FieldDef.floatField("ability.damagePerSecond", this::getDamagePerSecond, this::setDamagePerSecond).column(ColumnHint.LEFT), - FieldDef.intField("ability.damageInterval", this::getDamageInterval, this::setDamageInterval).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.damagePerSecond", this::getDamagePerSecond, this::setDamagePerSecond), + FieldDef.intField("ability.damageInterval", this::getDamageInterval, this::setDamageInterval) + ), FieldDef.section("ability.section.debuffs"), - FieldDef.intField("ability.slownessLevel", this::getSlownessLevel, this::setSlownessLevel).column(ColumnHint.LEFT), - FieldDef.intField("ability.debuffDuration", this::getDebuffDuration, this::setDebuffDuration).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.intField("ability.slownessLevel", this::getSlownessLevel, this::setSlownessLevel), + FieldDef.intField("ability.debuffDuration", this::getDebuffDuration, this::setDebuffDuration) + ), FieldDef.intField("ability.poisonLevel", this::getPoisonLevel, this::setPoisonLevel), FieldDef.boolField("ability.affectsCaster", this::isAffectsCaster, this::setAffectsCaster) .hover("ability.hover.affectsCaster"), diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeal.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeal.java index 72f3813c3..ceb20a86c 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeal.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeal.java @@ -11,7 +11,6 @@ import net.minecraft.util.AxisAlignedBB; import net.minecraft.world.World; import noppes.npcs.entity.EntityNPCInterface; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import noppes.npcs.api.ability.type.IAbilityHeal; @@ -289,13 +288,17 @@ public class AbilityHeal extends Ability implements IAbilityHeal { FieldDef.intField("ability.duration", this::getDurationTicks, this::setDurationTicks) .range(1, 1000).visibleWhen(() -> !this.isInstantHeal()), FieldDef.section("ability.section.healing"), - FieldDef.floatField("ability.healAmount", this::getHealAmount, this::setHealAmount).column(ColumnHint.LEFT), - FieldDef.floatField("ability.healPercent", this::getHealPercent, this::setHealPercent).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.healAmount", this::getHealAmount, this::setHealAmount), + FieldDef.floatField("ability.healPercent", this::getHealPercent, this::setHealPercent) + ), FieldDef.floatField("ability.healRadius", this::getHealRadius, this::setHealRadius), - FieldDef.boolField("ability.healSelf", this::isHealSelf, this::setHealSelf) - .hover("ability.hover.healSelf").column(ColumnHint.LEFT), - FieldDef.boolField("ability.healAllies", this::isHealAllies, this::setHealAllies) - .hover("ability.hover.healAllies").column(ColumnHint.RIGHT) + FieldDef.row( + FieldDef.boolField("ability.healSelf", this::isHealSelf, this::setHealSelf) + .hover("ability.hover.healSelf"), + FieldDef.boolField("ability.healAllies", this::isHealAllies, this::setHealAllies) + .hover("ability.hover.healAllies") + ) ); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java index 8b6597b11..3db472c1a 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java @@ -9,7 +9,6 @@ import kamkeel.npcs.controllers.data.telegraph.TelegraphType; import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import noppes.npcs.api.ability.type.IAbilityHeavyHit; @@ -110,8 +109,10 @@ public class AbilityHeavyHit extends Ability implements IAbilityHeavyHit { @Override public List getFieldDefinitions() { return Arrays.asList( - FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage).column(ColumnHint.LEFT), - FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback) + ), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) ); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java index 39377a19d..b5d196cb5 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java @@ -7,7 +7,6 @@ import kamkeel.npcs.controllers.data.ability.AnchorPoint; import kamkeel.npcs.controllers.data.ability.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.ability.data.*; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; @@ -252,34 +251,45 @@ public class AbilityLaserShot extends Ability implements IAbilityLaserShot { return Arrays.asList( // Type tab FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), - FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback).column(ColumnHint.LEFT), - FieldDef.floatField("ability.knockbackUp", this::getKnockbackUp, this::setKnockbackUp).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback), + FieldDef.floatField("ability.knockbackUp", this::getKnockbackUp, this::setKnockbackUp) + ), FieldDef.section("ability.section.beam"), - FieldDef.floatField("ability.laserWidth", this::getLaserWidth, this::setLaserWidth).column(ColumnHint.LEFT), - FieldDef.floatField("ability.expansionSpeed", this::getExpansionSpeed, this::setExpansionSpeed).column(ColumnHint.RIGHT), - FieldDef.intField("ability.lingerTicks", this::getLingerTicks, this::setLingerTicks).column(ColumnHint.LEFT), - FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.laserWidth", this::getLaserWidth, this::setLaserWidth), + FieldDef.floatField("ability.expansionSpeed", this::getExpansionSpeed, this::setExpansionSpeed) + ), + FieldDef.row( + FieldDef.intField("ability.lingerTicks", this::getLingerTicks, this::setLingerTicks), + FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime) + ), FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance), FieldDef.section("ability.section.explosive"), FieldDef.boolField("gui.enabled", this::isExplosive, this::setExplosive).hover("ability.hover.explosive"), FieldDef.floatField("gui.radius", this::getExplosionRadius, this::setExplosionRadius).visibleWhen(this::isExplosive), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects), + // Visual tab FieldDef.section("ability.section.colors").tab("ability.tab.visual"), FieldDef.colorSubGui("ability.innerColor", this::getInnerColor, this::setInnerColor).tab("ability.tab.visual"), FieldDef.boolField("ability.outerEnabled", this::isOuterColorEnabled, this::setOuterColorEnabled).tab("ability.tab.visual"), FieldDef.colorSubGui("ability.outerColor", this::getOuterColor, this::setOuterColor) .tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled), - FieldDef.floatField("ability.outerWidth", this::getOuterColorWidth, this::setOuterColorWidth) - .tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled).column(ColumnHint.LEFT), - FieldDef.floatField("ability.outerAlpha", this::getOuterColorAlpha, this::setOuterColorAlpha) - .tab("ability.tab.visual").range(0, 1).visibleWhen(this::isOuterColorEnabled).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.outerWidth", this::getOuterColorWidth, this::setOuterColorWidth) + .visibleWhen(this::isOuterColorEnabled), + FieldDef.floatField("ability.outerAlpha", this::getOuterColorAlpha, this::setOuterColorAlpha) + .range(0, 1).visibleWhen(this::isOuterColorEnabled) + ).tab("ability.tab.visual"), FieldDef.section("ability.section.effects").tab("ability.tab.visual"), FieldDef.boolField("ability.lightning", this::hasLightningEffect, this::setLightningEffect).tab("ability.tab.visual"), - FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity) - .tab("ability.tab.visual").range(0.01f, 5.0f).visibleWhen(this::hasLightningEffect).column(ColumnHint.LEFT), - FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) - .tab("ability.tab.visual").range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect).column(ColumnHint.RIGHT) + FieldDef.row( + FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity) + .range(0.01f, 5.0f).visibleWhen(this::hasLightningEffect), + FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) + .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) + ).tab("ability.tab.visual") ); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java index e8e48a732..dcad556b6 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java @@ -17,7 +17,6 @@ import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.Vec3; import net.minecraft.world.World; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import noppes.npcs.api.ability.type.IAbilityOrb; @@ -416,12 +415,18 @@ public class AbilityOrb extends Ability implements IAbilityOrb { public List getFieldDefinitions() { return Arrays.asList( // Type tab - FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage).column(ColumnHint.LEFT), - FieldDef.floatField("stats.speed", this::getOrbSpeed, this::setOrbSpeed).column(ColumnHint.RIGHT), - FieldDef.floatField("stats.size", this::getOrbSize, this::setOrbSize).column(ColumnHint.LEFT), - FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback).column(ColumnHint.RIGHT), - FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance).column(ColumnHint.LEFT), - FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.floatField("stats.speed", this::getOrbSpeed, this::setOrbSpeed) + ), + FieldDef.row( + FieldDef.floatField("stats.size", this::getOrbSize, this::setOrbSize), + FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback) + ), + FieldDef.row( + FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance), + FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime) + ), FieldDef.section("ability.section.homing"), FieldDef.boolField("gui.enabled", this::isHoming, this::setHoming).hover("ability.hover.homing"), FieldDef.floatField("gui.strength", this::getHomingStrength, this::setHomingStrength).visibleWhen(this::isHoming), @@ -439,17 +444,21 @@ public class AbilityOrb extends Ability implements IAbilityOrb { FieldDef.boolField("ability.outerEnabled", this::isOuterColorEnabled, this::setOuterColorEnabled).tab("ability.tab.visual"), FieldDef.colorSubGui("ability.outerColor", this::getOuterColor, this::setOuterColor) .tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled), - FieldDef.floatField("ability.outerWidth", this::getOuterColorWidth, this::setOuterColorWidth) - .tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled).column(ColumnHint.LEFT), - FieldDef.floatField("ability.outerAlpha", this::getOuterColorAlpha, this::setOuterColorAlpha) - .tab("ability.tab.visual").range(0, 1).visibleWhen(this::isOuterColorEnabled).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.outerWidth", this::getOuterColorWidth, this::setOuterColorWidth) + .visibleWhen(this::isOuterColorEnabled), + FieldDef.floatField("ability.outerAlpha", this::getOuterColorAlpha, this::setOuterColorAlpha) + .range(0, 1).visibleWhen(this::isOuterColorEnabled) + ).tab("ability.tab.visual"), FieldDef.section("ability.section.effects").tab("ability.tab.visual"), FieldDef.floatField("ability.rotationSpeed", this::getRotationSpeed, this::setRotationSpeed).tab("ability.tab.visual"), FieldDef.boolField("ability.lightning", this::hasLightningEffect, this::setLightningEffect).tab("ability.tab.visual"), - FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity) - .tab("ability.tab.visual").range(0.01f, 5.0f).visibleWhen(this::hasLightningEffect).column(ColumnHint.LEFT), - FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) - .tab("ability.tab.visual").range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect).column(ColumnHint.RIGHT) + FieldDef.row( + FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity) + .range(0.01f, 5.0f).visibleWhen(this::hasLightningEffect), + FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) + .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) + ).tab("ability.tab.visual") ); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java index 658d4092f..1efa694ba 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java @@ -7,7 +7,6 @@ import kamkeel.npcs.controllers.data.ability.AnchorPoint; import kamkeel.npcs.controllers.data.ability.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.ability.data.*; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import kamkeel.npcs.controllers.data.telegraph.Telegraph; @@ -461,12 +460,18 @@ public class AbilityOrbDual extends Ability { public List getFieldDefinitions() { return Arrays.asList( // Type tab - FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage).column(ColumnHint.LEFT), - FieldDef.floatField("stats.speed", this::getOrbSpeed, this::setOrbSpeed).column(ColumnHint.RIGHT), - FieldDef.floatField("stats.size", this::getOrbSize, this::setOrbSize).column(ColumnHint.LEFT), - FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback).column(ColumnHint.RIGHT), - FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance).column(ColumnHint.LEFT), - FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.floatField("stats.speed", this::getOrbSpeed, this::setOrbSpeed) + ), + FieldDef.row( + FieldDef.floatField("stats.size", this::getOrbSize, this::setOrbSize), + FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback) + ), + FieldDef.row( + FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance), + FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime) + ), FieldDef.section("ability.section.dual"), FieldDef.boolField("ability.dualFire", this::isDualFire, this::setDualFire), FieldDef.intField("ability.dualFireDelay", this::getDualFireDelay, this::setDualFireDelay) @@ -492,24 +497,28 @@ public class AbilityOrbDual extends Ability { FieldDef.colorSubGui("ability.outerColor", () -> getOuterColor(0), v -> setOuterColor(0, v)) .tab("ability.tab.visual").visibleWhen(() -> isOuterColorEnabled(0)), - FieldDef.floatField("ability.outerWidth", - () -> getOuterColorWidth(0), v -> setOuterColorWidth(0, v)) - .tab("ability.tab.visual").visibleWhen(() -> isOuterColorEnabled(0)).column(ColumnHint.LEFT), - FieldDef.floatField("ability.outerAlpha", - () -> getOuterColorAlpha(0), v -> setOuterColorAlpha(0, v)) - .tab("ability.tab.visual").range(0, 1).visibleWhen(() -> isOuterColorEnabled(0)).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.outerWidth", + () -> getOuterColorWidth(0), v -> setOuterColorWidth(0, v)) + .visibleWhen(() -> isOuterColorEnabled(0)), + FieldDef.floatField("ability.outerAlpha", + () -> getOuterColorAlpha(0), v -> setOuterColorAlpha(0, v)) + .range(0, 1).visibleWhen(() -> isOuterColorEnabled(0)) + ).tab("ability.tab.visual"), FieldDef.floatField("ability.rotationSpeed", () -> getRotationSpeed(0), v -> setRotationSpeed(0, v)) .tab("ability.tab.visual"), FieldDef.boolField("ability.lightning", () -> hasLightningEffect(0), v -> setLightningEffect(0, v)) .tab("ability.tab.visual"), - FieldDef.floatField("gui.density", - () -> getLightningDensity(0), v -> setLightningDensity(0, v)) - .tab("ability.tab.visual").range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(0)).column(ColumnHint.LEFT), - FieldDef.floatField("gui.radius", - () -> getLightningRadius(0), v -> setLightningRadius(0, v)) - .tab("ability.tab.visual").range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(0)).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("gui.density", + () -> getLightningDensity(0), v -> setLightningDensity(0, v)) + .range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(0)), + FieldDef.floatField("gui.radius", + () -> getLightningRadius(0), v -> setLightningRadius(0, v)) + .range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(0)) + ).tab("ability.tab.visual"), // Visual tab - Orb 2 FieldDef.enumField("ability.anchorPoint", AnchorPoint.class, () -> getAnchorPointEnum(1), v -> setAnchorPointEnum(1, v)) @@ -524,24 +533,28 @@ public class AbilityOrbDual extends Ability { FieldDef.colorSubGui("ability.outerColor", () -> getOuterColor(1), v -> setOuterColor(1, v)) .tab("ability.tab.visual").visibleWhen(() -> isOuterColorEnabled(1)), - FieldDef.floatField("ability.outerWidth", - () -> getOuterColorWidth(1), v -> setOuterColorWidth(1, v)) - .tab("ability.tab.visual").visibleWhen(() -> isOuterColorEnabled(1)).column(ColumnHint.LEFT), - FieldDef.floatField("ability.outerAlpha", - () -> getOuterColorAlpha(1), v -> setOuterColorAlpha(1, v)) - .tab("ability.tab.visual").range(0, 1).visibleWhen(() -> isOuterColorEnabled(1)).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.outerWidth", + () -> getOuterColorWidth(1), v -> setOuterColorWidth(1, v)) + .visibleWhen(() -> isOuterColorEnabled(1)), + FieldDef.floatField("ability.outerAlpha", + () -> getOuterColorAlpha(1), v -> setOuterColorAlpha(1, v)) + .range(0, 1).visibleWhen(() -> isOuterColorEnabled(1)) + ).tab("ability.tab.visual"), FieldDef.floatField("ability.rotationSpeed", () -> getRotationSpeed(1), v -> setRotationSpeed(1, v)) .tab("ability.tab.visual"), FieldDef.boolField("ability.lightning", () -> hasLightningEffect(1), v -> setLightningEffect(1, v)) .tab("ability.tab.visual"), - FieldDef.floatField("gui.density", - () -> getLightningDensity(1), v -> setLightningDensity(1, v)) - .tab("ability.tab.visual").range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(1)).column(ColumnHint.LEFT), - FieldDef.floatField("gui.radius", - () -> getLightningRadius(1), v -> setLightningRadius(1, v)) - .tab("ability.tab.visual").range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(1)).column(ColumnHint.RIGHT) + FieldDef.row( + FieldDef.floatField("gui.density", + () -> getLightningDensity(1), v -> setLightningDensity(1, v)) + .range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(1)), + FieldDef.floatField("gui.radius", + () -> getLightningRadius(1), v -> setLightningRadius(1, v)) + .range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(1)) + ).tab("ability.tab.visual") ); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityProjectile.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityProjectile.java index 579887826..d8dd4aebc 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityProjectile.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityProjectile.java @@ -14,7 +14,6 @@ import noppes.npcs.entity.EntityNPCInterface; import noppes.npcs.api.ability.type.IAbilityProjectile; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; @@ -254,8 +253,10 @@ public class AbilityProjectile extends Ability implements IAbilityProjectile { @Override public List getFieldDefinitions() { return Arrays.asList( - FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage).column(ColumnHint.LEFT), - FieldDef.floatField("stats.speed", this::getSpeed, this::setSpeed).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.floatField("stats.speed", this::getSpeed, this::setSpeed) + ), FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback), FieldDef.stringEnumField("ability.projectileType", new String[]{"fireball", "arrow", "magic"}, this::getProjectileType, this::setProjectileType), FieldDef.section("ability.section.homing"), diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java index 626cc6fc5..b2c72ed24 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java @@ -13,7 +13,6 @@ import net.minecraft.util.DamageSource; import net.minecraft.world.World; import noppes.npcs.entity.EntityNPCInterface; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import noppes.npcs.api.ability.type.IAbilityShockwave; @@ -171,8 +170,10 @@ public class AbilityShockwave extends Ability implements IAbilityShockwave { return Arrays.asList( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), FieldDef.section("ability.section.push"), - FieldDef.floatField("gui.radius", this::getPushRadius, this::setPushRadius).column(ColumnHint.LEFT), - FieldDef.floatField("gui.strength", this::getPushStrength, this::setPushStrength).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("gui.radius", this::getPushRadius, this::setPushRadius), + FieldDef.floatField("gui.strength", this::getPushStrength, this::setPushStrength) + ), FieldDef.intField("ability.maxTargets", this::getMaxTargets, this::setMaxTargets), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) ); diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java index 7b4310030..94381209b 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java @@ -18,7 +18,6 @@ import noppes.npcs.entity.EntityNPCInterface; import noppes.npcs.api.ability.type.IAbilitySlam; import somehussar.gui.annotationHandling.GuiEditable; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import java.util.Arrays; @@ -578,11 +577,15 @@ public class AbilitySlam extends Ability implements IAbilitySlam { public List getFieldDefinitions() { return Arrays.asList( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), - FieldDef.floatField("gui.radius", this::getRadius, this::setRadius).column(ColumnHint.LEFT), - FieldDef.floatField("ability.knockback", this::getKnockbackStrength, this::setKnockbackStrength).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("gui.radius", this::getRadius, this::setRadius), + FieldDef.floatField("ability.knockback", this::getKnockbackStrength, this::setKnockbackStrength) + ), FieldDef.section("ability.section.leap"), - FieldDef.floatField("gui.speed", this::getLeapSpeed, this::setLeapSpeed).column(ColumnHint.LEFT), - FieldDef.floatField("gui.height", this::getLeapHeight, this::setLeapHeight).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("gui.speed", this::getLeapSpeed, this::setLeapSpeed), + FieldDef.floatField("gui.height", this::getLeapHeight, this::setLeapHeight) + ), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) ); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySweeper.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySweeper.java index aad2c47c2..e57c47e20 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySweeper.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySweeper.java @@ -6,7 +6,6 @@ import kamkeel.npcs.controllers.data.ability.Ability; import kamkeel.npcs.controllers.data.ability.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.ability.data.EnergyColorData; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import kamkeel.npcs.controllers.data.telegraph.Telegraph; @@ -203,18 +202,26 @@ public class AbilitySweeper extends Ability implements IAbilitySweeper { public List getFieldDefinitions() { return Arrays.asList( - FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage).column(ColumnHint.LEFT), - FieldDef.intField("ability.damageInterval", this::getDamageInterval, this::setDamageInterval).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.intField("ability.damageInterval", this::getDamageInterval, this::setDamageInterval) + ), FieldDef.section("ability.section.beam"), - FieldDef.floatField("gui.length", this::getBeamLength, this::setBeamLength).column(ColumnHint.LEFT), - FieldDef.floatField("gui.width", this::getBeamWidth, this::setBeamWidth).column(ColumnHint.RIGHT), - FieldDef.floatField("gui.height", this::getBeamHeight, this::setBeamHeight).column(ColumnHint.LEFT), - FieldDef.floatField("ability.sweepSpeed", this::getSweepSpeed, this::setSweepSpeed).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("gui.length", this::getBeamLength, this::setBeamLength), + FieldDef.floatField("gui.width", this::getBeamWidth, this::setBeamWidth) + ), + FieldDef.row( + FieldDef.floatField("gui.height", this::getBeamHeight, this::setBeamHeight), + FieldDef.floatField("ability.sweepSpeed", this::getSweepSpeed, this::setSweepSpeed) + ), FieldDef.intField("ability.rotations", this::getNumberOfRotations, this::setNumberOfRotations), - FieldDef.boolField("ability.piercing", this::isPiercing, this::setPiercing) - .hover("ability.hover.piercing").column(ColumnHint.LEFT), - FieldDef.boolField("ability.lockTarget", this::isLockOnTarget, this::setLockOnTarget) - .hover("ability.hover.lockTarget").column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.boolField("ability.piercing", this::isPiercing, this::setPiercing) + .hover("ability.hover.piercing"), + FieldDef.boolField("ability.lockTarget", this::isLockOnTarget, this::setLockOnTarget) + .hover("ability.hover.lockTarget") + ), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects), // Visual tab diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTeleport.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTeleport.java index 414586b80..528ddc025 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTeleport.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTeleport.java @@ -16,7 +16,6 @@ import noppes.npcs.entity.EntityNPCInterface; import noppes.npcs.api.ability.type.IAbilityTeleport; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; @@ -564,22 +563,28 @@ public class AbilityTeleport extends Ability implements IAbilityTeleport { FieldDef.enumField("ability.mode", TeleportMode.class, this::getModeEnum, this::setModeEnum), FieldDef.floatField("ability.blinkRadius", this::getBlinkRadius, this::setBlinkRadius) .visibleWhen(() -> this.getModeEnum() == TeleportMode.BLINK || this.getModeEnum() == TeleportMode.SINGLE), - FieldDef.intField("ability.blinkCount", this::getBlinkCount, this::setBlinkCount) - .visibleWhen(() -> this.getModeEnum() == TeleportMode.BLINK).column(ColumnHint.LEFT), - FieldDef.intField("ability.blinkDelay", this::getBlinkDelayTicks, this::setBlinkDelayTicks) - .visibleWhen(() -> this.getModeEnum() == TeleportMode.BLINK).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.intField("ability.blinkCount", this::getBlinkCount, this::setBlinkCount) + .visibleWhen(() -> this.getModeEnum() == TeleportMode.BLINK), + FieldDef.intField("ability.blinkDelay", this::getBlinkDelayTicks, this::setBlinkDelayTicks) + .visibleWhen(() -> this.getModeEnum() == TeleportMode.BLINK) + ), FieldDef.floatField("ability.behindDistance", this::getBehindDistance, this::setBehindDistance) .visibleWhen(() -> this.getModeEnum() == TeleportMode.BEHIND), FieldDef.boolField("ability.lineOfSight", this::isRequireLineOfSight, this::setRequireLineOfSight) .hover("ability.hover.lineOfSight") .visibleWhen(() -> this.getModeEnum() == TeleportMode.BLINK || this.getModeEnum() == TeleportMode.SINGLE), FieldDef.section("ability.section.damage"), - FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage).column(ColumnHint.LEFT), - FieldDef.floatField("gui.radius", this::getDamageRadius, this::setDamageRadius).column(ColumnHint.RIGHT), - FieldDef.boolField("ability.damageAtStart", this::isDamageAtStart, this::setDamageAtStart) - .hover("ability.hover.dmgAtStart").column(ColumnHint.LEFT), - FieldDef.boolField("ability.damageAtEnd", this::isDamageAtEnd, this::setDamageAtEnd) - .hover("ability.hover.dmgAtEnd").column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.floatField("gui.radius", this::getDamageRadius, this::setDamageRadius) + ), + FieldDef.row( + FieldDef.boolField("ability.damageAtStart", this::isDamageAtStart, this::setDamageAtStart) + .hover("ability.hover.dmgAtStart"), + FieldDef.boolField("ability.damageAtEnd", this::isDamageAtEnd, this::setDamageAtEnd) + .hover("ability.hover.dmgAtEnd") + ), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) ); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTrap.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTrap.java index 65673f861..c4f371056 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTrap.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTrap.java @@ -14,7 +14,6 @@ import noppes.npcs.entity.EntityNPCInterface; import noppes.npcs.api.ability.type.IAbilityTrap; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; @@ -476,13 +475,19 @@ public class AbilityTrap extends Ability implements IAbilityTrap { FieldDef.enumField("ability.placement", TrapPlacement.class, this::getPlacementEnum, this::setPlacementEnum) .hover("ability.hover.placement"), FieldDef.section("ability.section.trigger"), - FieldDef.floatField("gui.radius", this::getTriggerRadius, this::setTriggerRadius).column(ColumnHint.LEFT), - FieldDef.intField("ability.armTime", this::getArmTime, this::setArmTime).column(ColumnHint.RIGHT), - FieldDef.intField("ability.maxTriggers", this::getMaxTriggers, this::setMaxTriggers).column(ColumnHint.LEFT), - FieldDef.intField("ability.triggerCooldown", this::getTriggerCooldown, this::setTriggerCooldown).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("gui.radius", this::getTriggerRadius, this::setTriggerRadius), + FieldDef.intField("ability.armTime", this::getArmTime, this::setArmTime) + ), + FieldDef.row( + FieldDef.intField("ability.maxTriggers", this::getMaxTriggers, this::setMaxTriggers), + FieldDef.intField("ability.triggerCooldown", this::getTriggerCooldown, this::setTriggerCooldown) + ), FieldDef.section("ability.section.damage"), - FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage).column(ColumnHint.LEFT), - FieldDef.floatField("gui.radius", this::getDamageRadius, this::setDamageRadius).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.floatField("gui.radius", this::getDamageRadius, this::setDamageRadius) + ), FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) ); diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java index 0df622235..6c92304e2 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java @@ -10,7 +10,6 @@ import net.minecraft.util.AxisAlignedBB; import net.minecraft.world.World; import noppes.npcs.entity.EntityNPCInterface; -import noppes.npcs.client.gui.builder.ColumnHint; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import noppes.npcs.api.ability.type.IAbilityVortex; @@ -304,11 +303,15 @@ public class AbilityVortex extends Ability implements IAbilityVortex { @Override public List getFieldDefinitions() { return Arrays.asList( - FieldDef.floatField("ability.pullRadius", this::getPullRadius, this::setPullRadius).column(ColumnHint.LEFT), - FieldDef.floatField("ability.pullStrength", this::getPullStrength, this::setPullStrength).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("ability.pullRadius", this::getPullRadius, this::setPullRadius), + FieldDef.floatField("ability.pullStrength", this::getPullStrength, this::setPullStrength) + ), FieldDef.section("ability.section.damage"), - FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage).column(ColumnHint.LEFT), - FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback).column(ColumnHint.RIGHT), + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback) + ), FieldDef.section("ability.section.aoe"), FieldDef.boolField("gui.enabled", this::isAoe, this::setAoe) .hover("ability.hover.aoe"), diff --git a/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java b/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java index 6954b36f1..60c3561b3 100644 --- a/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java +++ b/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java @@ -1,11 +1,9 @@ package noppes.npcs.client.gui.advanced; import kamkeel.npcs.controllers.data.ability.Ability; -import kamkeel.npcs.controllers.data.ability.AbilityEffect; import kamkeel.npcs.controllers.data.ability.Condition; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldBuilder; import noppes.npcs.client.gui.builder.FieldDef; -import noppes.npcs.client.gui.builder.FieldType; import net.minecraft.client.gui.GuiButton; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.StatCollector; @@ -55,7 +53,6 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi private int editingConditionIndex = -1; private AbilityFieldBuilder builder; - private FieldDef activeSubGuiField = null; // Scroll position preservation per tab private float[] tabScrollY; @@ -263,7 +260,6 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi // ═══════════════════════════════════════════════════════════════════════════ @Override - @SuppressWarnings({"unchecked", "rawtypes"}) public void buttonEvent(GuiButton guibutton) { int id = guibutton.id; @@ -281,6 +277,22 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi if (id == -1000) { close(); return; } // Condition buttons (50-80) + if (handleConditionButton(id)) return; + + // Declarative field handling (effects list, booleans, enums, sub-guis, clear buttons) + if (builder.handleButtonEvent(id, guibutton)) { + // SUB_GUI needs special handling: open the sub-gui + FieldDef subGuiDef = builder.getActiveSubGuiField(); + if (subGuiDef != null && subGuiDef.getSubGuiFactory() != null) { + setSubGui(subGuiDef.getSubGuiFactory().get()); + } else { + initGui(); + } + return; + } + } + + private boolean handleConditionButton(int id) { if (id >= 50 && id < 80) { int condIndex = (id - 50) / 10; int action = (id - 50) % 10; @@ -295,109 +307,16 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi initGui(); } } - return; + return true; } if (id == 80) { if (conditions.size() < 3) { editingConditionIndex = conditions.size(); setSubGui(new SubGuiConditionEdit(null)); } - return; - } - - // Clear buttons (effects delete or SUB_GUI clear) - if (id >= CLEAR_ID_START) { - // Check effects list delete first - int[] meta = builder.getEffectWidgetMeta().get(id); - if (meta != null && meta[1] == 3) { - FieldDef def = builder.getClearFieldMap().get(id); - if (def != null && def.getType() == FieldType.EFFECTS_LIST) { - handleEffectButton(def, meta, guibutton); - return; - } - } - // SUB_GUI clear - FieldDef def = builder.getClearFieldMap().get(id); - if (def != null && def.hasClearAction()) { - def.getClearAction().run(); - initGui(); - } - return; - } - - // Declarative field buttons - if (id >= DECLARATIVE_ID_START) { - FieldDef def = builder.getButtonFieldMap().get(id); - if (def == null) return; - - // Effects list buttons (type, amp, add) - int[] meta = builder.getEffectWidgetMeta().get(id); - if (meta != null && def.getType() == FieldType.EFFECTS_LIST) { - handleEffectButton(def, meta, guibutton); - return; - } - - switch (def.getType()) { - case BOOLEAN: - def.setValue(((GuiNpcButton) guibutton).getValue() == 1); - initGui(); - break; - case ENUM: { - int idx = ((GuiNpcButton) guibutton).getValue(); - Class> ec = def.getEnumClass(); - if (ec != null) { - Enum[] constants = ec.getEnumConstants(); - if (idx >= 0 && idx < constants.length) def.setValue(constants[idx]); - } - initGui(); - break; - } - case STRING_ENUM: { - int idx = ((GuiNpcButton) guibutton).getValue(); - String[] values = def.getStringEnumValues(); - if (values != null && idx >= 0 && idx < values.length) def.setStringEnumValue(values[idx]); - initGui(); - break; - } - case SUB_GUI: - activeSubGuiField = def; - if (def.getSubGuiFactory() != null) setSubGui(def.getSubGuiFactory().get()); - break; - } - } - } - - @SuppressWarnings("unchecked") - private void handleEffectButton(FieldDef def, int[] meta, GuiButton btn) { - List effects = (List) def.getValue(); - if (effects == null) return; - int effectIdx = meta[0]; - int action = meta[1]; - - switch (action) { - case 0: // Type changed - if (effectIdx < effects.size()) { - effects.get(effectIdx).setType(AbilityEffect.EffectType.fromOrdinal(((GuiNpcButton) btn).getValue())); - } - break; - case 2: // Amp changed - if (effectIdx < effects.size()) { - effects.get(effectIdx).setAmplifier(((GuiNpcButton) btn).getValue()); - } - break; - case 3: // Delete - if (effectIdx < effects.size()) { - effects.remove(effectIdx); - initGui(); - } - break; - case 4: // Add - if (effects.size() < 5) { - effects.add(new AbilityEffect(AbilityEffect.EffectType.SLOWNESS, 60, 0)); - initGui(); - } - break; + return true; } + return false; } // ═══════════════════════════════════════════════════════════════════════════ @@ -405,38 +324,9 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi // ═══════════════════════════════════════════════════════════════════════════ @Override - @SuppressWarnings("unchecked") public void unFocused(GuiNpcTextField textField) { - int id = textField.id; - if (id < DECLARATIVE_ID_START) return; - - // Check effects list duration fields - int[] meta = builder.getEffectWidgetMeta().get(id); - if (meta != null && meta[1] == 1) { - FieldDef def = builder.getTextFieldMap().get(id); - if (def != null && def.getType() == FieldType.EFFECTS_LIST) { - List effects = (List) def.getValue(); - if (effects != null && meta[0] < effects.size()) { - effects.get(meta[0]).setDurationTicks(textField.getInteger()); - } - return; - } - } - - FieldDef def = builder.getTextFieldMap().get(id); - if (def == null) return; - - switch (def.getType()) { - case FLOAT: - try { def.setValue(Float.parseFloat(textField.getText())); } catch (NumberFormatException ignored) {} - break; - case INT: - try { def.setValue(Integer.parseInt(textField.getText())); } catch (NumberFormatException ignored) {} - break; - case STRING: - def.setValue(textField.getText()); - break; - } + if (textField.id < DECLARATIVE_ID_START) return; + builder.handleTextFieldEvent(textField.id, textField); } // ═══════════════════════════════════════════════════════════════════════════ @@ -445,12 +335,7 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi @Override public void subGuiClosed(SubGuiInterface subgui) { - if (activeSubGuiField != null) { - FieldDef def = activeSubGuiField; - activeSubGuiField = null; - if (def.getSubGuiResultHandler() != null) { - def.getSubGuiResultHandler().accept(subgui); - } + if (builder.handleSubGuiClosed(subgui)) { initGui(); return; } diff --git a/src/main/java/noppes/npcs/client/gui/builder/ColumnHint.java b/src/main/java/noppes/npcs/client/gui/builder/ColumnHint.java deleted file mode 100644 index c076b6e6d..000000000 --- a/src/main/java/noppes/npcs/client/gui/builder/ColumnHint.java +++ /dev/null @@ -1,11 +0,0 @@ -package noppes.npcs.client.gui.builder; - -import cpw.mods.fml.relauncher.Side; -import cpw.mods.fml.relauncher.SideOnly; - -@SideOnly(Side.CLIENT) -public enum ColumnHint { - FULL, - LEFT, - RIGHT -} diff --git a/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java b/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java index c632f85a2..63f188d44 100644 --- a/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java +++ b/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java @@ -24,12 +24,10 @@ public class FieldDef { private final String label; private final FieldType type; private String tab = null; - private ColumnHint column = ColumnHint.FULL; private Supplier getter; private Consumer setter; private BooleanSupplier visibleWhen = () -> true; private BooleanSupplier enabledWhen = () -> true; - private String tooltip = null; private String hoverText = null; // Numeric range @@ -51,6 +49,10 @@ public class FieldDef { private Supplier buttonTextColorSupplier; private Runnable clearAction; + // Row pairing (ROW type only) + private FieldDef leftChild; + private FieldDef rightChild; + private FieldDef(String label, FieldType type) { this.label = label; this.type = type; @@ -134,6 +136,17 @@ public class FieldDef { return def; } + /** + * Creates a two-column row pairing two fields side by side. + * If one child is hidden (via visibleWhen), the other renders full-width. + */ + public static FieldDef row(FieldDef left, FieldDef right) { + FieldDef def = new FieldDef("", FieldType.ROW); + def.leftChild = left; + def.rightChild = right; + return def; + } + // ═══════════════════════════════════════════════════════════════════ // CONVENIENCE FACTORIES (SUB_GUI wrappers) // ═══════════════════════════════════════════════════════════════════ @@ -206,11 +219,6 @@ public class FieldDef { return this; } - public FieldDef column(ColumnHint column) { - this.column = column; - return this; - } - public FieldDef visibleWhen(BooleanSupplier condition) { this.visibleWhen = condition; return this; @@ -221,11 +229,6 @@ public class FieldDef { return this; } - public FieldDef tooltip(String tooltip) { - this.tooltip = tooltip; - return this; - } - public FieldDef hover(String hoverText) { this.hoverText = hoverText; return this; @@ -253,10 +256,8 @@ public class FieldDef { public String getLabel() { return label; } public FieldType getType() { return type; } public String getTab() { return tab; } - public ColumnHint getColumn() { return column; } public boolean isVisible() { return visibleWhen.getAsBoolean(); } public boolean isEnabled() { return enabledWhen.getAsBoolean(); } - public String getTooltip() { return tooltip; } public String getHoverText() { return hoverText; } public float getMin() { return min; } public float getMax() { return max; } @@ -293,4 +294,7 @@ public class FieldDef { return buttonTextColorSupplier != null ? buttonTextColorSupplier.get() : null; } + public FieldDef getLeftChild() { return leftChild; } + public FieldDef getRightChild() { return rightChild; } + } diff --git a/src/main/java/noppes/npcs/client/gui/builder/FieldType.java b/src/main/java/noppes/npcs/client/gui/builder/FieldType.java index e348f6f0b..052e2f4cd 100644 --- a/src/main/java/noppes/npcs/client/gui/builder/FieldType.java +++ b/src/main/java/noppes/npcs/client/gui/builder/FieldType.java @@ -14,5 +14,6 @@ public enum FieldType { STRING, SECTION_HEADER, LABEL, - EFFECTS_LIST + EFFECTS_LIST, + ROW } diff --git a/src/main/java/noppes/npcs/client/gui/builder/GuiFieldBuilder.java b/src/main/java/noppes/npcs/client/gui/builder/GuiFieldBuilder.java index 02af4c3da..43a3956c1 100644 --- a/src/main/java/noppes/npcs/client/gui/builder/GuiFieldBuilder.java +++ b/src/main/java/noppes/npcs/client/gui/builder/GuiFieldBuilder.java @@ -3,6 +3,7 @@ package noppes.npcs.client.gui.builder; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiButton; import net.minecraft.util.StatCollector; import noppes.npcs.client.gui.util.GuiNPCInterface; import noppes.npcs.client.gui.util.GuiNpcButton; @@ -10,6 +11,7 @@ import noppes.npcs.client.gui.util.GuiNpcButtonYesNo; import noppes.npcs.client.gui.util.GuiNpcLabel; import noppes.npcs.client.gui.util.GuiNpcTextField; import noppes.npcs.client.gui.util.GuiScrollWindow; +import noppes.npcs.client.gui.util.SubGuiInterface; import java.util.HashMap; import java.util.List; @@ -19,8 +21,8 @@ import java.util.Map; * General-purpose builder that converts a list of {@link FieldDef} into positioned * GUI widgets inside a {@link GuiScrollWindow}. *

- * Supports 1-column and 2-column layouts. Subclasses can override {@link #buildField} - * to handle custom field types. + * Uses {@link FieldDef#row(FieldDef, FieldDef)} for two-column layouts. + * Subclasses can override {@link #buildField} to handle custom field types. */ @SideOnly(Side.CLIENT) public class GuiFieldBuilder { @@ -36,9 +38,6 @@ public class GuiFieldBuilder { protected int rowHeight = 24; protected int labelPadding = 8; - // Column mode - protected int columnCount = 2; - // Dependencies protected final GuiNPCInterface parent; protected GuiScrollWindow sw; @@ -71,7 +70,6 @@ public class GuiFieldBuilder { // ═══════════════════════════════════════════════════════════════════ public GuiFieldBuilder scrollWindowId(int id) { this.scrollWindowId = id; return this; } - public GuiFieldBuilder columns(int count) { this.columnCount = Math.max(1, Math.min(2, count)); return this; } public GuiFieldBuilder contentRight(int v) { this.contentRight = v; return this; } public GuiFieldBuilder startIds(int widget, int clear, int label) { this.widgetId = widget; this.clearId = clear; this.labelId = label; return this; @@ -125,38 +123,37 @@ public class GuiFieldBuilder { // Section header if (def.getType() == FieldType.SECTION_HEADER) { y += 3; - String sectionText = StatCollector.translateToLocal(def.getLabel()); - if (def.getTooltip() != null && !def.getTooltip().isEmpty()) { - sectionText += " (" + StatCollector.translateToLocal(def.getTooltip()) + ")"; + GuiNpcLabel sectionLabel = new GuiNpcLabel(labelId++, def.getLabel(), colLLabel, y + 2, 0xFFFF55); + if (def.getHoverText() != null && !def.getHoverText().isEmpty()) { + sectionLabel.setHoverText(def.getHoverText()); } - sw.addLabel(new GuiNpcLabel(labelId++, sectionText, colLLabel, y + 2, 0xFFFF55)); + sw.addLabel(sectionLabel); y += 15; continue; } - // Two-column pair: LEFT followed by RIGHT (only in 2-column mode) - if (columnCount == 2 - && def.getColumn() == ColumnHint.LEFT - && i + 1 < fields.size() - && fields.get(i + 1).getColumn() == ColumnHint.RIGHT - && fields.get(i + 1).getType() != FieldType.SECTION_HEADER) { - renderFieldAt(def, colLLabel, colLField, colLWidth, y); + // ROW: explicit two-column pair + if (def.getType() == FieldType.ROW) { + FieldDef left = def.getLeftChild(); + FieldDef right = def.getRightChild(); + boolean leftVis = left != null && left.isVisible(); + boolean rightVis = right != null && right.isVisible(); - i++; - FieldDef rightDef = fields.get(i); - renderFieldAt(rightDef, colRLabel, colRField, colRWidth, y); - - y += rowHeight; - } else { - // Full-width: compute fieldX from label pixel width - int fieldW = getFullFieldWidth(def); - String translated = StatCollector.translateToLocal(def.getLabel()); - int labelW = fontRenderer.getStringWidth(translated); - int fieldX = colLLabel + labelW + labelPadding; - - renderFieldAt(def, colLLabel, fieldX, fieldW, y); - y += rowHeight; + if (leftVis && rightVis) { + renderFieldAt(left, colLLabel, colLField, colLWidth, y); + renderFieldAt(right, colRLabel, colRField, colRWidth, y); + } else if (leftVis) { + renderFullWidth(left, y); + } else if (rightVis) { + renderFullWidth(right, y); + } + if (leftVis || rightVis) y += rowHeight; + continue; } + + // Full-width field + renderFullWidth(def, y); + y += rowHeight; } lastBuildY = y; @@ -182,9 +179,12 @@ public class GuiFieldBuilder { @SuppressWarnings({"unchecked", "rawtypes"}) protected void renderFieldAt(FieldDef def, int labelX, int fieldX, int fieldW, int y) { - sw.addLabel(new GuiNpcLabel(labelId++, def.getLabel(), labelX, y + 5, 0xFFFFFF)); - - String hover = def.getHoverText() != null ? def.getHoverText() : def.getTooltip(); + GuiNpcLabel fieldLabel = new GuiNpcLabel(labelId++, def.getLabel(), labelX, y + 5, 0xFFFFFF); + String hover = def.getHoverText(); + if (hover != null && !hover.isEmpty()) { + fieldLabel.setHoverText(hover); + } + sw.addLabel(fieldLabel); switch (def.getType()) { case FLOAT: { @@ -307,6 +307,14 @@ public class GuiFieldBuilder { } } + private void renderFullWidth(FieldDef def, int y) { + int fieldW = getFullFieldWidth(def); + String translated = StatCollector.translateToLocal(def.getLabel()); + int labelW = fontRenderer.getStringWidth(translated); + int fieldX = colLLabel + labelW + labelPadding; + renderFieldAt(def, colLLabel, fieldX, fieldW, y); + } + protected int getFullFieldWidth(FieldDef def) { switch (def.getType()) { case FLOAT: @@ -321,6 +329,109 @@ public class GuiFieldBuilder { } } + // ═══════════════════════════════════════════════════════════════════ + // EVENT HANDLING + // ═══════════════════════════════════════════════════════════════════ + + private FieldDef activeSubGuiField; + + /** + * Handles button events for declarative fields. + * Call from parent GUI's buttonEvent(). Returns true if the event was handled. + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + public boolean handleButtonEvent(int buttonId, GuiButton button) { + // Check clear buttons first + if (clearFieldMap.containsKey(buttonId)) { + FieldDef def = clearFieldMap.get(buttonId); + if (def != null && def.hasClearAction()) { + def.getClearAction().run(); + return true; + } + } + + // Check field buttons + FieldDef def = buttonFieldMap.get(buttonId); + if (def == null) return false; + + switch (def.getType()) { + case BOOLEAN: + def.setValue(((GuiNpcButton) button).getValue() == 1); + return true; + case ENUM: { + int idx = ((GuiNpcButton) button).getValue(); + Class> ec = def.getEnumClass(); + if (ec != null) { + Enum[] constants = ec.getEnumConstants(); + if (idx >= 0 && idx < constants.length) def.setValue(constants[idx]); + } + return true; + } + case STRING_ENUM: { + int idx = ((GuiNpcButton) button).getValue(); + String[] values = def.getStringEnumValues(); + if (values != null && idx >= 0 && idx < values.length) def.setStringEnumValue(values[idx]); + return true; + } + case SUB_GUI: + activeSubGuiField = def; + return true; + default: + return false; + } + } + + /** + * Handles text field unfocus events for declarative fields. + * Call from parent GUI's unFocused(). Returns true if the event was handled. + */ + public boolean handleTextFieldEvent(int textFieldId, GuiNpcTextField field) { + FieldDef def = textFieldMap.get(textFieldId); + if (def == null) return false; + + switch (def.getType()) { + case FLOAT: + try { def.setValue(Float.parseFloat(field.getText())); } catch (NumberFormatException ignored) {} + return true; + case INT: + try { def.setValue(Integer.parseInt(field.getText())); } catch (NumberFormatException ignored) {} + return true; + case STRING: + def.setValue(field.getText()); + return true; + default: + return false; + } + } + + /** + * Handles sub-gui close events. Call from parent GUI's subGuiClosed(). + * Returns true if the event was handled (activeSubGuiField was set). + */ + public boolean handleSubGuiClosed(SubGuiInterface subgui) { + if (activeSubGuiField != null) { + FieldDef def = activeSubGuiField; + activeSubGuiField = null; + if (def.getSubGuiResultHandler() != null) { + def.getSubGuiResultHandler().accept(subgui); + } + return true; + } + return false; + } + + /** + * Returns the FieldDef for the currently active sub-gui, or null. + * After handleButtonEvent returns true for a SUB_GUI field, the parent + * should check this and call setSubGui(def.getSubGuiFactory().get()). + */ + public FieldDef getActiveSubGuiField() { return activeSubGuiField; } + + /** + * Clears the active sub-gui field tracking. + */ + public void clearActiveSubGuiField() { activeSubGuiField = null; } + // ═══════════════════════════════════════════════════════════════════ // GETTERS // ═══════════════════════════════════════════════════════════════════ diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiNpcLabel.java b/src/main/java/noppes/npcs/client/gui/util/GuiNpcLabel.java index f620e1e63..60b4afdb6 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiNpcLabel.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiNpcLabel.java @@ -1,18 +1,32 @@ package noppes.npcs.client.gui.util; +import kamkeel.npcs.util.TextSplitter; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.RenderHelper; import net.minecraft.util.StatCollector; import noppes.npcs.client.CustomNpcResourceListener; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL12; -public class GuiNpcLabel { +import java.util.Iterator; +import java.util.List; + +public class GuiNpcLabel extends Gui { public String label; public int x, y, color; public boolean enabled = true; public int id; public boolean drawShadow = false; + // Hover text support + public String hoverableText = ""; + private boolean wasHovered = false; + private int hoverCount = 0; + public GuiNpcLabel(int id, Object label, int x, int y, int color) { this.id = id; this.label = StatCollector.translateToLocal(label.toString()); @@ -25,6 +39,10 @@ public class GuiNpcLabel { this(id, label, x, y, CustomNpcResourceListener.DefaultTextColor); } + public void setHoverText(String text) { + this.hoverableText = text; + } + public void drawLabel(GuiScreen gui, FontRenderer fontRenderer) { if (enabled) fontRenderer.drawString(label, x, y, color, drawShadow); @@ -34,4 +52,119 @@ public class GuiNpcLabel { int size = Minecraft.getMinecraft().fontRenderer.getStringWidth(label); x += (width - size) / 2; } + + public boolean isMouseOver(int mouseX, int mouseY, FontRenderer fr) { + int width = fr.getStringWidth(label); + return mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + 10; + } + + /** + * Draws hover tooltip if the mouse is over this label. + * @param localMouseX Mouse X in scroll-local coordinates (for hit testing) + * @param localMouseY Mouse Y in scroll-local coordinates (for hit testing) + * @param screenMouseX Mouse X in screen coordinates (for tooltip positioning) + * @param screenMouseY Mouse Y in screen coordinates (for tooltip positioning) + * @param hasSubGui Whether a sub-gui is open + * @param fr FontRenderer for measuring label width + */ + public void drawHover(int localMouseX, int localMouseY, int screenMouseX, int screenMouseY, boolean hasSubGui, FontRenderer fr) { + if (hasSubGui || hoverableText.isEmpty()) return; + + boolean hovered = isMouseOver(localMouseX, localMouseY, fr); + if (!hovered) { + wasHovered = false; + hoverCount = 0; + return; + } + if (!wasHovered) { + wasHovered = true; + hoverCount = 0; + } + if (hoverCount < 65) hoverCount++; + + if (hoverCount > 60) { + GL11.glPushMatrix(); + Minecraft mc = Minecraft.getMinecraft(); + String displayString = StatCollector.translateToLocal(hoverableText); + GL11.glColor4f(1, 1, 1, 1); + List lines = TextSplitter.splitText(displayString, 30); + drawHoveringText(lines, screenMouseX, screenMouseY, mc); + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glPopMatrix(); + } + } + + @SuppressWarnings("rawtypes") + protected void drawHoveringText(List textLines, int x, int y, Minecraft mc) { + if (mc.fontRenderer == null || textLines.isEmpty()) + return; + GL11.glDisable(GL12.GL_RESCALE_NORMAL); + RenderHelper.disableStandardItemLighting(); + GL11.glDisable(GL11.GL_LIGHTING); + GL11.glDisable(GL11.GL_DEPTH_TEST); + + int maxWidth = 0; + Iterator iterator = textLines.iterator(); + while (iterator.hasNext()) { + String s = (String) iterator.next(); + int lineWidth = mc.fontRenderer.getStringWidth(s); + if (lineWidth > maxWidth) { + maxWidth = lineWidth; + } + } + + int j2 = x + 12; + int k2 = y - 12; + int maxHeight = 8; + + if (textLines.size() > 1) { + maxHeight += 2 + (textLines.size() - 1) * 10; + } + + ScaledResolution scaledRes = new ScaledResolution(mc, mc.displayWidth, mc.displayHeight); + int screenWidth = scaledRes.getScaledWidth(); + int screenHeight = scaledRes.getScaledHeight(); + + if (j2 + maxWidth + 6 > screenWidth) { + j2 = x - maxWidth - 16; + } + if (j2 < 4) { + j2 = 4; + } + if (k2 + maxHeight + 6 > screenHeight) { + k2 = screenHeight - maxHeight - 6; + } + if (k2 < 4) { + k2 = 4; + } + + this.zLevel = 300.0F; + int j1 = -267386864; + this.drawGradientRect(j2 - 3, k2 - 4, j2 + maxWidth + 3, k2 - 3, j1, j1); + this.drawGradientRect(j2 - 3, k2 + maxHeight + 3, j2 + maxWidth + 3, k2 + maxHeight + 4, j1, j1); + this.drawGradientRect(j2 - 3, k2 - 3, j2 + maxWidth + 3, k2 + maxHeight + 3, j1, j1); + this.drawGradientRect(j2 - 4, k2 - 3, j2 - 3, k2 + maxHeight + 3, j1, j1); + this.drawGradientRect(j2 + maxWidth + 3, k2 - 3, j2 + maxWidth + 4, k2 + maxHeight + 3, j1, j1); + int k1 = 1347420415; + int l1 = (k1 & 16711422) >> 1 | k1 & -16777216; + this.drawGradientRect(j2 - 3, k2 - 3 + 1, j2 - 3 + 1, k2 + maxHeight + 3 - 1, k1, l1); + this.drawGradientRect(j2 + maxWidth + 2, k2 - 3 + 1, j2 + maxWidth + 3, k2 + maxHeight + 3 - 1, k1, l1); + this.drawGradientRect(j2 - 3, k2 - 3, j2 + maxWidth + 3, k2 - 3 + 1, k1, k1); + this.drawGradientRect(j2 - 3, k2 + maxHeight + 2, j2 + maxWidth + 3, k2 + maxHeight + 3, l1, l1); + + for (int i2 = 0; i2 < textLines.size(); ++i2) { + String s1 = (String) textLines.get(i2); + mc.fontRenderer.drawStringWithShadow(s1, j2, k2, -1); + if (i2 == 0) { + k2 += 2; + } + k2 += 10; + } + + this.zLevel = 0.0F; + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_DEPTH_TEST); + RenderHelper.enableStandardItemLighting(); + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + } } diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiScrollWindow.java b/src/main/java/noppes/npcs/client/gui/util/GuiScrollWindow.java index fa33a9a09..ab6e612d4 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiScrollWindow.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiScrollWindow.java @@ -300,6 +300,14 @@ public class GuiScrollWindow extends GuiScreen implements ITextfieldListener, IC button.drawHover(mouseX, mouseY, subGui); } } + // Label hover: convert screen mouse to scroll-local coords for hit testing + int localMouseX = mouseX - xPos; + int localMouseY = (int) (mouseY - yPos + scrollY); + for (GuiNpcLabel label : labels.values()) { + if (!label.hoverableText.isEmpty()) { + label.drawHover(localMouseX, localMouseY, mouseX, mouseY, subGui, fontRendererObj); + } + } } public void elementClicked() { diff --git a/src/main/resources/assets/customnpcs/lang/en_US.lang b/src/main/resources/assets/customnpcs/lang/en_US.lang index 8f5af1340..a95b71f67 100644 --- a/src/main/resources/assets/customnpcs/lang/en_US.lang +++ b/src/main/resources/assets/customnpcs/lang/en_US.lang @@ -1698,6 +1698,7 @@ gui.sound=Sound gui.animation=Animation gui.duration=Duration gui.amp=Amp +gui.speed=Speed # Common Type Settings ability.radius=Radius @@ -1735,9 +1736,13 @@ ability.firingSpeed=Firing Speed ability.amount=Amount ability.dualCharge=Dual Charging -# Charge (no unique keys) +# Charge +ability.chargeSpeed=Charge Speed -# Dash (no unique keys) +# Dash +ability.dashMode=Dash Mode +ability.dashDistance=Dash Distance +ability.dashSpeed=Dash Speed # Teleport ability.blinkRadius=Blink Radius From 0004029de9a0de216212604aa22fe6c9993419db Mon Sep 17 00:00:00 2001 From: Kam Date: Mon, 2 Feb 2026 21:54:51 -0500 Subject: [PATCH 03/14] Remove Bukkit from this --- .../noppes/npcs/CustomNpcsPermissions.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/java/noppes/npcs/CustomNpcsPermissions.java b/src/main/java/noppes/npcs/CustomNpcsPermissions.java index 6f99dd8fc..af9b2b9af 100644 --- a/src/main/java/noppes/npcs/CustomNpcsPermissions.java +++ b/src/main/java/noppes/npcs/CustomNpcsPermissions.java @@ -7,7 +7,6 @@ import kamkeel.npcs.util.BukkitUtil; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import org.apache.logging.log4j.LogManager; -import org.bukkit.entity.Player; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -67,8 +66,8 @@ public class CustomNpcsPermissions { public static final Permission GLOBAL_NATURALSPAWN = new Permission("customnpcs.global.naturalspawn"); public static final Permission GLOBAL_TAG = new Permission("customnpcs.global.tag"); public static final Permission GLOBAL_ANIMATION = new Permission("customnpcs.global.animation"); - public static final Permission GLOBAL_ABILITY = new Permission("customnpcs.global.ability"); public static final Permission GLOBAL_MAGIC = new Permission("customnpcs.global.magic"); + public static final Permission GLOBAL_ABILITY = new Permission("customnpcs.global.ability"); public static final Permission GLOBAL_EFFECT = new Permission("customnpcs.global.effect"); public static final Permission SPAWNER_MOB = new Permission("customnpcs.spawner.mob"); @@ -112,11 +111,8 @@ public class CustomNpcsPermissions { public static final Permission PROFILE_REGION_BYPASS = new Permission("customnpcs.profile.region-bypass"); public static final Permission PROFILE_MAX = new Permission("customnpcs.profile.max.*"); - // Auction - public static final Permission AUCTION_TRADES_MAX = new Permission("customnpcs.auction.trades.*"); - public static CustomNpcsPermissions Instance; - private static boolean isEnabled; + private Method hasPermission; public CustomNpcsPermissions() { Instance = this; @@ -132,16 +128,16 @@ public class CustomNpcsPermissions { } try { - Class.forName("org.bukkit.entity.Player").getMethod("hasPermission", String.class); - isEnabled = true; - + hasPermission = BukkitUtil.getPlayerClass().getMethod("hasPermission", String.class); LogManager.getLogger(CustomNpcs.class).info("Bukkit permissions enabled"); LogManager.getLogger(CustomNpcs.class).info("Permissions available:"); Collections.sort(Permission.permissions, String.CASE_INSENSITIVE_ORDER); for (String p : Permission.permissions) { LogManager.getLogger(CustomNpcs.class).info(p); } - } catch (Exception e) { + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (SecurityException e) { e.printStackTrace(); } } @@ -175,13 +171,17 @@ public class CustomNpcsPermissions { } private boolean bukkitPermission(String username, String permission) { - if (!BukkitUtil.isEnabled() || !isEnabled) return false; + if (hasPermission == null) return false; try { Object player = BukkitUtil.getPlayer(username); if (player == null) return false; - return ((Player) player).hasPermission(permission); - } catch (Exception e) { + return (Boolean) hasPermission.invoke(player, permission); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { e.printStackTrace(); } return false; @@ -206,6 +206,6 @@ public class CustomNpcsPermissions { } public static boolean enabled() { - return BukkitUtil.isEnabled() && isEnabled; + return BukkitUtil.isEnabled(); } } From 60b846b35e9463f2351bbd8c203642d278dbb277 Mon Sep 17 00:00:00 2001 From: Vidal Date: Tue, 3 Feb 2026 05:43:50 -0300 Subject: [PATCH 04/14] - Added onDamageTaken to Ability - Reworked AbilityGuard - Added AbilityOrbBarrage - Updated translation - Updated onDamageTaken method calls --- src/api | 2 +- .../controllers/data/ability/Ability.java | 15 + .../data/ability/AbilityController.java | 1 + .../data/ability/type/AbilityGuard.java | 169 ++--- .../data/ability/type/AbilityOrbBarrage.java | 576 ++++++++++++++++++ src/main/java/noppes/npcs/DataAbilities.java | 18 +- .../java/noppes/npcs/ai/CombatHandler.java | 16 +- .../controllers/data/PlayerAbilityData.java | 18 +- .../animations/Ability_Guard_Active.json | 50 ++ .../animations/Ability_Guard_Counter.json | 203 ++++++ .../assets/customnpcs/lang/en_US.lang | 4 + 11 files changed, 986 insertions(+), 86 deletions(-) create mode 100644 src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java create mode 100644 src/main/resources/assets/customnpcs/animations/Ability_Guard_Active.json create mode 100644 src/main/resources/assets/customnpcs/animations/Ability_Guard_Counter.json diff --git a/src/api b/src/api index bf650319d..f9de3f4f3 160000 --- a/src/api +++ b/src/api @@ -1 +1 @@ -Subproject commit bf650319da422790bff294d570dd879143fe8d4c +Subproject commit f9de3f4f326d8e45750d28695a5f212db70bdfca diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java index 007e4f2f4..2148a239d 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java @@ -2,6 +2,7 @@ package kamkeel.npcs.controllers.data.ability; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; +import kamkeel.npcs.controllers.data.ability.type.AbilityGuard; import kamkeel.npcs.controllers.data.telegraph.Telegraph; import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; @@ -148,6 +149,9 @@ public abstract class Ability implements IAbility { public void onComplete(EntityLivingBase caster, EntityLivingBase target) { } + public void onDamageTaken(EntityLivingBase caster, EntityLivingBase attacker, DamageSource source, float damage) { + } + /** * Apply damage to an entity with ability hit event support. * Fires the abilityHit script event, allowing scripts to modify or cancel the damage. @@ -427,6 +431,17 @@ public abstract class Ability implements IAbility { this::getActiveAnimationName, this::setActiveAnimationName) .tab("Effects")); + if (this instanceof AbilityGuard) { + defs.add(FieldDef.animSubGui("ability.counterAnimation", + () -> ((AbilityGuard) this).getCounterAnimationId(), + (id) -> ((AbilityGuard) this).setCounterAnimationId(id), + () -> ((AbilityGuard) this).getCounterAnimationName(), + (name) -> ((AbilityGuard) this).setCounterAnimationName(name)) + .tab("Effects") + .visibleWhen(() -> ((AbilityGuard) this).canCounter()) + ); + } + // Effects tab - Telegraph TelegraphType tType = getTelegraphType(); if (tType != null && tType != TelegraphType.NONE) { diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/AbilityController.java b/src/main/java/kamkeel/npcs/controllers/data/ability/AbilityController.java index eba8795f7..50e41d45c 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/AbilityController.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/AbilityController.java @@ -364,6 +364,7 @@ public class AbilityController implements IAbilityHandler { registerType("cnpc:projectile", AbilityProjectile::new); registerType("cnpc:orb", AbilityOrb::new); registerType("cnpc:dual_orb", AbilityOrbDual::new); + registerType("cnpc:orb_barrage", AbilityOrbBarrage::new); registerType("cnpc:dual_disc", AbilityDisc::new); registerType("cnpc:dual_disc", AbilityDiscDual::new); registerType("cnpc:laser_shot", AbilityLaserShot::new); diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java index 9e420741f..9d792f7c3 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java @@ -1,14 +1,16 @@ package kamkeel.npcs.controllers.data.ability.type; -import kamkeel.npcs.controllers.data.ability.Ability; -import kamkeel.npcs.controllers.data.ability.LockMovementType; -import kamkeel.npcs.controllers.data.ability.TargetingMode; -import kamkeel.npcs.controllers.data.ability.UserType; +import kamkeel.npcs.controllers.data.ability.*; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.DamageSource; import net.minecraft.world.World; +import noppes.npcs.api.handler.data.IAnimation; +import noppes.npcs.controllers.AnimationController; +import noppes.npcs.controllers.data.Animation; +import noppes.npcs.controllers.data.PlayerData; import noppes.npcs.entity.EntityNPCInterface; import noppes.npcs.api.ability.type.IAbilityGuard; @@ -21,7 +23,6 @@ import cpw.mods.fml.relauncher.SideOnly; import java.util.Arrays; import java.util.List; -import java.util.Random; /** * Guard ability: Defensive stance that reduces incoming damage. @@ -29,23 +30,40 @@ import java.util.Random; */ public class AbilityGuard extends Ability implements IAbilityGuard { - private static final Random RANDOM = new Random(); - - // Type-specific parameters private int durationTicks = 60; private float damageReduction = 0.5f; - private boolean canCounter = false; - private CounterType counterType = CounterType.FLAT; + private AbilityGuard.CounterType counterType = AbilityGuard.CounterType.FLAT; private float counterValue = 6.0f; - private float counterChance = 0.3f; - private String counterSound = "random.wood_click"; + private String counterSound = "random.anvil_land"; + private boolean canCounter = false; + private int counterWindow = 10; private int counterAnimationId = -1; + private String counterAnimationName; // Runtime state private transient EntityLivingBase lastAttacker; private transient boolean counterTriggered; + private transient boolean counterEligible; private transient float lastDamageTaken; + public AbilityGuard() { + this.typeId = "ability.cnpc.guard"; + this.name = "Guard"; + this.targetingMode = TargetingMode.SELF; + this.lockMovement = LockMovementType.ACTIVE; + this.cooldownTicks = 0; + this.windUpTicks = 0; + this.interruptible = false; // Hard to interrupt while guarding + // No telegraph for guard - it's a defensive stance + this.telegraphType = TelegraphType.NONE; + this.showTelegraph = false; + this.windUpSound = "random.anvil_use"; + this.allowedBy = UserType.BOTH; + + this.activeAnimationName = "Ability_Guard_Active"; + this.counterAnimationName = "Ability_Guard_Counter"; + } + public enum CounterType { FLAT, PERCENT; @@ -60,22 +78,6 @@ public class AbilityGuard extends Ability implements IAbilityGuard { } } - public AbilityGuard() { - this.typeId = "ability.cnpc.guard"; - this.name = "Guard"; - this.targetingMode = TargetingMode.SELF; - this.lockMovement = LockMovementType.ACTIVE; - this.cooldownTicks = 0; - this.windUpTicks = 10; - this.interruptible = false; // Hard to interrupt while guarding - // No telegraph for guard - it's a defensive stance - this.telegraphType = TelegraphType.NONE; - this.showTelegraph = false; - this.windUpSound = "random.anvil_use"; - this.activeSound = "random.anvil_land"; - this.allowedBy = UserType.NPC_ONLY; - } - @Override public boolean isTargetingModeLocked() { return true; @@ -91,32 +93,28 @@ public class AbilityGuard extends Ability implements IAbilityGuard { lastAttacker = null; counterTriggered = false; lastDamageTaken = 0.0f; + counterEligible = true; } @Override public void onActiveTick(EntityLivingBase caster, EntityLivingBase target, World world, int tick) { - // Counter attack logic if triggered - if (canCounter && counterTriggered && lastAttacker != null && !world.isRemote) { + if (canCounter && counterEligible && counterTriggered && lastAttacker != null && !world.isRemote) { performCounter(caster, world); } - // Check if guard duration has ended + if (tick > counterWindow && counterEligible) { + counterEligible = false; + } + if (tick >= durationTicks) { signalCompletion(); } } - /** - * Called externally when the caster takes damage while guarding. - * This should be called from the damage handling code. - * - * @param attacker The entity that attacked - * @param damage The damage amount (after reduction) - */ public void onDamageTaken(EntityLivingBase caster, EntityLivingBase attacker, DamageSource source, float damage) { - if (!canCounter || attacker == null) return; + if (!isGuarding()) return; + if (!canCounter || attacker == null || !counterEligible) return; if (!isDirectHit(source)) return; - if (RANDOM.nextFloat() >= counterChance) return; lastAttacker = attacker; lastDamageTaken = damage; @@ -124,8 +122,14 @@ public class AbilityGuard extends Ability implements IAbilityGuard { // Counter will be performed in onActiveTick - don't self-interrupt } + private boolean isDirectHit(DamageSource source) { + if (source == null) return false; + if (source.isMagicDamage() || source.isFireDamage() || source.isExplosion()) return false; + return source.getEntity() instanceof EntityLivingBase; + } + private void performCounter(EntityLivingBase caster, World world) { - float counterDamage = counterType == CounterType.PERCENT + float counterDamage = counterType == AbilityGuard.CounterType.PERCENT ? lastDamageTaken * (counterValue / 100.0f) : counterValue; @@ -135,18 +139,33 @@ public class AbilityGuard extends Ability implements IAbilityGuard { } // Use shared animation utility - only available for NPCs if (caster instanceof EntityNPCInterface) { - ((EntityNPCInterface) caster).abilities.playAbilityAnimation(counterAnimationId); + if (getCounterAnimation() instanceof IAnimation) { + ((EntityNPCInterface) caster).abilities.playAbilityAnimation((Animation) getCounterAnimation()); + } + } else if (caster instanceof EntityPlayer) { + if (getCounterAnimation() instanceof IAnimation) { + PlayerData.get((EntityPlayer) caster).abilityData.playAbilityAnimation((Animation) getCounterAnimation()); + } } counterTriggered = false; + counterEligible = false; lastAttacker = null; lastDamageTaken = 0.0f; } - private boolean isDirectHit(DamageSource source) { - if (source == null) return false; - if (source.isMagicDamage() || source.isFireDamage() || source.isExplosion()) return false; - return source.getEntity() instanceof EntityLivingBase; + private IAnimation getCounterAnimation() { + if (AnimationController.Instance == null) return null; + + if (counterAnimationId > 0) { + return AnimationController.Instance.get(counterAnimationId); + } + + if (!counterAnimationName.isEmpty()) { + return AnimationController.Instance.get(counterAnimationName, true); + } + + return null; } /** @@ -154,7 +173,7 @@ public class AbilityGuard extends Ability implements IAbilityGuard { * Returns 0.5 for 50% reduction. */ public float getDamageReductionFactor() { - if (isExecuting() && getPhase() == kamkeel.npcs.controllers.data.ability.AbilityPhase.ACTIVE) { + if (isExecuting() && getPhase() == AbilityPhase.ACTIVE) { return damageReduction; } return 0.0f; @@ -164,7 +183,7 @@ public class AbilityGuard extends Ability implements IAbilityGuard { * Check if the caster is currently in guard stance. */ public boolean isGuarding() { - return isExecuting() && getPhase() == kamkeel.npcs.controllers.data.ability.AbilityPhase.ACTIVE; + return isExecuting() && getPhase() == AbilityPhase.ACTIVE; } @Override @@ -185,11 +204,12 @@ public class AbilityGuard extends Ability implements IAbilityGuard { nbt.setInteger("durationTicks", durationTicks); nbt.setFloat("damageReduction", damageReduction); nbt.setBoolean("canCounter", canCounter); + nbt.setInteger("counterWindow", counterWindow); nbt.setString("counterType", counterType.name()); nbt.setFloat("counterValue", counterValue); - nbt.setFloat("counterChance", counterChance); nbt.setString("counterSound", counterSound); nbt.setInteger("counterAnimationId", counterAnimationId); + nbt.setString("counterAnimationName", counterAnimationName); } @Override @@ -197,6 +217,7 @@ public class AbilityGuard extends Ability implements IAbilityGuard { this.durationTicks = nbt.hasKey("durationTicks") ? nbt.getInteger("durationTicks") : 60; this.damageReduction = nbt.hasKey("damageReduction") ? nbt.getFloat("damageReduction") : 0.5f; this.canCounter = nbt.hasKey("canCounter") && nbt.getBoolean("canCounter"); + this.counterWindow = nbt.hasKey("counterWindow") ? nbt.getInteger("counterWindow") : 10; try { this.counterType = CounterType.valueOf(nbt.getString("counterType")); } catch (Exception e) { @@ -209,9 +230,11 @@ public class AbilityGuard extends Ability implements IAbilityGuard { } else { this.counterValue = 6.0f; } - this.counterChance = nbt.hasKey("counterChance") ? nbt.getFloat("counterChance") : 0.3f; this.counterSound = nbt.hasKey("counterSound") ? nbt.getString("counterSound") : "random.wood_click"; this.counterAnimationId = nbt.hasKey("counterAnimationId") ? nbt.getInteger("counterAnimationId") : -1; + this.counterAnimationName = nbt.hasKey("counterAnimationName") ? + nbt.getString("counterAnimationName") : + "Ability_Guard_Counter"; } // Getters & Setters @@ -223,17 +246,26 @@ public class AbilityGuard extends Ability implements IAbilityGuard { this.durationTicks = Math.max(1, durationTicks); } + @Override + public int getCounterWindow() { + return this.counterWindow; + } + + @Override + public void setCounterWindow(int ticks) { + this.counterWindow = Math.min(durationTicks, ticks); + } + + @Override public float getDamageReduction() { return damageReduction; } + @Override public void setDamageReduction(float damageReduction) { this.damageReduction = damageReduction; } - public boolean isCanCounter() { - return canCounter; - } @Override public boolean canCounter() { @@ -271,14 +303,6 @@ public class AbilityGuard extends Ability implements IAbilityGuard { this.counterValue = counterValue; } - public float getCounterChance() { - return counterChance; - } - - public void setCounterChance(float counterChance) { - this.counterChance = counterChance; - } - public String getCounterSound() { return counterSound; } @@ -295,6 +319,14 @@ public class AbilityGuard extends Ability implements IAbilityGuard { this.counterAnimationId = counterAnimationId; } + public String getCounterAnimationName() { + return counterAnimationName; + } + + public void setCounterAnimationName(String name) { + this.counterAnimationName = name; + } + @SideOnly(Side.CLIENT) @Override public List getFieldDefinitions() { @@ -302,20 +334,19 @@ public class AbilityGuard extends Ability implements IAbilityGuard { FieldDef.intField("ability.duration", this::getDurationTicks, this::setDurationTicks).range(1, 1000), FieldDef.floatField("ability.damageReduction", this::getDamageReduction, this::setDamageReduction), FieldDef.section("ability.section.counter"), - FieldDef.boolField("gui.enabled", this::isCanCounter, this::setCanCounter).hover("ability.hover.canCounter"), + FieldDef.boolField("gui.enabled", this::canCounter, this::setCanCounter).hover("ability.hover.canCounter"), FieldDef.enumField("gui.type", CounterType.class, this::getCounterTypeEnum, this::setCounterTypeEnum) - .hover("ability.hover.counterType").visibleWhen(this::isCanCounter), + .hover("ability.hover.counterType").visibleWhen(this::canCounter), FieldDef.row( FieldDef.floatField("gui.value", this::getCounterValue, this::setCounterValue) - .visibleWhen(this::isCanCounter), - FieldDef.floatField("gui.chance", this::getCounterChance, this::setCounterChance) - .visibleWhen(this::isCanCounter) + .visibleWhen(this::canCounter), + FieldDef.intField("ability.counterWindow", this::getCounterWindow, this::setCounterWindow) + .visibleWhen(this::canCounter) ), FieldDef.stringField("gui.sound", this::getCounterSound, this::setCounterSound) - .visibleWhen(this::isCanCounter), - FieldDef.intField("gui.animation", this::getCounterAnimationId, this::setCounterAnimationId) - .visibleWhen(this::isCanCounter), + .visibleWhen(this::canCounter), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) + ); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java new file mode 100644 index 000000000..f0425fa9a --- /dev/null +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java @@ -0,0 +1,576 @@ +package kamkeel.npcs.controllers.data.ability.type; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import kamkeel.npcs.controllers.data.ability.Ability; +import kamkeel.npcs.controllers.data.ability.AnchorPoint; +import kamkeel.npcs.controllers.data.ability.LockMovementType; +import kamkeel.npcs.controllers.data.ability.TargetingMode; +import kamkeel.npcs.controllers.data.ability.data.*; +import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; +import kamkeel.npcs.controllers.data.telegraph.Telegraph; +import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance; +import kamkeel.npcs.controllers.data.telegraph.TelegraphType; +import kamkeel.npcs.entity.EntityAbilityOrb; +import kamkeel.npcs.util.AnchorPointHelper; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; +import net.minecraftforge.common.util.Constants; +import noppes.npcs.client.gui.builder.FieldDef; +import noppes.npcs.entity.EntityNPCInterface; +import noppes.npcs.util.ValueUtil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class AbilityOrbBarrage extends Ability { + + // Ability-specific properties + private float orbSize = 0.5f; + private int orbAmount = 16; + private int firingSpeed = 2; + private boolean dualCharging = true; + + // Data classes for energy properties + private final EnergyColorData colorData = new EnergyColorData(); + private final EnergyCombatData combatData = new EnergyCombatData(4.0f, 0.0f, 0.0f, false, 1.5f, 0.5f); + private final EnergyHomingData homingData = new EnergyHomingData(); + private final EnergyLightningData lightningData = new EnergyLightningData(); + private final EnergyLifespanData lifespanData = new EnergyLifespanData(); + private final EnergyAnchorData[] anchorData = new EnergyAnchorData[]{ + new EnergyAnchorData(AnchorPoint.RIGHT_HAND), new EnergyAnchorData(AnchorPoint.LEFT_HAND) + }; + + // Array to store entities + private transient List orbEntities = new ArrayList<>(); + private transient EntityAbilityOrb[] chargingEntities = null; + + // Field to keep track of the currently firing orb + private int currentOrb = 0; + + public AbilityOrbBarrage() { + this.typeId = "ability.cnpc.orb_barrage"; + this.name = "Orb Barrage"; + this.targetingMode = TargetingMode.AGGRO_TARGET; + this.maxRange = 75.0f; + this.minRange = 5.0f; + this.cooldownTicks = 0; + this.windUpTicks = 30; + this.lockMovement = LockMovementType.WINDUP; + this.telegraphType = TelegraphType.CIRCLE; + this.showTelegraph = true; + // Default built-in animation + this.windUpAnimationName = "Ability_BeamDual_Windup"; + this.activeAnimationName = "Ability_BeamDual_Active"; + } + +// @Override +// @SideOnly(Side.CLIENT) +// public SubGuiAbilityConfig createConfigGui(IAbilityConfigCallback callback) { +// return new SubGuiAbilityOrbBarrage(this, callback); +// } + + @Override + public boolean isTargetingModeLocked() { + return true; + } + + @Override + public TargetingMode[] getAllowedTargetingModes() { + return new TargetingMode[]{TargetingMode.AGGRO_TARGET}; + } + + @Override + public void onExecute(EntityLivingBase caster, EntityLivingBase target, World world) { + if (world.isRemote) { + signalCompletion(); + return; + } + + for (int i = 0; i < chargingEntities.length; i++) { + EntityAbilityOrb orbEntity = chargingEntities[i]; + + if (orbEntity != null && !orbEntity.isDead) { + orbEntity.setDead(); + } + + chargingEntities[i] = null; + } + } + + @Override + public void onWindUpTick(EntityLivingBase caster, EntityLivingBase target, World world, int tick) { + if (world.isRemote) return; + + // Spawn orb in charging mode on first tick of windup + if (tick == 1) { + // Create orb in charging mode - follows caster based on anchor point during windup + + if (dualCharging) { + chargingEntities = new EntityAbilityOrb[2]; + } else { + chargingEntities = new EntityAbilityOrb[1]; + } + + for (int i = 0; i < chargingEntities.length; i++) { + Vec3 spawnPos = AnchorPointHelper.calculateAnchorPosition(caster, anchorData[i]); + + EntityAbilityOrb orbEntity = new EntityAbilityOrb( + world, caster, target, + spawnPos.xCoord, spawnPos.yCoord, spawnPos.zCoord, orbSize, + colorData, combatData, homingData, lightningData, lifespanData + ); + + orbEntity.setupCharging(anchorData[i], windUpTicks); + + chargingEntities[i] = orbEntity; + world.spawnEntityInWorld(orbEntity); + } + } + } + + @Override + public void onActiveTick(EntityLivingBase caster, EntityLivingBase target, World world, int tick) { + if (!orbEntities.isEmpty()) { + boolean allDead = true; + + for (EntityAbilityOrb orbEntity : orbEntities) { + if (orbEntity != null && !orbEntity.isDead) { + allDead = false; + break; + } + } + + if (allDead && currentOrb >= orbAmount) { + signalCompletion(); + return; + } + } + + if (currentOrb >= orbAmount) { + return; + } + + int ticksPerOrb = Math.max(1, 20 / firingSpeed); + + if (tick % ticksPerOrb != 0) { + return; + } + + EnergyAnchorData anchor; + + if (dualCharging) { + anchor = anchorData[currentOrb % 2]; + } else { + anchor = anchorData[0]; + } + + Vec3 spawnPos = AnchorPointHelper.calculateAnchorPosition(caster, anchor); + + EntityAbilityOrb orb = new EntityAbilityOrb( + world, caster, target, spawnPos.xCoord, spawnPos.yCoord, spawnPos.zCoord, + orbSize, colorData, combatData, homingData, lightningData, lifespanData + ); + + world.spawnEntityInWorld(orb); + + orbEntities.add(orb); + currentOrb++; + } + + @Override + public void cleanup() { + currentOrb = 0; + + if (orbEntities != null && !orbEntities.isEmpty()) { + for (EntityAbilityOrb orbEntity : orbEntities) { + if (orbEntity != null && !orbEntity.isDead) { + orbEntity.setDead(); + } + } + orbEntities.clear(); + } + + if (chargingEntities != null) { + for (int i = 0; i < chargingEntities.length; i++) { + if (chargingEntities[i] != null && !chargingEntities[i].isDead) { + chargingEntities[i].setDead(); + } + chargingEntities[i] = null; + } + chargingEntities = null; + } + } + + @Override + public TelegraphInstance createTelegraph(EntityLivingBase caster, EntityLivingBase target) { + if (!showTelegraph || telegraphType == TelegraphType.NONE || target == null) { + return null; + } + + // Create small circle telegraph at target position + Telegraph telegraph = Telegraph.circle(orbSize * 1.5f); + telegraph.setDurationTicks(windUpTicks); + telegraph.setColor(windUpColor); + telegraph.setWarningColor(activeColor); + telegraph.setWarningStartTick(Math.max(5, windUpTicks / 4)); + telegraph.setHeightOffset(telegraphHeightOffset); + + // Position at target and follow target during windup + TelegraphInstance instance = new TelegraphInstance(telegraph, target.posX, target.posY, target.posZ, caster.rotationYaw); + instance.setCasterEntityId(caster.getEntityId()); + instance.setEntityIdToFollow(target.getEntityId()); + + return instance; + } + + @Override + public float getTelegraphRadius() { + return orbSize * 1.5f; + } + + @Override + public void writeTypeNBT(NBTTagCompound nbt) { + nbt.setFloat("orbSize", orbSize); + nbt.setInteger("orbAmount", orbAmount); + nbt.setInteger("firingSpeed", firingSpeed); + nbt.setBoolean("dualCharging", dualCharging); + colorData.writeNBT(nbt); + combatData.writeNBT(nbt); + homingData.writeNBT(nbt); + lightningData.writeNBT(nbt); + lifespanData.writeNBT(nbt); + + for (int i = 0; i < anchorData.length; i++) { + NBTTagCompound comp = new NBTTagCompound(); + anchorData[i].writeNBT(comp); + nbt.setTag("Anchor_" + i, comp); + } + } + + @Override + public void readTypeNBT(NBTTagCompound nbt) { + this.orbSize = nbt.hasKey("orbSize") ? nbt.getFloat("orbSize") : 1.0f; + this.orbAmount = nbt.hasKey("orbAmount") ? nbt.getInteger("orbAmount") : 16; + this.firingSpeed = nbt.hasKey("firingSpeed") ? nbt.getInteger("firingSpeed") : 2; + this.dualCharging = !nbt.hasKey("dualCharging") || nbt.getBoolean("dualCharging"); + colorData.readNBT(nbt); + combatData.readNBT(nbt); + homingData.readNBT(nbt); + lightningData.readNBT(nbt); + lifespanData.readNBT(nbt); + + for (int i = 0; i < anchorData.length; i++) { + if (nbt.hasKey("Anchor_" + i, Constants.NBT.TAG_COMPOUND)) { + anchorData[i].readNBT(nbt.getCompoundTag("Anchor_" + i)); + } else { + anchorData[i] = new EnergyAnchorData(i == 0 ? AnchorPoint.RIGHT_HAND : AnchorPoint.LEFT_HAND); + } + } + } + + // Getters & Setters + public float getOrbSpeed() { + return homingData.speed; + } + + public void setOrbSpeed(float orbSpeed) { + homingData.speed = orbSpeed; + } + + public float getOrbSize() { + return orbSize; + } + + public void setOrbSize(float orbSize) { + this.orbSize = orbSize; + } + + public int getOrbAmount() { return orbAmount; } + + public void setOrbAmount(int orbAmount) { this.orbAmount = orbAmount; } + + public int getFiringSpeed() { return firingSpeed; } + + public void setFiringSpeed(int firingSpeed) { this.firingSpeed = firingSpeed; } + + public boolean isDualCharging() { return dualCharging; } + + public void setDualCharging(boolean dualCharging) { this.dualCharging = dualCharging; } + + public float getMaxDistance() { + return lifespanData.maxDistance; + } + + public void setMaxDistance(float maxDistance) { + lifespanData.maxDistance = maxDistance; + } + + public int getMaxLifetime() { + return lifespanData.maxLifetime; + } + + public void setMaxLifetime(int maxLifetime) { + lifespanData.maxLifetime = maxLifetime; + } + + public float getDamage() { + return combatData.damage; + } + + public void setDamage(float damage) { + combatData.damage = damage; + } + + public float getKnockback() { + return combatData.knockback; + } + + public void setKnockback(float knockback) { + combatData.knockback = knockback; + } + + public float getKnockbackUp() { + return combatData.knockbackUp; + } + + public void setKnockbackUp(float knockbackUp) { + combatData.knockbackUp = knockbackUp; + } + + public boolean isHoming() { + return homingData.homing; + } + + public void setHoming(boolean homing) { + homingData.homing = homing; + } + + public float getHomingStrength() { + return homingData.homingStrength; + } + + public void setHomingStrength(float homingStrength) { + homingData.homingStrength = homingStrength; + } + + public float getHomingRange() { + return homingData.homingRange; + } + + public void setHomingRange(float homingRange) { + homingData.homingRange = homingRange; + } + + public boolean isExplosive() { + return combatData.explosive; + } + + public void setExplosive(boolean explosive) { + combatData.explosive = explosive; + } + + public float getExplosionRadius() { + return combatData.explosionRadius; + } + + public void setExplosionRadius(float explosionRadius) { + combatData.explosionRadius = explosionRadius; + } + + public float getExplosionDamageFalloff() { + return combatData.explosionDamageFalloff; + } + + public void setExplosionDamageFalloff(float explosionDamageFalloff) { + combatData.explosionDamageFalloff = explosionDamageFalloff; + } + + public int getInnerColor() { + return colorData.innerColor; + } + + public void setInnerColor(int innerColor) { + colorData.innerColor = innerColor; + } + + public int getOuterColor() { + return colorData.outerColor; + } + + public void setOuterColor(int outerColor) { + colorData.outerColor = outerColor; + } + + public float getOuterColorWidth() { + return colorData.outerColorWidth; + } + + public void setOuterColorWidth(float outerColorWidth) { + colorData.outerColorWidth = outerColorWidth; + } + + public float getOuterColorAlpha() { + return colorData.outerColorAlpha; + } + + public void setOuterColorAlpha(float outerColorAlpha) { + colorData.outerColorAlpha = outerColorAlpha; + } + + public boolean isOuterColorEnabled() { + return colorData.outerColorEnabled; + } + + public void setOuterColorEnabled(boolean outerColorEnabled) { + colorData.outerColorEnabled = outerColorEnabled; + } + + public float getRotationSpeed() { + return colorData.rotationSpeed; + } + + public void setRotationSpeed(float rotationSpeed) { + colorData.rotationSpeed = rotationSpeed; + } + + public boolean hasLightningEffect() { + return lightningData.lightningEffect; + } + + public void setLightningEffect(boolean lightningEffect) { + lightningData.lightningEffect = lightningEffect; + } + + public float getLightningDensity() { + return lightningData.lightningDensity; + } + + public void setLightningDensity(float lightningDensity) { + lightningData.lightningDensity = lightningDensity; + } + + public float getLightningRadius() { + return lightningData.lightningRadius; + } + + public void setLightningRadius(float lightningRadius) { + lightningData.lightningRadius = lightningRadius; + } + + public int getLightningFadeTime() { + return lightningData.lightningFadeTime; + } + + public void setLightningFadeTime(int lightningFadeTime) { + lightningData.lightningFadeTime = lightningFadeTime; + } + + private EnergyAnchorData getAnchorData(int orb) { + orb = ValueUtil.clamp(orb, 0, 1); + return anchorData[orb]; + } + + public AnchorPoint getAnchorPointEnum(int orb) { return getAnchorData(orb).anchorPoint; } + public void setAnchorPointEnum(int orb, AnchorPoint anchorPoint) { getAnchorData(orb).anchorPoint = anchorPoint; } + public float getAnchorOffsetX(int orb) { return getAnchorData(orb).anchorOffsetX; } + public void setAnchorOffsetX(int orb, float x) { getAnchorData(orb).anchorOffsetX = x; } + public float getAnchorOffsetY(int orb) { return getAnchorData(orb).anchorOffsetY; } + public void setAnchorOffsetY(int orb, float y) { getAnchorData(orb).anchorOffsetY = y; } + public float getAnchorOffsetZ(int orb) { return getAnchorData(orb).anchorOffsetZ; } + public void setAnchorOffsetZ(int orb, float z) { getAnchorData(orb).anchorOffsetZ = z; } + + public AnchorPoint getAnchorPointEnum() { return getAnchorPointEnum(0); } + public void setAnchorPointEnum(AnchorPoint anchorPoint) { setAnchorPointEnum(0, anchorPoint); } + public float getAnchorOffsetX() { return getAnchorOffsetX(0); } + public void setAnchorOffsetX(float x) { setAnchorOffsetX(0, x); } + public float getAnchorOffsetY() { return getAnchorOffsetY(0); } + public void setAnchorOffsetY(float y) { setAnchorOffsetY(0, y); } + public float getAnchorOffsetZ() { return getAnchorOffsetZ(0); } + public void setAnchorOffsetZ(float z) { setAnchorOffsetZ(0, z); } + + //@Override + public int getAnchorPoint(int orb) { return getAnchorData(orb).anchorPoint.ordinal(); } + public int getAnchorPoint() { return getAnchorData(0).anchorPoint.ordinal(); } + + //@Override + public void setAnchorPoint(int orb, int point) { getAnchorData(orb).anchorPoint = AnchorPoint.fromOrdinal(point); } + public void setAnchorPoint(int point) { getAnchorData(0).anchorPoint = AnchorPoint.fromOrdinal(point); } + + @Override + @SideOnly(Side.CLIENT) + public Entity createPreviewEntity(EntityNPCInterface npc) { + if (npc == null || npc.worldObj == null) return null; + + EntityAbilityOrb orb = new EntityAbilityOrb(npc.worldObj); + orb.setupPreview(npc, orbSize, colorData, lightningData, anchorData[0], windUpTicks); + return orb; + } + + @Override + public int getPreviewActiveDuration() { + return lifespanData.maxLifetime > 0 ? Math.min(lifespanData.maxLifetime, 100) : 100; + } + + @SideOnly(Side.CLIENT) + @Override + public List getFieldDefinitions() { + return Arrays.asList( + // Type tab + FieldDef.row( + FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), + FieldDef.floatField("stats.speed", this::getOrbSpeed, this::setOrbSpeed) + ), + FieldDef.row( + FieldDef.floatField("stats.size", this::getOrbSize, this::setOrbSize), + FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback) + ), + FieldDef.row( + FieldDef.floatField("ability.maxDistance", this::getMaxDistance, this::setMaxDistance), + FieldDef.intField("ability.lifetime", this::getMaxLifetime, this::setMaxLifetime) + ), + FieldDef.section("ability.section.barrage"), + FieldDef.row( + FieldDef.intField("ability.amount", this::getOrbAmount, this::setOrbAmount), + FieldDef.intField("ability.firingSpeed", this::getFiringSpeed, this::setFiringSpeed) + ), + FieldDef.boolField("ability.dualCharge", this::isDualCharging, this::setDualCharging), + FieldDef.section("ability.section.homing"), + FieldDef.boolField("gui.enabled", this::isHoming, this::setHoming).hover("ability.hover.homing"), + FieldDef.floatField("gui.strength", this::getHomingStrength, this::setHomingStrength).visibleWhen(this::isHoming), + FieldDef.section("ability.section.explosive"), + FieldDef.boolField("gui.enabled", this::isExplosive, this::setExplosive).hover("ability.hover.explosive"), + FieldDef.floatField("gui.radius", this::getExplosionRadius, this::setExplosionRadius).visibleWhen(this::isExplosive), + AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects), + + + // Visual tab + FieldDef.enumField("ability.anchorPoint", AnchorPoint.class, this::getAnchorPointEnum, this::setAnchorPointEnum) + .tab("ability.tab.visual"), + FieldDef.section("ability.section.colors").tab("ability.tab.visual"), + FieldDef.colorSubGui("ability.innerColor", this::getInnerColor, this::setInnerColor).tab("ability.tab.visual"), + FieldDef.boolField("ability.outerEnabled", this::isOuterColorEnabled, this::setOuterColorEnabled).tab("ability.tab.visual"), + FieldDef.colorSubGui("ability.outerColor", this::getOuterColor, this::setOuterColor) + .tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled), + FieldDef.row( + FieldDef.floatField("ability.outerWidth", this::getOuterColorWidth, this::setOuterColorWidth) + .visibleWhen(this::isOuterColorEnabled), + FieldDef.floatField("ability.outerAlpha", this::getOuterColorAlpha, this::setOuterColorAlpha) + .range(0, 1).visibleWhen(this::isOuterColorEnabled) + ).tab("ability.tab.visual"), + FieldDef.section("ability.section.effects").tab("ability.tab.visual"), + FieldDef.floatField("ability.rotationSpeed", this::getRotationSpeed, this::setRotationSpeed).tab("ability.tab.visual"), + FieldDef.boolField("ability.lightning", this::hasLightningEffect, this::setLightningEffect).tab("ability.tab.visual"), + FieldDef.row( + FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity) + .range(0.01f, 5.0f).visibleWhen(this::hasLightningEffect), + FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) + .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) + ).tab("ability.tab.visual") + ); + } +} diff --git a/src/main/java/noppes/npcs/DataAbilities.java b/src/main/java/noppes/npcs/DataAbilities.java index 8c44c482e..635b741ac 100644 --- a/src/main/java/noppes/npcs/DataAbilities.java +++ b/src/main/java/noppes/npcs/DataAbilities.java @@ -429,6 +429,14 @@ public class DataAbilities { playAbilityAnimation((Animation) AnimationController.Instance.get(animation)); } + public void playAbilityAnimation(String animation) { + if (animation.isEmpty()) return; + if (AnimationController.Instance == null) return; + if (AnimationController.Instance.get(animation, true) == null) return; + + playAbilityAnimation((Animation) AnimationController.Instance.get(animation, true)); + } + /** * Stop any currently playing ability animation. */ @@ -501,18 +509,12 @@ public class DataAbilities { // Track hit for hit count condition recordHit(); - // Check if currently executing a Guard ability and notify it of damage taken - if (currentAbility instanceof AbilityGuard) { - AbilityGuard guard = (AbilityGuard) currentAbility; - if (guard.isGuarding() && source.getEntity() instanceof EntityLivingBase) { - guard.onDamageTaken(npc, (EntityLivingBase) source.getEntity(), source, amount); - } - } - if (currentAbility == null || !currentAbility.isExecuting()) { return false; } + currentAbility.onDamageTaken(npc, (EntityLivingBase) source.getEntity(), source, amount); + if (currentAbility.canInterrupt(source)) { interruptCurrentAbility(source, amount); return true; diff --git a/src/main/java/noppes/npcs/ai/CombatHandler.java b/src/main/java/noppes/npcs/ai/CombatHandler.java index 750725551..ff81e4821 100644 --- a/src/main/java/noppes/npcs/ai/CombatHandler.java +++ b/src/main/java/noppes/npcs/ai/CombatHandler.java @@ -1,6 +1,7 @@ package noppes.npcs.ai; import kamkeel.npcs.addon.DBCAddon; +import kamkeel.npcs.controllers.data.ability.type.AbilityGuard; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.player.EntityPlayer; @@ -80,13 +81,14 @@ public class CombatHandler { } // Handle guard counter before interruption - if (npc.abilities.getCurrentAbility() instanceof kamkeel.npcs.controllers.data.ability.type.AbilityGuard) { - kamkeel.npcs.controllers.data.ability.type.AbilityGuard guard = - (kamkeel.npcs.controllers.data.ability.type.AbilityGuard) npc.abilities.getCurrentAbility(); - if (guard.isGuarding() && e instanceof EntityLivingBase) { - guard.onDamageTaken(npc, (EntityLivingBase) e, source, damageAmount); - } - } + +// if (npc.abilities.getCurrentAbility() instanceof AbilityGuard) { +// AbilityGuard guard = +// (AbilityGuard) npc.abilities.getCurrentAbility(); +// if (guard.isGuarding() && e instanceof EntityLivingBase) { +// guard.onDamageTaken(npc, (EntityLivingBase) e, source, damageAmount); +// } +// } // Check for ability interruption npc.abilities.onDamage(source, damageAmount); diff --git a/src/main/java/noppes/npcs/controllers/data/PlayerAbilityData.java b/src/main/java/noppes/npcs/controllers/data/PlayerAbilityData.java index 45f9dfe44..724b054c0 100644 --- a/src/main/java/noppes/npcs/controllers/data/PlayerAbilityData.java +++ b/src/main/java/noppes/npcs/controllers/data/PlayerAbilityData.java @@ -453,13 +453,29 @@ public class PlayerAbilityData implements IPlayerAbilityData { // ANIMATION // ═══════════════════════════════════════════════════════════════════ - private void playAbilityAnimation(Animation animation) { + public void playAbilityAnimation(Animation animation) { if (animation == null || AnimationController.Instance == null) return; playerData.animationData.setEnabled(true); playerData.animationData.setAnimation(animation); playerData.animationData.updateClient(); } + public void playAbilityAnimation(int animation) { + if (animation < 0) return; + if (AnimationController.Instance == null) return; + if (AnimationController.Instance.get(animation) == null) return; + + playAbilityAnimation((Animation) AnimationController.Instance.get(animation)); + } + + public void playAbilityAnimation(String animation) { + if (animation.isEmpty()) return; + if (AnimationController.Instance == null) return; + if (AnimationController.Instance.get(animation, true) == null) return; + + playAbilityAnimation((Animation) AnimationController.Instance.get(animation, true)); + } + private void stopAbilityAnimation() { playerData.animationData.setAnimation(null); playerData.animationData.updateClient(); diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Guard_Active.json b/src/main/resources/assets/customnpcs/animations/Ability_Guard_Active.json new file mode 100644 index 000000000..258320341 --- /dev/null +++ b/src/main/resources/assets/customnpcs/animations/Ability_Guard_Active.json @@ -0,0 +1,50 @@ +{ + "Loop": 0, + "Speed": 1.0f, + "Frames": [ + { + "ColorMarker": 16777215, + "Comment": "", + "Speed": 2.0f, + "FrameParts": [ + { + "Pivot2": -3.0f, + "Part": "RIGHT_ARM", + "Rotation1": -80.0f, + "Rotation0": -120.0f, + "Pivot0": 2.0f, + "Pivot1": 2.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -3.0f, + "Part": "LEFT_ARM", + "Rotation1": 80.0f, + "Rotation0": -120.0f, + "Pivot0": -2.0f, + "Pivot1": 2.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": 0.0f, + "Part": "HEAD", + "Rotation1": 0.0f, + "Rotation0": 12.0f, + "Pivot0": 0.0f, + "Pivot1": 0.0f, + "Rotation2": 0.0f + } + ], + "Smooth": 0b, + "Duration": 10 + } + ], + "CurrentFrameTime": 0, + "CurrentFrame": 0, + "Smooth": 0b, + "ID": 18, + "WhileAttacking": 1b, + "WhileWalking": 1b, + "Name": "Ability_Guard_Active", + "WhileStanding": 1b +} diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Guard_Counter.json b/src/main/resources/assets/customnpcs/animations/Ability_Guard_Counter.json new file mode 100644 index 000000000..9194dfd72 --- /dev/null +++ b/src/main/resources/assets/customnpcs/animations/Ability_Guard_Counter.json @@ -0,0 +1,203 @@ +{ + "Loop": 2, + "Speed": 1.0f, + "Frames": [ + { + "ColorMarker": 16777215, + "Comment": "", + "Speed": 2.0f, + "FrameParts": [ + { + "Pivot2": 0.0f, + "Part": "LEFT_LEG", + "Rotation1": 0.0f, + "Rotation0": 0.0f, + "Pivot0": 0.0f, + "Pivot1": 0.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -3.0f, + "Part": "RIGHT_ARM", + "Rotation1": -80.0f, + "Rotation0": -120.0f, + "Pivot0": 2.0f, + "Pivot1": 2.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -3.0f, + "Part": "LEFT_ARM", + "Rotation1": 80.0f, + "Rotation0": -120.0f, + "Pivot0": -2.0f, + "Pivot1": 2.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": 0.0f, + "Part": "HEAD", + "Rotation1": 0.0f, + "Rotation0": 12.0f, + "Pivot0": 0.0f, + "Pivot1": 0.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": 0.0f, + "Part": "BODY", + "Rotation1": 0.0f, + "Rotation0": 0.0f, + "Pivot0": 0.0f, + "Pivot1": 0.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": 0.0f, + "Part": "RIGHT_LEG", + "Rotation1": 0.0f, + "Rotation0": 0.0f, + "Pivot0": 0.0f, + "Pivot1": 0.0f, + "Rotation2": 0.0f + } + ], + "Smooth": 0b, + "Duration": 3 + }, + { + "ColorMarker": 16777215, + "Comment": "", + "Speed": 2.0f, + "FrameParts": [ + { + "Pivot2": -3.0f, + "Part": "LEFT_LEG", + "Rotation1": 0.0f, + "Rotation0": 6.0f, + "Pivot0": 0.0f, + "Pivot1": 0.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -3.0f, + "Part": "RIGHT_ARM", + "Rotation1": -20.0f, + "Rotation0": 90.0f, + "Pivot0": 0.0f, + "Pivot1": 3.0f, + "Rotation2": 60.0f + }, + { + "Pivot2": -3.0f, + "Part": "LEFT_ARM", + "Rotation1": 20.0f, + "Rotation0": 90.0f, + "Pivot0": 0.0f, + "Pivot1": 3.0f, + "Rotation2": -60.0f + }, + { + "Pivot2": -6.0f, + "Part": "HEAD", + "Rotation1": 0.0f, + "Rotation0": 25.0f, + "Pivot0": 0.0f, + "Pivot1": 3.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -6.0f, + "Part": "BODY", + "Rotation1": 0.0f, + "Rotation0": 31.0f, + "Pivot0": 0.0f, + "Pivot1": 3.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": 0.0f, + "Part": "RIGHT_LEG", + "Rotation1": 0.0f, + "Rotation0": 31.0f, + "Pivot0": 0.0f, + "Pivot1": 1.0f, + "Rotation2": 0.0f + } + ], + "Smooth": 0b, + "Duration": 3 + }, + { + "ColorMarker": 16777215, + "Comment": "", + "Speed": 0.8f, + "FrameParts": [ + { + "Pivot2": -3.0f, + "Part": "LEFT_LEG", + "Rotation1": 0.0f, + "Rotation0": 6.0f, + "Pivot0": 0.0f, + "Pivot1": 0.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -3.0f, + "Part": "RIGHT_ARM", + "Rotation1": -20.0f, + "Rotation0": 90.0f, + "Pivot0": 0.0f, + "Pivot1": 3.0f, + "Rotation2": 60.0f + }, + { + "Pivot2": -3.0f, + "Part": "LEFT_ARM", + "Rotation1": 20.0f, + "Rotation0": 90.0f, + "Pivot0": 0.0f, + "Pivot1": 3.0f, + "Rotation2": -60.0f + }, + { + "Pivot2": -6.0f, + "Part": "HEAD", + "Rotation1": 0.0f, + "Rotation0": 25.0f, + "Pivot0": 0.0f, + "Pivot1": 3.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -6.0f, + "Part": "BODY", + "Rotation1": 0.0f, + "Rotation0": 31.0f, + "Pivot0": 0.0f, + "Pivot1": 3.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": 0.0f, + "Part": "RIGHT_LEG", + "Rotation1": 0.0f, + "Rotation0": 31.0f, + "Pivot0": 0.0f, + "Pivot1": 1.0f, + "Rotation2": 0.0f + } + ], + "Smooth": 0b, + "Duration": 10 + } + ], + "CurrentFrameTime": 0, + "CurrentFrame": 0, + "Smooth": 0b, + "ID": 17, + "WhileAttacking": 1b, + "WhileWalking": 1b, + "Name": "Ability_Guard_Counter", + "WhileStanding": 1b +} diff --git a/src/main/resources/assets/customnpcs/lang/en_US.lang b/src/main/resources/assets/customnpcs/lang/en_US.lang index a95b71f67..afa79dad0 100644 --- a/src/main/resources/assets/customnpcs/lang/en_US.lang +++ b/src/main/resources/assets/customnpcs/lang/en_US.lang @@ -1608,6 +1608,7 @@ ability.cnpc.beam_dual=Beam Dual ability.cnpc.projectile=Projectile ability.cnpc.orb=Orb ability.cnpc.orb_dual=Orb Dual +ability.cnpc.orb_barrage=Orb Barrage ability.cnpc.charge=Charge ability.cnpc.dash=Dash ability.cnpc.teleport=Teleport @@ -1645,6 +1646,7 @@ ability.windUpSound=Wind Up Sound ability.activeSound=Active Sound ability.windUpAnimation=Wind Up Animation ability.activeAnimation=Active Animation +ability.counterAnimation=Counter Animation ability.showTelegraph=Show Telegraph ability.windUpColor=Wind Up Color ability.activeColor=Active Color @@ -1672,6 +1674,7 @@ ability.section.disc1=Disc 1 ability.section.disc2=Disc 2 ability.section.orb1=Orb 1 ability.section.orb2=Orb 2 +ability.section.barrage=Barrage ability.section.counter=Counter ability.section.area=Area ability.section.damage=Damage @@ -1763,6 +1766,7 @@ ability.pushStrength=Push Strength # Guard ability.damageReduction=Damage Reduction +ability.counterWindow=Counter Ticks # Heal ability.instantHeal=Instant Heal From 4f629c56797e271a05e943ec711377f656a7ab24 Mon Sep 17 00:00:00 2001 From: Vidal Date: Tue, 3 Feb 2026 05:57:40 -0300 Subject: [PATCH 05/14] Made ability abort after the counter has been triggered --- .../npcs/controllers/data/ability/type/AbilityGuard.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java index 9d792f7c3..60f5caf88 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java @@ -109,6 +109,11 @@ public class AbilityGuard extends Ability implements IAbilityGuard { if (tick >= durationTicks) { signalCompletion(); } + + // Just enough to see the counter animation + if (counterTriggered && tick >= counterWindow + 10) { + signalCompletion(); + } } public void onDamageTaken(EntityLivingBase caster, EntityLivingBase attacker, DamageSource source, float damage) { @@ -148,7 +153,6 @@ public class AbilityGuard extends Ability implements IAbilityGuard { } } - counterTriggered = false; counterEligible = false; lastAttacker = null; lastDamageTaken = 0.0f; From 8fc0155df8f142f1ab115c6b84a14b6dc2969b73 Mon Sep 17 00:00:00 2001 From: Vidal Date: Tue, 3 Feb 2026 06:22:24 -0300 Subject: [PATCH 06/14] Attempt at damage reduction --- .../data/ability/type/AbilityGuard.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java index 60f5caf88..829a51c8f 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java @@ -20,6 +20,7 @@ import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; +import noppes.npcs.util.ValueUtil; import java.util.Arrays; import java.util.List; @@ -117,12 +118,19 @@ public class AbilityGuard extends Ability implements IAbilityGuard { } public void onDamageTaken(EntityLivingBase caster, EntityLivingBase attacker, DamageSource source, float damage) { - if (!isGuarding()) return; - if (!canCounter || attacker == null || !counterEligible) return; - if (!isDirectHit(source)) return; + if (!isGuarding() || attacker == null) return; lastAttacker = attacker; lastDamageTaken = damage; + + float reduction = ValueUtil.clamp(getDamageReductionFactor(), 0, damage); + float newHealth = ValueUtil.clamp(caster.getHealth() + reduction, 0, caster.getMaxHealth()); + + caster.setHealth(newHealth); + + if (!canCounter || !counterEligible || counterTriggered) return; + if (!isDirectHit(source)) return; + counterTriggered = true; // Counter will be performed in onActiveTick - don't self-interrupt } From 8aa6e926f62ed61fdb4d7e36715aff6e37b46e05 Mon Sep 17 00:00:00 2001 From: Kam Date: Tue, 3 Feb 2026 04:27:54 -0500 Subject: [PATCH 07/14] Some Ability Helpers --- src/api | 2 +- .../controllers/data/ability/Ability.java | 29 ++++- .../data/ability/type/AbilityCutter.java | 36 +++++-- .../data/ability/type/AbilityDash.java | 19 ++++ .../data/ability/type/AbilityHeavyHit.java | 102 +++++++++++++++--- .../data/ability/type/AbilitySlam.java | 91 ++++++++++------ .../data/ability/type/AbilityVortex.java | 7 +- .../npcs/entity/EntityAbilityProjectile.java | 17 +++ .../gui/advanced/SubGuiAbilityConfig.java | 8 +- .../npcs/client/gui/builder/FieldDef.java | 51 +++++++++ .../client/gui/builder/GuiFieldBuilder.java | 40 +++---- .../npcs/client/gui/util/GuiNPCInterface.java | 16 +++ 12 files changed, 326 insertions(+), 92 deletions(-) diff --git a/src/api b/src/api index f9de3f4f3..03be7a5ca 160000 --- a/src/api +++ b/src/api @@ -1 +1 @@ -Subproject commit f9de3f4f326d8e45750d28695a5f212db70bdfca +Subproject commit 03be7a5cac601cd19509df9dc7bac17081aea591 diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java index 2148a239d..3b892335e 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java @@ -409,9 +409,26 @@ public abstract class Ability implements IAbility { FieldDef.intField("ability.maxRange", () -> (int) getMaxRange(), v -> setMaxRange(v)).range(1, 100) ).tab("Target")); if (!isTargetingModeLocked()) { - defs.add(FieldDef.enumField("ability.targetingMode", TargetingMode.class, - this::getTargetingMode, this::setTargetingMode) - .tab("Target").hover("ability.hover.targeting")); + TargetingMode[] allowed = getAllowedTargetingModes(); + if (allowed != null && allowed.length > 0) { + // Build string enum from allowed targeting modes only + String[] allowedKeys = new String[allowed.length]; + for (int i = 0; i < allowed.length; i++) { + allowedKeys[i] = allowed[i].name(); + } + defs.add(FieldDef.stringEnumField("ability.targetingMode", allowedKeys, + () -> this.getTargetingMode().name(), + v -> { + try { this.setTargetingMode(TargetingMode.valueOf(v)); } + catch (Exception ignored) {} + }) + .tab("Target").hover("ability.hover.targeting")); + } else { + // No restrictions - show all modes + defs.add(FieldDef.enumField("ability.targetingMode", TargetingMode.class, + this::getTargetingMode, this::setTargetingMode) + .tab("Target").hover("ability.hover.targeting")); + } } // Effects tab - Sounds @@ -563,8 +580,12 @@ public abstract class Ability implements IAbility { instance.setEntityIdToFollow(caster.getEntityId()); // For LINE/CONE telegraphs: track target direction during windup + // Only track if movement is NOT locked during windup (locked = NPC can't rotate) if ((telegraphType == TelegraphType.LINE || telegraphType == TelegraphType.CONE) && target != null) { - instance.setTargetEntityId(target.getEntityId()); + if (!lockMovement.locksWindup()) { + instance.setTargetEntityId(target.getEntityId()); + } + // If windup is locked, yaw stays fixed at creation time } } else if (target != null) { // AOE_TARGET abilities: telegraph follows target during windup diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java index ba0962356..e0e5e020a 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java @@ -113,12 +113,16 @@ public class AbilityCutter extends Ability implements IAbilityCutter { switch (sweepMode) { case SWIPE: + float prevRotation = currentRotation; + currentRotation += sweepSpeed; if (currentRotation > arcAngle / 2.0f) { - signalCompletion(); // Swipe arc complete + // Final sweep — check from prevRotation to end of arc + performSweepDamageRange(caster, world, innerRadius, range, prevRotation, arcAngle / 2.0f); + signalCompletion(); return; } - performSweepDamage(caster, world, innerRadius, range, currentRotation); - currentRotation += sweepSpeed; + // Check entities between previous and current sweep position + performSweepDamageRange(caster, world, innerRadius, range, prevRotation, currentRotation); break; case SPIN: @@ -126,15 +130,23 @@ public class AbilityCutter extends Ability implements IAbilityCutter { signalCompletion(); // Spin duration complete return; } + float prevSpin = currentRotation; currentRotation = (currentRotation + sweepSpeed) % 360.0f; hitEntities.clear(); - performSweepDamage(caster, world, innerRadius, range, currentRotation); + performSweepDamageRange(caster, world, innerRadius, range, prevSpin, currentRotation); break; } } - private void performSweepDamage(EntityLivingBase caster, World world, float minDist, float maxDist, float angleOffset) { - float casterYaw = caster.rotationYaw + angleOffset; + /** + * Check for entities between two sweep angles, ensuring no gaps between ticks. + * For SWIPE mode, this covers the continuous arc from startAngle to endAngle. + */ + private void performSweepDamageRange(EntityLivingBase caster, World world, float minDist, float maxDist, + float startAngle, float endAngle) { + // Calculate the angular range covered this tick + float minAngle = Math.min(startAngle, endAngle); + float maxAngle = Math.max(startAngle, endAngle); AxisAlignedBB searchBox = AxisAlignedBB.getBoundingBox( caster.posX - maxDist, caster.posY - 1, caster.posZ - maxDist, @@ -155,7 +167,7 @@ public class AbilityCutter extends Ability implements IAbilityCutter { double dist = Math.sqrt(dx * dx + dz * dz); if (dist < minDist || dist > maxDist) continue; - if (!isInArc(dx, dz, casterYaw, arcAngle)) continue; + if (!isInSweepRange(dx, dz, caster.rotationYaw, minAngle, maxAngle)) continue; hitEntities.add(entity.getEntityId()); @@ -172,6 +184,16 @@ public class AbilityCutter extends Ability implements IAbilityCutter { } } + /** + * Check if an entity falls within the angular range between two sweep positions. + * This ensures entities at long range can't slip between tick-gaps. + */ + private boolean isInSweepRange(double dx, double dz, float casterYaw, float minAngle, float maxAngle) { + double angleToEntity = Math.toDegrees(Math.atan2(-dx, dz)); + double entityRelative = normalizeAngle(angleToEntity - casterYaw); + return entityRelative >= minAngle && entityRelative <= maxAngle; + } + private boolean isInArc(double dx, double dz, float casterYaw, float arcWidth) { double angleToEntity = Math.toDegrees(Math.atan2(-dx, dz)); double angleDiff = normalizeAngle(angleToEntity - casterYaw); diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java index fb5d59f0e..6c514a7f0 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java @@ -92,6 +92,7 @@ public class AbilityDash extends Ability implements IAbilityDash { // Runtime state private transient Vec3 dashDirection; private transient double startX, startY, startZ; + private transient double prevTickX, prevTickZ; private transient DashDirection chosenDirection; public AbilityDash() { @@ -130,6 +131,8 @@ public class AbilityDash extends Ability implements IAbilityDash { startX = caster.posX; startY = caster.posY; startZ = caster.posZ; + prevTickX = caster.posX; + prevTickZ = caster.posZ; // Choose random direction based on mode DashDirection[] directions = dashMode == DashMode.AGGRESSIVE @@ -163,6 +166,22 @@ public class AbilityDash extends Ability implements IAbilityDash { public void onActiveTick(EntityLivingBase caster, EntityLivingBase target, World world, int tick) { if (dashDirection == null) return; + // Stall detection: if entity hasn't moved since last tick, it's stuck against a wall + if (tick > 1) { + double movedThisTick = Math.sqrt( + Math.pow(caster.posX - prevTickX, 2) + + Math.pow(caster.posZ - prevTickZ, 2)); + if (movedThisTick < 0.01) { + caster.motionX = 0; + caster.motionZ = 0; + caster.velocityChanged = true; + signalCompletion(); + return; + } + } + prevTickX = caster.posX; + prevTickZ = caster.posZ; + // Calculate distance traveled double distanceTraveled = Math.sqrt( Math.pow(caster.posX - startX, 2) + diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java index 3db472c1a..ce432e01a 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java @@ -6,37 +6,40 @@ import kamkeel.npcs.controllers.data.ability.Ability; import kamkeel.npcs.controllers.data.ability.LockMovementType; import kamkeel.npcs.controllers.data.ability.TargetingMode; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.world.World; import noppes.npcs.client.gui.builder.FieldDef; import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldDefs; import noppes.npcs.api.ability.type.IAbilityHeavyHit; -import noppes.npcs.entity.EntityNPCInterface; import java.util.Arrays; import java.util.List; /** - * Heavy Hit ability: Single-target melee attack with optional stun. - * Deals high damage to one target and can stun them. + * Heavy Hit ability: AOE rectangle melee attack in front of the caster. + * Deals high damage to all entities within a rectangular zone and can apply effects. + * Has a LINE telegraph showing the hit area during windup, making it dodgeable. */ public class AbilityHeavyHit extends Ability implements IAbilityHeavyHit { private float damage = 8.0f; private float knockback = 2.0f; + private float hitLength = 4.0f; // How far in front of the caster the hit reaches + private float hitWidth = 3.0f; // How wide to each side (total width = hitWidth * 2) public AbilityHeavyHit() { this.typeId = "ability.cnpc.heavy_hit"; this.name = "Heavy Hit"; - this.targetingMode = TargetingMode.AGGRO_TARGET; - this.maxRange = 3.0f; + this.targetingMode = TargetingMode.AOE_SELF; + this.maxRange = 5.0f; this.minRange = 0.0f; - this.lockMovement = LockMovementType.NO; + this.lockMovement = LockMovementType.WINDUP; this.cooldownTicks = 0; this.windUpTicks = 30; - this.telegraphType = TelegraphType.POINT; - this.showTelegraph = false; + this.telegraphType = TelegraphType.LINE; + this.showTelegraph = true; this.windUpSound = "random.anvil_use"; this.activeSound = "random.anvil_land"; this.windUpAnimationName = "Ability_HeavyHit_Windup"; @@ -50,22 +53,66 @@ public class AbilityHeavyHit extends Ability implements IAbilityHeavyHit { @Override public TargetingMode[] getAllowedTargetingModes() { - return new TargetingMode[]{TargetingMode.AGGRO_TARGET}; + return new TargetingMode[]{TargetingMode.AOE_SELF}; + } + + @Override + public float getTelegraphLength() { + return hitLength; + } + + @Override + public float getTelegraphWidth() { + return hitWidth * 2.0f; // Total width (hitWidth is distance to each side) } @Override public void onExecute(EntityLivingBase caster, EntityLivingBase target, World world) { - if (world.isRemote || target == null) { + if (world.isRemote) { signalCompletion(); return; } - // Apply damage with scripted event support - boolean wasHit = applyAbilityDamage(caster, target, damage, knockback); + // Calculate forward and right vectors from caster yaw + float yawRad = (float) Math.toRadians(caster.rotationYaw); + double forwardX = -Math.sin(yawRad); + double forwardZ = Math.cos(yawRad); + double rightX = forwardZ; // perpendicular right + double rightZ = -forwardX; - // Apply effects if hit wasn't cancelled - if (wasHit) { - applyEffects(target); + // Search area: AABB that encompasses the rectangle + float searchDist = Math.max(hitLength, hitWidth) + 1.0f; + @SuppressWarnings("unchecked") + List entities = world.getEntitiesWithinAABBExcludingEntity( + caster, caster.boundingBox.expand(searchDist, 2, searchDist)); + + boolean anyHit = false; + for (Entity entity : entities) { + if (!(entity instanceof EntityLivingBase) || entity == caster) continue; + EntityLivingBase livingTarget = (EntityLivingBase) entity; + + double dx = livingTarget.posX - caster.posX; + double dz = livingTarget.posZ - caster.posZ; + + // Project onto forward direction (must be in front, within hitLength) + double forwardDist = dx * forwardX + dz * forwardZ; + if (forwardDist < 0 || forwardDist > hitLength) continue; + + // Project onto right direction (must be within hitWidth to each side) + double sideDist = dx * rightX + dz * rightZ; + if (Math.abs(sideDist) > hitWidth) continue; + + // Entity is within the rectangle - apply damage + boolean wasHit = applyAbilityDamage(caster, livingTarget, damage, knockback); + if (wasHit) { + applyEffects(livingTarget); + anyHit = true; + } + } + + // Play hit sound even if nothing was hit (the attack still happens) + if (!anyHit) { + world.playSoundAtEntity(caster, "random.anvil_land", 0.5f, 1.2f); } } @@ -80,12 +127,16 @@ public class AbilityHeavyHit extends Ability implements IAbilityHeavyHit { public void writeTypeNBT(NBTTagCompound nbt) { nbt.setFloat("damage", damage); nbt.setFloat("knockback", knockback); + nbt.setFloat("hitLength", hitLength); + nbt.setFloat("hitWidth", hitWidth); } @Override public void readTypeNBT(NBTTagCompound nbt) { this.damage = nbt.hasKey("damage") ? nbt.getFloat("damage") : 8.0f; this.knockback = nbt.hasKey("knockback") ? nbt.getFloat("knockback") : 2.0f; + this.hitLength = nbt.hasKey("hitLength") ? nbt.getFloat("hitLength") : 4.0f; + this.hitWidth = nbt.hasKey("hitWidth") ? nbt.getFloat("hitWidth") : 3.0f; } // Getters & Setters @@ -105,6 +156,22 @@ public class AbilityHeavyHit extends Ability implements IAbilityHeavyHit { this.knockback = knockback; } + public float getHitLength() { + return hitLength; + } + + public void setHitLength(float hitLength) { + this.hitLength = hitLength; + } + + public float getHitWidth() { + return hitWidth; + } + + public void setHitWidth(float hitWidth) { + this.hitWidth = hitWidth; + } + @SideOnly(Side.CLIENT) @Override public List getFieldDefinitions() { @@ -113,6 +180,11 @@ public class AbilityHeavyHit extends Ability implements IAbilityHeavyHit { FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback) ), + FieldDef.section("ability.section.hitZone"), + FieldDef.row( + FieldDef.floatField("ability.hitLength", this::getHitLength, this::setHitLength), + FieldDef.floatField("ability.hitWidth", this::getHitWidth, this::setHitWidth) + ), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) ); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java index 94381209b..39f1a3ca8 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java @@ -130,9 +130,46 @@ public class AbilitySlam extends Ability implements IAbilitySlam { launchTowardTarget(caster); } + /** + * Calculate the initial vertical velocity needed to reach a target height + * in Minecraft's physics (gravity=0.08, vertical drag=0.98). + * Uses iterative simulation since the drag makes a closed-form solution impractical. + */ + private static double calculateLaunchVelocity(double targetHeight) { + // Binary search for the initial velocity that reaches targetHeight + double lo = 0.0, hi = 10.0; + for (int iter = 0; iter < 30; iter++) { + double mid = (lo + hi) / 2.0; + double maxY = simulateMaxHeight(mid); + if (maxY < targetHeight) { + lo = mid; + } else { + hi = mid; + } + } + return (lo + hi) / 2.0; + } + + /** + * Simulate Minecraft vertical physics to find peak height reached + * with a given initial upward velocity. + */ + private static double simulateMaxHeight(double vy) { + double y = 0; + double maxY = 0; + for (int t = 0; t < 200 && vy > 0; t++) { + y += vy; + vy -= 0.08; // gravity + vy *= 0.98; // vertical drag + if (y > maxY) maxY = y; + } + return maxY; + } + /** * Calculate ballistic arc and launch caster toward target. - * Accounts for Minecraft's drag physics to actually reach the destination. + * leapHeight = exact peak height in blocks above launch point. + * leapSpeed = velocity multiplier (faster motion, same height). */ private void launchTowardTarget(EntityLivingBase caster) { double dx = targetX - caster.posX; @@ -140,11 +177,15 @@ public class AbilitySlam extends Ability implements IAbilitySlam { double dz = targetZ - caster.posZ; double horizontalDist = Math.sqrt(dx * dx + dz * dz); + // Calculate vertical velocity to reach exact leapHeight + double arcHeight = Math.max(1.0, leapHeight); + double vy = calculateLaunchVelocity(arcHeight); + // For AOE_SELF or very close targets, just hop in place if (horizontalDist < 0.5) { caster.motionX = 0; caster.motionZ = 0; - caster.motionY = 0.8 * leapSpeed; + caster.motionY = vy; hasLaunched = true; if (caster instanceof EntityNPCInterface) { ((EntityNPCInterface) caster).setNpcJumpingState(true); @@ -164,8 +205,9 @@ public class AbilitySlam extends Ability implements IAbilitySlam { targetZ = caster.posZ + dz; } - // Choose flight time based on distance - shorter distances = faster - int flightTicks = (int) Math.max(15, Math.min(horizontalDist * 1.5, 30)); + // Choose flight time based on distance, scaled by speed (faster = fewer ticks) + double speedFactor = Math.max(0.1, leapSpeed); + int flightTicks = (int) Math.max(10, Math.min(horizontalDist * 1.5 / speedFactor, 40)); // Minecraft applies drag of 0.91 per tick to horizontal motion in air // Total distance traveled with initial velocity v0 over n ticks: @@ -175,34 +217,16 @@ public class AbilitySlam extends Ability implements IAbilitySlam { double dragPowN = Math.pow(drag, flightTicks); double vHorizontal = horizontalDist * (1.0 - drag) / (1.0 - dragPowN); - // Scale by leap speed - vHorizontal *= leapSpeed; + // Speed scales horizontal velocity to cover ground faster + vHorizontal *= speedFactor; - // Vertical velocity calculation: - // Minecraft gravity is 0.08 per tick, with 0.98 drag on vertical motion - // For a nice arc, we want to peak roughly in the middle of the flight - double gravity = 0.08; - double verticalDrag = 0.98; - - // Calculate required upward velocity to create a nice arc and land at target height - // Peak height should be proportional to horizontal distance for visual appeal - double arcHeight = Math.max(1.0, leapHeight) * leapSpeed; - - // Approximate the required initial vertical velocity - // Account for gravity and drag - use a simplified model - double peakTicks = flightTicks * 0.4; // Peak around 40% through flight - double vy = (arcHeight * 2.0 / peakTicks) + (gravity * peakTicks * 0.5); - - // Adjust for height difference + // Adjust vertical velocity for height difference between start and target if (dy > 0) { vy += dy / flightTicks * 1.5; // Going up - need more velocity } else if (dy < 0) { vy += dy / flightTicks * 0.3; // Going down - gravity helps } - // Ensure minimum upward velocity for visible jump - vy = Math.max(vy, 0.6 * leapSpeed); - // Normalize horizontal direction and apply velocity double dirX = dx / horizontalDist; double dirZ = dz / horizontalDist; @@ -221,7 +245,6 @@ public class AbilitySlam extends Ability implements IAbilitySlam { float targetYaw = (float) (Math.atan2(-dx, dz) * 180.0D / Math.PI); caster.rotationYaw = targetYaw; caster.rotationYawHead = targetYaw; - } @Override @@ -395,10 +418,14 @@ public class AbilitySlam extends Ability implements IAbilitySlam { double dz = tz - npc.posZ; double horizontalDist = Math.sqrt(dx * dx + dz * dz); + // Calculate vertical velocity for exact leapHeight + double arcHeight = Math.max(1.0, leapHeight); + double vy = calculateLaunchVelocity(arcHeight); + if (horizontalDist < 0.5) { previewVelX = 0; previewVelZ = 0; - previewVelY = 0.8 * leapSpeed; + previewVelY = vy; } else { if (horizontalDist > maxRange) { double scale = maxRange / horizontalDist; @@ -407,15 +434,11 @@ public class AbilitySlam extends Ability implements IAbilitySlam { horizontalDist = maxRange; } - int flightTicks = (int) Math.max(15, Math.min(horizontalDist * 1.5, 30)); + double speedFactor = Math.max(0.1, leapSpeed); + int flightTicks = (int) Math.max(10, Math.min(horizontalDist * 1.5 / speedFactor, 40)); double drag = 0.91; double dragPowN = Math.pow(drag, flightTicks); - double vHorizontal = horizontalDist * (1.0 - drag) / (1.0 - dragPowN) * leapSpeed; - - double arcHeight = Math.max(1.0, leapHeight) * leapSpeed; - double peakTicks = flightTicks * 0.4; - double vy = (arcHeight * 2.0 / peakTicks) + (0.08 * peakTicks * 0.5); - vy = Math.max(vy, 0.6 * leapSpeed); + double vHorizontal = horizontalDist * (1.0 - drag) / (1.0 - dragPowN) * speedFactor; double dirX = dx / horizontalDist; double dirZ = dz / horizontalDist; diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java index 6c92304e2..aaa6041f4 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java @@ -138,7 +138,7 @@ public class AbilityVortex extends Ability implements IAbilityVortex { double dz = destZ - entity.posZ; double dist = Math.sqrt(dx * dx + dy * dy + dz * dz); - if (dist <= 1.0f) { + if (dist <= 1.5f) { getPulledEntities().remove(uuid); onTargetArrived(caster, entity, world); continue; @@ -146,7 +146,10 @@ public class AbilityVortex extends Ability implements IAbilityVortex { anyStillPulling = true; - double factor = pullStrength / dist; + // Clamp speed to never exceed half the remaining distance, preventing overshoot/slingshot + double maxSpeed = dist * 0.5; + double effectiveSpeed = Math.min(pullStrength, maxSpeed); + double factor = effectiveSpeed / dist; double nextX = dx * factor; double nextY = dy * factor * 0.5; double nextZ = dz * factor; diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityProjectile.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityProjectile.java index 57f99e1c8..10dd0d953 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityProjectile.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityProjectile.java @@ -192,6 +192,19 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA // Skip lifetime/distance checks in preview mode if (!previewMode) { + // Failsafe: if owner entity is gone, dead, or NPC was killed/reset, self-destruct + if (ownerEntityId >= 0 && ticksExisted > 5) { + Entity owner = worldObj.getEntityByID(ownerEntityId); + if (owner == null || owner.isDead) { + this.setDead(); + return; + } + if (owner instanceof EntityNPCInterface && ((EntityNPCInterface) owner).isKilled()) { + this.setDead(); + return; + } + } + // Set death time on first tick if not already set (handles chunk load/unload) if (deathWorldTime < 0 && worldObj != null) { deathWorldTime = worldObj.getTotalWorldTime() + maxLifetime; @@ -392,6 +405,10 @@ public abstract class EntityAbilityProjectile extends Entity implements IEntityA // ==================== ENTITY HELPERS ==================== + public int getOwnerEntityId() { + return ownerEntityId; + } + protected Entity getOwner() { // In preview mode, use direct reference (no world lookup) if (previewMode && previewOwner != null) { diff --git a/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java b/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java index 60c3561b3..1e97227a9 100644 --- a/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java +++ b/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java @@ -281,11 +281,9 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi // Declarative field handling (effects list, booleans, enums, sub-guis, clear buttons) if (builder.handleButtonEvent(id, guibutton)) { - // SUB_GUI needs special handling: open the sub-gui - FieldDef subGuiDef = builder.getActiveSubGuiField(); - if (subGuiDef != null && subGuiDef.getSubGuiFactory() != null) { - setSubGui(subGuiDef.getSubGuiFactory().get()); - } else { + // SUB_GUI fields are opened directly by the builder via setSubGuiWithResult(). + // Only rebuild if no sub-gui was opened (e.g. boolean toggle, enum change). + if (!hasSubGui()) { initGui(); } return; diff --git a/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java b/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java index 63f188d44..6d9ee58ec 100644 --- a/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java +++ b/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java @@ -297,4 +297,55 @@ public class FieldDef { public FieldDef getLeftChild() { return leftChild; } public FieldDef getRightChild() { return rightChild; } + // ═══════════════════════════════════════════════════════════════════ + // LIST MANIPULATION (for mod injection) + // ═══════════════════════════════════════════════════════════════════ + + /** + * Insert a field before the first field matching the target label. + * Searches top-level labels and ROW children. + * + * @param fields The field list to modify + * @param targetLabel The label of the field to insert before + * @param newField The field to insert + * @return true if the target was found and the field was inserted + */ + public static boolean insertBefore(java.util.List fields, String targetLabel, FieldDef newField) { + for (int i = 0; i < fields.size(); i++) { + if (matchesLabel(fields.get(i), targetLabel)) { + fields.add(i, newField); + return true; + } + } + return false; + } + + /** + * Insert a field after the first field matching the target label. + * Searches top-level labels and ROW children. + * + * @param fields The field list to modify + * @param targetLabel The label of the field to insert after + * @param newField The field to insert + * @return true if the target was found and the field was inserted + */ + public static boolean insertAfter(java.util.List fields, String targetLabel, FieldDef newField) { + for (int i = 0; i < fields.size(); i++) { + if (matchesLabel(fields.get(i), targetLabel)) { + fields.add(i + 1, newField); + return true; + } + } + return false; + } + + private static boolean matchesLabel(FieldDef def, String targetLabel) { + if (targetLabel.equals(def.label)) return true; + if (def.type == FieldType.ROW) { + if (def.leftChild != null && targetLabel.equals(def.leftChild.label)) return true; + if (def.rightChild != null && targetLabel.equals(def.rightChild.label)) return true; + } + return false; + } + } diff --git a/src/main/java/noppes/npcs/client/gui/builder/GuiFieldBuilder.java b/src/main/java/noppes/npcs/client/gui/builder/GuiFieldBuilder.java index 43a3956c1..42e117ecf 100644 --- a/src/main/java/noppes/npcs/client/gui/builder/GuiFieldBuilder.java +++ b/src/main/java/noppes/npcs/client/gui/builder/GuiFieldBuilder.java @@ -333,11 +333,13 @@ public class GuiFieldBuilder { // EVENT HANDLING // ═══════════════════════════════════════════════════════════════════ - private FieldDef activeSubGuiField; - /** * Handles button events for declarative fields. * Call from parent GUI's buttonEvent(). Returns true if the event was handled. + *

+ * For SUB_GUI fields, the sub-gui is opened directly via {@code parent.setSubGuiWithResult()}, + * so the result handler survives initGui() rebuilds. After this returns true, check + * {@code parent.hasSubGui()} to determine if initGui() should be called. */ @SuppressWarnings({"unchecked", "rawtypes"}) public boolean handleButtonEvent(int buttonId, GuiButton button) { @@ -374,7 +376,13 @@ public class GuiFieldBuilder { return true; } case SUB_GUI: - activeSubGuiField = def; + if (def.getSubGuiFactory() != null) { + parent.setSubGuiWithResult(def.getSubGuiFactory().get(), sub -> { + if (def.getSubGuiResultHandler() != null) { + def.getSubGuiResultHandler().accept(sub); + } + }); + } return true; default: return false; @@ -406,32 +414,16 @@ public class GuiFieldBuilder { /** * Handles sub-gui close events. Call from parent GUI's subGuiClosed(). - * Returns true if the event was handled (activeSubGuiField was set). + *

+ * Note: SUB_GUI fields opened via handleButtonEvent use + * {@code parent.setSubGuiWithResult()}, so their results are handled + * automatically by {@code GuiNPCInterface.closeSubGui()}. This method + * only handles sub-guis opened through other means. */ public boolean handleSubGuiClosed(SubGuiInterface subgui) { - if (activeSubGuiField != null) { - FieldDef def = activeSubGuiField; - activeSubGuiField = null; - if (def.getSubGuiResultHandler() != null) { - def.getSubGuiResultHandler().accept(subgui); - } - return true; - } return false; } - /** - * Returns the FieldDef for the currently active sub-gui, or null. - * After handleButtonEvent returns true for a SUB_GUI field, the parent - * should check this and call setSubGui(def.getSubGuiFactory().get()). - */ - public FieldDef getActiveSubGuiField() { return activeSubGuiField; } - - /** - * Clears the active sub-gui field tracking. - */ - public void clearActiveSubGuiField() { activeSubGuiField = null; } - // ═══════════════════════════════════════════════════════════════════ // GETTERS // ═══════════════════════════════════════════════════════════════════ diff --git a/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface.java b/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface.java index 4ddd820c0..06f74bffe 100644 --- a/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface.java +++ b/src/main/java/noppes/npcs/client/gui/util/GuiNPCInterface.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; import java.util.function.Supplier; public abstract class GuiNPCInterface extends GuiScreen { @@ -52,6 +53,7 @@ public abstract class GuiNPCInterface extends GuiScreen { public Supplier closeOnEscSupplier = null; public int guiLeft, guiTop, xSize, ySize; private SubGuiInterface subgui; + private Consumer pendingSubGuiResult; public int mouseX, mouseY, mouseScroll; public float bgScale = 1; public float bgScaleX = 1; @@ -519,7 +521,21 @@ public abstract class GuiNPCInterface extends GuiScreen { initGui(); } + /** + * Open a sub-gui with a result handler that will be called when the sub-gui closes. + * The handler survives initGui() rebuilds since it lives on the parent, not the builder. + */ + public void setSubGuiWithResult(SubGuiInterface gui, Consumer resultHandler) { + this.pendingSubGuiResult = resultHandler; + setSubGui(gui); + } + public void closeSubGui(SubGuiInterface gui) { + if (pendingSubGuiResult != null) { + Consumer handler = pendingSubGuiResult; + pendingSubGuiResult = null; + handler.accept(gui); + } subgui = null; initGui(); } From b368871e4f2000c814b10210a4bc0ac60eb359ad Mon Sep 17 00:00:00 2001 From: Kam Date: Tue, 3 Feb 2026 04:45:31 -0500 Subject: [PATCH 08/14] Update Ability.java --- .../npcs/controllers/data/ability/Ability.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java index 3b892335e..cda26df62 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java @@ -481,6 +481,7 @@ public abstract class Ability implements IAbility { @SideOnly(Side.CLIENT) public final List getAllFieldDefinitions() { List all = new ArrayList<>(getBaseFieldDefinitions()); + modifyBaseFieldDefinitions(all); List typeDefs = getFieldDefinitions(); // Default tab for type-specific fields that don't explicitly set one for (FieldDef def : typeDefs) { @@ -492,6 +493,17 @@ public abstract class Ability implements IAbility { return all; } + /** + * Override to modify the base field definitions before type-specific fields are added. + * Use {@link FieldDef#insertBefore}, {@link FieldDef#insertAfter}, or direct list + * manipulation to add, remove, or reorder base fields. + * + * @param baseFields The mutable list of base fields (General/Target/Effects tabs) + */ + @SideOnly(Side.CLIENT) + protected void modifyBaseFieldDefinitions(List baseFields) { + } + /** * Creates the GUI for configuring this ability. * Override this method to provide a custom GUI subclass for type-specific settings. From fd85215592d1d703e199e2160e1630ac76115e6e Mon Sep 17 00:00:00 2001 From: Kam Date: Tue, 3 Feb 2026 05:07:54 -0500 Subject: [PATCH 09/14] Fix Ability Def Handler --- .../controllers/data/ability/Ability.java | 70 +++++++------------ .../data/ability/type/AbilityBeamDual.java | 6 +- .../data/ability/type/AbilityCharge.java | 6 +- .../data/ability/type/AbilityCutter.java | 6 +- .../data/ability/type/AbilityDash.java | 6 +- .../data/ability/type/AbilityDisc.java | 6 +- .../data/ability/type/AbilityDiscDual.java | 6 +- .../data/ability/type/AbilityEnergyBeam.java | 6 +- .../data/ability/type/AbilityGuard.java | 6 +- .../data/ability/type/AbilityHazard.java | 6 +- .../data/ability/type/AbilityHeal.java | 6 +- .../data/ability/type/AbilityHeavyHit.java | 6 +- .../data/ability/type/AbilityLaserShot.java | 6 +- .../data/ability/type/AbilityOrb.java | 6 +- .../data/ability/type/AbilityOrbBarrage.java | 6 +- .../data/ability/type/AbilityOrbDual.java | 6 +- .../data/ability/type/AbilityProjectile.java | 6 +- .../data/ability/type/AbilityShockwave.java | 6 +- .../data/ability/type/AbilitySlam.java | 6 +- .../data/ability/type/AbilitySweeper.java | 6 +- .../data/ability/type/AbilityTeleport.java | 6 +- .../data/ability/type/AbilityTrap.java | 6 +- .../data/ability/type/AbilityVortex.java | 6 +- .../gui/advanced/SubGuiAbilityConfig.java | 4 +- 24 files changed, 94 insertions(+), 112 deletions(-) diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java index cda26df62..86a5e3794 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java @@ -33,7 +33,6 @@ import noppes.npcs.scripted.event.player.PlayerAbilityEvent; import noppes.npcs.client.gui.builder.FieldDef; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import net.minecraft.entity.Entity; @@ -345,24 +344,31 @@ public abstract class Ability implements IAbility { } /** - * Returns the declarative field definitions for this ability's GUI. - * Override in subclasses to declare type-specific and visual fields. - * The GUI rendering engine in SubGuiAbilityConfig uses this list to - * automatically build the Type and Visual tabs. + * Add field definitions for this ability's GUI. + * Override in subclasses to add type-specific fields. The list already contains + * the base fields (General, Target, Effects tabs), so subclasses can also + * modify, insert into, or remove base fields using {@link FieldDef#insertBefore}, + * {@link FieldDef#insertAfter}, or direct list manipulation. + *

+ * Fields added here without an explicit {@code .tab()} will default to the "Type" tab. + * + * @param defs The mutable list of field definitions to add to or modify */ @SideOnly(Side.CLIENT) - public List getFieldDefinitions() { - return Collections.emptyList(); + public void getAbilityDefinitions(List defs) { } /** - * Returns field definitions for all base Ability fields (General, Target, Effects tabs). + * Builds and returns all field definitions for this ability's GUI. + * Base fields (General, Target, Effects) are added first, then + * {@link #getAbilityDefinitions(List)} is called so subclasses can add + * type-specific fields and modify any existing fields. */ @SideOnly(Side.CLIENT) - public List getBaseFieldDefinitions() { + public final List getAllDefinitions() { List defs = new ArrayList<>(); - // General tab + // ── General tab ────────────────────────────────────────────── defs.add(FieldDef.stringField("gui.name", this::getName, this::setName) .tab("General")); defs.add(FieldDef.row( @@ -370,7 +376,6 @@ public abstract class Ability implements IAbility { FieldDef.boolField("gui.enabled", this::isEnabled, this::setEnabled) ).tab("General")); defs.add(FieldDef.section("ability.section.timing").tab("General")); - // WindUp: 3 mutually exclusive entries based on animation/sync state defs.add(FieldDef.intField("ability.windUpTicks", this::getRawWindUpTicks, this::setWindUpTicks) .tab("General").range(0, 1000) .visibleWhen(() -> !hasWindUpAnimation())); @@ -403,7 +408,7 @@ public abstract class Ability implements IAbility { .range(0, 1000).visibleWhen(this::isInterruptible) ).tab("General")); - // Target tab + // ── Target tab ─────────────────────────────────────────────── defs.add(FieldDef.row( FieldDef.intField("ability.minRange", () -> (int) getMinRange(), v -> setMinRange(v)).range(0, 100), FieldDef.intField("ability.maxRange", () -> (int) getMaxRange(), v -> setMaxRange(v)).range(1, 100) @@ -411,7 +416,6 @@ public abstract class Ability implements IAbility { if (!isTargetingModeLocked()) { TargetingMode[] allowed = getAllowedTargetingModes(); if (allowed != null && allowed.length > 0) { - // Build string enum from allowed targeting modes only String[] allowedKeys = new String[allowed.length]; for (int i = 0; i < allowed.length; i++) { allowedKeys[i] = allowed[i].name(); @@ -424,20 +428,18 @@ public abstract class Ability implements IAbility { }) .tab("Target").hover("ability.hover.targeting")); } else { - // No restrictions - show all modes defs.add(FieldDef.enumField("ability.targetingMode", TargetingMode.class, this::getTargetingMode, this::setTargetingMode) .tab("Target").hover("ability.hover.targeting")); } } - // Effects tab - Sounds + // ── Effects tab ────────────────────────────────────────────── defs.add(FieldDef.section("ability.section.sounds").tab("Effects")); defs.add(FieldDef.soundSubGui("ability.windUpSound", this::getWindUpSound, this::setWindUpSound) .tab("Effects")); defs.add(FieldDef.soundSubGui("ability.activeSound", this::getActiveSound, this::setActiveSound) .tab("Effects")); - // Effects tab - Animations defs.add(FieldDef.section("ability.section.animations").tab("Effects")); defs.add(FieldDef.animSubGui("ability.windUpAnimation", this::getWindUpAnimationId, this::setWindUpAnimationId, @@ -459,7 +461,6 @@ public abstract class Ability implements IAbility { ); } - // Effects tab - Telegraph TelegraphType tType = getTelegraphType(); if (tType != null && tType != TelegraphType.NONE) { defs.add(FieldDef.section("ability.section.telegraph").tab("Effects") @@ -472,36 +473,17 @@ public abstract class Ability implements IAbility { .tab("Effects").visibleWhen(this::isShowTelegraph)); } - return defs; - } - - /** - * Returns ALL field definitions: base (General/Target/Effects) + type-specific (Type/Visual). - */ - @SideOnly(Side.CLIENT) - public final List getAllFieldDefinitions() { - List all = new ArrayList<>(getBaseFieldDefinitions()); - modifyBaseFieldDefinitions(all); - List typeDefs = getFieldDefinitions(); - // Default tab for type-specific fields that don't explicitly set one - for (FieldDef def : typeDefs) { - if (def.getTab() == null) { - def.tab("Type"); + // ── Type-specific fields ───────────────────────────────────── + int baseSize = defs.size(); + getAbilityDefinitions(defs); + // Default tab for ability-added fields that don't specify one + for (int i = baseSize; i < defs.size(); i++) { + if (defs.get(i).getTab() == null) { + defs.get(i).tab("Type"); } } - all.addAll(typeDefs); - return all; - } - /** - * Override to modify the base field definitions before type-specific fields are added. - * Use {@link FieldDef#insertBefore}, {@link FieldDef#insertAfter}, or direct list - * manipulation to add, remove, or reorder base fields. - * - * @param baseFields The mutable list of base fields (General/Target/Effects tabs) - */ - @SideOnly(Side.CLIENT) - protected void modifyBaseFieldDefinitions(List baseFields) { + return defs; } /** diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java index 955fa1a42..61ba417fa 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java @@ -377,8 +377,8 @@ public class AbilityBeamDual extends Ability { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( // Type tab FieldDef.row( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), @@ -485,7 +485,7 @@ public class AbilityBeamDual extends Ability { () -> getLightningRadius(1), v -> setLightningRadius(1, v)) .range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(1)) ).tab("ability.tab.visual") - ); + )); } @Override diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCharge.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCharge.java index d149dc3ad..e09ff7e11 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCharge.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCharge.java @@ -397,8 +397,8 @@ public class AbilityCharge extends Ability implements IAbilityCharge { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( FieldDef.row( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), FieldDef.floatField("ability.chargeSpeed", this::getChargeSpeed, this::setChargeSpeed) @@ -408,6 +408,6 @@ public class AbilityCharge extends Ability implements IAbilityCharge { FieldDef.floatField("ability.hitWidth", this::getHitWidth, this::setHitWidth) ), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java index e0e5e020a..405dac612 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityCutter.java @@ -338,8 +338,8 @@ public class AbilityCutter extends Ability implements IAbilityCutter { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( FieldDef.row( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), FieldDef.floatField("gui.range", this::getRange, this::setRange) @@ -359,6 +359,6 @@ public class AbilityCutter extends Ability implements IAbilityCutter { FieldDef.boolField("ability.piercing", this::isPiercing, this::setPiercing) .hover("ability.hover.piercing"), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java index 6c514a7f0..10cfd2978 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDash.java @@ -370,14 +370,14 @@ public class AbilityDash extends Ability implements IAbilityDash { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( FieldDef.enumField("ability.dashMode", DashMode.class, this::getDashModeEnum, this::setDashModeEnum) .hover("ability.hover.dashMode"), FieldDef.row( FieldDef.floatField("ability.dashDistance", this::getDashDistance, this::setDashDistance), FieldDef.floatField("ability.dashSpeed", this::getDashSpeed, this::setDashSpeed) ) - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java index f44270c14..4f48c1c90 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java @@ -273,8 +273,8 @@ public class AbilityDisc extends Ability implements IAbilityDisc { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( // Type tab FieldDef.row( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), @@ -333,6 +333,6 @@ public class AbilityDisc extends Ability implements IAbilityDisc { FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) ).tab("ability.tab.visual") - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java index cf57498c3..2717da23a 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java @@ -386,8 +386,8 @@ public class AbilityDiscDual extends Ability { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( // Type tab FieldDef.row( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), @@ -495,7 +495,7 @@ public class AbilityDiscDual extends Ability { () -> getLightningRadius(1), v -> setLightningRadius(1, v)) .range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(1)) ).tab("ability.tab.visual") - ); + )); } @Override diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java index 03182d847..5c960960a 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java @@ -276,8 +276,8 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( // Type tab FieldDef.row( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), @@ -335,6 +335,6 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) ).tab("ability.tab.visual") - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java index 829a51c8f..dcf43d530 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java @@ -341,8 +341,8 @@ public class AbilityGuard extends Ability implements IAbilityGuard { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( FieldDef.intField("ability.duration", this::getDurationTicks, this::setDurationTicks).range(1, 1000), FieldDef.floatField("ability.damageReduction", this::getDamageReduction, this::setDamageReduction), FieldDef.section("ability.section.counter"), @@ -359,6 +359,6 @@ public class AbilityGuard extends Ability implements IAbilityGuard { .visibleWhen(this::canCounter), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHazard.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHazard.java index d98110faf..99ea47172 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHazard.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHazard.java @@ -630,8 +630,8 @@ public class AbilityHazard extends Ability implements IAbilityHazard { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( FieldDef.intField("ability.duration", this::getDurationTicks, this::setDurationTicks).range(1, 2000), FieldDef.enumField("ability.shape", HazardShape.class, this::getShapeEnum, this::setShapeEnum) .hover("ability.hover.shape"), @@ -656,6 +656,6 @@ public class AbilityHazard extends Ability implements IAbilityHazard { FieldDef.boolField("ability.affectsCaster", this::isAffectsCaster, this::setAffectsCaster) .hover("ability.hover.affectsCaster"), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeal.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeal.java index ceb20a86c..107db40c6 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeal.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeal.java @@ -281,8 +281,8 @@ public class AbilityHeal extends Ability implements IAbilityHeal { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( FieldDef.boolField("ability.instantHeal", this::isInstantHeal, this::setInstantHeal) .hover("ability.hover.instant"), FieldDef.intField("ability.duration", this::getDurationTicks, this::setDurationTicks) @@ -299,6 +299,6 @@ public class AbilityHeal extends Ability implements IAbilityHeal { FieldDef.boolField("ability.healAllies", this::isHealAllies, this::setHealAllies) .hover("ability.hover.healAllies") ) - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java index ce432e01a..0e236de32 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityHeavyHit.java @@ -174,8 +174,8 @@ public class AbilityHeavyHit extends Ability implements IAbilityHeavyHit { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( FieldDef.row( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback) @@ -186,6 +186,6 @@ public class AbilityHeavyHit extends Ability implements IAbilityHeavyHit { FieldDef.floatField("ability.hitWidth", this::getHitWidth, this::setHitWidth) ), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java index b5d196cb5..bef721080 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java @@ -247,8 +247,8 @@ public class AbilityLaserShot extends Ability implements IAbilityLaserShot { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( // Type tab FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), FieldDef.row( @@ -290,6 +290,6 @@ public class AbilityLaserShot extends Ability implements IAbilityLaserShot { FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) ).tab("ability.tab.visual") - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java index dcad556b6..f1553025b 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java @@ -412,8 +412,8 @@ public class AbilityOrb extends Ability implements IAbilityOrb { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( // Type tab FieldDef.row( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), @@ -459,6 +459,6 @@ public class AbilityOrb extends Ability implements IAbilityOrb { FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) ).tab("ability.tab.visual") - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java index f0425fa9a..c7f7ecfa5 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java @@ -518,8 +518,8 @@ public class AbilityOrbBarrage extends Ability { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( // Type tab FieldDef.row( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), @@ -571,6 +571,6 @@ public class AbilityOrbBarrage extends Ability { FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) ).tab("ability.tab.visual") - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java index 1efa694ba..487f7ee05 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java @@ -457,8 +457,8 @@ public class AbilityOrbDual extends Ability { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( // Type tab FieldDef.row( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), @@ -555,7 +555,7 @@ public class AbilityOrbDual extends Ability { () -> getLightningRadius(1), v -> setLightningRadius(1, v)) .range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(1)) ).tab("ability.tab.visual") - ); + )); } @Override diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityProjectile.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityProjectile.java index d8dd4aebc..e5f6f5df6 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityProjectile.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityProjectile.java @@ -251,8 +251,8 @@ public class AbilityProjectile extends Ability implements IAbilityProjectile { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( FieldDef.row( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), FieldDef.floatField("stats.speed", this::getSpeed, this::setSpeed) @@ -266,6 +266,6 @@ public class AbilityProjectile extends Ability implements IAbilityProjectile { FieldDef.boolField("gui.enabled", this::isExplosive, this::setExplosive).hover("ability.hover.explosive"), FieldDef.floatField("gui.radius", this::getExplosionRadius, this::setExplosionRadius).visibleWhen(this::isExplosive), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java index b2c72ed24..2e1f9bfb4 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java @@ -166,8 +166,8 @@ public class AbilityShockwave extends Ability implements IAbilityShockwave { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), FieldDef.section("ability.section.push"), FieldDef.row( @@ -176,6 +176,6 @@ public class AbilityShockwave extends Ability implements IAbilityShockwave { ), FieldDef.intField("ability.maxTargets", this::getMaxTargets, this::setMaxTargets), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java index 39f1a3ca8..30b57bf6d 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySlam.java @@ -597,8 +597,8 @@ public class AbilitySlam extends Ability implements IAbilitySlam { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), FieldDef.row( FieldDef.floatField("gui.radius", this::getRadius, this::setRadius), @@ -610,6 +610,6 @@ public class AbilitySlam extends Ability implements IAbilitySlam { FieldDef.floatField("gui.height", this::getLeapHeight, this::setLeapHeight) ), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySweeper.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySweeper.java index e57c47e20..1ef4f7df4 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySweeper.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilitySweeper.java @@ -199,8 +199,8 @@ public class AbilitySweeper extends Ability implements IAbilitySweeper { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( FieldDef.row( FieldDef.floatField("enchantment.damage", this::getDamage, this::setDamage), @@ -234,6 +234,6 @@ public class AbilitySweeper extends Ability implements IAbilitySweeper { .tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled), FieldDef.floatField("ability.outerWidth", this::getOuterColorWidth, this::setOuterColorWidth) .tab("ability.tab.visual").visibleWhen(this::isOuterColorEnabled) - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTeleport.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTeleport.java index 528ddc025..887ef25fc 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTeleport.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTeleport.java @@ -558,8 +558,8 @@ public class AbilityTeleport extends Ability implements IAbilityTeleport { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( FieldDef.enumField("ability.mode", TeleportMode.class, this::getModeEnum, this::setModeEnum), FieldDef.floatField("ability.blinkRadius", this::getBlinkRadius, this::setBlinkRadius) .visibleWhen(() -> this.getModeEnum() == TeleportMode.BLINK || this.getModeEnum() == TeleportMode.SINGLE), @@ -586,6 +586,6 @@ public class AbilityTeleport extends Ability implements IAbilityTeleport { .hover("ability.hover.dmgAtEnd") ), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTrap.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTrap.java index c4f371056..102c4395f 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTrap.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityTrap.java @@ -468,8 +468,8 @@ public class AbilityTrap extends Ability implements IAbilityTrap { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( FieldDef.intField("ability.duration", this::getDurationTicks, this::setDurationTicks) .range(1, 2000), FieldDef.enumField("ability.placement", TrapPlacement.class, this::getPlacementEnum, this::setPlacementEnum) @@ -490,6 +490,6 @@ public class AbilityTrap extends Ability implements IAbilityTrap { ), FieldDef.floatField("ability.knockback", this::getKnockback, this::setKnockback), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) - ); + )); } } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java index aaa6041f4..e31a1e6ce 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityVortex.java @@ -304,8 +304,8 @@ public class AbilityVortex extends Ability implements IAbilityVortex { @SideOnly(Side.CLIENT) @Override - public List getFieldDefinitions() { - return Arrays.asList( + public void getAbilityDefinitions(List defs) { + defs.addAll(Arrays.asList( FieldDef.row( FieldDef.floatField("ability.pullRadius", this::getPullRadius, this::setPullRadius), FieldDef.floatField("ability.pullStrength", this::getPullStrength, this::setPullStrength) @@ -326,6 +326,6 @@ public class AbilityVortex extends Ability implements IAbilityVortex { FieldDef.floatField("enchantment.damage", this::getPullDamage, this::setPullDamage) .visibleWhen(this::isDamageOnPull), AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) - ); + )); } } diff --git a/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java b/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java index 1e97227a9..d2e7d5dc4 100644 --- a/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java +++ b/src/main/java/noppes/npcs/client/gui/advanced/SubGuiAbilityConfig.java @@ -62,7 +62,7 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi this.callback = callback; this.conditions = new ArrayList<>(ability.getConditions()); - this.fieldDefs = ability.getAllFieldDefinitions(); + this.fieldDefs = ability.getAllDefinitions(); discoverCustomTabs(); setBackground("menubg.png", 217); @@ -376,7 +376,7 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi ability.readNBT(nbt); this.conditions = new ArrayList<>(ability.getConditions()); - this.fieldDefs = ability.getAllFieldDefinitions(); + this.fieldDefs = ability.getAllDefinitions(); discoverCustomTabs(); initGui(); } From c5822023a0ff08cd55f7a08722f15ea26402a7c9 Mon Sep 17 00:00:00 2001 From: Vidal Date: Tue, 3 Feb 2026 07:45:02 -0300 Subject: [PATCH 10/14] Added modifyVisibility to FieldDef AbilityGuard tweaks --- .../controllers/data/ability/Ability.java | 11 -------- .../data/ability/type/AbilityGuard.java | 26 ++++++++++++++----- .../npcs/client/gui/builder/FieldDef.java | 22 +++++++++++++++- .../assets/customnpcs/lang/en_US.lang | 1 + 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java index 86a5e3794..1939304a9 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java @@ -450,17 +450,6 @@ public abstract class Ability implements IAbility { this::getActiveAnimationName, this::setActiveAnimationName) .tab("Effects")); - if (this instanceof AbilityGuard) { - defs.add(FieldDef.animSubGui("ability.counterAnimation", - () -> ((AbilityGuard) this).getCounterAnimationId(), - (id) -> ((AbilityGuard) this).setCounterAnimationId(id), - () -> ((AbilityGuard) this).getCounterAnimationName(), - (name) -> ((AbilityGuard) this).setCounterAnimationName(name)) - .tab("Effects") - .visibleWhen(() -> ((AbilityGuard) this).canCounter()) - ); - } - TelegraphType tType = getTelegraphType(); if (tType != null && tType != TelegraphType.NONE) { defs.add(FieldDef.section("ability.section.telegraph").tab("Effects") diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java index dcf43d530..eab84d138 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityGuard.java @@ -58,7 +58,7 @@ public class AbilityGuard extends Ability implements IAbilityGuard { // No telegraph for guard - it's a defensive stance this.telegraphType = TelegraphType.NONE; this.showTelegraph = false; - this.windUpSound = "random.anvil_use"; + this.activeSound = "random.anvil_use"; this.allowedBy = UserType.BOTH; this.activeAnimationName = "Ability_Guard_Active"; @@ -128,11 +128,12 @@ public class AbilityGuard extends Ability implements IAbilityGuard { caster.setHealth(newHealth); - if (!canCounter || !counterEligible || counterTriggered) return; - if (!isDirectHit(source)) return; - - counterTriggered = true; - // Counter will be performed in onActiveTick - don't self-interrupt + if (!canCounter || !counterEligible || counterTriggered || !isDirectHit(source)) { + caster.setHealth(newHealth); + } else { + caster.setHealth(ValueUtil.clamp(caster.getHealth() + damage, 0, caster.getMaxHealth())); + counterTriggered = true; + } } private boolean isDirectHit(DamageSource source) { @@ -360,5 +361,18 @@ public class AbilityGuard extends Ability implements IAbilityGuard { AbilityFieldDefs.effectsListField("ability.effects", this::getEffects, this::setEffects) )); + + FieldDef.insertAfter(defs, "ability.activeSound", + FieldDef.soundSubGui("ability.counterSound", this::getCounterSound, this::setCounterSound) + .tab("Effects").visibleWhen(this::canCounter)); + + FieldDef.insertAfter(defs, "ability.activeAnimation", + FieldDef.animSubGui("ability.counterAnimation", + this::getCounterAnimationId, this::setCounterAnimationId, + this::getCounterAnimationName, this::setCounterAnimationName) + .tab("Effects").visibleWhen(this::canCounter)); + + FieldDef.modifyVisibility(defs, "ability.windUpAnimation", () -> false); + FieldDef.modifyVisibility(defs, "ability.windUpSound", () -> false); } } diff --git a/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java b/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java index 6d9ee58ec..e013f4cb2 100644 --- a/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java +++ b/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java @@ -9,6 +9,7 @@ import noppes.npcs.client.gui.select.GuiAnimationSelection; import noppes.npcs.client.gui.select.GuiSoundSelection; import noppes.npcs.client.gui.util.SubGuiInterface; +import java.util.List; import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.function.Supplier; @@ -329,7 +330,7 @@ public class FieldDef { * @param newField The field to insert * @return true if the target was found and the field was inserted */ - public static boolean insertAfter(java.util.List fields, String targetLabel, FieldDef newField) { + public static boolean insertAfter(List fields, String targetLabel, FieldDef newField) { for (int i = 0; i < fields.size(); i++) { if (matchesLabel(fields.get(i), targetLabel)) { fields.add(i + 1, newField); @@ -339,6 +340,25 @@ public class FieldDef { return false; } + /** + * Modify the visibility condition of a field. + * Searches top-level labels and ROW children. + * + * @param fields The field list to modify + * @param targetLabel The label of the field to modify + * @param condition The condition to replace + * @return true if the target was found and the condition was modified + */ + public static boolean modifyVisibility(List fields, String targetLabel, BooleanSupplier condition) { + for (FieldDef field : fields) { + if (matchesLabel(field, targetLabel)) { + field.visibleWhen(condition); + return true; + } + } + return false; + } + private static boolean matchesLabel(FieldDef def, String targetLabel) { if (targetLabel.equals(def.label)) return true; if (def.type == FieldType.ROW) { diff --git a/src/main/resources/assets/customnpcs/lang/en_US.lang b/src/main/resources/assets/customnpcs/lang/en_US.lang index afa79dad0..ea433dc7e 100644 --- a/src/main/resources/assets/customnpcs/lang/en_US.lang +++ b/src/main/resources/assets/customnpcs/lang/en_US.lang @@ -1644,6 +1644,7 @@ ability.conditions=Conditions # Effects Tab ability.windUpSound=Wind Up Sound ability.activeSound=Active Sound +ability.counterSound=Counter Sound ability.windUpAnimation=Wind Up Animation ability.activeAnimation=Active Animation ability.counterAnimation=Counter Animation From 4889c8b8811ce312ed14f3343ab396d078b33110 Mon Sep 17 00:00:00 2001 From: Vidal Date: Tue, 3 Feb 2026 11:57:19 -0300 Subject: [PATCH 11/14] Added animation to shockwave --- .../data/ability/type/AbilityShockwave.java | 10 +- .../animations/Ability_Shockwave_Active.json | 77 +++++++ .../animations/Ability_Shockwave_Windup.json | 203 ++++++++++++++++++ 3 files changed, 285 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/assets/customnpcs/animations/Ability_Shockwave_Active.json create mode 100644 src/main/resources/assets/customnpcs/animations/Ability_Shockwave_Windup.json diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java index 2e1f9bfb4..775c15515 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityShockwave.java @@ -40,8 +40,10 @@ public class AbilityShockwave extends Ability implements IAbilityShockwave { this.cooldownTicks = 0; this.windUpTicks = 25; this.telegraphType = TelegraphType.CIRCLE; - this.windUpSound = "random.explode"; + this.windUpSound = "game.tnt.primed"; this.activeSound = "random.explode"; + this.windUpAnimationName = "Ability_Shockwave_Windup"; + this.activeAnimationName = "Ability_Shockwave_Active"; } @Override @@ -105,14 +107,12 @@ public class AbilityShockwave extends Ability implements IAbilityShockwave { applyEffects(entity); } } - - // Shockwave completes instantly - signalCompletion(); } @Override public void onActiveTick(EntityLivingBase caster, EntityLivingBase target, World world, int tick) { - // Shockwave is instant - nothing to do per-tick + if (tick == 10) + signalCompletion(); } @Override diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Shockwave_Active.json b/src/main/resources/assets/customnpcs/animations/Ability_Shockwave_Active.json new file mode 100644 index 000000000..8ea8fc18b --- /dev/null +++ b/src/main/resources/assets/customnpcs/animations/Ability_Shockwave_Active.json @@ -0,0 +1,77 @@ +{ + "Loop": 0, + "Speed": 1.0f, + "Frames": [ + { + "ColorMarker": 16777215, + "Comment": "", + "Speed": 1.0f, + "FrameParts": [ + { + "Pivot2": -7.0f, + "Part": "LEFT_ARM", + "Rotation1": -12.0f, + "Rotation0": 12.0f, + "Pivot0": -1.0f, + "Pivot1": 7.0f, + "Rotation2": -63.0f + }, + { + "Pivot2": -9.0f, + "Part": "HEAD", + "Rotation1": 0.0f, + "Rotation0": 69.0f, + "Pivot0": 0.0f, + "Pivot1": 7.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -7.0f, + "Part": "RIGHT_ARM", + "Rotation1": 12.0f, + "Rotation0": 12.0f, + "Pivot0": 1.0f, + "Pivot1": 7.0f, + "Rotation2": 63.0f + }, + { + "Pivot2": -4.0f, + "Part": "RIGHT_LEG", + "Rotation1": 0.0f, + "Rotation0": 56.0f, + "Pivot0": 0.0f, + "Pivot1": 4.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -6.0f, + "Part": "LEFT_LEG", + "Rotation1": 0.0f, + "Rotation0": 0.0f, + "Pivot0": 0.0f, + "Pivot1": 0.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -9.0f, + "Part": "BODY", + "Rotation1": 0.0f, + "Rotation0": 50.0f, + "Pivot0": 0.0f, + "Pivot1": 7.0f, + "Rotation2": 0.0f + } + ], + "Smooth": 0b, + "Duration": 2 + } + ], + "CurrentFrameTime": 0, + "CurrentFrame": 0, + "Smooth": 0b, + "ID": 20, + "WhileAttacking": 1b, + "WhileWalking": 1b, + "Name": "Ability_Shockwave_Active", + "WhileStanding": 1b +} diff --git a/src/main/resources/assets/customnpcs/animations/Ability_Shockwave_Windup.json b/src/main/resources/assets/customnpcs/animations/Ability_Shockwave_Windup.json new file mode 100644 index 000000000..2d45359b3 --- /dev/null +++ b/src/main/resources/assets/customnpcs/animations/Ability_Shockwave_Windup.json @@ -0,0 +1,203 @@ +{ + "Loop": -1, + "Speed": 1.0f, + "Frames": [ + { + "ColorMarker": 16777215, + "Comment": "", + "Speed": 2.0f, + "FrameParts": [ + { + "Pivot2": 4.0f, + "Part": "LEFT_ARM", + "Rotation1": -12.0f, + "Rotation0": -183.0f, + "Pivot0": -1.0f, + "Pivot1": -2.0f, + "Rotation2": -12.0f + }, + { + "Pivot2": 3.0f, + "Part": "HEAD", + "Rotation1": 0.0f, + "Rotation0": -18.0f, + "Pivot0": 0.0f, + "Pivot1": 1.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": 4.0f, + "Part": "RIGHT_ARM", + "Rotation1": 12.0f, + "Rotation0": -183.0f, + "Pivot0": 1.0f, + "Pivot1": -2.0f, + "Rotation2": 12.0f + }, + { + "Pivot2": -1.0f, + "Part": "RIGHT_LEG", + "Rotation1": 0.0f, + "Rotation0": 12.0f, + "Pivot0": 0.0f, + "Pivot1": 0.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -2.0f, + "Part": "LEFT_LEG", + "Rotation1": 0.0f, + "Rotation0": -25.0f, + "Pivot0": 0.0f, + "Pivot1": -5.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": 3.0f, + "Part": "BODY", + "Rotation1": 0.0f, + "Rotation0": -18.0f, + "Pivot0": 0.0f, + "Pivot1": 1.0f, + "Rotation2": 0.0f + } + ], + "Smooth": 0b, + "Duration": 5 + }, + { + "ColorMarker": 16777215, + "Comment": "", + "Speed": 0.5f, + "FrameParts": [ + { + "Pivot2": 4.0f, + "Part": "LEFT_ARM", + "Rotation1": -12.0f, + "Rotation0": -183.0f, + "Pivot0": -1.0f, + "Pivot1": -2.0f, + "Rotation2": -12.0f + }, + { + "Pivot2": 3.0f, + "Part": "HEAD", + "Rotation1": 0.0f, + "Rotation0": -18.0f, + "Pivot0": 0.0f, + "Pivot1": 1.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": 4.0f, + "Part": "RIGHT_ARM", + "Rotation1": 12.0f, + "Rotation0": -183.0f, + "Pivot0": 1.0f, + "Pivot1": -2.0f, + "Rotation2": 12.0f + }, + { + "Pivot2": -1.0f, + "Part": "RIGHT_LEG", + "Rotation1": 0.0f, + "Rotation0": 12.0f, + "Pivot0": 0.0f, + "Pivot1": 0.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -2.0f, + "Part": "LEFT_LEG", + "Rotation1": 0.0f, + "Rotation0": -25.0f, + "Pivot0": 0.0f, + "Pivot1": -5.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": 3.0f, + "Part": "BODY", + "Rotation1": 0.0f, + "Rotation0": -18.0f, + "Pivot0": 0.0f, + "Pivot1": 1.0f, + "Rotation2": 0.0f + } + ], + "Smooth": 0b, + "Duration": 18 + }, + { + "ColorMarker": 16777215, + "Comment": "", + "Speed": 3.0f, + "FrameParts": [ + { + "Pivot2": -7.0f, + "Part": "LEFT_ARM", + "Rotation1": -12.0f, + "Rotation0": 12.0f, + "Pivot0": -1.0f, + "Pivot1": 7.0f, + "Rotation2": -63.0f + }, + { + "Pivot2": -9.0f, + "Part": "HEAD", + "Rotation1": 0.0f, + "Rotation0": 69.0f, + "Pivot0": 0.0f, + "Pivot1": 7.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -7.0f, + "Part": "RIGHT_ARM", + "Rotation1": 12.0f, + "Rotation0": 12.0f, + "Pivot0": 1.0f, + "Pivot1": 7.0f, + "Rotation2": 63.0f + }, + { + "Pivot2": -4.0f, + "Part": "RIGHT_LEG", + "Rotation1": 0.0f, + "Rotation0": 56.0f, + "Pivot0": 0.0f, + "Pivot1": 4.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -6.0f, + "Part": "LEFT_LEG", + "Rotation1": 0.0f, + "Rotation0": 0.0f, + "Pivot0": 0.0f, + "Pivot1": 0.0f, + "Rotation2": 0.0f + }, + { + "Pivot2": -9.0f, + "Part": "BODY", + "Rotation1": 0.0f, + "Rotation0": 50.0f, + "Pivot0": 0.0f, + "Pivot1": 7.0f, + "Rotation2": 0.0f + } + ], + "Smooth": 0b, + "Duration": 2 + } + ], + "CurrentFrameTime": 0, + "CurrentFrame": 1, + "Smooth": 0b, + "ID": 19, + "WhileAttacking": 1b, + "WhileWalking": 1b, + "Name": "Ability_Shockwave_Windup", + "WhileStanding": 1b +} From eb2d904bac667454f04bbf49ff08af9a95da95b5 Mon Sep 17 00:00:00 2001 From: Vidal Date: Tue, 3 Feb 2026 11:57:47 -0300 Subject: [PATCH 12/14] Color-only overload to EnergyColorData --- .../npcs/controllers/data/ability/data/EnergyColorData.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/data/EnergyColorData.java b/src/main/java/kamkeel/npcs/controllers/data/ability/data/EnergyColorData.java index 4bd841742..9ed99e22e 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/data/EnergyColorData.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/data/EnergyColorData.java @@ -16,6 +16,11 @@ public class EnergyColorData { public EnergyColorData() {} + public EnergyColorData(int innerColor, int outerColor) { + this.innerColor = innerColor; + this.outerColor = outerColor; + } + public EnergyColorData(int innerColor, int outerColor, boolean outerColorEnabled, float outerColorWidth, float outerColorAlpha, float rotationSpeed) { this.innerColor = innerColor; From 1a8b8fb5f3179e20ffd5d0163d95255603ca2622 Mon Sep 17 00:00:00 2001 From: Vidal Date: Tue, 3 Feb 2026 11:58:39 -0300 Subject: [PATCH 13/14] Made staves shoot EntityAbilityOrb --- .../noppes/npcs/items/ItemElementalStaff.java | 1 + .../java/noppes/npcs/items/ItemStaff.java | 138 +++++++++++++----- 2 files changed, 104 insertions(+), 35 deletions(-) diff --git a/src/main/java/noppes/npcs/items/ItemElementalStaff.java b/src/main/java/noppes/npcs/items/ItemElementalStaff.java index d786222b1..03384f76a 100644 --- a/src/main/java/noppes/npcs/items/ItemElementalStaff.java +++ b/src/main/java/noppes/npcs/items/ItemElementalStaff.java @@ -16,6 +16,7 @@ public class ItemElementalStaff extends ItemStaff { public ItemElementalStaff(int par1, EnumNpcToolMaterial material) { super(par1, material); setHasSubtypes(true); + this.color = OrbColor.GENERIC; } @Override diff --git a/src/main/java/noppes/npcs/items/ItemStaff.java b/src/main/java/noppes/npcs/items/ItemStaff.java index 89ce879cf..9957b195b 100644 --- a/src/main/java/noppes/npcs/items/ItemStaff.java +++ b/src/main/java/noppes/npcs/items/ItemStaff.java @@ -1,7 +1,11 @@ package noppes.npcs.items; +import kamkeel.npcs.controllers.data.ability.AnchorPoint; +import kamkeel.npcs.controllers.data.ability.data.*; +import kamkeel.npcs.entity.EntityAbilityOrb; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.passive.EntitySheep; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.EnumAction; import net.minecraft.item.ItemStack; @@ -20,13 +24,18 @@ import noppes.npcs.entity.EntityProjectile; import noppes.npcs.util.IProjectileCallback; import org.lwjgl.opengl.GL11; +import java.awt.*; + public class ItemStaff extends ItemNpcInterface implements IProjectileCallback { private EnumNpcToolMaterial material; + protected OrbColor color; + public ItemStaff(int par1, EnumNpcToolMaterial material) { super(par1); this.material = material; + this.color = OrbColor.get(material.ordinal());; setCreativeTab(CustomItems.tabWeapon); } @@ -36,70 +45,92 @@ public class ItemStaff extends ItemNpcInterface implements IProjectileCallback { } @Override - public void onPlayerStoppedUsing(ItemStack stack, World worldObj, EntityPlayer player, int par4) { - if (worldObj.isRemote) { + public void onPlayerStoppedUsing(ItemStack stack, World world, EntityPlayer player, int par4) { + + if (world.isRemote) return; - } + if (stack.stackTagCompound == null) return; - Entity entity = ((WorldServer) player.worldObj).getEntityByID(stack.stackTagCompound.getInteger("MagicProjectile")); - if (entity == null || !(entity instanceof EntityProjectile)) + + Entity entity = ((WorldServer) world) + .getEntityByID(stack.stackTagCompound.getInteger("MagicProjectile")); + + if (!(entity instanceof EntityAbilityOrb)) return; - EntityProjectile item = (EntityProjectile) entity; - item.callback = this; - item.callbackItem = stack; - item.explosive = true; - item.explosiveDamage = false; - item.explosiveRadius = 1; - item.prevRotationYaw = item.rotationYaw = player.rotationYaw; - item.prevRotationPitch = item.rotationPitch = player.rotationPitch; - item.shoot(2); - player.worldObj.playSoundAtEntity(player, "customnpcs:magic.shot", 1.0F, 1); + EntityAbilityOrb orb = (EntityAbilityOrb) entity; + orb.startMoving(null); + + world.playSoundAtEntity( + player, + "customnpcs:magic.shot", + 1.0F, + 1.0F + ); } @Override public void onUsingTick(ItemStack stack, EntityPlayer player, int count) { int tick = getMaxItemUseDuration(stack) - count; + if (player.worldObj.isRemote) { spawnParticle(stack, player); return; } + int chargeTime = 20 + material.getHarvestLevel() * 8; + if (tick == chargeTime) { + if (!player.capabilities.isCreativeMode && !hasInfinite(stack)) { if (!hasItem(player, CustomItems.mana)) return; consumeItem(player, CustomItems.mana); } - player.worldObj.playSoundAtEntity(player, "customnpcs:magic.charge", 1.0F, 1); + + player.worldObj.playSoundAtEntity( + player, + "customnpcs:magic.charge", + 1.0F, + 1.0F + ); + if (stack.stackTagCompound == null) { stack.stackTagCompound = new NBTTagCompound(); } + int damage = 6 + material.getDamageVsEntity() + player.worldObj.rand.nextInt(4); damage += damage * EnchantInterface.getLevel(EnchantInterface.Damage, stack) * 0.5f; - EntityProjectile projectile = new EntityMagicProjectile(player.worldObj, player, getProjectile(stack), false); - projectile.damage = damage; - projectile.setSpeed(25); - double dx = -MathHelper.sin((float) ((player.rotationYaw / 180F) * Math.PI)) * MathHelper.cos((float) ((player.rotationPitch / 180F) * Math.PI)); - double dz = MathHelper.cos((float) ((player.rotationYaw / 180F) * Math.PI)) * MathHelper.cos((float) ((player.rotationPitch / 180F) * Math.PI)); - projectile.setPosition(player.posX + dx * 0.8, player.posY + 1.5 - player.rotationPitch / 80, player.posZ + dz * 0.8); - player.worldObj.spawnEntityInWorld(projectile); - stack.stackTagCompound.setInteger("MagicProjectile", projectile.getEntityId());//entityid - } - if (tick > chargeTime && stack.stackTagCompound != null) { - Entity entity = ((WorldServer) player.worldObj).getEntityByID(stack.stackTagCompound.getInteger("MagicProjectile")); - if (entity == null || !(entity instanceof EntityProjectile)) - return; - EntityProjectile item = (EntityProjectile) entity; - item.ticksInAir = 0; - double dx = -MathHelper.sin((float) ((player.rotationYaw / 180F) * Math.PI)) * MathHelper.cos((float) ((player.rotationPitch / 180F) * Math.PI)); - double dz = MathHelper.cos((float) ((player.rotationYaw / 180F) * Math.PI)) * MathHelper.cos((float) ((player.rotationPitch / 180F) * Math.PI)); - item.setPosition(player.posX + dx * 0.8, player.posY + 1.5 - player.rotationPitch / 80, player.posZ + dz * 0.8); - } + EnergyCombatData combat = new EnergyCombatData(); + combat.damage = damage; + combat.explosive = true; + EnergyColorData colorData = new EnergyColorData(getOrbColor(stack, false), getOrbColor(stack, true)); + EnergyLightningData lightning = new EnergyLightningData(); + EnergyLifespanData lifespan = new EnergyLifespanData(100, 72000); + EnergyHomingData homing = new EnergyHomingData(); + + homing.speed = 0.5f; + homing.homingStrength = 0.35f; + homing.homingRange = 20f; + + EntityAbilityOrb orb = new EntityAbilityOrb( + player.worldObj, player, null, + player.posX, player.posY + player.getEyeHeight(), player.posZ, + 1.0f, colorData, combat, homing, lightning, lifespan + ); + + orb.setupCharging( + new EnergyAnchorData(AnchorPoint.FRONT, 0, -1, 0), + chargeTime + ); + + player.worldObj.spawnEntityInWorld(orb); + stack.stackTagCompound.setInteger("MagicProjectile", orb.getEntityId()); + } } @Override @@ -118,6 +149,15 @@ public class ItemStaff extends ItemNpcInterface implements IProjectileCallback { return EnumAction.bow; } + public int getOrbColor(ItemStack stack, boolean outer) { + if (color == OrbColor.GENERIC) { + float[] color = EntitySheep.fleeceColorTable[stack.getItemDamage()]; + return new Color(color[0], color[1], color[2]).getRGB(); + } + + return outer ? color.outer : color.inner; + } + public ItemStack getProjectile(ItemStack stack) { if (stack.getItem() == CustomItems.staffWood) { return new ItemStack(CustomItems.spellNature); @@ -196,4 +236,32 @@ public class ItemStaff extends ItemNpcInterface implements IProjectileCallback { public boolean hasInfinite(ItemStack stack) { return EnchantInterface.getLevel(EnchantInterface.Infinite, stack) > 0; } + + public enum OrbColor { + WOOD(0x7cc818, 0x644a32), + STONE(0x532d5b, 0x515151), + BRONZE(0x83F7F6, 0x5CF0FF), + IRON(0xf7fac5, 0xeafa94), + DIA(0x44B6FF, 0x94DFED), + GOLD(0xb3011e, 0xd47c32), + EMERALD(0xdd6df7, 0xcf1dfa), + DEMONIC(0xb8144a, 0x422643), + FROST(0xffffff, 0xaccbfe), + MITHRIL(0xf7fac5, 0xffffff), + GENERIC(0xFFFFFF, 0x88FFFF); + + public final int inner; + public final int outer; + + OrbColor(int inner, int outer) { + this.inner = inner; + this.outer = outer; + } + + public static OrbColor get(int id) { + if (id >= OrbColor.values().length || id < 0) return GENERIC; + + return OrbColor.values()[id]; + } + } } From 2d47aa00d81f1e25666697d00fbfb8b286e0ab16 Mon Sep 17 00:00:00 2001 From: Vidal Date: Tue, 3 Feb 2026 12:32:30 -0300 Subject: [PATCH 14/14] - Added standalone min max methods to FieldDef - Increased lightning density and radius minmax on all energy abilities - Made AbilityOrbBarrage interruptible during active state - Renamed AbilityEnergyBeam to AbilityBeam - Updated imports --- .../controllers/data/ability/Ability.java | 2 - .../data/ability/AbilityController.java | 2 +- ...bilityEnergyBeam.java => AbilityBeam.java} | 8 +-- .../data/ability/type/AbilityBeamDual.java | 8 +-- .../data/ability/type/AbilityDisc.java | 4 +- .../data/ability/type/AbilityDiscDual.java | 4 +- .../data/ability/type/AbilityLaserShot.java | 4 +- .../data/ability/type/AbilityOrb.java | 4 +- .../data/ability/type/AbilityOrbBarrage.java | 49 ++++++++++++++----- .../data/ability/type/AbilityOrbDual.java | 4 +- .../npcs/client/gui/builder/FieldDef.java | 10 ++++ 11 files changed, 67 insertions(+), 32 deletions(-) rename src/main/java/kamkeel/npcs/controllers/data/ability/type/{AbilityEnergyBeam.java => AbilityBeam.java} (98%) diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java index 1939304a9..015f6361b 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/Ability.java @@ -2,7 +2,6 @@ package kamkeel.npcs.controllers.data.ability; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; -import kamkeel.npcs.controllers.data.ability.type.AbilityGuard; import kamkeel.npcs.controllers.data.telegraph.Telegraph; import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance; import kamkeel.npcs.controllers.data.telegraph.TelegraphType; @@ -36,7 +35,6 @@ import java.util.ArrayList; import java.util.List; import net.minecraft.entity.Entity; -import somehussar.gui.annotationHandling.GuiEditable; public abstract class Ability implements IAbility { diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/AbilityController.java b/src/main/java/kamkeel/npcs/controllers/data/ability/AbilityController.java index 50e41d45c..f12ebd421 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/AbilityController.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/AbilityController.java @@ -368,7 +368,7 @@ public class AbilityController implements IAbilityHandler { registerType("cnpc:dual_disc", AbilityDisc::new); registerType("cnpc:dual_disc", AbilityDiscDual::new); registerType("cnpc:laser_shot", AbilityLaserShot::new); - registerType("cnpc:beam", AbilityEnergyBeam::new); + registerType("cnpc:beam", AbilityBeam::new); registerType("cnpc:dual_beam", AbilityBeamDual::new); // Movement abilities diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeam.java similarity index 98% rename from src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java rename to src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeam.java index 5c960960a..25a4edf76 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityEnergyBeam.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeam.java @@ -30,7 +30,7 @@ import noppes.npcs.entity.EntityNPCInterface; * The beam stays attached to the origin and curves as it homes in on target. * Cannot cross over itself (self-intersection prevention). */ -public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { +public class AbilityBeam extends Ability implements IAbilityEnergyBeam { // Shape properties (standalone) private float beamWidth = 0.4f; @@ -47,7 +47,7 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { // Transient state for beam entity (used during windup charging) private transient EntityAbilityBeam beamEntity = null; - public AbilityEnergyBeam() { + public AbilityBeam() { this.typeId = "ability.cnpc.beam"; this.name = "Beam"; this.targetingMode = TargetingMode.AGGRO_TARGET; @@ -331,9 +331,9 @@ public class AbilityEnergyBeam extends Ability implements IAbilityEnergyBeam { .tab("ability.tab.visual"), FieldDef.row( FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity) - .range(0.01f, 5.0f).visibleWhen(this::hasLightningEffect), + .range(0.01f, 100f).visibleWhen(this::hasLightningEffect), FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) - .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) + .range(0.1f, 100f).visibleWhen(this::hasLightningEffect) ).tab("ability.tab.visual") )); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java index 61ba417fa..5cdf297fb 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityBeamDual.java @@ -444,10 +444,10 @@ public class AbilityBeamDual extends Ability { FieldDef.row( FieldDef.floatField("gui.density", () -> getLightningDensity(0), v -> setLightningDensity(0, v)) - .range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(0)), + .range(0.01f, 100f).visibleWhen(() -> hasLightningEffect(0)), FieldDef.floatField("gui.radius", () -> getLightningRadius(0), v -> setLightningRadius(0, v)) - .range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(0)) + .range(0.1f, 100f).visibleWhen(() -> hasLightningEffect(0)) ).tab("ability.tab.visual"), // Visual tab - Beam 2 FieldDef.enumField("ability.anchorPoint", AnchorPoint.class, @@ -480,10 +480,10 @@ public class AbilityBeamDual extends Ability { FieldDef.row( FieldDef.floatField("gui.density", () -> getLightningDensity(1), v -> setLightningDensity(1, v)) - .range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(1)), + .range(0.01f, 100f).visibleWhen(() -> hasLightningEffect(1)), FieldDef.floatField("gui.radius", () -> getLightningRadius(1), v -> setLightningRadius(1, v)) - .range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(1)) + .range(0.1f, 100f).visibleWhen(() -> hasLightningEffect(1)) ).tab("ability.tab.visual") )); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java index 4f48c1c90..7ee8a9260 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDisc.java @@ -329,9 +329,9 @@ public class AbilityDisc extends Ability implements IAbilityDisc { .tab("ability.tab.visual"), FieldDef.row( FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity) - .range(0.01f, 5.0f).visibleWhen(this::hasLightningEffect), + .range(0.01f, 100f).visibleWhen(this::hasLightningEffect), FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) - .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) + .range(0.1f, 100f).visibleWhen(this::hasLightningEffect) ).tab("ability.tab.visual") )); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java index 2717da23a..e2e07da15 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityDiscDual.java @@ -490,10 +490,10 @@ public class AbilityDiscDual extends Ability { FieldDef.row( FieldDef.floatField("gui.density", () -> getLightningDensity(1), v -> setLightningDensity(1, v)) - .range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(1)), + .range(0.01f, 100f).visibleWhen(() -> hasLightningEffect(1)), FieldDef.floatField("gui.radius", () -> getLightningRadius(1), v -> setLightningRadius(1, v)) - .range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(1)) + .range(0.1f, 100f).visibleWhen(() -> hasLightningEffect(1)) ).tab("ability.tab.visual") )); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java index bef721080..031598207 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityLaserShot.java @@ -286,9 +286,9 @@ public class AbilityLaserShot extends Ability implements IAbilityLaserShot { FieldDef.boolField("ability.lightning", this::hasLightningEffect, this::setLightningEffect).tab("ability.tab.visual"), FieldDef.row( FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity) - .range(0.01f, 5.0f).visibleWhen(this::hasLightningEffect), + .range(0.01f, 100f).visibleWhen(this::hasLightningEffect), FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) - .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) + .range(0.1f, 100f).visibleWhen(this::hasLightningEffect) ).tab("ability.tab.visual") )); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java index f1553025b..b45bf87af 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrb.java @@ -455,9 +455,9 @@ public class AbilityOrb extends Ability implements IAbilityOrb { FieldDef.boolField("ability.lightning", this::hasLightningEffect, this::setLightningEffect).tab("ability.tab.visual"), FieldDef.row( FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity) - .range(0.01f, 5.0f).visibleWhen(this::hasLightningEffect), + .visibleWhen(this::hasLightningEffect).range(0.01f, 100f), FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) - .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) + .range(0.1f, 100f).visibleWhen(this::hasLightningEffect) ).tab("ability.tab.visual") )); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java index c7f7ecfa5..79641ae41 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbBarrage.java @@ -16,6 +16,7 @@ import kamkeel.npcs.util.AnchorPointHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.DamageSource; import net.minecraft.util.Vec3; import net.minecraft.world.World; import net.minecraftforge.common.util.Constants; @@ -182,19 +183,36 @@ public class AbilityOrbBarrage extends Ability { currentOrb++; } + @Override + public boolean canInterrupt(DamageSource source) { + // Can be interrupted if the caster is hit when the beam is moving + if (!interruptible) { + return false; + } + + // Only direct physical hits can interrupt, not magic, fire, or other indirect damage + if (source == null) { + return false; + } + + // Reject indirect damage types + if (source.isMagicDamage() || source.isFireDamage() || source.isExplosion()) { + return false; + } + + // Reject damage without a direct attacker entity + if (source.getEntity() == null) { + return false; + } + + // Direct hit from an entity - can interrupt + return true; + } + @Override public void cleanup() { currentOrb = 0; - if (orbEntities != null && !orbEntities.isEmpty()) { - for (EntityAbilityOrb orbEntity : orbEntities) { - if (orbEntity != null && !orbEntity.isDead) { - orbEntity.setDead(); - } - } - orbEntities.clear(); - } - if (chargingEntities != null) { for (int i = 0; i < chargingEntities.length; i++) { if (chargingEntities[i] != null && !chargingEntities[i].isDead) { @@ -204,6 +222,15 @@ public class AbilityOrbBarrage extends Ability { } chargingEntities = null; } + + if (orbEntities != null && !orbEntities.isEmpty()) { + for (EntityAbilityOrb orbEntity : orbEntities) { + if (orbEntity != null && !orbEntity.isDead) { + orbEntity.setDead(); + } + } + orbEntities.clear(); + } } @Override @@ -567,9 +594,9 @@ public class AbilityOrbBarrage extends Ability { FieldDef.boolField("ability.lightning", this::hasLightningEffect, this::setLightningEffect).tab("ability.tab.visual"), FieldDef.row( FieldDef.floatField("gui.density", this::getLightningDensity, this::setLightningDensity) - .range(0.01f, 5.0f).visibleWhen(this::hasLightningEffect), + .range(0.01f, 100f).visibleWhen(this::hasLightningEffect), FieldDef.floatField("gui.radius", this::getLightningRadius, this::setLightningRadius) - .range(0.1f, 10.0f).visibleWhen(this::hasLightningEffect) + .range(0.1f, 100f).visibleWhen(this::hasLightningEffect) ).tab("ability.tab.visual") )); } diff --git a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java index 487f7ee05..52b5355ea 100644 --- a/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java +++ b/src/main/java/kamkeel/npcs/controllers/data/ability/type/AbilityOrbDual.java @@ -550,10 +550,10 @@ public class AbilityOrbDual extends Ability { FieldDef.row( FieldDef.floatField("gui.density", () -> getLightningDensity(1), v -> setLightningDensity(1, v)) - .range(0.01f, 5.0f).visibleWhen(() -> hasLightningEffect(1)), + .range(0.01f, 100f).visibleWhen(() -> hasLightningEffect(1)), FieldDef.floatField("gui.radius", () -> getLightningRadius(1), v -> setLightningRadius(1, v)) - .range(0.1f, 10.0f).visibleWhen(() -> hasLightningEffect(1)) + .range(0.1f, 100f).visibleWhen(() -> hasLightningEffect(1)) ).tab("ability.tab.visual") )); } diff --git a/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java b/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java index e013f4cb2..9263cc880 100644 --- a/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java +++ b/src/main/java/noppes/npcs/client/gui/builder/FieldDef.java @@ -220,6 +220,16 @@ public class FieldDef { return this; } + public FieldDef min(float min) { + this.min = min; + return this; + } + + public FieldDef max(float max) { + this.max = max; + return this; + } + public FieldDef visibleWhen(BooleanSupplier condition) { this.visibleWhen = condition; return this;