mirror of
https://github.com/KAMKEEL/CustomNPC-Plus.git
synced 2026-11-12 18:57:32 +00:00
Merge branch 'dev' of https://github.com/KAMKEEL/CustomNPC-Plus into dev
This commit is contained in:
commit
99de894d3f
14 files changed
+495
-233
No files matched your search
@@ -4,6 +4,7 @@ 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.conditions.ConditionItem;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityCharge;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityCutter;
|
||||
import kamkeel.npcs.controllers.data.ability.type.AbilityDash;
|
||||
@@ -152,6 +153,7 @@ public class AbilityController implements IAbilityHandler {
|
||||
private void registerBuiltinConditionTypes() {
|
||||
registerCondition(ConditionHPThreshold::new);
|
||||
registerCondition(ConditionHitCount::new);
|
||||
registerCondition(ConditionItem::new);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════════
|
||||
|
||||
+3
-1
@@ -14,6 +14,8 @@ import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class AbilityCondition {
|
||||
public static final int MAX_CONDITIONS = 5;
|
||||
|
||||
protected String typeId = "";
|
||||
protected String name = "";
|
||||
protected UserType userType = UserType.BOTH;
|
||||
@@ -69,7 +71,7 @@ public abstract class AbilityCondition {
|
||||
nbt.setString("typeId", getTypeId());
|
||||
nbt.setString("name", getName());
|
||||
nbt.setInteger("userType", getUserType().ordinal());
|
||||
nbt.setInteger("filter", getUserType().ordinal());
|
||||
nbt.setInteger("filter", getFilter().ordinal());
|
||||
writeTypeNBT(nbt);
|
||||
return nbt;
|
||||
}
|
||||
|
||||
+35
-17
@@ -8,19 +8,26 @@ import java.util.List;
|
||||
|
||||
public class ConditionHPThreshold extends AbilityCondition{
|
||||
private float threshold = 0.5f; // 50%
|
||||
private boolean percent = true;
|
||||
private ThresholdType thresholdType = ThresholdType.ABOVE;
|
||||
|
||||
public enum ThresholdType {
|
||||
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;
|
||||
}
|
||||
},
|
||||
EQUAL {
|
||||
@Override
|
||||
public boolean test(float value, float threshold) {
|
||||
return value == threshold;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -41,6 +48,8 @@ public class ConditionHPThreshold extends AbilityCondition{
|
||||
return "condition.hp_above";
|
||||
case BELOW:
|
||||
return "condition.hp_below";
|
||||
case EQUAL:
|
||||
return "condition.hp_equal";
|
||||
default:
|
||||
return name();
|
||||
}
|
||||
@@ -54,8 +63,8 @@ public class ConditionHPThreshold extends AbilityCondition{
|
||||
|
||||
@Override
|
||||
public boolean check(EntityLivingBase caster, EntityLivingBase target) {
|
||||
float casterHP = caster.getHealth() / caster.getMaxHealth();
|
||||
float targetHP = target.getHealth() / target.getMaxHealth();
|
||||
float casterHP = isPercent() ? caster.getHealth() / caster.getMaxHealth() : caster.getHealth();
|
||||
float targetHP = isPercent() ? target.getHealth() / target.getMaxHealth() : target.getHealth();
|
||||
|
||||
|
||||
return compare(casterHP, targetHP);
|
||||
@@ -75,6 +84,24 @@ public class ConditionHPThreshold extends AbilityCondition{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getConditionDefinitions(List<FieldDef> defs) {
|
||||
defs.add(FieldDef.floatField("condition.threshold", this::getThreshold, this::setThreshold).min(0));
|
||||
defs.add(FieldDef.boolField("condition.percent", this::isPercent, this::setIsPercent));
|
||||
defs.add(FieldDef.enumField("condition.threshold_type", ThresholdType.class,
|
||||
this::getThresholdType, this::setThresholdType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTypeNBT(NBTTagCompound nbt) {
|
||||
nbt.setFloat("threshold", threshold);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readTypeNBT(NBTTagCompound nbt) {
|
||||
threshold = nbt.getFloat("threshold");
|
||||
}
|
||||
|
||||
public float getThreshold() {
|
||||
return threshold;
|
||||
}
|
||||
@@ -91,20 +118,11 @@ public class ConditionHPThreshold extends AbilityCondition{
|
||||
this.thresholdType = thresholdType;
|
||||
}
|
||||
|
||||
@Override
|
||||
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));
|
||||
public boolean isPercent() {
|
||||
return percent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTypeNBT(NBTTagCompound nbt) {
|
||||
nbt.setFloat("threshold", threshold);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readTypeNBT(NBTTagCompound nbt) {
|
||||
threshold = nbt.getFloat("threshold");
|
||||
public void setIsPercent(boolean percent) {
|
||||
this.percent = percent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package kamkeel.npcs.controllers.data.ability.conditions;
|
||||
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import noppes.npcs.client.gui.builder.FieldDef;
|
||||
import noppes.npcs.entity.EntityNPCInterface;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ConditionItem extends AbilityCondition {
|
||||
|
||||
public enum UsageType {
|
||||
ARMOR, HOLDING, AMMO, OFFHAND;
|
||||
|
||||
public static UsageType fromOrdinal(int ordinal) {
|
||||
UsageType[] values = values();
|
||||
return (ordinal >= 0 && ordinal < values.length) ? values[ordinal] : HOLDING;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ArmorSlot {
|
||||
BOOTS, LEGS, CHEST, HELMET;
|
||||
|
||||
public static ArmorSlot fromOrdinal(int ordinal) {
|
||||
ArmorSlot[] values = values();
|
||||
return (ordinal >= 0 && ordinal < values.length) ? values[ordinal] : BOOTS;
|
||||
}
|
||||
}
|
||||
|
||||
// Shared
|
||||
private UsageType usageType = UsageType.HOLDING;
|
||||
private String itemName = "";
|
||||
|
||||
// ARMOR only
|
||||
private ArmorSlot armorSlot = ArmorSlot.BOOTS;
|
||||
private boolean fullArmorSet = false;
|
||||
|
||||
// AMMO + PLAYER only
|
||||
private int requiredCount = 1;
|
||||
|
||||
public ConditionItem() {
|
||||
this.typeId = "condition.cnpc.item";
|
||||
this.name = "condition.item";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean check(EntityLivingBase caster, EntityLivingBase target) {
|
||||
switch (getFilter()) {
|
||||
case CASTER:
|
||||
return checkEntity(caster);
|
||||
case TARGET:
|
||||
return target != null && checkEntity(target);
|
||||
case BOTH:
|
||||
return checkEntity(caster) && (target != null && checkEntity(target));
|
||||
default:
|
||||
return checkEntity(caster);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkEntity(EntityLivingBase entity) {
|
||||
switch (usageType) {
|
||||
case HOLDING:
|
||||
return checkHolding(entity);
|
||||
case ARMOR:
|
||||
return checkArmor(entity);
|
||||
case AMMO:
|
||||
return checkAmmo(entity);
|
||||
case OFFHAND:
|
||||
return checkOffhand(entity);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkHolding(EntityLivingBase entity) {
|
||||
ItemStack held = entity.getHeldItem();
|
||||
return matchesItem(held);
|
||||
}
|
||||
|
||||
private boolean checkArmor(EntityLivingBase entity) {
|
||||
// MC getEquipmentInSlot: 1=boots, 2=legs, 3=chest, 4=helmet
|
||||
int slot = armorSlot.ordinal() + 1; // BOOTS=0, LEGS=1, CHEST=2, HELMET=3
|
||||
return matchesItem(entity.getEquipmentInSlot(slot));
|
||||
}
|
||||
|
||||
private boolean checkFullArmor(EntityLivingBase entity) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int slot = i + 1;
|
||||
if (!matchesItem(i, entity.getEquipmentInSlot(slot)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkAmmo(EntityLivingBase entity) {
|
||||
if (entity instanceof EntityPlayer) {
|
||||
return checkPlayerInventoryCount((EntityPlayer) entity);
|
||||
}
|
||||
if (entity instanceof EntityNPCInterface) {
|
||||
return checkNPCProjectile((EntityNPCInterface) entity);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkOffhand(EntityLivingBase entity) {
|
||||
// No offhand for players
|
||||
if (entity instanceof EntityPlayer) return false;
|
||||
|
||||
ItemStack item = ((EntityNPCInterface) entity).getOffHand();
|
||||
return matchesItem(item);
|
||||
}
|
||||
|
||||
private boolean checkPlayerInventoryCount(EntityPlayer player) {
|
||||
int count = 0;
|
||||
for (ItemStack stack : player.inventory.mainInventory) {
|
||||
if (matchesItem(stack)) {
|
||||
count += stack.stackSize;
|
||||
}
|
||||
}
|
||||
return count >= requiredCount;
|
||||
}
|
||||
|
||||
private boolean checkNPCProjectile(EntityNPCInterface npc) {
|
||||
ItemStack projectile = npc.inventory.getProjectile();
|
||||
return matchesItem(projectile);
|
||||
}
|
||||
|
||||
private boolean matchesItem(ItemStack stack) {
|
||||
return matchesItem(0, stack);
|
||||
}
|
||||
|
||||
private boolean matchesItem(int index, ItemStack stack) {
|
||||
if (stack == null || itemName == null || itemName.isEmpty()) return false;
|
||||
String registryName = net.minecraft.item.Item.itemRegistry.getNameForObject(stack.getItem());
|
||||
return itemName.equals(registryName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getConditionDefinitions(List<FieldDef> defs) {
|
||||
defs.add(FieldDef.enumField("condition.usage_type", UsageType.class,
|
||||
this::getUsageType, this::setUsageType));
|
||||
|
||||
defs.add(FieldDef.stringField("condition.item_name",
|
||||
this::getItemName, this::setItemName));
|
||||
// .hover("condition.hover.item_name"));
|
||||
|
||||
|
||||
|
||||
defs.add(FieldDef.enumField("condition.armor_slot", ArmorSlot.class,
|
||||
this::getArmorSlot, this::setArmorSlot)
|
||||
.visibleWhen(() -> usageType == UsageType.ARMOR));
|
||||
// .hover("condition.hover.armor_slots"));
|
||||
|
||||
defs.add(FieldDef.intField("condition.item_count",
|
||||
this::getRequiredCount, this::setRequiredCount)
|
||||
.range(1, 64)
|
||||
.visibleWhen(() -> usageType == UsageType.AMMO && userType.allowsPlayer()));
|
||||
// .hover("condition.hover.required_count"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTypeNBT(NBTTagCompound nbt) {
|
||||
nbt.setString("itemName", itemName);
|
||||
nbt.setInteger("usageType", usageType.ordinal());
|
||||
nbt.setInteger("armorSlot", armorSlot.ordinal());
|
||||
nbt.setInteger("requiredCount", requiredCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readTypeNBT(NBTTagCompound nbt) {
|
||||
itemName = nbt.getString("itemName");
|
||||
usageType = UsageType.fromOrdinal(nbt.getInteger("usageType"));
|
||||
armorSlot = ArmorSlot.fromOrdinal(nbt.getInteger("armorSlot"));
|
||||
requiredCount = nbt.getInteger("requiredCount");
|
||||
}
|
||||
|
||||
|
||||
public UsageType getUsageType() { return usageType; }
|
||||
public void setUsageType(UsageType usageType) { this.usageType = usageType; }
|
||||
|
||||
public String getItemName() { return itemName; }
|
||||
public void setItemName(String itemName) { this.itemName = itemName; }
|
||||
|
||||
public ArmorSlot getArmorSlot() { return armorSlot; }
|
||||
public void setArmorSlot(ArmorSlot armorSlot) { this.armorSlot = armorSlot; }
|
||||
|
||||
public boolean isFullArmorSet() {
|
||||
return fullArmorSet;
|
||||
}
|
||||
|
||||
public void setFullArmorSet(boolean fullArmorSet) {
|
||||
this.fullArmorSet = fullArmorSet;
|
||||
}
|
||||
|
||||
public int getRequiredCount() { return requiredCount; }
|
||||
public void setRequiredCount(int requiredCount) { this.requiredCount = Math.max(1, requiredCount); }
|
||||
}
|
||||
@@ -52,7 +52,7 @@ public class AbilityCharge extends AbilityMovement implements IAbilityCharge {
|
||||
this.windUpSound = "mob.zombie.wood";
|
||||
this.activeSound = "mob.zombie.attack";
|
||||
this.windUpAnimationName = "Ability_Charge_Windup";
|
||||
this.activeAnimationName = "Ability_Active_Windup";
|
||||
this.activeAnimationName = "Ability_Charge_Active";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -48,8 +48,8 @@ public class AbilityBeam extends AbilityEnergyProjectile<EntityAbilityBeam> impl
|
||||
this.cooldownTicks = 0;
|
||||
this.windUpTicks = 40;
|
||||
this.lockMovement = LockMovementType.WINDUP_AND_ACTIVE;
|
||||
this.rotationMode = RotationMode.TRACK;
|
||||
this.rotationPhase = LockMovementType.WINDUP_AND_ACTIVE;
|
||||
this.rotationMode = RotationMode.LOCKED;
|
||||
this.rotationPhase = LockMovementType.ACTIVE;
|
||||
this.telegraphType = TelegraphType.CIRCLE;
|
||||
this.showTelegraph = true;
|
||||
this.windUpAnimationName = "Ability_Beam_Windup";
|
||||
|
||||
@@ -115,6 +115,9 @@ public class AbilityOrb extends AbilityEnergyProjectile<EntityAbilityOrb> implem
|
||||
orb.setDamage(4.0f);
|
||||
orb.setKnockback(0.0f);
|
||||
orb.setKnockbackUp(0.0f);
|
||||
orb.setProjectileCount(2);
|
||||
orb.setFireDelay(2);
|
||||
a.setLockMovement(LockMovementType.WINDUP_AND_ACTIVE);
|
||||
a.setMaxRange(75.0f);
|
||||
a.setBurstEnabled(true);
|
||||
a.setBurstAmount(15);
|
||||
|
||||
@@ -20,6 +20,8 @@ import noppes.npcs.client.gui.util.SubGuiInterface;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static kamkeel.npcs.controllers.data.ability.conditions.AbilityCondition.MAX_CONDITIONS;
|
||||
|
||||
public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldListener, ISubGuiListener {
|
||||
|
||||
private static final int DECLARATIVE_ID_START = 1000;
|
||||
@@ -42,6 +44,12 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi
|
||||
private static final int L_LABEL_X = 5;
|
||||
private static final int ROW_H = 24;
|
||||
|
||||
// Condition buttons
|
||||
private static final int COND_BASE = 50;
|
||||
private static final int COND_STRIDE = 10;
|
||||
private static final int COND_END = COND_BASE + MAX_CONDITIONS * COND_STRIDE; // 50 + N*10
|
||||
private static final int BTN_ADD_COND = COND_END;
|
||||
|
||||
private final Ability ability;
|
||||
private final IAbilityConfigCallback callback;
|
||||
private int activeTab = TAB_GENERAL;
|
||||
@@ -234,17 +242,17 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi
|
||||
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++) {
|
||||
for (int i = 0; i < conditions.size() && i < MAX_CONDITIONS; 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"));
|
||||
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(80, L_LABEL_X, y, 50, 20, "gui.add"));
|
||||
if (conditions.size() < MAX_CONDITIONS) {
|
||||
sw.addButton(new GuiNpcButton(BTN_ADD_COND, L_LABEL_X, y, 50, 20, "gui.add"));;
|
||||
y += ROW_H;
|
||||
}
|
||||
|
||||
@@ -312,9 +320,9 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi
|
||||
}
|
||||
|
||||
private boolean handleConditionButton(int id) {
|
||||
if (id >= 50 && id < 80) {
|
||||
int condIndex = (id - 50) / 10;
|
||||
int action = (id - 50) % 10;
|
||||
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;
|
||||
@@ -328,8 +336,8 @@ public class SubGuiAbilityConfig extends SubGuiInterface implements ITextfieldLi
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (id == 80) {
|
||||
if (conditions.size() < 3) {
|
||||
if (id == BTN_ADD_COND) {
|
||||
if (conditions.size() < MAX_CONDITIONS) {
|
||||
editingConditionIndex = conditions.size();
|
||||
setSubGui(new SubGuiConditionEdit(null));
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static kamkeel.npcs.controllers.data.ability.conditions.AbilityCondition.MAX_CONDITIONS;
|
||||
|
||||
/**
|
||||
* SubGui for editing a {@link ChainedAbility}.
|
||||
@@ -70,9 +71,9 @@ public class SubGuiChainedAbilityConfig extends SubGuiInterface implements IText
|
||||
// Actual ID = COND_BASE + i * COND_STRIDE + offset
|
||||
// offset 0 = name/click, 1 = edit, 2 = delete
|
||||
private static final int COND_BASE = 50;
|
||||
private static final int COND_END = 80;
|
||||
private static final int COND_STRIDE = 10;
|
||||
private static final int BTN_ADD_COND = 80;
|
||||
private static final int COND_END = COND_BASE + MAX_CONDITIONS * COND_STRIDE; // 50 + N*10
|
||||
private static final int BTN_ADD_COND = COND_END;
|
||||
|
||||
// ── Layout constants ──────────────────────────────────────────────────────
|
||||
private static final int L_LABEL_X = 5;
|
||||
@@ -427,7 +428,7 @@ public class SubGuiChainedAbilityConfig extends SubGuiInterface implements IText
|
||||
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++) {
|
||||
for (int i = 0; i < conditions.size() && i < MAX_CONDITIONS; 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));
|
||||
@@ -436,7 +437,7 @@ public class SubGuiChainedAbilityConfig extends SubGuiInterface implements IText
|
||||
y += 22;
|
||||
}
|
||||
|
||||
if (conditions.size() < 3) {
|
||||
if (conditions.size() < MAX_CONDITIONS) {
|
||||
sw.addButton(new GuiNpcButton(BTN_ADD_COND, L_LABEL_X, y, 50, 20, "gui.add"));
|
||||
y += ROW_H;
|
||||
}
|
||||
@@ -615,7 +616,7 @@ public class SubGuiChainedAbilityConfig extends SubGuiInterface implements IText
|
||||
return true;
|
||||
}
|
||||
if (id == BTN_ADD_COND) {
|
||||
if (conditions.size() < 3) {
|
||||
if (conditions.size() < MAX_CONDITIONS) {
|
||||
editingConditionIndex = conditions.size();
|
||||
setSubGui(new SubGuiConditionEdit(null));
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import net.minecraft.util.DamageSource;
|
||||
import noppes.npcs.AbstractDataAbilities;
|
||||
import noppes.npcs.EventHooks;
|
||||
import noppes.npcs.LogWriter;
|
||||
import noppes.npcs.NoppesUtilPlayer;
|
||||
import noppes.npcs.api.ability.IPlayerAbilityData;
|
||||
import noppes.npcs.api.entity.IPlayer;
|
||||
import noppes.npcs.controllers.ScriptController;
|
||||
@@ -297,6 +298,7 @@ public class PlayerAbilityData extends AbstractDataAbilities implements IPlayerA
|
||||
// Apply rotation and position locks after ability tick
|
||||
applyRotationControl(player);
|
||||
applyPositionLock(player);
|
||||
applyAnimationRotationSync(player);
|
||||
|
||||
// Sync lock state to client (only sends when flags change)
|
||||
syncAbilityStateIfNeeded(player);
|
||||
@@ -844,6 +846,17 @@ public class PlayerAbilityData extends AbstractDataAbilities implements IPlayerA
|
||||
}
|
||||
}
|
||||
|
||||
private void applyAnimationRotationSync(EntityPlayer player) {
|
||||
if (rotationLocked || currentAbility == null) return;
|
||||
if (currentAbility.getPhase() == AbilityPhase.IDLE || currentAbility.getPhase() == AbilityPhase.DAZED)
|
||||
return;
|
||||
|
||||
// TODO This is a temporary duct-tape solution to fix the animation not rotating with head rotation
|
||||
if (!currentAbility.isRotationLockedForCurrentPhase() && player instanceof EntityPlayerMP) {
|
||||
NoppesUtilPlayer.swingPlayerArm((EntityPlayerMP) player);
|
||||
}
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
// POSITION LOCKING (Player-specific application)
|
||||
// ═══════════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in new issue
Block a user