/* * 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.DrawnWings; import de.steamwar.lobby.particle.WingDesign; import de.steamwar.lobby.particle.elements.Circle; import de.steamwar.lobby.particle.elements.Cloud; import de.steamwar.lobby.particle.elements.Wing; import de.steamwar.lobby.particle.elements.custom.YOffset; import lombok.experimental.UtilityClass; import org.bukkit.Material; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @UtilityClass public class Designs { // Built on first use, so the design classes never depend on each other's initialisation order private Map registry; public final ParticleDesign SIMPLE = new ParticleDesign("simple", Material.BLAZE_POWDER, "PARTICLE_DESIGN_SIMPLE") { @Override public ParticleElement build(ParameterValues values, ParticleElement particle) { return particle; } }; public final DoubleParameter CIRCLE_RADIUS = new DoubleParameter("radius", "PARTICLE_PARAM_RADIUS", 1, 0.2, 3, 0.1); public final DoubleParameter CIRCLE_SPEED = new DoubleParameter("circleSpeed", "PARTICLE_PARAM_CIRCLE_SPEED", 1, -20, 20, 0.5); public final DoubleParameter CIRCLE_PHASE = new DoubleParameter("phase", "PARTICLE_PARAM_PHASE", 0, 0, 345, 15); public final DoubleParameter CIRCLE_RISE = new DoubleParameter("rise", "PARTICLE_PARAM_RISE", 0, 0, 3, 0.1); public final DoubleParameter CIRCLE_RISE_SPEED = new DoubleParameter("riseSpeed", "PARTICLE_PARAM_RISE_SPEED", 20, 0, 100, 5); public final BooleanParameter CIRCLE_BOUNCE = new BooleanParameter("bounce", "PARTICLE_PARAM_BOUNCE", true); public final BooleanParameter CIRCLE_INVERTED = new BooleanParameter("inverted", "PARTICLE_PARAM_INVERTED", false); public final ParticleDesign CIRCLE = new ParticleDesign("circle", Material.MAGMA_CREAM, "PARTICLE_DESIGN_CIRCLE", CIRCLE_RADIUS, CIRCLE_SPEED, CIRCLE_PHASE, CIRCLE_RISE, CIRCLE_RISE_SPEED, CIRCLE_BOUNCE, CIRCLE_INVERTED) { @Override public ParticleElement build(ParameterValues values, ParticleElement particle) { double rise = values.get(CIRCLE_RISE); if (rise > 0) { particle = new YOffset(particle, values.get(CIRCLE_RISE_SPEED), 0, rise, values.get(CIRCLE_INVERTED), values.get(CIRCLE_BOUNCE)); } return new Circle(particle, values.get(CIRCLE_RADIUS), values.get(CIRCLE_SPEED), values.get(CIRCLE_PHASE)); } }; public final ChoiceParameter WING_IMAGE = new ChoiceParameter<>("image", "PARTICLE_PARAM_WING_IMAGE", WingDesign.SIMPLE, List.of( new ChoiceParameter.Choice<>("simple", WingDesign.SIMPLE, false), new ChoiceParameter.Choice<>("complex", WingDesign.COMPLEX, false), new ChoiceParameter.Choice<>("sword", WingDesign.SWORD, false), new ChoiceParameter.Choice<>("sw", WingDesign.SW, true), new ChoiceParameter.Choice<>("wgs", WingDesign.WGS, true), new ChoiceParameter.Choice<>("sword_crossed", WingDesign.SWORD_CROSSED, true), new ChoiceParameter.Choice<>("mwgl", WingDesign.MWGL, true), new ChoiceParameter.Choice<>("eclipse", WingDesign.ECLIPSE, true), new ChoiceParameter.Choice<>("pl", WingDesign.PL, true), new ChoiceParameter.Choice<>("plompa_easter", WingDesign.PlompaEasterWings, true), new ChoiceParameter.Choice<>("ely_e", WingDesign.ELY_E, true), new ChoiceParameter.Choice<>("ely_l", WingDesign.ELY_L, true), new ChoiceParameter.Choice<>("ely_y", WingDesign.ELY_Y, true), new ChoiceParameter.Choice<>("ev", WingDesign.EV, true) )); 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) { @Override public ParticleElement build(ParameterValues values, ParticleElement particle) { return new Wing(particle, values.get(WING_SIZE), values.get(WING_IMAGE)); } @Override public int points(ParameterValues values) { return 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 @Override public void applyDefaults(ParameterValues values) { values.set(EntryParameters.COUNT, 1) .set(EntryParameters.SPEED, 0.0) .set(EntryParameters.TICK_MODE, EntryParameters.TickMode.ALWAYS) .set(EntryParameters.INTERVAL, 20) .set(EntryParameters.PLACEMENT, EntryParameters.Placement.BODY); } }; public final ChoiceParameter DRAWN_SHAPE = ChoiceParameter.ofEnum("shape", "PARTICLE_PARAM_DRAWN_SHAPE", DrawnWings.ANGEL); 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) { @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))); } @Override public int points(ParameterValues values) { return 2 * values.get(WING_DETAIL); } @Override public void applyDefaults(ParameterValues values) { WING.applyDefaults(values); } }; public final ParticleDesign CLOUD = new ParticleDesign("cloud", Material.WHITE_WOOL, "PARTICLE_DESIGN_CLOUD") { @Override public ParticleElement build(ParameterValues values, ParticleElement particle) { return new Cloud(particle); } }; private Map registry() { if (registry == null) { Map designs = new LinkedHashMap<>(); List.of(SIMPLE, CIRCLE, WING, DRAWN_WING, CLOUD).forEach(design -> register(designs, design)); RewardDesigns.all().forEach(design -> register(designs, design)); InternalDesigns.all().forEach(design -> register(designs, design)); registry = designs; } return registry; } private void register(Map designs, ParticleDesign design) { if (designs.put(design.getId(), design) != null) { throw new IllegalStateException("Duplicate particle design " + design.getId()); } } public ParticleDesign byId(String id) { return registry().get(id); } public List all() { return List.copyOf(registry().values()); } }