Compare commits

...
1 Commits
Author SHA1 Message Date
dmg 89a57167cc feat(book): show ability prerequisites first
Release / release (push) Successful in 9m18s
2026-09-20 21:16:48 -04:00
14 changed files with 18 additions and 16 deletions

No files matched your search

@@ -235,14 +235,13 @@ public final class CharacterBookController implements Consumer<ControlInput>, Au
: !points ? "Unavailable: points" : !slot ? "Unavailable: slots" : "Available";
var builder = new PageBuilder();
builder.text(definition.name());
builder.text("Cost: " + definition.pointCost());
builder.text(requirements);
if (learned) builder.component(abilityButton("Unlearn", ABILITY_UNLEARN, view, definition.id()));
else if (stats && points && slot) builder.component(abilityButton("Learn", ABILITY_UNLOCK, view, definition.id()));
else builder.text(state);
builder.blank();
definition.lore().forEach(builder::text);
builder.blank(); builder.text(definition.instructions());
builder.text("Requires: " + requirements);
builder.text("Cooldown: " + durationSeconds(definition.cooldown()) + "s");
if (!definition.parameters().isEmpty()) builder.text("Parameters: " + definition.parameters().entrySet().stream()
.sorted(Map.Entry.comparingByKey()).map(entry -> entry.getKey() + "=" + entry.getValue())
@@ -147,7 +147,7 @@ class AbilityEngineNativeTest {
String compactAvailable = available.replaceAll("\\s+", "");
assertTrue(compactAvailable.contains("TestFocus"), available);
assertFalse(compactAvailable.contains("Icon:"), available);
assertTrue(compactAvailable.contains("Cost:1"), available);
assertFalse(compactAvailable.contains("Cost:"), available);
assertTrue(compactAvailable.contains("Cooldown:4s"), available);
var learn = PartyBookNativeTest.button(a, "[Learn]");
PartyBookNativeTest.click(f, a, learn); PartyBookNativeTest.click(f, a, learn);
@@ -346,7 +346,10 @@ class CharacterBookNativeTest {
var fireballJump = changePage(pages.get(index), "Fireball");
assertNotNull(fireballJump);
var detail = pages.get(fireballJump.page() - 1);
assertTrue(detail.getString().startsWith("Fireball\nCost: 1\n[Learn]"), detail.getString());
assertTrue(detail.getString().startsWith("Fireball\nINT 12\n[Learn]"), detail.getString());
assertFalse(text(a.books.getLast()).contains("Cost:"));
assertFalse(text(a.books.getLast()).contains("Requires:"));
assertTrue(text(a.books.getLast()).contains("Shield Bash\nSTR 12, CON 12"));
assertFalse(detail.getString().contains("Icon:"));
assertFalse(text(a.books.getLast()).contains("Assign ability"));
assertFalse(text(a.books.getLast()).contains("[3]"));
@@ -359,7 +362,7 @@ class CharacterBookNativeTest {
assertTrue(refreshed.get(1).getString().contains("3: Fireball"));
var activeJump = changePage(refreshed.get(1), "Fireball");
assertNotNull(activeJump);
assertTrue(refreshed.get(activeJump.page() - 1).getString().startsWith("Fireball\nCost: 1\n[Unlearn]"));
assertTrue(refreshed.get(activeJump.page() - 1).getString().startsWith("Fireball\nINT 12\n[Unlearn]"));
}
}
@@ -74,7 +74,7 @@ class FrostNovaNativeTest {
caster.core.inventory.getInventory().setSelectedSlot(0); PartyBookNativeTest.open(fixture, caster);
String text = PartyBookNativeTest.text(caster).replaceAll("\\s+", "");
assertTrue(text.contains("FrostNova")); assertTrue(text.contains("INT16")); assertTrue(text.contains("DEX10"));
assertTrue(text.contains("Cost:1")); assertTrue(text.contains("5")); assertTrue(text.contains("SlownessII"));
assertFalse(text.contains("Cost:")); assertTrue(text.contains("5")); assertTrue(text.contains("SlownessII"));
PartyBookNativeTest.click(fixture, caster, button(caster, "[Learn]", "frost_nova")); drain(fixture, 2);
use(fixture, caster); drain(fixture, 2);
assertEquals(8, damage.get(enemy.getUniqueId()), 1.0e-9); assertEquals(8, damage.get(opponent.core.id), 1.0e-9);
@@ -55,7 +55,7 @@ class GuardianBondNativeTest {
guardian.core.inventory.getInventory().setSelectedSlot(0); PartyBookNativeTest.open(fixture, guardian);
String text = PartyBookNativeTest.text(guardian).replaceAll("\\s+", "");
assertTrue(text.contains("GuardianBond")); assertTrue(text.contains("CON16")); assertTrue(text.contains("WIS10"));
assertTrue(text.contains("Cost:1")); assertTrue(text.contains("30%")); assertTrue(text.contains("6seconds"));
assertFalse(text.contains("Cost:")); assertTrue(text.contains("30%")); assertTrue(text.contains("6seconds"));
PartyBookNativeTest.click(fixture, guardian, button(guardian, "[Learn]", "guardian_bond")); drain(fixture, 2);
use(fixture, guardian); drain(fixture, 2);
@@ -37,7 +37,7 @@ class HexNativeTest {
a.core.inventory.getInventory().setSelectedSlot(0); PartyBookNativeTest.open(f, a);
String book = PartyBookNativeTest.text(a).replaceAll("\\s+", "");
assertTrue(book.contains("Hex")); assertTrue(book.contains("CHR14")); assertTrue(book.contains("WIS12"));
assertTrue(book.contains("Cost:1")); assertTrue(book.contains("12")); assertTrue(book.contains("20%")); assertTrue(book.contains("4s"));
assertFalse(book.contains("Cost:")); assertTrue(book.contains("12")); assertTrue(book.contains("20%")); assertTrue(book.contains("4s"));
PartyBookNativeTest.click(f, a, abilityButton(a, "[Learn]", "hex")); PartyBookNativeTest.drain(f); PartyBookNativeTest.drain(f);
var enemy = mock(org.bukkit.entity.LivingEntity.class); var enemyId = java.util.UUID.randomUUID();
@@ -2,7 +2,7 @@ package games.dmg.fantasystick;
import static org.junit.jupiter.api.Assertions.*;import static org.mockito.Mockito.*;
import games.dmg.fantasystick.persistence.*;import games.dmg.fantasystick.progression.Stat;import java.math.BigInteger;import java.nio.file.Path;import java.util.*;import net.minecraft.network.chat.ClickEvent;import org.bukkit.event.player.PlayerInteractEvent;import org.bukkit.inventory.EquipmentSlot;import org.junit.jupiter.api.*;import org.junit.jupiter.api.io.TempDir;
class InspireNativeTest{@TempDir Path data;@BeforeAll static void bootstrap()throws Exception{NativeRuntime.bootstrap();}
@Test void bookAcquisitionSneakUseAddsOwnedTemporaryHealthAndExpiryPreservesUnrelatedAbsorption()throws Exception{try(var f=new FantasyStickLifecycleNativeTest.Fixture(data)){f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(data);withInspire(data,a,false);f.players.put(a.core.id,a.player);f.activate(a);a.core.inventory.getInventory().setSelectedSlot(0);PartyBookNativeTest.open(f,a);String book=PartyBookNativeTest.text(a).replaceAll("\\s+","");assertTrue(book.contains("Inspire"));assertTrue(book.contains("CHR12"));assertTrue(book.contains("WIS10"));assertTrue(book.contains("Cost:1"));assertTrue(book.contains("12"));assertTrue(book.contains("6s"));PartyBookNativeTest.click(f,a,button(a,"[Learn]","inspire"));PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);
@Test void bookAcquisitionSneakUseAddsOwnedTemporaryHealthAndExpiryPreservesUnrelatedAbsorption()throws Exception{try(var f=new FantasyStickLifecycleNativeTest.Fixture(data)){f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(data);withInspire(data,a,false);f.players.put(a.core.id,a.player);f.activate(a);a.core.inventory.getInventory().setSelectedSlot(0);PartyBookNativeTest.open(f,a);String book=PartyBookNativeTest.text(a).replaceAll("\\s+","");assertTrue(book.contains("Inspire"));assertTrue(book.contains("CHR12"));assertTrue(book.contains("WIS10"));assertFalse(book.contains("Cost:"));assertTrue(book.contains("12"));assertTrue(book.contains("6s"));PartyBookNativeTest.click(f,a,button(a,"[Learn]","inspire"));PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);
double maximum=a.maximumHealth.getBaseValue();var absorption=new java.util.concurrent.atomic.AtomicReference<>(2.0);doAnswer(c->absorption.get()).when(a.player).getAbsorptionAmount();doAnswer(c->{absorption.set(c.getArgument(0));return null;}).when(a.player).setAbsorptionAmount(anyDouble());doReturn(true).when(a.player).isSneaking();a.core.inventory.getInventory().setSelectedSlot(2);f.dispatcher.accept(new PlayerInteractEvent(a.player,org.bukkit.event.block.Action.RIGHT_CLICK_AIR,a.core.inventory.getItem(2),null,org.bukkit.block.BlockFace.SELF,EquipmentSlot.HAND));PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);assertEquals(7,absorption.get(),1e-9);assertEquals(maximum,a.maximumHealth.getBaseValue(),1e-9);assertEquals(120L,f.delayedTicks.getLast());f.delayed.getLast().run();assertEquals(2,absorption.get(),1e-9);var storage=(CharacterStorage)FantasyStickLifecycleNativeTest.Fixture.field(f.plugin,"characters");assertNotNull(storage.find(a.core.record.id()).get().orElseThrow().cooldowns().get("inspire"));}}
@Test void aimedPartyAllyActualAbsorptionCreatesPersistedSupportShare()throws Exception{try(var f=new FantasyStickLifecycleNativeTest.Fixture(data)){f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(data);var b=new FantasyStickLifecycleNativeTest.Actor(data);withInspire(data,a,true);f.players.put(a.core.id,a.player);f.players.put(b.core.id,b.player);f.activate(a);f.activate(b);var parties=PartyLifecycleNativeTest.parties(f);var party=parties.create(a.core.id).orElseThrow();assertTrue(parties.accept(b.core.id,parties.invite(a.core.id,party.id(),b.core.id).orElseThrow().id()));
doReturn(false).when(a.player).isSneaking();doReturn(new org.bukkit.Location(a.world,0,64,0)).when(a.player).getLocation();doReturn(new org.bukkit.Location(a.world,8,64,0)).when(b.player).getLocation();doReturn(true).when(a.player).hasLineOfSight(b.player);doReturn(b.player).when(a.player).getTargetEntity(64);var absorption=new java.util.concurrent.atomic.AtomicReference<>(0.0);doAnswer(c->absorption.get()).when(b.player).getAbsorptionAmount();doAnswer(c->{absorption.set(c.getArgument(0));return null;}).when(b.player).setAbsorptionAmount(anyDouble());use(f,a);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);assertEquals(5,absorption.get(),1e-9);
@@ -45,7 +45,7 @@ class LongbowNativeTest {
a.core.inventory.getInventory().setSelectedSlot(0); PartyBookNativeTest.open(f, a);
String text = PartyBookNativeTest.text(a).replaceAll("\\s+", "");
assertTrue(text.contains("Longbow")); assertTrue(text.contains("DEX14"));
assertTrue(text.contains("Cost:1"), text); assertTrue(text.contains("Draw"), text);
assertFalse(text.contains("Cost:"), text); assertTrue(text.contains("Draw"), text);
assertTrue(text.contains("1s"), text);
PartyBookNativeTest.click(f, a, abilityButton(a, "[Learn]", "longbow"));
PartyBookNativeTest.drain(f); PartyBookNativeTest.drain(f);
@@ -58,7 +58,7 @@ class MendingLightNativeTest {
caster.core.inventory.getInventory().setSelectedSlot(0); PartyBookNativeTest.open(fixture, caster);
String text = PartyBookNativeTest.text(caster).replaceAll("\\s+", "");
assertTrue(text.contains("MendingLight")); assertTrue(text.contains("WIS12"));
assertTrue(text.contains("CHR10")); assertTrue(text.contains("Cost:1"));
assertTrue(text.contains("CHR10")); assertFalse(text.contains("Cost:"));
assertTrue(text.contains("12")); assertTrue(text.contains("8"));
PartyBookNativeTest.click(fixture, caster, button(caster, "[Learn]", "mending_light"));
drain(fixture, 2);
@@ -56,7 +56,7 @@ class PurifyNativeTest {
actor.core.inventory.getInventory().setSelectedSlot(0); PartyBookNativeTest.open(fixture, actor);
String book = PartyBookNativeTest.text(actor).replaceAll("\\s+", "");
assertTrue(book.contains("Purify")); assertTrue(book.contains("WIS14")); assertTrue(book.contains("CHR10"));
assertTrue(book.contains("Cost:1")); assertTrue(book.contains("15")); assertTrue(book.contains("12"));
assertFalse(book.contains("Cost:")); assertTrue(book.contains("15")); assertTrue(book.contains("12"));
PartyBookNativeTest.click(fixture, actor, button(actor, "[Learn]", "purify")); drain(fixture, 2);
doReturn(true).when(actor.player).isSneaking(); use(fixture, actor); drain(fixture, 2);
@@ -34,7 +34,7 @@ class QuickstepNativeTest {
a.core.inventory.getInventory().setSelectedSlot(0); PartyBookNativeTest.open(f, a);
String text = PartyBookNativeTest.text(a).replaceAll("\\s+", "");
assertTrue(text.contains("Quickstep")); assertTrue(text.contains("DEX12"));
assertTrue(text.contains("Cost:1")); assertTrue(text.contains("4")); assertTrue(text.contains("5s"));
assertFalse(text.contains("Cost:")); assertTrue(text.contains("4")); assertTrue(text.contains("5s"));
PartyBookNativeTest.click(f, a, abilityButton(a, "[Learn]", "quickstep"));
PartyBookNativeTest.drain(f); PartyBookNativeTest.drain(f);
var storage = (CharacterStorage) FantasyStickLifecycleNativeTest.Fixture.field(f.plugin, "characters");
@@ -55,7 +55,7 @@ class RallyingCryNativeTest {
caster.core.inventory.getInventory().setSelectedSlot(0); PartyBookNativeTest.open(fixture, caster);
String text = PartyBookNativeTest.text(caster).replaceAll("\\s+", "");
assertTrue(text.contains("RallyingCry")); assertTrue(text.contains("CHR16")); assertTrue(text.contains("CON12"));
assertTrue(text.contains("Cost:1")); assertTrue(text.contains("20%")); assertTrue(text.contains("6seconds"));
assertFalse(text.contains("Cost:")); assertTrue(text.contains("20%")); assertTrue(text.contains("6seconds"));
PartyBookNativeTest.click(fixture, caster, button(caster, "[Learn]", "rallying_cry")); drain(fixture, 2);
use(fixture, caster); drain(fixture, 2);
assertEquals(0, casterEffects.get(PotionEffectType.SPEED).getAmplifier());
@@ -32,7 +32,7 @@ class ShieldBashNativeTest {
a.core.inventory.getInventory().setSelectedSlot(0); PartyBookNativeTest.open(f, a);
String book = PartyBookNativeTest.text(a).replaceAll("\\s+", "");
assertTrue(book.contains("ShieldBash")); assertTrue(book.contains("STR12")); assertTrue(book.contains("CON12"));
assertTrue(book.contains("Cost:1")); assertTrue(book.contains("3")); assertTrue(book.contains("6s"));
assertFalse(book.contains("Cost:")); assertTrue(book.contains("3")); assertTrue(book.contains("6s"));
PartyBookNativeTest.click(f, a, abilityButton(a, "[Learn]", "shield_bash"));
PartyBookNativeTest.drain(f); PartyBookNativeTest.drain(f);
var storage = (CharacterStorage) FantasyStickLifecycleNativeTest.Fixture.field(f.plugin, "characters");
@@ -31,7 +31,7 @@ class StoneSkinNativeTest {
a.core.inventory.getInventory().setSelectedSlot(0); PartyBookNativeTest.open(f, a);
String text = PartyBookNativeTest.text(a).replaceAll("\\s+", "");
assertTrue(text.contains("StoneSkin")); assertTrue(text.contains("CON14"));
assertTrue(text.contains("Cost:1")); assertTrue(text.contains("25%")); assertTrue(text.contains("4s"));
assertFalse(text.contains("Cost:")); assertTrue(text.contains("25%")); assertTrue(text.contains("4s"));
PartyBookNativeTest.click(f, a, abilityButton(a, "[Learn]", "stone_skin"));
PartyBookNativeTest.drain(f); PartyBookNativeTest.drain(f);
var storage = (CharacterStorage) FantasyStickLifecycleNativeTest.Fixture.field(f.plugin, "characters");