forked from SteamWar/SteamWar
Add colour along the wing and sparkle to lobby wings
Both wing designs can colour their points from the spine to the tips instead of changing colour over time, and a sparkle setting shows only a share of the points each tick, which also lowers their cost. The angel and phoenix drawn shapes are removed.
This commit is contained in:
@@ -171,6 +171,8 @@ PARTICLE_PARAM_WING_IMAGE = §fWing shape
|
||||
PARTICLE_PARAM_WING_SIZE = §fWing size
|
||||
PARTICLE_PARAM_DRAWN_SHAPE = §fShape
|
||||
PARTICLE_PARAM_WING_DETAIL = §fPoints per wing
|
||||
PARTICLE_PARAM_WING_COLORING = §fColour mode
|
||||
PARTICLE_PARAM_WING_SPARKLE = §fSparkle (points shown, %)
|
||||
|
||||
PARTICLE_CHOICE_TICKMODE_MOVE = §fWhile moving
|
||||
PARTICLE_CHOICE_TICKMODE_ALWAYS = §fAlways
|
||||
@@ -194,11 +196,11 @@ PARTICLE_CHOICE_VISIBILITY_ONLY_OTHERS = §fOnly others
|
||||
PARTICLE_CHOICE_IMAGE_SIMPLE = §fSimple
|
||||
PARTICLE_CHOICE_IMAGE_COMPLEX = §fComplex
|
||||
PARTICLE_CHOICE_IMAGE_SWORD = §fSword
|
||||
PARTICLE_CHOICE_SHAPE_ANGEL = §fAngel
|
||||
PARTICLE_CHOICE_SHAPE_BAT = §fBat
|
||||
PARTICLE_CHOICE_SHAPE_BUTTERFLY = §fButterfly
|
||||
PARTICLE_CHOICE_SHAPE_FAIRY = §fFairy
|
||||
PARTICLE_CHOICE_SHAPE_PHOENIX = §fPhoenix
|
||||
PARTICLE_CHOICE_COLORING_OVER_TIME = §fChange over time
|
||||
PARTICLE_CHOICE_COLORING_ALONG_WING = §fFrom the back to the tips
|
||||
|
||||
# Particle types
|
||||
PARTICLE_TYPE_DUST = §fDust
|
||||
|
||||
@@ -171,6 +171,8 @@ PARTICLE_PARAM_WING_IMAGE = §fFlügelform
|
||||
PARTICLE_PARAM_WING_SIZE = §fFlügelgröße
|
||||
PARTICLE_PARAM_DRAWN_SHAPE = §fForm
|
||||
PARTICLE_PARAM_WING_DETAIL = §fPunkte pro Flügel
|
||||
PARTICLE_PARAM_WING_COLORING = §fFarbmodus
|
||||
PARTICLE_PARAM_WING_SPARKLE = §fFunkeln (sichtbare Punkte, %)
|
||||
|
||||
PARTICLE_CHOICE_TICKMODE_MOVE = §fBeim Bewegen
|
||||
PARTICLE_CHOICE_TICKMODE_ALWAYS = §fImmer
|
||||
@@ -194,11 +196,11 @@ PARTICLE_CHOICE_VISIBILITY_ONLY_OTHERS = §fNur andere
|
||||
PARTICLE_CHOICE_IMAGE_SIMPLE = §fEinfach
|
||||
PARTICLE_CHOICE_IMAGE_COMPLEX = §fKomplex
|
||||
PARTICLE_CHOICE_IMAGE_SWORD = §fSchwert
|
||||
PARTICLE_CHOICE_SHAPE_ANGEL = §fEngel
|
||||
PARTICLE_CHOICE_SHAPE_BAT = §fFledermaus
|
||||
PARTICLE_CHOICE_SHAPE_BUTTERFLY = §fSchmetterling
|
||||
PARTICLE_CHOICE_SHAPE_FAIRY = §fFee
|
||||
PARTICLE_CHOICE_SHAPE_PHOENIX = §fPhönix
|
||||
PARTICLE_CHOICE_COLORING_OVER_TIME = §fWechseln mit der Zeit
|
||||
PARTICLE_CHOICE_COLORING_ALONG_WING = §fVom Rücken zu den Spitzen
|
||||
|
||||
# Particle types
|
||||
PARTICLE_TYPE_DUST = §fStaub
|
||||
|
||||
@@ -30,18 +30,6 @@ import java.util.Map;
|
||||
// Coordinates use the same units as the wing images: x is sideways from the spine, y upwards, about 11 by 13.
|
||||
public enum DrawnWings {
|
||||
|
||||
// A curved upper edge, a row of covert feathers and long flight feathers ending in a scalloped edge
|
||||
ANGEL {
|
||||
@Override
|
||||
List<List<Vector>> rightWing() {
|
||||
List<List<Vector>> lines = new ArrayList<>();
|
||||
lines.add(curve(p(0.5, 7), p(3, 10), p(6, 11.8), p(9, 12.4), p(10.8, 11.2), p(11, 8.5)));
|
||||
lines.add(curve(p(1, 6.6), p(4, 8.3), p(7, 9.3), p(10, 9.8)));
|
||||
lines.add(lineThrough(p(0.5, 5.5), p(2.2, 3.8), p(3.4, 4.6), p(4.2, 2.8), p(5.4, 3.9), p(6.3, 2.6), p(7.5, 4),
|
||||
p(8.3, 3.4), p(9.4, 5.2), p(10, 5), p(10.7, 6.6), p(11, 7.5), p(11, 8.5)));
|
||||
return lines;
|
||||
}
|
||||
},
|
||||
// An arm bone along the top, fingers spreading from the wrist and skin hanging between them
|
||||
BAT {
|
||||
@Override
|
||||
@@ -82,19 +70,6 @@ public enum DrawnWings {
|
||||
return List.of(ellipse(5.2, 9.3, 5, 1.9, 35), ellipse(3.8, 4.6, 3.6, 1.5, -30));
|
||||
}
|
||||
},
|
||||
// An upswept lower edge with flame tongues rising from it, each bending out and curling back at the tip
|
||||
PHOENIX {
|
||||
@Override
|
||||
List<List<Vector>> rightWing() {
|
||||
List<List<Vector>> lines = new ArrayList<>();
|
||||
lines.add(curve(p(0.5, 5), p(4, 5.2), p(8, 7), p(11, 10), p(12, 13)));
|
||||
double[][] tongues = {{1.5, 5.2, 2.5, 10}, {4, 5.4, 5.5, 11.5}, {6.5, 6.2, 8.2, 12.8}, {9, 8, 10.5, 14}};
|
||||
for (double[] tongue : tongues) {
|
||||
lines.add(curve(p(tongue[0], tongue[1]), p(tongue[0] + 1.2, tongue[1] + 1.8), p(tongue[2] - 0.8, tongue[3] - 1.5), p(tongue[2], tongue[3])));
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
},
|
||||
;
|
||||
|
||||
// The right wing as lines; the left wing mirrors it
|
||||
@@ -172,11 +147,6 @@ public enum DrawnWings {
|
||||
return result;
|
||||
}
|
||||
|
||||
// Straight segments between the points, for sharp corners like feather tips
|
||||
private static List<Vector> lineThrough(Vector... points) {
|
||||
return new ArrayList<>(List.of(points));
|
||||
}
|
||||
|
||||
private static List<Vector> ellipse(double centerX, double centerY, double radiusX, double radiusY, double tiltDegrees) {
|
||||
double tilt = Math.toRadians(tiltDegrees);
|
||||
List<Vector> result = new ArrayList<>();
|
||||
|
||||
@@ -43,6 +43,8 @@ public class ParticleTickData {
|
||||
private boolean onlyOthers = false;
|
||||
// Set for entries placed relative to the body, null for world placement
|
||||
private BodyFrame frame;
|
||||
// Where a point sits along its shape, from 0 to 1; when set, gradients colour by it instead of by time
|
||||
private Double shade;
|
||||
|
||||
public ParticleTickData withLocation(Location location) {
|
||||
ParticleTickData particleTickData = copy();
|
||||
@@ -57,6 +59,17 @@ public class ParticleTickData {
|
||||
return particleTickData;
|
||||
}
|
||||
|
||||
public ParticleTickData withShade(double shade) {
|
||||
ParticleTickData particleTickData = copy();
|
||||
particleTickData.shade = shade;
|
||||
return particleTickData;
|
||||
}
|
||||
|
||||
// The gradient position for this tick: along the shape when a shade is set, otherwise moving with time
|
||||
public double gradientPosition() {
|
||||
return shade != null ? Math.min(shade, 0.9999) * 360 : (deg * 10) % 360;
|
||||
}
|
||||
|
||||
public ParticleTickData onlySelf() {
|
||||
ParticleTickData particleTickData = copy();
|
||||
particleTickData.onlySelf = true;
|
||||
@@ -77,6 +90,6 @@ public class ParticleTickData {
|
||||
}
|
||||
|
||||
public ParticleTickData copy() {
|
||||
return new ParticleTickData(world, player, location, deg, isMoving, viewers, onlySelf, onlyOthers, frame);
|
||||
return new ParticleTickData(world, player, location, deg, isMoving, viewers, onlySelf, onlyOthers, frame, shade);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,15 +84,26 @@ public class Designs {
|
||||
));
|
||||
public final DoubleParameter WING_SIZE = new DoubleParameter("size", "PARTICLE_PARAM_WING_SIZE", 0.15, 0.05, 0.3, 0.01);
|
||||
|
||||
public final ParticleDesign WING = new ParticleDesign("wing", Material.ELYTRA, "PARTICLE_DESIGN_WING", WING_IMAGE, WING_SIZE) {
|
||||
public enum WingColoring {
|
||||
// The whole wing changes colour through the entry's colours over time
|
||||
OVER_TIME,
|
||||
// The colours run from the spine to the wing tips
|
||||
ALONG_WING,
|
||||
}
|
||||
|
||||
public final ChoiceParameter<WingColoring> WING_COLORING = ChoiceParameter.ofEnum("coloring", "PARTICLE_PARAM_WING_COLORING", WingColoring.OVER_TIME);
|
||||
// Percent of the points shown each tick; fewer makes the wing twinkle and costs less
|
||||
public final IntParameter WING_SPARKLE = new IntParameter("sparkle", "PARTICLE_PARAM_WING_SPARKLE", 100, 10, 100);
|
||||
|
||||
public final ParticleDesign WING = new ParticleDesign("wing", Material.ELYTRA, "PARTICLE_DESIGN_WING", WING_IMAGE, WING_SIZE, WING_COLORING, WING_SPARKLE) {
|
||||
@Override
|
||||
public ParticleElement build(ParameterValues values, ParticleElement particle) {
|
||||
return new Wing(particle, values.get(WING_SIZE), values.get(WING_IMAGE));
|
||||
return wing(values, particle, values.get(WING_IMAGE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int points(ParameterValues values) {
|
||||
return values.get(WING_IMAGE).getVectors().length;
|
||||
return shown(values, values.get(WING_IMAGE).getVectors().length);
|
||||
}
|
||||
|
||||
// Wings spawn a particle on every pixel of the image, so they start sparse, and sit on the back even while gliding
|
||||
@@ -106,19 +117,20 @@ public class Designs {
|
||||
}
|
||||
};
|
||||
|
||||
public final ChoiceParameter<DrawnWings> DRAWN_SHAPE = ChoiceParameter.ofEnum("shape", "PARTICLE_PARAM_DRAWN_SHAPE", DrawnWings.ANGEL);
|
||||
public final ChoiceParameter<DrawnWings> DRAWN_SHAPE = ChoiceParameter.ofEnum("shape", "PARTICLE_PARAM_DRAWN_SHAPE", DrawnWings.BAT);
|
||||
public final IntParameter WING_DETAIL = new IntParameter("detail", "PARTICLE_PARAM_WING_DETAIL", 20, 6, 60);
|
||||
|
||||
// Wings drawn from lines, with a chosen number of points per wing; sparse ones stay cheap enough to show often
|
||||
public final ParticleDesign DRAWN_WING = new ParticleDesign("drawn_wing", Material.FEATHER, "PARTICLE_DESIGN_DRAWN_WING", DRAWN_SHAPE, WING_DETAIL, WING_SIZE) {
|
||||
public final ParticleDesign DRAWN_WING = new ParticleDesign("drawn_wing", Material.FEATHER, "PARTICLE_DESIGN_DRAWN_WING",
|
||||
DRAWN_SHAPE, WING_DETAIL, WING_SIZE, WING_COLORING, WING_SPARKLE) {
|
||||
@Override
|
||||
public ParticleElement build(ParameterValues values, ParticleElement particle) {
|
||||
return new Wing(particle, values.get(WING_SIZE), values.get(DRAWN_SHAPE).withDetail(values.get(WING_DETAIL)));
|
||||
return wing(values, particle, values.get(DRAWN_SHAPE).withDetail(values.get(WING_DETAIL)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int points(ParameterValues values) {
|
||||
return 2 * values.get(WING_DETAIL);
|
||||
return shown(values, 2 * values.get(WING_DETAIL));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -134,6 +146,15 @@ public class Designs {
|
||||
}
|
||||
};
|
||||
|
||||
private ParticleElement wing(ParameterValues values, ParticleElement particle, WingDesign shape) {
|
||||
return new Wing(particle, values.get(WING_SIZE), shape, values.get(WING_COLORING) == WingColoring.ALONG_WING, values.get(WING_SPARKLE));
|
||||
}
|
||||
|
||||
// Points shown per tick on average with the sparkle setting
|
||||
private int shown(ParameterValues values, int points) {
|
||||
return (int) Math.ceil(points * values.get(WING_SPARKLE) / 100.0);
|
||||
}
|
||||
|
||||
private Map<String, ParticleDesign> registry() {
|
||||
if (registry == null) {
|
||||
Map<String, ParticleDesign> designs = new LinkedHashMap<>();
|
||||
|
||||
@@ -54,7 +54,7 @@ public class DataParticle implements ParticleElement {
|
||||
if (gradient == null) {
|
||||
return Color.fromRGB(RANDOM.nextInt(256), RANDOM.nextInt(256), RANDOM.nextInt(256));
|
||||
}
|
||||
java.awt.Color color = gradient.getColor((particleTickData.getDeg() * 10) % 360, 360);
|
||||
java.awt.Color color = gradient.getColor(particleTickData.gradientPosition(), 360);
|
||||
return Color.fromRGB(color.getRed(), color.getGreen(), color.getBlue());
|
||||
}
|
||||
|
||||
|
||||
@@ -65,8 +65,7 @@ public class DustParticle implements ParticleElement {
|
||||
Location location = particleTickData.getLocation().add(0.0, 0.2, 0.0);
|
||||
Particle.DustOptions dustOptions;
|
||||
if (gradient != null) {
|
||||
double result = (particleTickData.getDeg() * 10) % 360;
|
||||
Color color = gradient.getColor(result, 360);
|
||||
Color color = gradient.getColor(particleTickData.gradientPosition(), 360);
|
||||
dustOptions = withColor(color.getRed(), color.getGreen(), color.getBlue());
|
||||
} else {
|
||||
dustOptions = randomParticleDust();
|
||||
|
||||
@@ -30,6 +30,11 @@ public class Wing extends DelegatingParticleElement {
|
||||
|
||||
private double size;
|
||||
private WingDesign wingDesign;
|
||||
// Colour each point by its distance from the spine instead of by time
|
||||
private boolean colorAlongWing;
|
||||
// Share of the points shown each tick, in percent; below 100 the wing twinkles
|
||||
private int density = 100;
|
||||
private double widest;
|
||||
|
||||
public Wing(ParticleElement particleElement, double size, WingDesign wingDesign) {
|
||||
super(particleElement);
|
||||
@@ -37,6 +42,15 @@ public class Wing extends DelegatingParticleElement {
|
||||
this.wingDesign = wingDesign;
|
||||
}
|
||||
|
||||
public Wing(ParticleElement particleElement, double size, WingDesign wingDesign, boolean colorAlongWing, int density) {
|
||||
this(particleElement, size, wingDesign);
|
||||
this.colorAlongWing = colorAlongWing;
|
||||
this.density = density;
|
||||
for (Vector vector : wingDesign.getVectors()) {
|
||||
widest = Math.max(widest, Math.abs(vector.getX()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick(ParticleTickData particleTickData) {
|
||||
BodyFrame frame = particleTickData.getFrame();
|
||||
@@ -45,19 +59,33 @@ public class Wing extends DelegatingParticleElement {
|
||||
double sneak = particleTickData.getPlayer().isSneaking() ? 0.5 : 0;
|
||||
Location base = particleTickData.getLocation();
|
||||
for (Vector dVector : wingDesign.getVectors()) {
|
||||
if (hidden()) continue;
|
||||
Vector local = frame.local(dVector.getX() * size, 0.6 + dVector.getY() * size - sneak, -0.5);
|
||||
particleElement.tick(particleTickData.withLocation(base.clone().add(local)));
|
||||
particleElement.tick(shaded(particleTickData, dVector).withLocation(base.clone().add(local)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (Vector dVector : wingDesign.getVectors()) {
|
||||
if (hidden()) continue;
|
||||
Vector vector = new Vector(dVector.getX() * size, 0.6 + dVector.getY() * size - (particleTickData.getPlayer().isSneaking() ? 0.5 : 0), 0.5);
|
||||
vector.rotateAroundY(Math.toRadians(particleTickData.getPlayer().getLocation().getYaw() * -1));
|
||||
vector.setX(-vector.getX());
|
||||
vector.setZ(-vector.getZ());
|
||||
Location location = particleTickData.getPlayer().getLocation().clone().add(vector);
|
||||
ParticleTickData current = particleTickData.withLocation(location);
|
||||
ParticleTickData current = shaded(particleTickData, dVector).withLocation(location);
|
||||
particleElement.tick(current);
|
||||
}
|
||||
}
|
||||
|
||||
// Full wings never draw a random number, so presets keep their exact look
|
||||
private boolean hidden() {
|
||||
return density < 100 && RANDOM.nextInt(100) >= density;
|
||||
}
|
||||
|
||||
private ParticleTickData shaded(ParticleTickData particleTickData, Vector point) {
|
||||
if (!colorAlongWing || widest == 0) {
|
||||
return particleTickData;
|
||||
}
|
||||
return particleTickData.withShade(Math.abs(point.getX()) / widest);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,9 @@ class EntryEditor {
|
||||
Map.entry(Designs.WING_IMAGE, Material.PHANTOM_MEMBRANE),
|
||||
Map.entry(Designs.WING_SIZE, Material.SCAFFOLDING),
|
||||
Map.entry(Designs.DRAWN_SHAPE, Material.FEATHER),
|
||||
Map.entry(Designs.WING_DETAIL, Material.AMETHYST_SHARD)
|
||||
Map.entry(Designs.WING_DETAIL, Material.AMETHYST_SHARD),
|
||||
Map.entry(Designs.WING_COLORING, Material.CYAN_DYE),
|
||||
Map.entry(Designs.WING_SPARKLE, Material.AMETHYST_CLUSTER)
|
||||
);
|
||||
|
||||
private record Context(Player player, SteamwarUser user, int index, int entryIndex, ParticleSlot slot, ParticleEntry entry) {
|
||||
|
||||
Reference in New Issue
Block a user