mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 22:27:32 +00:00
Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
15486a1ea8
11 files changed
+385
-414
No files matched your search
@@ -1,6 +1,9 @@
|
||||
package kamkeel.npcs.controllers;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.*;
|
||||
import kamkeel.npcs.controllers.data.ability.conditions.AbilityCondition;
|
||||
import kamkeel.npcs.controllers.data.ability.conditions.ConditionHPThreshold;
|
||||
import kamkeel.npcs.controllers.data.ability.conditions.ConditionHitCount;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityCharge;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityCutter;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityDash;
|
||||
@@ -54,7 +57,7 @@ public class AbilityController implements IAbilityHandler {
|
||||
private final List<IAbilityFieldProvider> fieldProviders = new ArrayList<>();
|
||||
private final List<IChainedAbilityFieldProvider> chainedFieldProviders = new ArrayList<>();
|
||||
private final List<IAbilityExtender> extenders = new ArrayList<>();
|
||||
private final Map<String, Supplier<IAbilityCondition>> conditionTypes = new HashMap<>();
|
||||
private final Map<String, Supplier<AbilityCondition>> conditionTypes = new HashMap<>();
|
||||
private final List<Predicate<EntityPlayer>> flightCheckers = new ArrayList<>();
|
||||
|
||||
// ── Legacy Migration ─────────────────────────────────────────────────────
|
||||
@@ -147,7 +150,8 @@ public class AbilityController implements IAbilityHandler {
|
||||
}
|
||||
|
||||
private void registerBuiltinConditionTypes() {
|
||||
registerCondition(IAbilityCondition.ConditionHPAbove::new);
|
||||
registerCondition(ConditionHPThreshold::new);
|
||||
registerCondition(ConditionHitCount::new);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
@@ -880,8 +884,8 @@ public class AbilityController implements IAbilityHandler {
|
||||
return extenders;
|
||||
}
|
||||
|
||||
public void registerCondition(Supplier<IAbilityCondition> conditionFactory) {
|
||||
IAbilityCondition temp = conditionFactory.get();
|
||||
public void registerCondition(Supplier<AbilityCondition> conditionFactory) {
|
||||
AbilityCondition temp = conditionFactory.get();
|
||||
String typeId = temp.getTypeId();
|
||||
if (conditionTypes.containsKey(typeId)) {
|
||||
LogWriter.info("AbilityController: Overwriting Condition type: " + typeId);
|
||||
@@ -889,7 +893,7 @@ public class AbilityController implements IAbilityHandler {
|
||||
conditionTypes.put(typeId, conditionFactory);
|
||||
}
|
||||
|
||||
public Supplier<IAbilityCondition> getConditionType(String key) {
|
||||
public Supplier<AbilityCondition> getConditionType(String key) {
|
||||
return conditionTypes.get(key);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package kamkeel.npcs.controllers.data.ability;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.conditions.AbilityCondition;
|
||||
import kamkeel.npcs.controllers.data.telegraph.Telegraph;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphInstance;
|
||||
import kamkeel.npcs.controllers.data.telegraph.TelegraphType;
|
||||
@@ -58,7 +59,7 @@ public abstract class Ability implements IAbility, IAbilityAction {
|
||||
// Selection
|
||||
protected int weight = 10;
|
||||
protected boolean enabled = true;
|
||||
protected List<Condition> conditions = new ArrayList<>();
|
||||
protected List<AbilityCondition> conditions = new ArrayList<>();
|
||||
|
||||
// Targeting
|
||||
protected TargetingMode targetingMode = TargetingMode.AGGRO_TARGET;
|
||||
@@ -1231,7 +1232,7 @@ public abstract class Ability implements IAbility, IAbilityAction {
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
public boolean checkConditions(EntityLivingBase caster, EntityLivingBase target) {
|
||||
for (Condition c : conditions) {
|
||||
for (AbilityCondition c : conditions) {
|
||||
if (!c.check(caster, target)) return false;
|
||||
}
|
||||
return true;
|
||||
@@ -1241,7 +1242,7 @@ public abstract class Ability implements IAbility, IAbilityAction {
|
||||
* Check conditions for a player caster, skipping target-requiring conditions.
|
||||
*/
|
||||
public boolean checkConditionsForPlayer(EntityLivingBase caster) {
|
||||
for (Condition c : conditions) {
|
||||
for (AbilityCondition c : conditions) {
|
||||
if (c.requiresTarget()) continue;
|
||||
if (!c.check(caster, null)) return false;
|
||||
}
|
||||
@@ -1310,7 +1311,7 @@ public abstract class Ability implements IAbility, IAbilityAction {
|
||||
|
||||
// Conditions
|
||||
NBTTagList condList = new NBTTagList();
|
||||
for (Condition c : conditions) condList.appendTag(c.writeNBT());
|
||||
for (AbilityCondition c : conditions) condList.appendTag(c.writeNBT());
|
||||
nbt.setTag("conditions", condList);
|
||||
|
||||
// Effects
|
||||
@@ -1397,7 +1398,7 @@ public abstract class Ability implements IAbility, IAbilityAction {
|
||||
conditions.clear();
|
||||
NBTTagList condList = nbt.getTagList("conditions", 10);
|
||||
for (int i = 0; i < condList.tagCount(); i++) {
|
||||
Condition c = Condition.fromNBT(condList.getCompoundTagAt(i));
|
||||
AbilityCondition c = AbilityCondition.fromNBT(condList.getCompoundTagAt(i));
|
||||
if (c != null) conditions.add(c);
|
||||
}
|
||||
|
||||
@@ -1935,11 +1936,11 @@ public abstract class Ability implements IAbility, IAbilityAction {
|
||||
return customData;
|
||||
}
|
||||
|
||||
public List<Condition> getConditions() {
|
||||
public List<AbilityCondition> getConditions() {
|
||||
return conditions;
|
||||
}
|
||||
|
||||
public void addCondition(Condition c) {
|
||||
public void addCondition(AbilityCondition c) {
|
||||
conditions.add(c);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.conditions.AbilityCondition;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
@@ -57,7 +58,7 @@ public class ChainedAbility implements IChainedAbility, IAbilityAction {
|
||||
/**
|
||||
* Chain-level conditions (individual ability conditions are ignored).
|
||||
*/
|
||||
private List<Condition> conditions = new ArrayList<>();
|
||||
private List<AbilityCondition> conditions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Ordered list of ability entries to execute.
|
||||
@@ -185,11 +186,11 @@ public class ChainedAbility implements IChainedAbility, IAbilityAction {
|
||||
return UserType.NPC_ONLY;
|
||||
}
|
||||
|
||||
public List<Condition> getConditions() {
|
||||
public List<AbilityCondition> getConditions() {
|
||||
return conditions;
|
||||
}
|
||||
|
||||
public void setConditions(List<Condition> conditions) {
|
||||
public void setConditions(List<AbilityCondition> conditions) {
|
||||
this.conditions = conditions != null ? conditions : new ArrayList<>();
|
||||
}
|
||||
|
||||
@@ -279,7 +280,7 @@ public class ChainedAbility implements IChainedAbility, IAbilityAction {
|
||||
* Check all chain-level conditions against the caster and target.
|
||||
*/
|
||||
public boolean checkConditions(EntityLivingBase caster, EntityLivingBase target) {
|
||||
for (Condition c : conditions) {
|
||||
for (AbilityCondition c : conditions) {
|
||||
if (!c.check(caster, target)) {
|
||||
return false;
|
||||
}
|
||||
@@ -291,7 +292,7 @@ public class ChainedAbility implements IChainedAbility, IAbilityAction {
|
||||
* Check conditions for player use (skip target-requiring conditions).
|
||||
*/
|
||||
public boolean checkConditionsForPlayer(EntityLivingBase caster) {
|
||||
for (Condition c : conditions) {
|
||||
for (AbilityCondition c : conditions) {
|
||||
if (c.requiresTarget()) continue;
|
||||
if (!c.check(caster, null)) {
|
||||
return false;
|
||||
@@ -382,7 +383,7 @@ public class ChainedAbility implements IChainedAbility, IAbilityAction {
|
||||
|
||||
// Conditions
|
||||
NBTTagList condList = new NBTTagList();
|
||||
for (Condition c : conditions) {
|
||||
for (AbilityCondition c : conditions) {
|
||||
condList.appendTag(c.writeNBT());
|
||||
}
|
||||
nbt.setTag("Conditions", condList);
|
||||
@@ -416,7 +417,7 @@ public class ChainedAbility implements IChainedAbility, IAbilityAction {
|
||||
conditions.clear();
|
||||
NBTTagList condList = nbt.getTagList("Conditions", 10);
|
||||
for (int i = 0; i < condList.tagCount(); i++) {
|
||||
Condition c = Condition.fromNBT(condList.getCompoundTagAt(i));
|
||||
AbilityCondition c = AbilityCondition.fromNBT(condList.getCompoundTagAt(i));
|
||||
if (c != null) {
|
||||
conditions.add(c);
|
||||
}
|
||||
|
||||
@@ -1,197 +0,0 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
public abstract class ConditionField<T> {
|
||||
protected final String key;
|
||||
protected final String label;
|
||||
protected final Class<T> type; // Float.class, Integer.class, etc
|
||||
protected T value;
|
||||
|
||||
public ConditionField(String key, String label, Class<T> type, T defaultValue) {
|
||||
this.key = key;
|
||||
this.label = label;
|
||||
this.type = type;
|
||||
this.value = defaultValue;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
public Class<T> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public abstract void writeNBT(NBTTagCompound nbt);
|
||||
|
||||
public abstract void readNBT(NBTTagCompound nbt);
|
||||
|
||||
public static ConditionField<Integer> intField(String key, String label, int defaultValue) {
|
||||
return intField(key, label, defaultValue, 0, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public static ConditionField<Integer> intField(String key, String label, int defaultValue, int min, int max) {
|
||||
return new NumberField<>(key, label, Integer.class, defaultValue, min, max);
|
||||
}
|
||||
|
||||
public static ConditionField<Double> doubleField(String key, String label, double defaultValue) {
|
||||
return doubleField(key, label, defaultValue, 0, Double.MAX_VALUE);
|
||||
}
|
||||
|
||||
public static ConditionField<Double> doubleField(String key, String label, double defaultValue, double min, double max) {
|
||||
return new NumberField<>(key, label, Double.class, defaultValue, min, max);
|
||||
}
|
||||
|
||||
public static ConditionField<Float> floatField(String key, String label, float defaultValue) {
|
||||
return floatField(key, label, defaultValue, 0, Float.MAX_VALUE);
|
||||
}
|
||||
|
||||
public static ConditionField<Float> floatField(String key, String label, float defaultValue, float min, float max) {
|
||||
return new NumberField<>(key, label, Float.class, defaultValue, min, max);
|
||||
}
|
||||
|
||||
public static ConditionField<String> stringField(String key, String label) {
|
||||
return new StringField(key, label, "");
|
||||
}
|
||||
|
||||
public static ConditionField<String> stringField(String key, String label, String defaultValue) {
|
||||
return new StringField(key, label, defaultValue);
|
||||
}
|
||||
|
||||
public static ConditionField<Boolean> booleanField(String key, String label, boolean defaultValue) {
|
||||
return new BoolField(key, label, defaultValue);
|
||||
}
|
||||
|
||||
public static <E extends Enum<E>> ConditionField<E> enumField(String key, String label, E defaultValue, Class<E> enumClass) {
|
||||
return new EnumField<>(key, label, defaultValue, enumClass);
|
||||
}
|
||||
|
||||
public static <E extends Enum<E>> ConditionField<E> enumField(String key, String label, E defaultValue) {
|
||||
return new EnumField<>(key, label, defaultValue, defaultValue.getDeclaringClass());
|
||||
}
|
||||
|
||||
private static class NumberField<T extends Number & Comparable<T>> extends ConditionField<T> {
|
||||
private T min;
|
||||
private T max;
|
||||
|
||||
public NumberField(String key, String label, Class<T> type, T defaultValue, T min, T max) {
|
||||
super(key, label, type, defaultValue);
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(T value) {
|
||||
if (value.compareTo(min) < 0) {
|
||||
this.value = min;
|
||||
} else if (value.compareTo(max) > 0) {
|
||||
this.value = max;
|
||||
} else {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public NumberField<T> min(T value) {
|
||||
this.min = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NumberField<T> max(T value) {
|
||||
this.max = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNBT(NBTTagCompound nbt) {
|
||||
if (value instanceof Integer) nbt.setInteger(key, (Integer) value);
|
||||
else if (value instanceof Float) nbt.setFloat(key, (Float) value);
|
||||
else if (value instanceof Double) nbt.setDouble(key, (Double) value);
|
||||
else if (value instanceof Long) nbt.setLong(key, (Long) value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void readNBT(NBTTagCompound nbt) {
|
||||
if (!nbt.hasKey(key)) return;
|
||||
T v;
|
||||
Class<?> t = type;
|
||||
if (t == Integer.class) v = (T) (Integer) nbt.getInteger(key);
|
||||
else if (t == Float.class) v = (T) (Float) nbt.getFloat(key);
|
||||
else if (t == Double.class) v = (T) (Double) nbt.getDouble(key);
|
||||
else if (t == Long.class) v = (T) (Long) nbt.getLong(key);
|
||||
else return;
|
||||
setValue(v);
|
||||
}
|
||||
}
|
||||
|
||||
private static class StringField extends ConditionField<String> {
|
||||
public StringField(String key, String label, String defaultValue) {
|
||||
super(key, label, String.class, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNBT(NBTTagCompound nbt) {
|
||||
nbt.setString(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readNBT(NBTTagCompound nbt) {
|
||||
setValue(nbt.getString(key));
|
||||
}
|
||||
}
|
||||
|
||||
private static class BoolField extends ConditionField<Boolean> {
|
||||
public BoolField(String key, String label, boolean defaultValue) {
|
||||
super(key, label, Boolean.class, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNBT(NBTTagCompound nbt) {
|
||||
nbt.setBoolean(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readNBT(NBTTagCompound nbt) {
|
||||
setValue(nbt.getBoolean(key));
|
||||
}
|
||||
}
|
||||
|
||||
private static class EnumField<E extends Enum<E>> extends ConditionField<E> {
|
||||
private final E[] options;
|
||||
|
||||
public EnumField(String key, String label, E defaultValue, Class<E> enumClass) {
|
||||
super(key, label, enumClass, defaultValue);
|
||||
this.options = enumClass.getEnumConstants();
|
||||
}
|
||||
|
||||
public E[] getOptions() {
|
||||
return options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNBT(NBTTagCompound nbt) {
|
||||
nbt.setString(key, value.name());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readNBT(NBTTagCompound nbt) {
|
||||
if (!nbt.hasKey(key)) return;
|
||||
try {
|
||||
setValue(Enum.valueOf(type, nbt.getString(key)));
|
||||
} catch (IllegalArgumentException ignored) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
import kamkeel.npcs.controllers.data.ability.conditions.AbilityCondition;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
|
||||
@@ -30,7 +31,7 @@ public interface IAbilityAction {
|
||||
|
||||
UserType getAllowedBy();
|
||||
|
||||
List<Condition> getConditions();
|
||||
List<AbilityCondition> getConditions();
|
||||
|
||||
boolean checkConditions(EntityLivingBase caster, EntityLivingBase target);
|
||||
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
package kamkeel.npcs.controllers.data.ability;
|
||||
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.LogWriter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface IAbilityCondition {
|
||||
/**
|
||||
* Check if this condition is met.
|
||||
*
|
||||
* @param caster The entity that would use the ability (NPC or Player)
|
||||
* @param target The current target (may be null for self-targeting abilities or players)
|
||||
* @return true if the condition is satisfied
|
||||
*/
|
||||
boolean check(EntityLivingBase caster, EntityLivingBase target);
|
||||
|
||||
UserType getUserType();
|
||||
|
||||
String getTypeId();
|
||||
|
||||
List<ConditionField<?>> getFields();
|
||||
|
||||
default NBTTagCompound writeNBT() {
|
||||
NBTTagCompound nbt = new NBTTagCompound();
|
||||
nbt.setInteger("userType", getUserType().ordinal());
|
||||
nbt.setString("type", getTypeId());
|
||||
for (ConditionField<?> field : getFields()) {
|
||||
field.writeNBT(nbt);
|
||||
}
|
||||
return nbt;
|
||||
}
|
||||
|
||||
default void readNBT(NBTTagCompound nbt) {
|
||||
for (ConditionField<?> field : getFields()) {
|
||||
field.readNBT(nbt);
|
||||
}
|
||||
}
|
||||
|
||||
static IAbilityCondition fromNBT(NBTTagCompound nbt) {
|
||||
String typeId = nbt.getString("type");
|
||||
Supplier<IAbilityCondition> factory = AbilityController.Instance.getConditionType(typeId);
|
||||
if (factory == null) {
|
||||
LogWriter.info("AbilityController: Unknown condition type: " + typeId);
|
||||
return null;
|
||||
}
|
||||
IAbilityCondition condition = factory.get();
|
||||
condition.readNBT(nbt);
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
class ConditionHPAbove implements IAbilityCondition {
|
||||
ConditionField<Float> threshold = ConditionField.floatField("threshold", "threshold", 0.5f);
|
||||
|
||||
public ConditionHPAbove() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check(EntityLivingBase caster, EntityLivingBase target) {
|
||||
return caster.getHealth() / caster.getMaxHealth() > threshold.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserType getUserType() {
|
||||
return UserType.BOTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypeId() {
|
||||
return "hp_above";
|
||||
}
|
||||
|
||||
public float getThreshold() {
|
||||
return threshold.getValue();
|
||||
}
|
||||
|
||||
public void setThreshold(float threshold) {
|
||||
this.threshold.setValue(threshold);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConditionField<?>> getFields() {
|
||||
return Arrays.asList(
|
||||
threshold
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package kamkeel.npcs.controllers.data.ability.conditions;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import kamkeel.npcs.controllers.AbilityController;
|
||||
import kamkeel.npcs.controllers.data.ability.UserType;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.LogWriter;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class AbilityCondition {
|
||||
protected String typeId = "";
|
||||
protected String name = "";
|
||||
protected UserType userType = UserType.BOTH;
|
||||
|
||||
/**
|
||||
* Check if this condition is met.
|
||||
*
|
||||
* @param caster The entity that would use the ability (NPC or Player)
|
||||
* @param target The current target (may be null for self-targeting abilities or players)
|
||||
* @return true if the condition is satisfied
|
||||
*/
|
||||
public abstract boolean check(EntityLivingBase caster, EntityLivingBase target);
|
||||
|
||||
public boolean requiresTarget() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public UserType getUserType() {
|
||||
return userType;
|
||||
}
|
||||
|
||||
public void setUserType(UserType userType) {
|
||||
this.userType = userType;
|
||||
}
|
||||
|
||||
public String getTypeId() {
|
||||
return typeId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public abstract List<FieldDef> getAbilityDefinitions(List<FieldDef> defs);
|
||||
|
||||
public final NBTTagCompound writeNBT() {
|
||||
NBTTagCompound nbt = new NBTTagCompound();
|
||||
nbt.setInteger("userType", getUserType().ordinal());
|
||||
nbt.setString("type", getTypeId());
|
||||
nbt.setString("name", getName());
|
||||
writeTypeNBT(nbt);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
public abstract void writeTypeNBT(NBTTagCompound nbt);
|
||||
|
||||
public abstract void readTypeNBT(NBTTagCompound nbt);
|
||||
|
||||
public final void readNBT(NBTTagCompound nbt) {
|
||||
typeId = nbt.getString("type");
|
||||
name = nbt.getString("name");
|
||||
userType = UserType.fromOrdinal(nbt.getInteger("userType"));
|
||||
readTypeNBT(nbt);
|
||||
}
|
||||
|
||||
public static AbilityCondition fromNBT(NBTTagCompound nbt) {
|
||||
String typeId = nbt.getString("type");
|
||||
Supplier<AbilityCondition> factory = AbilityController.Instance.getConditionType(typeId);
|
||||
if (factory == null) {
|
||||
LogWriter.info("AbilityController: Unknown condition type: " + typeId);
|
||||
return null;
|
||||
}
|
||||
AbilityCondition condition = factory.get();
|
||||
condition.readNBT(nbt);
|
||||
|
||||
return condition;
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
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{
|
||||
private float threshold = 0.5f; // 50%
|
||||
private ThresholdType thresholdType = ThresholdType.ABOVE;
|
||||
|
||||
public enum ThresholdType {
|
||||
ABOVE {
|
||||
@Override
|
||||
public boolean test(float value, float threshold) {
|
||||
return value > threshold;
|
||||
}
|
||||
},
|
||||
BELOW {
|
||||
@Override
|
||||
public boolean test(float value, float threshold) {
|
||||
return value < threshold;
|
||||
}
|
||||
};
|
||||
|
||||
public abstract boolean test(float value, float threshold);
|
||||
|
||||
public static ThresholdType fromOrdinal(int ordinal) {
|
||||
ThresholdType[] values = values();
|
||||
if (ordinal >= 0 && ordinal < values.length) {
|
||||
return values[ordinal];
|
||||
}
|
||||
return ABOVE;
|
||||
}
|
||||
}
|
||||
|
||||
public ConditionHPThreshold() {
|
||||
this.typeId = "condition.cnpc.hp_threshold";
|
||||
this.name = "Health Threshold";
|
||||
this.userType = UserType.NPC_ONLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check(EntityLivingBase caster, EntityLivingBase target) {
|
||||
float casterHP = caster.getHealth() / caster.getMaxHealth();
|
||||
float targetHP = target.getHealth() / target.getMaxHealth();
|
||||
|
||||
|
||||
return compare(casterHP, targetHP);
|
||||
}
|
||||
|
||||
public boolean compare(float casterHp, float targetHp) {
|
||||
boolean casterCheck = thresholdType.test(casterHp, threshold);
|
||||
boolean targetCheck = thresholdType.test(targetHp, threshold);
|
||||
|
||||
switch (getUserType()) {
|
||||
case BOTH:
|
||||
return casterCheck && targetCheck;
|
||||
case PLAYER_ONLY:
|
||||
return casterCheck;
|
||||
default:
|
||||
return targetCheck;
|
||||
}
|
||||
}
|
||||
|
||||
public float getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
|
||||
public void setThreshold(float threshold) {
|
||||
this.threshold = Math.max(0, threshold);
|
||||
}
|
||||
|
||||
public ThresholdType getThresholdType() {
|
||||
return thresholdType;
|
||||
}
|
||||
|
||||
public void setThresholdType(ThresholdType thresholdType) {
|
||||
this.thresholdType = thresholdType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FieldDef> getAbilityDefinitions(List<FieldDef> defs) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTypeNBT(NBTTagCompound nbt) {
|
||||
nbt.setFloat("threshold", threshold);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readTypeNBT(NBTTagCompound nbt) {
|
||||
threshold = nbt.getFloat("threshold");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
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 noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
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.userType = UserType.NPC_ONLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check(EntityLivingBase caster, EntityLivingBase target) {
|
||||
if (caster instanceof EntityNPCInterface) {
|
||||
EntityNPCInterface npc = (EntityNPCInterface) caster;
|
||||
if (npc.abilities != null) {
|
||||
return npc.abilities.getRecentHitCount(withinTicks) >= requiredHits;
|
||||
}
|
||||
}
|
||||
|
||||
// For players, hit count tracking is not yet supported
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getRequiredHits() {
|
||||
return requiredHits;
|
||||
}
|
||||
|
||||
public void setRequiredHits(int requiredHits) {
|
||||
this.requiredHits = Math.max(0, requiredHits);
|
||||
}
|
||||
|
||||
public int getWithinTicks() {
|
||||
return withinTicks;
|
||||
}
|
||||
|
||||
public void setWithinTicks(int withinTicks) {
|
||||
this.withinTicks = Math.max(0, withinTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FieldDef> getAbilityDefinitions(List<FieldDef> defs) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTypeNBT(NBTTagCompound nbt) {
|
||||
nbt.setInteger("requiredHits", requiredHits);
|
||||
nbt.setInteger("withinTicks", withinTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readTypeNBT(NBTTagCompound nbt) {
|
||||
requiredHits = nbt.getInteger("requiredHits");
|
||||
withinTicks = nbt.getInteger("withinTicks");
|
||||
}
|
||||
}
|
||||
@@ -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,51 @@ 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++) {
|
||||
// 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;
|
||||
// }
|
||||
//
|
||||
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 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 float getConditionThreshold(Condition cond) {
|
||||
// NBTTagCompound nbt = cond.writeNBT();
|
||||
// return nbt.hasKey("threshold") ? nbt.getFloat("threshold") : 0.5f;
|
||||
// }
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
// BUTTON EVENTS
|
||||
@@ -408,8 +408,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 (Condition c : conditions) ability.addCondition(c);
|
||||
}
|
||||
|
||||
public void loadAbility(Ability loadedAbility) {
|
||||
@@ -418,7 +418,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();
|
||||
|
||||
@@ -10,6 +10,7 @@ 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;
|
||||
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;
|
||||
@@ -22,11 +23,14 @@ 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 noppes.npcs.client.gui.util.IAbilityConfigCallback;
|
||||
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 noppes.npcs.client.gui.util.ISubGuiListener;
|
||||
import noppes.npcs.client.gui.util.ITextfieldListener;
|
||||
import noppes.npcs.client.gui.util.SubGuiInterface;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@@ -34,6 +38,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* SubGui for editing a {@link ChainedAbility}.
|
||||
* Core tabs: General, Entries, Conditions.
|
||||
@@ -89,7 +94,7 @@ public class SubGuiChainedAbilityConfig extends SubGuiInterface implements IText
|
||||
|
||||
private List<FieldDef> fieldDefs;
|
||||
private List<ChainedAbilityEntry> entries;
|
||||
private List<Condition> conditions;
|
||||
// private List<AbilityCondition> conditions;
|
||||
|
||||
// Dynamic tabs injected by field providers (e.g., "Icon")
|
||||
private List<String> extraTabs = new ArrayList<>();
|
||||
@@ -128,7 +133,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();
|
||||
|
||||
@@ -424,23 +429,23 @@ 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++) {
|
||||
// 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;
|
||||
// }
|
||||
|
||||
return y;
|
||||
}
|
||||
@@ -618,29 +623,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;
|
||||
}
|
||||
|
||||
@@ -845,14 +850,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);
|
||||
}
|
||||
}
|
||||
// Condition result = gui.getResult();
|
||||
// if (result != null && editingConditionIndex >= 0) {
|
||||
// if (editingConditionIndex < conditions.size()) {
|
||||
// conditions.set(editingConditionIndex, result);
|
||||
// } else {
|
||||
// conditions.add(result);
|
||||
// }
|
||||
// }
|
||||
editingConditionIndex = -1;
|
||||
}
|
||||
|
||||
@@ -890,10 +895,10 @@ public class SubGuiChainedAbilityConfig extends SubGuiInterface implements IText
|
||||
}
|
||||
|
||||
// Conditions
|
||||
chain.getConditions().clear();
|
||||
for (Condition c : conditions) {
|
||||
chain.getConditions().add(c);
|
||||
}
|
||||
// chain.getConditions().clear();
|
||||
// for (Condition c : conditions) {
|
||||
// chain.getConditions().add(c);
|
||||
// }
|
||||
|
||||
// Remove consumed NPC slots (descending order to preserve indices)
|
||||
if (npcSlots != null && !consumedSlotIndices.isEmpty()) {
|
||||
|
||||
Reference in new issue
Block a user