From e71278b49520d5f1e555ed0ec2e454d0ef63b66c Mon Sep 17 00:00:00 2001 From: ellieisjelly Date: Thu, 4 Jan 2024 19:15:57 -0300 Subject: [PATCH] Initial role picking --- .../Sabotage/game/map/SabotageMap.java | 14 ++-- .../Sabotage/game/phase/SabotageActive.java | 76 ++++++++++++++++++- .../Sabotage/game/phase/SabotageWaiting.java | 1 - .../resources/data/sabotage/lang/en_us.json | 7 +- 4 files changed, 84 insertions(+), 14 deletions(-) diff --git a/src/main/java/me/ellieis/Sabotage/game/map/SabotageMap.java b/src/main/java/me/ellieis/Sabotage/game/map/SabotageMap.java index 271141f..014daca 100644 --- a/src/main/java/me/ellieis/Sabotage/game/map/SabotageMap.java +++ b/src/main/java/me/ellieis/Sabotage/game/map/SabotageMap.java @@ -20,13 +20,13 @@ public class SabotageMap { private final MapTemplate template; - private final Stream spawns; + private final List spawns; private final Map playerSpawnPos = new HashMap<>(); public SabotageMap(MapTemplate template) { this.template = template; - this.spawns = template.getMetadata().getRegions("spawn"); - if (this.spawns == null) { + this.spawns = template.getMetadata().getRegions("spawn").toList(); + if (this.spawns.isEmpty()) { throw new GameOpenException(Text.literal("Failed to load spawns")); } } @@ -35,7 +35,7 @@ public MapTemplate getTemplate() { return this.template; } - public Stream getSpawns() { + public List getSpawns() { return this.spawns; } @@ -44,16 +44,14 @@ public Map getPlayerSpawns() { } public void spawnEntity(Entity entity) { - List spawnList = spawns.toList(); - TemplateRegion spawn = spawnList.get(new Random().nextInt(spawnList.size())); + TemplateRegion spawn = spawns.get(new Random().nextInt(spawns.size())); Vec3d pos = spawn.getBounds().centerBottom(); entity.teleport(pos.getX(), pos.getY(), pos.getZ()); entity.setYaw(spawn.getData().getFloat("Rotation")); } public void spawnEntity(ServerWorld world, ServerPlayerEntity plr) { - List spawnList = spawns.toList(); - TemplateRegion spawn = spawnList.get(new Random().nextInt(spawnList.size())); + TemplateRegion spawn = spawns.get(new Random().nextInt(spawns.size())); Vec3d pos = spawn.getBounds().centerBottom(); plr.teleport(world, pos.getX(), pos.getY(), pos.getZ(), spawn.getData().getFloat("Rotation"), 0); this.playerSpawnPos.put(new PlayerRef(plr.getUuid()), pos); diff --git a/src/main/java/me/ellieis/Sabotage/game/phase/SabotageActive.java b/src/main/java/me/ellieis/Sabotage/game/phase/SabotageActive.java index 4712324..06a7774 100644 --- a/src/main/java/me/ellieis/Sabotage/game/phase/SabotageActive.java +++ b/src/main/java/me/ellieis/Sabotage/game/phase/SabotageActive.java @@ -13,11 +13,17 @@ import net.minecraft.util.math.Vec3d; import xyz.nucleoid.plasmid.game.GameActivity; import xyz.nucleoid.plasmid.game.GameSpace; +import xyz.nucleoid.plasmid.game.common.GlobalWidgets; +import xyz.nucleoid.plasmid.game.common.widget.SidebarWidget; import xyz.nucleoid.plasmid.game.event.GameActivityEvents; +import xyz.nucleoid.plasmid.game.player.MutablePlayerSet; import xyz.nucleoid.plasmid.game.player.PlayerSet; import xyz.nucleoid.plasmid.game.rule.GameRuleType; import xyz.nucleoid.plasmid.util.PlayerRef; +import java.util.ArrayList; +import java.util.List; +import java.util.Collections; import java.util.Set; public class SabotageActive { @@ -28,11 +34,24 @@ public class SabotageActive { private boolean gameStarted = false; private boolean countdown = false; private long startTime; + private GameActivity activity; + private final MutablePlayerSet saboteurs; + private final MutablePlayerSet detectives; + private final MutablePlayerSet innocents; + private GlobalWidgets widgets; + private SidebarWidget globalSidebar; + private SidebarWidget innocentSidebar; + private SidebarWidget detectiveSidebar; + private SidebarWidget saboteurSidebar; public SabotageActive(SabotageConfig config, GameSpace gameSpace, SabotageMap map, ServerWorld world) { this.config = config; this.gameSpace = gameSpace; this.map = map; this.world = world; + + this.saboteurs = new MutablePlayerSet(gameSpace.getServer()); + this.detectives = new MutablePlayerSet(gameSpace.getServer()); + this.innocents = new MutablePlayerSet(gameSpace.getServer()); } private static void gameStartedRules(GameActivity activity) { activity.allow(GameRuleType.FALL_DAMAGE); @@ -54,35 +73,78 @@ private static void rules(GameActivity activity) { activity.deny(GameRuleType.BREAK_BLOCKS); activity.deny(GameRuleType.CRAFTING); } + + public void pickRoles() { + PlayerSet plrs = this.gameSpace.getPlayers(); + int playerCount = plrs.size(); + // need to make a new list from .toList to make it mutable + List plrList = new ArrayList<>(plrs.stream().toList()); + Collections.shuffle(plrList); + int sabCount = playerCount / 3; + if (sabCount < 1) { + sabCount = 1; + } + int detCount = playerCount / 8; + + for (ServerPlayerEntity plr : plrList) { + if (detCount >= 1) { + this.detectives.add(plr); + detCount--; + } else if (sabCount >= 1) { + this.saboteurs.add(plr); + sabCount--; + } else { + this.innocents.add(plr); + } + } + this.innocents.showTitle(Text.translatable("sabotage.role_reveal", Text.translatable("sabotage.innocent").formatted(Formatting.GREEN)), 10, 80, 10); + this.innocents.playSound(SoundEvents.ENTITY_ILLUSIONER_CAST_SPELL); + this.detectives.showTitle(Text.translatable("sabotage.role_reveal", Text.translatable("sabotage.detective").formatted(Formatting.DARK_BLUE)), 10, 80, 10); + this.detectives.playSound(SoundEvents.BLOCK_AMETHYST_BLOCK_CHIME); + this.saboteurs.showTitle(Text.translatable("sabotage.role_reveal", Text.translatable("sabotage.saboteur").formatted(Formatting.RED)), 10, 80, 10); + this.saboteurs.playSound(SoundEvents.AMBIENT_SOUL_SAND_VALLEY_MOOD.value()); + } + public void Start() { + this.gameStarted = true; + pickRoles(); + gameStartedRules(this.activity); + } public static void Open(GameSpace gameSpace, ServerWorld world, SabotageMap map, SabotageConfig config) { gameSpace.setActivity(activity -> { SabotageActive game = new SabotageActive(config, gameSpace, map, world); game.startTime = world.getTime(); game.countdown = true; + game.widgets = GlobalWidgets.addTo(activity); + game.globalSidebar = game.widgets.addSidebar(Text.translatable("gameType.sabotage.sabotage")); rules(activity); activity.listen(GameActivityEvents.TICK, game::onTick); + PlayerSet plrs = game.gameSpace.getPlayers(); + plrs.showTitle(Text.literal(Integer.toString(game.config.getCountdownTime())).formatted(Formatting.GOLD), 20); plrs.playSound(SoundEvents.BLOCK_NOTE_BLOCK_HARP.value(), SoundCategory.PLAYERS, 1.0F, 2.0F); - for (ServerPlayerEntity plr : plrs) { + plrs.forEach(plr -> { game.map.spawnEntity(world, plr); - } + game.globalSidebar.addPlayer(plr); + }); + }); } public void onTick() { long time = this.world.getTime(); if (!gameStarted) { - // to-do: implement grace period if (this.countdown) { if (time % 20 == 0) { // second has passed + PlayerSet plrs = this.gameSpace.getPlayers(); int secondsSinceStart = (int) Math.floor((time / 20) - (this.startTime / 20)); int countdownTime = this.config.getCountdownTime(); if (secondsSinceStart >= countdownTime) { this.countdown = false; + plrs.playSound(SoundEvents.BLOCK_RESPAWN_ANCHOR_CHARGE); + plrs.sendMessage(Text.translatable("sabotage.game_start", this.config.getGracePeriod()).formatted(Formatting.GOLD)); } else { - PlayerSet plrs = this.gameSpace.getPlayers(); plrs.showTitle(Text.literal(Integer.toString(countdownTime - secondsSinceStart)).formatted(Formatting.GOLD), 20); plrs.playSound(SoundEvents.BLOCK_NOTE_BLOCK_HARP.value(), SoundCategory.PLAYERS, 1.0F, 2.0F); } @@ -95,6 +157,12 @@ public void onTick() { // Teleport without changing the pitch and yaw plr.networkHandler.requestTeleport(pos.getX(), pos.getY(), pos.getZ(), plr.getYaw(), plr.getPitch(), flags); } + } else { + // to-do: implement grace period + int secondsSinceStart = (int) Math.floor((time / 20) - (this.startTime / 20)) - this.config.getCountdownTime(); + if (secondsSinceStart >= this.config.getGracePeriod()) { + Start(); + } } } else { // to-do: implement game loop diff --git a/src/main/java/me/ellieis/Sabotage/game/phase/SabotageWaiting.java b/src/main/java/me/ellieis/Sabotage/game/phase/SabotageWaiting.java index 3bee9ed..d7876f6 100644 --- a/src/main/java/me/ellieis/Sabotage/game/phase/SabotageWaiting.java +++ b/src/main/java/me/ellieis/Sabotage/game/phase/SabotageWaiting.java @@ -28,7 +28,6 @@ public class SabotageWaiting { private final GameSpace gameSpace; private final SabotageMap map; private final ServerWorld world; - private SidebarWidget widget; private int playerCount; public SabotageWaiting(SabotageConfig config, GameSpace gameSpace, SabotageMap map, ServerWorld world) { this.config = config; diff --git a/src/main/resources/data/sabotage/lang/en_us.json b/src/main/resources/data/sabotage/lang/en_us.json index 2e362e5..bb08a4c 100644 --- a/src/main/resources/data/sabotage/lang/en_us.json +++ b/src/main/resources/data/sabotage/lang/en_us.json @@ -1,5 +1,10 @@ { "gameType.sabotage.sabotage": "Sabotage", "sabotage.waiting": "Waiting for players.", - "sabotage.full": "Game is full." + "sabotage.full": "Game is full.", + "sabotage.game_start": "The game has started! You have %s seconds to collect items, gear, or hide. Your roles will be selected after the grace period.", + "sabotage.role_reveal": "You are a %s", + "sabotage.innocent": "Innocent", + "sabotage.detective": "Detective", + "sabotage.saboteur": "Saboteur" } \ No newline at end of file