feat(potions): add restoration potion for default player size
This commit is contained in:
@@ -27,7 +27,8 @@ public final class HeightMath {
|
||||
if (stored == null || !Double.isFinite(stored)) {
|
||||
return clamp(1.0, settings);
|
||||
}
|
||||
return clamp(stored, settings);
|
||||
// Restoration is an explicit escape from configured stature limits.
|
||||
return stored == 1.0 ? 1.0 : clamp(stored, settings);
|
||||
}
|
||||
|
||||
public static double clamp(double value, HeightSettings settings) {
|
||||
|
||||
@@ -17,6 +17,7 @@ public final class PotionRecipes {
|
||||
static final String[] SHIFTING_SHAPE = {"ACA", "AWA", "ACA"};
|
||||
static final String[] GROWTH_SHAPE = {"GAG", "ASA", "GRG"};
|
||||
static final String[] DIMINUTION_SHAPE = {"GAG", "ASA", "GFG"};
|
||||
static final String[] RESTORATION_SHAPE = {"GAG", "ASA", "GUG"};
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final NamespacedKey potionKindKey;
|
||||
@@ -30,6 +31,7 @@ public final class PotionRecipes {
|
||||
registerShifting();
|
||||
registerGrowth();
|
||||
registerDiminution();
|
||||
registerRestoration();
|
||||
}
|
||||
|
||||
public ItemStack create(StaturePotion kind) {
|
||||
@@ -96,11 +98,23 @@ public final class PotionRecipes {
|
||||
plugin.getServer().addRecipe(recipe);
|
||||
}
|
||||
|
||||
private void registerRestoration() {
|
||||
ShapedRecipe recipe = new ShapedRecipe(new NamespacedKey(plugin, "restoration"),
|
||||
create(StaturePotion.RESTORATION));
|
||||
recipe.shape(RESTORATION_SHAPE);
|
||||
recipe.setIngredient('G', Material.GOLD_INGOT);
|
||||
recipe.setIngredient('A', Material.AMETHYST_SHARD);
|
||||
recipe.setIngredient('S', new RecipeChoice.ExactChoice(create(StaturePotion.SHIFTING)));
|
||||
recipe.setIngredient('U', Material.SUGAR);
|
||||
plugin.getServer().addRecipe(recipe);
|
||||
}
|
||||
|
||||
private static Color color(StaturePotion kind) {
|
||||
return switch (kind) {
|
||||
case SHIFTING -> Color.PURPLE;
|
||||
case GROWTH -> Color.LIME;
|
||||
case DIMINUTION -> Color.FUCHSIA;
|
||||
case RESTORATION -> Color.WHITE;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,12 +50,8 @@ public final class StatureListener implements Listener {
|
||||
}
|
||||
Player player = event.getPlayer();
|
||||
double current = currentScale(player);
|
||||
double scale = switch (kind) {
|
||||
case SHIFTING -> HeightMath.randomScale(settings,
|
||||
bound -> ThreadLocalRandom.current().nextInt(bound));
|
||||
case GROWTH -> HeightMath.grow(current, settings);
|
||||
case DIMINUTION -> HeightMath.shrink(current, settings);
|
||||
};
|
||||
double scale = kind.scaleAfterDrinking(current, settings,
|
||||
bound -> ThreadLocalRandom.current().nextInt(bound));
|
||||
applyAndSave(player, scale);
|
||||
player.sendMessage("Your scale is now " + scale + ".");
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
package games.dmg.spigotheights;
|
||||
|
||||
import java.util.function.IntUnaryOperator;
|
||||
|
||||
public enum StaturePotion {
|
||||
SHIFTING("Potion of Shifting Stature"),
|
||||
GROWTH("Potion of Growth"),
|
||||
DIMINUTION("Potion of Diminution");
|
||||
DIMINUTION("Potion of Diminution"),
|
||||
RESTORATION("Potion of Restoration");
|
||||
|
||||
private final String displayName;
|
||||
|
||||
@@ -11,6 +14,15 @@ public enum StaturePotion {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public double scaleAfterDrinking(double current, HeightSettings settings, IntUnaryOperator randomIndex) {
|
||||
return switch (this) {
|
||||
case SHIFTING -> HeightMath.randomScale(settings, randomIndex);
|
||||
case GROWTH -> HeightMath.grow(current, settings);
|
||||
case DIMINUTION -> HeightMath.shrink(current, settings);
|
||||
case RESTORATION -> 1.0;
|
||||
};
|
||||
}
|
||||
|
||||
public String displayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,20 @@ class HeightMathTest {
|
||||
assertEquals(1.1, HeightMath.grow(1.0, SETTINGS), 0.000001);
|
||||
}
|
||||
|
||||
@Test
|
||||
void savedDefaultSizeSurvivesRangesThatExcludeIt() {
|
||||
for (HeightSettings settings : new HeightSettings[] {
|
||||
new HeightSettings(0.2, 0.8, 0.1, 0.5, 1.5, 20),
|
||||
new HeightSettings(1.2, 2.0, 0.1, 1.5, 1.5, 20)}) {
|
||||
assertEquals(1.0, HeightMath.safeStoredScale(1.0, settings));
|
||||
assertEquals(settings.minimum(), HeightMath.safeStoredScale(0.1, settings));
|
||||
assertEquals(settings.maximum(), HeightMath.safeStoredScale(3.0, settings));
|
||||
double fallback = HeightMath.clamp(1.0, settings);
|
||||
assertEquals(fallback, HeightMath.safeStoredScale(null, settings));
|
||||
assertEquals(fallback, HeightMath.safeStoredScale(Double.NaN, settings));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingAndStoredValuesAreSafelyClamped() {
|
||||
assertEquals(1.0, HeightMath.safeStoredScale(null, SETTINGS), 0.000001);
|
||||
|
||||
@@ -12,6 +12,19 @@ class HeightStoreTest {
|
||||
@TempDir
|
||||
Path temporaryDirectory;
|
||||
|
||||
@Test
|
||||
void restorationReplacesPreviousSizeAndSurvivesReloadOutsideLimits() throws Exception {
|
||||
UUID playerId = UUID.randomUUID();
|
||||
HeightSettings settings = new HeightSettings(0.2, 0.8, 0.1, 0.5, 1.5, 20);
|
||||
HeightStore store = new HeightStore(temporaryDirectory.toFile());
|
||||
store.save(playerId, 0.4);
|
||||
store.save(playerId, StaturePotion.RESTORATION.scaleAfterDrinking(0.4, settings, bound -> 0));
|
||||
|
||||
HeightStore reloaded = new HeightStore(temporaryDirectory.toFile());
|
||||
assertEquals(1.0, reloaded.find(playerId));
|
||||
assertEquals(1.0, HeightMath.safeStoredScale(reloaded.find(playerId), settings));
|
||||
}
|
||||
|
||||
@Test
|
||||
void storesByUuidAndPreservesUnknownYamlFields() throws Exception {
|
||||
UUID playerId = UUID.randomUUID();
|
||||
|
||||
@@ -2,6 +2,7 @@ package games.dmg.spigotheights;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -13,6 +14,17 @@ class PotionRecipesTest {
|
||||
assertArrayEquals(new String[] {"GAG", "ASA", "GFG"}, PotionRecipes.DIMINUTION_SHAPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void restorationUsesApprovedShapeAndDistinctIdentity() {
|
||||
assertArrayEquals(new String[] {"GAG", "ASA", "GUG"}, PotionRecipes.RESTORATION_SHAPE);
|
||||
assertEquals("RESTORATION", StaturePotion.RESTORATION.name());
|
||||
for (StaturePotion kind : StaturePotion.values()) {
|
||||
if (kind != StaturePotion.RESTORATION) {
|
||||
assertNotEquals(kind.name(), StaturePotion.RESTORATION.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void everyPotionHasASeparatePersistentIdentity() {
|
||||
assertNotEquals(StaturePotion.SHIFTING.name(), StaturePotion.GROWTH.name());
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package games.dmg.spigotheights;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class StaturePotionTest {
|
||||
@Test
|
||||
void existingPotionsKeepTheirScaleRules() {
|
||||
HeightSettings settings = new HeightSettings(0.4, 2.0, 0.1, 0.5, 1.5, 20);
|
||||
assertEquals(0.4, StaturePotion.SHIFTING.scaleAfterDrinking(1.0, settings, bound -> 0));
|
||||
assertEquals(2.0, StaturePotion.SHIFTING.scaleAfterDrinking(1.0, settings, bound -> bound - 1));
|
||||
assertEquals(1.1, StaturePotion.GROWTH.scaleAfterDrinking(1.0, settings, bound -> 0));
|
||||
assertEquals(0.9, StaturePotion.DIMINUTION.scaleAfterDrinking(1.0, settings, bound -> 0));
|
||||
assertEquals(2.0, StaturePotion.GROWTH.scaleAfterDrinking(2.0, settings, bound -> 0));
|
||||
assertEquals(0.4, StaturePotion.DIMINUTION.scaleAfterDrinking(0.4, settings, bound -> 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
void restorationAlwaysReturnsNormalSizeWithoutRandomness() {
|
||||
for (HeightSettings settings : new HeightSettings[] {
|
||||
new HeightSettings(0.4, 2.0, 0.1, 0.5, 1.5, 20),
|
||||
new HeightSettings(0.2, 0.8, 0.1, 0.5, 1.5, 20),
|
||||
new HeightSettings(1.2, 2.0, 0.1, 1.5, 1.5, 20)}) {
|
||||
for (double current : new double[] {0.2, 1.0, 2.0}) {
|
||||
assertEquals(1.0, StaturePotion.RESTORATION.scaleAfterDrinking(current, settings,
|
||||
bound -> { throw new AssertionError("Restoration must not roll a random size"); }));
|
||||
}
|
||||
}
|
||||
assertEquals("Potion of Restoration", StaturePotion.RESTORATION.displayName());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user