Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public final class Messages {
private static final Component SURVIVOR_JOIN_PART_UPPER;
private static final Component SURVIVOR_JOIN_LOWER_PART;
public static final Component SLENDER_JOIN_PART;
private static final Component STATS_HEADER;
private static final int MAP_ANNOUNCEMENT_MIN_WIDTH = 20;

static {
Expand Down Expand Up @@ -74,6 +75,8 @@ public final class Messages {
.append(withPrefix(Component.text("Eliminate all survivors to win the game!", NamedTextColor.YELLOW)))
.append(Component.newline())
.append(withMiniPrefix("<red>Right-click your <color:#ff00d4>SlenderEye</color> <red>to toggle invisibility!"));

STATS_HEADER = withMini("<dark_gray>---[<gold>Statistics<dark_gray>]---");
}

private Messages() {
Expand Down Expand Up @@ -128,6 +131,51 @@ public static Component getDeathComponent(Player player) {
return PREFIX.append(Component.space()).append(withMini("<red><player> <color:#249D9F>was</color> <color:#ff0000>TAKEN!</color>", playerTag));
}

/**
* Builds the round-end stats box for a survivor.
*
* @param player the survivor the box is about
* @param pageFounds how many pages the survivor found this round
* @param died whether the survivor died this round
* @return the formatted stats box
*/
@Contract(value = "_, _, _ -> new", pure = true)
public static Component getSurvivorRoundSummaryComponent(Player player, int pageFounds, boolean died) {
Component deathIcon = died
? Component.text("✓", NamedTextColor.GREEN)
: Component.text("✗", NamedTextColor.RED);
var resolver = TagResolver.builder()
.tag("pages", (_, _) -> Tag.preProcessParsed(String.valueOf(pageFounds)))
.tag("died", Tag.inserting(deathIcon))
.build();
return Component.text(player.getUsername(), NamedTextColor.GOLD)
.append(Component.newline())
.append(STATS_HEADER)
.append(Component.newline())
.append(withMini("<gray>Pages: <green><pages>", resolver))
.append(Component.newline())
.append(withMini("<gray>Death: <died>", resolver));
}

/**
* Builds the round-end stats box for the slender.
*
* @param player the slender the box is about
* @param kills how many survivors the slender caught this round
* @return the formatted stats box
*/
@Contract(value = "_, _ -> new", pure = true)
public static Component getSlenderRoundSummaryComponent(Player player, int kills) {
var resolver = TagResolver.builder()
.tag("kills", (_, _) -> Tag.preProcessParsed(String.valueOf(kills)))
.build();
return Component.text(player.getUsername(), NamedTextColor.GOLD)
.append(Component.newline())
.append(STATS_HEADER)
.append(Component.newline())
.append(withMini("<gray>Kills: <green><kills>", resolver));
}


@Contract(value = "_, _ -> new", pure = true)
public static Component getViewComponent(String time, Component pageStatus) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import net.onelitefeather.cygnus.event.GameFinishEvent;
import net.onelitefeather.cygnus.jumpscare.JumpScareManager;
import net.onelitefeather.cygnus.phase.GamePhase;
import net.onelitefeather.cygnus.player.CygnusPlayer;
import net.onelitefeather.cygnus.player.event.SpectatorAddEvent;

import java.util.function.Consumer;
Expand All @@ -39,7 +40,12 @@ public PlayerDeathListener(Supplier<Phase> phaseSupplier, TeamService teamServic
public void accept(PlayerDeathEvent event) {
Player player = event.getPlayer();

if (survivorTeam.getPlayers().contains(player) && player.getInstance() != null) {
if (survivorTeam.getPlayers().contains(player)) {
((CygnusPlayer) player).setDeath(true);
this.slenderTeam.getPlayers().stream().findFirst()
.ifPresent(slender -> ((CygnusPlayer) slender).incrementKills());

if (player.getInstance() == null) return;
Pos deathPos = player.getPosition();
DeadPlayerMannequin mannequin = DeadPlayerMannequin.sleeping(player);
mannequin.setInstance(player.getInstance(), deathPos.add(0, 0.15, 0));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

import net.theevilreaper.aves.util.Broadcaster;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.onelitefeather.cygnus.common.Messages;
import net.onelitefeather.cygnus.event.GameFinishEvent;
import net.onelitefeather.cygnus.player.CygnusPlayer;
import net.onelitefeather.cygnus.team.TeamHelper;

import java.util.function.Consumer;

Expand All @@ -19,5 +23,23 @@ public void accept(GameFinishEvent event) {
case TIME_OVER, ALL_PAGES_FOUND, SLENDER_LEFT -> Messages.SURVIVOR_WIN_MESSAGE;
};
Broadcaster.broadcast(endComponent);
Broadcaster.broadcast(buildRoundSummary());
}

/**
* Builds a per-player summary of this round's stats, one line per {@link CygnusPlayer} online.
*
* @return the summary component
*/
private Component buildRoundSummary() {
Component summary = Component.empty();
for (Player onlinePlayer : MinecraftServer.getConnectionManager().getOnlinePlayers()) {
if (!(onlinePlayer instanceof CygnusPlayer cygnusPlayer)) continue;
Component box = TeamHelper.isSlenderTeam(onlinePlayer)
? Messages.getSlenderRoundSummaryComponent(onlinePlayer, cygnusPlayer.getKills())
: Messages.getSurvivorRoundSummaryComponent(onlinePlayer, cygnusPlayer.getPageFounds(), cygnusPlayer.hasDied());
summary = summary.append(Component.newline()).append(box);
}
return summary;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import net.minestom.server.event.player.PlayerEntityInteractEvent;
import net.onelitefeather.cygnus.common.Tags;
import net.onelitefeather.cygnus.common.page.PageProvider;
import net.onelitefeather.cygnus.player.CygnusPlayer;
import net.onelitefeather.cygnus.team.TeamHelper;

import java.util.UUID;
Expand All @@ -24,6 +25,7 @@ public void accept(PlayerEntityInteractEvent event) {
Entity target = event.getTarget();
if (!TeamHelper.isSurvivorTeam(player) || !target.hasTag(Tags.PAGE_TAG)) return;
UUID uuid = target.getTag(Tags.PAGE_TAG);
((CygnusPlayer) player).incrementPageFound();
pageProvider.triggerPageFound(player, uuid);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,18 @@ public final class CygnusPlayer extends InstanceSwitchChunkPlayer {
private int heartbeatTicks;
private boolean heartbeatActive;

private int pageFounds;
private int kills;
private boolean death;

public CygnusPlayer(PlayerConnection playerConnection, GameProfile gameProfile) {
super(playerConnection, gameProfile);
this.blockedSprinting = false;
this.heartbeatTicks = 0;
this.heartbeatActive = false;
this.pageFounds = 0;
this.kills = 0;
this.death = false;
}

/**
Expand Down Expand Up @@ -100,6 +107,56 @@ public boolean hasBlockedSprinting() {
return blockedSprinting;
}

/**
* Increments the number of pages this player has found in the current round.
*/
public void incrementPageFound() {
this.pageFounds++;
}

/**
* Returns how many pages this player has found in the current round.
*
* @return the page count
*/
public int getPageFounds() {
return pageFounds;
}

/**
* Increments the number of survivors this player has killed in the current round.
*/
public void incrementKills() {
this.kills++;
}

/**
* Returns how many survivors this player has killed in the current round.
*
* @return the kill count
*/
public int getKills() {
return kills;
}

/**
* Marks whether this player died during the current round.
*
* @param death {@code true} if the player died this round
*/
public void setDeath(boolean death) {
this.death = death;
}

/**
* Checks if the player died during the current round.
*
* @return {@code true} if the player died this round, otherwise {@code false}.
*/
public boolean hasDied() {
return death;
}

/**
* Updates the heartbeat sound and red border vignette effect on player tick.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
import net.onelitefeather.cygnus.common.Tags;
import net.onelitefeather.cygnus.common.config.GameConfig;
import net.onelitefeather.cygnus.jumpscare.JumpScareManager;
import net.onelitefeather.cygnus.player.CygnusPlayer;
import net.onelitefeather.cygnus.player.event.SpectatorAddEvent;
import net.onelitefeather.cygnus.team.TeamHelper;
import net.theevilreaper.xerus.api.team.Team;
import net.theevilreaper.xerus.api.team.Team;
import net.theevilreaper.xerus.api.team.TeamService;
import org.jetbrains.annotations.NotNull;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

class PlayerDeathListenerTest extends CygnusPlayerTestBase {

Expand All @@ -42,4 +43,53 @@ void testDyingSurvivorFiresSpectatorAddEventForThemselves(@NotNull Env env) {

env.destroyInstance(instance, true);
}

@Test
void testDyingSurvivorIsMarkedAsDied(@NotNull Env env) {
Instance instance = env.createFlatInstance();
CygnusPlayer player = (CygnusPlayer) env.createPlayer(instance);

TeamService teamService = TeamService.of();
Team slenderTeam = Team.of(GameConfig.SLENDER_KEY, 1);
Team survivorTeam = Team.of(GameConfig.SURVIVOR_KEY, 5);
teamService.add(slenderTeam);
teamService.add(survivorTeam);

survivorTeam.addPlayer(player);
player.setTag(Tags.TEAM_KEY, GameConfig.SURVIVOR_KEY);

PlayerDeathListener listener = new PlayerDeathListener(() -> null, teamService, new JumpScareManager());

listener.accept(new PlayerDeathEvent(player, null, null));

assertTrue(player.hasDied());

env.destroyInstance(instance, true);
}

@Test
void testDyingSurvivorIncrementsSlenderKills(@NotNull Env env) {
Instance instance = env.createFlatInstance();
CygnusPlayer survivor = (CygnusPlayer) env.createPlayer(instance);
CygnusPlayer slender = (CygnusPlayer) env.createPlayer(instance);

TeamService teamService = TeamService.of();
Team slenderTeam = Team.of(GameConfig.SLENDER_KEY, 1);
Team survivorTeam = Team.of(GameConfig.SURVIVOR_KEY, 5);
teamService.add(slenderTeam);
teamService.add(survivorTeam);

survivorTeam.addPlayer(survivor);
survivor.setTag(Tags.TEAM_KEY, GameConfig.SURVIVOR_KEY);
slenderTeam.addPlayer(slender);
slender.setTag(Tags.TEAM_KEY, GameConfig.SLENDER_KEY);

PlayerDeathListener listener = new PlayerDeathListener(() -> null, teamService, new JumpScareManager());

listener.accept(new PlayerDeathEvent(survivor, null, null));

assertEquals(1, slender.getKills());

env.destroyInstance(instance, true);
}
}
Loading