Cap particle speed at 0.05 and give each wing shape its own icon

Speed steps by 0.005 up to 0.05; presets keep their faster particles. Number
values now show up to three decimals.
This commit is contained in:
2026-10-26 14:43:44 +01:00
parent 8fd6fdf81e
commit baa278a1f5
8 changed files with 41 additions and 18 deletions
@@ -68,17 +68,17 @@ public class Designs {
// Images keep their old ids, so saved wings still load; preset and tournament images stay out of the builder
private final List<ChoiceParameter.Choice<WingShape>> WING_SHAPES = List.of(
new ChoiceParameter.Choice<>("simple", WingShape.image(WingDesign.SIMPLE), false),
new ChoiceParameter.Choice<>("complex", WingShape.image(WingDesign.COMPLEX), false),
new ChoiceParameter.Choice<>("sword", WingShape.image(WingDesign.SWORD), false),
new ChoiceParameter.Choice<>("bat", WingShape.drawn(DrawnWings.BAT), false),
new ChoiceParameter.Choice<>("butterfly", WingShape.drawn(DrawnWings.BUTTERFLY), false),
new ChoiceParameter.Choice<>("fairy", WingShape.drawn(DrawnWings.FAIRY), false),
new ChoiceParameter.Choice<>("simple", WingShape.image(WingDesign.SIMPLE, Material.FEATHER), false),
new ChoiceParameter.Choice<>("complex", WingShape.image(WingDesign.COMPLEX, Material.PHANTOM_MEMBRANE), false),
new ChoiceParameter.Choice<>("sword", WingShape.image(WingDesign.SWORD, Material.STONE_SWORD), false),
new ChoiceParameter.Choice<>("bat", WingShape.drawn(DrawnWings.BAT, Material.BAT_SPAWN_EGG), false),
new ChoiceParameter.Choice<>("butterfly", WingShape.drawn(DrawnWings.BUTTERFLY, Material.PINK_PETALS), false),
new ChoiceParameter.Choice<>("fairy", WingShape.drawn(DrawnWings.FAIRY, Material.ALLAY_SPAWN_EGG), false),
// Tournament wing images, unlocked by the placement that earns their reward
new ChoiceParameter.Choice<>("mwgl", WingShape.image(WingDesign.MWGL), false, () -> RewardDesigns.EVENT_PLACEMENT_MINI_WARGEAR_LIGA.getRequirement()),
new ChoiceParameter.Choice<>("sw", WingShape.image(WingDesign.SW), false, () -> RewardDesigns.EVENT_PLACEMENT_UNDERWATER_MWG.getRequirement()),
new ChoiceParameter.Choice<>("wgs", WingShape.image(WingDesign.WGS), false, () -> RewardDesigns.EVENT_PLACEMENT_WARGEAR_SEASON_2022.getRequirement()),
new ChoiceParameter.Choice<>("sword_crossed", WingShape.image(WingDesign.SWORD_CROSSED), false, () -> RewardDesigns.EVENT_PLACEMENT_WARGEAR_CLASH.getRequirement()),
new ChoiceParameter.Choice<>("mwgl", WingShape.image(WingDesign.MWGL, Material.IRON_SWORD), false, () -> RewardDesigns.EVENT_PLACEMENT_MINI_WARGEAR_LIGA.getRequirement()),
new ChoiceParameter.Choice<>("sw", WingShape.image(WingDesign.SW, Material.CYAN_CARPET), false, () -> RewardDesigns.EVENT_PLACEMENT_UNDERWATER_MWG.getRequirement()),
new ChoiceParameter.Choice<>("wgs", WingShape.image(WingDesign.WGS, Material.DIAMOND_HELMET), false, () -> RewardDesigns.EVENT_PLACEMENT_WARGEAR_SEASON_2022.getRequirement()),
new ChoiceParameter.Choice<>("sword_crossed", WingShape.image(WingDesign.SWORD_CROSSED, Material.GOLDEN_SWORD), false, () -> RewardDesigns.EVENT_PLACEMENT_WARGEAR_CLASH.getRequirement()),
new ChoiceParameter.Choice<>("eclipse", WingShape.image(WingDesign.ECLIPSE), true),
new ChoiceParameter.Choice<>("pl", WingShape.image(WingDesign.PL), true),
new ChoiceParameter.Choice<>("plompa_easter", WingShape.image(WingDesign.PlompaEasterWings), true),
@@ -139,7 +139,7 @@ public class EntryParameters {
public final DoubleParameter SPREAD_Y = new DoubleParameter("spreadY", "PARTICLE_PARAM_SPREAD_Y", 0, 0, 0.5, 0.01);
public final DoubleParameter SPREAD_Z = new DoubleParameter("spreadZ", "PARTICLE_PARAM_SPREAD_Z", 0, 0, 0.5, 0.01);
// For most particles the speed of their random spray; above 0.2 they shoot blocks away
public final DoubleParameter SPEED = new DoubleParameter("speed", "PARTICLE_PARAM_SPEED", 0.01, 0, 0.2, 0.01);
public final DoubleParameter SPEED = new DoubleParameter("speed", "PARTICLE_PARAM_SPEED", 0.01, 0, 0.05, 0.005);
public final GradientParameter COLORS = new GradientParameter("colors", "PARTICLE_PARAM_COLORS", 8);
// Blocks that are also items, so they work for block and item particles alike
public final ChoiceParameter<Material> BLOCK = new ChoiceParameter<>("block", "PARTICLE_PARAM_BLOCK", Material.STONE, List.of(
@@ -40,6 +40,12 @@ public class ParameterValues {
return this;
}
// Skips the builder's limits; only for presets, which are never stored
public <T> ParameterValues setUnchecked(Parameter<T> parameter, T value) {
values.put(parameter.getKey(), value);
return this;
}
// Puts back values saved with copy()
public void restore(ParameterValues saved) {
values.clear();
@@ -21,24 +21,34 @@ package de.steamwar.lobby.particle.design;
import de.steamwar.lobby.particle.DrawnWings;
import de.steamwar.lobby.particle.WingDesign;
import lombok.Getter;
import org.bukkit.Material;
// A wing shape of the wings design: either a fixed image or a shape drawn with a chosen number of points
public class WingShape {
private final WingDesign image;
private final DrawnWings drawn;
@Getter
private final Material icon;
private WingShape(WingDesign image, DrawnWings drawn) {
private WingShape(WingDesign image, DrawnWings drawn, Material icon) {
this.image = image;
this.drawn = drawn;
this.icon = icon;
}
public static WingShape image(WingDesign image, Material icon) {
return new WingShape(image, null, icon);
}
// Shapes only presets use, never shown in the builder
public static WingShape image(WingDesign image) {
return new WingShape(image, null);
return image(image, Material.PHANTOM_MEMBRANE);
}
public static WingShape drawn(DrawnWings drawn) {
return new WingShape(null, drawn);
public static WingShape drawn(DrawnWings drawn, Material icon) {
return new WingShape(null, drawn, icon);
}
public boolean isDrawn() {
@@ -186,6 +186,7 @@ class EntryEditor {
if (parameter == PARTICLE) icon = ((ParticleType) value).getIcon();
if (parameter == COLORS) icon = Material.RED_DYE;
if (parameter == BLOCK) icon = (Material) value;
if (value instanceof WingShape shape) icon = shape.getIcon();
return new SWItem(icon, name(parameter.getNameKey(), player), lore, false, clickType -> {
if (parameter instanceof BooleanParameter toggle) {
@@ -252,7 +253,7 @@ class EntryEditor {
private Material choiceIcon(Object value) {
if (value instanceof ParticleType type) return type.getIcon();
if (value instanceof WingShape) return Material.PHANTOM_MEMBRANE;
if (value instanceof WingShape shape) return shape.getIcon();
if (value instanceof Material material) return material;
return Material.LEVER;
}
@@ -82,7 +82,7 @@ class ParticleGuiText {
}
String number(double value) {
return value == Math.rint(value) ? String.valueOf((long) value) : String.format(Locale.ROOT, "%.2f", value).replaceAll("0+$", "");
return value == Math.rint(value) ? String.valueOf((long) value) : String.format(Locale.ROOT, "%.3f", value).replaceAll("0+$", "");
}
@SuppressWarnings("unchecked")
@@ -64,6 +64,12 @@ public class ParticleEntry {
return this;
}
// For presets that go beyond what the builder allows
public <T> ParticleEntry withUnchecked(Parameter<T> parameter, T value) {
values.setUnchecked(parameter, value);
return this;
}
public List<Parameter<?>> getParameters() {
return parametersOf(design);
}
@@ -112,7 +112,7 @@ public class Presets {
.with(SPREAD_X, spread)
.with(SPREAD_Y, spread)
.with(SPREAD_Z, spread)
.with(SPEED, speed)
.withUnchecked(SPEED, speed)
.with(COUNT, count);
}