From 185ac63a445e40cfef5567b2ef161b48ee98ba8f Mon Sep 17 00:00:00 2001 From: NotEvil Date: Tue, 14 Apr 2026 02:37:14 +0200 Subject: [PATCH] feat(D-01): implement 5 remaining components (blinding, shock, gps, choking, adjustable) --- .../component/AdjustableComponent.java | 67 +++++++++++++++++++ .../bondage/component/BlindingComponent.java | 36 ++++++++++ .../bondage/component/ChokingComponent.java | 46 +++++++++++++ .../v2/bondage/component/ComponentType.java | 7 +- .../v2/bondage/component/GpsComponent.java | 45 +++++++++++++ .../v2/bondage/component/ShockComponent.java | 52 ++++++++++++++ 6 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/tiedup/remake/v2/bondage/component/AdjustableComponent.java create mode 100644 src/main/java/com/tiedup/remake/v2/bondage/component/BlindingComponent.java create mode 100644 src/main/java/com/tiedup/remake/v2/bondage/component/ChokingComponent.java create mode 100644 src/main/java/com/tiedup/remake/v2/bondage/component/GpsComponent.java create mode 100644 src/main/java/com/tiedup/remake/v2/bondage/component/ShockComponent.java diff --git a/src/main/java/com/tiedup/remake/v2/bondage/component/AdjustableComponent.java b/src/main/java/com/tiedup/remake/v2/bondage/component/AdjustableComponent.java new file mode 100644 index 0000000..63238e7 --- /dev/null +++ b/src/main/java/com/tiedup/remake/v2/bondage/component/AdjustableComponent.java @@ -0,0 +1,67 @@ +package com.tiedup.remake.v2.bondage.component; + +import com.google.gson.JsonObject; + +/** + * Component: positional adjustment for data-driven items. + * Allows Y offset adjustment via GUI slider. + * + * JSON config: + * {@code "adjustable": {"default": 0.0, "min": -4.0, "max": 4.0, "step": 0.25}} + */ +public class AdjustableComponent implements IItemComponent { + + private final float defaultValue; + private final float min; + private final float max; + private final float step; + + private AdjustableComponent(float defaultValue, float min, float max, float step) { + this.defaultValue = defaultValue; + this.min = min; + this.max = max; + this.step = step; + } + + public static IItemComponent fromJson(JsonObject config) { + float defaultVal = 0.0f; + float min = -4.0f; + float max = 4.0f; + float step = 0.25f; + if (config != null) { + if (config.has("default")) defaultVal = config.get("default").getAsFloat(); + if (config.has("min")) min = config.get("min").getAsFloat(); + if (config.has("max")) max = config.get("max").getAsFloat(); + if (config.has("step")) step = config.get("step").getAsFloat(); + } + // Ensure min <= max + if (min > max) { + float tmp = min; + min = max; + max = tmp; + } + step = Math.max(0.01f, step); + defaultVal = Math.max(min, Math.min(max, defaultVal)); + return new AdjustableComponent(defaultVal, min, max, step); + } + + /** Default Y offset value. */ + public float getDefaultValue() { + return defaultValue; + } + + /** Minimum Y offset. */ + public float getMin() { + return min; + } + + /** Maximum Y offset. */ + public float getMax() { + return max; + } + + /** Step increment for the adjustment slider. */ + public float getStep() { + return step; + } +} diff --git a/src/main/java/com/tiedup/remake/v2/bondage/component/BlindingComponent.java b/src/main/java/com/tiedup/remake/v2/bondage/component/BlindingComponent.java new file mode 100644 index 0000000..d9142f6 --- /dev/null +++ b/src/main/java/com/tiedup/remake/v2/bondage/component/BlindingComponent.java @@ -0,0 +1,36 @@ +package com.tiedup.remake.v2.bondage.component; + +import com.google.gson.JsonObject; +import org.jetbrains.annotations.Nullable; + +/** + * Component: blinding effect for data-driven items. + * Replaces IHasBlindingEffect marker interface. + * + * JSON config: + * {@code "blinding": {}} or {@code "blinding": {"overlay": "tiedup:textures/overlay/custom.png"}} + */ +public class BlindingComponent implements IItemComponent { + + private final String overlay; // nullable — null means default overlay + + private BlindingComponent(String overlay) { + this.overlay = overlay; + } + + public static IItemComponent fromJson(JsonObject config) { + String overlay = null; + if (config != null && config.has("overlay")) { + overlay = config.get("overlay").getAsString(); + } + return new BlindingComponent(overlay); + } + + /** + * Custom overlay texture path, or null for the mod's default blindfold overlay. + */ + @Nullable + public String getOverlay() { + return overlay; + } +} diff --git a/src/main/java/com/tiedup/remake/v2/bondage/component/ChokingComponent.java b/src/main/java/com/tiedup/remake/v2/bondage/component/ChokingComponent.java new file mode 100644 index 0000000..5860159 --- /dev/null +++ b/src/main/java/com/tiedup/remake/v2/bondage/component/ChokingComponent.java @@ -0,0 +1,46 @@ +package com.tiedup.remake.v2.bondage.component; + +import com.google.gson.JsonObject; + +/** + * Component: choking effect for data-driven items. + * When active, drains air, applies darkness/slowness, deals damage. + * + * JSON config: + * {@code "choking": {"air_drain_per_tick": 8, "non_lethal_for_master": true}} + */ +public class ChokingComponent implements IItemComponent { + + private final int airDrainPerTick; + private final boolean nonLethalForMaster; + + private ChokingComponent(int airDrainPerTick, boolean nonLethalForMaster) { + this.airDrainPerTick = airDrainPerTick; + this.nonLethalForMaster = nonLethalForMaster; + } + + public static IItemComponent fromJson(JsonObject config) { + int drain = 8; + boolean nonLethal = true; + if (config != null) { + if (config.has("air_drain_per_tick")) { + drain = config.get("air_drain_per_tick").getAsInt(); + } + if (config.has("non_lethal_for_master")) { + nonLethal = config.get("non_lethal_for_master").getAsBoolean(); + } + } + drain = Math.max(1, drain); + return new ChokingComponent(drain, nonLethal); + } + + /** Air drained per tick (net after vanilla +4 restoration). */ + public int getAirDrainPerTick() { + return airDrainPerTick; + } + + /** Whether the choke is non-lethal when used by a master on their pet. */ + public boolean isNonLethalForMaster() { + return nonLethalForMaster; + } +} diff --git a/src/main/java/com/tiedup/remake/v2/bondage/component/ComponentType.java b/src/main/java/com/tiedup/remake/v2/bondage/component/ComponentType.java index ca16f26..3964db4 100644 --- a/src/main/java/com/tiedup/remake/v2/bondage/component/ComponentType.java +++ b/src/main/java/com/tiedup/remake/v2/bondage/component/ComponentType.java @@ -10,7 +10,12 @@ import org.jetbrains.annotations.Nullable; public enum ComponentType { LOCKABLE("lockable", LockableComponent::fromJson), RESISTANCE("resistance", ResistanceComponent::fromJson), - GAGGING("gagging", GaggingComponent::fromJson); + GAGGING("gagging", GaggingComponent::fromJson), + BLINDING("blinding", BlindingComponent::fromJson), + SHOCK("shock", ShockComponent::fromJson), + GPS("gps", GpsComponent::fromJson), + CHOKING("choking", ChokingComponent::fromJson), + ADJUSTABLE("adjustable", AdjustableComponent::fromJson); private final String jsonKey; private final Function factory; diff --git a/src/main/java/com/tiedup/remake/v2/bondage/component/GpsComponent.java b/src/main/java/com/tiedup/remake/v2/bondage/component/GpsComponent.java new file mode 100644 index 0000000..272792a --- /dev/null +++ b/src/main/java/com/tiedup/remake/v2/bondage/component/GpsComponent.java @@ -0,0 +1,45 @@ +package com.tiedup.remake.v2.bondage.component; + +import com.google.gson.JsonObject; + +/** + * Component: GPS tracking and safe zone for data-driven items. + * + * JSON config: + * {@code "gps": {"safe_zone_radius": 50, "public_tracking": false}} + */ +public class GpsComponent implements IItemComponent { + + private final int safeZoneRadius; + private final boolean publicTracking; + + private GpsComponent(int safeZoneRadius, boolean publicTracking) { + this.safeZoneRadius = safeZoneRadius; + this.publicTracking = publicTracking; + } + + public static IItemComponent fromJson(JsonObject config) { + int radius = 50; + boolean publicTracking = false; + if (config != null) { + if (config.has("safe_zone_radius")) { + radius = config.get("safe_zone_radius").getAsInt(); + } + if (config.has("public_tracking")) { + publicTracking = config.get("public_tracking").getAsBoolean(); + } + } + radius = Math.max(0, radius); + return new GpsComponent(radius, publicTracking); + } + + /** Safe zone radius in blocks. 0 = no safe zone (tracking only). */ + public int getSafeZoneRadius() { + return safeZoneRadius; + } + + /** Whether any player can track (not just the owner). */ + public boolean isPublicTracking() { + return publicTracking; + } +} diff --git a/src/main/java/com/tiedup/remake/v2/bondage/component/ShockComponent.java b/src/main/java/com/tiedup/remake/v2/bondage/component/ShockComponent.java new file mode 100644 index 0000000..1c6d867 --- /dev/null +++ b/src/main/java/com/tiedup/remake/v2/bondage/component/ShockComponent.java @@ -0,0 +1,52 @@ +package com.tiedup.remake.v2.bondage.component; + +import com.google.gson.JsonObject; + +/** + * Component: shock collar behavior for data-driven items. + * + * JSON config: + * {@code "shock": {"damage": 2.0, "auto_interval": 0}} + * auto_interval: ticks between auto-shocks (0 = no auto-shock, manual only) + */ +public class ShockComponent implements IItemComponent { + + private final float damage; + private final int autoInterval; // 0 = manual only + + private ShockComponent(float damage, int autoInterval) { + this.damage = damage; + this.autoInterval = autoInterval; + } + + public static IItemComponent fromJson(JsonObject config) { + float damage = 2.0f; + int autoInterval = 0; + if (config != null) { + if (config.has("damage")) { + damage = config.get("damage").getAsFloat(); + } + if (config.has("auto_interval")) { + autoInterval = config.get("auto_interval").getAsInt(); + } + } + damage = Math.max(0.0f, damage); + autoInterval = Math.max(0, autoInterval); + return new ShockComponent(damage, autoInterval); + } + + /** Damage dealt per shock. */ + public float getDamage() { + return damage; + } + + /** Ticks between auto-shocks. 0 = manual shock only (via controller). */ + public int getAutoInterval() { + return autoInterval; + } + + /** Whether this item has auto-shock capability. */ + public boolean hasAutoShock() { + return autoInterval > 0; + } +}