diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/ChoiceParameter.java b/LobbySystem/src/de/steamwar/lobby/particle/design/ChoiceParameter.java index 9df4eed0..76876caf 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/ChoiceParameter.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/ChoiceParameter.java @@ -21,17 +21,25 @@ package de.steamwar.lobby.particle.design; import com.google.gson.JsonElement; import com.google.gson.JsonPrimitive; +import de.steamwar.lobby.particle.ParticleRequirement; import lombok.Getter; import java.util.ArrayList; import java.util.List; +import java.util.function.Function; import java.util.function.Predicate; +import java.util.function.Supplier; @Getter public class ChoiceParameter extends Parameter { - // Internal choices are usable by presets but never offered in the builder or accepted from storage - public record Choice(String id, E value, boolean internal) { + // Internal choices are usable by presets but never offered in the builder or accepted from storage. Locked choices + // are offered with their requirement; the requirement is looked up lazily as it may live in a reward design. + public record Choice(String id, E value, boolean internal, Supplier requirement) { + + public Choice(String id, E value, boolean internal) { + this(id, value, internal, () -> ParticleRequirement.NO_REQUIRMENT); + } } private final List> choices; @@ -41,14 +49,18 @@ public class ChoiceParameter extends Parameter { this.choices = choices; } - public static > ChoiceParameter ofEnum(String key, String nameKey, E defaultValue, Predicate internal) { + public static > ChoiceParameter ofEnum(String key, String nameKey, E defaultValue, Predicate internal, Function requirement) { List> choices = new ArrayList<>(); for (E value : defaultValue.getDeclaringClass().getEnumConstants()) { - choices.add(new Choice<>(value.name(), value, internal.test(value))); + choices.add(new Choice<>(value.name(), value, internal.test(value), () -> requirement.apply(value))); } return new ChoiceParameter<>(key, nameKey, defaultValue, choices); } + public static > ChoiceParameter ofEnum(String key, String nameKey, E defaultValue, Predicate internal) { + return ofEnum(key, nameKey, defaultValue, internal, value -> ParticleRequirement.NO_REQUIRMENT); + } + public static > ChoiceParameter ofEnum(String key, String nameKey, E defaultValue) { return ofEnum(key, nameKey, defaultValue, value -> false); } @@ -57,6 +69,10 @@ public class ChoiceParameter extends Parameter { return choices.stream().filter(choice -> !choice.internal()).map(Choice::value).toList(); } + public ParticleRequirement requirement(E value) { + return choiceOf(value).requirement().get(); + } + @Override public JsonElement toJson(E value) { return new JsonPrimitive(choiceOf(value).id()); diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java b/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java index 892d6b4f..d2a05cf9 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java @@ -74,10 +74,11 @@ public class Designs { new ChoiceParameter.Choice<>("bat", WingShape.drawn(DrawnWings.BAT), false), new ChoiceParameter.Choice<>("butterfly", WingShape.drawn(DrawnWings.BUTTERFLY), false), new ChoiceParameter.Choice<>("fairy", WingShape.drawn(DrawnWings.FAIRY), false), - new ChoiceParameter.Choice<>("sw", WingShape.image(WingDesign.SW), true), - new ChoiceParameter.Choice<>("wgs", WingShape.image(WingDesign.WGS), true), - new ChoiceParameter.Choice<>("sword_crossed", WingShape.image(WingDesign.SWORD_CROSSED), true), - new ChoiceParameter.Choice<>("mwgl", WingShape.image(WingDesign.MWGL), true), + // Tournament wing images, unlocked by the placement that earns their reward + new ChoiceParameter.Choice<>("mwgl", WingShape.image(WingDesign.MWGL), false, () -> RewardDesigns.EVENT_PLACEMENT_MINI_WARGEAR_LIGA.getRequirement()), + new ChoiceParameter.Choice<>("sw", WingShape.image(WingDesign.SW), false, () -> RewardDesigns.EVENT_PLACEMENT_UNDERWATER_MWG.getRequirement()), + new ChoiceParameter.Choice<>("wgs", WingShape.image(WingDesign.WGS), false, () -> RewardDesigns.EVENT_PLACEMENT_WARGEAR_SEASON_2022.getRequirement()), + new ChoiceParameter.Choice<>("sword_crossed", WingShape.image(WingDesign.SWORD_CROSSED), false, () -> RewardDesigns.EVENT_PLACEMENT_WARGEAR_CLASH.getRequirement()), new ChoiceParameter.Choice<>("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 6e012ab0..78b10de8 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java @@ -132,7 +132,7 @@ public class EntryParameters { } } - public final ChoiceParameter PARTICLE = ChoiceParameter.ofEnum("particle", "PARTICLE_PARAM_PARTICLE", ParticleType.FLAME, type -> !type.isBuildable()); + public final ChoiceParameter PARTICLE = ChoiceParameter.ofEnum("particle", "PARTICLE_PARAM_PARTICLE", ParticleType.FLAME, type -> !type.isBuildable(), ParticleType::getRequirement); public final IntParameter COUNT = new IntParameter("count", "PARTICLE_PARAM_COUNT", 5, 1, 20); // Minecraft scatters particles around their point by about this many blocks; beyond half a block a design dissolves public final DoubleParameter SPREAD_X = new DoubleParameter("spreadX", "PARTICLE_PARAM_SPREAD_X", 0, 0, 0.5, 0.01); diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleType.java b/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleType.java index 4a4945e1..de64fe61 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleType.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/ParticleType.java @@ -53,7 +53,7 @@ public enum ParticleType { SMOKE(Material.COBWEB, Particle.SMOKE, Data.NONE, true), LARGE_SMOKE(Material.GRAY_WOOL, Particle.LARGE_SMOKE, Data.NONE, false), WHITE_SMOKE(Material.LIGHT_GRAY_DYE, Particle.WHITE_SMOKE, Data.NONE, true), - CAMPFIRE_COSY_SMOKE(Material.CAMPFIRE, Particle.CAMPFIRE_COSY_SMOKE, Data.NONE, false), + CAMPFIRE_COSY_SMOKE(Material.CAMPFIRE, Particle.CAMPFIRE_COSY_SMOKE, Data.NONE, true), CAMPFIRE_SIGNAL_SMOKE(Material.HAY_BLOCK, Particle.CAMPFIRE_SIGNAL_SMOKE, Data.NONE, false), ASH(Material.BASALT, Particle.ASH, Data.NONE, true), WHITE_ASH(Material.BONE_MEAL, Particle.WHITE_ASH, Data.NONE, true), @@ -180,10 +180,12 @@ public enum ParticleType { return data == Data.DUST || data == Data.COLOR || data == Data.COLOR_TRANSITION || data == Data.TRAIL; } - // Leaves drift down slowly and pile up around a player, so only the server team may build with them + // Leaves drift down slowly and pile up around a player, so only the server team may build with them. Cosy smoke is + // earned by taking part in Hells Bells. 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(); default -> ParticleRequirement.NO_REQUIRMENT; }; } diff --git a/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java b/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java index 0e98a990..c0b5db17 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java @@ -22,7 +22,6 @@ package de.steamwar.lobby.particle.gui; import de.steamwar.inventory.SWInventory; import de.steamwar.inventory.SWItem; import de.steamwar.lobby.LobbySystem; -import de.steamwar.lobby.particle.ParticleRequirement; import de.steamwar.lobby.particle.UnlockContext; import de.steamwar.lobby.particle.design.*; import de.steamwar.lobby.particle.slot.ParticleEntry; @@ -233,16 +232,19 @@ class EntryEditor { return lines; } - // Left click moves forward, right click backward + // Left click moves forward, right click backward, skipping locked options private void cycle(Context context, ChoiceParameter parameter, E current, int direction) { - List values = parameter.getBuildableValues(); + UnlockContext unlock = new UnlockContext(SteamwarUser.get(context.player().getUniqueId())); + List values = parameter.getBuildableValues().stream() + .filter(value -> value == current || parameter.requirement(value).test(unlock)) + .toList(); apply(context, parameter, values.get(Math.floorMod(values.indexOf(current) + direction, values.size()))); context.reopen(); } private void pick(Context context, ChoiceParameter parameter, E current) { Pickers.choice(context.player(), parameter, current, EntryEditor::choiceIcon, - value -> value instanceof ParticleType type ? type.getRequirement() : ParticleRequirement.NO_REQUIRMENT, picked -> { + parameter::requirement, picked -> { apply(context, parameter, picked); context.reopen(); }, context::reopen); diff --git a/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java b/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java index 12f3be23..11664735 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java @@ -175,12 +175,18 @@ public class ParticleEntry { return new Always(values.get(VISIBILITY).wrap(touch)); } - // Shown only when both the design 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; } - return !design.usesEntryParticle() || values.get(PARTICLE).getRequirement().test(context); + for (Parameter parameter : design.getParameters()) { + if (parameter instanceof ChoiceParameter choice && !((ChoiceParameter) choice).requirement(values.get(choice)).test(context)) { + return false; + } + } + return !design.usesEntryParticle() || PARTICLE.requirement(values.get(PARTICLE)).test(context); } // Particles each point spawns; designs that set their own point count replace the amount with 1