redscript-mc 1.0.0 → 1.2.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 (136) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.yml +72 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.yml +57 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +17 -25
  4. package/CHANGELOG.md +112 -0
  5. package/CONTRIBUTING.md +140 -0
  6. package/README.md +28 -19
  7. package/README.zh.md +28 -19
  8. package/dist/__tests__/cli.test.js +148 -10
  9. package/dist/__tests__/codegen.test.js +26 -1
  10. package/dist/__tests__/diagnostics.test.js +5 -5
  11. package/dist/__tests__/e2e.test.js +336 -17
  12. package/dist/__tests__/formatter.test.d.ts +1 -0
  13. package/dist/__tests__/formatter.test.js +40 -0
  14. package/dist/__tests__/lexer.test.js +12 -2
  15. package/dist/__tests__/lowering.test.js +200 -12
  16. package/dist/__tests__/mc-integration.test.js +370 -31
  17. package/dist/__tests__/mc-syntax.test.js +3 -3
  18. package/dist/__tests__/nbt.test.js +2 -2
  19. package/dist/__tests__/optimizer-advanced.test.js +5 -5
  20. package/dist/__tests__/parser.test.js +80 -0
  21. package/dist/__tests__/runtime.test.js +9 -9
  22. package/dist/__tests__/typechecker.test.js +158 -0
  23. package/dist/ast/types.d.ts +40 -3
  24. package/dist/cli.js +25 -7
  25. package/dist/codegen/mcfunction/index.d.ts +1 -1
  26. package/dist/codegen/mcfunction/index.js +38 -3
  27. package/dist/codegen/structure/index.js +32 -1
  28. package/dist/compile.d.ts +10 -0
  29. package/dist/compile.js +36 -5
  30. package/dist/events/types.d.ts +35 -0
  31. package/dist/events/types.js +59 -0
  32. package/dist/formatter/index.d.ts +1 -0
  33. package/dist/formatter/index.js +26 -0
  34. package/dist/index.js +3 -2
  35. package/dist/ir/builder.d.ts +2 -1
  36. package/dist/ir/types.d.ts +11 -2
  37. package/dist/ir/types.js +1 -1
  38. package/dist/lexer/index.d.ts +1 -1
  39. package/dist/lexer/index.js +2 -0
  40. package/dist/lowering/index.d.ts +34 -1
  41. package/dist/lowering/index.js +622 -23
  42. package/dist/mc-test/runner.d.ts +2 -2
  43. package/dist/mc-test/runner.js +3 -3
  44. package/dist/mc-test/setup.js +2 -2
  45. package/dist/parser/index.d.ts +4 -0
  46. package/dist/parser/index.js +153 -16
  47. package/dist/typechecker/index.d.ts +17 -0
  48. package/dist/typechecker/index.js +343 -17
  49. package/docs/COMPILATION_STATS.md +24 -24
  50. package/docs/ENTITY_TYPE_SYSTEM.md +242 -0
  51. package/docs/IMPLEMENTATION_GUIDE.md +1 -1
  52. package/docs/STRUCTURE_TARGET.md +1 -1
  53. package/editors/vscode/.vscodeignore +1 -0
  54. package/editors/vscode/CHANGELOG.md +9 -0
  55. package/editors/vscode/icons/mcrs.svg +7 -0
  56. package/editors/vscode/icons/redscript-icons.json +10 -0
  57. package/editors/vscode/out/extension.js +1295 -80
  58. package/editors/vscode/package-lock.json +2 -2
  59. package/editors/vscode/package.json +10 -3
  60. package/editors/vscode/src/hover.ts +55 -2
  61. package/editors/vscode/src/symbols.ts +42 -0
  62. package/package.json +1 -1
  63. package/src/__tests__/cli.test.ts +176 -10
  64. package/src/__tests__/codegen.test.ts +28 -1
  65. package/src/__tests__/diagnostics.test.ts +5 -5
  66. package/src/__tests__/e2e.test.ts +335 -17
  67. package/src/__tests__/fixtures/event-test.mcrs +13 -0
  68. package/src/__tests__/fixtures/impl-test.mcrs +46 -0
  69. package/src/__tests__/fixtures/interval-test.mcrs +11 -0
  70. package/src/__tests__/fixtures/is-check-test.mcrs +20 -0
  71. package/src/__tests__/fixtures/timeout-test.mcrs +7 -0
  72. package/src/__tests__/lexer.test.ts +14 -2
  73. package/src/__tests__/lowering.test.ts +226 -12
  74. package/src/__tests__/mc-integration.test.ts +421 -31
  75. package/src/__tests__/mc-syntax.test.ts +3 -3
  76. package/src/__tests__/nbt.test.ts +2 -2
  77. package/src/__tests__/optimizer-advanced.test.ts +5 -5
  78. package/src/__tests__/parser.test.ts +91 -5
  79. package/src/__tests__/runtime.test.ts +9 -9
  80. package/src/__tests__/typechecker.test.ts +171 -0
  81. package/src/ast/types.ts +44 -3
  82. package/src/cli.ts +10 -10
  83. package/src/codegen/mcfunction/index.ts +40 -3
  84. package/src/codegen/structure/index.ts +35 -1
  85. package/src/compile.ts +54 -6
  86. package/src/events/types.ts +69 -0
  87. package/src/examples/capture_the_flag.mcrs +208 -0
  88. package/src/examples/{counter.rs → counter.mcrs} +1 -1
  89. package/src/examples/hunger_games.mcrs +301 -0
  90. package/src/examples/new_features_demo.mcrs +193 -0
  91. package/src/examples/parkour_race.mcrs +233 -0
  92. package/src/examples/rpg.mcrs +13 -0
  93. package/src/examples/{shop.rs → shop.mcrs} +1 -1
  94. package/src/examples/{showcase_game.rs → showcase_game.mcrs} +3 -3
  95. package/src/examples/{turret.rs → turret.mcrs} +1 -1
  96. package/src/examples/zombie_survival.mcrs +314 -0
  97. package/src/index.ts +4 -3
  98. package/src/ir/builder.ts +3 -1
  99. package/src/ir/types.ts +12 -2
  100. package/src/lexer/index.ts +3 -1
  101. package/src/lowering/index.ts +684 -24
  102. package/src/mc-test/runner.ts +3 -3
  103. package/src/mc-test/setup.ts +2 -2
  104. package/src/parser/index.ts +170 -19
  105. package/src/stdlib/README.md +178 -140
  106. package/src/stdlib/bossbar.mcrs +68 -0
  107. package/src/stdlib/{cooldown.rs → cooldown.mcrs} +1 -1
  108. package/src/stdlib/effects.mcrs +64 -0
  109. package/src/stdlib/interactions.mcrs +195 -0
  110. package/src/stdlib/inventory.mcrs +38 -0
  111. package/src/stdlib/mobs.mcrs +99 -0
  112. package/src/stdlib/particles.mcrs +52 -0
  113. package/src/stdlib/sets.mcrs +20 -0
  114. package/src/stdlib/spawn.mcrs +41 -0
  115. package/src/stdlib/tags.mcrs +951 -0
  116. package/src/stdlib/teams.mcrs +68 -0
  117. package/src/stdlib/timer.mcrs +72 -0
  118. package/src/stdlib/world.mcrs +92 -0
  119. package/src/typechecker/index.ts +404 -18
  120. package/src/examples/rpg.rs +0 -13
  121. package/src/stdlib/mobs.rs +0 -99
  122. package/src/stdlib/timer.rs +0 -51
  123. /package/src/examples/{arena.rs → arena.mcrs} +0 -0
  124. /package/src/examples/{pvp_arena.rs → pvp_arena.mcrs} +0 -0
  125. /package/src/examples/{quiz.rs → quiz.mcrs} +0 -0
  126. /package/src/examples/{stdlib_demo.rs → stdlib_demo.mcrs} +0 -0
  127. /package/src/examples/{world_manager.rs → world_manager.mcrs} +0 -0
  128. /package/src/stdlib/{combat.rs → combat.mcrs} +0 -0
  129. /package/src/stdlib/{math.rs → math.mcrs} +0 -0
  130. /package/src/stdlib/{player.rs → player.mcrs} +0 -0
  131. /package/src/stdlib/{strings.rs → strings.mcrs} +0 -0
  132. /package/src/templates/{combat.rs → combat.mcrs} +0 -0
  133. /package/src/templates/{economy.rs → economy.mcrs} +0 -0
  134. /package/src/templates/{mini-game-framework.rs → mini-game-framework.mcrs} +0 -0
  135. /package/src/templates/{quest.rs → quest.mcrs} +0 -0
  136. /package/src/test_programs/{zombie_game.rs → zombie_game.mcrs} +0 -0
@@ -1,156 +1,194 @@
1
- # RedScript Stdlib
1
+ # RedScript Standard Library
2
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:
3
+ Ready-to-use utility functions for common Minecraft operations.
5
4
 
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.
5
+ ## Usage
10
6
 
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:
7
+ ```mcrs
8
+ import "stdlib/effects.mcrs"
9
+ import "stdlib/world.mcrs"
33
10
 
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);
11
+ fn start() {
12
+ set_day();
13
+ buff_all(@a, 600); // 30 second buff
45
14
  }
46
15
  ```
47
16
 
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:
17
+ ## Modules
123
18
 
124
- ```rs
125
- if (cooldown_ready("dash") == 1) {
126
- cooldown_start("dash", 40);
127
- }
128
- cooldown_tick("dash");
19
+ ### math.mcrs
20
+ Basic math utilities.
21
+ - `abs(x)` — Absolute value
22
+ - `min(a, b)` — Minimum of two values
23
+ - `max(a, b)` — Maximum of two values
24
+ - `clamp(x, min, max)` — Clamp value to range
25
+ - `sign(x)` — Sign of number (-1, 0, 1)
26
+
27
+ ### effects.mcrs
28
+ Effect shortcuts.
29
+ - `speed(target, duration, level)`
30
+ - `jump(target, duration, level)`
31
+ - `regen(target, duration, level)`
32
+ - `resistance(target, duration, level)`
33
+ - `strength(target, duration, level)`
34
+ - `invisible(target, duration)`
35
+ - `night_vision(target, duration)`
36
+ - `slow_fall(target, duration)`
37
+ - `glow(target, duration)`
38
+ - `clear_effects(target)`
39
+ - `buff_all(target, duration)` — Speed + strength + regen + resistance
40
+
41
+ ### world.mcrs
42
+ World and game rule helpers.
43
+ - `set_day()`, `set_night()`, `set_noon()`, `set_midnight()`
44
+ - `weather_clear()`, `weather_rain()`, `weather_thunder()`
45
+ - `enable_keep_inventory()`, `disable_keep_inventory()`
46
+ - `disable_mob_griefing()`, `disable_fire_spread()`
47
+ - `set_peaceful()`, `set_easy()`, `set_normal()`, `set_hard()`
48
+ - `barrier_wall(x1,y1,z1,x2,y2,z2)`
49
+ - `clear_area(x1,y1,z1,x2,y2,z2)`
50
+ - `glass_box(x1,y1,z1,x2,y2,z2)`
51
+
52
+ ### inventory.mcrs
53
+ Inventory management.
54
+ - `clear_inventory(target)`
55
+ - `give_kit_warrior(target)`
56
+ - `give_kit_archer(target)`
57
+ - `give_kit_mage(target)`
58
+ - `remove_item(target, item)`
59
+
60
+ ### player.mcrs
61
+ Player state management.
62
+ - `heal(amount)`
63
+ - `damage(amount)`
64
+ - `is_op()` — Check if player has op tag
65
+
66
+ ### cooldown.mcrs
67
+ Cooldown system using scoreboards.
68
+ - `cooldown_start(target, ticks)`
69
+ - `cooldown_tick()`
70
+ - `is_on_cooldown(target)` → int
71
+
72
+ ### timer.mcrs
73
+ Timer utilities with an OOP API.
74
+ - `Timer::new(ticks)` → `Timer`
75
+ - `timer.start()`, `timer.pause()`, `timer.reset()`
76
+ - `timer.done()` → bool
77
+ - `timer.elapsed()` → int
78
+ - `timer.remaining()` → int
79
+ - `timer.tick()` — manual tick update; current runtime uses one shared timer slot
80
+
81
+ ### combat.mcrs
82
+ Combat helpers.
83
+ - `apply_damage(target, amount)`
84
+ - `knockback(target, strength)`
85
+
86
+ ### mobs.mcrs
87
+ Mob spawning utilities.
88
+ - `spawn_zombie(x, y, z)`
89
+ - `spawn_skeleton(x, y, z)`
90
+ - `spawn_creeper(x, y, z)`
91
+
92
+ ### sets.mcrs
93
+ Runtime set operations (NBT-based).
94
+ - `make_set()` → string
95
+ - `add_to_set(set, value)`
96
+ - `in_set(set, value)` → int
97
+ - `remove_from_set(set, value)`
98
+
99
+ ### strings.mcrs
100
+ String formatting helpers.
101
+ - `broadcast(msg)` — Announce to all players
102
+ - `whisper(target, msg)` — Private message
103
+
104
+ ### particles.mcrs
105
+ Particle effect shortcuts.
106
+ - `hearts(target)` — Heart particles above target
107
+ - `flames(x, y, z)` — Fire particles
108
+ - `smoke(x, y, z)` — Smoke effect
109
+ - `explosion_effect(x, y, z)` — Explosion particles
110
+ - `sparkles(target)` — Enchantment sparkles
111
+ - `angry(target)` — Angry villager particles
112
+ - `happy(target)` — Happy villager particles
113
+ - `portal_effect(x, y, z)` — Portal particles
114
+ - `totem_effect(target)` — Totem of undying particles
115
+ - `end_sparkles(target)` — End rod particles
116
+
117
+ ### spawn.mcrs
118
+ Teleport and spawn utilities.
119
+ - `teleport_to(target, x, y, z)` — TP to coordinates
120
+ - `teleport_to_entity(target, dest)` — TP to entity
121
+ - `gather_all(x, y, z)` — TP all players
122
+ - `launch_up(target, height)` — Launch player upward
123
+ - `goto_lobby(target)` — TP to lobby
124
+ - `goto_arena(target)` — TP to arena
125
+
126
+ ### teams.mcrs
127
+ Team management.
128
+ - `create_team(name, color)` — Create colored team
129
+ - `create_red_team()`, `create_blue_team()` — Quick team setup
130
+ - `create_green_team()`, `create_yellow_team()`
131
+ - `add_to_team(target, team)` — Add player to team
132
+ - `remove_from_teams(target)` — Remove from all teams
133
+ - `setup_two_teams()` — Quick 2-team setup
134
+ - `setup_four_teams()` — Quick 4-team setup
135
+ - `cleanup_teams()` — Remove all teams
136
+
137
+ ### bossbar.mcrs
138
+ Bossbar for timers and progress.
139
+ - `create_timer_bar(id, name, seconds)` — Timer bossbar
140
+ - `create_health_bar(id, name, max)` — Red health bar
141
+ - `create_progress_bar(id, name, max)` — Blue progress bar
142
+ - `update_bar(id, value)` — Update value
143
+ - `hide_bar(id)`, `show_bar(id)` — Visibility
144
+ - `remove_bar(id)` — Delete bossbar
145
+ - `update_bar_color(id, percent)` — Color by percentage
146
+
147
+ ### interactions.mcrs
148
+ Player input detection (right click, sneak, look direction).
149
+ - `interactions_init()` — Setup scoreboards (call on @load)
150
+ - `on_right_click()` — Detect carrot-on-stick right click
151
+ - `is_sneaking(target)` — Check if sneaking
152
+ - `on_sneak_start()` — Detect sneak start (first tick)
153
+ - `check_look_up()` — Tag players looking up
154
+ - `check_look_down()` — Tag players looking down
155
+ - `on_sneak_click()` — Detect sneak + right click combo
156
+ - `on_double_sneak()` — Detect double-tap sneak
157
+
158
+ **New selector filters:**
159
+ ```mcrs
160
+ // Rotation (pitch/yaw)
161
+ @a[x_rotation=-90..-45] // Looking up
162
+ @a[x_rotation=45..90] // Looking down
163
+ @a[y_rotation=0..90] // Facing east
164
+
165
+ // Position ranges
166
+ @a[x=-5..5, y=62..68, z=-5..5] // In specific area
129
167
  ```
130
168
 
131
- ## Incorporation Patterns
169
+ ### tags.mcrs
170
+ Minecraft Java Edition tag constants generated from the Minecraft Fandom tag list.
132
171
 
133
- ### Copy into your project
172
+ #### Coverage
173
+ - 171 `BLOCK_*` constants for Java block tags
174
+ - 14 `ENTITY_*` constants for Java entity type tags
175
+ - 99 `ITEM_*` constants for Java item tags
176
+ - 2 `FLUID_*` constants for Java fluid tags
177
+ - 27 `DAMAGE_*` constants for Java damage type tags
134
178
 
135
- This is the simplest path today. Paste the helper functions above your gameplay
136
- functions and compile one `.rs` file.
179
+ #### Naming
180
+ - Constants use `SCREAMING_SNAKE_CASE`
181
+ - Each constant is prefixed by category: `BLOCK_`, `ENTITY_`, `ITEM_`, `FLUID_`, `DAMAGE_`
182
+ - Each value is the full tag selector string, for example `#minecraft:mineable/axe`
137
183
 
138
- ### Compile separately
184
+ #### Usage
185
+ ```mcrs
186
+ import "stdlib/tags.mcrs"
139
187
 
140
- You can inspect or ship a stdlib datapack directly:
188
+ // Select skeleton variants
189
+ kill(@e[type=ENTITY_SKELETONS]);
141
190
 
142
- ```bash
143
- npx ts-node src/cli.ts compile src/stdlib/math.rs -o dist/stdlib-math
191
+ // Use block and item tags in your own helpers
192
+ const LOGS: string = BLOCK_LOGS;
193
+ const SWORDS: string = ITEM_SWORDS;
144
194
  ```
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,68 @@
1
+ // Bossbar helpers for progress bars and timers
2
+ // Usage: import "stdlib/bossbar.mcrs"
3
+
4
+ /// Create and show a timer bossbar
5
+ fn create_timer_bar(id: string, name: string, max_seconds: int) {
6
+ bossbar_add(id, name);
7
+ bossbar_set_max(id, max_seconds * 20);
8
+ bossbar_set_value(id, max_seconds * 20);
9
+ bossbar_set_color(id, "green");
10
+ bossbar_set_style(id, "progress");
11
+ bossbar_set_players(id, @a);
12
+ bossbar_set_visible(id, 1);
13
+ }
14
+
15
+ /// Create a health-style bossbar (red)
16
+ fn create_health_bar(id: string, name: string, max_val: int) {
17
+ bossbar_add(id, name);
18
+ bossbar_set_max(id, max_val);
19
+ bossbar_set_value(id, max_val);
20
+ bossbar_set_color(id, "red");
21
+ bossbar_set_style(id, "progress");
22
+ bossbar_set_players(id, @a);
23
+ bossbar_set_visible(id, 1);
24
+ }
25
+
26
+ /// Create a progress bossbar (blue)
27
+ fn create_progress_bar(id: string, name: string, max_val: int) {
28
+ bossbar_add(id, name);
29
+ bossbar_set_max(id, max_val);
30
+ bossbar_set_value(id, 0);
31
+ bossbar_set_color(id, "blue");
32
+ bossbar_set_style(id, "progress");
33
+ bossbar_set_players(id, @a);
34
+ bossbar_set_visible(id, 1);
35
+ }
36
+
37
+ /// Update bossbar value
38
+ fn update_bar(id: string, value: int) {
39
+ bossbar_set_value(id, value);
40
+ }
41
+
42
+ /// Hide bossbar
43
+ fn hide_bar(id: string) {
44
+ bossbar_set_visible(id, 0);
45
+ }
46
+
47
+ /// Show bossbar
48
+ fn show_bar(id: string) {
49
+ bossbar_set_visible(id, 1);
50
+ }
51
+
52
+ /// Remove bossbar
53
+ fn remove_bar(id: string) {
54
+ bossbar_remove(id);
55
+ }
56
+
57
+ /// Set bossbar color based on percentage
58
+ fn update_bar_color(id: string, percent: int) {
59
+ if (percent > 66) {
60
+ bossbar_set_color(id, "green");
61
+ } else {
62
+ if (percent > 33) {
63
+ bossbar_set_color(id, "yellow");
64
+ } else {
65
+ bossbar_set_color(id, "red");
66
+ }
67
+ }
68
+ }
@@ -1,6 +1,6 @@
1
1
  // Cooldown helpers.
2
2
  //
3
- // Like timer.rs, the `name` parameter is reserved for a future compiler/runtime
3
+ // Like timer.mcrs, the `name` parameter is reserved for a future compiler/runtime
4
4
  // that can route string literals through user-defined calls. Today this file
5
5
  // manages one cooldown slot on the `rs` objective.
6
6
 
@@ -0,0 +1,64 @@
1
+ // Effect helper functions
2
+
3
+ /// Give speed boost
4
+ fn speed(target: selector, duration: int, level: int) {
5
+ effect(target, "minecraft:speed", duration, level);
6
+ }
7
+
8
+ /// Give jump boost
9
+ fn jump(target: selector, duration: int, level: int) {
10
+ effect(target, "minecraft:jump_boost", duration, level);
11
+ }
12
+
13
+ /// Give regeneration
14
+ fn regen(target: selector, duration: int, level: int) {
15
+ effect(target, "minecraft:regeneration", duration, level);
16
+ }
17
+
18
+ /// Give resistance
19
+ fn resistance(target: selector, duration: int, level: int) {
20
+ effect(target, "minecraft:resistance", duration, level);
21
+ }
22
+
23
+ /// Give strength
24
+ fn strength(target: selector, duration: int, level: int) {
25
+ effect(target, "minecraft:strength", duration, level);
26
+ }
27
+
28
+ /// Give invisibility
29
+ fn invisible(target: selector, duration: int) {
30
+ effect(target, "minecraft:invisibility", duration, 0);
31
+ }
32
+
33
+ /// Give night vision
34
+ fn night_vision(target: selector, duration: int) {
35
+ effect(target, "minecraft:night_vision", duration, 0);
36
+ }
37
+
38
+ /// Give slow falling
39
+ fn slow_fall(target: selector, duration: int) {
40
+ effect(target, "minecraft:slow_falling", duration, 0);
41
+ }
42
+
43
+ /// Give glowing effect
44
+ fn glow(target: selector, duration: int) {
45
+ effect(target, "minecraft:glowing", duration, 0);
46
+ }
47
+
48
+ /// Clear all effects from target
49
+ fn clear_effects(target: selector) {
50
+ effect_clear(target);
51
+ }
52
+
53
+ /// Clear specific effect from target
54
+ fn clear_effect(target: selector, eff: string) {
55
+ effect_clear(target, eff);
56
+ }
57
+
58
+ /// Full buff package (speed, strength, regen)
59
+ fn buff_all(target: selector, duration: int) {
60
+ speed(target, duration, 1);
61
+ strength(target, duration, 1);
62
+ regen(target, duration, 1);
63
+ resistance(target, duration, 0);
64
+ }
@@ -0,0 +1,195 @@
1
+ // Player interaction detection helpers
2
+ // Usage: import "stdlib/interactions.mcrs"
3
+ //
4
+ // Common patterns for detecting player input:
5
+ // - Right click (carrot on stick)
6
+ // - Sneak/crouch
7
+ // - Look direction
8
+ // - Item in hand
9
+
10
+ // =============================================
11
+ // SETUP - Call once on @load
12
+ // =============================================
13
+
14
+ /// Initialize interaction scoreboards
15
+ fn interactions_init() {
16
+ // Right click detection (carrot on a stick)
17
+ scoreboard_add_objective("rs.click", "minecraft.used:minecraft.carrot_on_a_stick");
18
+
19
+ // Sneak time tracking
20
+ scoreboard_add_objective("rs.sneak", "minecraft.custom:minecraft.sneak_time");
21
+
22
+ // Attack detection (left click on entity)
23
+ scoreboard_add_objective("rs.attack", "minecraft.custom:minecraft.damage_dealt");
24
+ }
25
+
26
+ // =============================================
27
+ // RIGHT CLICK DETECTION
28
+ // =============================================
29
+ // Uses Carrot on a Stick item
30
+ // Give players: /give @p carrot_on_a_stick{CustomModelData:1234}
31
+
32
+ /// Check if player right-clicked (carrot on stick)
33
+ /// Call this in @tick, resets after detection
34
+ fn on_right_click(callback_fn: string) {
35
+ // Players with click score > 0 have clicked
36
+ foreach (p in @a) {
37
+ let clicks: int = scoreboard_get(p, "rs.click");
38
+ if (clicks > 0) {
39
+ // Reset counter
40
+ scoreboard_set(p, "rs.click", 0);
41
+ // Trigger callback by tag
42
+ tag_add(p, "rs.clicked");
43
+ }
44
+ }
45
+ }
46
+
47
+ /// Example: detect right click and do something
48
+ fn example_right_click() {
49
+ foreach (p in @a) {
50
+ let clicks: int = scoreboard_get(p, "rs.click");
51
+ if (clicks > 0) {
52
+ scoreboard_set(p, "rs.click", 0);
53
+ // Do your action here
54
+ say("Player right clicked!");
55
+ }
56
+ }
57
+ }
58
+
59
+ // =============================================
60
+ // SNEAK DETECTION
61
+ // =============================================
62
+
63
+ /// Check if player just started sneaking
64
+ /// Returns 1 if sneaking, 0 otherwise
65
+ fn is_sneaking(target: selector) -> int {
66
+ let sneak_time: int = scoreboard_get(target, "rs.sneak");
67
+ if (sneak_time > 0) {
68
+ return 1;
69
+ }
70
+ return 0;
71
+ }
72
+
73
+ /// Detect sneak start (first tick of sneaking)
74
+ fn on_sneak_start() {
75
+ foreach (p in @a) {
76
+ let sneak_time: int = scoreboard_get(p, "rs.sneak");
77
+ // Sneak time == 1 means just started
78
+ if (sneak_time == 1) {
79
+ tag_add(p, "rs.sneak_start");
80
+ } else {
81
+ tag_remove(p, "rs.sneak_start");
82
+ }
83
+ }
84
+ }
85
+
86
+ // =============================================
87
+ // LOOK DIRECTION
88
+ // =============================================
89
+ // Uses execute with rotation checks
90
+
91
+ /// Check if player is looking up (pitch < -45)
92
+ fn check_look_up() {
93
+ // Now supports p[filters] syntax sugar!
94
+ foreach (p in @a) {
95
+ execute if entity p[x_rotation=-90..-45] run {
96
+ tag_add(@s, "rs.look_up");
97
+ }
98
+ execute unless entity p[x_rotation=-90..-45] run {
99
+ tag_remove(@s, "rs.look_up");
100
+ }
101
+ }
102
+ }
103
+
104
+ /// Check if player is looking down (pitch > 45)
105
+ fn check_look_down() {
106
+ foreach (p in @a) {
107
+ execute if entity p[x_rotation=45..90] run {
108
+ tag_add(@s, "rs.look_down");
109
+ }
110
+ execute unless entity p[x_rotation=45..90] run {
111
+ tag_remove(@s, "rs.look_down");
112
+ }
113
+ }
114
+ }
115
+
116
+ /// Check if player is looking straight (pitch -45 to 45)
117
+ fn check_look_straight() {
118
+ foreach (p in @a) {
119
+ execute if entity p[x_rotation=-45..45] run {
120
+ tag_add(@s, "rs.look_straight");
121
+ }
122
+ execute unless entity p[x_rotation=-45..45] run {
123
+ tag_remove(@s, "rs.look_straight");
124
+ }
125
+ }
126
+ }
127
+
128
+ // =============================================
129
+ // ITEM IN HAND
130
+ // =============================================
131
+ // Use execute if data or predicates
132
+
133
+ /// Check if holding specific item (by tag)
134
+ /// Usage: check_holding_tag("my_wand") checks for tag rs.holding.my_wand
135
+ fn check_holding_item(item_id: string) {
136
+ // This requires predicate files in datapack
137
+ // Example predicate: data/ns/predicates/holding_diamond_sword.json
138
+ // { "condition": "minecraft:entity_properties",
139
+ // "entity": "this",
140
+ // "predicate": { "equipment": { "mainhand": { "items": ["minecraft:diamond_sword"] }}}}
141
+
142
+ // For now, use NBT check via execute
143
+ say("Use execute if data for item checks");
144
+ }
145
+
146
+ // =============================================
147
+ // COMBINED: SNEAK + RIGHT CLICK
148
+ // =============================================
149
+ // Common pattern: Sneak + Use for special ability
150
+
151
+ /// Detect sneak + right click combo
152
+ fn on_sneak_click() {
153
+ foreach (p in @a) {
154
+ let clicks: int = scoreboard_get(p, "rs.click");
155
+ let sneak: int = scoreboard_get(p, "rs.sneak");
156
+
157
+ if (clicks > 0) {
158
+ if (sneak > 0) {
159
+ // Sneak + Click!
160
+ scoreboard_set(p, "rs.click", 0);
161
+ tag_add(p, "rs.sneak_click");
162
+ } else {
163
+ // Normal click
164
+ scoreboard_set(p, "rs.click", 0);
165
+ tag_add(p, "rs.clicked");
166
+ }
167
+ }
168
+ }
169
+ }
170
+
171
+ // =============================================
172
+ // DOUBLE TAP SNEAK
173
+ // =============================================
174
+ // Detect double-tap sneak (toggle fly, etc)
175
+
176
+ let last_sneak_tick: int = 0;
177
+ const DOUBLE_TAP_WINDOW: int = 10; // 0.5 second
178
+
179
+ fn on_double_sneak() {
180
+ foreach (p in @a) {
181
+ let sneak: int = scoreboard_get(p, "rs.sneak");
182
+ let last: int = scoreboard_get(p, "rs.last_sneak");
183
+ let now: int = scoreboard_get(p, "rs.tick");
184
+
185
+ // Just started sneaking
186
+ if (sneak == 1) {
187
+ let diff: int = now - last;
188
+ if (diff < DOUBLE_TAP_WINDOW) {
189
+ // Double sneak detected!
190
+ tag_add(p, "rs.double_sneak");
191
+ }
192
+ scoreboard_set(p, "rs.last_sneak", now);
193
+ }
194
+ }
195
+ }