From 8e4730bd121e6b172ffce7dfa0325320a9663fe2 Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Mon, 26 Oct 2026 14:48:29 +0100 Subject: [PATCH] Turn reward touches into an unlockable Touch setting Every entry gets a Touch setting next to its design, offering the 16 touches the rewards carried, each unlocked by its reward. The reward designs that the builder can now make are removed; only the underwater rain cloud and the medium, hard and advanced egg hunt designs stay. Reward requirements move to Unlocks, shared by touches, wing images and cosy smoke. The trail duration moves to the particle row to make room in the design row. --- .../de/steamwar/lobby/LobbySystem.properties | 33 +++-- .../steamwar/lobby/LobbySystem_de.properties | 33 +++-- .../lobby/particle/design/Designs.java | 8 +- .../particle/design/EntryParameters.java | 4 +- .../lobby/particle/design/FixedDesign.java | 16 +-- .../lobby/particle/design/ParticleDesign.java | 5 - .../lobby/particle/design/ParticleType.java | 2 +- .../lobby/particle/design/RewardDesigns.java | 120 +----------------- .../steamwar/lobby/particle/design/Touch.java | 30 +++++ .../lobby/particle/design/Touches.java | 89 +++++++++++++ .../lobby/particle/design/Unlocks.java | 65 ++++++++++ .../lobby/particle/gui/EntryEditor.java | 19 ++- .../lobby/particle/gui/ParticleGuiText.java | 3 + .../lobby/particle/slot/ParticleEntry.java | 11 +- 14 files changed, 263 insertions(+), 175 deletions(-) create mode 100644 LobbySystem/src/de/steamwar/lobby/particle/design/Touch.java create mode 100644 LobbySystem/src/de/steamwar/lobby/particle/design/Touches.java create mode 100644 LobbySystem/src/de/steamwar/lobby/particle/design/Unlocks.java diff --git a/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties b/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties index e60bb545..b69d53b6 100644 --- a/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties +++ b/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties @@ -116,6 +116,7 @@ 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} @@ -137,6 +138,7 @@ PARTICLE_DESIGN_WING = §fWings PARTICLE_DESIGN_CLOUD = §fCloud PARTICLE_PARAM_PARTICLE = §fParticle +PARTICLE_PARAM_TOUCH = §fTouch PARTICLE_PARAM_COUNT = §fAmount PARTICLE_PARAM_SPREAD_X = §fSpread X PARTICLE_PARAM_SPREAD_Y = §fSpread Y @@ -198,6 +200,27 @@ PARTICLE_CHOICE_IMAGE_SWORD = §fSword PARTICLE_CHOICE_IMAGE_BAT = §fBat PARTICLE_CHOICE_IMAGE_BUTTERFLY = §fButterfly PARTICLE_CHOICE_IMAGE_FAIRY = §fFairy +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 @@ -373,21 +396,11 @@ PARTICLE_TEAM_PULSE_LOGO = §fPulse Logo PARTICLE_TEAM_PULSE_HEART_BEAT = §cHeart Beat PARTICLE_EVENT_ENCHANTING = §cEnchantment -PARTICLE_EVENT_CLOUD = §fClouds -PARTICLE_EVENT_SMOKE = §7Smoke -PARTICLE_EVENT_WATER = §bWater -PARTICLE_EVENT_LAVA = §cLava -PARTICLE_EVENT_WINGS = §fWings PARTICLE_EVENT_RAIN_CLOUD = §fRandom Raincloud -PARTICLE_EVENT_WGS = §fWGS -PARTICLE_EVENT_WARGEARCLASH = §fClash -PARTICLE_EGG_HUNT_EASY = §aGreenery PARTICLE_EGG_HUNT_MEDIUM = §eHide and Seek PARTICLE_EGG_HUNT_HARD = §cOrbit -PARTICLE_EGG_HUNT_EXTREME = §5Purple rain PARTICLE_EGG_HUNT_ADVANCED = §5Lift off -PARTICLE_EGG_HUNT_HALF = §fThe hunt is on JUMP_AND_RUN_PROGRESS = §e{0}§8/§f{1} §c{2} §7{3} JUMP_AND_RUN_CANCEL = {0} diff --git a/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties b/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties index d87f72f0..6130a069 100644 --- a/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties +++ b/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties @@ -116,6 +116,7 @@ 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} @@ -137,6 +138,7 @@ PARTICLE_DESIGN_WING = §fFlügel PARTICLE_DESIGN_CLOUD = §fWolke PARTICLE_PARAM_PARTICLE = §fPartikel +PARTICLE_PARAM_TOUCH = §fAkzent PARTICLE_PARAM_COUNT = §fAnzahl PARTICLE_PARAM_SPREAD_X = §fStreuung X PARTICLE_PARAM_SPREAD_Y = §fStreuung Y @@ -198,6 +200,27 @@ PARTICLE_CHOICE_IMAGE_SWORD = §fSchwert PARTICLE_CHOICE_IMAGE_BAT = §fFledermaus PARTICLE_CHOICE_IMAGE_BUTTERFLY = §fSchmetterling PARTICLE_CHOICE_IMAGE_FAIRY = §fFee +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 @@ -362,21 +385,11 @@ PARTICLE_PLAYER_10697_AURA = §7Rauchgranate PARTICLE_TEAM_PULSE_HEART_BEAT = §cHerzschlag PARTICLE_EVENT_ENCHANTING = §cVerzaubert -PARTICLE_EVENT_CLOUD = §fWolken -PARTICLE_EVENT_SMOKE = §7Rauch -PARTICLE_EVENT_WATER = §bWasser -PARTICLE_EVENT_LAVA = §cLava -PARTICLE_EVENT_WINGS = §fFlügel PARTICLE_EVENT_RAIN_CLOUD = §fRegenwolke -PARTICLE_EVENT_WGS = §fWGS -PARTICLE_EVENT_WARGEARCLASH = §fClash -PARTICLE_EGG_HUNT_EASY = §aGrünplfanzen PARTICLE_EGG_HUNT_MEDIUM = §eVersteckspiel PARTICLE_EGG_HUNT_HARD = §cOrbit -PARTICLE_EGG_HUNT_EXTREME = §5Lila regen PARTICLE_EGG_HUNT_ADVANCED = §5Abheben -PARTICLE_EGG_HUNT_HALF = §fDie Jagd ist eröffnet JUMP_AND_RUN_FINISHED = §aBeendet in {0} mit {1} Fails JUMP_AND_RUN_PERSONAL_BEST = §aNice! Du hast deinen Rekord um {0} verbessert! diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java b/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java index 9b3b6a66..69b3ca5e 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java @@ -75,10 +75,10 @@ public class Designs { 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, 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<>("mwgl", WingShape.image(WingDesign.MWGL, Material.IRON_SWORD), false, Unlocks.MINI_WARGEAR_LIGA_PLACEMENT), + new ChoiceParameter.Choice<>("sw", WingShape.image(WingDesign.SW, Material.CYAN_CARPET), false, Unlocks.UNDERWATER_MWG_PLACEMENT), + new ChoiceParameter.Choice<>("wgs", WingShape.image(WingDesign.WGS, Material.DIAMOND_HELMET), false, Unlocks.WARGEAR_SEASON_2022_PLACEMENT), + new ChoiceParameter.Choice<>("sword_crossed", WingShape.image(WingDesign.SWORD_CROSSED, Material.GOLDEN_SWORD), false, Unlocks.WARGEAR_CLASH_PLACEMENT), 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), diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java b/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java index 29ba76e0..b3c757dc 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java @@ -204,8 +204,10 @@ 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( - PARTICLE, COUNT, SPREAD_X, SPREAD_Y, SPREAD_Z, SPEED, COLORS, BLOCK, + TOUCH, 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/FixedDesign.java b/LobbySystem/src/de/steamwar/lobby/particle/design/FixedDesign.java index 8e8f552d..48d9e49b 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/FixedDesign.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/FixedDesign.java @@ -32,8 +32,6 @@ public class FixedDesign extends ParticleDesign { private final int points; private final Consumer defaults; private final Supplier shape; - private Supplier touch; - private int touchPoints; public FixedDesign(String id, Material icon, String nameKey, ParticleRequirement requirement, int points, Consumer defaults, Supplier shape) { super(id, icon, nameKey, DesignVisibility.REWARD, requirement); @@ -47,21 +45,9 @@ public class FixedDesign extends ParticleDesign { return shape.get(); } - // Adds the reward's unique touch; its points count towards the slot budget - public FixedDesign withTouch(int touchPoints, Supplier touch) { - this.touchPoints = touchPoints; - this.touch = touch; - return this; - } - - @Override - public ParticleElement touch() { - return touch == null ? null : touch.get(); - } - @Override public int points(ParameterValues values) { - return points + touchPoints; + return points; } @Override diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleDesign.java b/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleDesign.java index 1c74f090..ac0b175a 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleDesign.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleDesign.java @@ -72,11 +72,6 @@ public abstract class ParticleDesign { return false; } - // An extra the builder cannot make, shown next to the design's look and checked every tick so it never misses - // a jump or landing; null for designs without one - public ParticleElement touch() { - return null; - } // Called after a design setting changed, to adjust others that depend on it public void adjust(Parameter changed, ParameterValues values) { diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleType.java b/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleType.java index de64fe61..dc9e6826 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleType.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleType.java @@ -185,7 +185,7 @@ public enum ParticleType { public ParticleRequirement getRequirement() { return switch (this) { case CHERRY_LEAVES, PALE_OAK_LEAVES, TINTED_LEAVES -> ParticleRequirement.SERVER_TEAM; - case CAMPFIRE_COSY_SMOKE -> RewardDesigns.EVENT_PARTICIPATION_HELLS_BELLS.getRequirement(); + case CAMPFIRE_COSY_SMOKE -> Unlocks.HELLS_BELLS.get(); default -> ParticleRequirement.NO_REQUIRMENT; }; } diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/RewardDesigns.java b/LobbySystem/src/de/steamwar/lobby/particle/design/RewardDesigns.java index 4f73de22..b689a917 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/RewardDesigns.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/RewardDesigns.java @@ -19,107 +19,26 @@ package de.steamwar.lobby.particle.design; -import de.steamwar.lobby.particle.Gradient; import de.steamwar.lobby.particle.ParticleElement; 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 org.bukkit.entity.Player; import org.bukkit.util.Vector; -import java.time.Month; import java.util.List; import java.util.function.Consumer; import static de.steamwar.lobby.particle.design.EntryParameters.*; -// Designs earned in tournaments, events and the Easter egg hunt. Rewards whose look the basic designs can build get a -// touch the builder cannot make: bursts on jumping, landing or sneaking, footprints, a link to team-mates, a seasonal -// extra, a preset-only shape or aimed glyphs. +// Reward designs the builder cannot make. Other rewards unlock ingredients instead: wing images, particles and touches. @UtilityClass public class RewardDesigns { - private final Consumer MOVE = values -> { - }; private final Consumer ALWAYS = values -> values.set(TICK_MODE, TickMode.ALWAYS); - private final Consumer WINGS = values -> values - .set(TICK_MODE, TickMode.ALWAYS) - .set(INTERVAL, 20) - .set(GLIDING, Gliding.NOT_GLIDING); - public final ParticleDesign EVENT_PLACEMENT_WARGEAR_SEASON = new FixedDesign("event_placement_wargear_season", Material.ENCHANTING_TABLE, "PARTICLE_EVENT_ENCHANTING", - ParticleRequirement.eventPlacement(22, 12, 285, 54), 5, MOVE, - () -> new Cloud(new Circle(new LocationMutator(new SimpleParticle(Particle.ENCHANT, 0, 0, 0, 0.01), 0, 1.1, 0)))) - .withTouch(3, () -> new NonMoving(new Glyphs(Glyphs.Path.INTO_PLAYER, 3, 1.5))); - public final ParticleDesign EVENT_PLACEMENT_AIRSHIP = new FixedDesign("event_placement_airship", Material.SNOWBALL, "PARTICLE_EVENT_CLOUD", - ParticleRequirement.eventPlacement(26, 205, 9, 54, 120, 292), 5, MOVE, - () -> new Circle(new LocationMutator(new SimpleParticle(Particle.CLOUD, 0, 0, 0, 0.01), 0, 2.2, 0))) - .withTouch(1, () -> new EventBurst(EventBurst.Trigger.JUMP, new SimpleParticle(Particle.CLOUD, 0.3F, 0.05F, 0.3F, 0.02, 12))); - public final ParticleDesign EVENT_PLACEMENT_HELLS_BELLS = new FixedDesign("event_placement_hells_bells", Material.TNT_MINECART, "PARTICLE_EVENT_SMOKE", - ParticleRequirement.eventPlacement(28, 205, 9, 11), 5, MOVE, - () -> new Cloud(new Circle(new LocationMutator(new SimpleParticle(Particle.CAMPFIRE_COSY_SMOKE, 0, 0, 0, 0.01), 0, 2.2, 0)))); - public final ParticleDesign EVENT_PLACEMENT_UNDERWATER = new FixedDesign("event_placement_underwater", Material.PRISMARINE_SHARD, "PARTICLE_EVENT_WATER", - ParticleRequirement.eventPlacement(31, 9, 210, 520), 5, MOVE, - () -> new Cloud(new SimpleParticle(Particle.DRIPPING_WATER))) - .withTouch(1, () -> new EventBurst(EventBurst.Trigger.LAND, 1, new Ring(new SimpleParticle(Particle.SPLASH, 0, 0, 0, 0, 3), 1, 16))); - public final ParticleDesign EVENT_PLACEMENT_ADVENT_WAR_SHIP = new FixedDesign("event_placement_advent_war_ship", Material.PRISMARINE_CRYSTALS, "PARTICLE_EVENT_WATER", - ParticleRequirement.eventPlacement(32, 9, 205, 210), 10, ALWAYS, - () -> new LocationMutator(new Circle(new Group(new SimpleParticle(Particle.DRIPPING_WATER), new SimpleParticle(Particle.UNDERWATER, 0.2F, 0.2F, 0.2F, 0.01))), 0, 1.1, 0)) - .withTouch(4, () -> new Footprints(new SimpleParticle(Particle.FISHING, 0.05F, 0, 0.05F, 0, 1), 40)); - public final ParticleDesign EVENT_PLACEMENT_MINI_WARGEAR_LIGA = wings("event_placement_mini_wargear_liga", Material.IRON_SWORD, "PARTICLE_EVENT_WINGS", - ParticleRequirement.eventPlacement(33, 9, 34, 205), Particle.UNDERWATER, 0.15, WingDesign.MWGL); - public final ParticleDesign EVENT_PLACEMENT_ABSTURZ = wings("event_placement_absturz", Material.FEATHER, "PARTICLE_EVENT_WINGS", - ParticleRequirement.eventPlacement(34, 210, 205, 527, 286), Particle.CRIT, 0.15, WingDesign.SIMPLE) - .withTouch(1, () -> 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)))); - public final ParticleDesign EVENT_PLACEMENT_UNDERWATER_MWG = wings("event_placement_underwater_mwg", Material.CYAN_CARPET, "PARTICLE_EVENT_RAIN_CLOUD", - ParticleRequirement.eventPlacement(35, 9, 210), Particle.CRIT, 0.15, WingDesign.SW); - public final ParticleDesign EVENT_PLACEMENT_WARGEAR_SEASON_2022 = wings("event_placement_wargear_season_2022", Material.DIAMOND_HELMET, "PARTICLE_EVENT_WGS", - ParticleRequirement.eventPlacement(37, 285, 210, 122), Particle.FIREWORK, 0.15, WingDesign.WGS); - public final ParticleDesign EVENT_PLACEMENT_WARGEAR_CLASH = wings("event_placement_wargear_clash", Material.GOLDEN_SWORD, "PARTICLE_EVENT_WARGEARCLASH", - ParticleRequirement.eventPlacement(38, 210, 158, 167, 286), Particle.CRIT, 0.1, WingDesign.SWORD_CROSSED); - - // For taking part in any event - public final ParticleDesign EVENT_PARTICIPATION_WATER = new FixedDesign("event_participation_water", Material.WATER_BUCKET, "PARTICLE_EVENT_WATER", - ParticleRequirement.EVENT_PARTICIPATION, 5, ALWAYS, - () -> new Circle(new LocationMutator(new SimpleParticle(Particle.DRIPPING_WATER), 0, 1.1, 0))) - .withTouch(5, () -> new TeamLink("event_participation_water", new SimpleParticle(Particle.DRIPPING_WATER, 0, 0, 0, 0, 1))); - public final ParticleDesign EVENT_PARTICIPATION_LAVA = new FixedDesign("event_participation_lava", Material.LAVA_BUCKET, "PARTICLE_EVENT_LAVA", - ParticleRequirement.EVENT_PARTICIPATION, 5, ALWAYS, - () -> new Circle(new LocationMutator(new SimpleParticle(Particle.DRIPPING_LAVA), 0, 1.1, 0))) - .withTouch(1, () -> 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)))); - - public final ParticleDesign EVENT_PARTICIPATION_WARGEAR_SEASON = new FixedDesign("event_participation_wargear_season", Material.BOOK, "PARTICLE_EVENT_ENCHANTING", - ParticleRequirement.eventParticipation(22), 5, MOVE, - () -> new SimpleParticle(Particle.ENCHANT)) - .withTouch(1, () -> new EventBurst(EventBurst.Trigger.SNEAK, new Glyphs(Glyphs.Path.OUT_OF_PLAYER, 16, 1.5))); - public final ParticleDesign EVENT_PARTICIPATION_AIRSHIP = new FixedDesign("event_participation_airship", Material.SNOW_BLOCK, "PARTICLE_EVENT_CLOUD", - ParticleRequirement.eventParticipation(26), 5, MOVE, - () -> new SimpleParticle(Particle.CLOUD)) - .withTouch(4, () -> new Footprints(new SimpleParticle(Particle.CLOUD, 0.05F, 0, 0.05F, 0, 1), 40)); - public final ParticleDesign EVENT_PARTICIPATION_HELLS_BELLS = new FixedDesign("event_participation_hells_bells", Material.TNT, "PARTICLE_EVENT_SMOKE", - ParticleRequirement.eventParticipation(28), 5, MOVE, - () -> new Circle(new SimpleParticle(Particle.CAMPFIRE_COSY_SMOKE, 0, 0, 0, 0.01))); - public final ParticleDesign EVENT_PARTICIPATION_UNDERWATER = new FixedDesign("event_participation_underwater", Material.PRISMARINE_BRICKS, "PARTICLE_EVENT_WATER", - ParticleRequirement.eventParticipation(31), 5, MOVE, - () -> new SimpleParticle(Particle.DRIPPING_WATER)) - .withTouch(5, () -> new TeamLink("event_participation_underwater", new SimpleParticle(Particle.DRIPPING_WATER, 0, 0, 0, 0, 1))); - public final ParticleDesign EVENT_PARTICIPATION_ADVENT_WAR_SHIP = new FixedDesign("event_participation_advent_war_ship", Material.PRISMARINE_WALL, "PARTICLE_EVENT_WATER", - ParticleRequirement.eventParticipation(32), 10, MOVE, - () -> new Group(new SimpleParticle(Particle.DRIPPING_WATER), new SimpleParticle(Particle.UNDERWATER, 0.2F, 0.2F, 0.2F, 0.01))) - .withTouch(2, () -> new Seasonal(Month.DECEMBER, new LocationMutator(new SimpleParticle(Particle.SNOWFLAKE, 1.2F, 0.3F, 1.2F, 0.01, 2), 0, 2.4, 0))); - public final ParticleDesign EVENT_PARTICIPATION_MINI_WARGEAR_LIGA = new FixedDesign("event_participation_mini_wargear_liga", Material.PRISMARINE_SLAB, "PARTICLE_EVENT_WATER", - ParticleRequirement.eventParticipation(33), 5, MOVE, - () -> new Circle(new SimpleParticle(Particle.UNDERWATER, 0, 0, 0, 0))) - .withTouch(3, () -> new NonMoving(new PulseShimmer(new SimpleParticle(Particle.UNDERWATER, 0, 0, 0, 0, 1), 80, 2))); 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( @@ -136,25 +55,12 @@ public class RewardDesigns { rainCloud(null, Particle.SNOWFLAKE, 5), rainCloud(null, Particle.TOTEM_OF_UNDYING, 2) )); - public final ParticleDesign EVENT_PARTICIPATION_WARGEAR_SEASON_2022 = wings("event_participation_wargear_season_2022", Material.DIAMOND_SWORD, "PARTICLE_EVENT_WINGS", - ParticleRequirement.eventParticipation(37), Particle.DRAGON_BREATH, 0.15, WingDesign.COMPLEX) - .withTouch(2, () -> 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)); - - public final ParticleDesign EGG_HUNT_EASY = new FixedDesign("egg_hunt_easy", Material.LIME_CONCRETE_POWDER, "PARTICLE_EGG_HUNT_EASY", - ParticleRequirement.EGG_HUNT_EASY, 1, ALWAYS, - () -> new LocationMutator(new SimpleParticle(Particle.FALLING_SPORE_BLOSSOM, 0.5F, 0.1f, 0.5F, 1, 1), 0, 2.2, 0)) - .withTouch(4, () -> new Footprints(new SimpleParticle(Particle.SPORE_BLOSSOM_AIR, 0.05F, 0, 0.05F, 0, 1), 40)); public final ParticleDesign EGG_HUNT_MEDIUM = new FixedDesign("egg_hunt_medium", Material.YELLOW_CONCRETE_POWDER, "PARTICLE_EGG_HUNT_MEDIUM", ParticleRequirement.EGG_HUNT_MEDIUM, 5, ALWAYS.andThen(values -> values.set(GROUND, Ground.ON_GROUND).set(SNEAK, Sneak.SNEAKING)), () -> new SimpleParticle(Particle.GLOW_SQUID_INK, 0.4F, 0.9F, 0.4F, 0.01)); public final ParticleDesign EGG_HUNT_HARD = new FixedDesign("egg_hunt_hard", Material.RED_CONCRETE_POWDER, "PARTICLE_EGG_HUNT_HARD", ParticleRequirement.EGG_HUNT_HARD, 2, ALWAYS, () -> new LocationMutator(new Circle(new DoubleCircle(new DustParticle(Particle.DUST, 0, 0, 0, 0.01, 1, null), new DustParticle(Particle.DUST, 0, 0, 0, 0.01, 1, null)), 0.8, 0.5), 0, 0.5, 0)); - public final ParticleDesign EGG_HUNT_EXTREME = new FixedDesign("egg_hunt_extreme", Material.PURPLE_CONCRETE_POWDER, "PARTICLE_EGG_HUNT_EXTREME", - ParticleRequirement.EGG_HUNT_EXTREME, 1, ALWAYS, - () -> new LocationMutator(new SimpleParticle(Particle.FALLING_OBSIDIAN_TEAR, 0.5F, 0.1F, 0.5F, 1, 1), 0, 2.2, 0)) - .withTouch(1, () -> 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)))); public final ParticleDesign EGG_HUNT_ADVANCED = new FixedDesign("egg_hunt_advanced", Material.BLACK_CONCRETE_POWDER, "PARTICLE_EGG_HUNT_ADVANCED", ParticleRequirement.EGG_HUNT_ADVANCED, 2, ALWAYS.andThen(values -> values.set(SNEAK, Sneak.SNEAKING)), () -> new LocationMutator(new Group( @@ -165,19 +71,6 @@ public class RewardDesigns { player.setVelocity(player.getVelocity().add(new Vector(0, 0.1, 0))); } ), 0, -0.2, 0)); - // Hearts above the head while sneaking on the ground, a heart cloud ring while in the air - public final ParticleDesign EGG_HUNT_HALF = new FixedDesign("egg_hunt_half", Material.EGG, "PARTICLE_EGG_HUNT_HALF", - ParticleRequirement.EGG_HUNT_FOUND_HALF, 5, ALWAYS, - () -> new Group( - new Sneaking(new Floor(new LocationMutator(new SimpleParticle(Particle.HEART, 0, 0, 0, 0.01), 0, 1.7, 0))), - new NonFloor(new NonFlying(new LocationMutator(new Cloud(new Circle(new SimpleParticle(Particle.HEART, 0, 0, 0, 0.01))), 0, 0.5, 0))) - )) - .withTouch(1, () -> new NonMoving(new HearthBeat(new DustParticle(Particle.DUST, 0, 0, 0, 0, 1, new Gradient(java.awt.Color.RED)), 80))); - - private FixedDesign wings(String id, Material icon, String nameKey, ParticleRequirement requirement, Particle particle, double size, WingDesign wingDesign) { - return new FixedDesign(id, icon, nameKey, requirement, wingDesign.getVectors().length, WINGS, - () -> new Wing(new SimpleParticle(particle, 0, 0, 0, 0, 1), size, wingDesign)); - } // A cloud above the head that drips the given particle; rain is an optional second particle inside the cloud private ParticleElement rainCloud(Particle rain, Particle drip, int dripCount) { @@ -188,15 +81,6 @@ public class RewardDesigns { } public List all() { - return List.of( - EVENT_PLACEMENT_WARGEAR_SEASON, EVENT_PLACEMENT_AIRSHIP, EVENT_PLACEMENT_HELLS_BELLS, EVENT_PLACEMENT_UNDERWATER, - EVENT_PLACEMENT_ADVENT_WAR_SHIP, EVENT_PLACEMENT_MINI_WARGEAR_LIGA, EVENT_PLACEMENT_ABSTURZ, EVENT_PLACEMENT_UNDERWATER_MWG, - EVENT_PLACEMENT_WARGEAR_SEASON_2022, EVENT_PLACEMENT_WARGEAR_CLASH, - EVENT_PARTICIPATION_WATER, EVENT_PARTICIPATION_LAVA, - EVENT_PARTICIPATION_WARGEAR_SEASON, EVENT_PARTICIPATION_AIRSHIP, EVENT_PARTICIPATION_HELLS_BELLS, EVENT_PARTICIPATION_UNDERWATER, - EVENT_PARTICIPATION_ADVENT_WAR_SHIP, EVENT_PARTICIPATION_MINI_WARGEAR_LIGA, EVENT_PARTICIPATION_UNDERWATER_MWG, - EVENT_PARTICIPATION_WARGEAR_SEASON_2022, - EGG_HUNT_EASY, EGG_HUNT_MEDIUM, EGG_HUNT_HARD, EGG_HUNT_EXTREME, EGG_HUNT_ADVANCED, EGG_HUNT_HALF - ); + return List.of(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 new file mode 100644 index 00000000..d5584b91 --- /dev/null +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/Touch.java @@ -0,0 +1,30 @@ +/* + * 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 new file mode 100644 index 00000000..f00e7844 --- /dev/null +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/Touches.java @@ -0,0 +1,89 @@ +/* + * 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); + + 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))), + 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)), + 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/design/Unlocks.java b/LobbySystem/src/de/steamwar/lobby/particle/design/Unlocks.java new file mode 100644 index 00000000..c11dc7a8 --- /dev/null +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/Unlocks.java @@ -0,0 +1,65 @@ +/* + * 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.ParticleRequirement; +import lombok.experimental.UtilityClass; + +import java.util.function.Supplier; + +// Requirements of the reward ingredients: wing images, particles and touches. Each is created on first use, as event +// requirements look up the event's name. +@UtilityClass +public class Unlocks { + + public final Supplier WARGEAR_SEASON_PLACEMENT = lazy(() -> ParticleRequirement.eventPlacement(22, 12, 285, 54)); + public final Supplier AIRSHIP_PLACEMENT = lazy(() -> ParticleRequirement.eventPlacement(26, 205, 9, 54, 120, 292)); + public final Supplier UNDERWATER_PLACEMENT = lazy(() -> ParticleRequirement.eventPlacement(31, 9, 210, 520)); + public final Supplier ADVENT_WAR_SHIP_PLACEMENT = lazy(() -> ParticleRequirement.eventPlacement(32, 9, 205, 210)); + public final Supplier MINI_WARGEAR_LIGA_PLACEMENT = lazy(() -> ParticleRequirement.eventPlacement(33, 9, 34, 205)); + public final Supplier ABSTURZ_PLACEMENT = lazy(() -> ParticleRequirement.eventPlacement(34, 210, 205, 527, 286)); + public final Supplier UNDERWATER_MWG_PLACEMENT = lazy(() -> ParticleRequirement.eventPlacement(35, 9, 210)); + public final Supplier WARGEAR_SEASON_2022_PLACEMENT = lazy(() -> ParticleRequirement.eventPlacement(37, 285, 210, 122)); + public final Supplier WARGEAR_CLASH_PLACEMENT = lazy(() -> ParticleRequirement.eventPlacement(38, 210, 158, 167, 286)); + + public final Supplier ANY_EVENT = () -> ParticleRequirement.EVENT_PARTICIPATION; + public final Supplier WARGEAR_SEASON = lazy(() -> ParticleRequirement.eventParticipation(22)); + public final Supplier AIRSHIP = lazy(() -> ParticleRequirement.eventParticipation(26)); + public final Supplier HELLS_BELLS = lazy(() -> ParticleRequirement.eventParticipation(28)); + public final Supplier UNDERWATER = lazy(() -> ParticleRequirement.eventParticipation(31)); + public final Supplier ADVENT_WAR_SHIP = lazy(() -> ParticleRequirement.eventParticipation(32)); + public final Supplier MINI_WARGEAR_LIGA = lazy(() -> ParticleRequirement.eventParticipation(33)); + public final Supplier WARGEAR_SEASON_2022 = lazy(() -> ParticleRequirement.eventParticipation(37)); + + public final Supplier EGG_HUNT_EASY = () -> ParticleRequirement.EGG_HUNT_EASY; + public final Supplier EGG_HUNT_EXTREME = () -> ParticleRequirement.EGG_HUNT_EXTREME; + public final Supplier EGG_HUNT_HALF = () -> ParticleRequirement.EGG_HUNT_FOUND_HALF; + + private Supplier lazy(Supplier create) { + return new Supplier<>() { + private ParticleRequirement requirement; + + @Override + public ParticleRequirement get() { + if (requirement == null) requirement = create.get(); + return requirement; + } + }; + } +} diff --git a/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java b/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java index 772e25e3..a7139dd8 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java @@ -119,21 +119,24 @@ 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 + 1, parameterItem(context, PARTICLE)); + inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 2, parameterItem(context, PARTICLE)); ParticleType type = entry.getValues().get(PARTICLE); if (type.usesColors()) { - inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 2, parameterItem(context, COLORS)); + inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 3, parameterItem(context, COLORS)); } else if (type.usesBlock()) { - inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 2, parameterItem(context, BLOCK)); + inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 3, 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> trail = List.of(TRAIL_DURATION, TRAIL_TARGET_X, TRAIL_TARGET_Y, TRAIL_TARGET_Z); - for (int i = 0; i < trail.size(); i++) { - inventory.setItem(ROW_DESIGN * 9 + FIRST_SETTING + 3 + i, parameterItem(context, trail.get(i))); + 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))); } + particleRow.add(TRAIL_DURATION); } - List> particleRow = design.replacesAmount(entry.getValues()) ? List.of(SPEED, SPREAD_X, SPREAD_Y, SPREAD_Z) : List.of(COUNT, SPEED, SPREAD_X, SPREAD_Y, SPREAD_Z); row(inventory, context, ROW_PARTICLE, particleRow); } else { inventory.setItem(ROW_PARTICLE * 9 + FIRST_SETTING, new SWItem(Material.STRUCTURE_VOID, msg("PARTICLE_FIXED_LOOK", player), clickType -> { @@ -187,6 +190,7 @@ 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) { @@ -254,6 +258,7 @@ 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 efbdc2af..cddfaefe 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/gui/ParticleGuiText.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/gui/ParticleGuiText.java @@ -120,6 +120,9 @@ 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 478ac1a3..bd64690e 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java @@ -169,9 +169,9 @@ public class ParticleEntry { return new LocationMutator(element, offsetX, offsetY, offsetZ); } - // The design's touch with the entry's placement and visibility, or null; touches ignore conditions and timing + // The entry's touch with its placement and visibility, or null; touches ignore conditions and timing public ParticleElement buildTouch() { - ParticleElement touch = design.touch(); + ParticleElement touch = values.get(TOUCH).element().get(); if (touch == null) { return null; } @@ -181,12 +181,15 @@ public class ParticleEntry { return new Always(values.get(VISIBILITY).wrap(touch)); } - // Shown only when the design, its chosen options and, for designs that use it, the particle type are unlocked + // Shown only when the design, its chosen options, the touch 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; @@ -203,7 +206,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); - return perTick / values.get(INTERVAL); + return perTick / values.get(INTERVAL) + values.get(TOUCH).points(); } public JsonObject toJson() {