Add anchor offset methods and update ability variant selection UI

This commit is contained in:
Kam committed 2026-02-06 22:43:07 -05:00
1 parent 74cae17ebd
commit 4c5e44fb22
7 files changed
+134 -36

No files matched your search

@@ -13,6 +13,7 @@ import java.util.function.Consumer;
public class AbilityVariant {
private final String displayKey;
private final String group;
private final Consumer<Ability> configurator;
/**
@@ -20,7 +21,17 @@ public class AbilityVariant {
* @param configurator Lambda that configures the ability with preset values
*/
public AbilityVariant(String displayKey, Consumer<Ability> configurator) {
this(displayKey, null, configurator);
}
/**
* @param displayKey Lang key for the variant display name
* @param group Optional group header shown in the variant selection GUI (e.g., "DBC Addon")
* @param configurator Lambda that configures the ability with preset values
*/
public AbilityVariant(String displayKey, String group, Consumer<Ability> configurator) {
this.displayKey = displayKey;
this.group = group;
this.configurator = configurator;
}
@@ -28,6 +39,10 @@ public class AbilityVariant {
return displayKey;
}
public String getGroup() {
return group;
}
/**
* Apply this variant's preset configuration to the given ability.
*/
@@ -521,6 +521,9 @@ public class AbilityBeam extends Ability implements IAbilityEnergyBeam {
public int getAnchorPoint(int index) { return projectiles[clampIndex(index)].anchor.anchorPoint.ordinal(); }
public void setAnchorPoint(int index, int point) { projectiles[clampIndex(index)].anchor.anchorPoint = AnchorPoint.fromOrdinal(point); }
public void setAnchorOffsetX(int index, float offset) { projectiles[clampIndex(index)].anchor.anchorOffsetX = offset; }
public void setAnchorOffsetY(int index, float offset) { projectiles[clampIndex(index)].anchor.anchorOffsetY = offset; }
public void setAnchorOffsetZ(int index, float offset) { projectiles[clampIndex(index)].anchor.anchorOffsetZ = offset; }
private int clampIndex(int index) {
return Math.max(0, Math.min(index, projectileCount - 1));
@@ -551,6 +551,9 @@ public class AbilityDisc extends Ability implements IAbilityDisc {
public int getAnchorPoint(int index) { return projectiles[clampIndex(index)].anchor.anchorPoint.ordinal(); }
public void setAnchorPoint(int index, int point) { projectiles[clampIndex(index)].anchor.anchorPoint = AnchorPoint.fromOrdinal(point); }
public void setAnchorOffsetX(int index, float offset) { projectiles[clampIndex(index)].anchor.anchorOffsetX = offset; }
public void setAnchorOffsetY(int index, float offset) { projectiles[clampIndex(index)].anchor.anchorOffsetY = offset; }
public void setAnchorOffsetZ(int index, float offset) { projectiles[clampIndex(index)].anchor.anchorOffsetZ = offset; }
private int clampIndex(int index) {
return Math.max(0, Math.min(index, projectileCount - 1));
@@ -536,6 +536,9 @@ public class AbilityOrb extends Ability implements IAbilityOrb {
public int getAnchorPoint(int index) { return projectiles[clampIndex(index)].anchor.anchorPoint.ordinal(); }
public void setAnchorPoint(int index, int point) { projectiles[clampIndex(index)].anchor.anchorPoint = AnchorPoint.fromOrdinal(point); }
public void setAnchorOffsetX(int index, float offset) { projectiles[clampIndex(index)].anchor.anchorOffsetX = offset; }
public void setAnchorOffsetY(int index, float offset) { projectiles[clampIndex(index)].anchor.anchorOffsetY = offset; }
public void setAnchorOffsetZ(int index, float offset) { projectiles[clampIndex(index)].anchor.anchorOffsetZ = offset; }
private int clampIndex(int index) {
return Math.max(0, Math.min(index, projectileCount - 1));
@@ -29,7 +29,8 @@ public class Register<T> {
public static boolean isEmpty(String registryKey) {
if (REGISTERED_NAMESPACES.isEmpty()) return true;
if (REGISTERED_NAMESPACES.get(registryKey).isEmpty()) return true;
List<String> list = REGISTERED_NAMESPACES.get(registryKey);
if (list == null || list.isEmpty()) return true;
return false;
}
@@ -2,10 +2,10 @@ package noppes.npcs.client.gui.advanced;
import kamkeel.npcs.controllers.data.ability.AbilityVariant;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.util.StatCollector;
import noppes.npcs.client.gui.util.GuiCustomScroll;
import noppes.npcs.client.gui.util.GuiNpcButton;
import noppes.npcs.client.gui.util.GuiNpcLabel;
import noppes.npcs.client.gui.util.GuiScrollWindow;
import noppes.npcs.client.gui.util.ICustomScrollListener;
import noppes.npcs.client.gui.util.SubGuiInterface;
import java.util.ArrayList;
@@ -13,23 +13,18 @@ import java.util.List;
/**
* SubGui for selecting a variant/template when creating a new ability.
* Uses a scroll window so external mods can register many variants.
* Uses a scroll list with group headers for external addon variants.
*/
public class SubGuiAbilityVariantSelect extends SubGuiInterface {
private static final int VARIANT_BTN_START = 10;
private static final int BTN_H = 20;
private static final int BTN_PAD = 2;
public class SubGuiAbilityVariantSelect extends SubGuiInterface implements ICustomScrollListener {
private final List<AbilityVariant> variants;
private final List<String> displayNames = new ArrayList<>();
private int selectedIndex = -1;
// Maps each scroll list index to a variant list index (-1 for non-selectable entries)
private final List<Integer> scrollToVariantIndex = new ArrayList<>();
public SubGuiAbilityVariantSelect(List<AbilityVariant> variants) {
this.variants = variants;
for (AbilityVariant variant : variants) {
displayNames.add(StatCollector.translateToLocal(variant.getDisplayKey()));
}
setBackground("menubg.png");
xSize = 200;
ySize = 216;
@@ -41,26 +36,78 @@ public class SubGuiAbilityVariantSelect extends SubGuiInterface {
addLabel(new GuiNpcLabel(0, "ability.selectVariant", guiLeft + 10, guiTop + 8));
// Scroll window for variant buttons
int swX = guiLeft + 5;
int swY = guiTop + 22;
int swW = 190;
int swH = 155;
// Build the unsorted scroll list with group headers
List<String> scrollList = new ArrayList<>();
scrollToVariantIndex.clear();
GuiScrollWindow sw = new GuiScrollWindow(this, swX, swY, swW, swH, 0);
addScrollableGui(0, sw); // Must register BEFORE adding components (initGui clears them)
boolean hasBaseVariants = false;
boolean hasGroupedVariants = false;
int localY = 2;
int btnW = swW - 14; // Leave room for scrollbar
for (int i = 0; i < displayNames.size(); i++) {
GuiNpcButton btn = new GuiNpcButton(VARIANT_BTN_START + i, 2, localY, btnW, BTN_H, displayNames.get(i));
if (i == selectedIndex) {
btn.packedFGColour = 0x55FF55;
}
sw.addButton(btn);
localY += BTN_H + BTN_PAD;
for (AbilityVariant v : variants) {
if (v.getGroup() == null)
hasBaseVariants = true;
else
hasGroupedVariants = true;
}
sw.maxScrollY = Math.max(localY - swH, 0);
// Add base (non-grouped) variants first
for (int i = 0; i < variants.size(); i++) {
if (variants.get(i).getGroup() == null) {
scrollList.add(variants.get(i).getDisplayKey());
scrollToVariantIndex.add(i);
}
}
// Blank separator between base and grouped variants
if (hasBaseVariants && hasGroupedVariants) {
scrollList.add("");
scrollToVariantIndex.add(-1);
}
// Add grouped variants with group headers
String lastGroup = null;
for (int i = 0; i < variants.size(); i++) {
AbilityVariant v = variants.get(i);
if (v.getGroup() == null)
continue;
if (!v.getGroup().equals(lastGroup)) {
scrollList.add(v.getGroup());
scrollToVariantIndex.add(-1);
lastGroup = v.getGroup();
}
scrollList.add(v.getDisplayKey());
scrollToVariantIndex.add(i);
}
GuiCustomScroll scroll = new GuiCustomScroll(this, 0);
scroll.guiLeft = guiLeft + 5;
scroll.guiTop = guiTop + 22;
scroll.setUnsortedList(scrollList);
scroll.setSize(190, 155);
// Mark blank separators and group headers as non-interactive colored entries
scroll.colors.put("", 0x000000);
if (lastGroup != null) {
for (int i = 0; i < variants.size(); i++) {
String group = variants.get(i).getGroup();
if (group != null)
scroll.colors.put(group, 0xFFFF00); // Yellow
}
}
// Restore selection in scroll
if (selectedIndex >= 0) {
for (int s = 0; s < scrollToVariantIndex.size(); s++) {
if (scrollToVariantIndex.get(s) == selectedIndex) {
scroll.selected = s;
break;
}
}
}
addScroll(scroll);
// Select / Cancel buttons
addButton(new GuiNpcButton(0, guiLeft + 5, guiTop + 188, 90, 20, "gui.select"));
@@ -68,6 +115,24 @@ public class SubGuiAbilityVariantSelect extends SubGuiInterface {
addButton(new GuiNpcButton(1, guiLeft + 105, guiTop + 188, 90, 20, "gui.cancel"));
}
@Override
public void customScrollClicked(int i, int j, int k, GuiCustomScroll scroll) {
if (scroll.id == 0 && scroll.selected >= 0 && scroll.selected < scrollToVariantIndex.size()) {
int variantIdx = scrollToVariantIndex.get(scroll.selected);
if (variantIdx >= 0) {
selectedIndex = variantIdx;
getButton(0).setEnabled(true);
}
}
}
@Override
public void customScrollDoubleClicked(String selection, GuiCustomScroll scroll) {
if (selectedIndex >= 0) {
close();
}
}
@Override
public void buttonEvent(GuiButton guibutton) {
int id = guibutton.id;
@@ -76,9 +141,6 @@ public class SubGuiAbilityVariantSelect extends SubGuiInterface {
} else if (id == 1) {
selectedIndex = -1;
close();
} else if (id >= VARIANT_BTN_START && id < VARIANT_BTN_START + displayNames.size()) {
selectedIndex = id - VARIANT_BTN_START;
initGui();
}
}
@@ -200,7 +200,8 @@ public class GuiCustomScroll extends GuiScreen {
int k = (14 * i + 4) - scrollY;
if (k >= 4 && k + 12 < ySize) {
int xOffset = scrollHeight < ySize - 8 ? 0 : 10;
String displayString = StatCollector.translateToLocal(list.get(i));
String rawEntry = list.get(i);
String displayString = StatCollector.translateToLocal(rawEntry);
String text = "";
float maxWidth = (xSize + xOffset - 8) * 0.8f;
@@ -215,7 +216,13 @@ public class GuiCustomScroll extends GuiScreen {
text += "...";
} else
text = displayString;
if ((multipleSelection && selectedList.contains(text)) || (!multipleSelection && selected == i)) {
// Entries with a custom color are non-interactive (headers/separators)
Integer customColor = colors.get(rawEntry);
if (customColor != null) {
if (!text.isEmpty())
fontRendererObj.drawString(text, j, k, customColor);
} else if ((multipleSelection && selectedList.contains(text)) || (!multipleSelection && selected == i)) {
drawVerticalLine(j - 2, k - 4, k + 10, 0xffffffff);
drawVerticalLine(j + xSize - 18 + xOffset, k - 4, k + 10, 0xffffffff);
drawHorizontalLine(j - 2, j + xSize - 18 + xOffset, k - 3, 0xffffffff);
@@ -239,13 +246,17 @@ public class GuiCustomScroll extends GuiScreen {
private int getMouseOver(int i, int j) {
i -= guiLeft;
j -= guiTop;
//fontRenderer.drawString(".", i , j, 0xffffff);
if (i >= 4 && i < xSize - 4 && j >= 4 && j < ySize) {
for (int j1 = 0; j1 < list.size(); j1++) {
if (!mouseInOption(i, j, j1)) {
continue;
}
// Skip non-interactive entries (colored headers/separators)
if (colors.containsKey(list.get(j1))) {
continue;
}
return j1;
}