redscript-mc 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +31 -0
- package/.github/ISSUE_TEMPLATE/wrong_output.md +33 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +34 -0
- package/.github/workflows/ci.yml +29 -0
- package/.github/workflows/publish-extension.yml +35 -0
- package/LICENSE +21 -0
- package/README.md +261 -0
- package/README.zh.md +261 -0
- package/dist/__tests__/cli.test.d.ts +1 -0
- package/dist/__tests__/cli.test.js +140 -0
- package/dist/__tests__/codegen.test.d.ts +1 -0
- package/dist/__tests__/codegen.test.js +121 -0
- package/dist/__tests__/diagnostics.test.d.ts +4 -0
- package/dist/__tests__/diagnostics.test.js +149 -0
- package/dist/__tests__/e2e.test.d.ts +6 -0
- package/dist/__tests__/e2e.test.js +1528 -0
- package/dist/__tests__/lexer.test.d.ts +1 -0
- package/dist/__tests__/lexer.test.js +316 -0
- package/dist/__tests__/lowering.test.d.ts +1 -0
- package/dist/__tests__/lowering.test.js +819 -0
- package/dist/__tests__/mc-integration.test.d.ts +12 -0
- package/dist/__tests__/mc-integration.test.js +395 -0
- package/dist/__tests__/mc-syntax.test.d.ts +1 -0
- package/dist/__tests__/mc-syntax.test.js +112 -0
- package/dist/__tests__/nbt.test.d.ts +1 -0
- package/dist/__tests__/nbt.test.js +82 -0
- package/dist/__tests__/optimizer-advanced.test.d.ts +1 -0
- package/dist/__tests__/optimizer-advanced.test.js +124 -0
- package/dist/__tests__/optimizer.test.d.ts +1 -0
- package/dist/__tests__/optimizer.test.js +118 -0
- package/dist/__tests__/parser.test.d.ts +1 -0
- package/dist/__tests__/parser.test.js +717 -0
- package/dist/__tests__/repl.test.d.ts +1 -0
- package/dist/__tests__/repl.test.js +27 -0
- package/dist/__tests__/runtime.test.d.ts +1 -0
- package/dist/__tests__/runtime.test.js +276 -0
- package/dist/__tests__/structure-optimizer.test.d.ts +1 -0
- package/dist/__tests__/structure-optimizer.test.js +33 -0
- package/dist/__tests__/typechecker.test.d.ts +1 -0
- package/dist/__tests__/typechecker.test.js +364 -0
- package/dist/ast/types.d.ts +357 -0
- package/dist/ast/types.js +9 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.js +407 -0
- package/dist/codegen/cmdblock/index.d.ts +26 -0
- package/dist/codegen/cmdblock/index.js +45 -0
- package/dist/codegen/mcfunction/index.d.ts +34 -0
- package/dist/codegen/mcfunction/index.js +413 -0
- package/dist/codegen/structure/index.d.ts +18 -0
- package/dist/codegen/structure/index.js +249 -0
- package/dist/compile.d.ts +30 -0
- package/dist/compile.js +152 -0
- package/dist/data/arena/function/__load.mcfunction +6 -0
- package/dist/data/arena/function/__tick.mcfunction +2 -0
- package/dist/data/arena/function/announce_leaders/else_1.mcfunction +3 -0
- package/dist/data/arena/function/announce_leaders/foreach_0/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/announce_leaders/foreach_0/then_0.mcfunction +3 -0
- package/dist/data/arena/function/announce_leaders/foreach_0.mcfunction +7 -0
- package/dist/data/arena/function/announce_leaders/foreach_1/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/announce_leaders/foreach_1/then_0.mcfunction +4 -0
- package/dist/data/arena/function/announce_leaders/foreach_1.mcfunction +6 -0
- package/dist/data/arena/function/announce_leaders/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/announce_leaders/then_0.mcfunction +4 -0
- package/dist/data/arena/function/announce_leaders.mcfunction +6 -0
- package/dist/data/arena/function/arena_tick/merge_2.mcfunction +1 -0
- package/dist/data/arena/function/arena_tick/then_0.mcfunction +4 -0
- package/dist/data/arena/function/arena_tick.mcfunction +11 -0
- package/dist/data/counter/function/__load.mcfunction +5 -0
- package/dist/data/counter/function/__tick.mcfunction +2 -0
- package/dist/data/counter/function/counter_tick/merge_2.mcfunction +1 -0
- package/dist/data/counter/function/counter_tick/then_0.mcfunction +3 -0
- package/dist/data/counter/function/counter_tick.mcfunction +11 -0
- package/dist/data/minecraft/tags/function/load.json +5 -0
- package/dist/data/minecraft/tags/function/tick.json +5 -0
- package/dist/data/quiz/function/__load.mcfunction +16 -0
- package/dist/data/quiz/function/__tick.mcfunction +6 -0
- package/dist/data/quiz/function/__trigger_quiz_a_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/__trigger_quiz_b_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/__trigger_quiz_c_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/__trigger_quiz_start_dispatch.mcfunction +4 -0
- package/dist/data/quiz/function/answer_a.mcfunction +4 -0
- package/dist/data/quiz/function/answer_b.mcfunction +4 -0
- package/dist/data/quiz/function/answer_c.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/else_1.mcfunction +5 -0
- package/dist/data/quiz/function/ask_question/else_4.mcfunction +5 -0
- package/dist/data/quiz/function/ask_question/else_7.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/merge_2.mcfunction +1 -0
- package/dist/data/quiz/function/ask_question/merge_5.mcfunction +2 -0
- package/dist/data/quiz/function/ask_question/merge_8.mcfunction +2 -0
- package/dist/data/quiz/function/ask_question/then_0.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/then_3.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question/then_6.mcfunction +4 -0
- package/dist/data/quiz/function/ask_question.mcfunction +7 -0
- package/dist/data/quiz/function/finish_quiz.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer/else_1.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/else_10.mcfunction +3 -0
- package/dist/data/quiz/function/handle_answer/else_16.mcfunction +3 -0
- package/dist/data/quiz/function/handle_answer/else_4.mcfunction +3 -0
- package/dist/data/quiz/function/handle_answer/else_7.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/merge_11.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_14.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_17.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_2.mcfunction +8 -0
- package/dist/data/quiz/function/handle_answer/merge_5.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/merge_8.mcfunction +2 -0
- package/dist/data/quiz/function/handle_answer/then_0.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/then_12.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/then_15.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer/then_3.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer/then_6.mcfunction +5 -0
- package/dist/data/quiz/function/handle_answer/then_9.mcfunction +6 -0
- package/dist/data/quiz/function/handle_answer.mcfunction +11 -0
- package/dist/data/quiz/function/start_quiz.mcfunction +5 -0
- package/dist/data/shop/function/__load.mcfunction +7 -0
- package/dist/data/shop/function/__tick.mcfunction +3 -0
- package/dist/data/shop/function/__trigger_shop_buy_dispatch.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase/else_1.mcfunction +5 -0
- package/dist/data/shop/function/complete_purchase/else_4.mcfunction +5 -0
- package/dist/data/shop/function/complete_purchase/else_7.mcfunction +3 -0
- package/dist/data/shop/function/complete_purchase/merge_2.mcfunction +2 -0
- package/dist/data/shop/function/complete_purchase/merge_5.mcfunction +2 -0
- package/dist/data/shop/function/complete_purchase/merge_8.mcfunction +2 -0
- package/dist/data/shop/function/complete_purchase/then_0.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase/then_3.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase/then_6.mcfunction +4 -0
- package/dist/data/shop/function/complete_purchase.mcfunction +7 -0
- package/dist/data/shop/function/handle_shop_trigger.mcfunction +3 -0
- package/dist/data/turret/function/__load.mcfunction +5 -0
- package/dist/data/turret/function/__tick.mcfunction +4 -0
- package/dist/data/turret/function/__trigger_deploy_turret_dispatch.mcfunction +4 -0
- package/dist/data/turret/function/deploy_turret.mcfunction +8 -0
- package/dist/data/turret/function/turret_tick/at_1.mcfunction +2 -0
- package/dist/data/turret/function/turret_tick/foreach_0.mcfunction +2 -0
- package/dist/data/turret/function/turret_tick/foreach_2.mcfunction +2 -0
- package/dist/data/turret/function/turret_tick/tick_body.mcfunction +3 -0
- package/dist/data/turret/function/turret_tick/tick_skip.mcfunction +1 -0
- package/dist/data/turret/function/turret_tick.mcfunction +5 -0
- package/dist/diagnostics/index.d.ts +44 -0
- package/dist/diagnostics/index.js +140 -0
- package/dist/index.d.ts +53 -0
- package/dist/index.js +126 -0
- package/dist/ir/builder.d.ts +32 -0
- package/dist/ir/builder.js +99 -0
- package/dist/ir/types.d.ts +117 -0
- package/dist/ir/types.js +15 -0
- package/dist/lexer/index.d.ts +36 -0
- package/dist/lexer/index.js +458 -0
- package/dist/lowering/index.d.ts +106 -0
- package/dist/lowering/index.js +2041 -0
- package/dist/mc-test/client.d.ts +128 -0
- package/dist/mc-test/client.js +174 -0
- package/dist/mc-test/runner.d.ts +28 -0
- package/dist/mc-test/runner.js +150 -0
- package/dist/mc-test/setup.d.ts +11 -0
- package/dist/mc-test/setup.js +98 -0
- package/dist/mc-validator/index.d.ts +17 -0
- package/dist/mc-validator/index.js +322 -0
- package/dist/nbt/index.d.ts +86 -0
- package/dist/nbt/index.js +250 -0
- package/dist/optimizer/commands.d.ts +36 -0
- package/dist/optimizer/commands.js +349 -0
- package/dist/optimizer/passes.d.ts +34 -0
- package/dist/optimizer/passes.js +227 -0
- package/dist/optimizer/structure.d.ts +8 -0
- package/dist/optimizer/structure.js +344 -0
- package/dist/pack.mcmeta +6 -0
- package/dist/parser/index.d.ts +76 -0
- package/dist/parser/index.js +1193 -0
- package/dist/repl.d.ts +16 -0
- package/dist/repl.js +165 -0
- package/dist/runtime/index.d.ts +101 -0
- package/dist/runtime/index.js +1288 -0
- package/dist/typechecker/index.d.ts +42 -0
- package/dist/typechecker/index.js +629 -0
- package/docs/COMPILATION_STATS.md +142 -0
- package/docs/IMPLEMENTATION_GUIDE.md +512 -0
- package/docs/LANGUAGE_REFERENCE.md +415 -0
- package/docs/MC_MAPPING.md +280 -0
- package/docs/STRUCTURE_TARGET.md +80 -0
- package/docs/mc-reference/commands.md +259 -0
- package/editors/vscode/.vscodeignore +10 -0
- package/editors/vscode/LICENSE +21 -0
- package/editors/vscode/README.md +78 -0
- package/editors/vscode/build.mjs +28 -0
- package/editors/vscode/icon.png +0 -0
- package/editors/vscode/mcfunction-language-configuration.json +28 -0
- package/editors/vscode/out/extension.js +7236 -0
- package/editors/vscode/package-lock.json +566 -0
- package/editors/vscode/package.json +137 -0
- package/editors/vscode/redscript-language-configuration.json +28 -0
- package/editors/vscode/snippets/redscript.json +114 -0
- package/editors/vscode/src/codeactions.ts +89 -0
- package/editors/vscode/src/completion.ts +130 -0
- package/editors/vscode/src/extension.ts +239 -0
- package/editors/vscode/src/hover.ts +1120 -0
- package/editors/vscode/src/symbols.ts +207 -0
- package/editors/vscode/syntaxes/mcfunction.tmLanguage.json +740 -0
- package/editors/vscode/syntaxes/redscript.tmLanguage.json +357 -0
- package/editors/vscode/tsconfig.json +13 -0
- package/jest.config.js +5 -0
- package/package.json +38 -0
- package/src/__tests__/cli.test.ts +130 -0
- package/src/__tests__/codegen.test.ts +128 -0
- package/src/__tests__/diagnostics.test.ts +195 -0
- package/src/__tests__/e2e.test.ts +1721 -0
- package/src/__tests__/fixtures/mc-commands-1.21.4.json +18734 -0
- package/src/__tests__/formatter.test.ts +46 -0
- package/src/__tests__/lexer.test.ts +356 -0
- package/src/__tests__/lowering.test.ts +962 -0
- package/src/__tests__/mc-integration.test.ts +409 -0
- package/src/__tests__/mc-syntax.test.ts +96 -0
- package/src/__tests__/nbt.test.ts +58 -0
- package/src/__tests__/optimizer-advanced.test.ts +144 -0
- package/src/__tests__/optimizer.test.ts +129 -0
- package/src/__tests__/parser.test.ts +800 -0
- package/src/__tests__/repl.test.ts +33 -0
- package/src/__tests__/runtime.test.ts +289 -0
- package/src/__tests__/structure-optimizer.test.ts +38 -0
- package/src/__tests__/typechecker.test.ts +395 -0
- package/src/ast/types.ts +248 -0
- package/src/cli.ts +445 -0
- package/src/codegen/cmdblock/index.ts +63 -0
- package/src/codegen/mcfunction/index.ts +471 -0
- package/src/codegen/structure/index.ts +305 -0
- package/src/compile.ts +188 -0
- package/src/diagnostics/index.ts +186 -0
- package/src/examples/README.md +77 -0
- package/src/examples/SHOWCASE_GAME.md +43 -0
- package/src/examples/arena.rs +44 -0
- package/src/examples/counter.rs +12 -0
- package/src/examples/pvp_arena.rs +131 -0
- package/src/examples/quiz.rs +90 -0
- package/src/examples/rpg.rs +13 -0
- package/src/examples/shop.rs +30 -0
- package/src/examples/showcase_game.rs +552 -0
- package/src/examples/stdlib_demo.rs +181 -0
- package/src/examples/turret.rs +27 -0
- package/src/examples/world_manager.rs +23 -0
- package/src/formatter/index.ts +22 -0
- package/src/index.ts +161 -0
- package/src/ir/builder.ts +114 -0
- package/src/ir/types.ts +119 -0
- package/src/lexer/index.ts +555 -0
- package/src/lowering/index.ts +2406 -0
- package/src/mc-test/client.ts +259 -0
- package/src/mc-test/runner.ts +140 -0
- package/src/mc-test/setup.ts +70 -0
- package/src/mc-validator/index.ts +367 -0
- package/src/nbt/index.ts +321 -0
- package/src/optimizer/commands.ts +416 -0
- package/src/optimizer/passes.ts +233 -0
- package/src/optimizer/structure.ts +441 -0
- package/src/parser/index.ts +1437 -0
- package/src/repl.ts +165 -0
- package/src/runtime/index.ts +1403 -0
- package/src/stdlib/README.md +156 -0
- package/src/stdlib/combat.rs +20 -0
- package/src/stdlib/cooldown.rs +45 -0
- package/src/stdlib/math.rs +49 -0
- package/src/stdlib/mobs.rs +99 -0
- package/src/stdlib/player.rs +29 -0
- package/src/stdlib/strings.rs +7 -0
- package/src/stdlib/timer.rs +51 -0
- package/src/templates/README.md +126 -0
- package/src/templates/combat.rs +96 -0
- package/src/templates/economy.rs +40 -0
- package/src/templates/mini-game-framework.rs +117 -0
- package/src/templates/quest.rs +78 -0
- package/src/test_programs/zombie_game.rs +25 -0
- package/src/typechecker/index.ts +737 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Examples
|
|
2
|
+
|
|
3
|
+
This folder contains small RedScript example programs that demonstrate common datapack patterns and the current language feature set.
|
|
4
|
+
|
|
5
|
+
## `counter.rs`
|
|
6
|
+
|
|
7
|
+
A minimal tick counter.
|
|
8
|
+
|
|
9
|
+
Demonstrates:
|
|
10
|
+
- `@tick`
|
|
11
|
+
- `scoreboard_get()` and `scoreboard_set()`
|
|
12
|
+
- integer math and `%`
|
|
13
|
+
- `if`
|
|
14
|
+
- `say()`
|
|
15
|
+
|
|
16
|
+
## `shop.rs`
|
|
17
|
+
|
|
18
|
+
A simple shop entry point that runs from `@on_trigger("shop_buy")` and reads a companion `shop_choice` scoreboard to decide what to give the player.
|
|
19
|
+
|
|
20
|
+
Demonstrates:
|
|
21
|
+
- `@on_trigger`
|
|
22
|
+
- helper functions
|
|
23
|
+
- nested `if` / `else`
|
|
24
|
+
- `give()`
|
|
25
|
+
- `tell()`
|
|
26
|
+
- scoreboard-driven branching
|
|
27
|
+
|
|
28
|
+
Note: the current trigger system fires when a trigger objective is set, but it does not pass the numeric trigger amount into the handler. This example uses `shop_choice` for the item selection value.
|
|
29
|
+
|
|
30
|
+
## `arena.rs`
|
|
31
|
+
|
|
32
|
+
A PvP arena tracker that checks the `kills` objective every 200 ticks, finds the highest score, and notifies the leader or tied leaders.
|
|
33
|
+
|
|
34
|
+
Demonstrates:
|
|
35
|
+
- periodic logic with `@tick`
|
|
36
|
+
- `foreach (player in @a)`
|
|
37
|
+
- per-player scoreboard reads
|
|
38
|
+
- aggregation with local variables
|
|
39
|
+
- `announce()`, `actionbar()`, `subtitle()`, and `title_times()`
|
|
40
|
+
- `tell()` and `title()`
|
|
41
|
+
|
|
42
|
+
## `world_manager.rs`
|
|
43
|
+
|
|
44
|
+
A small world administration example that resets a lobby platform and locks in predictable world settings from a trigger handler.
|
|
45
|
+
|
|
46
|
+
Demonstrates:
|
|
47
|
+
- `BlockPos` tuple literals with `setblock()` and `fill()`
|
|
48
|
+
- `weather()` and `time_set()`
|
|
49
|
+
- `gamerule()`
|
|
50
|
+
- `announce()` and `actionbar()`
|
|
51
|
+
- `@on_trigger`
|
|
52
|
+
|
|
53
|
+
## `turret.rs`
|
|
54
|
+
|
|
55
|
+
An automated turret deployment example. A trigger spawns an invisible armor stand, tags it as a turret, stores a health value, and a tick loop kills nearby zombies around every deployed turret.
|
|
56
|
+
|
|
57
|
+
Demonstrates:
|
|
58
|
+
- `spawn_object()`
|
|
59
|
+
- world object field assignment
|
|
60
|
+
- entity tagging
|
|
61
|
+
- `struct` literals and field reads
|
|
62
|
+
- `@tick(rate=20)`
|
|
63
|
+
- nested `foreach`
|
|
64
|
+
- `at` blocks
|
|
65
|
+
|
|
66
|
+
## `quiz.rs`
|
|
67
|
+
|
|
68
|
+
A trigger-based quiz game. Players start with `quiz_start`, answer with `quiz_a`, `quiz_b`, or `quiz_c`, and keep score in scoreboards while receiving `tellraw`-style messages through `tell()`.
|
|
69
|
+
|
|
70
|
+
Demonstrates:
|
|
71
|
+
- multiple `@on_trigger` handlers
|
|
72
|
+
- regular functions with parameters
|
|
73
|
+
- scoreboard-backed state machines
|
|
74
|
+
- branching by current question and answer choice
|
|
75
|
+
- `title()` and `tell()`
|
|
76
|
+
|
|
77
|
+
Note: `tell()` lowers to Minecraft `tellraw`, so these messages are rendered as JSON text components in the datapack output.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Crystal Rush
|
|
2
|
+
|
|
3
|
+
`showcase_game.rs` is a complete RedScript mini-game showcase built around a simple loop:
|
|
4
|
+
|
|
5
|
+
1. Players join with `/trigger crystal_join`
|
|
6
|
+
2. Anyone in the lobby can start a countdown with `/trigger crystal_start`
|
|
7
|
+
3. During the round, players use `/trigger crystal_claim` near one of four crystal lanes
|
|
8
|
+
4. `/trigger crystal_dash` spends the shared stdlib cooldown to lunge forward
|
|
9
|
+
5. Zombies spawn in waves and touching them applies scoreboard-based damage
|
|
10
|
+
6. First player to `15` score wins, then the arena resets
|
|
11
|
+
|
|
12
|
+
## Mechanics
|
|
13
|
+
|
|
14
|
+
- Four crystal pads exist at north, south, east, and west.
|
|
15
|
+
- A player claims the crystal in the lane they are currently closest to.
|
|
16
|
+
- Claiming a crystal removes the block, awards score, and starts its recharge cycle.
|
|
17
|
+
- Every second the game respawns missing crystals and periodically spawns zombie pressure.
|
|
18
|
+
- If a player's tracked health reaches `0`, they are teleported back to spawn and lose `1` score.
|
|
19
|
+
|
|
20
|
+
## Feature Coverage
|
|
21
|
+
|
|
22
|
+
- `const` declarations: scoring, timers, cooldown, and damage are all constant-driven.
|
|
23
|
+
- `enum` types: `Phase` and `Lane` drive game flow and crystal logic.
|
|
24
|
+
- Arrays: lane lists and respawn loops use `int[]`.
|
|
25
|
+
- Structs: `GameState` and `PlayerState` snapshot scoreboard-backed state.
|
|
26
|
+
- String interpolation: titles, actionbars, and announcements use `${...}`.
|
|
27
|
+
- `match`: used for phase dispatch, lane lookup, lane labels, and lane crystal state.
|
|
28
|
+
- Default parameters: `crystal_reward(base, streak = 0)`.
|
|
29
|
+
- `foreach` over selectors: player counting and per-player round updates.
|
|
30
|
+
- BlockPos with `~` and `^`: arena pad marking uses `(~0, 64, ~0)`, dash uses `(^0, ^0, ^3)`.
|
|
31
|
+
- `@tick(rate=20)`: once-per-second game logic runs in `crystal_rush_second`.
|
|
32
|
+
- Trigger decorator: this repo currently supports `@on_trigger("...")`, not `@on_advancement` / `@on_death`, so Crystal Rush uses trigger handlers for join/start/claim/dash.
|
|
33
|
+
- Stdlib imports: `math.rs`, `player.rs`, and `cooldown.rs` are imported and exercised.
|
|
34
|
+
- `execute/as/at` blocks: used for zombie contact damage and spawn-pad marking.
|
|
35
|
+
- Scoreboard operations: all game state is stored in objectives like `score`, `crystals`, `health`, and `crystal`.
|
|
36
|
+
- `fill` / `setblock`: arena build and crystal respawn both use block-editing builtins.
|
|
37
|
+
- `title` / `subtitle` / `actionbar`: all phases and major player events surface feedback through UI.
|
|
38
|
+
- Multiple functions calling each other: the game loop is split into snapshots, dispatch, arena setup, scoring, respawn, and reset helpers.
|
|
39
|
+
|
|
40
|
+
## Notes
|
|
41
|
+
|
|
42
|
+
- The imported stdlib cooldown helper is currently a single global slot on objective `rs`, so dash acts as a shared cooldown showcase rather than a per-player system.
|
|
43
|
+
- The compiler surface today does not implement `@on_advancement` or `@on_death`; this example intentionally stays within the supported decorator set in the current codebase.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// PvP arena scoreboard tracker.
|
|
2
|
+
// Reads the vanilla kills objective, announces the top score every 200 ticks,
|
|
3
|
+
// and tells the current leader(s) directly.
|
|
4
|
+
|
|
5
|
+
@tick
|
|
6
|
+
fn arena_tick() {
|
|
7
|
+
let ticks: int = scoreboard_get("arena", #ticks);
|
|
8
|
+
ticks = ticks + 1;
|
|
9
|
+
scoreboard_set("arena", #ticks, ticks);
|
|
10
|
+
|
|
11
|
+
if (ticks % 200 == 0) {
|
|
12
|
+
announce_leaders();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
fn announce_leaders() {
|
|
17
|
+
let top_kills: int = 0;
|
|
18
|
+
|
|
19
|
+
foreach (player in @a) {
|
|
20
|
+
let kills: int = scoreboard_get(player, #kills);
|
|
21
|
+
if (kills > top_kills) {
|
|
22
|
+
top_kills = kills;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (top_kills > 0) {
|
|
27
|
+
announce("Arena update: leader check complete.");
|
|
28
|
+
title_times(@a, 10, 40, 10);
|
|
29
|
+
actionbar(@a, "Top kills updated");
|
|
30
|
+
|
|
31
|
+
foreach (player in @a) {
|
|
32
|
+
let kills: int = scoreboard_get(player, #kills);
|
|
33
|
+
if (kills == top_kills) {
|
|
34
|
+
tell(player, "You are leading the arena right now.");
|
|
35
|
+
title(player, "Arena Leader");
|
|
36
|
+
subtitle(player, "Hold the top score");
|
|
37
|
+
actionbar(player, "Stay alive to keep the lead");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
announce("Arena update: no PvP kills yet.");
|
|
42
|
+
actionbar(@a, "No arena leader yet");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Tick counter that announces every 100 ticks.
|
|
2
|
+
|
|
3
|
+
@tick
|
|
4
|
+
fn counter_tick() {
|
|
5
|
+
let ticks: int = scoreboard_get("counter", #ticks);
|
|
6
|
+
ticks = ticks + 1;
|
|
7
|
+
scoreboard_set("counter", #ticks, ticks);
|
|
8
|
+
|
|
9
|
+
if (ticks % 100 == 0) {
|
|
10
|
+
say("Counter reached another 100 ticks");
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
struct FighterState {
|
|
2
|
+
health: int,
|
|
3
|
+
eliminations: int,
|
|
4
|
+
alive: int
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
fn snapshot_fighter() -> FighterState {
|
|
8
|
+
let health: int = scoreboard_get(@s, #arena_health);
|
|
9
|
+
let eliminations: int = scoreboard_get(@s, #arena_elims);
|
|
10
|
+
let alive: int = scoreboard_get(@s, #arena_alive);
|
|
11
|
+
let state: FighterState = { health: health, eliminations: eliminations, alive: alive };
|
|
12
|
+
return state;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
fn save_fighter(state: FighterState) {
|
|
16
|
+
scoreboard_set(@s, #arena_health, state.health);
|
|
17
|
+
scoreboard_set(@s, #arena_elims, state.eliminations);
|
|
18
|
+
scoreboard_set(@s, #arena_alive, state.alive);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
fn count_team(tagName: string) -> int {
|
|
22
|
+
let total: int = 0;
|
|
23
|
+
|
|
24
|
+
if (tagName == "red") {
|
|
25
|
+
foreach (player in @a[tag=arena_red, tag=arena_alive]) {
|
|
26
|
+
total += 1;
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
foreach (player in @a[tag=arena_blue, tag=arena_alive]) {
|
|
30
|
+
total += 1;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return total;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fn check_winner() {
|
|
38
|
+
let red_alive: int = count_team("red");
|
|
39
|
+
let blue_alive: int = count_team("blue");
|
|
40
|
+
|
|
41
|
+
if (red_alive == 0) {
|
|
42
|
+
title(@a, "Blue Team Wins");
|
|
43
|
+
subtitle(@a, "Red squad has been eliminated");
|
|
44
|
+
} else {
|
|
45
|
+
if (blue_alive == 0) {
|
|
46
|
+
title(@a, "Red Team Wins");
|
|
47
|
+
subtitle(@a, "Blue squad has been eliminated");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
fn knock_out_current_player() {
|
|
53
|
+
let state: FighterState = snapshot_fighter();
|
|
54
|
+
state.health = 0;
|
|
55
|
+
state.alive = 0;
|
|
56
|
+
save_fighter(state);
|
|
57
|
+
@s.tag("arena_out");
|
|
58
|
+
@s.untag("arena_alive");
|
|
59
|
+
title(@s, "Eliminated");
|
|
60
|
+
actionbar(@s, "Wait for the next arena reset");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
fn award_elimination() {
|
|
64
|
+
let killer: FighterState = snapshot_fighter();
|
|
65
|
+
killer.eliminations = killer.eliminations + 1;
|
|
66
|
+
save_fighter(killer);
|
|
67
|
+
title(@s, "Elimination");
|
|
68
|
+
actionbar(@s, "Your elimination total is now ${killer.eliminations}");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
fn check_milestones() {
|
|
72
|
+
let milestones: int[] = [1, 3, 5];
|
|
73
|
+
let kills: int = scoreboard_get(@s, #arena_elims);
|
|
74
|
+
|
|
75
|
+
foreach (milestone in milestones) {
|
|
76
|
+
if (kills == milestone) {
|
|
77
|
+
actionbar(@s, "Milestone reached: ${milestone} eliminations");
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@tick
|
|
83
|
+
fn arena_status_tick() {
|
|
84
|
+
let red_alive: int = count_team("red");
|
|
85
|
+
let blue_alive: int = count_team("blue");
|
|
86
|
+
actionbar(@a, "Arena status: Red ${red_alive} alive | Blue ${blue_alive} alive");
|
|
87
|
+
check_winner();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@on_trigger("arena_assign_red")
|
|
91
|
+
fn arena_assign_red() {
|
|
92
|
+
@s.tag("arena_red");
|
|
93
|
+
@s.tag("arena_alive");
|
|
94
|
+
@s.untag("arena_blue");
|
|
95
|
+
@s.untag("arena_out");
|
|
96
|
+
scoreboard_set(@s, #arena_health, 20);
|
|
97
|
+
scoreboard_set(@s, #arena_elims, 0);
|
|
98
|
+
scoreboard_set(@s, #arena_alive, 1);
|
|
99
|
+
title(@s, "Red Team");
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@on_trigger("arena_assign_blue")
|
|
103
|
+
fn arena_assign_blue() {
|
|
104
|
+
@s.tag("arena_blue");
|
|
105
|
+
@s.tag("arena_alive");
|
|
106
|
+
@s.untag("arena_red");
|
|
107
|
+
@s.untag("arena_out");
|
|
108
|
+
scoreboard_set(@s, #arena_health, 20);
|
|
109
|
+
scoreboard_set(@s, #arena_elims, 0);
|
|
110
|
+
scoreboard_set(@s, #arena_alive, 1);
|
|
111
|
+
title(@s, "Blue Team");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
@on_trigger("arena_hit")
|
|
115
|
+
fn arena_hit() {
|
|
116
|
+
let state: FighterState = snapshot_fighter();
|
|
117
|
+
state.health = state.health - 5;
|
|
118
|
+
save_fighter(state);
|
|
119
|
+
|
|
120
|
+
if (state.health <= 0) {
|
|
121
|
+
knock_out_current_player();
|
|
122
|
+
} else {
|
|
123
|
+
subtitle(@s, "Health now ${state.health}");
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
@on_trigger("arena_elim")
|
|
128
|
+
fn arena_elim() {
|
|
129
|
+
award_elimination();
|
|
130
|
+
check_milestones();
|
|
131
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Quiz game with trigger-based answers.
|
|
2
|
+
// Use /trigger quiz_start to begin, then /trigger quiz_a, /trigger quiz_b, or /trigger quiz_c.
|
|
3
|
+
|
|
4
|
+
@on_trigger("quiz_start")
|
|
5
|
+
fn start_quiz() {
|
|
6
|
+
scoreboard_set(@s, #quiz_score, 0);
|
|
7
|
+
scoreboard_set(@s, #quiz_question, 1);
|
|
8
|
+
ask_question();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
fn ask_question() {
|
|
12
|
+
let question: int = scoreboard_get(@s, #quiz_question);
|
|
13
|
+
|
|
14
|
+
if (question == 1) {
|
|
15
|
+
tell(@s, "Question 1: Which block drops diamonds?");
|
|
16
|
+
tell(@s, "A) Diamond ore B) Stone C) Oak log");
|
|
17
|
+
} else {
|
|
18
|
+
if (question == 2) {
|
|
19
|
+
tell(@s, "Question 2: Which food restores more hunger?");
|
|
20
|
+
tell(@s, "A) Bread B) Steak C) Beetroot");
|
|
21
|
+
} else {
|
|
22
|
+
if (question == 3) {
|
|
23
|
+
tell(@s, "Question 3: Which mob explodes?");
|
|
24
|
+
tell(@s, "A) Cow B) Creeper C) Villager");
|
|
25
|
+
} else {
|
|
26
|
+
finish_quiz();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
fn handle_answer(choice: int) {
|
|
33
|
+
let question: int = scoreboard_get(@s, #quiz_question);
|
|
34
|
+
let score: int = scoreboard_get(@s, #quiz_score);
|
|
35
|
+
|
|
36
|
+
if (question == 1) {
|
|
37
|
+
if (choice == 1) {
|
|
38
|
+
score = score + 1;
|
|
39
|
+
tell(@s, "Correct.");
|
|
40
|
+
} else {
|
|
41
|
+
tell(@s, "Wrong. The answer was A.");
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
if (question == 2) {
|
|
45
|
+
if (choice == 2) {
|
|
46
|
+
score = score + 1;
|
|
47
|
+
tell(@s, "Correct.");
|
|
48
|
+
} else {
|
|
49
|
+
tell(@s, "Wrong. The answer was B.");
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
if (question == 3) {
|
|
53
|
+
if (choice == 2) {
|
|
54
|
+
score = score + 1;
|
|
55
|
+
tell(@s, "Correct.");
|
|
56
|
+
} else {
|
|
57
|
+
tell(@s, "Wrong. The answer was B.");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
scoreboard_set(@s, #quiz_score, score);
|
|
64
|
+
question = question + 1;
|
|
65
|
+
scoreboard_set(@s, #quiz_question, question);
|
|
66
|
+
ask_question();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
fn finish_quiz() {
|
|
70
|
+
let score: int = scoreboard_get(@s, #quiz_score);
|
|
71
|
+
title(@s, "Quiz Complete");
|
|
72
|
+
tell(@s, "Your final quiz score is recorded in quiz_score.");
|
|
73
|
+
scoreboard_set(@s, #quiz_question, 0);
|
|
74
|
+
scoreboard_set(@s, #quiz_score, score);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
@on_trigger("quiz_a")
|
|
78
|
+
fn answer_a() {
|
|
79
|
+
handle_answer(1);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@on_trigger("quiz_b")
|
|
83
|
+
fn answer_b() {
|
|
84
|
+
handle_answer(2);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@on_trigger("quiz_c")
|
|
88
|
+
fn answer_c() {
|
|
89
|
+
handle_answer(3);
|
|
90
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import "../stdlib/math.rs"
|
|
2
|
+
import "../stdlib/combat.rs"
|
|
3
|
+
|
|
4
|
+
fn attack(enemy: string, base: int, bonus: int) {
|
|
5
|
+
let raw_damage: int = weapon_damage(base, bonus);
|
|
6
|
+
let damage: int = clamp(raw_damage, 1, 20);
|
|
7
|
+
apply_damage(enemy, damage);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
@tick
|
|
11
|
+
fn battle_tick() {
|
|
12
|
+
attack("goblin", 4, 2);
|
|
13
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Trigger-driven shop.
|
|
2
|
+
// Players set shop_choice, then run /trigger shop_buy.
|
|
3
|
+
|
|
4
|
+
fn complete_purchase() {
|
|
5
|
+
let choice: int = scoreboard_get(@s, #shop_choice);
|
|
6
|
+
|
|
7
|
+
if (choice == 1) {
|
|
8
|
+
give(@s, "minecraft:bread", 1);
|
|
9
|
+
tell(@s, "You bought bread.");
|
|
10
|
+
} else {
|
|
11
|
+
if (choice == 2) {
|
|
12
|
+
give(@s, "minecraft:steak", 1);
|
|
13
|
+
tell(@s, "You bought steak.");
|
|
14
|
+
} else {
|
|
15
|
+
if (choice == 3) {
|
|
16
|
+
give(@s, "minecraft:diamond", 1);
|
|
17
|
+
tell(@s, "You bought a diamond.");
|
|
18
|
+
} else {
|
|
19
|
+
tell(@s, "Invalid shop_choice. Use 1, 2, or 3.");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
scoreboard_set(@s, #shop_choice, 0);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
@on_trigger("shop_buy")
|
|
28
|
+
fn handle_shop_trigger() {
|
|
29
|
+
complete_purchase();
|
|
30
|
+
}
|