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.
Files changed (272) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +40 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +31 -0
  3. package/.github/ISSUE_TEMPLATE/wrong_output.md +33 -0
  4. package/.github/PULL_REQUEST_TEMPLATE.md +34 -0
  5. package/.github/workflows/ci.yml +29 -0
  6. package/.github/workflows/publish-extension.yml +35 -0
  7. package/LICENSE +21 -0
  8. package/README.md +261 -0
  9. package/README.zh.md +261 -0
  10. package/dist/__tests__/cli.test.d.ts +1 -0
  11. package/dist/__tests__/cli.test.js +140 -0
  12. package/dist/__tests__/codegen.test.d.ts +1 -0
  13. package/dist/__tests__/codegen.test.js +121 -0
  14. package/dist/__tests__/diagnostics.test.d.ts +4 -0
  15. package/dist/__tests__/diagnostics.test.js +149 -0
  16. package/dist/__tests__/e2e.test.d.ts +6 -0
  17. package/dist/__tests__/e2e.test.js +1528 -0
  18. package/dist/__tests__/lexer.test.d.ts +1 -0
  19. package/dist/__tests__/lexer.test.js +316 -0
  20. package/dist/__tests__/lowering.test.d.ts +1 -0
  21. package/dist/__tests__/lowering.test.js +819 -0
  22. package/dist/__tests__/mc-integration.test.d.ts +12 -0
  23. package/dist/__tests__/mc-integration.test.js +395 -0
  24. package/dist/__tests__/mc-syntax.test.d.ts +1 -0
  25. package/dist/__tests__/mc-syntax.test.js +112 -0
  26. package/dist/__tests__/nbt.test.d.ts +1 -0
  27. package/dist/__tests__/nbt.test.js +82 -0
  28. package/dist/__tests__/optimizer-advanced.test.d.ts +1 -0
  29. package/dist/__tests__/optimizer-advanced.test.js +124 -0
  30. package/dist/__tests__/optimizer.test.d.ts +1 -0
  31. package/dist/__tests__/optimizer.test.js +118 -0
  32. package/dist/__tests__/parser.test.d.ts +1 -0
  33. package/dist/__tests__/parser.test.js +717 -0
  34. package/dist/__tests__/repl.test.d.ts +1 -0
  35. package/dist/__tests__/repl.test.js +27 -0
  36. package/dist/__tests__/runtime.test.d.ts +1 -0
  37. package/dist/__tests__/runtime.test.js +276 -0
  38. package/dist/__tests__/structure-optimizer.test.d.ts +1 -0
  39. package/dist/__tests__/structure-optimizer.test.js +33 -0
  40. package/dist/__tests__/typechecker.test.d.ts +1 -0
  41. package/dist/__tests__/typechecker.test.js +364 -0
  42. package/dist/ast/types.d.ts +357 -0
  43. package/dist/ast/types.js +9 -0
  44. package/dist/cli.d.ts +11 -0
  45. package/dist/cli.js +407 -0
  46. package/dist/codegen/cmdblock/index.d.ts +26 -0
  47. package/dist/codegen/cmdblock/index.js +45 -0
  48. package/dist/codegen/mcfunction/index.d.ts +34 -0
  49. package/dist/codegen/mcfunction/index.js +413 -0
  50. package/dist/codegen/structure/index.d.ts +18 -0
  51. package/dist/codegen/structure/index.js +249 -0
  52. package/dist/compile.d.ts +30 -0
  53. package/dist/compile.js +152 -0
  54. package/dist/data/arena/function/__load.mcfunction +6 -0
  55. package/dist/data/arena/function/__tick.mcfunction +2 -0
  56. package/dist/data/arena/function/announce_leaders/else_1.mcfunction +3 -0
  57. package/dist/data/arena/function/announce_leaders/foreach_0/merge_2.mcfunction +1 -0
  58. package/dist/data/arena/function/announce_leaders/foreach_0/then_0.mcfunction +3 -0
  59. package/dist/data/arena/function/announce_leaders/foreach_0.mcfunction +7 -0
  60. package/dist/data/arena/function/announce_leaders/foreach_1/merge_2.mcfunction +1 -0
  61. package/dist/data/arena/function/announce_leaders/foreach_1/then_0.mcfunction +4 -0
  62. package/dist/data/arena/function/announce_leaders/foreach_1.mcfunction +6 -0
  63. package/dist/data/arena/function/announce_leaders/merge_2.mcfunction +1 -0
  64. package/dist/data/arena/function/announce_leaders/then_0.mcfunction +4 -0
  65. package/dist/data/arena/function/announce_leaders.mcfunction +6 -0
  66. package/dist/data/arena/function/arena_tick/merge_2.mcfunction +1 -0
  67. package/dist/data/arena/function/arena_tick/then_0.mcfunction +4 -0
  68. package/dist/data/arena/function/arena_tick.mcfunction +11 -0
  69. package/dist/data/counter/function/__load.mcfunction +5 -0
  70. package/dist/data/counter/function/__tick.mcfunction +2 -0
  71. package/dist/data/counter/function/counter_tick/merge_2.mcfunction +1 -0
  72. package/dist/data/counter/function/counter_tick/then_0.mcfunction +3 -0
  73. package/dist/data/counter/function/counter_tick.mcfunction +11 -0
  74. package/dist/data/minecraft/tags/function/load.json +5 -0
  75. package/dist/data/minecraft/tags/function/tick.json +5 -0
  76. package/dist/data/quiz/function/__load.mcfunction +16 -0
  77. package/dist/data/quiz/function/__tick.mcfunction +6 -0
  78. package/dist/data/quiz/function/__trigger_quiz_a_dispatch.mcfunction +4 -0
  79. package/dist/data/quiz/function/__trigger_quiz_b_dispatch.mcfunction +4 -0
  80. package/dist/data/quiz/function/__trigger_quiz_c_dispatch.mcfunction +4 -0
  81. package/dist/data/quiz/function/__trigger_quiz_start_dispatch.mcfunction +4 -0
  82. package/dist/data/quiz/function/answer_a.mcfunction +4 -0
  83. package/dist/data/quiz/function/answer_b.mcfunction +4 -0
  84. package/dist/data/quiz/function/answer_c.mcfunction +4 -0
  85. package/dist/data/quiz/function/ask_question/else_1.mcfunction +5 -0
  86. package/dist/data/quiz/function/ask_question/else_4.mcfunction +5 -0
  87. package/dist/data/quiz/function/ask_question/else_7.mcfunction +4 -0
  88. package/dist/data/quiz/function/ask_question/merge_2.mcfunction +1 -0
  89. package/dist/data/quiz/function/ask_question/merge_5.mcfunction +2 -0
  90. package/dist/data/quiz/function/ask_question/merge_8.mcfunction +2 -0
  91. package/dist/data/quiz/function/ask_question/then_0.mcfunction +4 -0
  92. package/dist/data/quiz/function/ask_question/then_3.mcfunction +4 -0
  93. package/dist/data/quiz/function/ask_question/then_6.mcfunction +4 -0
  94. package/dist/data/quiz/function/ask_question.mcfunction +7 -0
  95. package/dist/data/quiz/function/finish_quiz.mcfunction +6 -0
  96. package/dist/data/quiz/function/handle_answer/else_1.mcfunction +5 -0
  97. package/dist/data/quiz/function/handle_answer/else_10.mcfunction +3 -0
  98. package/dist/data/quiz/function/handle_answer/else_16.mcfunction +3 -0
  99. package/dist/data/quiz/function/handle_answer/else_4.mcfunction +3 -0
  100. package/dist/data/quiz/function/handle_answer/else_7.mcfunction +5 -0
  101. package/dist/data/quiz/function/handle_answer/merge_11.mcfunction +2 -0
  102. package/dist/data/quiz/function/handle_answer/merge_14.mcfunction +2 -0
  103. package/dist/data/quiz/function/handle_answer/merge_17.mcfunction +2 -0
  104. package/dist/data/quiz/function/handle_answer/merge_2.mcfunction +8 -0
  105. package/dist/data/quiz/function/handle_answer/merge_5.mcfunction +2 -0
  106. package/dist/data/quiz/function/handle_answer/merge_8.mcfunction +2 -0
  107. package/dist/data/quiz/function/handle_answer/then_0.mcfunction +5 -0
  108. package/dist/data/quiz/function/handle_answer/then_12.mcfunction +5 -0
  109. package/dist/data/quiz/function/handle_answer/then_15.mcfunction +6 -0
  110. package/dist/data/quiz/function/handle_answer/then_3.mcfunction +6 -0
  111. package/dist/data/quiz/function/handle_answer/then_6.mcfunction +5 -0
  112. package/dist/data/quiz/function/handle_answer/then_9.mcfunction +6 -0
  113. package/dist/data/quiz/function/handle_answer.mcfunction +11 -0
  114. package/dist/data/quiz/function/start_quiz.mcfunction +5 -0
  115. package/dist/data/shop/function/__load.mcfunction +7 -0
  116. package/dist/data/shop/function/__tick.mcfunction +3 -0
  117. package/dist/data/shop/function/__trigger_shop_buy_dispatch.mcfunction +4 -0
  118. package/dist/data/shop/function/complete_purchase/else_1.mcfunction +5 -0
  119. package/dist/data/shop/function/complete_purchase/else_4.mcfunction +5 -0
  120. package/dist/data/shop/function/complete_purchase/else_7.mcfunction +3 -0
  121. package/dist/data/shop/function/complete_purchase/merge_2.mcfunction +2 -0
  122. package/dist/data/shop/function/complete_purchase/merge_5.mcfunction +2 -0
  123. package/dist/data/shop/function/complete_purchase/merge_8.mcfunction +2 -0
  124. package/dist/data/shop/function/complete_purchase/then_0.mcfunction +4 -0
  125. package/dist/data/shop/function/complete_purchase/then_3.mcfunction +4 -0
  126. package/dist/data/shop/function/complete_purchase/then_6.mcfunction +4 -0
  127. package/dist/data/shop/function/complete_purchase.mcfunction +7 -0
  128. package/dist/data/shop/function/handle_shop_trigger.mcfunction +3 -0
  129. package/dist/data/turret/function/__load.mcfunction +5 -0
  130. package/dist/data/turret/function/__tick.mcfunction +4 -0
  131. package/dist/data/turret/function/__trigger_deploy_turret_dispatch.mcfunction +4 -0
  132. package/dist/data/turret/function/deploy_turret.mcfunction +8 -0
  133. package/dist/data/turret/function/turret_tick/at_1.mcfunction +2 -0
  134. package/dist/data/turret/function/turret_tick/foreach_0.mcfunction +2 -0
  135. package/dist/data/turret/function/turret_tick/foreach_2.mcfunction +2 -0
  136. package/dist/data/turret/function/turret_tick/tick_body.mcfunction +3 -0
  137. package/dist/data/turret/function/turret_tick/tick_skip.mcfunction +1 -0
  138. package/dist/data/turret/function/turret_tick.mcfunction +5 -0
  139. package/dist/diagnostics/index.d.ts +44 -0
  140. package/dist/diagnostics/index.js +140 -0
  141. package/dist/index.d.ts +53 -0
  142. package/dist/index.js +126 -0
  143. package/dist/ir/builder.d.ts +32 -0
  144. package/dist/ir/builder.js +99 -0
  145. package/dist/ir/types.d.ts +117 -0
  146. package/dist/ir/types.js +15 -0
  147. package/dist/lexer/index.d.ts +36 -0
  148. package/dist/lexer/index.js +458 -0
  149. package/dist/lowering/index.d.ts +106 -0
  150. package/dist/lowering/index.js +2041 -0
  151. package/dist/mc-test/client.d.ts +128 -0
  152. package/dist/mc-test/client.js +174 -0
  153. package/dist/mc-test/runner.d.ts +28 -0
  154. package/dist/mc-test/runner.js +150 -0
  155. package/dist/mc-test/setup.d.ts +11 -0
  156. package/dist/mc-test/setup.js +98 -0
  157. package/dist/mc-validator/index.d.ts +17 -0
  158. package/dist/mc-validator/index.js +322 -0
  159. package/dist/nbt/index.d.ts +86 -0
  160. package/dist/nbt/index.js +250 -0
  161. package/dist/optimizer/commands.d.ts +36 -0
  162. package/dist/optimizer/commands.js +349 -0
  163. package/dist/optimizer/passes.d.ts +34 -0
  164. package/dist/optimizer/passes.js +227 -0
  165. package/dist/optimizer/structure.d.ts +8 -0
  166. package/dist/optimizer/structure.js +344 -0
  167. package/dist/pack.mcmeta +6 -0
  168. package/dist/parser/index.d.ts +76 -0
  169. package/dist/parser/index.js +1193 -0
  170. package/dist/repl.d.ts +16 -0
  171. package/dist/repl.js +165 -0
  172. package/dist/runtime/index.d.ts +101 -0
  173. package/dist/runtime/index.js +1288 -0
  174. package/dist/typechecker/index.d.ts +42 -0
  175. package/dist/typechecker/index.js +629 -0
  176. package/docs/COMPILATION_STATS.md +142 -0
  177. package/docs/IMPLEMENTATION_GUIDE.md +512 -0
  178. package/docs/LANGUAGE_REFERENCE.md +415 -0
  179. package/docs/MC_MAPPING.md +280 -0
  180. package/docs/STRUCTURE_TARGET.md +80 -0
  181. package/docs/mc-reference/commands.md +259 -0
  182. package/editors/vscode/.vscodeignore +10 -0
  183. package/editors/vscode/LICENSE +21 -0
  184. package/editors/vscode/README.md +78 -0
  185. package/editors/vscode/build.mjs +28 -0
  186. package/editors/vscode/icon.png +0 -0
  187. package/editors/vscode/mcfunction-language-configuration.json +28 -0
  188. package/editors/vscode/out/extension.js +7236 -0
  189. package/editors/vscode/package-lock.json +566 -0
  190. package/editors/vscode/package.json +137 -0
  191. package/editors/vscode/redscript-language-configuration.json +28 -0
  192. package/editors/vscode/snippets/redscript.json +114 -0
  193. package/editors/vscode/src/codeactions.ts +89 -0
  194. package/editors/vscode/src/completion.ts +130 -0
  195. package/editors/vscode/src/extension.ts +239 -0
  196. package/editors/vscode/src/hover.ts +1120 -0
  197. package/editors/vscode/src/symbols.ts +207 -0
  198. package/editors/vscode/syntaxes/mcfunction.tmLanguage.json +740 -0
  199. package/editors/vscode/syntaxes/redscript.tmLanguage.json +357 -0
  200. package/editors/vscode/tsconfig.json +13 -0
  201. package/jest.config.js +5 -0
  202. package/package.json +38 -0
  203. package/src/__tests__/cli.test.ts +130 -0
  204. package/src/__tests__/codegen.test.ts +128 -0
  205. package/src/__tests__/diagnostics.test.ts +195 -0
  206. package/src/__tests__/e2e.test.ts +1721 -0
  207. package/src/__tests__/fixtures/mc-commands-1.21.4.json +18734 -0
  208. package/src/__tests__/formatter.test.ts +46 -0
  209. package/src/__tests__/lexer.test.ts +356 -0
  210. package/src/__tests__/lowering.test.ts +962 -0
  211. package/src/__tests__/mc-integration.test.ts +409 -0
  212. package/src/__tests__/mc-syntax.test.ts +96 -0
  213. package/src/__tests__/nbt.test.ts +58 -0
  214. package/src/__tests__/optimizer-advanced.test.ts +144 -0
  215. package/src/__tests__/optimizer.test.ts +129 -0
  216. package/src/__tests__/parser.test.ts +800 -0
  217. package/src/__tests__/repl.test.ts +33 -0
  218. package/src/__tests__/runtime.test.ts +289 -0
  219. package/src/__tests__/structure-optimizer.test.ts +38 -0
  220. package/src/__tests__/typechecker.test.ts +395 -0
  221. package/src/ast/types.ts +248 -0
  222. package/src/cli.ts +445 -0
  223. package/src/codegen/cmdblock/index.ts +63 -0
  224. package/src/codegen/mcfunction/index.ts +471 -0
  225. package/src/codegen/structure/index.ts +305 -0
  226. package/src/compile.ts +188 -0
  227. package/src/diagnostics/index.ts +186 -0
  228. package/src/examples/README.md +77 -0
  229. package/src/examples/SHOWCASE_GAME.md +43 -0
  230. package/src/examples/arena.rs +44 -0
  231. package/src/examples/counter.rs +12 -0
  232. package/src/examples/pvp_arena.rs +131 -0
  233. package/src/examples/quiz.rs +90 -0
  234. package/src/examples/rpg.rs +13 -0
  235. package/src/examples/shop.rs +30 -0
  236. package/src/examples/showcase_game.rs +552 -0
  237. package/src/examples/stdlib_demo.rs +181 -0
  238. package/src/examples/turret.rs +27 -0
  239. package/src/examples/world_manager.rs +23 -0
  240. package/src/formatter/index.ts +22 -0
  241. package/src/index.ts +161 -0
  242. package/src/ir/builder.ts +114 -0
  243. package/src/ir/types.ts +119 -0
  244. package/src/lexer/index.ts +555 -0
  245. package/src/lowering/index.ts +2406 -0
  246. package/src/mc-test/client.ts +259 -0
  247. package/src/mc-test/runner.ts +140 -0
  248. package/src/mc-test/setup.ts +70 -0
  249. package/src/mc-validator/index.ts +367 -0
  250. package/src/nbt/index.ts +321 -0
  251. package/src/optimizer/commands.ts +416 -0
  252. package/src/optimizer/passes.ts +233 -0
  253. package/src/optimizer/structure.ts +441 -0
  254. package/src/parser/index.ts +1437 -0
  255. package/src/repl.ts +165 -0
  256. package/src/runtime/index.ts +1403 -0
  257. package/src/stdlib/README.md +156 -0
  258. package/src/stdlib/combat.rs +20 -0
  259. package/src/stdlib/cooldown.rs +45 -0
  260. package/src/stdlib/math.rs +49 -0
  261. package/src/stdlib/mobs.rs +99 -0
  262. package/src/stdlib/player.rs +29 -0
  263. package/src/stdlib/strings.rs +7 -0
  264. package/src/stdlib/timer.rs +51 -0
  265. package/src/templates/README.md +126 -0
  266. package/src/templates/combat.rs +96 -0
  267. package/src/templates/economy.rs +40 -0
  268. package/src/templates/mini-game-framework.rs +117 -0
  269. package/src/templates/quest.rs +78 -0
  270. package/src/test_programs/zombie_game.rs +25 -0
  271. package/src/typechecker/index.ts +737 -0
  272. 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,7 @@
1
+ // String helpers for RedScript datapacks.
2
+ // Runtime string manipulation is still limited; `str_len` is compiler-assisted
3
+ // and lowers to `data get storage rs:strings ...` for literal-backed strings.
4
+
5
+ fn str_len(s: string) -> int {
6
+ return 0;
7
+ }
@@ -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
+ }