redscript-mc 1.2.21 → 1.2.24

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 (126) hide show
  1. package/.github/workflows/publish-extension-on-ci.yml +99 -0
  2. package/dist/__tests__/entity-types.test.d.ts +1 -0
  3. package/dist/__tests__/entity-types.test.js +203 -0
  4. package/dist/__tests__/var-allocator.test.d.ts +1 -0
  5. package/dist/__tests__/var-allocator.test.js +69 -0
  6. package/dist/ast/types.d.ts +2 -1
  7. package/dist/cli.js +17 -6
  8. package/dist/codegen/mcfunction/index.d.ts +2 -0
  9. package/dist/codegen/mcfunction/index.js +47 -43
  10. package/dist/codegen/structure/index.d.ts +4 -1
  11. package/dist/codegen/structure/index.js +8 -12
  12. package/dist/codegen/var-allocator.d.ts +28 -0
  13. package/dist/codegen/var-allocator.js +74 -0
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.js +8 -6
  16. package/dist/lowering/index.d.ts +2 -0
  17. package/dist/lowering/index.js +62 -3
  18. package/dist/parser/index.js +22 -1
  19. package/dist/typechecker/index.js +30 -0
  20. package/dist/types/entity-hierarchy.d.ts +29 -0
  21. package/dist/types/entity-hierarchy.js +107 -0
  22. package/editors/vscode/package-lock.json +6 -4
  23. package/editors/vscode/package.json +3 -3
  24. package/package.json +1 -1
  25. package/src/__tests__/entity-types.test.ts +236 -0
  26. package/src/__tests__/var-allocator.test.ts +75 -0
  27. package/src/ast/types.ts +8 -4
  28. package/src/cli.ts +20 -6
  29. package/src/codegen/mcfunction/index.ts +55 -48
  30. package/src/codegen/structure/index.ts +9 -14
  31. package/src/codegen/var-allocator.ts +71 -0
  32. package/src/examples/capture_the_flag.mcrs +34 -34
  33. package/src/examples/hunger_games.mcrs +59 -59
  34. package/src/examples/new_features_demo.mcrs +32 -32
  35. package/src/examples/parkour_race.mcrs +58 -58
  36. package/src/index.ts +10 -6
  37. package/src/lowering/index.ts +73 -8
  38. package/src/parser/index.ts +20 -1
  39. package/src/typechecker/index.ts +30 -0
  40. package/src/types/entity-hierarchy.ts +120 -0
  41. package/dist/data/arena/function/__load.mcfunction +0 -6
  42. package/dist/data/arena/function/__tick.mcfunction +0 -2
  43. package/dist/data/arena/function/announce_leaders/else_1.mcfunction +0 -3
  44. package/dist/data/arena/function/announce_leaders/foreach_0/merge_2.mcfunction +0 -1
  45. package/dist/data/arena/function/announce_leaders/foreach_0/then_0.mcfunction +0 -3
  46. package/dist/data/arena/function/announce_leaders/foreach_0.mcfunction +0 -7
  47. package/dist/data/arena/function/announce_leaders/foreach_1/merge_2.mcfunction +0 -1
  48. package/dist/data/arena/function/announce_leaders/foreach_1/then_0.mcfunction +0 -4
  49. package/dist/data/arena/function/announce_leaders/foreach_1.mcfunction +0 -6
  50. package/dist/data/arena/function/announce_leaders/merge_2.mcfunction +0 -1
  51. package/dist/data/arena/function/announce_leaders/then_0.mcfunction +0 -4
  52. package/dist/data/arena/function/announce_leaders.mcfunction +0 -6
  53. package/dist/data/arena/function/arena_tick/merge_2.mcfunction +0 -1
  54. package/dist/data/arena/function/arena_tick/then_0.mcfunction +0 -4
  55. package/dist/data/arena/function/arena_tick.mcfunction +0 -11
  56. package/dist/data/counter/function/__load.mcfunction +0 -5
  57. package/dist/data/counter/function/__tick.mcfunction +0 -2
  58. package/dist/data/counter/function/counter_tick/merge_2.mcfunction +0 -1
  59. package/dist/data/counter/function/counter_tick/then_0.mcfunction +0 -3
  60. package/dist/data/counter/function/counter_tick.mcfunction +0 -11
  61. package/dist/data/minecraft/tags/function/load.json +0 -5
  62. package/dist/data/minecraft/tags/function/tick.json +0 -5
  63. package/dist/data/quiz/function/__load.mcfunction +0 -16
  64. package/dist/data/quiz/function/__tick.mcfunction +0 -6
  65. package/dist/data/quiz/function/__trigger_quiz_a_dispatch.mcfunction +0 -4
  66. package/dist/data/quiz/function/__trigger_quiz_b_dispatch.mcfunction +0 -4
  67. package/dist/data/quiz/function/__trigger_quiz_c_dispatch.mcfunction +0 -4
  68. package/dist/data/quiz/function/__trigger_quiz_start_dispatch.mcfunction +0 -4
  69. package/dist/data/quiz/function/answer_a.mcfunction +0 -4
  70. package/dist/data/quiz/function/answer_b.mcfunction +0 -4
  71. package/dist/data/quiz/function/answer_c.mcfunction +0 -4
  72. package/dist/data/quiz/function/ask_question/else_1.mcfunction +0 -5
  73. package/dist/data/quiz/function/ask_question/else_4.mcfunction +0 -5
  74. package/dist/data/quiz/function/ask_question/else_7.mcfunction +0 -4
  75. package/dist/data/quiz/function/ask_question/merge_2.mcfunction +0 -1
  76. package/dist/data/quiz/function/ask_question/merge_5.mcfunction +0 -2
  77. package/dist/data/quiz/function/ask_question/merge_8.mcfunction +0 -2
  78. package/dist/data/quiz/function/ask_question/then_0.mcfunction +0 -4
  79. package/dist/data/quiz/function/ask_question/then_3.mcfunction +0 -4
  80. package/dist/data/quiz/function/ask_question/then_6.mcfunction +0 -4
  81. package/dist/data/quiz/function/ask_question.mcfunction +0 -7
  82. package/dist/data/quiz/function/finish_quiz.mcfunction +0 -6
  83. package/dist/data/quiz/function/handle_answer/else_1.mcfunction +0 -5
  84. package/dist/data/quiz/function/handle_answer/else_10.mcfunction +0 -3
  85. package/dist/data/quiz/function/handle_answer/else_16.mcfunction +0 -3
  86. package/dist/data/quiz/function/handle_answer/else_4.mcfunction +0 -3
  87. package/dist/data/quiz/function/handle_answer/else_7.mcfunction +0 -5
  88. package/dist/data/quiz/function/handle_answer/merge_11.mcfunction +0 -2
  89. package/dist/data/quiz/function/handle_answer/merge_14.mcfunction +0 -2
  90. package/dist/data/quiz/function/handle_answer/merge_17.mcfunction +0 -2
  91. package/dist/data/quiz/function/handle_answer/merge_2.mcfunction +0 -8
  92. package/dist/data/quiz/function/handle_answer/merge_5.mcfunction +0 -2
  93. package/dist/data/quiz/function/handle_answer/merge_8.mcfunction +0 -2
  94. package/dist/data/quiz/function/handle_answer/then_0.mcfunction +0 -5
  95. package/dist/data/quiz/function/handle_answer/then_12.mcfunction +0 -5
  96. package/dist/data/quiz/function/handle_answer/then_15.mcfunction +0 -6
  97. package/dist/data/quiz/function/handle_answer/then_3.mcfunction +0 -6
  98. package/dist/data/quiz/function/handle_answer/then_6.mcfunction +0 -5
  99. package/dist/data/quiz/function/handle_answer/then_9.mcfunction +0 -6
  100. package/dist/data/quiz/function/handle_answer.mcfunction +0 -11
  101. package/dist/data/quiz/function/start_quiz.mcfunction +0 -5
  102. package/dist/data/shop/function/__load.mcfunction +0 -7
  103. package/dist/data/shop/function/__tick.mcfunction +0 -3
  104. package/dist/data/shop/function/__trigger_shop_buy_dispatch.mcfunction +0 -4
  105. package/dist/data/shop/function/complete_purchase/else_1.mcfunction +0 -5
  106. package/dist/data/shop/function/complete_purchase/else_4.mcfunction +0 -5
  107. package/dist/data/shop/function/complete_purchase/else_7.mcfunction +0 -3
  108. package/dist/data/shop/function/complete_purchase/merge_2.mcfunction +0 -2
  109. package/dist/data/shop/function/complete_purchase/merge_5.mcfunction +0 -2
  110. package/dist/data/shop/function/complete_purchase/merge_8.mcfunction +0 -2
  111. package/dist/data/shop/function/complete_purchase/then_0.mcfunction +0 -4
  112. package/dist/data/shop/function/complete_purchase/then_3.mcfunction +0 -4
  113. package/dist/data/shop/function/complete_purchase/then_6.mcfunction +0 -4
  114. package/dist/data/shop/function/complete_purchase.mcfunction +0 -7
  115. package/dist/data/shop/function/handle_shop_trigger.mcfunction +0 -3
  116. package/dist/data/turret/function/__load.mcfunction +0 -5
  117. package/dist/data/turret/function/__tick.mcfunction +0 -4
  118. package/dist/data/turret/function/__trigger_deploy_turret_dispatch.mcfunction +0 -4
  119. package/dist/data/turret/function/deploy_turret.mcfunction +0 -8
  120. package/dist/data/turret/function/turret_tick/at_1.mcfunction +0 -2
  121. package/dist/data/turret/function/turret_tick/foreach_0.mcfunction +0 -2
  122. package/dist/data/turret/function/turret_tick/foreach_2.mcfunction +0 -2
  123. package/dist/data/turret/function/turret_tick/tick_body.mcfunction +0 -3
  124. package/dist/data/turret/function/turret_tick/tick_skip.mcfunction +0 -1
  125. package/dist/data/turret/function/turret_tick.mcfunction +0 -5
  126. package/dist/pack.mcmeta +0 -6
@@ -1,7 +1,7 @@
1
1
  // ============================================
2
2
  // Capture the Flag Mini-Game
3
3
  // ============================================
4
- // 场景:两队对抗,抢夺对方旗帜带回己方基地得分
4
+ // Scenario: Two teams compete, capture the enemy flag and return it to your base to score
5
5
  // Scenario: Two teams compete to capture enemy flag
6
6
  // ============================================
7
7
 
@@ -11,7 +11,7 @@ import "../stdlib/world.mcrs"
11
11
  import "../stdlib/inventory.mcrs"
12
12
  import "../stdlib/particles.mcrs"
13
13
 
14
- // ===== 配置 =====
14
+ // ===== Configuration =====
15
15
  const RED_BASE_X: int = -50;
16
16
  const RED_BASE_Z: int = 0;
17
17
  const BLUE_BASE_X: int = 50;
@@ -19,7 +19,7 @@ const BLUE_BASE_Z: int = 0;
19
19
  const BASE_Y: int = 64;
20
20
  const WIN_SCORE: int = 3;
21
21
 
22
- // ===== 游戏状态 =====
22
+ // ===== Game State =====
23
23
  struct GameState {
24
24
  running: int,
25
25
  red_score: int,
@@ -36,54 +36,54 @@ let game: GameState = {
36
36
  blue_flag_taken: 0
37
37
  };
38
38
 
39
- // ===== 初始化 =====
39
+ // ===== Initialization =====
40
40
  @load
41
41
  fn init() {
42
- // 创建记分板
42
+ // Create scoreboards
43
43
  scoreboard_add_objective("ctf_team", "dummy");
44
44
  scoreboard_add_objective("ctf_flag", "dummy");
45
45
 
46
- // 创建队伍
46
+ // Create teams
47
47
  setup_two_teams();
48
48
 
49
- // 世界设置
49
+ // World settings
50
50
  set_day();
51
51
  weather_clear();
52
52
  enable_keep_inventory();
53
53
 
54
- announce("§e[CTF] §f夺旗战已加载!使用 /trigger start 开始游戏");
54
+ announce("§e[CTF] §fCapture the Flag loaded! Use /trigger start to begin");
55
55
  }
56
56
 
57
- // ===== 开始游戏 =====
57
+ // ===== Start Game =====
58
58
  fn start_game() {
59
59
  game.running = 1;
60
60
  game.red_score = 0;
61
61
  game.blue_score = 0;
62
62
 
63
- // 随机分配队伍
63
+ // Randomly assign teams
64
64
  assign_teams();
65
65
 
66
- // 传送到各自基地
66
+ // Teleport to respective bases
67
67
  tp(@a[team=red], RED_BASE_X, BASE_Y, RED_BASE_Z);
68
68
  tp(@a[team=blue], BLUE_BASE_X, BASE_Y, BLUE_BASE_Z);
69
69
 
70
- // 给装备
70
+ // Give equipment
71
71
  foreach (p in @a) {
72
72
  clear_inventory(p);
73
73
  give_kit_warrior(p);
74
74
  }
75
75
 
76
- // 放置旗帜(盔甲架)
76
+ // Place flags (banners)
77
77
  place_flags();
78
78
 
79
- announce("§e[CTF] §a游戏开始!抢夺敌方旗帜!");
80
- title(@a, "§6夺旗战开始!");
79
+ announce("§e[CTF] §aGame started! Capture the enemy flag!");
80
+ title(@a, "§6Capture the Flag - Start!");
81
81
  }
82
82
 
83
83
  fn place_flags() {
84
- // 红方旗帜(红色旗帜方块)
84
+ // Red team flag (red banner block)
85
85
  setblock(RED_BASE_X, BASE_Y + 1, RED_BASE_Z, "minecraft:red_banner");
86
- // 蓝方旗帜
86
+ // Blue team flag
87
87
  setblock(BLUE_BASE_X, BASE_Y + 1, BLUE_BASE_Z, "minecraft:blue_banner");
88
88
 
89
89
  game.red_flag_taken = 0;
@@ -104,7 +104,7 @@ fn assign_teams() {
104
104
  }
105
105
  }
106
106
 
107
- // ===== tick 检查 =====
107
+ // ===== Tick Check =====
108
108
  @tick
109
109
  fn game_tick() {
110
110
  if (game.running == 1) {
@@ -115,22 +115,22 @@ fn game_tick() {
115
115
  }
116
116
 
117
117
  fn check_flag_pickup() {
118
- // 检查蓝队玩家是否靠近红旗
118
+ // Check if blue team players are near the red flag
119
119
  foreach (p in @a[team=blue]) {
120
- // 如果在红方基地附近且旗帜未被拿走
120
+ // If near red team base and flag has not been taken
121
121
  let dist: int = distance_to(p, RED_BASE_X, BASE_Y, RED_BASE_Z);
122
122
  if (dist < 3) {
123
123
  if (game.red_flag_taken == 0) {
124
124
  game.red_flag_taken = 1;
125
125
  tag_add(p, "has_flag");
126
126
  setblock(RED_BASE_X, BASE_Y + 1, RED_BASE_Z, "minecraft:air");
127
- announce("§e[CTF] §9蓝队 §f拿到了 §c红方旗帜§f");
127
+ announce("§e[CTF] §9Blue Team §fhas taken the §cRed Flag§f!");
128
128
  glow(p, 9999);
129
129
  }
130
130
  }
131
131
  }
132
132
 
133
- // 检查红队玩家是否靠近蓝旗
133
+ // Check if red team players are near the blue flag
134
134
  foreach (p in @a[team=red]) {
135
135
  let dist: int = distance_to(p, BLUE_BASE_X, BASE_Y, BLUE_BASE_Z);
136
136
  if (dist < 3) {
@@ -138,7 +138,7 @@ fn check_flag_pickup() {
138
138
  game.blue_flag_taken = 1;
139
139
  tag_add(p, "has_flag");
140
140
  setblock(BLUE_BASE_X, BASE_Y + 1, BLUE_BASE_Z, "minecraft:air");
141
- announce("§e[CTF] §c红队 §f拿到了 §9蓝方旗帜§f");
141
+ announce("§e[CTF] §cRed Team §fhas taken the §9Blue Flag§f!");
142
142
  glow(p, 9999);
143
143
  }
144
144
  }
@@ -146,12 +146,12 @@ fn check_flag_pickup() {
146
146
  }
147
147
 
148
148
  fn check_flag_capture() {
149
- // 蓝队带红旗回蓝方基地
149
+ // Blue team carries red flag back to blue base
150
150
  foreach (p in @a[team=blue, tag=has_flag]) {
151
151
  let dist: int = distance_to(p, BLUE_BASE_X, BASE_Y, BLUE_BASE_Z);
152
152
  if (dist < 5) {
153
153
  game.blue_score = game.blue_score + 1;
154
- announce("§e[CTF] §9蓝队 §a得分!§f (" + game.blue_score + "/" + WIN_SCORE + ")");
154
+ announce("§e[CTF] §9Blue Team §ascores! §f(" + game.blue_score + "/" + WIN_SCORE + ")");
155
155
  tag_remove(p, "has_flag");
156
156
  effect_clear(p, "minecraft:glowing");
157
157
  place_flags();
@@ -159,12 +159,12 @@ fn check_flag_capture() {
159
159
  }
160
160
  }
161
161
 
162
- // 红队带蓝旗回红方基地
162
+ // Red team carries blue flag back to red base
163
163
  foreach (p in @a[team=red, tag=has_flag]) {
164
164
  let dist: int = distance_to(p, RED_BASE_X, BASE_Y, RED_BASE_Z);
165
165
  if (dist < 5) {
166
166
  game.red_score = game.red_score + 1;
167
- announce("§e[CTF] §c红队 §a得分!§f (" + game.red_score + "/" + WIN_SCORE + ")");
167
+ announce("§e[CTF] §cRed Team §ascores! §f(" + game.red_score + "/" + WIN_SCORE + ")");
168
168
  tag_remove(p, "has_flag");
169
169
  effect_clear(p, "minecraft:glowing");
170
170
  place_flags();
@@ -186,23 +186,23 @@ fn end_game(winner: string) {
186
186
  game.running = 0;
187
187
 
188
188
  if (winner == "red") {
189
- title(@a, "§c红队获胜!");
190
- announce("§e[CTF] §c红队 §6赢得了比赛!");
189
+ title(@a, "§cRed Team Wins!");
190
+ announce("§e[CTF] §cRed Team §6wins the match!");
191
191
  } else {
192
- title(@a, "§9蓝队获胜!");
193
- announce("§e[CTF] §9蓝队 §6赢得了比赛!");
192
+ title(@a, "§9Blue Team Wins!");
193
+ announce("§e[CTF] §9Blue Team §6wins the match!");
194
194
  }
195
195
 
196
- // 清理
196
+ // Cleanup
197
197
  foreach (p in @a[tag=has_flag]) {
198
198
  tag_remove(p, "has_flag");
199
199
  effect_clear(p);
200
200
  }
201
201
  }
202
202
 
203
- // ===== 辅助函数 =====
203
+ // ===== Helper Functions =====
204
204
  fn distance_to(target: selector, x: int, y: int, z: int) -> int {
205
- // 简化的距离计算(使用记分板)
205
+ // Simplified distance calculation (using scoreboard)
206
206
  let dist: int = scoreboard_get(target, "ctf_dist");
207
207
  return dist;
208
208
  }
@@ -1,8 +1,8 @@
1
1
  // ============================================
2
- // Hunger Games - 饥饿游戏
2
+ // Hunger Games - Hunger Games
3
3
  // ============================================
4
- // 场景:玩家从中央补给点开始,搜刮物资生存
5
- // 边界逐渐缩小,最后存活者获胜
4
+ // Scenario: Players start from the central supply point, scavenge for resources
5
+ // Border gradually shrinks, last survivor wins
6
6
  // Scenario: Battle royale with shrinking border
7
7
  // ============================================
8
8
 
@@ -11,19 +11,19 @@ import "../stdlib/world.mcrs"
11
11
  import "../stdlib/bossbar.mcrs"
12
12
  import "../stdlib/particles.mcrs"
13
13
 
14
- // ===== 配置 =====
14
+ // ===== Configuration =====
15
15
  const CENTER_X: int = 0;
16
16
  const CENTER_Y: int = 64;
17
17
  const CENTER_Z: int = 0;
18
18
  const INITIAL_BORDER: int = 200;
19
19
  const FINAL_BORDER: int = 20;
20
- const GRACE_PERIOD: int = 600; // 30秒无敌时间
21
- const SHRINK_INTERVAL: int = 1200; // 60秒缩圈
20
+ const GRACE_PERIOD: int = 600; // 30-second grace period
21
+ const SHRINK_INTERVAL: int = 1200; // Shrink every 60 seconds
22
22
 
23
- // ===== 游戏状态 =====
23
+ // ===== Game State =====
24
24
  struct HGState {
25
25
  running: int,
26
- phase: int, // 0=等待, 1=倒计时, 2=游戏中, 3=结束
26
+ phase: int, // 0=waiting, 1=countdown, 2=in-game, 3=ended
27
27
  countdown: int,
28
28
  grace_timer: int,
29
29
  border_timer: int,
@@ -46,36 +46,36 @@ fn init() {
46
46
  scoreboard_add_objective("hg_kills", "dummy");
47
47
  scoreboard_add_objective("hg_alive", "dummy");
48
48
 
49
- // 设置世界边界
49
+ // Set world border
50
50
  // worldborder center 0 0
51
51
  // worldborder set 200
52
52
 
53
- announce("§c[饥饿游戏] §f已加载!等待玩家加入...");
53
+ announce("§c[Hunger Games] §fLoaded! Waiting for players to join...");
54
54
  }
55
55
 
56
- // ===== 开始游戏 =====
56
+ // ===== Start Game =====
57
57
  fn start_countdown() {
58
58
  game.phase = 1;
59
- game.countdown = 200; // 10秒倒计时
59
+ game.countdown = 200; // 10-second countdown
60
60
 
61
- // 传送所有玩家到中央
61
+ // Teleport all players to center
62
62
  foreach (p in @a) {
63
- tp(p, CENTER_X, CENTER_Y + 50, CENTER_Z); // 高空开始
63
+ tp(p, CENTER_X, CENTER_Y + 50, CENTER_Z); // Start from high altitude
64
64
  scoreboard_set(p, "hg_kills", 0);
65
65
  scoreboard_set(p, "hg_alive", 1);
66
66
 
67
- // 清空背包
67
+ // Clear inventory
68
68
  clear(p);
69
69
 
70
- // 冻结玩家
70
+ // Freeze players
71
71
  effect(p, "minecraft:slowness", 15, 255);
72
- effect(p, "minecraft:jump_boost", 15, 250); // 防止跳跃
72
+ effect(p, "minecraft:jump_boost", 15, 250); // Prevent jumping
73
73
  }
74
74
 
75
- // 创建边界 bossbar
76
- create_progress_bar("hg_border", "§c边界缩小中", INITIAL_BORDER);
75
+ // Create border bossbar
76
+ create_progress_bar("hg_border", "§cBorder Shrinking", INITIAL_BORDER);
77
77
 
78
- announce("§c[饥饿游戏] §e游戏即将开始!");
78
+ announce("§c[Hunger Games] §eGame starting soon!");
79
79
  }
80
80
 
81
81
  fn start_game() {
@@ -85,25 +85,25 @@ fn start_game() {
85
85
  game.border_timer = SHRINK_INTERVAL;
86
86
  game.current_border = INITIAL_BORDER;
87
87
 
88
- // 计算存活人数
88
+ // Count alive players
89
89
  game.alive_count = 0;
90
90
  foreach (p in @a) {
91
91
  game.alive_count = game.alive_count + 1;
92
92
 
93
- // 清除效果
93
+ // Clear effects
94
94
  effect_clear(p);
95
95
 
96
- // 缓降
96
+ // Slow fall
97
97
  slow_fall(p, 100);
98
98
  }
99
99
 
100
- title(@a, "§c游戏开始!");
101
- subtitle(@a, "§7搜刮物资,成为最后的生存者!");
100
+ title(@a, "§cGame Start!");
101
+ subtitle(@a, "§7Scavenge for supplies, be the last survivor!");
102
102
 
103
- announce("§c[饥饿游戏] §a游戏开始!§730秒内无法互相伤害");
103
+ announce("§c[Hunger Games] §aGame started! §7No PvP for 30 seconds");
104
104
  }
105
105
 
106
- // ===== tick =====
106
+ // ===== Every Tick =====
107
107
  @tick
108
108
  fn game_tick() {
109
109
  if (game.phase == 1) {
@@ -118,7 +118,7 @@ fn game_tick() {
118
118
  fn countdown_tick() {
119
119
  game.countdown = game.countdown - 1;
120
120
 
121
- // 倒计时提示
121
+ // Countdown hints
122
122
  if (game.countdown == 100) {
123
123
  title(@a, "§e5");
124
124
  playsound("minecraft:block.note_block.pling", "player", @a);
@@ -146,30 +146,30 @@ fn countdown_tick() {
146
146
  }
147
147
 
148
148
  fn main_game_tick() {
149
- // 无敌时间
149
+ // Grace period
150
150
  if (game.grace_timer > 0) {
151
151
  game.grace_timer = game.grace_timer - 1;
152
152
 
153
153
  if (game.grace_timer == 0) {
154
- announce("§c[饥饿游戏] §4无敌时间结束!可以开始战斗!");
155
- title(@a, "§c战斗开始!");
154
+ announce("§c[Hunger Games] §4Grace period ended! Combat is now allowed!");
155
+ title(@a, "§cCombat Start!");
156
156
  }
157
157
  }
158
158
 
159
- // 边界缩小
159
+ // Border shrink
160
160
  game.border_timer = game.border_timer - 1;
161
161
  if (game.border_timer <= 0) {
162
162
  shrink_border();
163
163
  game.border_timer = SHRINK_INTERVAL;
164
164
  }
165
165
 
166
- // 更新 bossbar
166
+ // Update bossbar
167
167
  update_bar("hg_border", game.current_border);
168
168
 
169
- // 检查边界伤害
169
+ // Check border damage
170
170
  check_border_damage();
171
171
 
172
- // 检查存活人数
172
+ // Check alive count
173
173
  check_alive();
174
174
  }
175
175
 
@@ -182,13 +182,13 @@ fn shrink_border() {
182
182
  }
183
183
 
184
184
  // worldborder set game.current_border 60
185
- announce("§c[饥饿游戏] §e边界正在缩小!当前大小:" + game.current_border);
185
+ announce("§c[Hunger Games] §eBorder is shrinking! Current size: " + game.current_border);
186
186
 
187
- // 更新 bossbar
187
+ // Update bossbar
188
188
  bossbar_set_max("hg_border", INITIAL_BORDER);
189
189
  bossbar_set_value("hg_border", game.current_border);
190
190
 
191
- // 颜色变化
191
+ // Color change
192
192
  if (game.current_border < 50) {
193
193
  bossbar_set_color("hg_border", "red");
194
194
  } else {
@@ -200,12 +200,12 @@ fn shrink_border() {
200
200
  }
201
201
 
202
202
  fn check_border_damage() {
203
- // 对边界外的玩家造成伤害
204
- // 需要检查玩家是否在边界外
203
+ // Deal damage to players outside the border
204
+ // Need to check if player is outside the border
205
205
  foreach (p in @a) {
206
- // 简化:使用 execute positioned
206
+ // Simplified: using execute positioned
207
207
  let _dist: int = 0; // TODO: calculate distance from center
208
- // 如果超出边界,造成伤害
208
+ // If outside border, deal damage
209
209
  // effect(p, "minecraft:wither", 1, 0);
210
210
  }
211
211
  }
@@ -224,15 +224,15 @@ fn check_alive() {
224
224
 
225
225
  game.alive_count = alive;
226
226
 
227
- // 更新记分板显示
228
- actionbar(@a, "§c存活: " + alive + " 人");
227
+ // Update scoreboard display
228
+ actionbar(@a, "§cAlive: " + alive);
229
229
 
230
- // 检查胜利
230
+ // Check for victory
231
231
  if (alive <= 1) {
232
232
  if (alive == 1) {
233
233
  declare_winner(winner);
234
234
  } else {
235
- // 无人存活
235
+ // No survivors
236
236
  end_game_no_winner();
237
237
  }
238
238
  }
@@ -244,11 +244,11 @@ fn declare_winner(winner: selector) {
244
244
 
245
245
  let kills: int = scoreboard_get(winner, "hg_kills");
246
246
 
247
- title(@a, "§6胜利者!");
248
- announce("§c[饥饿游戏] §6游戏结束!");
249
- announce("§a胜利者击杀数:" + kills);
247
+ title(@a, "§6Winner!");
248
+ announce("§c[Hunger Games] §6Game Over!");
249
+ announce("§aWinner's kills: " + kills);
250
250
 
251
- // 胜利特效
251
+ // Victory effects
252
252
  totem_effect(winner);
253
253
  buff_all(winner, 200);
254
254
 
@@ -259,27 +259,27 @@ fn end_game_no_winner() {
259
259
  game.phase = 3;
260
260
  game.running = 0;
261
261
 
262
- title(@a, "§7游戏结束");
263
- subtitle(@a, "§c无人存活");
262
+ title(@a, "§7Game Over");
263
+ subtitle(@a, "§cNo survivors");
264
264
 
265
265
  remove_bar("hg_border");
266
266
  }
267
267
 
268
- // ===== 玩家死亡处理 =====
268
+ // ===== Player Death Handler =====
269
269
  fn on_player_death(player: selector, killer: selector) {
270
270
  scoreboard_set(player, "hg_alive", 0);
271
271
 
272
- // 更新击杀数
272
+ // Update kill count
273
273
  scoreboard_add(killer, "hg_kills", 1);
274
274
 
275
- // 切换观察模式
275
+ // Switch to spectator mode
276
276
  // gamemode spectator player
277
277
 
278
278
  let kills: int = scoreboard_get(killer, "hg_kills");
279
- announce("§c☠ §7玩家被击杀!击杀者已有 " + kills + " ");
279
+ announce("§c☠ §7A player was eliminated! Killer now has " + kills + " kills");
280
280
  }
281
281
 
282
- // ===== 重置游戏 =====
282
+ // ===== Reset Game =====
283
283
  fn reset_game() {
284
284
  game.phase = 0;
285
285
  game.running = 0;
@@ -291,11 +291,11 @@ fn reset_game() {
291
291
  // gamemode survival p
292
292
  }
293
293
 
294
- // 重置边界
294
+ // Reset border
295
295
  game.current_border = INITIAL_BORDER;
296
296
  // worldborder set 200
297
297
 
298
298
  remove_bar("hg_border");
299
299
 
300
- announce("§c[饥饿游戏] §7游戏已重置");
300
+ announce("§c[Hunger Games] §7Game has been reset");
301
301
  }
@@ -1,19 +1,19 @@
1
1
  /**
2
2
  * RedScript New Features Demo
3
- * 展示 2026-03-12 新增的语言特性
3
+ * Showcasing language features added on 2026-03-12
4
4
  */
5
5
 
6
6
  // ============================================
7
- // 1. 类型推断 (Type Inference)
7
+ // 1. Type Inference
8
8
  // ============================================
9
9
  fn type_inference_demo() {
10
- // 不需要写 `: int`,编译器自动推断
10
+ // No need to write `: int`, compiler infers automatically
11
11
  let health = 100;
12
12
  let name = "Steve";
13
13
  let alive = true;
14
14
  let speed = 1.5;
15
15
 
16
- // NBT 后缀也能推断
16
+ // NBT suffixes can also be inferred
17
17
  let damage = 20b; // byte
18
18
  let distance = 1000s; // short
19
19
  let bignum = 999999L; // long
@@ -23,25 +23,25 @@ fn type_inference_demo() {
23
23
  }
24
24
 
25
25
  // ============================================
26
- // 2. for-range 循环 (For-Range Loops)
26
+ // 2. For-Range Loops
27
27
  // ============================================
28
28
  fn for_range_demo() {
29
- // 0 9 循环
29
+ // Loop from 0 to 9
30
30
  for i in 0..10 {
31
31
  say("Count: ${i}");
32
32
  }
33
33
 
34
- // 可以用于倒计时
34
+ // Can be used for countdown
35
35
  for sec in 0..5 {
36
36
  title(@a, "Starting in ${sec}...");
37
37
  }
38
38
  }
39
39
 
40
40
  // ============================================
41
- // 3. NBT 结构化参数 (NBT Structured Params)
41
+ // 3. NBT Structured Params
42
42
  // ============================================
43
43
  fn nbt_params_demo() {
44
- // 给予带 NBT 的物品
44
+ // Give item with NBT
45
45
  give(@s, "minecraft:diamond_sword", 1, {
46
46
  display: { Name: "Excalibur" },
47
47
  Enchantments: [
@@ -50,7 +50,7 @@ fn nbt_params_demo() {
50
50
  ]
51
51
  });
52
52
 
53
- // 召唤带属性的实体
53
+ // Summon entity with attributes
54
54
  summon("minecraft:zombie", @s, {
55
55
  CustomName: "Boss Zombie",
56
56
  Health: 100.0,
@@ -61,31 +61,31 @@ fn nbt_params_demo() {
61
61
  }
62
62
 
63
63
  // ============================================
64
- // 4. Set 数据结构 (Runtime Set)
64
+ // 4. Set Data Structure (Runtime Set)
65
65
  // ============================================
66
66
  fn set_demo() {
67
- // 创建集合
67
+ // Create set
68
68
  let visited = set_new();
69
69
 
70
- // 使用方法语法添加元素
70
+ // Add elements using method syntax
71
71
  visited.add("spawn");
72
72
  visited.add("castle");
73
73
  visited.add("dungeon");
74
74
 
75
- // 检查是否存在
75
+ // Check if exists
76
76
  if (visited.contains("castle")) {
77
77
  say("You've been to the castle!");
78
78
  }
79
79
 
80
- // 删除元素
80
+ // Remove element
81
81
  visited.remove("spawn");
82
82
 
83
- // 清空集合
83
+ // Clear set
84
84
  visited.clear();
85
85
  }
86
86
 
87
87
  // ============================================
88
- // 5. 方法语法糖 (Method Syntax Sugar)
88
+ // 5. Method Syntax Sugar
89
89
  // ============================================
90
90
  fn method_syntax_demo() {
91
91
  let items: string[] = [];
@@ -98,7 +98,7 @@ fn method_syntax_demo() {
98
98
  let count = items.len();
99
99
  say("You have ${count} items");
100
100
 
101
- // Set 也可以用方法语法
101
+ // Sets can also use method syntax
102
102
  let tags = set_new();
103
103
  tags.add("vip");
104
104
  tags.add("admin");
@@ -109,44 +109,44 @@ fn method_syntax_demo() {
109
109
  }
110
110
 
111
111
  // ============================================
112
- // 6. #mc_name 语法 (MC Identifier Syntax)
112
+ // 6. #mc_name Syntax (MC Identifier Syntax)
113
113
  // ============================================
114
114
  fn mc_name_demo() {
115
- // #name 编译为裸 MC 名称(不带引号)
115
+ // #name compiles to bare MC name (without quotes)
116
116
  scoreboard_set(@s, #kills, 0);
117
117
  scoreboard_add(@s, #deaths, 1);
118
118
 
119
119
  let score = scoreboard_get(@s, #points);
120
120
 
121
- // 用于 tag
121
+ // For tag
122
122
  tag_add(@s, #vip);
123
123
 
124
- // 用于 team
124
+ // For team
125
125
  team_join(@s, #red);
126
126
 
127
- // 对比:字符串仍需引号
127
+ // Comparison: strings still need quotes
128
128
  give(@s, "minecraft:diamond", 1);
129
129
  }
130
130
 
131
131
  // ============================================
132
- // 7. 块注释 (Block Comments)
132
+ // 7. Block Comments
133
133
  // ============================================
134
134
 
135
135
  /*
136
- * 这是块注释
137
- * 可以跨越多行
136
+ * This is a block comment
137
+ * Can span multiple lines
138
138
  */
139
139
 
140
140
  /**
141
- * 这是文档注释
142
- * @param player 目标玩家
141
+ * This is a doc comment
142
+ * @param player Target player
143
143
  */
144
144
  fn documented_function() {
145
145
  say("Hello!");
146
146
  }
147
147
 
148
148
  // ============================================
149
- // 综合示例:简单游戏
149
+ // Combined Example: Simple Game
150
150
  // ============================================
151
151
 
152
152
  struct Player {
@@ -163,7 +163,7 @@ fn init_player() {
163
163
  visited: visited_set
164
164
  };
165
165
 
166
- // 记录出生点(使用 set_add,因为 visited string ID
166
+ // Record spawn point (using set_add since visited is a string ID)
167
167
  set_add(p.visited, "spawn");
168
168
 
169
169
  scoreboard_set(@s, #score, p.score);
@@ -172,7 +172,7 @@ fn init_player() {
172
172
 
173
173
  @tick(rate=20)
174
174
  fn game_tick() {
175
- // 每秒检查一次
175
+ // Check once per second
176
176
  for i in 0..1 {
177
177
  let score = scoreboard_get(@s, #score);
178
178
  if (score >= 100) {
@@ -183,7 +183,7 @@ fn game_tick() {
183
183
  }
184
184
 
185
185
  fn reward_player(amount: int) {
186
- // 类型推断 + NBT 参数
186
+ // Type inference + NBT params
187
187
  let bonus = amount * 2;
188
188
  scoreboard_add(@s, #score, bonus);
189
189