Skip to content

Commit

Permalink
Data-drive River Race zone unlock flow, add countdown boss bar
Browse files Browse the repository at this point in the history
  • Loading branch information
Gegy committed Nov 15, 2024
1 parent 2e974aa commit e9a8286
Show file tree
Hide file tree
Showing 13 changed files with 143 additions and 76 deletions.
6 changes: 3 additions & 3 deletions src/generated/resources/assets/ltminigames/lang/en_ud.json
Original file line number Diff line number Diff line change
Expand Up @@ -408,10 +408,10 @@
"ltminigames.minigame.river_race.cant_place_collectable": "ssǝɹboɹd oʇ ǝuoz ʇɔǝɹɹoɔ ǝɥʇ ɟo puǝ ǝɥʇ ʇɐ ʇuǝɯnuoW ǝɥʇ uı ǝɔɐןԀ",
"ltminigames.minigame.river_race.shop": "doɥS",
"ltminigames.minigame.river_race.trivia.collectable_given": "¡ʇuǝɯnuoɯ ǝɥʇ oʇuı ǝɔɐןd oʇ ǝןqɐʇɔǝןןoɔ ɐ uǝʌıb uǝǝq ǝʌ,noʎ",
"ltminigames.minigame.river_race.trivia.collectable_placed": "˙spuoɔǝs %s uı ʇɹɐʇs ןןıʍ sǝɯɐb-oɹɔıɯ ǝɥ⟘ ¡ǝןqɐʇɔǝןןoɔ %s ǝɥʇ ǝɔɐןd oʇ ʇsɹıɟ ǝɹɐ ɯɐǝʇ %s",
"ltminigames.minigame.river_race.trivia.collectable_placed_title": "¡ǝןqɐʇɔǝןןoɔ %s ǝɥʇ ǝɔɐןd oʇ ʇsɹıɟ ǝɹɐ ɯɐǝʇ %s",
"ltminigames.minigame.river_race.trivia.collectable_placed.subtitle": "ǝuoz %ǝɯɐu% pǝʇǝןdɯoƆ",
"ltminigames.minigame.river_race.trivia.collectable_placed.title": "¡%ɯɐǝʇ% o⅁",
"ltminigames.minigame.river_race.trivia.correct": "¡ʎןʇɔǝɹɹoɔ pǝɹǝʍsuɐ uoıʇsǝnb ɐıʌıɹ⟘",
"ltminigames.minigame.river_race.trivia.games_start_in": ")s(puoɔǝs %s uı ʇɹɐʇs sǝɯɐboɹɔıW",
"ltminigames.minigame.river_race.trivia.games_start_in": "%ǝɯıʇ% uı ʇɹɐʇs sǝɯɐboɹɔıW",
"ltminigames.minigame.river_race.trivia.incorrect": "¡spuoɔǝs %s ɹoɟ ʇno pǝʞɔoן ʍou sı uoıʇsǝnb sıɥ⟘ ¡ʇɔǝɹɹoɔuI",
"ltminigames.minigame.river_race.trivia.loot_given": "¡pǝʞɔoןun uǝǝq sɐɥ ʇooꞀ",
"ltminigames.minigame.river_race.trivia.victory_point_change": ")s(ʇuıoԀ ʎɹoʇɔıΛ %s+",
Expand Down
6 changes: 3 additions & 3 deletions src/generated/resources/assets/ltminigames/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -408,10 +408,10 @@
"ltminigames.minigame.river_race.cant_place_collectable": "Place in the Monument at the end of the correct zone to progress",
"ltminigames.minigame.river_race.shop": "Shop",
"ltminigames.minigame.river_race.trivia.collectable_given": "You've been given a collectable to place into the monument!",
"ltminigames.minigame.river_race.trivia.collectable_placed": "%s team are first to place the %s collectable! The micro-games will start in %s seconds.",
"ltminigames.minigame.river_race.trivia.collectable_placed_title": "%s team are first to place the %s collectable!",
"ltminigames.minigame.river_race.trivia.collectable_placed.subtitle": "Completed %name% zone",
"ltminigames.minigame.river_race.trivia.collectable_placed.title": "Go %team%!",
"ltminigames.minigame.river_race.trivia.correct": "Trivia question answered correctly!",
"ltminigames.minigame.river_race.trivia.games_start_in": "Microgames start in %s second(s)",
"ltminigames.minigame.river_race.trivia.games_start_in": "Microgames start in %time%",
"ltminigames.minigame.river_race.trivia.incorrect": "Incorrect! This question is now locked out for %s seconds!",
"ltminigames.minigame.river_race.trivia.loot_given": "Loot has been unlocked!",
"ltminigames.minigame.river_race.trivia.victory_point_change": "+%s Victory Point(s)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class RiverRace {
public static final GameBehaviorEntry<ProgressBehaviour> RIVER_RACE_PROGRESS_BEHAVIOUR = REGISTRATE.object("river_race_progress").behavior(ProgressBehaviour.CODEC).register();
public static final GameBehaviorEntry<CollectablesBehaviour> COLLECTABLES_BEHAVIOUR = REGISTRATE.object("river_race_collectables").behavior(CollectablesBehaviour.CODEC).register();
public static final GameBehaviorEntry<PreventBreakBehaviour> PREVENT_BREAK_BEHAVIOUR = REGISTRATE.object("prevent_break").behavior(PreventBreakBehaviour.CODEC).register();
public static final GameBehaviorEntry<UnlockZoneAction> UNLOCK_ZONE_ACTION = REGISTRATE.object("unlock_zone").behavior(UnlockZoneAction.CODEC).register();

public static final GameClientTweakEntry<RiverRaceClientBarState> BAR_STATE = REGISTRATE.object("river_race_bar")
.clientState(RiverRaceClientBarState.CODEC).streamCodec(RiverRaceClientBarState.STREAM_CODEC)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,20 @@ public final class RiverRaceTexts {
.withStyle(ChatFormatting.GOLD);
public static final Component LOOT_GIVEN = KEYS.add("trivia.loot_given", "Loot has been unlocked!")
.withStyle(ChatFormatting.GOLD);
public static final TranslationCollector.Fun2 COLLECTABLE_PLACED_TITLE = KEYS.add2("trivia.collectable_placed_title", "%s team are first to place the %s collectable!")
.withStyle(ChatFormatting.GREEN);
public static final TranslationCollector.Fun3 COLLECTABLE_PLACED = KEYS.add3("trivia.collectable_placed", "%s team are first to place the %s collectable! The micro-games will start in %s seconds.")
.withStyle(ChatFormatting.GREEN);
public static final TranslationCollector.Fun1 VICTORY_POINT_CHANGE = KEYS.add1("trivia.victory_point_change", "+%s Victory Point(s)")
.withStyle(ChatFormatting.GREEN);

public static final TranslationCollector.Fun1 GAMES_START_IN = KEYS.add1("trivia.games_start_in", "Microgames start in %s second(s)")
.withStyle(ChatFormatting.GREEN);

public static final Component CANT_PLACE_COLLECTABLE = KEYS.add("cant_place_collectable", "Place in the Monument at the end of the correct zone to progress")
.withStyle(ChatFormatting.RED);
public static final Component TRIVIA_BLOCK_ALREADY_USED = KEYS.add("trivia_block_already_used", "This Trivia Block has already been used!")
.withStyle(ChatFormatting.RED);

public static void collectTranslations(BiConsumer<String, String> consumer) {
KEYS.forEach(consumer);
KEYS.add("trivia.collectable_placed.title", "Go %team%!");
KEYS.add("trivia.collectable_placed.subtitle", "Completed %name% zone");
KEYS.add("trivia.games_start_in", "Microgames start in %time%");

KEYS.forEach(consumer);
consumer.accept(LoveTropics.ID + ".minigame.river_race", "River Race");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
import com.lovetropics.lib.codec.MoreCodecs;
import com.lovetropics.lib.entity.FireworkPalette;
import com.lovetropics.minigames.common.content.river_race.RiverRaceTexts;
import com.lovetropics.minigames.common.content.river_race.event.RiverRaceEvents;
import com.lovetropics.minigames.common.core.game.GameException;
import com.lovetropics.minigames.common.core.game.IGamePhase;
import com.lovetropics.minigames.common.core.game.behavior.IGameBehavior;
import com.lovetropics.minigames.common.core.game.behavior.action.GameActionContext;
import com.lovetropics.minigames.common.core.game.behavior.action.GameActionList;
import com.lovetropics.minigames.common.core.game.behavior.action.GameActionParameter;
import com.lovetropics.minigames.common.core.game.behavior.event.EventRegistrar;
import com.lovetropics.minigames.common.core.game.behavior.event.GamePhaseEvents;
import com.lovetropics.minigames.common.core.game.behavior.event.GamePlayerEvents;
Expand All @@ -25,8 +25,6 @@
import com.mojang.serialization.codecs.RecordCodecBuilder;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.ChatFormatting;
import net.minecraft.SharedConstants;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
Expand All @@ -46,16 +44,13 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;

public final class CollectablesBehaviour implements IGameBehavior, IGameState {
public static final MapCodec<CollectablesBehaviour> CODEC = RecordCodecBuilder.mapCodec(i -> i.group(
ExtraCodecs.nonEmptyList(Collectable.CODEC.listOf()).fieldOf("collectables").forGetter(CollectablesBehaviour::collectables)
).apply(i, CollectablesBehaviour::new));

public static final GameStateKey<CollectablesBehaviour> COLLECTABLES = GameStateKey.create("collectables");
public static final int COUNTDOWN_SECONDS = 45;
private final List<Collectable> collectables;

public CollectablesBehaviour(List<Collectable> collectables) {
Expand All @@ -66,8 +61,6 @@ public CollectablesBehaviour(List<Collectable> collectables) {
private final LongSet placedCollectables = new LongOpenHashSet();

private final Map<String, GameTeamKey> firstTeamToCollect = new HashMap<>();
@Nullable
private Countdown countdown;

@Nullable
public Collectable getCollectableForZone(String zone) {
Expand Down Expand Up @@ -101,11 +94,6 @@ public void register(IGamePhase game, EventRegistrar events) throws GameExceptio
}
}

events.listen(GamePhaseEvents.TICK, () -> {
if (countdown != null){
countdown.tick(game);
}
});
events.listen(GamePhaseEvents.CREATE, () ->
monumentSlots.forEach((pos, collectable) -> spawnCollectableDisplay(game, collectable, pos.getCenter()))
);
Expand Down Expand Up @@ -156,27 +144,17 @@ private InteractionResult tryPlaceCollectable(IGamePhase game, TeamState teams,

private InteractionResult onCollectablePlaced(IGamePhase game, GameTeam team, Collectable collectable, BlockPos slotPos) {
if (firstTeamToCollect.putIfAbsent(collectable.zone, team.key()) == null) {
addEffectsForPlacedCollectable(game, collectable, team);
// Start microgames countdown
countdown = new Countdown(game.ticks() + (SharedConstants.TICKS_PER_SECOND * COUNTDOWN_SECONDS), (unused) -> {
collectable.onCompleteAction.apply(game, GameActionContext.EMPTY);
collectable.unlocksZone.ifPresent(zone -> game.invoker(RiverRaceEvents.UNLOCK_ZONE).onUnlockZone(zone));
countdown = null;
});
GameActionContext context = GameActionContext.builder()
.set(GameActionParameter.TEAM, team)
.set(GameActionParameter.NAME, Component.literal(collectable.zoneDisplayName()))
.build();
collectable.onCompleteAction.apply(game, context, game.allPlayers());
}
game.statistics().forTeam(team.key()).incrementInt(StatisticKey.VICTORY_POINTS, collectable.victoryPoints);
FireworkPalette.DYE_COLORS.spawn(slotPos.above(), game.level());
return InteractionResult.PASS;
}

private static void addEffectsForPlacedCollectable(IGamePhase game, Collectable collectable, GameTeam team) {
Component teamName = team.config().styledName();
game.allPlayers().showTitle(null, RiverRaceTexts.COLLECTABLE_PLACED_TITLE.apply(teamName, collectable.zoneDisplayName()), 20, 40, 20);
game.allPlayers().sendMessage(RiverRaceTexts.COLLECTABLE_PLACED.apply(teamName, collectable.zoneDisplayName(), COUNTDOWN_SECONDS));

game.allPlayers().playSound(SoundEvents.RAID_HORN.value(), SoundSource.NEUTRAL, 1f, 1);
}

@Nullable
private Collectable getMatchingCollectable(ItemStack itemStack) {
for (Collectable collectable : collectables) {
Expand All @@ -191,44 +169,16 @@ public List<Collectable> collectables() {
return collectables;
}

private static class Countdown {

private final long endTicks;
private final Consumer<Void> end;

public Countdown(long endTicks, Consumer<Void> end) {
this.endTicks = endTicks;
this.end = end;
}

public void tick(IGamePhase game){
long ticks = game.ticks();
if(ticks >= endTicks){
end.accept(null);
} else if(ticks % 20 == 0) {
long remainingTicks = endTicks - ticks;
long remainingSeconds = (remainingTicks / SharedConstants.TICKS_PER_SECOND);
if(remainingSeconds == 30 || remainingSeconds == 15 || remainingSeconds == 10) {
game.allPlayers().sendMessage(RiverRaceTexts.GAMES_START_IN.apply(remainingSeconds).withStyle(ChatFormatting.GREEN));
} else if((remainingTicks / SharedConstants.TICKS_PER_SECOND) <= 5) {
game.allPlayers().playSound(SoundEvents.UI_BUTTON_CLICK.value(), SoundSource.NEUTRAL, 0.2f, 1f);
game.allPlayers().showTitle(Component.literal(remainingTicks / SharedConstants.TICKS_PER_SECOND + "").withStyle(ChatFormatting.GREEN), 10, 20, 10);
}
}
}
}

public record Collectable(String zone, Optional<String> unlocksZone, String zoneDisplayName, ItemStack collectable,
public record Collectable(String zone, String zoneDisplayName, ItemStack collectable,
List<String> monumentSlotRegions,
int victoryPoints, GameActionList<Void> onCompleteAction) {
int victoryPoints, GameActionList<ServerPlayer> onCompleteAction) {
public static final Codec<Collectable> CODEC = RecordCodecBuilder.create(i -> i.group(
Codec.STRING.fieldOf("zone").forGetter(Collectable::zone),
Codec.STRING.optionalFieldOf("unlocks_zone").forGetter(Collectable::unlocksZone),
Codec.STRING.fieldOf("zone_display_name").forGetter(Collectable::zoneDisplayName),
MoreCodecs.ITEM_STACK.fieldOf("item").forGetter(Collectable::collectable),
ExtraCodecs.nonEmptyList(Codec.STRING.listOf()).fieldOf("monument_slot_region").forGetter(Collectable::monumentSlotRegions),
Codec.INT.fieldOf("victory_points").forGetter(Collectable::victoryPoints),
GameActionList.VOID_CODEC.fieldOf("on_complete").forGetter(Collectable::onCompleteAction)
GameActionList.PLAYER_CODEC.fieldOf("on_complete").forGetter(Collectable::onCompleteAction)
).apply(i, Collectable::new));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.lovetropics.minigames.common.content.river_race.behaviour;

import com.lovetropics.minigames.common.content.river_race.RiverRace;
import com.lovetropics.minigames.common.content.river_race.event.RiverRaceEvents;
import com.lovetropics.minigames.common.core.game.GameException;
import com.lovetropics.minigames.common.core.game.IGamePhase;
import com.lovetropics.minigames.common.core.game.behavior.GameBehaviorType;
import com.lovetropics.minigames.common.core.game.behavior.IGameBehavior;
import com.lovetropics.minigames.common.core.game.behavior.event.EventRegistrar;
import com.lovetropics.minigames.common.core.game.behavior.event.GameActionEvents;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;

import java.util.function.Supplier;

public record UnlockZoneAction(
String zone
) implements IGameBehavior {
public static final MapCodec<UnlockZoneAction> CODEC = RecordCodecBuilder.mapCodec(i -> i.group(
Codec.STRING.fieldOf("zone").forGetter(UnlockZoneAction::zone)
).apply(i, UnlockZoneAction::new));

@Override
public void register(IGamePhase game, EventRegistrar events) throws GameException {
events.listen(GameActionEvents.APPLY, context -> {
game.invoker(RiverRaceEvents.UNLOCK_ZONE).onUnlockZone(zone);
return true;
});
}

@Override
public Supplier<? extends GameBehaviorType<?>> behaviorType() {
return RiverRace.UNLOCK_ZONE_ACTION;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@
import com.lovetropics.minigames.common.content.river_race.RiverRace;
import com.lovetropics.minigames.common.content.river_race.client_state.RiverRaceClientBarState;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import it.unimi.dsi.fastutil.ints.IntList;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.FastColor;
import net.minecraft.world.item.DyeColor;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.client.event.RegisterGuiLayersEvent;
import net.neoforged.neoforge.client.event.RenderGuiLayerEvent;
import net.neoforged.neoforge.client.gui.VanillaGuiLayers;

@EventBusSubscriber(modid = LoveTropics.ID, value = Dist.CLIENT)
public final class RiverRaceBarRenderer {
private static final int MAP_TOP = 3;

Expand Down Expand Up @@ -44,6 +50,22 @@ public static void registerOverlays(RegisterGuiLayersEvent event) {
});
}

@SubscribeEvent
public static void onRenderLayerPre(RenderGuiLayerEvent.Pre event) {
if (event.getName().equals(VanillaGuiLayers.BOSS_OVERLAY) && ClientGameStateManager.getOrNull(RiverRace.BAR_STATE) != null) {
PoseStack pose = event.getGuiGraphics().pose();
pose.pushPose();
pose.translate(0.0f, MAP_HEIGHT + POINTER_SIZE, 0.0f);
}
}

@SubscribeEvent
public static void onRenderLayerPost(RenderGuiLayerEvent.Post event) {
if (event.getName().equals(VanillaGuiLayers.BOSS_OVERLAY) && ClientGameStateManager.getOrNull(RiverRace.BAR_STATE) != null) {
event.getGuiGraphics().pose().popPose();
}
}

private static void render(GuiGraphics graphics, RiverRaceClientBarState barState) {
RenderSystem.enableBlend();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
import com.lovetropics.minigames.common.core.game.behavior.instances.action.SpawnParticlesAroundPlayerAction;
import com.lovetropics.minigames.common.core.game.behavior.instances.action.SpawnTornadoAction;
import com.lovetropics.minigames.common.core.game.behavior.instances.action.SpectatorActivityAction;
import com.lovetropics.minigames.common.core.game.behavior.instances.action.StartProgressChannelAction;
import com.lovetropics.minigames.common.core.game.behavior.instances.action.SwapPlayersAction;
import com.lovetropics.minigames.common.core.game.behavior.instances.action.TargetPlayerAction;
import com.lovetropics.minigames.common.core.game.behavior.instances.action.TransformPlayerTornadoAction;
Expand Down Expand Up @@ -282,6 +283,7 @@ public class GameBehaviorTypes {
public static final GameBehaviorEntry<AddCollidersAction> ADD_COLLIDERS = register("add_colliders", AddCollidersAction.CODEC);
public static final GameBehaviorEntry<RemoveCollidersAction> REMOVE_COLLIDERS = register("remove_colliders", RemoveCollidersAction.CODEC);
public static final GameBehaviorEntry<IncrementStatisticAction> INCREMENT_STATISTIC = register("increment_statistic", IncrementStatisticAction.CODEC);
public static final GameBehaviorEntry<StartProgressChannelAction> START_PROGRESS_CHANNEL = register("start_progress_channel", StartProgressChannelAction.CODEC);

public static final GameBehaviorEntry<SetupIntegrationsBehavior> SETUP_INTEGRATIONS = register("setup_integrations", SetupIntegrationsBehavior.CODEC);
public static final GameBehaviorEntry<AssignPlayerRolesBehavior> ASSIGN_PLAYER_ROLES = register("assign_player_roles", AssignPlayerRolesBehavior.CODEC);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.lovetropics.minigames.common.core.game.state.team.GameTeam;
import com.lovetropics.minigames.common.core.integration.game_actions.GamePackage;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;

Expand All @@ -16,6 +17,7 @@ public class GameActionParameter<T> {
public static final GameActionParameter<Integer> COUNT = GameActionParameter.create();
public static final GameActionParameter<ItemStack> ITEM = GameActionParameter.create();
public static final GameActionParameter<GameTeam> TEAM = GameActionParameter.create();
public static final GameActionParameter<Component> NAME = GameActionParameter.create();

private GameActionParameter() {
}
Expand Down
Loading

0 comments on commit e9a8286

Please sign in to comment.