feat: Enhance minigame effects and UI interactions
- Implemented LeaveMinigameQueueEffect to handle player removal from queues and runtime. - Added OpenMinigameQueueUIEffect to manage the opening of the minigame queue UI. - Introduced StartPlayerTimerEffect and StopPlayerTimerEffect for managing player timers and scoring. - Enhanced PlaceBlocksEffect with options for filling volumes and hollow placements. - Updated SpawnItemEffect to fix codec handling for item IDs. - Added MountPlayerEffect and DismountPlayerEffect for player interactions with NPCs. - Improved StartQueuedMinigameEffect to check player counts before starting games. - Added localization entries for new effects and UI elements. - Updated manifest to include HyUI as a dependency.
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
# King of the Hill — Overview
|
||||
|
||||
In this tutorial you will build a **King of the Hill** minigame with three rounds. Each round has a dedicated capture point in a different part of the arena. Players earn one point per second while standing on the active hill. The player with the most points after all three rounds wins.
|
||||
|
||||
## What You Will Build
|
||||
|
||||
| Volume / File | Purpose |
|
||||
|---|---|
|
||||
| `King_Of_The_Hill.json` | Minigame definition — rounds, timing, HUD, PvP rules |
|
||||
| Queue pad | Players step on it to join the waiting session |
|
||||
| Start button | Game master trigger to launch the game and set phase to ACTIVE |
|
||||
| Arena boundary | Map discovery tag — tells the runtime which map it is running on |
|
||||
| Spawn zone | Where players enter to activate and start playing |
|
||||
| Capture Zone A | Active during Round 1 — scores +1/second while standing inside |
|
||||
| Capture Zone B | Active during Round 2 — scores +1/second while standing inside |
|
||||
| Capture Zone C | Active during Round 3 — scores +1/second while standing inside |
|
||||
| Round 2 / Round 3 signal volumes | Announce the new round when it starts |
|
||||
| End-game timer volumes | Detect when Round 3 finishes and end the game |
|
||||
|
||||
## Game Flow
|
||||
|
||||
```
|
||||
1. Players step on the queue pad.
|
||||
2. Game master triggers the start button (or add auto-start logic).
|
||||
3. Runtime starts → phase is set to ACTIVE.
|
||||
4. Players enter the spawn zone → they become ACTIVE (HUD shown, items given).
|
||||
5. Round 1 runs for 120 seconds. Capture Zone A scores.
|
||||
6. Round 1 ends → Round 2 begins. Capture Zone B scores.
|
||||
7. Round 2 ends → Round 3 begins. Capture Zone C scores.
|
||||
8. Round 3 ends → game_end timer fires → EndMinigame.
|
||||
9. Scores are tallied. Highest score wins. Arena resets.
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- A Hytale server with core-minigames installed.
|
||||
- A world with three distinct hilltop areas for your capture zones (A, B, C).
|
||||
- A lobby or staging area where players queue before the game begins.
|
||||
- Basic familiarity with placing trigger volumes and adding conditions/effects in the editor.
|
||||
|
||||
## Files in This Tutorial
|
||||
|
||||
| File | Contents |
|
||||
|---|---|
|
||||
| `02-minigame-definition.md` | JSON definition with all fields explained |
|
||||
| `03-join-and-start.md` | Queue pad, start button, map boundary |
|
||||
| `04-spawn-and-activation.md` | Spawn zone + player activation |
|
||||
| `05-capture-zones.md` | The three scoring capture zones |
|
||||
| `06-round-signals.md` | Round announcements and end-game timer |
|
||||
| `07-end-and-reset.md` | Ending the game and resetting the arena |
|
||||
| `08-full-example-files.md` | All complete configurations in one place |
|
||||
@@ -0,0 +1,60 @@
|
||||
# King of the Hill — Minigame Definition
|
||||
|
||||
Create the following file in your server's assets:
|
||||
|
||||
```
|
||||
src/main/resources/Server/Minigames/King_Of_The_Hill.json
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"Id": "King_Of_The_Hill",
|
||||
"Name": "King of the Hill",
|
||||
"Enabled": true,
|
||||
"MinPlayers": 2,
|
||||
"MaxPlayers": 16,
|
||||
"TeamMode": "SOLO",
|
||||
"WinCondition": "HIGHEST_SCORE",
|
||||
"RoundLengthSeconds": 120,
|
||||
"TotalRounds": 3,
|
||||
"CountdownSeconds": 10,
|
||||
"AllowPvp": true,
|
||||
"RequiredGameMode": "Adventure",
|
||||
"ShowHud": true,
|
||||
"ShowScore": true,
|
||||
"ShowTime": true,
|
||||
"ShowRound": true
|
||||
}
|
||||
```
|
||||
|
||||
## Field Breakdown
|
||||
|
||||
| Field | Value | Why |
|
||||
|---|---|---|
|
||||
| `Id` | `King_Of_The_Hill` | Must match the filename exactly and all `MinigameId` fields on every trigger volume in the world. |
|
||||
| `MinPlayers` | `2` | Queue will not start a countdown until at least 2 players have joined. Set to `1` for solo testing. |
|
||||
| `TeamMode` | `SOLO` | Each player competes individually with their own score. |
|
||||
| `WinCondition` | `HIGHEST_SCORE` | The player with the most points when the game ends wins. |
|
||||
| `RoundLengthSeconds` | `120` | Each hill is active for 2 minutes before the next round begins. |
|
||||
| `TotalRounds` | `3` | Three rounds run in sequence. The runtime advances rounds automatically when each timer expires. |
|
||||
| `CountdownSeconds` | `10` | After MinPlayers has joined the queue, a 10-second countdown begins before the game starts. |
|
||||
| `AllowPvp` | `true` | Players can knock each other off the hill. Set to `false` for a passive score-race version. |
|
||||
| `RequiredGameMode` | `Adventure` | Applied to each player when they activate. Prevents block breaking and placing. |
|
||||
| `ShowHud` | `true` | Enables the in-game HUD. Without this, no HUD appears even if the other Show* fields are set. |
|
||||
| `ShowScore` | `true` | Shows the player's current score on the HUD. |
|
||||
| `ShowTime` | `true` | Shows time remaining in the current round on the HUD. Only renders when `RoundLengthSeconds > 0`. |
|
||||
| `ShowRound` | `true` | Shows current round out of total rounds (e.g. `2 / 3`). Only renders when `TotalRounds > 1`. |
|
||||
|
||||
## How Rounds Work
|
||||
|
||||
You do not need to manually advance rounds. The runtime handles this automatically:
|
||||
|
||||
1. When the game starts, the `$round` timer begins counting down `RoundLengthSeconds` for round 1.
|
||||
2. When the timer expires, round 2 starts and the timer resets.
|
||||
3. When round 3's timer expires, `on_game_rounds_complete` is dispatched.
|
||||
|
||||
Your trigger volumes use the `CurrentRound` condition to check which round is active, so each capture zone automatically becomes active or inactive as rounds change.
|
||||
|
||||
## Testing With One Player
|
||||
|
||||
Change `MinPlayers` to `1` while setting up and testing your world. Change it back before going live.
|
||||
@@ -0,0 +1,86 @@
|
||||
# King of the Hill — Join Pad & Auto-Start
|
||||
|
||||
This step sets up the volumes that let players join the queue and auto-start the game once enough players are ready.
|
||||
|
||||
---
|
||||
|
||||
## 1. Arena Boundary Volume
|
||||
|
||||
This volume is not interactive — it exists purely so the runtime knows which map it is running on. Place it as a large box that encompasses the entire arena.
|
||||
|
||||
**Volume type:** Any (Enter trigger is fine, no effects needed)
|
||||
|
||||
**Tags:**
|
||||
|
||||
| Tag | Value |
|
||||
|---|---|
|
||||
| `MinigameId` | `King_Of_The_Hill` |
|
||||
| `MapId` | `Hillside` *(replace with your map name)* |
|
||||
| `MapRole` | `MainArena` |
|
||||
|
||||
No conditions. No effects.
|
||||
|
||||
> The `MapId` value is arbitrary — pick a name that describes your arena (e.g. `Hillside`, `Volcano`, `Castle`). Use the same value on every other volume in this world that belongs to this map.
|
||||
|
||||
---
|
||||
|
||||
## 2. Queue Pad
|
||||
|
||||
Place this volume at a lobby pad where players gather before the game. When stepped on, it adds the player to the queue and attempts to start the game. The start attempt is a no-op until `MinPlayers` (2) have joined, at which point the runtime is created automatically.
|
||||
|
||||
**Volume type:** Enter trigger
|
||||
|
||||
**Tags:**
|
||||
|
||||
| Tag | Value |
|
||||
|---|---|
|
||||
| `MinigameId` | `King_Of_The_Hill` |
|
||||
|
||||
**Effects:**
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `JoinMinigameQueue` | `MinigameId = King_Of_The_Hill` |
|
||||
| `StartQueuedMinigame` | `MinigameId = King_Of_The_Hill` |
|
||||
|
||||
> **How the auto-start works:** `StartQueuedMinigame` checks that no runtime is already running and that the queue has at least `MinPlayers` players before doing anything. With `MinPlayers = 2`: Player 1 steps on the pad — `StartQueuedMinigame` sees only 1 queued player and skips. Player 2 steps on the pad — queue now has 2 players, `StartQueuedMinigame` creates the runtime (phase = `WAITING_FOR_PLAYERS`). The signal volume below immediately advances it to `ACTIVE`.
|
||||
|
||||
Players who step on this pad after the game has already started are queued for the next game — `StartQueuedMinigame` detects the active runtime and skips.
|
||||
|
||||
---
|
||||
|
||||
## 3. STARTING Phase Volume
|
||||
|
||||
The system runs the `CountdownSeconds` countdown automatically during `WAITING_FOR_PLAYERS`. Once the countdown finishes, the runtime advances to `STARTING` and fires `SignalPhaseStart=STARTING`. Your volume responds by setting the phase to `ACTIVE` to begin the game.
|
||||
|
||||
**Volume type:** Any (Tag Added trigger — fired by the runtime, not physically entered)
|
||||
|
||||
**Tags:**
|
||||
|
||||
| Tag | Value |
|
||||
|---|---|
|
||||
| `MinigameId` | `King_Of_The_Hill` |
|
||||
| `MapId` | `Hillside` |
|
||||
| `SignalPhaseStart` | `STARTING` |
|
||||
|
||||
**Effects:**
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `SetMinigamePhase` | `MinigameId = King_Of_The_Hill`, `Phase = ACTIVE` |
|
||||
| `SetRound` | `Operation = Set`, `Amount = 1` |
|
||||
(anything else you want to happen? Effects, sounds, Starting cinematic? Do before setting to active and starting the round)
|
||||
|
||||
> **Countdown**: with `CountdownSeconds = 10` in the definition, a "Starting in N..." message is sent to all players each second. If a player steps off the queue pad (`LeaveMinigameQueue`) or disconnects during the countdown and the player count drops below `MinPlayers`, the countdown cancels and players are returned to the queue automatically.
|
||||
>
|
||||
> **Skip the countdown**: set `CountdownSeconds = 0` in the definition to go from `STARTING` to `ACTIVE` immediately.
|
||||
|
||||
---
|
||||
|
||||
## Leave Queue (Optional)
|
||||
|
||||
If players want to leave before the game starts, add a separate pad with:
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `LeaveMinigameQueue` | `MinigameId = King_Of_The_Hill` |
|
||||
@@ -0,0 +1,67 @@
|
||||
# King of the Hill — Spawn Zone & Player Activation
|
||||
|
||||
Players are not automatically active when the game starts. They must enter the spawn zone, which triggers the activation lifecycle: inventory save, item giving, game mode change, and HUD display.
|
||||
|
||||
---
|
||||
|
||||
## What Activation Does
|
||||
|
||||
When `SetPlayerStatus ACTIVE` fires for a player, the runtime:
|
||||
|
||||
1. Saves their current inventory (if `SavePlayerInventory = true`, the default).
|
||||
2. Gives them their start items or assigned loadout (if any defined in the definition).
|
||||
3. Applies `RequiredGameMode` (`Adventure` in this tutorial).
|
||||
4. Shows the HUD (since `ShowHud = true`).
|
||||
|
||||
This only happens once per player per game. If the same player re-enters the spawn zone it is harmless — the runtime ignores duplicate ACTIVE requests.
|
||||
|
||||
---
|
||||
|
||||
## Spawn Zone Volume
|
||||
|
||||
Place this volume at the area where players begin the round — typically a platform or small room at the edge of the arena that all players pass through when the game starts.
|
||||
|
||||
**Volume type:** Enter trigger
|
||||
|
||||
**Tags:**
|
||||
|
||||
| Tag | Value |
|
||||
|---|---|
|
||||
| `MinigameId` | `King_Of_The_Hill` |
|
||||
| `MapId` | `Hillside` |
|
||||
|
||||
**Conditions:**
|
||||
|
||||
| Condition | Fields | Purpose |
|
||||
|---|---|---|
|
||||
| `PlayerInMinigame` | `MinigameId = King_Of_The_Hill` | Only fires for players who are actually in the runtime (not random passersby). |
|
||||
| `MinigamePhase` | `MinigameId = King_Of_The_Hill`, `Phase = ACTIVE` | Prevents accidental activation while players are still in the lobby countdown. |
|
||||
|
||||
**Effects:**
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `SetPlayerStatus` | `MinigameId = King_Of_The_Hill`, `Status = ACTIVE` |
|
||||
| `SetSpawnPoint` | `MinigameId = King_Of_The_Hill`, `DestinationId = 100,64,200` *(replace with your spawn coordinates)* |
|
||||
|
||||
> The `SetSpawnPoint` stores a respawn destination for each player. When a player dies during the game, the runtime automatically respawns them at their stored checkpoint. Replace `100,64,200` with the actual world coordinates of your spawn area center. You can also use the format `world_name,X,Y,Z` if the spawn is in a different world.
|
||||
|
||||
---
|
||||
|
||||
## How Players Get to the Spawn Zone
|
||||
|
||||
In a typical KOTH setup, players are somewhere in the arena or lobby when the game starts. You have two options:
|
||||
|
||||
**Option A — Players walk there.** The spawn zone is accessible from the lobby area. When the game starts and phase becomes `ACTIVE`, players walk through the spawn zone on their way into the arena. This is the simplest approach and works well when the lobby and arena are adjacent.
|
||||
|
||||
**Option B — Teleport on game start.** Add a `SignalPhaseStart=ACTIVE` signal volume (covered in `06-round-signals.md`) with a `RespawnPlayer` effect. This teleports all active players to their spawn on phase change.
|
||||
|
||||
For this tutorial, Option A is assumed. If using Option B, `RespawnPlayer` resolves the destination using the player's stored checkpoint from `SetSpawnPoint`, so the activation volume still needs to fire first. Consider placing the spawn zone between the lobby exit and the arena entrance so it is always traversed.
|
||||
|
||||
---
|
||||
|
||||
## Respawn on Death
|
||||
|
||||
Because `SetSpawnPoint` is called at activation, player deaths during the game automatically respawn at those coordinates. No additional setup is required for basic respawning.
|
||||
|
||||
If you want players to respawn with a delay or only when a specific condition is met, add a `RespawnPlayer` effect to a separate signal or death-event volume.
|
||||
@@ -0,0 +1,147 @@
|
||||
# King of the Hill : Capture Zones
|
||||
|
||||
Each round has one active capture zone. Players standing inside the correct zone for the current round earn +1 point per second. Zones outside the active round do nothing.
|
||||
|
||||
You will create three separate trigger volumes : one per hilltop.
|
||||
|
||||
---
|
||||
|
||||
## How Scoring Works
|
||||
|
||||
Each capture zone uses:
|
||||
|
||||
- A **TICK** volume type so it fires continuously while players are standing inside it.
|
||||
- A `CurrentRound` condition that passes only when the correct round number is active.
|
||||
- A `ModifyPlayerScore` effect that adds 1 point per trigger fire.
|
||||
|
||||
The tick rate on the volume controls how often points are awarded. Set it to **1 second** in the editor so players earn 1 point per second. If the tick fires every 0.5 seconds, players would earn 2 points per second : adjust the amount or tick rate to your preference.
|
||||
leaving it at zero would be everytick its fired, Giving 30 points
|
||||
---
|
||||
|
||||
## Capture Zone A : Round 1
|
||||
|
||||
Place this volume on Hilltop A, the first round's scoring area. Size it so that players must be clearly on top of the hill.
|
||||
|
||||
**Volume type:** TICK trigger (tick interval: 1 second)
|
||||
|
||||
**Tags:**
|
||||
|
||||
| Tag | Value |
|
||||
|---|---|
|
||||
| `MinigameId` | `King_Of_The_Hill` |
|
||||
| `MapId` | `Hillside` |
|
||||
|
||||
**Conditions:**
|
||||
|
||||
| Condition | Fields | Purpose |
|
||||
|---|---|---|
|
||||
| `PlayerInMinigame` | `MinigameId = King_Of_The_Hill` | Only scores players in the runtime. |
|
||||
| `CurrentRound` | `MinigameId = King_Of_The_Hill`, `Compare = EQUAL`, `Round = 1` | Only active during Round 1. |
|
||||
|
||||
**Effects:**
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `ModifyPlayerScore` | `MinigameId = King_Of_The_Hill`, `Operation = ADD`, `Amount = 1` |
|
||||
|
||||
---
|
||||
|
||||
## Capture Zone B : Round 2
|
||||
|
||||
Place this volume on Hilltop B. Same setup as Zone A with only the round number changed.
|
||||
|
||||
**Volume type:** TICK trigger (tick interval: 1 second)
|
||||
|
||||
**Tags:** Same as Zone A (`MinigameId`, `MapId`)
|
||||
|
||||
**Conditions:**
|
||||
|
||||
| Condition | Fields |
|
||||
|---|---|
|
||||
| `PlayerInMinigame` | `MinigameId = King_Of_The_Hill` |
|
||||
| `CurrentRound` | `MinigameId = King_Of_The_Hill`, `Compare = EQUAL`, `Round = 2` |
|
||||
|
||||
**Effects:**
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `ModifyPlayerScore` | `MinigameId = King_Of_The_Hill`, `Operation = ADD`, `Amount = 1` |
|
||||
|
||||
---
|
||||
|
||||
## Capture Zone C : Round 3
|
||||
|
||||
Place this volume on Hilltop C.
|
||||
|
||||
**Volume type:** TICK trigger (tick interval: 1 second)
|
||||
|
||||
**Tags:** Same as above
|
||||
|
||||
**Conditions:**
|
||||
|
||||
| Condition | Fields |
|
||||
|---|---|
|
||||
| `PlayerInMinigame` | `MinigameId = King_Of_The_Hill` |
|
||||
| `CurrentRound` | `MinigameId = King_Of_The_Hill`, `Compare = EQUAL`, `Round = 3` |
|
||||
|
||||
**Effects:**
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `ModifyPlayerScore` | `MinigameId = King_Of_The_Hill`, `Operation = ADD`, `Amount = 1` |
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
**You may want to add further effects the zones** :
|
||||
On Capture Zone 1 using `SignalRoundStart=1` volume tag (covered in `06-round-signals.md` and `tags.md`)
|
||||
you can add the following to play a sound at the start of the round and have a VFX with a duration of the round set
|
||||
|
||||
On Tag Added trigger
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `PlaySound` | `Your choice of sound`|
|
||||
| `Play VFX` | `Your choice of VFX` `Duration = round time`|
|
||||
|
||||
|
||||
|
||||
**Multiple players on the hill at once** : each player in the volume gets the `ModifyPlayerScore` effect independently. If two players stand on Hilltop A during Round 1, both earn +1/second. This is intentional for KOTH : fighting over the hill is part of the game.
|
||||
|
||||
**Zone size** : make your capture zones intentionally tight so there is real competition for the spot. A zone that is too large removes the "king of the hill" tension.
|
||||
|
||||
|
||||
**Dymanic Zone Size**
|
||||
Lets say you have rounds last 60 secounds. You want the Capture Zone for round 2 to get smaller half way.
|
||||
Create two Capture Zones one the full size and one the half size
|
||||
|
||||
Add on the large Capture Zone 2 using `SignalRoundStart=2` volume tag (covered in `06-round-signals.md` and `tags.md`)
|
||||
And another tag to each to later identify them
|
||||
`Round2Capture=Large`
|
||||
`Round2Capture=Small`
|
||||
|
||||
The larger Capture Zone
|
||||
On Tag Added trigger
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `DisableVolume` | `MatchTagKey=Round2Capture` `MatchTagValue=Small`|
|
||||
| `PlaySound` | `Your choice of sound`|
|
||||
| `Play VFX` | `Your choice of VFX` `Duration = 30`|
|
||||
| `EnableVolume` | `EffectDelay=30` `MatchTagKey=Round2Capture` `MatchTagValue=Small`|
|
||||
| `ModifyTag` | `Operation=Set` `TagKey=SmallRound2Capture` `TagValue=Enabled` `MatchTagKey=Round2Capture` `MatchTagValue=Small`|
|
||||
| `DisableVolume` | `MatchTagKey=Round2Capture` `MatchTagValue=Large`|
|
||||
|
||||
The Smaller Capture Zone
|
||||
On Tag Added trigger
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `PlaySound` | `Your choice of sound`|
|
||||
| `Play VFX` | `Your choice of VFX` `Duration = 30`|
|
||||
| `EnableVolume` | `EffectDelay=30` `MatchTagKey=Round2Capture` `MatchTagValue=Large`|
|
||||
| `ModifyTag` | `Operation=Remove` `TagKey=SmallRound2Capture` `TagValue=Enabled` `MatchTagKey=Round2Capture` `MatchTagValue=Small`|
|
||||
| `DisableVolume` | `MatchTagKey=Round2Capture` `MatchTagValue=Large`|
|
||||
|
||||
|
||||
There are a couple of ways to do this, but this is just one I felt like typing.
|
||||
|
||||
**Score display** : the HUD shows the current score in real time. Players can see how their score compares while standing on the hill. Round and time remaining are also shown because `ShowRound = true` and `ShowTime = true` are set in the definition.
|
||||
@@ -0,0 +1,112 @@
|
||||
# King of the Hill — Round Signals & Game End
|
||||
|
||||
This step wires up announcements for each new round and explains how the game ends automatically when the final round completes.
|
||||
|
||||
---
|
||||
|
||||
## How Signal Volumes Work
|
||||
|
||||
Signal volumes have special tags (`SignalRoundStart`, `SignalPhaseTick`, `SignalPhaseStart`, etc.) that the runtime writes to at the right moment. When the tag value changes, Hytale fires the volume's `TAG_ADDED` trigger, which runs the attached effects.
|
||||
|
||||
Every signal volume must also have `MinigameId` set so the runtime knows which game's signals to respond to.
|
||||
|
||||
---
|
||||
|
||||
## Round 2 Announcement
|
||||
|
||||
When Round 2 begins, fire a message to all players announcing the new hill location.
|
||||
|
||||
**Volume type:** Any (Tag Added trigger is conventional for signal volumes — the volume is never physically entered, it is fired by the runtime)
|
||||
|
||||
**Tags:**
|
||||
|
||||
| Tag | Value |
|
||||
|---|---|
|
||||
| `MinigameId` | `King_Of_The_Hill` |
|
||||
| `MapId` | `Hillside` |
|
||||
| `SignalRoundStart` | `2` |
|
||||
|
||||
**Effects:**
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `SendMinigameMessage` | `MinigameId = King_Of_The_Hill`, `MessageKey = round_2_start`, `Target = ALL` |
|
||||
|
||||
> `MessageKey` references a translation key in your server's language files. If you do not have a dedicated translations setup, you can skip `SendMinigameMessage` for now — the HUD already shows the updated round number automatically.
|
||||
|
||||
---
|
||||
|
||||
## Round 3 Announcement
|
||||
|
||||
Same structure, fires when Round 3 begins.
|
||||
|
||||
**Tags:**
|
||||
|
||||
| Tag | Value |
|
||||
|---|---|
|
||||
| `MinigameId` | `King_Of_The_Hill` |
|
||||
| `MapId` | `Hillside` |
|
||||
| `SignalRoundStart` | `3` |
|
||||
|
||||
**Effects:**
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `SendMinigameMessage` | `MinigameId = King_Of_The_Hill`, `MessageKey = round_3_start`, `Target = ALL` |
|
||||
|
||||
---
|
||||
|
||||
## How the Game Ends Automatically
|
||||
|
||||
When the Round 3 timer expires, the runtime calls `end()` automatically (because `TotalRounds = 3` and neither `OvertimeEnabled` nor `SuddenDeathEnabled` are set). No extra timer volume is needed.
|
||||
|
||||
The end sequence fires in this order:
|
||||
|
||||
1. `SignalPhaseStart=ENDING` fires — use this for a scoreboard display, player freeze, or end announcement.
|
||||
2. HUDs are removed, inventories restored, rewards distributed.
|
||||
3. `on_game_end` event fires (with `reason = "rounds_complete"`).
|
||||
4. Runtime is removed from the active list.
|
||||
5. `SignalPhaseStart=RESETTING` fires — use this to restore blocks, re-enable the queue pad, etc.
|
||||
6. `on_arena_reset` event fires.
|
||||
|
||||
You do not need a `StartTimer`/`SignalOnTimerExpire` pair to end the game.
|
||||
|
||||
---
|
||||
|
||||
## ENDING Phase Volume (Optional)
|
||||
|
||||
To show a final message or freeze players briefly at game end, respond to `SignalPhaseStart=ENDING`:
|
||||
|
||||
**Tags:**
|
||||
|
||||
| Tag | Value |
|
||||
|---|---|
|
||||
| `MinigameId` | `King_Of_The_Hill` |
|
||||
| `MapId` | `Hillside` |
|
||||
| `SignalPhaseStart` | `ENDING` |
|
||||
|
||||
**Example effects:**
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `SendMinigameMessage` | `MinigameId = King_Of_The_Hill`, `MessageKey = game_over`, `Target = ALL` |
|
||||
|
||||
---
|
||||
|
||||
## Round 1 Announcement (Optional)
|
||||
|
||||
Round 1 begins immediately when the game goes ACTIVE (there is no `SignalRoundStart=1` in the current round implementation for the initial round). If you want a Round 1 announcement, fire it from the `SignalPhaseStart=ACTIVE` volume set up in step 03:
|
||||
|
||||
**Tags:**
|
||||
|
||||
| Tag | Value |
|
||||
|---|---|
|
||||
| `MinigameId` | `King_Of_The_Hill` |
|
||||
| `MapId` | `Hillside` |
|
||||
| `SignalPhaseStart` | `ACTIVE` |
|
||||
|
||||
**Effects:**
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `SendMinigameMessage` | `MinigameId = King_Of_The_Hill`, `MessageKey = round_1_start`, `Target = ALL` |
|
||||
@@ -0,0 +1,87 @@
|
||||
# King of the Hill — Ending & Resetting
|
||||
|
||||
This step covers what happens when the game ends, what signals fire and when, and how to use arena reset to prepare for the next game.
|
||||
|
||||
---
|
||||
|
||||
## What Happens When the Game Ends
|
||||
|
||||
When the final round timer expires (and no overtime/sudden death is configured), the runtime calls `end("rounds_complete")` automatically. The full sequence:
|
||||
|
||||
1. **HUDs removed** for all players in the runtime.
|
||||
2. **Phase set to `ENDING`** → `SignalPhaseStart=ENDING` fires.
|
||||
3. **Active signal timers cancelled.**
|
||||
4. **Temporary entities cleaned up** (spawned NPCs/items tracked by the runtime).
|
||||
5. **Player inventories restored** (since `RestorePlayerInventory = true` is the default).
|
||||
6. **Rewards distributed** (if any `Rewards` are defined in the definition).
|
||||
7. **`on_game_end` event dispatched** with `reason = "rounds_complete"` and final scores.
|
||||
8. **Runtime state cleared** — scores, player status, timers, counters all zeroed.
|
||||
9. **Runtime removed** from the active list.
|
||||
10. **Phase set to `RESETTING`** → `SignalPhaseStart=RESETTING` fires.
|
||||
11. **`on_arena_reset` event dispatched** (since `ResetOnEnd = true` is the default).
|
||||
|
||||
You do not need to manually reset scores or clear HUDs.
|
||||
|
||||
---
|
||||
|
||||
## ENDING Phase Volume (Optional)
|
||||
|
||||
Use `SignalPhaseStart=ENDING` to show a scoreboard, announce the winner, or freeze players briefly before cleanup. This fires while the runtime still holds final scores.
|
||||
|
||||
**Tags:**
|
||||
|
||||
| Tag | Value |
|
||||
|---|---|
|
||||
| `MinigameId` | `King_Of_The_Hill` |
|
||||
| `MapId` | `Hillside` |
|
||||
| `SignalPhaseStart` | `ENDING` |
|
||||
|
||||
**Example effects:**
|
||||
|
||||
| Effect | Fields |
|
||||
|---|---|
|
||||
| `SendMinigameMessage` | `MinigameId = King_Of_The_Hill`, `MessageKey = game_over`, `Target = ALL` |
|
||||
|
||||
---
|
||||
|
||||
## Arena Reset Volume
|
||||
|
||||
Use `SignalPhaseStart=RESETTING` to restore any world state changed during the game. This fires after the runtime has been cleaned up, so it is safe to re-enable the queue pad without risk of double-triggering.
|
||||
|
||||
> **Scope note:** `SignalPhaseStart=RESETTING` is scoped by `MinigameId` tag match, NOT by physical containment within the `MapRole=MainArena` boundary. Any volume anywhere in the world with a matching `MinigameId` tag will respond. The arena boundary volume is only used for map *discovery*, not for event routing.
|
||||
|
||||
For this King of the Hill setup there are no block placements or NPC spawns, so the arena reset volume is optional. Add it if you want to re-enable the queue pad, reset visual markers, or restore barriers changed mid-game.
|
||||
|
||||
**Tags:**
|
||||
|
||||
| Tag | Value |
|
||||
|---|---|
|
||||
| `MinigameId` | `King_Of_The_Hill` |
|
||||
| `MapId` | `Hillside` |
|
||||
| `SignalPhaseStart` | `RESETTING` |
|
||||
|
||||
**Example effects:**
|
||||
|
||||
| Effect | Fields | Purpose |
|
||||
|---|---|---|
|
||||
| `PlaceBlocks` | *(coordinates of any changed areas, original block id)* | Restore modified terrain. |
|
||||
|
||||
---
|
||||
|
||||
## Repeating the Game
|
||||
|
||||
After the runtime ends and `SignalPhaseStart=RESETTING` fires, the minigame is ready to start again. Players can step back onto the queue pad and a new runtime will be created when `StartQueuedMinigame` fires again.
|
||||
|
||||
No state from the previous game persists — scores, player status, timers, and counters are all cleared by the end flow.
|
||||
|
||||
---
|
||||
|
||||
## Manual Reset
|
||||
|
||||
If you need to reset the game mid-match (for testing or crash recovery), use the admin command:
|
||||
|
||||
```
|
||||
/minigame reset King_Of_The_Hill
|
||||
```
|
||||
|
||||
This calls `ResetMinigame` directly, which sets phase to `RESETTING`, fires `SignalPhaseStart=RESETTING`, clears runtime state, and dispatches `on_arena_reset` — without going through the normal end flow (no rewards, no inventory restore, no `ENDING` phase).
|
||||
@@ -0,0 +1,135 @@
|
||||
# King of the Hill — Complete Reference
|
||||
|
||||
All volumes and the definition file in one place. Use this as a checklist when setting up your world.
|
||||
|
||||
---
|
||||
|
||||
## Definition File
|
||||
|
||||
**Path:** `src/main/resources/Server/Minigames/King_Of_The_Hill.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"Id": "King_Of_The_Hill",
|
||||
"Name": "King of the Hill",
|
||||
"Enabled": true,
|
||||
"MinPlayers": 2,
|
||||
"MaxPlayers": 16,
|
||||
"TeamMode": "SOLO",
|
||||
"WinCondition": "HIGHEST_SCORE",
|
||||
"RoundLengthSeconds": 120,
|
||||
"TotalRounds": 3,
|
||||
"CountdownSeconds": 10,
|
||||
"AllowPvp": true,
|
||||
"RequiredGameMode": "Adventure",
|
||||
"ShowHud": true,
|
||||
"ShowScore": true,
|
||||
"ShowTime": true,
|
||||
"ShowRound": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Volume Checklist
|
||||
|
||||
| # | Volume Name | Type | Tags | Conditions | Effects |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | Arena Boundary | Enter | `MinigameId=King_Of_The_Hill` `MapId=Hillside` `MapRole=MainArena` | — | — |
|
||||
| 2 | Queue Pad | Enter | `MinigameId=King_Of_The_Hill` | — | `JoinMinigameQueue` → `StartQueuedMinigame` |
|
||||
| 3 | Starting Signal | Tag Added | `MinigameId=King_Of_The_Hill` `MapId=Hillside` `SignalPhaseStart=STARTING` | — | `SetMinigamePhase ACTIVE` |
|
||||
| 4 | Spawn Zone | Enter | `MinigameId=King_Of_The_Hill` `MapId=Hillside` | `PlayerInMinigame` + `MinigamePhase=ACTIVE` | `SetPlayerStatus ACTIVE` → `SetSpawnPoint` |
|
||||
| 5 | Capture Zone A | TICK (1s) | `MinigameId=King_Of_The_Hill` `MapId=Hillside` | `PlayerInMinigame` + `CurrentRound=EQUAL 1` | `ModifyPlayerScore ADD 1` |
|
||||
| 6 | Capture Zone B | TICK (1s) | `MinigameId=King_Of_The_Hill` `MapId=Hillside` | `PlayerInMinigame` + `CurrentRound=EQUAL 2` | `ModifyPlayerScore ADD 1` |
|
||||
| 7 | Capture Zone C | TICK (1s) | `MinigameId=King_Of_The_Hill` `MapId=Hillside` | `PlayerInMinigame` + `CurrentRound=EQUAL 3` | `ModifyPlayerScore ADD 1` |
|
||||
| 8 | Round 2 Signal | Tag Added | `MinigameId=King_Of_The_Hill` `MapId=Hillside` `SignalRoundStart=2` | — | `SendMinigameMessage round_2_start ALL` |
|
||||
| 9 | Round 3 Signal | Tag Added | `MinigameId=King_Of_The_Hill` `MapId=Hillside` `SignalRoundStart=3` | — | `SendMinigameMessage round_3_start ALL` |
|
||||
| 10 | End Announcement | Tag Added | `MinigameId=King_Of_The_Hill` `MapId=Hillside` `SignalPhaseStart=ENDING` | — | `SendMinigameMessage game_over ALL` *(optional)* |
|
||||
| 11 | Arena Reset | Tag Added | `MinigameId=King_Of_The_Hill` `MapId=Hillside` `SignalPhaseStart=RESETTING` | — | *(block restore effects)* *(optional)* |
|
||||
|
||||
The game ends automatically when Round 3's timer expires — no end-game timer volume is needed.
|
||||
|
||||
---
|
||||
|
||||
## Volume Detail — Queue Pad (Auto-Start)
|
||||
|
||||
```
|
||||
Tags:
|
||||
MinigameId = King_Of_The_Hill
|
||||
|
||||
Effects:
|
||||
JoinMinigameQueue MinigameId=King_Of_The_Hill
|
||||
StartQueuedMinigame MinigameId=King_Of_The_Hill
|
||||
```
|
||||
|
||||
`StartQueuedMinigame` is a no-op until `MinPlayers` (2) are in the queue AND no runtime is already running.
|
||||
|
||||
---
|
||||
|
||||
## Volume Detail — Starting Signal
|
||||
|
||||
```
|
||||
Tags:
|
||||
MinigameId = King_Of_The_Hill
|
||||
MapId = Hillside
|
||||
SignalPhaseStart = STARTING
|
||||
|
||||
Effects:
|
||||
SetMinigamePhase MinigameId=King_Of_The_Hill Phase=ACTIVE
|
||||
```
|
||||
|
||||
Fires after the countdown completes. The system runs the `CountdownSeconds` countdown
|
||||
automatically during `WAITING_FOR_PLAYERS` — no timer volume required.
|
||||
|
||||
---
|
||||
|
||||
## Volume Detail — Spawn Zone
|
||||
|
||||
```
|
||||
Tags:
|
||||
MinigameId = King_Of_The_Hill
|
||||
MapId = Hillside
|
||||
|
||||
Conditions:
|
||||
PlayerInMinigame MinigameId=King_Of_The_Hill
|
||||
MinigamePhase MinigameId=King_Of_The_Hill Phase=ACTIVE
|
||||
|
||||
Effects:
|
||||
SetPlayerStatus MinigameId=King_Of_The_Hill Status=ACTIVE
|
||||
SetSpawnPoint MinigameId=King_Of_The_Hill DestinationId=<X,Y,Z>
|
||||
```
|
||||
|
||||
Replace `<X,Y,Z>` with the world coordinates of your spawn area.
|
||||
|
||||
---
|
||||
|
||||
## Volume Detail — Capture Zone A (copy pattern for B and C)
|
||||
|
||||
```
|
||||
Tags:
|
||||
MinigameId = King_Of_The_Hill
|
||||
MapId = Hillside
|
||||
|
||||
Conditions:
|
||||
PlayerInMinigame MinigameId=King_Of_The_Hill
|
||||
CurrentRound MinigameId=King_Of_The_Hill Compare=EQUAL Round=1
|
||||
|
||||
Effects:
|
||||
ModifyPlayerScore MinigameId=King_Of_The_Hill Operation=ADD Amount=1
|
||||
```
|
||||
|
||||
Change `Round=1` to `Round=2` and `Round=3` for Zones B and C.
|
||||
|
||||
---
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
| Symptom | Likely Cause |
|
||||
|---|---|
|
||||
| HUD never appears | `SetPlayerStatus ACTIVE` is not firing — check that the spawn zone has both `PlayerInMinigame` and `MinigamePhase=ACTIVE` conditions. |
|
||||
| Score never changes | Capture zone tick interval is not set, or the `CurrentRound` condition does not match the active round. Verify the `Round` value matches the round number (1, 2, or 3). |
|
||||
| Game never starts | Queue pad must have both `JoinMinigameQueue` AND `StartQueuedMinigame`. The starting signal volume must have `SignalPhaseStart=STARTING` with `SetMinigamePhase ACTIVE` effect. |
|
||||
| Game never ends | Rounds do not auto-end if `OvertimeEnabled` or `SuddenDeathEnabled` are set in the definition. Verify neither is enabled. |
|
||||
| Volume conditions blocked | Wrong `MinigameId` value — ensure every volume and every condition/effect field uses exactly `King_Of_The_Hill` (case-sensitive, underscores not spaces). |
|
||||
| Players not activating | Phase was never set to `ACTIVE` — verify the auto-start signal volume (`SignalPhaseStart=WAITING_FOR_PLAYERS`) is present and fires `SetMinigamePhase ACTIVE`. |
|
||||
| Game starts with 1 player | `MinPlayers` in the definition is set to `1`. Change to `2` if you need two players. |
|
||||
@@ -0,0 +1,50 @@
|
||||
These are just examples of how tutorial files might be depending on their game and format.
|
||||
solo-brawl/
|
||||
01-overview.md
|
||||
02-create-minigame-definition.md
|
||||
03-create-start-pad.md
|
||||
04-create-arena-and-spawns.md
|
||||
05-activate-players.md
|
||||
06-enable-pvp-and-damage.md
|
||||
07-add-scoring.md
|
||||
08-add-timer-and-win-condition.md
|
||||
09-end-reset-and-cleanup.md
|
||||
10-full-example-files.md
|
||||
|
||||
team-objective-game/
|
||||
01-overview.md
|
||||
02-create-minigame-definition.md
|
||||
03-create-queue-and-start-flow.md
|
||||
04-create-map-tags-and-arena.md
|
||||
05-create-team-spawns.md
|
||||
06-assign-and-balance-teams.md
|
||||
07-activate-players.md
|
||||
08-create-objectives.md
|
||||
09-add-team-scoring.md
|
||||
10-add-win-condition.md
|
||||
11-end-reset-and-cleanup.md
|
||||
12-full-example-files.md
|
||||
|
||||
parkour-checkpoints/
|
||||
01-overview.md
|
||||
02-create-minigame-definition.md
|
||||
03-create-start-and-finish-volumes.md
|
||||
04-create-checkpoints.md
|
||||
05-track-player-progress.md
|
||||
06-add-timer.md
|
||||
07-handle-falls-and-respawns.md
|
||||
08-finish-reset-and-cleanup.md
|
||||
09-full-example-files.md
|
||||
|
||||
hot-potato/
|
||||
01-overview.md
|
||||
02-create-minigame-definition.md
|
||||
03-create-queue-and-start-flow.md
|
||||
04-create-arena-and-spawns.md
|
||||
05-activate-players.md
|
||||
06-spawn-the-potato-item.md
|
||||
07-pass-the-potato.md
|
||||
08-countdown-and-explosion.md
|
||||
09-eliminate-or-score-players.md
|
||||
10-end-reset-and-cleanup.md
|
||||
11-full-example-files.md
|
||||
@@ -97,6 +97,9 @@ All minigame effects that operate on a runtime include a `MinigameId` field. In
|
||||
| `ClearInventory` | `MinigameId`, optional `PlayerId` | Clears the player's inventory. |
|
||||
| `SetObjectiveStatus` | `MinigameId`, `ObjectiveId`, `Status` | Creates or updates an objective status and dispatches `on_objective_complete` when complete. |
|
||||
| `ModifyObjectiveProgress` | `MinigameId`, `ObjectiveId`, `Operation`, `Amount` | Sets, adds, or subtracts objective progress and completes an active objective when progress reaches the required threshold. |
|
||||
| `OpenMinigameQueueUI` | optional `MinigameId`, optional `MapId` | Opens the queue UI page for the triggering player. Mode is inferred: no `MinigameId` → Global browser; `MinigameId` only → Single-game map list; both `MinigameId` and `MapId` → Local arena popup. |
|
||||
| `StartPlayerTimer` | `MinigameId`, optional `PlayerId` | Starts a per-player stopwatch for the triggering player. Records the start timestamp in player state. Use on race start pads. If `PlayerId` is blank, the trigger context player is used. |
|
||||
| `StopPlayerTimer` | `MinigameId`, optional `PlayerId`, optional `Operation` | Stops the player's stopwatch and applies the lap time to the player's score. `Operation` controls multi-round behaviour: `SET` (default) replaces the score, `ADD` accumulates lap times for a total time, `BEST` keeps the lowest recorded lap. Ignored if `StartPlayerTimer` was never called for this player. |
|
||||
|
||||
### Operation Values
|
||||
|
||||
|
||||
+14
-1
@@ -18,7 +18,8 @@ Definition file: `Server/Minigames/Quick_Brawl.json`
|
||||
"WinCondition": "HIGHEST_SCORE",
|
||||
"RoundLengthSeconds": 120,
|
||||
"CountdownSeconds": 5,
|
||||
"AllowPvp": true
|
||||
"AllowPvp": true,
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -28,6 +29,18 @@ Editor setup:
|
||||
2. Add the `StartMinigame` effect.
|
||||
3. Set `MinigameId` to `Quick_Brawl` using the asset picker.
|
||||
|
||||
## Activating Players
|
||||
|
||||
Players must be explicitly set to `ACTIVE` status before the activation lifecycle runs. This is what triggers inventory saving, start item giving, game mode change, and HUD display. Without a `SetPlayerStatus ACTIVE` effect, none of these happen.
|
||||
|
||||
A common pattern is a spawn-room trigger volume that all players enter when the game starts:
|
||||
|
||||
1. Create a trigger volume covering the spawn area.
|
||||
2. Add `PlayerInMinigame` as a condition (`MinigameId = Quick_Brawl`, leave `PlayerId` blank).
|
||||
3. Add `SetPlayerStatus` as an effect (`MinigameId = Quick_Brawl`, `Status = ACTIVE`, leave `PlayerId` blank).
|
||||
|
||||
The entering player is resolved from the trigger context, so leaving `PlayerId` blank activates whoever enters the volume.
|
||||
|
||||
## Score Zone
|
||||
|
||||
Definition file: `Server/Minigames/Hill_Points.json`
|
||||
|
||||
@@ -65,6 +65,7 @@ Supported values:
|
||||
| `FIRST_TO_SCORE` | First player or team to a target score wins. |
|
||||
| `LAST_ALIVE` | Last active player or team wins. |
|
||||
| `OBJECTIVE_COMPLETE` | Objective completion determines the winner. |
|
||||
| `LOWEST_TIME` | Fastest completion time wins. Use `StartPlayerTimer` on the start pad and `StopPlayerTimer` on the finish line. Players who have not finished (score = 0) are ranked last. Times display as `M:SS.cc`. |
|
||||
| `CUSTOM` | Trigger logic determines the winner. |
|
||||
|
||||
## World Rules
|
||||
@@ -91,6 +92,28 @@ Supported values:
|
||||
| `StartLoadouts` | `LoadoutConfig[]` | No | `[]` | Named item loadouts. A player's assigned loadout (set via `SetPlayerLoadout`) takes priority over `StartItems`. |
|
||||
| `Rewards` | `RewardConfig[]` | No | `[]` | Rewards distributed at game end, before `on_game_end` fires. |
|
||||
|
||||
## HUD
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `ShowHud` | Boolean | No | `false` | Whether to show a HUD for each active player. Opt-in per game. |
|
||||
| `ShowScore` | Boolean | No | `true` | Whether to show the player's current score on the HUD. |
|
||||
| `ShowLives` | Boolean | No | `true` | Whether to show the player's remaining lives on the HUD. Only visible when `DefaultPlayerLives` is greater than `0`. |
|
||||
| `ShowPosition` | Boolean | No | `false` | Whether to show the player's current race position (rank among active non-eliminated players). Useful for racing games using `LOWEST_SCORE`. |
|
||||
| `ShowRound` | Boolean | No | `true` | Whether to show the current round out of total rounds (e.g. `2 / 3`). Only rendered when `TotalRounds` is greater than `1`. |
|
||||
| `ShowTime` | Boolean | No | `true` | Whether to show the time remaining in the current round (e.g. `1:45`). Only rendered when `RoundLengthSeconds` is greater than `0`. Displays `0:00` once the round timer has expired. |
|
||||
| `ShowScoreboard` | Boolean | No | `false` | Whether to show a ranked scoreboard panel on the HUD listing player names and scores in order. Capped at 10 rows or `MaxPlayers`, whichever is smaller. |
|
||||
|
||||
The HUD is shown when a player becomes `ACTIVE` and removed when the game ends. It refreshes approximately once per second. Position is ranked by current score respecting `WinCondition` (`LOWEST_SCORE` ranks lower scores ahead).
|
||||
|
||||
## Queue UI
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `UIQueueable` | Boolean | No | `false` | Whether this minigame appears in the global queue UI browser. Must be `true` for the game to show in `GLOBAL` mode. `SINGLE` and `LOCAL` modes work regardless of this flag — they are controlled by the `UIQueue=True` volume tag. |
|
||||
|
||||
When `UIQueueable=true`, the game will appear in the `OpenMinigameQueueUI` global browser alongside the queue count and a clickable join button, provided at least one `MainArena` volume has `UIQueue=True`.
|
||||
|
||||
## ItemStackConfig
|
||||
|
||||
```json
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
## Tutorial Feedback
|
||||
|
||||
## Tests
|
||||
|
||||
Need to test, expand, and work on load outs, back burner for now.
|
||||
|
||||
## Changes and questions
|
||||
|
||||
Make it in the set spawn point you can type the XYZ for where to spawn the player. (is that likely now, but should be their own boxes)
|
||||
|
||||
the double send message name. Need to change the custom one.
|
||||
|
||||
|
||||
|
||||
## Bugs
|
||||
|
||||
|
||||
|
||||
## Completed
|
||||
|
||||
- **HUD top-right positioning** — HUD anchor now uses `setRight(8).setTop(8)` and renders in the top-right corner.
|
||||
- **Scoreboard HUD panel** (`ShowScoreboard` in definition) — ranked player list with name + score shown below the standard HUD tiles. Capped at 10 rows. IDs are stable for delta refresh.
|
||||
- **Queue UI system** (`OpenMinigameQueueUI` effect) — three modes: Global (all UIQueueable games), Single (one game's maps), Local (single arena popup). Join auto-attempts game start. Leave queue button shown when already queued. Volume tags: `UIQueue=True` + `UIQueueType=Global|Single|Local` on `MainArena` volumes. Definition flag: `UIQueueable=true`.
|
||||
@@ -104,6 +104,68 @@ MapId=Castle
|
||||
SignalOnTimerExpire=overtime_warning
|
||||
```
|
||||
|
||||
## Map Voting Tags
|
||||
|
||||
These tags control which maps and variants appear in the voting UI shown to queued players once `MinPlayers` is reached on a game with `MapSelectionMode: VOTE`.
|
||||
|
||||
| Tag | Required | Values | Used By |
|
||||
|-----|----------|--------|---------|
|
||||
| `MapVoteable` | Yes | `True` | Marks a `MainArena` volume's map as a selectable option in the vote UI. |
|
||||
| `VariantVotable` | No | `True` | Marks a specific variant of a map as a selectable variant in the vote UI. Only meaningful when the volume also has `VariantId` set. |
|
||||
|
||||
Both tags must be on a volume that also has `MinigameId`, `MapId`, and `MapRole=MainArena`.
|
||||
|
||||
Map-only example (no variant choice):
|
||||
```text
|
||||
MinigameId=KOTH
|
||||
MapId=Castle
|
||||
MapRole=MainArena
|
||||
MapVoteable=True
|
||||
```
|
||||
|
||||
Map with voteable variants:
|
||||
```text
|
||||
MinigameId=KOTH
|
||||
MapId=Castle
|
||||
VariantId=Night
|
||||
MapRole=MainArena
|
||||
MapVoteable=True
|
||||
VariantVotable=True
|
||||
```
|
||||
|
||||
When variants are present the vote UI groups them under the map name. Voting for a variant records a `MapId:VariantId` preference (e.g. `Castle:Night`) that the queue service honours when selecting the starting map.
|
||||
|
||||
If only one total voteable option exists (one map with no variants, or one map with exactly one variant), the vote UI is skipped entirely and the game starts directly.
|
||||
|
||||
## Queue UI Tags
|
||||
|
||||
These tags opt a `MainArena` volume into the joinable queue UI. They are read by `OpenMinigameQueueUI` when a player opens the queue menu from an NPC or interaction pad.
|
||||
|
||||
| Tag | Required | Values | Used By |
|
||||
|-----|----------|--------|---------|
|
||||
| `UIQueue` | Yes | `True` | Marks the volume as a queue UI candidate. Must be on a `MapRole=MainArena` volume. |
|
||||
| `UIQueueType` | No | `Global`, `Single`, `Local` | Controls which display modes include this arena. Defaults to `Global`. |
|
||||
|
||||
`UIQueueType` meanings:
|
||||
|
||||
| Value | Behaviour |
|
||||
|-------|-----------|
|
||||
| `Global` | Arena appears in the global game browser (all games) and in single-game menus. |
|
||||
| `Single` | Arena appears only when browsing that specific minigame. |
|
||||
| `Local` | Arena is intended for a nearby NPC opened with `OpenMinigameQueueUI` + explicit `MinigameId` + `MapId`. |
|
||||
|
||||
Minimum queue UI candidate (add to an existing `MainArena` volume):
|
||||
|
||||
```text
|
||||
MinigameId=KOTH
|
||||
MapId=Castle
|
||||
MapRole=MainArena
|
||||
UIQueue=True
|
||||
UIQueueType=Global
|
||||
```
|
||||
|
||||
The minigame's `UIQueueable=true` definition flag must also be set for the game to appear in the global browser.
|
||||
|
||||
## Validation Notes
|
||||
|
||||
- A volume with `MapId` but no `MinigameId` produces a warning and is ignored for map discovery.
|
||||
|
||||
Reference in New Issue
Block a user