Condition overhaul completed

This commit is contained in:
Vidal committed 2026-02-20 21:36:08 -03:00
1 parent a2e0bb50b9
commit 89e87b7656
9 files changed
+290 -292

No files matched your search

@@ -1233,6 +1233,7 @@ public abstract class Ability implements IAbility, IAbilityAction {
public boolean checkConditions(EntityLivingBase caster, EntityLivingBase target) {
for (AbilityCondition c : conditions) {
if (!c.getUserType().allowsNpc()) continue;
if (!c.check(caster, target)) return false;
}
return true;
@@ -1243,6 +1244,7 @@ public abstract class Ability implements IAbility, IAbilityAction {
*/
public boolean checkConditionsForPlayer(EntityLivingBase caster) {
for (AbilityCondition c : conditions) {
if (!c.getUserType().allowsPlayer()) continue;
if (c.requiresTarget()) continue;
if (!c.check(caster, null)) return false;
}
@@ -9,6 +9,7 @@ import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.LogWriter;
import noppes.npcs.client.gui.builder.FieldDef;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
@@ -16,6 +17,7 @@ public abstract class AbilityCondition {
protected String typeId = "";
protected String name = "";
protected UserType userType = UserType.BOTH;
protected ConditionFilter conditionFilter = ConditionFilter.CASTER;
/**
* Check if this condition is met.
@@ -34,10 +36,6 @@ public abstract class AbilityCondition {
return userType;
}
public void setUserType(UserType userType) {
this.userType = userType;
}
public String getTypeId() {
return typeId;
}
@@ -46,14 +44,32 @@ public abstract class AbilityCondition {
return name;
}
public ConditionFilter getFilter() {
return conditionFilter;
}
public void setFilter(ConditionFilter filter) {
this.conditionFilter = filter;
}
@SideOnly(Side.CLIENT)
public abstract List<FieldDef> getAbilityDefinitions(List<FieldDef> defs);
public abstract void getConditionDefinitions(List<FieldDef> defs);
@SideOnly(Side.CLIENT)
public final List<FieldDef> getAllDefinitions() {
List<FieldDef> defs = new ArrayList<>();
defs.add(FieldDef.enumField("condition.filter", ConditionFilter.class, this::getFilter, this::setFilter));
getConditionDefinitions(defs);
return defs;
}
public final NBTTagCompound writeNBT() {
NBTTagCompound nbt = new NBTTagCompound();
nbt.setInteger("userType", getUserType().ordinal());
nbt.setString("type", getTypeId());
nbt.setString("typeId", getTypeId());
nbt.setString("name", getName());
nbt.setInteger("userType", getUserType().ordinal());
nbt.setInteger("filter", getUserType().ordinal());
writeTypeNBT(nbt);
return nbt;
}
@@ -63,14 +79,15 @@ public abstract class AbilityCondition {
public abstract void readTypeNBT(NBTTagCompound nbt);
public final void readNBT(NBTTagCompound nbt) {
typeId = nbt.getString("type");
typeId = nbt.getString("typeId");
name = nbt.getString("name");
userType = UserType.fromOrdinal(nbt.getInteger("userType"));
conditionFilter = ConditionFilter.fromOrdinal(nbt.getInteger("filter"));
readTypeNBT(nbt);
}
public static AbilityCondition fromNBT(NBTTagCompound nbt) {
String typeId = nbt.getString("type");
String typeId = nbt.getString("typeId");
Supplier<AbilityCondition> factory = AbilityController.Instance.getConditionType(typeId);
if (factory == null) {
LogWriter.info("AbilityController: Unknown condition type: " + typeId);
@@ -0,0 +1,39 @@
package kamkeel.npcs.controllers.data.ability.conditions;
import kamkeel.npcs.controllers.data.ability.UserType;
public enum ConditionFilter {
CASTER,
TARGET,
BOTH;
public boolean checksCaster() {
return this == CASTER || this == BOTH;
}
public boolean checksTarget() {
return this == TARGET || this == BOTH;
}
public static ConditionFilter fromOrdinal(int ordinal) {
ConditionFilter[] values = values();
if (ordinal >= 0 && ordinal < values.length) {
return values[ordinal];
}
return BOTH;
}
@Override
public String toString() {
switch (this) {
case BOTH:
return "condition.filter.both";
case CASTER:
return "condition.filter.caster";
case TARGET:
return "condition.filter.target";
default:
return name();
}
}
}
@@ -1,11 +1,9 @@
package kamkeel.npcs.controllers.data.ability.conditions;
import kamkeel.npcs.controllers.data.ability.UserType;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.client.gui.builder.FieldDef;
import java.util.Collections;
import java.util.List;
public class ConditionHPThreshold extends AbilityCondition{
@@ -16,13 +14,13 @@ public class ConditionHPThreshold extends AbilityCondition{
ABOVE {
@Override
public boolean test(float value, float threshold) {
return value > threshold;
return value >= threshold;
}
},
BELOW {
@Override
public boolean test(float value, float threshold) {
return value < threshold;
return value <= threshold;
}
};
@@ -35,12 +33,23 @@ public class ConditionHPThreshold extends AbilityCondition{
}
return ABOVE;
}
@Override
public String toString() {
switch (this) {
case ABOVE:
return "condition.hp_above";
case BELOW:
return "condition.hp_below";
default:
return name();
}
}
}
public ConditionHPThreshold() {
this.typeId = "condition.cnpc.hp_threshold";
this.name = "Health Threshold";
this.userType = UserType.NPC_ONLY;
this.name = "condition.hp_threshold";
}
@Override
@@ -56,10 +65,10 @@ public class ConditionHPThreshold extends AbilityCondition{
boolean casterCheck = thresholdType.test(casterHp, threshold);
boolean targetCheck = thresholdType.test(targetHp, threshold);
switch (getUserType()) {
switch (getFilter()) {
case BOTH:
return casterCheck && targetCheck;
case PLAYER_ONLY:
case CASTER:
return casterCheck;
default:
return targetCheck;
@@ -83,8 +92,10 @@ public class ConditionHPThreshold extends AbilityCondition{
}
@Override
public List<FieldDef> getAbilityDefinitions(List<FieldDef> defs) {
return Collections.emptyList();
public void getConditionDefinitions(List<FieldDef> defs) {
defs.add(FieldDef.floatField("condition.threshold", this::getThreshold, this::setThreshold).min(0));
defs.add(FieldDef.enumField("condition.threshold_type", ThresholdType.class,
this::getThresholdType, this::setThresholdType));
}
@Override
@@ -6,16 +6,15 @@ import net.minecraft.nbt.NBTTagCompound;
import noppes.npcs.client.gui.builder.FieldDef;
import noppes.npcs.entity.EntityNPCInterface;
import java.util.Collections;
import java.util.List;
public class ConditionHitCount extends AbilityCondition{
public class ConditionHitCount extends AbilityCondition {
private int requiredHits = 3;
private int withinTicks = 60;
public ConditionHitCount() {
this.typeId = "condition.cnpc.hit_count";
this.name = "Hit Count";
this.name = "condition.hit_count";
this.userType = UserType.NPC_ONLY;
}
@@ -49,8 +48,9 @@ public class ConditionHitCount extends AbilityCondition{
}
@Override
public List<FieldDef> getAbilityDefinitions(List<FieldDef> defs) {
return Collections.emptyList();
public void getConditionDefinitions(List<FieldDef> defs) {
defs.add(FieldDef.intField("condition.required_hits", this::getRequiredHits, this::setRequiredHits).min(1));
defs.add(FieldDef.intField("condition.within_ticks", this::getWithinTicks, this::setWithinTicks).min(0));
}
@Override
@@ -1,7 +1,7 @@
package noppes.npcs.client.gui.advanced;
import kamkeel.npcs.controllers.data.ability.Ability;
import kamkeel.npcs.controllers.data.ability.Condition;
import kamkeel.npcs.controllers.data.ability.conditions.AbilityCondition;
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldBuilder;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.nbt.NBTTagCompound;
@@ -49,7 +49,7 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi
private List<FieldDef> fieldDefs;
private List<String> customTabNames;
private List<Condition> conditions;
private List<AbilityCondition> conditions;
private int editingConditionIndex = -1;
private AbilityFieldBuilder builder;
@@ -60,7 +60,7 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi
public SubGuiAbilityConfig(Ability ability, IAbilityConfigCallback callback) {
this.ability = ability;
this.callback = callback;
// this.conditions = new ArrayList<>(ability.getConditions());
this.conditions = new ArrayList<>(ability.getConditions());
this.fieldDefs = ability.getAllDefinitions();
discoverCustomTabs();
@@ -230,51 +230,32 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi
// ═══════════════════════════════════════════════════════════════════════════
private int renderConditions(GuiScrollWindow sw, int y, int labelCounter) {
// y += 3;
// sw.addLabel(new GuiNpcLabel(labelCounter, "ability.conditions", L_LABEL_X, y + 2, 0xFFFF55));
// y += 15;
//
// for (int i = 0; i < conditions.size() && i < 3; i++) {
// Condition cond = conditions.get(i);
// String condName = getConditionDisplayName(cond);
// sw.addButton(new GuiNpcButton(50 + i * 10, L_LABEL_X, y, 140, 20, condName));
// sw.addButton(new GuiNpcButton(51 + i * 10, L_LABEL_X + 145, y, 40, 20, "gui.edit"));
// sw.addButton(new GuiNpcButton(52 + i * 10, L_LABEL_X + 190, y, 20, 20, "X"));
// y += 22;
// }
//
// if (conditions.size() < 3) {
// sw.addButton(new GuiNpcButton(80, L_LABEL_X, y, 50, 20, "gui.add"));
// y += ROW_H;
// }
//
y += 3;
sw.addLabel(new GuiNpcLabel(labelCounter, "ability.conditions", L_LABEL_X, y + 2, 0xFFFF55));
y += 15;
for (int i = 0; i < conditions.size() && i < 3; i++) {
AbilityCondition cond = conditions.get(i);
String condName = getConditionDisplayName(cond);
sw.addButton(new GuiNpcButton(50 + i * 10, L_LABEL_X, y, 140, 20, condName));
sw.addButton(new GuiNpcButton(51 + i * 10, L_LABEL_X + 145, y, 40, 20, "gui.edit"));
sw.addButton(new GuiNpcButton(52 + i * 10, L_LABEL_X + 190, y, 20, 20, "X"));
y += 22;
}
if (conditions.size() < 3) {
sw.addButton(new GuiNpcButton(80, L_LABEL_X, y, 50, 20, "gui.add"));
y += ROW_H;
}
return y;
}
// private String getConditionDisplayName(Condition cond) {
// if (cond == null) return "None";
// String typeId = cond.getTypeId();
// switch (typeId) {
// case "hp_above":
// return StatCollector.translateToLocal("condition.hp_above") + " " + (int) (getConditionThreshold(cond) * 100) + "%";
// case "hp_below":
// return StatCollector.translateToLocal("condition.hp_below") + " " + (int) (getConditionThreshold(cond) * 100) + "%";
// case "target_hp_above":
// return StatCollector.translateToLocal("condition.target_hp_above") + " " + (int) (getConditionThreshold(cond) * 100) + "%";
// case "target_hp_below":
// return StatCollector.translateToLocal("condition.target_hp_below") + " " + (int) (getConditionThreshold(cond) * 100) + "%";
// case "hit_count":
// Condition.ConditionHitCount hc = (Condition.ConditionHitCount) cond;
// return StatCollector.translateToLocal("condition.hit_count") + ": " + hc.getRequiredHits() + "/" + hc.getWithinTicks() + "t";
// default:
// return typeId;
// }
// }
// private float getConditionThreshold(Condition cond) {
// NBTTagCompound nbt = cond.writeNBT();
// return nbt.hasKey("threshold") ? nbt.getFloat("threshold") : 0.5f;
// }
private String getConditionDisplayName(AbilityCondition cond) {
if (cond == null) return "None";
String name = cond.getName();
return StatCollector.translateToLocal(name);
}
// ═══════════════════════════════════════════════════════════════════════════
// BUTTON EVENTS
@@ -382,7 +363,7 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi
if (subgui instanceof SubGuiConditionEdit) {
SubGuiConditionEdit condEdit = (SubGuiConditionEdit) subgui;
Condition result = condEdit.getResult();
AbilityCondition result = condEdit.getResult();
if (result != null && editingConditionIndex >= 0) {
if (editingConditionIndex < conditions.size()) {
conditions.set(editingConditionIndex, result);
@@ -408,8 +389,8 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi
}
protected void applyToAbility() {
// ability.getConditions().clear();
// for (Condition c : conditions) ability.addCondition(c);
ability.getConditions().clear();
for (AbilityCondition c : conditions) ability.addCondition(c);
}
public void loadAbility(Ability loadedAbility) {
@@ -418,7 +399,7 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi
nbt.setString("typeId", ability.getTypeId());
ability.readNBT(nbt);
// this.conditions = new ArrayList<>(ability.getConditions());
this.conditions = new ArrayList<>(ability.getConditions());
this.fieldDefs = ability.getAllDefinitions();
discoverCustomTabs();
initGui();
@@ -6,7 +6,6 @@ import kamkeel.npcs.controllers.data.ability.AbilityAction;
import kamkeel.npcs.controllers.data.ability.AbilityVariant;
import kamkeel.npcs.controllers.data.ability.ChainedAbility;
import kamkeel.npcs.controllers.data.ability.ChainedAbilityEntry;
import kamkeel.npcs.controllers.data.ability.Condition;
import kamkeel.npcs.controllers.data.ability.AbilityIconData;
import kamkeel.npcs.controllers.data.ability.IChainedAbilityFieldProvider;
import kamkeel.npcs.controllers.data.ability.UserType;
@@ -14,7 +13,6 @@ import kamkeel.npcs.controllers.data.ability.conditions.AbilityCondition;
import kamkeel.npcs.network.PacketClient;
import kamkeel.npcs.network.packets.request.ability.CustomAbilitySavePacket;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.StatCollector;
import noppes.npcs.client.gui.builder.FieldDef;
import noppes.npcs.client.gui.builder.GuiFieldBuilder;
@@ -23,16 +21,12 @@ import noppes.npcs.client.gui.util.GuiNpcButton;
import noppes.npcs.client.gui.util.GuiNpcLabel;
import noppes.npcs.client.gui.util.GuiNpcTextField;
import noppes.npcs.client.gui.util.GuiScrollWindow;
import kamkeel.npcs.controllers.data.ability.Ability;
import kamkeel.npcs.controllers.data.ability.AbilityAction;
import kamkeel.npcs.controllers.data.ability.ChainedAbility;
import noppes.npcs.client.gui.util.*;
import java.util.ArrayList;
import noppes.npcs.client.gui.util.IChainedAbilityConfigCallback;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
@@ -94,7 +88,7 @@ public class SubGuiChainedAbilityConfig extends SubGuiInterface implements IText
private List<FieldDef> fieldDefs;
private List<ChainedAbilityEntry> entries;
// private List<AbilityCondition> conditions;
private List<AbilityCondition> conditions;
// Dynamic tabs injected by field providers (e.g., "Icon")
private List<String> extraTabs = new ArrayList<>();
@@ -133,7 +127,7 @@ public class SubGuiChainedAbilityConfig extends SubGuiInterface implements IText
this.readOnlyEntries = readOnlyEntries;
this.npcSlots = npcSlots;
this.entries = new ArrayList<>(chain.getEntries());
// this.conditions = new ArrayList<>(chain.getConditions());
this.conditions = new ArrayList<>(chain.getConditions());
buildFieldDefs();
@@ -429,50 +423,31 @@ public class SubGuiChainedAbilityConfig extends SubGuiInterface implements IText
}
private int renderConditions(GuiScrollWindow sw, int y, int labelCounter) {
// y += 3;
// sw.addLabel(new GuiNpcLabel(labelCounter, "ability.conditions", L_LABEL_X, y + 2, 0xFFFF55));
// y += 15;
//
// for (int i = 0; i < conditions.size() && i < 3; i++) {
// Condition cond = conditions.get(i);
// String condName = getConditionDisplayName(cond);
// sw.addButton(new GuiNpcButton(COND_BASE + i * COND_STRIDE, L_LABEL_X, y, 140, 20, condName));
// sw.addButton(new GuiNpcButton(COND_BASE + i * COND_STRIDE + 1, L_LABEL_X + 145, y, 40, 20, "gui.edit"));
// sw.addButton(new GuiNpcButton(COND_BASE + i * COND_STRIDE + 2, L_LABEL_X + 190, y, 20, 20, "X"));
// y += 22;
// }
//
// if (conditions.size() < 3) {
// sw.addButton(new GuiNpcButton(BTN_ADD_COND, L_LABEL_X, y, 50, 20, "gui.add"));
// y += ROW_H;
// }
y += 3;
sw.addLabel(new GuiNpcLabel(labelCounter, "ability.conditions", L_LABEL_X, y + 2, 0xFFFF55));
y += 15;
for (int i = 0; i < conditions.size() && i < 3; i++) {
AbilityCondition cond = conditions.get(i);
String condName = getConditionDisplayName(cond);
sw.addButton(new GuiNpcButton(COND_BASE + i * COND_STRIDE, L_LABEL_X, y, 140, 20, condName));
sw.addButton(new GuiNpcButton(COND_BASE + i * COND_STRIDE + 1, L_LABEL_X + 145, y, 40, 20, "gui.edit"));
sw.addButton(new GuiNpcButton(COND_BASE + i * COND_STRIDE + 2, L_LABEL_X + 190, y, 20, 20, "X"));
y += 22;
}
if (conditions.size() < 3) {
sw.addButton(new GuiNpcButton(BTN_ADD_COND, L_LABEL_X, y, 50, 20, "gui.add"));
y += ROW_H;
}
return y;
}
private String getConditionDisplayName(Condition cond) {
private String getConditionDisplayName(AbilityCondition cond) {
if (cond == null) return "None";
String typeId = cond.getTypeId();
switch (typeId) {
case "hp_above":
return StatCollector.translateToLocal("condition.hp_above") + " " + (int) (getConditionThreshold(cond) * 100) + "%";
case "hp_below":
return StatCollector.translateToLocal("condition.hp_below") + " " + (int) (getConditionThreshold(cond) * 100) + "%";
case "target_hp_above":
return StatCollector.translateToLocal("condition.target_hp_above") + " " + (int) (getConditionThreshold(cond) * 100) + "%";
case "target_hp_below":
return StatCollector.translateToLocal("condition.target_hp_below") + " " + (int) (getConditionThreshold(cond) * 100) + "%";
case "hit_count":
Condition.ConditionHitCount hc = (Condition.ConditionHitCount) cond;
return StatCollector.translateToLocal("condition.hit_count") + ": " + hc.getRequiredHits() + "/" + hc.getWithinTicks() + "t";
default:
return typeId;
}
}
private float getConditionThreshold(Condition cond) {
NBTTagCompound nbt = cond.writeNBT();
return nbt.hasKey("threshold") ? nbt.getFloat("threshold") : 0.5f;
String name = cond.getName();
return StatCollector.translateToLocal(name);
}
// ═══════════════════════════════════════════════════════════════════════════
@@ -623,29 +598,29 @@ public class SubGuiChainedAbilityConfig extends SubGuiInterface implements IText
}
private boolean handleConditionButton(int id) {
// if (id >= COND_BASE && id < COND_END) {
// int condIndex = (id - COND_BASE) / COND_STRIDE;
// int action = (id - COND_BASE) % COND_STRIDE;
// if (action == 0 || action == 1) {
// if (condIndex < conditions.size()) {
// editingConditionIndex = condIndex;
// setSubGui(new SubGuiConditionEdit(conditions.get(condIndex)));
// }
// } else if (action == 2) {
// if (condIndex < conditions.size()) {
// conditions.remove(condIndex);
// initGui();
// }
// }
// return true;
// }
// if (id == BTN_ADD_COND) {
// if (conditions.size() < 3) {
// editingConditionIndex = conditions.size();
// setSubGui(new SubGuiConditionEdit(null));
// }
// return true;
// }
if (id >= COND_BASE && id < COND_END) {
int condIndex = (id - COND_BASE) / COND_STRIDE;
int action = (id - COND_BASE) % COND_STRIDE;
if (action == 0 || action == 1) {
if (condIndex < conditions.size()) {
editingConditionIndex = condIndex;
setSubGui(new SubGuiConditionEdit(conditions.get(condIndex)));
}
} else if (action == 2) {
if (condIndex < conditions.size()) {
conditions.remove(condIndex);
initGui();
}
}
return true;
}
if (id == BTN_ADD_COND) {
if (conditions.size() < 3) {
editingConditionIndex = conditions.size();
setSubGui(new SubGuiConditionEdit(null));
}
return true;
}
return false;
}
@@ -850,14 +825,14 @@ public class SubGuiChainedAbilityConfig extends SubGuiInterface implements IText
}
private void handleConditionEditClosed(SubGuiConditionEdit gui) {
// Condition result = gui.getResult();
// if (result != null && editingConditionIndex >= 0) {
// if (editingConditionIndex < conditions.size()) {
// conditions.set(editingConditionIndex, result);
// } else {
// conditions.add(result);
// }
// }
AbilityCondition result = gui.getResult();
if (result != null && editingConditionIndex >= 0) {
if (editingConditionIndex < conditions.size()) {
conditions.set(editingConditionIndex, result);
} else {
conditions.add(result);
}
}
editingConditionIndex = -1;
}
@@ -895,10 +870,10 @@ public class SubGuiChainedAbilityConfig extends SubGuiInterface implements IText
}
// Conditions
// chain.getConditions().clear();
// for (Condition c : conditions) {
// chain.getConditions().add(c);
// }
chain.getConditions().clear();
for (AbilityCondition c : conditions) {
chain.getConditions().add(c);
}
// Remove consumed NPC slots (descending order to preserve indices)
if (npcSlots != null && !consumedSlotIndices.isEmpty()) {
@@ -1,190 +1,159 @@
package noppes.npcs.client.gui.advanced;
import kamkeel.npcs.controllers.data.ability.Condition;
import kamkeel.npcs.controllers.AbilityController;
import kamkeel.npcs.controllers.data.ability.conditions.AbilityCondition;
import net.minecraft.client.gui.GuiButton;
import noppes.npcs.client.gui.util.GuiNpcButton;
import noppes.npcs.client.gui.util.GuiNpcLabel;
import noppes.npcs.client.gui.util.GuiNpcTextField;
import noppes.npcs.client.gui.util.ITextfieldListener;
import noppes.npcs.client.gui.util.SubGuiInterface;
import noppes.npcs.client.gui.builder.FieldDef;
import noppes.npcs.client.gui.util.*;
import kamkeel.npcs.controllers.data.ability.gui.AbilityFieldBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
/**
* SubGui for editing a single ability condition.
* Allows selecting condition type and configuring its parameters.
* SubGui for editing a single AbilityCondition.
*
* Type selection stays manual (we need to swap the condition object).
* Field rendering is fully delegated to AbilityCondition#getAbilityDefinitions(),
* mirroring the pattern used in SubGuiAbilityConfig.
*/
public class SubGuiConditionEdit extends SubGuiInterface implements ITextfieldListener {
public class SubGuiConditionEdit extends SubGuiInterface implements ITextfieldListener, ISubGuiListener {
// Condition types
private static final String[] CONDITION_TYPES = {
"condition.hp_above",
"condition.hp_below",
"condition.target_hp_above",
"condition.target_hp_below",
"condition.hit_count"
};
private static final int DECLARATIVE_ID_START = 1000;
private static final int CLEAR_ID_START = 2000;
private static final int LABEL_ID_START = 3000;
private static final String[] CONDITION_TYPE_IDS = {
"hp_above",
"hp_below",
"target_hp_above",
"target_hp_below",
"hit_count"
};
private static final int BTN_TYPE = 1;
private static final int BTN_CANCEL = 10;
private static final int BTN_DONE = 11;
// Current condition being edited
private Condition condition;
private Condition result;
private AbilityCondition condition;
private AbilityCondition result;
// State
private final String[] conditionTypeIds;
private final String[] conditionTypeNames;
private int selectedTypeIndex = 0;
private float threshold = 0.5f; // For HP conditions (0.0-1.0)
private int requiredHits = 3; // For hit_count
private int withinTicks = 60; // For hit_count
public SubGuiConditionEdit(Condition existing) {
this.condition = existing;
private AbilityFieldBuilder builder;
public SubGuiConditionEdit(AbilityCondition existing) {
this.result = null;
conditionTypeIds = AbilityController.Instance.getConditionTypes();
conditionTypeNames = new String[conditionTypeIds.length];
for (int i = 0; i < conditionTypeIds.length; i++) {
Supplier<AbilityCondition> factory = AbilityController.Instance.getConditionType(conditionTypeIds[i]);
conditionTypeNames[i] = factory != null ? factory.get().getName() : conditionTypeIds[i];
}
if (existing != null) {
String typeId = existing.getTypeId();
for (int i = 0; i < CONDITION_TYPE_IDS.length; i++) {
if (CONDITION_TYPE_IDS[i].equals(typeId)) {
for (int i = 0; i < conditionTypeIds.length; i++) {
if (conditionTypeIds[i].equals(existing.getTypeId())) {
selectedTypeIndex = i;
break;
}
}
loadFromCondition(existing);
this.condition = existing;
} else {
this.condition = spawnCondition(selectedTypeIndex);
}
setBackground("menubg.png");
xSize = 220;
ySize = 140;
xSize = 240;
ySize = 180;
}
private void loadFromCondition(Condition cond) {
String typeId = cond.getTypeId();
if (typeId.equals("hit_count")) {
Condition.ConditionHitCount hitCount = (Condition.ConditionHitCount) cond;
requiredHits = hitCount.getRequiredHits();
withinTicks = hitCount.getWithinTicks();
} else {
// HP-based conditions
net.minecraft.nbt.NBTTagCompound nbt = cond.writeNBT();
threshold = nbt.hasKey("threshold") ? nbt.getFloat("threshold") : 0.5f;
}
private AbilityCondition spawnCondition(int typeIndex) {
if (typeIndex < 0 || typeIndex >= conditionTypeIds.length) return null;
Supplier<AbilityCondition> factory = AbilityController.Instance.getConditionType(conditionTypeIds[typeIndex]);
return factory != null ? factory.get() : null;
}
@Override
public void initGui() {
GuiNpcTextField.unfocus();
super.initGui();
int y = guiTop + 8;
int labelX = guiLeft + 8;
int fieldX = guiLeft + 90;
int swX = guiLeft + 4;
int swY = guiTop + 5;
int swW = xSize - 8;
int swH = ySize - 35;
// Title
addLabel(new GuiNpcLabel(0, "condition.edit", labelX, y));
y += 18;
// Condition Type selector
addLabel(new GuiNpcLabel(1, "gui.type", labelX, y + 5));
GuiNpcButton typeBtn = new GuiNpcButton(1, fieldX, y, 115, 20, CONDITION_TYPES, selectedTypeIndex);
typeBtn.setHoverText("condition.hover.type");
int labelY = guiTop + 8;
addLabel(new GuiNpcLabel(0, "gui.type", guiLeft + 8, labelY + 5));
GuiNpcButton typeBtn = new GuiNpcButton(BTN_TYPE, guiLeft + 80, labelY, 155, 20, conditionTypeNames, selectedTypeIndex);
addButton(typeBtn);
y += 26;
// Type-specific fields
String typeId = CONDITION_TYPE_IDS[selectedTypeIndex];
if (typeId.equals("hit_count")) {
// Hit count fields
addLabel(new GuiNpcLabel(2, "condition.hits", labelX, y + 5));
GuiNpcTextField hitsField = new GuiNpcTextField(2, this, fontRendererObj, fieldX, y, 40, 20, "" + requiredHits);
hitsField.setIntegersOnly();
hitsField.setMinMaxDefault(1, 100, 3);
hitsField.setHoverText("condition.hover.hits");
addTextField(hitsField);
y += 24;
swY += 26;
swH -= 26;
addLabel(new GuiNpcLabel(3, "condition.within", labelX, y + 5));
GuiNpcTextField ticksField = new GuiNpcTextField(3, this, fontRendererObj, fieldX, y, 40, 20, "" + withinTicks);
ticksField.setIntegersOnly();
ticksField.setMinMaxDefault(1, 1200, 60);
ticksField.setHoverText("condition.hover.within");
addTextField(ticksField);
} else {
// HP threshold field (as percentage)
addLabel(new GuiNpcLabel(2, "condition.percent", labelX, y + 5));
int percent = (int) (threshold * 100);
GuiNpcTextField thresholdField = new GuiNpcTextField(4, this, fontRendererObj, fieldX, y, 40, 20, "" + percent);
thresholdField.setIntegersOnly();
thresholdField.setMinMaxDefault(1, 99, 50);
thresholdField.setHoverText("condition.hover.threshold");
addTextField(thresholdField);
addLabel(new GuiNpcLabel(4, "%", fieldX + 45, y + 5));
List<FieldDef> fields = new ArrayList<>();
if (condition != null) {
fields = condition.getAllDefinitions();
}
// Bottom buttons
addButton(new GuiNpcButton(10, guiLeft + 8, guiTop + ySize - 28, 60, 20, "gui.cancel"));
addButton(new GuiNpcButton(11, guiLeft + xSize - 68, guiTop + ySize - 28, 60, 20, "gui.done"));
builder = new AbilityFieldBuilder(this, fontRendererObj);
builder.startIds(DECLARATIVE_ID_START, CLEAR_ID_START, LABEL_ID_START);
builder.startY(5);
builder.buildScrollWindow(fields, swX, swY, swW, swH);
int btnY = guiTop + ySize - 26;
addButton(new GuiNpcButton(BTN_CANCEL, guiLeft + 8, btnY, 60, 20, "gui.cancel"));
addButton(new GuiNpcButton(BTN_DONE, guiLeft + xSize - 68, btnY, 60, 20, "gui.done"));
}
@Override
public void buttonEvent(GuiButton guibutton) {
int id = guibutton.id;
if (id == 1) {
// Type changed
selectedTypeIndex = ((GuiNpcButton) guibutton).getValue();
if (id == BTN_TYPE) {
int newIndex = ((GuiNpcButton) guibutton).getValue();
if (newIndex != selectedTypeIndex) {
selectedTypeIndex = newIndex;
condition = spawnCondition(selectedTypeIndex);
}
initGui();
} else if (id == 10) {
// Cancel - close without saving
return;
}
if (id == BTN_CANCEL) {
result = null;
close();
} else if (id == 11) {
// Done - create condition and close
result = createCondition();
return;
}
if (id == BTN_DONE) {
result = condition;
close();
return;
}
if (builder != null && builder.handleButtonEvent(id, guibutton)) {
if (!hasSubGui()) {
initGui();
}
}
}
@Override
public void unFocused(GuiNpcTextField textField) {
int id = textField.id;
if (id == 2) {
requiredHits = textField.getInteger();
} else if (id == 3) {
withinTicks = textField.getInteger();
} else if (id == 4) {
int percent = textField.getInteger();
threshold = percent / 100.0f;
if (textField.id < DECLARATIVE_ID_START) return;
if (builder != null && builder.handleTextFieldEvent(textField.id, textField)) {
initGui();
}
}
private Condition createCondition() {
String typeId = CONDITION_TYPE_IDS[selectedTypeIndex];
switch (typeId) {
case "hp_above":
return new Condition.ConditionHPAbove(threshold);
case "hp_below":
return new Condition.ConditionHPBelow(threshold);
case "target_hp_above":
return new Condition.ConditionTargetHPAbove(threshold);
case "target_hp_below":
return new Condition.ConditionTargetHPBelow(threshold);
case "hit_count":
return new Condition.ConditionHitCount(requiredHits, withinTicks);
default:
return null;
@Override
public void subGuiClosed(SubGuiInterface subgui) {
if (builder != null && builder.handleSubGuiClosed(subgui)) {
initGui();
}
}
/**
* Get the resulting condition after dialog closes.
* Returns null if cancelled or no valid condition.
*/
public Condition getResult() {
public AbilityCondition getResult() {
return result;
}
}