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,156 @@
|
|
|
1
|
+
# RedScript Stdlib
|
|
2
|
+
|
|
3
|
+
This folder contains source-only utility modules for RedScript projects. There is
|
|
4
|
+
no import system yet, so stdlib usage is intentionally simple:
|
|
5
|
+
|
|
6
|
+
1. Copy the functions you need into your project file.
|
|
7
|
+
2. Compile a stdlib file on its own to inspect the generated `.mcfunction` output.
|
|
8
|
+
3. Recreate the same pattern with `raw("function namespace:name")` if you prefer
|
|
9
|
+
to wire precompiled datapack functions manually.
|
|
10
|
+
|
|
11
|
+
## Modules
|
|
12
|
+
|
|
13
|
+
### `math.rs`
|
|
14
|
+
|
|
15
|
+
Integer helpers:
|
|
16
|
+
|
|
17
|
+
- `abs(x: int) -> int`
|
|
18
|
+
- `min(a: int, b: int) -> int`
|
|
19
|
+
- `max(a: int, b: int) -> int`
|
|
20
|
+
- `clamp(x: int, lo: int, hi: int) -> int`
|
|
21
|
+
- `sign(x: int) -> int`
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
|
|
25
|
+
```rs
|
|
26
|
+
let offset: int = abs(delta);
|
|
27
|
+
let limited: int = clamp(offset, 0, 20);
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### `player.rs`
|
|
31
|
+
|
|
32
|
+
Nearest-player helpers:
|
|
33
|
+
|
|
34
|
+
- `heal(amount: int)` adds to the nearest player's `health` scoreboard value
|
|
35
|
+
- `damage(amount: int)` subtracts from the nearest player's `health` scoreboard
|
|
36
|
+
- `is_op() -> int` returns `1` when the nearest player has the `op` tag
|
|
37
|
+
|
|
38
|
+
Example:
|
|
39
|
+
|
|
40
|
+
```rs
|
|
41
|
+
if (is_op() == 1) {
|
|
42
|
+
heal(4);
|
|
43
|
+
} else {
|
|
44
|
+
damage(2);
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### `strings.rs`
|
|
49
|
+
|
|
50
|
+
String helpers:
|
|
51
|
+
|
|
52
|
+
- `str_len(s: string) -> int`
|
|
53
|
+
|
|
54
|
+
Important limitation:
|
|
55
|
+
|
|
56
|
+
RedScript still does not support general runtime string manipulation. Today the
|
|
57
|
+
compiler only lowers `str_len(...)` cleanly when the input is a string literal,
|
|
58
|
+
a `const` string, or a string variable initialized from a literal-backed value.
|
|
59
|
+
That path works by storing the string in `storage rs:strings` and reading its
|
|
60
|
+
character count with `data get storage`.
|
|
61
|
+
|
|
62
|
+
Example:
|
|
63
|
+
|
|
64
|
+
```rs
|
|
65
|
+
let name: string = "Player";
|
|
66
|
+
let n: int = str_len(name);
|
|
67
|
+
tell(@s, "${n}");
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### `mobs.rs`
|
|
71
|
+
|
|
72
|
+
Vanilla Java Edition entity type constants for selectors, summon helpers, and
|
|
73
|
+
command wrappers. The file groups hostile, passive, neutral, boss, and misc
|
|
74
|
+
entity IDs so you can copy stable names instead of repeating raw strings.
|
|
75
|
+
|
|
76
|
+
Example:
|
|
77
|
+
|
|
78
|
+
```rs
|
|
79
|
+
summon(ALLAY, "~", "~", "~");
|
|
80
|
+
summon(ZOMBIE, "~", "~", "~");
|
|
81
|
+
```
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### `timer.rs`
|
|
85
|
+
|
|
86
|
+
Countdown helpers plus a `Timer` struct shape:
|
|
87
|
+
|
|
88
|
+
- `struct Timer { ticks: int, active: int }`
|
|
89
|
+
- `timer_start(name: string, duration: int)`
|
|
90
|
+
- `timer_tick(name: string) -> int`
|
|
91
|
+
- `timer_done(name: string) -> int`
|
|
92
|
+
|
|
93
|
+
Important limitation:
|
|
94
|
+
|
|
95
|
+
Current RedScript lowering does not preserve string arguments when they are passed
|
|
96
|
+
into user-defined functions. Because of that, `timer.rs` is implemented as a
|
|
97
|
+
single-slot template backed by `timer_ticks` and `timer_active` fake players on
|
|
98
|
+
the `rs` objective. Keep one copy per named timer, or replace those fake-player
|
|
99
|
+
names with your own concrete identifiers.
|
|
100
|
+
|
|
101
|
+
Example:
|
|
102
|
+
|
|
103
|
+
```rs
|
|
104
|
+
timer_start("wave", 200);
|
|
105
|
+
let remaining: int = timer_tick("wave");
|
|
106
|
+
if (timer_done("wave") == 1) {
|
|
107
|
+
say("Next wave.");
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### `cooldown.rs`
|
|
112
|
+
|
|
113
|
+
Cooldown helpers:
|
|
114
|
+
|
|
115
|
+
- `cooldown_start(name: string, ticks: int)`
|
|
116
|
+
- `cooldown_ready(name: string) -> int`
|
|
117
|
+
- `cooldown_tick(name: string)`
|
|
118
|
+
|
|
119
|
+
This file has the same single-slot limitation as `timer.rs`. Copy it and rename
|
|
120
|
+
the scoreboard fake players if you need multiple independent cooldowns.
|
|
121
|
+
|
|
122
|
+
Example:
|
|
123
|
+
|
|
124
|
+
```rs
|
|
125
|
+
if (cooldown_ready("dash") == 1) {
|
|
126
|
+
cooldown_start("dash", 40);
|
|
127
|
+
}
|
|
128
|
+
cooldown_tick("dash");
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Incorporation Patterns
|
|
132
|
+
|
|
133
|
+
### Copy into your project
|
|
134
|
+
|
|
135
|
+
This is the simplest path today. Paste the helper functions above your gameplay
|
|
136
|
+
functions and compile one `.rs` file.
|
|
137
|
+
|
|
138
|
+
### Compile separately
|
|
139
|
+
|
|
140
|
+
You can inspect or ship a stdlib datapack directly:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npx ts-node src/cli.ts compile src/stdlib/math.rs -o dist/stdlib-math
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Call precompiled helpers with `raw()`
|
|
147
|
+
|
|
148
|
+
If you compile helper files into their own namespace, you can call them from raw
|
|
149
|
+
Minecraft commands:
|
|
150
|
+
|
|
151
|
+
```rs
|
|
152
|
+
raw("function stdlib_math:abs");
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
That pattern is most useful for command wrappers or tick/load entrypoints where
|
|
156
|
+
the datapack interface is already fixed.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Combat helpers for simple RPG-style datapacks.
|
|
2
|
+
|
|
3
|
+
fn weapon_damage(base: int, bonus: int) -> int {
|
|
4
|
+
return base + bonus;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
fn enemy_health(name: string) -> int {
|
|
8
|
+
return scoreboard_get(name, #health);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
fn apply_damage(name: string, amount: int) {
|
|
12
|
+
let health: int = enemy_health(name);
|
|
13
|
+
let next: int = health - amount;
|
|
14
|
+
|
|
15
|
+
if (next < 0) {
|
|
16
|
+
scoreboard_set(name, #health, 0);
|
|
17
|
+
} else {
|
|
18
|
+
scoreboard_set(name, #health, next);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// Cooldown helpers.
|
|
2
|
+
//
|
|
3
|
+
// Like timer.rs, the `name` parameter is reserved for a future compiler/runtime
|
|
4
|
+
// that can route string literals through user-defined calls. Today this file
|
|
5
|
+
// manages one cooldown slot on the `rs` objective.
|
|
6
|
+
|
|
7
|
+
fn cooldown_start(name: string, ticks: int) {
|
|
8
|
+
scoreboard_set("cooldown_ticks", #rs, ticks);
|
|
9
|
+
scoreboard_set("cooldown_active", #rs, 1);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
fn cooldown_ready(name: string) -> int {
|
|
13
|
+
let active: int = scoreboard_get("cooldown_active", #rs);
|
|
14
|
+
let ticks_left: int = scoreboard_get("cooldown_ticks", #rs);
|
|
15
|
+
|
|
16
|
+
if (active == 0) {
|
|
17
|
+
return 1;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (ticks_left <= 0) {
|
|
21
|
+
return 1;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fn cooldown_tick(name: string) {
|
|
28
|
+
let active: int = scoreboard_get("cooldown_active", #rs);
|
|
29
|
+
let ticks_left: int = scoreboard_get("cooldown_ticks", #rs);
|
|
30
|
+
|
|
31
|
+
if (active == 0) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (ticks_left > 0) {
|
|
36
|
+
let next: int = ticks_left - 1;
|
|
37
|
+
scoreboard_set("cooldown_ticks", #rs, next);
|
|
38
|
+
|
|
39
|
+
if (next == 0) {
|
|
40
|
+
scoreboard_set("cooldown_active", #rs, 0);
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
scoreboard_set("cooldown_active", #rs, 0);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Integer math helpers for RedScript datapacks.
|
|
2
|
+
|
|
3
|
+
fn abs(x: int) -> int {
|
|
4
|
+
if (x < 0) {
|
|
5
|
+
return -x;
|
|
6
|
+
} else {
|
|
7
|
+
return x;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
fn min(a: int, b: int) -> int {
|
|
12
|
+
if (a < b) {
|
|
13
|
+
return a;
|
|
14
|
+
} else {
|
|
15
|
+
return b;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
fn max(a: int, b: int) -> int {
|
|
20
|
+
if (a > b) {
|
|
21
|
+
return a;
|
|
22
|
+
} else {
|
|
23
|
+
return b;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fn clamp(x: int, lo: int, hi: int) -> int {
|
|
28
|
+
if (x < lo) {
|
|
29
|
+
return lo;
|
|
30
|
+
} else {
|
|
31
|
+
if (x > hi) {
|
|
32
|
+
return hi;
|
|
33
|
+
} else {
|
|
34
|
+
return x;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
fn sign(x: int) -> int {
|
|
40
|
+
if (x > 0) {
|
|
41
|
+
return 1;
|
|
42
|
+
} else {
|
|
43
|
+
if (x < 0) {
|
|
44
|
+
return -1;
|
|
45
|
+
} else {
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// Vanilla Minecraft Java Edition entity type constants.
|
|
2
|
+
// Copy the names you need into your own project until RedScript gets imports.
|
|
3
|
+
|
|
4
|
+
// Hostile mobs
|
|
5
|
+
const ZOMBIE: string = "minecraft:zombie"
|
|
6
|
+
const SKELETON: string = "minecraft:skeleton"
|
|
7
|
+
const CREEPER: string = "minecraft:creeper"
|
|
8
|
+
const SPIDER: string = "minecraft:spider"
|
|
9
|
+
const CAVE_SPIDER: string = "minecraft:cave_spider"
|
|
10
|
+
const ENDERMAN: string = "minecraft:enderman"
|
|
11
|
+
const WITCH: string = "minecraft:witch"
|
|
12
|
+
const PHANTOM: string = "minecraft:phantom"
|
|
13
|
+
const DROWNED: string = "minecraft:drowned"
|
|
14
|
+
const HUSK: string = "minecraft:husk"
|
|
15
|
+
const STRAY: string = "minecraft:stray"
|
|
16
|
+
const WARDEN: string = "minecraft:warden"
|
|
17
|
+
const PILLAGER: string = "minecraft:pillager"
|
|
18
|
+
const RAVAGER: string = "minecraft:ravager"
|
|
19
|
+
const VINDICATOR: string = "minecraft:vindicator"
|
|
20
|
+
const EVOKER: string = "minecraft:evoker"
|
|
21
|
+
const VEXE: string = "minecraft:vex"
|
|
22
|
+
const ZOMBIE_VILLAGER: string = "minecraft:zombie_villager"
|
|
23
|
+
const BLAZE: string = "minecraft:blaze"
|
|
24
|
+
const GHAST: string = "minecraft:ghast"
|
|
25
|
+
const MAGMA_CUBE: string = "minecraft:magma_cube"
|
|
26
|
+
const SLIME: string = "minecraft:slime"
|
|
27
|
+
const PIGLIN_BRUTE: string = "minecraft:piglin_brute"
|
|
28
|
+
const HOGLIN: string = "minecraft:hoglin"
|
|
29
|
+
const ZOGLIN: string = "minecraft:zoglin"
|
|
30
|
+
const ENDERMITE: string = "minecraft:endermite"
|
|
31
|
+
const SILVERFISH: string = "minecraft:silverfish"
|
|
32
|
+
const SHULKER: string = "minecraft:shulker"
|
|
33
|
+
const GUARDIAN: string = "minecraft:guardian"
|
|
34
|
+
const ELDER_GUARDIAN: string = "minecraft:elder_guardian"
|
|
35
|
+
const BOGGED: string = "minecraft:bogged"
|
|
36
|
+
const BREEZE: string = "minecraft:breeze"
|
|
37
|
+
|
|
38
|
+
// Passive mobs
|
|
39
|
+
const PIG: string = "minecraft:pig"
|
|
40
|
+
const COW: string = "minecraft:cow"
|
|
41
|
+
const SHEEP: string = "minecraft:sheep"
|
|
42
|
+
const CHICKEN: string = "minecraft:chicken"
|
|
43
|
+
const HORSE: string = "minecraft:horse"
|
|
44
|
+
const DONKEY: string = "minecraft:donkey"
|
|
45
|
+
const MULE: string = "minecraft:mule"
|
|
46
|
+
const RABBIT: string = "minecraft:rabbit"
|
|
47
|
+
const COD: string = "minecraft:cod"
|
|
48
|
+
const SALMON: string = "minecraft:salmon"
|
|
49
|
+
const TROPICAL_FISH: string = "minecraft:tropical_fish"
|
|
50
|
+
const PUFFERFISH: string = "minecraft:pufferfish"
|
|
51
|
+
const SQUID: string = "minecraft:squid"
|
|
52
|
+
const GLOW_SQUID: string = "minecraft:glow_squid"
|
|
53
|
+
const BAT: string = "minecraft:bat"
|
|
54
|
+
const VILLAGER: string = "minecraft:villager"
|
|
55
|
+
const WANDERING_TRADER: string = "minecraft:wandering_trader"
|
|
56
|
+
const SNOW_GOLEM: string = "minecraft:snow_golem"
|
|
57
|
+
const STRIDER: string = "minecraft:strider"
|
|
58
|
+
const AXOLOTL: string = "minecraft:axolotl"
|
|
59
|
+
const FROG: string = "minecraft:frog"
|
|
60
|
+
const TADPOLE: string = "minecraft:tadpole"
|
|
61
|
+
const ALLAY: string = "minecraft:allay"
|
|
62
|
+
const SNIFFER: string = "minecraft:sniffer"
|
|
63
|
+
const ARMADILLO: string = "minecraft:armadillo"
|
|
64
|
+
const TURTLE: string = "minecraft:turtle"
|
|
65
|
+
|
|
66
|
+
// Neutral mobs
|
|
67
|
+
const WOLF: string = "minecraft:wolf"
|
|
68
|
+
const BEE: string = "minecraft:bee"
|
|
69
|
+
const POLAR_BEAR: string = "minecraft:polar_bear"
|
|
70
|
+
const DOLPHIN: string = "minecraft:dolphin"
|
|
71
|
+
const IRON_GOLEM: string = "minecraft:iron_golem"
|
|
72
|
+
const PIGLIN: string = "minecraft:piglin"
|
|
73
|
+
const ZOMBIFIED_PIGLIN: string = "minecraft:zombified_piglin"
|
|
74
|
+
const PANDA: string = "minecraft:panda"
|
|
75
|
+
const LLAMA: string = "minecraft:llama"
|
|
76
|
+
const TRADER_LLAMA: string = "minecraft:trader_llama"
|
|
77
|
+
const CAT: string = "minecraft:cat"
|
|
78
|
+
const OCELOT: string = "minecraft:ocelot"
|
|
79
|
+
const FOX: string = "minecraft:fox"
|
|
80
|
+
const GOAT: string = "minecraft:goat"
|
|
81
|
+
const CAMEL: string = "minecraft:camel"
|
|
82
|
+
|
|
83
|
+
// Bosses
|
|
84
|
+
const ENDER_DRAGON: string = "minecraft:ender_dragon"
|
|
85
|
+
const WITHER: string = "minecraft:wither"
|
|
86
|
+
|
|
87
|
+
// Special / misc
|
|
88
|
+
const ARMOR_STAND: string = "minecraft:armor_stand"
|
|
89
|
+
const ITEM_FRAME: string = "minecraft:item_frame"
|
|
90
|
+
const GLOW_ITEM_FRAME: string = "minecraft:glow_item_frame"
|
|
91
|
+
const PAINTING: string = "minecraft:painting"
|
|
92
|
+
const BOAT: string = "minecraft:boat"
|
|
93
|
+
const MINECART: string = "minecraft:minecart"
|
|
94
|
+
const TNT: string = "minecraft:tnt"
|
|
95
|
+
const FALLING_BLOCK: string = "minecraft:falling_block"
|
|
96
|
+
const ITEM: string = "minecraft:item"
|
|
97
|
+
const XP_ORB: string = "minecraft:experience_orb"
|
|
98
|
+
const FIREBALL: string = "minecraft:fireball"
|
|
99
|
+
const PLAYER: string = "minecraft:player"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Player helpers built on scoreboard/tag patterns.
|
|
2
|
+
// These helpers target the nearest player via @p.
|
|
3
|
+
|
|
4
|
+
fn heal(amount: int) {
|
|
5
|
+
let health: int = scoreboard_get(@p, #health);
|
|
6
|
+
let next: int = health + amount;
|
|
7
|
+
scoreboard_set(@p, #health, next);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
fn damage(amount: int) {
|
|
11
|
+
let health: int = scoreboard_get(@p, #health);
|
|
12
|
+
let next: int = health - amount;
|
|
13
|
+
|
|
14
|
+
if (next < 0) {
|
|
15
|
+
scoreboard_set(@p, #health, 0);
|
|
16
|
+
} else {
|
|
17
|
+
scoreboard_set(@p, #health, next);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
fn is_op() -> int {
|
|
22
|
+
let result: int = 0;
|
|
23
|
+
|
|
24
|
+
execute if entity @p[tag=op] run {
|
|
25
|
+
result = 1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Countdown timer helpers.
|
|
2
|
+
//
|
|
3
|
+
// The current compiler does not propagate string literals through user-defined
|
|
4
|
+
// function calls yet, so the `name` parameter is a forward-compatible placeholder.
|
|
5
|
+
// This module manages one timer slot backed by fake players on the `rs` objective.
|
|
6
|
+
|
|
7
|
+
struct Timer {
|
|
8
|
+
ticks: int,
|
|
9
|
+
active: int
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
fn timer_start(name: string, duration: int) {
|
|
13
|
+
scoreboard_set("timer_ticks", #rs, duration);
|
|
14
|
+
scoreboard_set("timer_active", #rs, 1);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
fn timer_tick(name: string) -> int {
|
|
18
|
+
let active: int = scoreboard_get("timer_active", #rs);
|
|
19
|
+
let ticks: int = scoreboard_get("timer_ticks", #rs);
|
|
20
|
+
|
|
21
|
+
if (active == 0) {
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (ticks > 0) {
|
|
26
|
+
let next: int = ticks - 1;
|
|
27
|
+
scoreboard_set("timer_ticks", #rs, next);
|
|
28
|
+
|
|
29
|
+
if (next == 0) {
|
|
30
|
+
scoreboard_set("timer_active", #rs, 0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return next;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
scoreboard_set("timer_active", #rs, 0);
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
fn timer_done(name: string) -> int {
|
|
41
|
+
let active: int = scoreboard_get("timer_active", #rs);
|
|
42
|
+
let ticks: int = scoreboard_get("timer_ticks", #rs);
|
|
43
|
+
|
|
44
|
+
if (active == 0) {
|
|
45
|
+
if (ticks <= 0) {
|
|
46
|
+
return 1;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Templates
|
|
2
|
+
|
|
3
|
+
This folder contains production-oriented RedScript templates you can copy into datapack projects and adapt to your own scoreboard/objective naming.
|
|
4
|
+
|
|
5
|
+
## Included templates
|
|
6
|
+
|
|
7
|
+
### `mini-game-framework.rs`
|
|
8
|
+
|
|
9
|
+
A reusable round controller with four phases:
|
|
10
|
+
|
|
11
|
+
- `0`: waiting
|
|
12
|
+
- `1`: starting
|
|
13
|
+
- `2`: playing
|
|
14
|
+
- `3`: ending
|
|
15
|
+
|
|
16
|
+
It provides `/trigger game_join`, `/trigger game_start`, and a `@tick(rate=20)` loop that advances the countdown and announces state changes with `title`, `subtitle`, and `actionbar`.
|
|
17
|
+
|
|
18
|
+
### `economy.rs`
|
|
19
|
+
|
|
20
|
+
A scoreboard-backed coin system with:
|
|
21
|
+
|
|
22
|
+
- `earn(player, amount)`
|
|
23
|
+
- `spend(player, amount) -> int`
|
|
24
|
+
- `balance(player) -> int`
|
|
25
|
+
- `shop_buy(player, item, price)`
|
|
26
|
+
|
|
27
|
+
Use it as the base layer for shops, quest rewards, or class unlocks.
|
|
28
|
+
|
|
29
|
+
### `combat.rs`
|
|
30
|
+
|
|
31
|
+
A combat state module built around `CombatEntity`:
|
|
32
|
+
|
|
33
|
+
- health
|
|
34
|
+
- max health
|
|
35
|
+
- defense
|
|
36
|
+
- cooldown
|
|
37
|
+
|
|
38
|
+
It includes direct damage/heal helpers, alive checks, cooldown ticking, and combat tags such as `in_combat`, `combat_ready`, and `defeated`.
|
|
39
|
+
|
|
40
|
+
### `quest.rs`
|
|
41
|
+
|
|
42
|
+
A mission system using a `Quest` struct and scoreboard-backed progress:
|
|
43
|
+
|
|
44
|
+
- start a quest
|
|
45
|
+
- add progress
|
|
46
|
+
- complete the quest
|
|
47
|
+
- hook into `/trigger kill_zombie`
|
|
48
|
+
|
|
49
|
+
This works well for survival servers, RPG loops, and PvE encounters.
|
|
50
|
+
|
|
51
|
+
## Combining templates
|
|
52
|
+
|
|
53
|
+
### Economy + Combat = RPG foundation
|
|
54
|
+
|
|
55
|
+
Use `combat.rs` to handle health, armor, and cooldown windows. Reward victories or enemy kills through `economy.rs`, then let players spend coins on better gear or consumables.
|
|
56
|
+
|
|
57
|
+
### Quest + Economy = reward loop
|
|
58
|
+
|
|
59
|
+
Run `quest_complete()` and then call `earn()` to pay players for finishing objectives. This gives you a clean mission-reward pipeline with minimal scoreboard plumbing.
|
|
60
|
+
|
|
61
|
+
### Mini-game framework + Combat = arena match
|
|
62
|
+
|
|
63
|
+
Use `mini-game-framework.rs` for phase control and player flow, then activate combat logic only during phase `2` so the lobby and ending states remain safe.
|
|
64
|
+
|
|
65
|
+
## RedScript reference card
|
|
66
|
+
|
|
67
|
+
### Core syntax
|
|
68
|
+
|
|
69
|
+
```rs
|
|
70
|
+
struct Stats { hp: int, armor: int }
|
|
71
|
+
|
|
72
|
+
fn add(a: int, b: int) -> int {
|
|
73
|
+
return a + b;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (score > 10) {
|
|
77
|
+
title(@s, "Ready");
|
|
78
|
+
} else {
|
|
79
|
+
actionbar(@s, "Keep going");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
foreach (player in @a) {
|
|
83
|
+
tell(player, "Round live");
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Decorators
|
|
88
|
+
|
|
89
|
+
```rs
|
|
90
|
+
@tick
|
|
91
|
+
fn every_tick() {}
|
|
92
|
+
|
|
93
|
+
@tick(rate=20)
|
|
94
|
+
fn once_per_second() {}
|
|
95
|
+
|
|
96
|
+
@on_trigger("shop_buy")
|
|
97
|
+
fn handle_trigger() {}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Common builtins
|
|
101
|
+
|
|
102
|
+
```rs
|
|
103
|
+
title(@a, "Fight!");
|
|
104
|
+
actionbar(@a, "Capture the point");
|
|
105
|
+
give(@s, "minecraft:bread", 1);
|
|
106
|
+
scoreboard_set("@s", "coins", 10);
|
|
107
|
+
let coins: int = scoreboard_get("@s", "coins");
|
|
108
|
+
tag_add(@s, "boss");
|
|
109
|
+
tag_remove(@s, "boss");
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Execution context
|
|
113
|
+
|
|
114
|
+
```rs
|
|
115
|
+
as @a {
|
|
116
|
+
say("Hello");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
at @s {
|
|
120
|
+
summon("zombie", "~", "~", "~");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
execute as @a if entity @s[tag=vip] run {
|
|
124
|
+
title(@s, "VIP");
|
|
125
|
+
}
|
|
126
|
+
```
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// Combat helper library with scoreboard-backed health and cooldown state.
|
|
2
|
+
|
|
3
|
+
struct CombatEntity { health: int, maxHealth: int, defense: int, cooldown: int }
|
|
4
|
+
|
|
5
|
+
fn entity_state(target: string) -> CombatEntity {
|
|
6
|
+
let health: int = scoreboard_get(target, #health);
|
|
7
|
+
let maxHealth: int = scoreboard_get(target, #max_health);
|
|
8
|
+
let defense: int = scoreboard_get(target, #defense);
|
|
9
|
+
let cooldown: int = scoreboard_get(target, #cooldown);
|
|
10
|
+
let entity: CombatEntity = {
|
|
11
|
+
health: health,
|
|
12
|
+
maxHealth: maxHealth,
|
|
13
|
+
defense: defense,
|
|
14
|
+
cooldown: cooldown
|
|
15
|
+
};
|
|
16
|
+
return entity;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
fn deal_damage(attacker: string, target: string, damage: int) {
|
|
20
|
+
let entity: CombatEntity = entity_state(target);
|
|
21
|
+
let finalDamage: int = damage - entity.defense;
|
|
22
|
+
|
|
23
|
+
if (entity.cooldown > 0) {
|
|
24
|
+
actionbar(attacker, "Attack on cooldown");
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (finalDamage < 1) {
|
|
29
|
+
finalDamage = 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (entity.health > finalDamage) {
|
|
33
|
+
entity.health = entity.health - finalDamage;
|
|
34
|
+
scoreboard_set(target, #health, entity.health);
|
|
35
|
+
scoreboard_set(attacker, #cooldown, 10);
|
|
36
|
+
tag_add(attacker, #in_combat);
|
|
37
|
+
tag_add(target, #in_combat);
|
|
38
|
+
tag_add(attacker, #combat_ready);
|
|
39
|
+
tag_remove(attacker, #combat_ready);
|
|
40
|
+
actionbar(attacker, "Hit confirmed");
|
|
41
|
+
actionbar(target, "You took damage");
|
|
42
|
+
} else {
|
|
43
|
+
scoreboard_set(target, #health, 0);
|
|
44
|
+
scoreboard_set(attacker, #cooldown, 10);
|
|
45
|
+
tag_add(attacker, #in_combat);
|
|
46
|
+
tag_add(target, #in_combat);
|
|
47
|
+
tag_add(target, #defeated);
|
|
48
|
+
tag_remove(target, #combat_ready);
|
|
49
|
+
title(target, "Defeated");
|
|
50
|
+
subtitle(target, "Wait for a heal or respawn");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
fn heal_entity(target: string, amount: int) {
|
|
55
|
+
let entity: CombatEntity = entity_state(target);
|
|
56
|
+
|
|
57
|
+
if (entity.health <= 0) {
|
|
58
|
+
tag_remove(target, #defeated);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
entity.health = entity.health + amount;
|
|
62
|
+
if (entity.health > entity.maxHealth) {
|
|
63
|
+
entity.health = entity.maxHealth;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
scoreboard_set(target, #health, entity.health);
|
|
67
|
+
actionbar(target, "Health restored");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fn is_alive(target: string) -> int {
|
|
71
|
+
let health: int = scoreboard_get(target, #health);
|
|
72
|
+
if (health > 0) {
|
|
73
|
+
return 1;
|
|
74
|
+
}
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@tick(rate=1)
|
|
79
|
+
fn combat_tick() {
|
|
80
|
+
foreach (entity in @e[tag=in_combat]) {
|
|
81
|
+
let cooldown: int = scoreboard_get(@s, #cooldown);
|
|
82
|
+
|
|
83
|
+
if (cooldown > 0) {
|
|
84
|
+
let next: int = cooldown - 1;
|
|
85
|
+
scoreboard_set(@s, #cooldown, next);
|
|
86
|
+
|
|
87
|
+
if (next == 0) {
|
|
88
|
+
tag_add(@s, #combat_ready);
|
|
89
|
+
tag_remove(@s, #in_combat);
|
|
90
|
+
}
|
|
91
|
+
} else {
|
|
92
|
+
tag_add(@s, #combat_ready);
|
|
93
|
+
tag_remove(@s, #in_combat);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|