Settle open particle slot questions

Slots hold up to 9 entries, so the slot editor is one entry row plus the
bottom bar, and the server team may spawn 90 particles per tick. The
water and lava rings for taking part in any event return as reward
designs, and locked slots can be deleted from their read-only view.
This commit is contained in:
2026-10-26 10:33:15 +01:00
parent 4c6b5e654a
commit 8e23490b04
7 changed files with 42 additions and 15 deletions
@@ -56,6 +56,7 @@ PARTICLE_UNLOCKED_BY_SPECIFIC_TEAM_EASTER = §fTeam {0} (Easter Egg Hunt)
PARTICLE_UNLOCKED_BY_SPECIFIC_USER = §fUser {0}
PARTICLE_UNLOCKED_BY_SPECIFIC_USER_EASTER = §fUser {0} (Easter Egg Hunt)
PARTICLE_UNLOCKED_BY_SERVER_TEAM = §fServer Team
PARTICLE_UNLOCKED_BY_EVENT = §fEvent participation
PARTICLE_UNLOCKED_BY_EVENT_PLACEMENT = §f{0} 1., 2. or 3. Place
PARTICLE_UNLOCKED_BY_EVENT_PARTICIPATION = §f{0}
PARTICLE_UNLOCKED_BY_EASTER_EGG_HUNT_HALF = §fFind 45 Easter Eggs
@@ -363,6 +364,7 @@ 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
@@ -56,6 +56,7 @@ PARTICLE_UNLOCKED_BY_SPECIFIC_TEAM_EASTER = §fTeam {0} (Oster-Eierer-Suche)
PARTICLE_UNLOCKED_BY_SPECIFIC_USER = §fUser {0}
PARTICLE_UNLOCKED_BY_SPECIFIC_USER_EASTER = §fUser {0} (Oster-Eierer-Suche)
PARTICLE_UNLOCKED_BY_SERVER_TEAM = §fServerteam
PARTICLE_UNLOCKED_BY_EVENT = §fEventteilnahme
PARTICLE_UNLOCKED_BY_EVENT_PLACEMENT = §f{0} 1., 2. oder 3. Platz
PARTICLE_UNLOCKED_BY_EVENT_PARTICIPATION = §f{0}
PARTICLE_UNLOCKED_BY_EASTER_EGG_HUNT_HALF = §fFinde 45 Oster-Eierer
@@ -352,6 +353,7 @@ 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
@@ -77,6 +77,17 @@ public interface ParticleRequirement {
return context.getUser().getTeam() != 0;
}
};
ParticleRequirement EVENT_PARTICIPATION = new ParticleRequirement() {
@Override
public String getRequirementName(Player player) {
return LobbySystem.getMessage().parse("PARTICLE_UNLOCKED_BY_EVENT", player);
}
@Override
public boolean test(UnlockContext context) {
return !context.getEvents().isEmpty();
}
}.or(SERVER_TEAM);
ParticleRequirement EGG_HUNT_EASY = _easterEggHuntDifficulty(EggDifficulty.EASY);
ParticleRequirement EGG_HUNT_MEDIUM = _easterEggHuntDifficulty(EggDifficulty.MEDIUM);
ParticleRequirement EGG_HUNT_HARD = _easterEggHuntDifficulty(EggDifficulty.HARD);
@@ -72,6 +72,14 @@ public class RewardDesigns {
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)));
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)));
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));
@@ -157,6 +165,7 @@ public class RewardDesigns {
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,
@@ -39,11 +39,12 @@ import java.util.List;
import static de.steamwar.lobby.particle.gui.ParticleGuiText.*;
// Lists a slot's entries; slots the player has lost access to are shown read-only
// Lists a slot's entries; slots the player has lost access to are shown read-only but can still be deleted
@UtilityClass
public class SlotEditor {
private final int SIZE = 54;
// One row of entries above the bottom bar
private final int SIZE = (ParticleSlots.MAX_ENTRIES + 8) / 9 * 9 + 9;
private final int BACK = BottomBar.position(SIZE, BottomBar.BACK);
private final int STATUS = BottomBar.position(SIZE, BottomBar.STATUS);
private final int ADD_ENTRY = BottomBar.position(SIZE, BottomBar.ADD);
@@ -79,13 +80,22 @@ public class SlotEditor {
}
inventory.setItem(BACK, new SWItem(Material.ARROW, msg("PARTICLE_BACK", player), clickType -> ParticleMenu.open(player)));
inventory.setItem(COST, costItem(player, user, slot));
// Locked slots can still be deleted, so players can clear what they made before losing the rank
inventory.setItem(DELETE, new SWItem(Material.LAVA_BUCKET, msg("PARTICLE_SLOT_DELETE", player), List.of(msg("PARTICLE_SHIFT_TO_DELETE", player)), false, clickType -> {
if (!clickType.isShiftClick()) return;
if (lobbyPlayer.getActiveSlot() == index) {
lobbyPlayer.deselect();
}
lobbyPlayer.setSlot(index, null);
ParticleMenu.open(player);
}));
if (!editable) {
List<String> lore = new ArrayList<>(requirement(ParticleSlots.requirement(index), player));
inventory.setItem(STATUS, new SWItem(Material.BARRIER, msg("PARTICLE_LOCKED", player), lore, false, clickType -> {
}));
inventory.setItem(COST, costItem(player, user, slot));
BottomBar.fillUnused(inventory, SIZE, false);
fill(inventory, 0, SIZE);
fill(inventory, 0, SIZE);
inventory.open();
return;
}
@@ -124,15 +134,6 @@ public class SlotEditor {
save(player, index, slot);
open(player, index);
}, () -> open(player, index))));
inventory.setItem(COST, costItem(player, user, slot));
inventory.setItem(DELETE, new SWItem(Material.LAVA_BUCKET, msg("PARTICLE_SLOT_DELETE", player), List.of(msg("PARTICLE_SHIFT_TO_DELETE", player)), false, clickType -> {
if (!clickType.isShiftClick()) return;
if (lobbyPlayer.getActiveSlot() == index) {
lobbyPlayer.deselect();
}
lobbyPlayer.setSlot(index, null);
ParticleMenu.open(player);
}));
BottomBar.fillUnused(inventory, SIZE, false);
fill(inventory, 0, SIZE);
inventory.open();
@@ -95,6 +95,7 @@ public class ParticleSlot implements ParticleSet {
JsonElement entries = json.get("entries");
if (entries != null && entries.isJsonArray()) {
for (JsonElement element : entries.getAsJsonArray()) {
if (slot.entries.size() >= ParticleSlots.MAX_ENTRIES) break;
if (!element.isJsonObject()) continue;
ParticleEntry entry = ParticleEntry.fromJson(element.getAsJsonObject());
if (entry != null) {
@@ -33,12 +33,13 @@ import java.util.logging.Level;
public class ParticleSlots {
public final int COUNT = 7;
public final int MAX_ENTRIES = 10;
// One row in the slot editor
public final int MAX_ENTRIES = 9;
private final String KEY_PREFIX = "lobby-particle-slot-";
// Particles per tick a slot may spawn. A default entry costs 5; the largest preset costs 38.
public double maxCost(SteamwarUser user) {
return user.hasPerm(UserPerm.TEAM) ? 60 : 30;
return user.hasPerm(UserPerm.TEAM) ? 90 : 30;
}
// Slots 1-3 for everyone, 4-5 for team members, 6-7 for the server team