redscript-mc 1.0.0 → 1.1.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.yml +72 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +57 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +17 -25
- package/CHANGELOG.md +58 -0
- package/CONTRIBUTING.md +140 -0
- package/README.md +28 -19
- package/README.zh.md +28 -19
- package/dist/__tests__/cli.test.js +10 -10
- package/dist/__tests__/codegen.test.js +1 -1
- package/dist/__tests__/diagnostics.test.js +5 -5
- package/dist/__tests__/e2e.test.js +146 -5
- package/dist/__tests__/formatter.test.d.ts +1 -0
- package/dist/__tests__/formatter.test.js +40 -0
- package/dist/__tests__/lowering.test.js +36 -3
- package/dist/__tests__/mc-integration.test.js +255 -10
- package/dist/__tests__/mc-syntax.test.js +3 -3
- package/dist/__tests__/nbt.test.js +2 -2
- package/dist/__tests__/optimizer-advanced.test.js +3 -3
- package/dist/__tests__/runtime.test.js +1 -1
- package/dist/ast/types.d.ts +21 -3
- package/dist/cli.js +25 -7
- package/dist/codegen/mcfunction/index.d.ts +1 -1
- package/dist/codegen/mcfunction/index.js +8 -2
- package/dist/codegen/structure/index.js +7 -1
- package/dist/formatter/index.d.ts +1 -0
- package/dist/formatter/index.js +26 -0
- package/dist/ir/builder.d.ts +2 -1
- package/dist/ir/types.d.ts +7 -2
- package/dist/ir/types.js +1 -1
- package/dist/lowering/index.d.ts +2 -0
- package/dist/lowering/index.js +183 -8
- package/dist/mc-test/runner.d.ts +2 -2
- package/dist/mc-test/runner.js +3 -3
- package/dist/mc-test/setup.js +2 -2
- package/dist/parser/index.d.ts +2 -0
- package/dist/parser/index.js +75 -7
- package/docs/COMPILATION_STATS.md +24 -24
- package/docs/IMPLEMENTATION_GUIDE.md +1 -1
- package/docs/STRUCTURE_TARGET.md +1 -1
- package/editors/vscode/.vscodeignore +1 -0
- package/editors/vscode/icons/mcrs.svg +7 -0
- package/editors/vscode/icons/redscript-icons.json +10 -0
- package/editors/vscode/out/extension.js +152 -9
- package/editors/vscode/package.json +10 -3
- package/editors/vscode/src/hover.ts +55 -2
- package/editors/vscode/src/symbols.ts +42 -0
- package/package.json +1 -1
- package/src/__tests__/cli.test.ts +10 -10
- package/src/__tests__/codegen.test.ts +1 -1
- package/src/__tests__/diagnostics.test.ts +5 -5
- package/src/__tests__/e2e.test.ts +134 -5
- package/src/__tests__/lowering.test.ts +48 -3
- package/src/__tests__/mc-integration.test.ts +285 -10
- package/src/__tests__/mc-syntax.test.ts +3 -3
- package/src/__tests__/nbt.test.ts +2 -2
- package/src/__tests__/optimizer-advanced.test.ts +3 -3
- package/src/__tests__/runtime.test.ts +1 -1
- package/src/ast/types.ts +20 -3
- package/src/cli.ts +10 -10
- package/src/codegen/mcfunction/index.ts +9 -2
- package/src/codegen/structure/index.ts +8 -1
- package/src/examples/capture_the_flag.mcrs +208 -0
- package/src/examples/{counter.rs → counter.mcrs} +1 -1
- package/src/examples/hunger_games.mcrs +301 -0
- package/src/examples/new_features_demo.mcrs +193 -0
- package/src/examples/parkour_race.mcrs +233 -0
- package/src/examples/rpg.mcrs +13 -0
- package/src/examples/{shop.rs → shop.mcrs} +1 -1
- package/src/examples/{showcase_game.rs → showcase_game.mcrs} +3 -3
- package/src/examples/{turret.rs → turret.mcrs} +1 -1
- package/src/examples/zombie_survival.mcrs +314 -0
- package/src/ir/builder.ts +3 -1
- package/src/ir/types.ts +8 -2
- package/src/lowering/index.ts +156 -8
- package/src/mc-test/runner.ts +3 -3
- package/src/mc-test/setup.ts +2 -2
- package/src/parser/index.ts +81 -8
- package/src/stdlib/README.md +155 -147
- package/src/stdlib/bossbar.mcrs +68 -0
- package/src/stdlib/{cooldown.rs → cooldown.mcrs} +1 -1
- package/src/stdlib/effects.mcrs +64 -0
- package/src/stdlib/interactions.mcrs +195 -0
- package/src/stdlib/inventory.mcrs +38 -0
- package/src/stdlib/mobs.mcrs +99 -0
- package/src/stdlib/particles.mcrs +52 -0
- package/src/stdlib/sets.mcrs +20 -0
- package/src/stdlib/spawn.mcrs +41 -0
- package/src/stdlib/teams.mcrs +68 -0
- package/src/stdlib/world.mcrs +92 -0
- package/src/examples/rpg.rs +0 -13
- package/src/stdlib/mobs.rs +0 -99
- /package/src/examples/{arena.rs → arena.mcrs} +0 -0
- /package/src/examples/{pvp_arena.rs → pvp_arena.mcrs} +0 -0
- /package/src/examples/{quiz.rs → quiz.mcrs} +0 -0
- /package/src/examples/{stdlib_demo.rs → stdlib_demo.mcrs} +0 -0
- /package/src/examples/{world_manager.rs → world_manager.mcrs} +0 -0
- /package/src/stdlib/{combat.rs → combat.mcrs} +0 -0
- /package/src/stdlib/{math.rs → math.mcrs} +0 -0
- /package/src/stdlib/{player.rs → player.mcrs} +0 -0
- /package/src/stdlib/{strings.rs → strings.mcrs} +0 -0
- /package/src/stdlib/{timer.rs → timer.mcrs} +0 -0
- /package/src/templates/{combat.rs → combat.mcrs} +0 -0
- /package/src/templates/{economy.rs → economy.mcrs} +0 -0
- /package/src/templates/{mini-game-framework.rs → mini-game-framework.mcrs} +0 -0
- /package/src/templates/{quest.rs → quest.mcrs} +0 -0
- /package/src/test_programs/{zombie_game.rs → zombie_game.mcrs} +0 -0
package/src/stdlib/README.md
CHANGED
|
@@ -1,156 +1,164 @@
|
|
|
1
|
-
# RedScript
|
|
1
|
+
# RedScript Standard Library
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
no import system yet, so stdlib usage is intentionally simple:
|
|
3
|
+
Ready-to-use utility functions for common Minecraft operations.
|
|
5
4
|
|
|
6
|
-
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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:
|
|
7
|
+
```mcrs
|
|
8
|
+
import "stdlib/effects.mcrs"
|
|
9
|
+
import "stdlib/world.mcrs"
|
|
114
10
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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);
|
|
11
|
+
fn start() {
|
|
12
|
+
set_day();
|
|
13
|
+
buff_all(@a, 600); // 30 second buff
|
|
127
14
|
}
|
|
128
|
-
cooldown_tick("dash");
|
|
129
15
|
```
|
|
130
16
|
|
|
131
|
-
##
|
|
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:
|
|
17
|
+
## Modules
|
|
150
18
|
|
|
151
|
-
|
|
152
|
-
|
|
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.
|
|
74
|
+
- `timer_start(name, ticks)`
|
|
75
|
+
- `timer_tick()`
|
|
76
|
+
- `timer_done(name)` → int
|
|
77
|
+
|
|
78
|
+
### combat.mcrs
|
|
79
|
+
Combat helpers.
|
|
80
|
+
- `apply_damage(target, amount)`
|
|
81
|
+
- `knockback(target, strength)`
|
|
82
|
+
|
|
83
|
+
### mobs.mcrs
|
|
84
|
+
Mob spawning utilities.
|
|
85
|
+
- `spawn_zombie(x, y, z)`
|
|
86
|
+
- `spawn_skeleton(x, y, z)`
|
|
87
|
+
- `spawn_creeper(x, y, z)`
|
|
88
|
+
|
|
89
|
+
### sets.mcrs
|
|
90
|
+
Runtime set operations (NBT-based).
|
|
91
|
+
- `make_set()` → string
|
|
92
|
+
- `add_to_set(set, value)`
|
|
93
|
+
- `in_set(set, value)` → int
|
|
94
|
+
- `remove_from_set(set, value)`
|
|
95
|
+
|
|
96
|
+
### strings.mcrs
|
|
97
|
+
String formatting helpers.
|
|
98
|
+
- `broadcast(msg)` — Announce to all players
|
|
99
|
+
- `whisper(target, msg)` — Private message
|
|
100
|
+
|
|
101
|
+
### particles.mcrs
|
|
102
|
+
Particle effect shortcuts.
|
|
103
|
+
- `hearts(target)` — Heart particles above target
|
|
104
|
+
- `flames(x, y, z)` — Fire particles
|
|
105
|
+
- `smoke(x, y, z)` — Smoke effect
|
|
106
|
+
- `explosion_effect(x, y, z)` — Explosion particles
|
|
107
|
+
- `sparkles(target)` — Enchantment sparkles
|
|
108
|
+
- `angry(target)` — Angry villager particles
|
|
109
|
+
- `happy(target)` — Happy villager particles
|
|
110
|
+
- `portal_effect(x, y, z)` — Portal particles
|
|
111
|
+
- `totem_effect(target)` — Totem of undying particles
|
|
112
|
+
- `end_sparkles(target)` — End rod particles
|
|
113
|
+
|
|
114
|
+
### spawn.mcrs
|
|
115
|
+
Teleport and spawn utilities.
|
|
116
|
+
- `teleport_to(target, x, y, z)` — TP to coordinates
|
|
117
|
+
- `teleport_to_entity(target, dest)` — TP to entity
|
|
118
|
+
- `gather_all(x, y, z)` — TP all players
|
|
119
|
+
- `launch_up(target, height)` — Launch player upward
|
|
120
|
+
- `goto_lobby(target)` — TP to lobby
|
|
121
|
+
- `goto_arena(target)` — TP to arena
|
|
122
|
+
|
|
123
|
+
### teams.mcrs
|
|
124
|
+
Team management.
|
|
125
|
+
- `create_team(name, color)` — Create colored team
|
|
126
|
+
- `create_red_team()`, `create_blue_team()` — Quick team setup
|
|
127
|
+
- `create_green_team()`, `create_yellow_team()`
|
|
128
|
+
- `add_to_team(target, team)` — Add player to team
|
|
129
|
+
- `remove_from_teams(target)` — Remove from all teams
|
|
130
|
+
- `setup_two_teams()` — Quick 2-team setup
|
|
131
|
+
- `setup_four_teams()` — Quick 4-team setup
|
|
132
|
+
- `cleanup_teams()` — Remove all teams
|
|
133
|
+
|
|
134
|
+
### bossbar.mcrs
|
|
135
|
+
Bossbar for timers and progress.
|
|
136
|
+
- `create_timer_bar(id, name, seconds)` — Timer bossbar
|
|
137
|
+
- `create_health_bar(id, name, max)` — Red health bar
|
|
138
|
+
- `create_progress_bar(id, name, max)` — Blue progress bar
|
|
139
|
+
- `update_bar(id, value)` — Update value
|
|
140
|
+
- `hide_bar(id)`, `show_bar(id)` — Visibility
|
|
141
|
+
- `remove_bar(id)` — Delete bossbar
|
|
142
|
+
- `update_bar_color(id, percent)` — Color by percentage
|
|
143
|
+
|
|
144
|
+
### interactions.mcrs
|
|
145
|
+
Player input detection (right click, sneak, look direction).
|
|
146
|
+
- `interactions_init()` — Setup scoreboards (call on @load)
|
|
147
|
+
- `on_right_click()` — Detect carrot-on-stick right click
|
|
148
|
+
- `is_sneaking(target)` — Check if sneaking
|
|
149
|
+
- `on_sneak_start()` — Detect sneak start (first tick)
|
|
150
|
+
- `check_look_up()` — Tag players looking up
|
|
151
|
+
- `check_look_down()` — Tag players looking down
|
|
152
|
+
- `on_sneak_click()` — Detect sneak + right click combo
|
|
153
|
+
- `on_double_sneak()` — Detect double-tap sneak
|
|
154
|
+
|
|
155
|
+
**New selector filters:**
|
|
156
|
+
```mcrs
|
|
157
|
+
// Rotation (pitch/yaw)
|
|
158
|
+
@a[x_rotation=-90..-45] // Looking up
|
|
159
|
+
@a[x_rotation=45..90] // Looking down
|
|
160
|
+
@a[y_rotation=0..90] // Facing east
|
|
161
|
+
|
|
162
|
+
// Position ranges
|
|
163
|
+
@a[x=-5..5, y=62..68, z=-5..5] // In specific area
|
|
153
164
|
```
|
|
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.
|
|
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
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// Inventory management helpers
|
|
2
|
+
|
|
3
|
+
/// Clear all items from a player's inventory
|
|
4
|
+
fn clear_inventory(target: selector) {
|
|
5
|
+
clear(target);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/// Give a kit of items to a player
|
|
9
|
+
fn give_kit_warrior(target: selector) {
|
|
10
|
+
give(target, "minecraft:iron_sword", 1);
|
|
11
|
+
give(target, "minecraft:iron_chestplate", 1);
|
|
12
|
+
give(target, "minecraft:iron_leggings", 1);
|
|
13
|
+
give(target, "minecraft:iron_boots", 1);
|
|
14
|
+
give(target, "minecraft:shield", 1);
|
|
15
|
+
give(target, "minecraft:cooked_beef", 16);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
fn give_kit_archer(target: selector) {
|
|
19
|
+
give(target, "minecraft:bow", 1);
|
|
20
|
+
give(target, "minecraft:arrow", 64);
|
|
21
|
+
give(target, "minecraft:leather_chestplate", 1);
|
|
22
|
+
give(target, "minecraft:leather_leggings", 1);
|
|
23
|
+
give(target, "minecraft:leather_boots", 1);
|
|
24
|
+
give(target, "minecraft:cooked_beef", 16);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fn give_kit_mage(target: selector) {
|
|
28
|
+
give(target, "minecraft:wooden_sword", 1);
|
|
29
|
+
give(target, "minecraft:golden_apple", 8);
|
|
30
|
+
give(target, "minecraft:ender_pearl", 16);
|
|
31
|
+
give(target, "minecraft:splash_potion{Potion:\"minecraft:harming\"}", 8);
|
|
32
|
+
give(target, "minecraft:cooked_beef", 16);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// Remove a specific item from player
|
|
36
|
+
fn remove_item(target: selector, item: string) {
|
|
37
|
+
clear(target, item);
|
|
38
|
+
}
|