diff --git a/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties b/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties index b69d53b6..8e7388e6 100644 --- a/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties +++ b/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties @@ -116,7 +116,6 @@ PARTICLE_SLOT_COST = §7Particles per tick§8: §e{0}§8/§7{1} PARTICLE_ENTRY_EDITOR = §0{0} PARTICLE_ENTRY_DESIGN = §7Design§8: {0} PARTICLE_ENTRY_PARTICLE = §7Particle§8: {0} -PARTICLE_ENTRY_TOUCH = §7Touch§8: {0} PARTICLE_ENTRY_LOCKED = §cDesign locked, not shown PARTICLE_ENTRY_COST = §7Particles per tick§8: §e{0} PARTICLE_ENTRY_COST_SHARE = §7This entry§8: §e{0} @@ -136,9 +135,23 @@ PARTICLE_DESIGN_SIMPLE = §fSimple PARTICLE_DESIGN_CIRCLE = §fCircle PARTICLE_DESIGN_WING = §fWings PARTICLE_DESIGN_CLOUD = §fCloud +PARTICLE_DESIGN_BURST = §fBurst +PARTICLE_DESIGN_FOOTPRINTS = §fFootprints +PARTICLE_DESIGN_TEAM_LINK = §fTeam link +PARTICLE_DESIGN_PULSE_SHIMMER = §fShimmer +PARTICLE_DESIGN_HEART_BEAT = §fHeartbeat PARTICLE_PARAM_PARTICLE = §fParticle -PARTICLE_PARAM_TOUCH = §fTouch +PARTICLE_PARAM_BURST_TRIGGER = §fWhen +PARTICLE_PARAM_BURST_SHAPE = §fShape +PARTICLE_PARAM_BURST_RADIUS = §fRing radius +PARTICLE_PARAM_BURST_FALL = §fMinimum fall height +PARTICLE_PARAM_FOOTPRINT_LIFETIME = §fPrint lifetime (ticks) +PARTICLE_PARAM_FOOTPRINT_STEP = §fDistance between prints +PARTICLE_PARAM_LINK_SPACING = §fDistance between particles +PARTICLE_PARAM_PULSE_SPEED = §fPulse duration (ticks) +PARTICLE_PARAM_PULSE_ROTATION = §fRotation +PARTICLE_PARAM_HEART_BEAT_SPEED = §fBeat duration (ticks) PARTICLE_PARAM_COUNT = §fAmount PARTICLE_PARAM_SPREAD_X = §fSpread X PARTICLE_PARAM_SPREAD_Y = §fSpread Y @@ -204,28 +217,17 @@ PARTICLE_CHOICE_IMAGE_MWGL = §fMiniWarGear League PARTICLE_CHOICE_IMAGE_SW = §fSteamWar PARTICLE_CHOICE_IMAGE_WGS = §fWarGear Season PARTICLE_CHOICE_IMAGE_SWORD_CROSSED = §fCrossed Swords -PARTICLE_CHOICE_TOUCH_NONE = §7None -PARTICLE_CHOICE_TOUCH_JUMP_CLOUD = §fCloud puff on jumping -PARTICLE_CHOICE_TOUCH_JUMP_WINGS = §5Wing beat on jumping -PARTICLE_CHOICE_TOUCH_LANDING_SPLASH = §bSplash on landing -PARTICLE_CHOICE_TOUCH_CRASH_LANDING = §cCrash landing -PARTICLE_CHOICE_TOUCH_LAVA_LANDING = §6Lava on landing -PARTICLE_CHOICE_TOUCH_OBSIDIAN_LANDING = §5Obsidian tears on landing -PARTICLE_CHOICE_TOUCH_GLYPH_BURST = §dGlyph burst on sneaking -PARTICLE_CHOICE_TOUCH_WET_FOOTPRINTS = §bWet footprints -PARTICLE_CHOICE_TOUCH_CLOUD_FOOTPRINTS = §fCloud footprints -PARTICLE_CHOICE_TOUCH_BLOSSOM_FOOTPRINTS = §aBlossom footprints -PARTICLE_CHOICE_TOUCH_WATER_LINK = §bWater link to others with it -PARTICLE_CHOICE_TOUCH_BUBBLE_LINK = §3Bubble link to others with it -PARTICLE_CHOICE_TOUCH_GLYPH_PULL = §dGlyphs while standing still -PARTICLE_CHOICE_TOUCH_STILL_SHIMMER = §3Shimmer while standing still -PARTICLE_CHOICE_TOUCH_HEARTBEAT = §cHeartbeat while standing still -PARTICLE_CHOICE_TOUCH_DECEMBER_SNOW = §fSnow in December PARTICLE_CHOICE_COLORING_OVER_TIME = §fChange over time PARTICLE_CHOICE_COLORING_ALONG_WING = §fFrom the back to the tips PARTICLE_CHOICE_MOTION_NONE = §fNone PARTICLE_CHOICE_MOTION_FLAP_SLOW = §fFlap slowly PARTICLE_CHOICE_MOTION_FLAP_FAST = §fFlap quickly +PARTICLE_CHOICE_MOTION_BEAT_ON_JUMP = §fBeat on jumping +PARTICLE_CHOICE_TRIGGER_JUMP = §fOn jumping +PARTICLE_CHOICE_TRIGGER_LAND = §fOn landing +PARTICLE_CHOICE_TRIGGER_SNEAK = §fOn sneaking +PARTICLE_CHOICE_BURSTSHAPE_PUFF = §fPuff +PARTICLE_CHOICE_BURSTSHAPE_RING = §fRing # Particle types PARTICLE_TYPE_DUST = §fDust diff --git a/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties b/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties index 6130a069..0fe6c771 100644 --- a/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties +++ b/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties @@ -116,7 +116,6 @@ PARTICLE_SLOT_COST = §7Partikel pro Tick§8: §e{0}§8/§7{1} PARTICLE_ENTRY_EDITOR = §0{0} PARTICLE_ENTRY_DESIGN = §7Design§8: {0} PARTICLE_ENTRY_PARTICLE = §7Partikel§8: {0} -PARTICLE_ENTRY_TOUCH = §7Akzent§8: {0} PARTICLE_ENTRY_LOCKED = §cDesign gesperrt, wird nicht angezeigt PARTICLE_ENTRY_COST = §7Partikel pro Tick§8: §e{0} PARTICLE_ENTRY_COST_SHARE = §7Dieser Eintrag§8: §e{0} @@ -136,9 +135,23 @@ PARTICLE_DESIGN_SIMPLE = §fEinfach PARTICLE_DESIGN_CIRCLE = §fKreis PARTICLE_DESIGN_WING = §fFlügel PARTICLE_DESIGN_CLOUD = §fWolke +PARTICLE_DESIGN_BURST = §fStoß +PARTICLE_DESIGN_FOOTPRINTS = §fFußspuren +PARTICLE_DESIGN_TEAM_LINK = §fTeamband +PARTICLE_DESIGN_PULSE_SHIMMER = §fSchimmer +PARTICLE_DESIGN_HEART_BEAT = §fHerzschlag PARTICLE_PARAM_PARTICLE = §fPartikel -PARTICLE_PARAM_TOUCH = §fAkzent +PARTICLE_PARAM_BURST_TRIGGER = §fWann +PARTICLE_PARAM_BURST_SHAPE = §fForm +PARTICLE_PARAM_BURST_RADIUS = §fRingradius +PARTICLE_PARAM_BURST_FALL = §fMindestfallhöhe +PARTICLE_PARAM_FOOTPRINT_LIFETIME = §fSpurdauer (Ticks) +PARTICLE_PARAM_FOOTPRINT_STEP = §fAbstand der Spuren +PARTICLE_PARAM_LINK_SPACING = §fAbstand der Partikel +PARTICLE_PARAM_PULSE_SPEED = §fPulsdauer (Ticks) +PARTICLE_PARAM_PULSE_ROTATION = §fDrehung +PARTICLE_PARAM_HEART_BEAT_SPEED = §fSchlagdauer (Ticks) PARTICLE_PARAM_COUNT = §fAnzahl PARTICLE_PARAM_SPREAD_X = §fStreuung X PARTICLE_PARAM_SPREAD_Y = §fStreuung Y @@ -204,28 +217,17 @@ PARTICLE_CHOICE_IMAGE_MWGL = §fMiniWarGear Liga PARTICLE_CHOICE_IMAGE_SW = §fSteamWar PARTICLE_CHOICE_IMAGE_WGS = §fWarGear Saison PARTICLE_CHOICE_IMAGE_SWORD_CROSSED = §fGekreuzte Schwerter -PARTICLE_CHOICE_TOUCH_NONE = §7Keiner -PARTICLE_CHOICE_TOUCH_JUMP_CLOUD = §fWolke beim Springen -PARTICLE_CHOICE_TOUCH_JUMP_WINGS = §5Flügelschlag beim Springen -PARTICLE_CHOICE_TOUCH_LANDING_SPLASH = §bSpritzer beim Landen -PARTICLE_CHOICE_TOUCH_CRASH_LANDING = §cBruchlandung -PARTICLE_CHOICE_TOUCH_LAVA_LANDING = §6Lava beim Landen -PARTICLE_CHOICE_TOUCH_OBSIDIAN_LANDING = §5Obsidiantränen beim Landen -PARTICLE_CHOICE_TOUCH_GLYPH_BURST = §dGlyphen beim Schleichen -PARTICLE_CHOICE_TOUCH_WET_FOOTPRINTS = §bNasse Fußspuren -PARTICLE_CHOICE_TOUCH_CLOUD_FOOTPRINTS = §fWolkenfußspuren -PARTICLE_CHOICE_TOUCH_BLOSSOM_FOOTPRINTS = §aBlütenfußspuren -PARTICLE_CHOICE_TOUCH_WATER_LINK = §bWasserband zu anderen damit -PARTICLE_CHOICE_TOUCH_BUBBLE_LINK = §3Blasenband zu anderen damit -PARTICLE_CHOICE_TOUCH_GLYPH_PULL = §dGlyphen im Stillstand -PARTICLE_CHOICE_TOUCH_STILL_SHIMMER = §3Schimmer im Stillstand -PARTICLE_CHOICE_TOUCH_HEARTBEAT = §cHerzschlag im Stillstand -PARTICLE_CHOICE_TOUCH_DECEMBER_SNOW = §fSchnee im Dezember PARTICLE_CHOICE_COLORING_OVER_TIME = §fWechseln mit der Zeit PARTICLE_CHOICE_COLORING_ALONG_WING = §fVom Rücken zu den Spitzen PARTICLE_CHOICE_MOTION_NONE = §fKeine PARTICLE_CHOICE_MOTION_FLAP_SLOW = §fLangsam schlagen PARTICLE_CHOICE_MOTION_FLAP_FAST = §fSchnell schlagen +PARTICLE_CHOICE_MOTION_BEAT_ON_JUMP = §fSchlag beim Springen +PARTICLE_CHOICE_TRIGGER_JUMP = §fBeim Springen +PARTICLE_CHOICE_TRIGGER_LAND = §fBeim Landen +PARTICLE_CHOICE_TRIGGER_SNEAK = §fBeim Schleichen +PARTICLE_CHOICE_BURSTSHAPE_PUFF = §fWolke +PARTICLE_CHOICE_BURSTSHAPE_RING = §fRing # Particle types PARTICLE_TYPE_DUST = §fStaub diff --git a/LobbySystem/src/de/steamwar/lobby/particle/CompiledSet.java b/LobbySystem/src/de/steamwar/lobby/particle/CompiledSet.java index c56d6b78..3a3b707b 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/CompiledSet.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/CompiledSet.java @@ -44,10 +44,6 @@ public class CompiledSet { for (ParticleEntry entry : particleSet.getEntries()) { if (entry.isUnlocked(context)) { compiledSet.add(entry.build()); - ParticleElement touch = entry.buildTouch(); - if (touch != null) { - compiledSet.add(touch); - } } } return compiledSet; diff --git a/LobbySystem/src/de/steamwar/lobby/particle/ParticleRequirement.java b/LobbySystem/src/de/steamwar/lobby/particle/ParticleRequirement.java index f5aa0186..d0ada80e 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/ParticleRequirement.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/ParticleRequirement.java @@ -244,6 +244,24 @@ public interface ParticleRequirement { }.or(SERVER_TEAM); } + // Met by meeting any of the requirements; the lore lists them one per line + static ParticleRequirement anyOf(ParticleRequirement... requirements) { + return new ParticleRequirement() { + @Override + public String getRequirementName(Player player) { + return java.util.Arrays.stream(requirements).map(requirement -> requirement.getRequirementName(player)).filter(Objects::nonNull).collect(Collectors.joining("\n")); + } + + @Override + public boolean matches(UnlockContext context) { + for (ParticleRequirement requirement : requirements) { + if (requirement.test(context)) return true; + } + return false; + } + }; + } + // The alternative is checked first, as it is usually the cheap server team check default ParticleRequirement or(ParticleRequirement particleRequirement) { return new ParticleRequirement() { diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java b/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java index 7cb0c534..35f6be40 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java @@ -20,6 +20,7 @@ package de.steamwar.lobby.particle.design; import de.steamwar.lobby.particle.ParticleElement; +import de.steamwar.lobby.particle.ParticleRequirement; import de.steamwar.lobby.particle.DrawnWings; import de.steamwar.lobby.particle.WingDesign; import de.steamwar.lobby.particle.elements.Circle; @@ -102,7 +103,8 @@ public class Designs { public final ChoiceParameter 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 ChoiceParameter WING_MOTION = ChoiceParameter.ofEnum("motion", "PARTICLE_PARAM_WING_MOTION", Wing.Motion.NONE, motion -> motion == Wing.Motion.JUMP_BEAT); + public final ChoiceParameter WING_MOTION = ChoiceParameter.ofEnum("motion", "PARTICLE_PARAM_WING_MOTION", Wing.Motion.NONE, motion -> false, + motion -> motion == Wing.Motion.BEAT_ON_JUMP ? Unlocks.WARGEAR_SEASON_2022.get() : ParticleRequirement.NO_REQUIRMENT); // Moving wings need to be redrawn often to look smooth; still ones are fine once a second private final int MOVING_WING_INTERVAL = 2; private final int STILL_WING_INTERVAL = 20; @@ -112,14 +114,12 @@ public class Designs { public ParticleElement build(ParameterValues values, ParticleElement particle) { WingShape shape = values.get(WING_SHAPE); return new Wing(particle, values.get(WING_SIZE), shape.design(values.get(WING_DETAIL)), - values.get(WING_COLORING) == WingColoring.ALONG_WING, values.get(WING_SPARKLE), values.get(WING_MOTION), - values.get(EntryParameters.TOUCH) == Touches.JUMP_WINGS); + values.get(WING_COLORING) == WingColoring.ALONG_WING, values.get(WING_SPARKLE), values.get(WING_MOTION)); } - // The wing beat touch makes these wings beat instead of drawing wings of its own @Override - public boolean absorbsTouch(Touch touch) { - return touch == Touches.JUMP_WINGS; + public boolean redrawsAfterJump(ParameterValues values) { + return values.get(WING_MOTION) == Wing.Motion.BEAT_ON_JUMP; } @Override @@ -141,7 +141,8 @@ public class Designs { @Override public void adjust(Parameter changed, ParameterValues values) { if (changed != WING_MOTION) return; - boolean moving = values.get(WING_MOTION) != Wing.Motion.NONE; + // A beat on jumping is redrawn every tick only while it beats + boolean moving = values.get(WING_MOTION) == Wing.Motion.FLAP_SLOW || values.get(WING_MOTION) == Wing.Motion.FLAP_FAST; int interval = values.get(EntryParameters.INTERVAL); if (moving && interval > MOVING_WING_INTERVAL) { values.set(EntryParameters.INTERVAL, MOVING_WING_INTERVAL); diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java b/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java index b3c757dc..29ba76e0 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java @@ -204,10 +204,8 @@ public class EntryParameters { public final ChoiceParameter SNEAK = ChoiceParameter.ofEnum("sneak", "PARTICLE_PARAM_SNEAK", Sneak.ANY); public final ChoiceParameter VISIBILITY = ChoiceParameter.ofEnum("visibility", "PARTICLE_PARAM_VISIBILITY", Visibility.EVERYONE); - public final ChoiceParameter TOUCH = new ChoiceParameter<>("touch", "PARTICLE_PARAM_TOUCH", Touches.NONE, Touches.choices()); - public final List> ALL = List.of( - TOUCH, PARTICLE, COUNT, SPREAD_X, SPREAD_Y, SPREAD_Z, SPEED, COLORS, BLOCK, + PARTICLE, COUNT, SPREAD_X, SPREAD_Y, SPREAD_Z, SPEED, COLORS, BLOCK, TRAIL_DURATION, TRAIL_TARGET_X, TRAIL_TARGET_Y, TRAIL_TARGET_Z, OFFSET_X, OFFSET_Y, OFFSET_Z, PLACEMENT, INTERVAL, TICK_MODE, MOVEMENT, GLIDING, GROUND, SNEAK, VISIBILITY diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleDesign.java b/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleDesign.java index 4d834e86..2ceb1f73 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleDesign.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleDesign.java @@ -72,9 +72,9 @@ public abstract class ParticleDesign { return false; } - - // Whether the design shows the touch itself instead of the touch drawing its own particles - public boolean absorbsTouch(Touch touch) { + // Whether the design must be drawn every tick for a moment after a jump, whatever its interval; these extra + // redraws do not count towards the budget + public boolean redrawsAfterJump(ParameterValues values) { return false; } diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/RewardDesigns.java b/LobbySystem/src/de/steamwar/lobby/particle/design/RewardDesigns.java index b689a917..5a74216e 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/RewardDesigns.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/RewardDesigns.java @@ -22,6 +22,12 @@ package de.steamwar.lobby.particle.design; import de.steamwar.lobby.particle.ParticleElement; import de.steamwar.lobby.particle.ParticleRequirement; import de.steamwar.lobby.particle.elements.*; +import de.steamwar.lobby.particle.elements.custom.HearthBeat; +import de.steamwar.lobby.particle.elements.custom.PulseShimmer; +import de.steamwar.lobby.particle.elements.touch.EventBurst; +import de.steamwar.lobby.particle.elements.touch.Footprints; +import de.steamwar.lobby.particle.elements.touch.Ring; +import de.steamwar.lobby.particle.elements.touch.TeamLink; import lombok.experimental.UtilityClass; import org.bukkit.Material; import org.bukkit.Particle; @@ -33,12 +39,142 @@ import java.util.function.Consumer; import static de.steamwar.lobby.particle.design.EntryParameters.*; -// Reward designs the builder cannot make. Other rewards unlock ingredients instead: wing images, particles and touches. +// Designs unlocked by event and egg hunt rewards. Most are styled like the basic designs, with a particle of the +// player's choice; the others have a fixed look. Rewards whose look the basic designs can already build unlock +// ingredients instead: wing images, a wing motion and particles. @UtilityClass public class RewardDesigns { private final Consumer ALWAYS = values -> values.set(TICK_MODE, TickMode.ALWAYS); + public enum BurstShape { + PUFF, + RING, + } + + private final int RING_POINTS = 16; + + public final ChoiceParameter BURST_TRIGGER = ChoiceParameter.ofEnum("trigger", "PARTICLE_PARAM_BURST_TRIGGER", EventBurst.Trigger.JUMP, trigger -> false, + trigger -> switch (trigger) { + case JUMP -> Unlocks.AIRSHIP_PLACEMENT.get(); + case LAND -> ParticleRequirement.anyOf(Unlocks.UNDERWATER_PLACEMENT.get(), Unlocks.ABSTURZ_PLACEMENT.get(), Unlocks.ANY_EVENT.get(), Unlocks.EGG_HUNT_EXTREME.get()); + case SNEAK -> Unlocks.WARGEAR_SEASON.get(); + }); + public final ChoiceParameter BURST_SHAPE = ChoiceParameter.ofEnum("burstShape", "PARTICLE_PARAM_BURST_SHAPE", BurstShape.PUFF); + public final DoubleParameter BURST_RADIUS = new DoubleParameter("burstRadius", "PARTICLE_PARAM_BURST_RADIUS", 1, 0.3, 2, 0.1); + public final DoubleParameter BURST_FALL = new DoubleParameter("minimumFall", "PARTICLE_PARAM_BURST_FALL", 1, 0, 10, 0.5); + + // Once at the feet when the player jumps, lands or starts sneaking + public final ParticleDesign BURST = new ParticleDesign("burst", Material.FIREWORK_ROCKET, "PARTICLE_DESIGN_BURST", DesignVisibility.REWARD, + ParticleRequirement.anyOf(Unlocks.AIRSHIP_PLACEMENT.get(), Unlocks.UNDERWATER_PLACEMENT.get(), Unlocks.ABSTURZ_PLACEMENT.get(), + Unlocks.ANY_EVENT.get(), Unlocks.EGG_HUNT_EXTREME.get(), Unlocks.WARGEAR_SEASON.get()), + BURST_TRIGGER, BURST_SHAPE, BURST_RADIUS, BURST_FALL) { + @Override + public ParticleElement build(ParameterValues values, ParticleElement particle) { + ParticleElement burst = values.get(BURST_SHAPE) == BurstShape.RING ? new Ring(particle, values.get(BURST_RADIUS), RING_POINTS) : particle; + double minimumFall = values.get(BURST_TRIGGER) == EventBurst.Trigger.LAND ? values.get(BURST_FALL) : 0; + return new EventBurst(values.get(BURST_TRIGGER), minimumFall, burst); + } + + // Shows only now and then, so it counts as a single point + @Override + public int points(ParameterValues values) { + return 1; + } + + @Override + public boolean showsSetting(Parameter parameter, ParameterValues values) { + if (parameter == BURST_RADIUS) return values.get(BURST_SHAPE) == BurstShape.RING; + if (parameter == BURST_FALL) return values.get(BURST_TRIGGER) == EventBurst.Trigger.LAND; + return true; + } + + @Override + public void applyDefaults(ParameterValues values) { + values.set(TICK_MODE, TickMode.ALWAYS).set(COUNT, 8).set(SPREAD_X, 0.3).set(SPREAD_Y, 0.05).set(SPREAD_Z, 0.3).set(SPEED, 0.02); + } + }; + + public final IntParameter FOOTPRINT_LIFETIME = new IntParameter("printLifetime", "PARTICLE_PARAM_FOOTPRINT_LIFETIME", 40, 10, 100); + public final DoubleParameter FOOTPRINT_STEP = new DoubleParameter("printStep", "PARTICLE_PARAM_FOOTPRINT_STEP", 0.6, 0.3, 2, 0.1); + // Blocks per tick while walking, to estimate how many prints are shown at once + private final double WALKING_SPEED = 0.22; + + public final ParticleDesign FOOTPRINTS = new ParticleDesign("footprints", Material.LEATHER_BOOTS, "PARTICLE_DESIGN_FOOTPRINTS", DesignVisibility.REWARD, + ParticleRequirement.anyOf(Unlocks.ADVENT_WAR_SHIP_PLACEMENT.get(), Unlocks.ADVENT_WAR_SHIP.get(), Unlocks.AIRSHIP.get(), Unlocks.EGG_HUNT_EASY.get()), + FOOTPRINT_LIFETIME, FOOTPRINT_STEP) { + @Override + public ParticleElement build(ParameterValues values, ParticleElement particle) { + return new Footprints(particle, values.get(FOOTPRINT_LIFETIME), values.get(FOOTPRINT_STEP)); + } + + @Override + public int points(ParameterValues values) { + return (int) Math.ceil(values.get(FOOTPRINT_LIFETIME) * WALKING_SPEED / values.get(FOOTPRINT_STEP)); + } + + @Override + public void applyDefaults(ParameterValues values) { + values.set(TICK_MODE, TickMode.ALWAYS).set(COUNT, 1).set(SPREAD_X, 0.05).set(SPREAD_Z, 0.05).set(SPEED, 0.0); + } + }; + + public final DoubleParameter LINK_SPACING = new DoubleParameter("linkSpacing", "PARTICLE_PARAM_LINK_SPACING", 0.5, 0.3, 2, 0.1); + + // A line to every nearby player who shows this design too + public final ParticleDesign TEAM_LINK = new ParticleDesign("team_link", Material.LEAD, "PARTICLE_DESIGN_TEAM_LINK", DesignVisibility.REWARD, + ParticleRequirement.anyOf(Unlocks.ANY_EVENT.get(), Unlocks.UNDERWATER.get()), + LINK_SPACING) { + @Override + public ParticleElement build(ParameterValues values, ParticleElement particle) { + return new TeamLink("team_link", particle, values.get(LINK_SPACING)); + } + + // A line to one partner half the range away + @Override + public int points(ParameterValues values) { + return (int) Math.ceil(TeamLink.RANGE / 2 / values.get(LINK_SPACING)); + } + + @Override + public void applyDefaults(ParameterValues values) { + values.set(TICK_MODE, TickMode.ALWAYS).set(COUNT, 1).set(SPEED, 0.0); + } + }; + + public final ParticleDesign SHIMMER = new ParticleDesign("shimmer", Material.AMETHYST_CLUSTER, "PARTICLE_DESIGN_PULSE_SHIMMER", DesignVisibility.REWARD, + ParticleRequirement.anyOf(Unlocks.MINI_WARGEAR_LIGA.get(), Unlocks.WARGEAR_SEASON_PLACEMENT.get()), + InternalDesigns.PULSE_SPEED, InternalDesigns.PULSE_ROTATION) { + @Override + public ParticleElement build(ParameterValues values, ParticleElement particle) { + return new PulseShimmer(particle, values.get(InternalDesigns.PULSE_SPEED), values.get(InternalDesigns.PULSE_ROTATION)); + } + + @Override + public int points(ParameterValues values) { + return 3; + } + + @Override + public void applyDefaults(ParameterValues values) { + values.set(TICK_MODE, TickMode.ALWAYS).set(MOVEMENT, Movement.STANDING_STILL).set(COUNT, 1).set(SPEED, 0.0); + } + }; + + public final ParticleDesign HEARTBEAT = new ParticleDesign("heartbeat", Material.RED_DYE, "PARTICLE_DESIGN_HEART_BEAT", DesignVisibility.REWARD, + Unlocks.EGG_HUNT_HALF.get(), + InternalDesigns.HEART_BEAT_SPEED) { + @Override + public ParticleElement build(ParameterValues values, ParticleElement particle) { + return new HearthBeat(particle, values.get(InternalDesigns.HEART_BEAT_SPEED)); + } + + @Override + public void applyDefaults(ParameterValues values) { + values.set(TICK_MODE, TickMode.ALWAYS).set(MOVEMENT, Movement.STANDING_STILL).set(COUNT, 1).set(SPEED, 0.0); + } + }; + public final ParticleDesign EVENT_PARTICIPATION_UNDERWATER_MWG = new FixedDesign("event_participation_underwater_mwg", Material.BLUE_CARPET, "PARTICLE_EVENT_RAIN_CLOUD", ParticleRequirement.eventParticipation(35), 15, ALWAYS, () -> new RandomParticle( @@ -81,6 +217,6 @@ public class RewardDesigns { } public List all() { - return List.of(EVENT_PARTICIPATION_UNDERWATER_MWG, EGG_HUNT_MEDIUM, EGG_HUNT_HARD, EGG_HUNT_ADVANCED); + return List.of(BURST, FOOTPRINTS, TEAM_LINK, SHIMMER, HEARTBEAT, EVENT_PARTICIPATION_UNDERWATER_MWG, EGG_HUNT_MEDIUM, EGG_HUNT_HARD, EGG_HUNT_ADVANCED); } } diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/Touch.java b/LobbySystem/src/de/steamwar/lobby/particle/design/Touch.java deleted file mode 100644 index d5584b91..00000000 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/Touch.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2026 SteamWar.de-Serverteam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package de.steamwar.lobby.particle.design; - -import de.steamwar.lobby.particle.ParticleElement; -import de.steamwar.lobby.particle.ParticleRequirement; -import org.bukkit.Material; - -import java.util.function.Supplier; - -// An extra effect an entry can carry next to its design, unlocked by a reward. Touches run every tick, independent -// of the entry's conditions and timing, so their points count fully towards the slot budget. -public record Touch(String id, Material icon, int points, Supplier requirement, Supplier element) { -} diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/Touches.java b/LobbySystem/src/de/steamwar/lobby/particle/design/Touches.java deleted file mode 100644 index 0123c800..00000000 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/Touches.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2026 SteamWar.de-Serverteam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ -package de.steamwar.lobby.particle.design; - -import de.steamwar.lobby.particle.Gradient; -import de.steamwar.lobby.particle.ParticleRequirement; -import de.steamwar.lobby.particle.WingDesign; -import de.steamwar.lobby.particle.elements.*; -import de.steamwar.lobby.particle.elements.custom.HearthBeat; -import de.steamwar.lobby.particle.elements.custom.NonMoving; -import de.steamwar.lobby.particle.elements.custom.PulseShimmer; -import de.steamwar.lobby.particle.elements.touch.*; -import lombok.experimental.UtilityClass; -import org.bukkit.Material; -import org.bukkit.Particle; - -import java.time.Month; -import java.util.List; - -// The touches of the entries' touch setting, each unlocked by the event or egg hunt reward that used to carry it -@UtilityClass -public class Touches { - - public final Touch NONE = new Touch("none", Material.GRAY_DYE, 0, () -> ParticleRequirement.NO_REQUIRMENT, () -> null); - - // On a Wings entry the entry's own wings beat; on others it draws dragon breath wings for the beat - public final Touch JUMP_WINGS = new Touch("jump_wings", Material.DRAGON_BREATH, 2, Unlocks.WARGEAR_SEASON_2022, - () -> new Delayed(new Wing(new SimpleParticle(Particle.DRAGON_BREATH, 0, 0, 0, 0, 1), 0.15, WingDesign.COMPLEX, false, 100, Wing.Motion.JUMP_BEAT), 2)); - - private final List ALL = List.of( - NONE, - // Bursts on jumping, landing or sneaking - new Touch("jump_cloud", Material.SNOWBALL, 1, Unlocks.AIRSHIP_PLACEMENT, - () -> new EventBurst(EventBurst.Trigger.JUMP, new SimpleParticle(Particle.CLOUD, 0.3F, 0.05F, 0.3F, 0.02, 12))), - JUMP_WINGS, - new Touch("landing_splash", Material.PRISMARINE_SHARD, 1, Unlocks.UNDERWATER_PLACEMENT, - () -> new EventBurst(EventBurst.Trigger.LAND, 1, new Ring(new SimpleParticle(Particle.SPLASH, 0, 0, 0, 0, 3), 1, 16))), - new Touch("crash_landing", Material.FEATHER, 1, Unlocks.ABSTURZ_PLACEMENT, - () -> new EventBurst(EventBurst.Trigger.LAND, 3, new Group(new SimpleParticle(Particle.EXPLOSION, 0, 0, 0, 0, 1), - new Ring(new SimpleParticle(Particle.CRIT, 0, 0.1F, 0, 0.1, 2), 1.2, 16)))), - new Touch("lava_landing", Material.LAVA_BUCKET, 1, Unlocks.ANY_EVENT, - () -> new EventBurst(EventBurst.Trigger.LAND, 1, new Group(new SimpleParticle(Particle.LAVA, 0.2F, 0, 0.2F, 0, 4), - new SimpleParticle(Particle.SMOKE, 0.2F, 0.1F, 0.2F, 0.02, 6)))), - new Touch("obsidian_landing", Material.CRYING_OBSIDIAN, 1, Unlocks.EGG_HUNT_EXTREME, - () -> new EventBurst(EventBurst.Trigger.LAND, 1, new Group(new Ring(new SimpleParticle(Particle.WITCH, 0, 0.05F, 0, 0, 2), 1, 16), - new SimpleParticle(Particle.LANDING_OBSIDIAN_TEAR, 0.4F, 0, 0.4F, 0, 6)))), - new Touch("glyph_burst", Material.BOOK, 1, Unlocks.WARGEAR_SEASON, - () -> new EventBurst(EventBurst.Trigger.SNEAK, new Glyphs(Glyphs.Path.OUT_OF_PLAYER, 16, 1.5))), - // Footprints - new Touch("wet_footprints", Material.PRISMARINE_CRYSTALS, 4, Unlocks.ADVENT_WAR_SHIP_PLACEMENT, - () -> new Footprints(new SimpleParticle(Particle.FISHING, 0.05F, 0, 0.05F, 0, 1), 40)), - new Touch("cloud_footprints", Material.SNOW_BLOCK, 4, Unlocks.AIRSHIP, - () -> new Footprints(new SimpleParticle(Particle.CLOUD, 0.05F, 0, 0.05F, 0, 1), 40)), - new Touch("blossom_footprints", Material.SPORE_BLOSSOM, 4, Unlocks.EGG_HUNT_EASY, - () -> new Footprints(new SimpleParticle(Particle.SPORE_BLOSSOM_AIR, 0.05F, 0, 0.05F, 0, 1), 40)), - // Lines to nearby players with the same touch - new Touch("water_link", Material.WATER_BUCKET, 5, Unlocks.ANY_EVENT, - () -> new TeamLink("water_link", new SimpleParticle(Particle.DRIPPING_WATER, 0, 0, 0, 0, 1))), - new Touch("bubble_link", Material.PRISMARINE_BRICKS, 5, Unlocks.UNDERWATER, - () -> new TeamLink("bubble_link", new SimpleParticle(Particle.BUBBLE_POP, 0, 0, 0, 0, 1))), - // While standing still - new Touch("glyph_pull", Material.ENCHANTING_TABLE, 3, Unlocks.WARGEAR_SEASON_PLACEMENT, - () -> new NonMoving(new Glyphs(Glyphs.Path.INTO_PLAYER, 3, 1.5))), - new Touch("still_shimmer", Material.PRISMARINE_SLAB, 3, Unlocks.MINI_WARGEAR_LIGA, - () -> new NonMoving(new PulseShimmer(new SimpleParticle(Particle.UNDERWATER, 0, 0, 0, 0, 1), 80, 2))), - new Touch("heartbeat", Material.POPPY, 1, Unlocks.EGG_HUNT_HALF, - () -> new NonMoving(new HearthBeat(new DustParticle(Particle.DUST, 0, 0, 0, 0, 1, new Gradient(java.awt.Color.RED)), 80))), - // Seasonal - new Touch("december_snow", Material.POWDER_SNOW_BUCKET, 2, Unlocks.ADVENT_WAR_SHIP, - () -> new Seasonal(Month.DECEMBER, new LocationMutator(new SimpleParticle(Particle.SNOWFLAKE, 1.2F, 0.3F, 1.2F, 0.01, 2), 0, 2.4, 0))) - ); - - public List> choices() { - return ALL.stream().map(touch -> new ChoiceParameter.Choice<>(touch.id(), touch, false, touch.requirement())).toList(); - } -} diff --git a/LobbySystem/src/de/steamwar/lobby/particle/elements/Wing.java b/LobbySystem/src/de/steamwar/lobby/particle/elements/Wing.java index 45c2d377..273a44a5 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/elements/Wing.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/elements/Wing.java @@ -33,8 +33,8 @@ public class Wing extends DelegatingParticleElement { NONE, FLAP_SLOW, FLAP_FAST, - // One wing beat after each jump and none otherwise; only for a reward - JUMP_BEAT, + // One wing beat after each jump; unlocked by a reward + BEAT_ON_JUMP, } // Wings stand slightly open when idle and open further the faster the player moves @@ -51,8 +51,6 @@ public class Wing extends DelegatingParticleElement { // Share of the points shown each tick, in percent; below 100 the wing twinkles private int density = 100; private Motion motion = Motion.NONE; - // An extra beat after each jump on top of the motion - private boolean beatOnJump; private double widest; public Wing(ParticleElement particleElement, double size, WingDesign wingDesign) { @@ -71,16 +69,8 @@ public class Wing extends DelegatingParticleElement { } } - public Wing(ParticleElement particleElement, double size, WingDesign wingDesign, boolean colorAlongWing, int density, Motion motion, boolean beatOnJump) { - this(particleElement, size, wingDesign, colorAlongWing, density, motion); - this.beatOnJump = beatOnJump; - } - @Override public void tick(ParticleTickData particleTickData) { - if (motion == Motion.JUMP_BEAT && BodyMotion.ticksSinceJump(particleTickData.getPlayer()) > JUMP_BEAT_TICKS) { - return; - } double ticks = particleTickData.getDeg() * 10; double open = Math.toRadians(openDegrees(particleTickData, ticks)); double cos = Math.cos(open), sin = Math.sin(open); @@ -115,13 +105,10 @@ public class Wing extends DelegatingParticleElement { private double openDegrees(ParticleTickData particleTickData, double ticks) { double speed = Math.min(1, BodyMotion.speed(particleTickData.getPlayer()) / FULL_OPEN_SPEED); double open = IDLE_OPEN_DEGREES + (MOVING_OPEN_DEGREES - IDLE_OPEN_DEGREES) * speed; - if (beatOnJump) { - open += jumpBeat(particleTickData); - } return switch (motion) { case FLAP_SLOW -> open + FLAP_DEGREES * Math.sin(2 * Math.PI * ticks / 20); case FLAP_FAST -> open + FLAP_DEGREES * Math.sin(2 * Math.PI * ticks / 10); - case JUMP_BEAT -> open + jumpBeat(particleTickData); + case BEAT_ON_JUMP -> open + jumpBeat(particleTickData); default -> open; }; } diff --git a/LobbySystem/src/de/steamwar/lobby/particle/elements/touch/Footprints.java b/LobbySystem/src/de/steamwar/lobby/particle/elements/touch/Footprints.java index 22fe879c..9182cd0c 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/elements/touch/Footprints.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/elements/touch/Footprints.java @@ -30,21 +30,21 @@ import java.util.Deque; import java.util.Map; import java.util.WeakHashMap; -// Leaves a print every half step on the ground and keeps showing it for a while after the player walked on +// Leaves a print every given distance on the ground and keeps showing it for a while after the player walked on public class Footprints extends DelegatingParticleElement { - private static final double STEP = 0.6; - private record Print(Location location, int age) { } private final int lifetime; + private final double step; // Weak keys drop players once they quit private final Map> prints = new WeakHashMap<>(); - public Footprints(ParticleElement particleElement, int lifetime) { + public Footprints(ParticleElement particleElement, int lifetime, double step) { super(particleElement); this.lifetime = lifetime; + this.step = step; } @Override @@ -54,7 +54,7 @@ public class Footprints extends DelegatingParticleElement { Deque playerPrints = prints.computeIfAbsent(player, key -> new ArrayDeque<>()); Location feet = player.getLocation(); Print last = playerPrints.peekLast(); - if (player.isOnGround() && (last == null || last.location().getWorld() != feet.getWorld() || last.location().distanceSquared(feet) > STEP * STEP)) { + if (player.isOnGround() && (last == null || last.location().getWorld() != feet.getWorld() || last.location().distanceSquared(feet) > step * step)) { playerPrints.addLast(new Print(feet, 0)); } diff --git a/LobbySystem/src/de/steamwar/lobby/particle/elements/touch/Glyphs.java b/LobbySystem/src/de/steamwar/lobby/particle/elements/touch/Glyphs.java deleted file mode 100644 index 62dfa1af..00000000 --- a/LobbySystem/src/de/steamwar/lobby/particle/elements/touch/Glyphs.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2026 SteamWar.de-Serverteam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package de.steamwar.lobby.particle.elements.touch; - -import de.steamwar.lobby.particle.ParticleElement; -import de.steamwar.lobby.particle.ParticleTickData; -import org.bukkit.Location; -import org.bukkit.Particle; -import org.bukkit.util.Vector; - -// Enchanting glyphs that fly along a path. Spawned with an amount of 0, the offset becomes the glyph's motion: it -// appears at location + offset and flies back to the location, like glyphs flying into an enchanting table. -public class Glyphs implements ParticleElement { - - public enum Path { - // From random points on the ground around the player into the chest - INTO_PLAYER, - // From the chest outwards to a ring around the player - OUT_OF_PLAYER, - } - - private static final double CHEST = 1.2; - - private final Path path; - private final int amount; - private final double radius; - - public Glyphs(Path path, int amount, double radius) { - this.path = path; - this.amount = amount; - this.radius = radius; - } - - @Override - public void tick(ParticleTickData particleTickData) { - Location chest = particleTickData.getPlayer().getLocation().add(0, CHEST, 0); - for (int i = 0; i < amount; i++) { - Location target; - Vector from; - if (path == Path.INTO_PLAYER) { - double angle = RANDOM.nextDouble() * 2 * Math.PI; - double distance = radius * (0.5 + RANDOM.nextDouble() / 2); - target = chest; - from = new Vector(Math.cos(angle) * distance, -CHEST, Math.sin(angle) * distance); - } else { - double angle = 2 * Math.PI * i / amount; - Vector out = new Vector(Math.cos(angle) * radius, 0, Math.sin(angle) * radius); - target = chest.clone().add(out); - from = out.multiply(-1); - } - Location spawn = target; - display(particleTickData, player -> player.spawnParticle(Particle.ENCHANT, spawn, 0, from.getX(), from.getY(), from.getZ(), 1)); - } - } -} diff --git a/LobbySystem/src/de/steamwar/lobby/particle/elements/touch/Seasonal.java b/LobbySystem/src/de/steamwar/lobby/particle/elements/touch/Seasonal.java deleted file mode 100644 index d7528a88..00000000 --- a/LobbySystem/src/de/steamwar/lobby/particle/elements/touch/Seasonal.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is a part of the SteamWar software. - * - * Copyright (C) 2026 SteamWar.de-Serverteam - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package de.steamwar.lobby.particle.elements.touch; - -import de.steamwar.lobby.particle.ParticleElement; -import de.steamwar.lobby.particle.ParticleTickData; -import de.steamwar.lobby.particle.elements.DelegatingParticleElement; - -import java.time.LocalDate; -import java.time.Month; - -// Only shows during the given month -public class Seasonal extends DelegatingParticleElement { - - private final Month month; - - public Seasonal(Month month, ParticleElement particleElement) { - super(particleElement); - this.month = month; - } - - @Override - public void tick(ParticleTickData particleTickData) { - if (LocalDate.now().getMonth() == month) { - particleElement.tick(particleTickData); - } - } -} diff --git a/LobbySystem/src/de/steamwar/lobby/particle/elements/touch/TeamLink.java b/LobbySystem/src/de/steamwar/lobby/particle/elements/touch/TeamLink.java index 63412c12..96b5c020 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/elements/touch/TeamLink.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/elements/touch/TeamLink.java @@ -34,18 +34,19 @@ import java.util.WeakHashMap; // A line of particles between nearby players who show the same reward. Each pair is drawn by only one of them. public class TeamLink extends DelegatingParticleElement { - private static final double RANGE = 8; - private static final double SPACING = 0.5; + public static final double RANGE = 8; private static final double CHEST = 1.2; // Per reward, who showed it in which tick private static final Map> SHOWING = new HashMap<>(); private final String reward; + private final double spacing; - public TeamLink(String reward, ParticleElement particleElement) { + public TeamLink(String reward, ParticleElement particleElement, double spacing) { super(particleElement); this.reward = reward; + this.spacing = spacing; } @Override @@ -64,7 +65,7 @@ public class TeamLink extends DelegatingParticleElement { if (to.getWorld() != from.getWorld() || to.distanceSquared(from) > RANGE * RANGE) continue; Vector step = to.toVector().subtract(from.toVector()); - int points = (int) Math.ceil(step.length() / SPACING); + int points = (int) Math.ceil(step.length() / spacing); step.multiply(1.0 / points); for (int i = 1; i < points; i++) { particleElement.tick(particleTickData.withLocation(from.clone().add(step.clone().multiply(i)))); diff --git a/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java b/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java index a7139dd8..8184f74a 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java @@ -119,21 +119,20 @@ class EntryEditor { inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING, new SWItem(design.getIcon(), designName(design, player), List.of(msg("PARTICLE_VALUE_CLICK", player)), false, clickType -> Pickers.design(player, design, picked -> changeDesign(context, picked), context::reopen))); - inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 1, parameterItem(context, TOUCH)); if (design.usesEntryParticle()) { - inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 2, parameterItem(context, PARTICLE)); + inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 1, parameterItem(context, PARTICLE)); ParticleType type = entry.getValues().get(PARTICLE); if (type.usesColors()) { - inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 3, parameterItem(context, COLORS)); + inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 2, parameterItem(context, COLORS)); } else if (type.usesBlock()) { - inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 3, parameterItem(context, BLOCK)); + inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 2, parameterItem(context, BLOCK)); } // The trail target follows the particle; its duration goes to the end of the particle row List> particleRow = new ArrayList<>(design.replacesAmount(entry.getValues()) ? List.of(SPEED, SPREAD_X, SPREAD_Y, SPREAD_Z) : List.of(COUNT, SPEED, SPREAD_X, SPREAD_Y, SPREAD_Z)); if (type.isTrail()) { List> target = List.of(TRAIL_TARGET_X, TRAIL_TARGET_Y, TRAIL_TARGET_Z); for (int i = 0; i < target.size(); i++) { - inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 4 + i, parameterItem(context, target.get(i))); + inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 3 + i, parameterItem(context, target.get(i))); } particleRow.add(TRAIL_DURATION); } @@ -190,7 +189,6 @@ class EntryEditor { if (parameter == COLORS) icon = Material.RED_DYE; if (parameter == BLOCK) icon = (Material) value; if (value instanceof WingShape shape) icon = shape.getIcon(); - if (value instanceof Touch touch) icon = touch.icon(); return new SWItem(icon, name(parameter.getNameKey(), player), lore, false, clickType -> { if (parameter instanceof BooleanParameter toggle) { @@ -258,7 +256,6 @@ class EntryEditor { private Material choiceIcon(Object value) { if (value instanceof ParticleType type) return type.getIcon(); if (value instanceof WingShape shape) return shape.getIcon(); - if (value instanceof Touch touch) return touch.icon(); if (value instanceof Material material) return material; return Material.LEVER; } diff --git a/LobbySystem/src/de/steamwar/lobby/particle/gui/ParticleGuiText.java b/LobbySystem/src/de/steamwar/lobby/particle/gui/ParticleGuiText.java index cddfaefe..b93526b8 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/gui/ParticleGuiText.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/gui/ParticleGuiText.java @@ -107,7 +107,7 @@ class ParticleGuiText { String name = requirement.getRequirementName(player); if (name != null) { lore.add(msg("PARTICLE_UNLOCKED_BY", player)); - lore.add(name); + lore.addAll(List.of(name.split("\n"))); } return lore; } @@ -120,9 +120,6 @@ class ParticleGuiText { if (entry.getDesign().usesEntryParticle()) { lore.add(msg("PARTICLE_ENTRY_PARTICLE", player, particleName(values.get(PARTICLE), player))); } - if (values.get(TOUCH) != Touches.NONE) { - lore.add(msg("PARTICLE_ENTRY_TOUCH", player, choiceName(TOUCH, values.get(TOUCH), player))); - } lore.add("§8- " + choiceName(TICK_MODE, values.get(TICK_MODE), player)); addCondition(lore, MOVEMENT, values.get(MOVEMENT), Movement.ANY, player); addCondition(lore, GLIDING, values.get(GLIDING), Gliding.ANY, player); diff --git a/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java b/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java index 2623497c..358f380f 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java @@ -99,9 +99,7 @@ public class ParticleEntry { element = values.get(VISIBILITY).wrap(element); int interval = values.get(INTERVAL); - if (interval > 1 && design.absorbsTouch(values.get(TOUCH))) { - // The jump beat needs every tick to look smooth; outside of it the usual interval applies, and the - // extra redraws are not counted towards the budget + if (interval > 1 && design.redrawsAfterJump(values)) { element = new AfterJump(element, new Delayed(element, interval), Wing.JUMP_BEAT_TICKS); } else if (interval > 1) { element = new Delayed(element, interval); @@ -174,30 +172,12 @@ public class ParticleEntry { return new LocationMutator(element, offsetX, offsetY, offsetZ); } - // The entry's touch with its placement and visibility, or null; touches ignore conditions and timing - public ParticleElement buildTouch() { - if (design.absorbsTouch(values.get(TOUCH))) { - return null; - } - ParticleElement touch = values.get(TOUCH).element().get(); - if (touch == null) { - return null; - } - if (values.get(PLACEMENT) == Placement.BODY) { - touch = new BodyRelative(touch); - } - return new Always(values.get(VISIBILITY).wrap(touch)); - } - - // Shown only when the design, its chosen options, the touch and, for designs that use it, the particle type are unlocked + // Shown only when the design, its chosen options and, for designs that use it, the particle type are unlocked @SuppressWarnings("unchecked") public boolean isUnlocked(UnlockContext context) { if (!design.getRequirement().test(context)) { return false; } - if (!TOUCH.requirement(values.get(TOUCH)).test(context)) { - return false; - } for (Parameter parameter : design.getParameters()) { if (parameter instanceof ChoiceParameter choice && !((ChoiceParameter) choice).requirement(values.get(choice)).test(context)) { return false; @@ -214,8 +194,7 @@ public class ParticleEntry { // Particle positions spawned per tick, used for the slot budget public double cost() { double perTick = design.usesEntryParticle() ? (double) design.points(values) * amount() : design.points(values); - int touchPoints = design.absorbsTouch(values.get(TOUCH)) ? 0 : values.get(TOUCH).points(); - return perTick / values.get(INTERVAL) + touchPoints; + return perTick / values.get(INTERVAL); } public JsonObject toJson() {