Files
CustomNPC-Plus/src/main/java/noppes/npcs/scripted/wrapper/ScriptDataAbilities.java
T
KamandClaude Opus 4.6 0311dc5806 Merge upstream dev: name-based storage, UUID/DisplayName, toggle system
Resolved conflicts in AbstractDataAbilities, DataAbilities, PlayerAbilityData
to integrate both toggle system (upstream) and chain delay tracking (local).
ChainedAbility now has UUID and DisplayName fields matching Ability pattern.
ChainedAbilityController rewritten: saves in abilities/chained/, dual-index
by name and UUID, legacy migration from chained_abilities/ directory.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 23:27:49 -05:00

219 lines
6.3 KiB
Java

package noppes.npcs.scripted.wrapper;
import kamkeel.npcs.controllers.data.ability.Ability;
import kamkeel.npcs.controllers.data.ability.AbilityController;
import kamkeel.npcs.controllers.data.ability.AbilityAction;
import net.minecraft.entity.EntityLivingBase;
import noppes.npcs.DataAbilities;
import noppes.npcs.api.ability.IAbility;
import noppes.npcs.api.ability.IDataAbilities;
import noppes.npcs.entity.EntityNPCInterface;
import java.util.List;
/**
* Script wrapper for DataAbilities providing API access to NPC abilities.
*/
public class ScriptDataAbilities implements IDataAbilities {
private final DataAbilities data;
private final EntityNPCInterface npc;
public ScriptDataAbilities(EntityNPCInterface npc) {
this.npc = npc;
this.data = npc.abilities;
}
@Override
public boolean isEnabled() {
return data.enabled;
}
@Override
public void setEnabled(boolean enabled) {
data.enabled = enabled;
}
@Override
public IAbility[] getAbilities() {
return data.getAbilities().toArray(new IAbility[0]);
}
@Override
public void addAbility(IAbility ability) {
if (ability instanceof Ability) {
Ability a = (Ability) ability;
// Validate ability allows NPCs
if (!a.getAllowedBy().allowsNpc()) {
return; // Ability is PLAYER_ONLY
}
data.addAbility(a);
}
}
@Override
public void addAbilityReference(String key) {
// Validate ability exists and allows NPCs
Ability ability = AbilityController.Instance.resolveAbility(key);
if (ability == null) {
return; // Ability doesn't exist
}
if (!ability.getAllowedBy().allowsNpc()) {
return; // Ability is PLAYER_ONLY
}
// Store by UUID/registry key for stable reference
String canonicalKey = ability.getId() != null ? ability.getId() : key;
data.addAbilityReference(canonicalKey);
}
@Override
public void removeAbility(String abilityId) {
data.removeAbility(abilityId);
}
@Override
public IAbility getAbility(String abilityId) {
return data.getAbility(abilityId);
}
@Override
public boolean hasAbility(String abilityId) {
return data.getAbility(abilityId) != null;
}
@Override
public boolean isAbilityReference(String abilityId) {
List<AbilityAction> slots = data.getAbilityActions();
for (int i = 0; i < slots.size(); i++) {
AbilityAction slot = slots.get(i);
if (slot.isAbilityReference()) {
if (slot.getReferenceId().equals(abilityId)) return true;
} else if (!slot.isReference()) {
Ability a = slot.getAbility();
if (a != null && a.getId().equals(abilityId)) return false;
}
}
return false;
}
@Override
public boolean convertToInline(String abilityId) {
List<AbilityAction> slots = data.getAbilityActions();
for (int i = 0; i < slots.size(); i++) {
AbilityAction slot = slots.get(i);
if (slot.isAbilityReference() && slot.getReferenceId().equals(abilityId)) {
return data.convertToInline(i);
}
}
return false;
}
@Override
public void clearAbilities() {
data.clearAbilities();
}
@Override
public IAbility getCurrentAbility() {
return data.getCurrentAbility();
}
@Override
public boolean isExecutingAbility() {
return data.isExecutingAbility();
}
@Override
public void interruptCurrentAbility() {
data.interruptCurrentAbility(null, 0);
}
@Override
public int getGlobalCooldown() {
return (int) data.getRemainingCooldown();
}
@Override
public void setGlobalCooldown(int ticks) {
// Set the cooldown by manipulating the internal cooldown end time
// Not directly exposed, but we can reset and let it tick down
data.resetCooldown();
// This is a best-effort implementation
}
@Override
public void resetCooldowns() {
data.resetCooldown();
}
@Override
public boolean forceStartAbility(String abilityId) {
return forceStartAbility(abilityId, null);
}
@Override
public boolean forceStartAbility(String abilityId, Object target) {
// Find the ability
Ability ability = data.getAbility(abilityId);
if (ability == null) {
return false;
}
// Resolve target
EntityLivingBase targetEntity = resolveTarget(target);
// Use the direct force start method
return data.forceStartAbility(ability, targetEntity);
}
@Override
public boolean executeAbility(String key) {
return executeAbility(key, null);
}
@Override
public boolean executeAbility(String key, Object target) {
// Validate ability exists and allows NPCs
Ability ability = AbilityController.Instance.resolveAbility(key);
if (ability == null) {
return false; // Ability doesn't exist
}
if (!ability.getAllowedBy().allowsNpc()) {
return false; // Ability is PLAYER_ONLY
}
EntityLivingBase targetEntity = resolveTarget(target);
return data.executeAbility(key, targetEntity);
}
@Override
public IAbility createAbility(String typeId) {
if (AbilityController.Instance == null) {
return null;
}
return AbilityController.Instance.create(typeId);
}
/**
* Resolve a target object to an EntityLivingBase.
*/
private EntityLivingBase resolveTarget(Object target) {
if (target == null) {
// Try to use the NPC's current attack target
return npc.getAttackTarget();
}
if (target instanceof EntityLivingBase) {
return (EntityLivingBase) target;
}
if (target instanceof noppes.npcs.api.entity.IEntityLivingBase) {
Object mcEntity = ((noppes.npcs.api.entity.IEntityLivingBase<?>) target).getMCEntity();
if (mcEntity instanceof EntityLivingBase) {
return (EntityLivingBase) mcEntity;
}
}
return null;
}
}