redscript-mc 1.2.20 → 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 (136) hide show
  1. package/.github/workflows/publish-extension-on-ci.yml +99 -0
  2. package/dist/__tests__/compile-all.test.js +5 -0
  3. package/dist/__tests__/entity-types.test.d.ts +1 -0
  4. package/dist/__tests__/entity-types.test.js +203 -0
  5. package/dist/__tests__/var-allocator.test.d.ts +1 -0
  6. package/dist/__tests__/var-allocator.test.js +69 -0
  7. package/dist/ast/types.d.ts +2 -1
  8. package/dist/cli.js +24 -7
  9. package/dist/codegen/mcfunction/index.d.ts +2 -0
  10. package/dist/codegen/mcfunction/index.js +47 -43
  11. package/dist/codegen/structure/index.d.ts +4 -1
  12. package/dist/codegen/structure/index.js +8 -12
  13. package/dist/codegen/var-allocator.d.ts +28 -0
  14. package/dist/codegen/var-allocator.js +74 -0
  15. package/dist/compile.d.ts +8 -0
  16. package/dist/compile.js +14 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.js +9 -7
  19. package/dist/lowering/index.d.ts +2 -0
  20. package/dist/lowering/index.js +62 -3
  21. package/dist/optimizer/dce.d.ts +2 -1
  22. package/dist/optimizer/dce.js +13 -2
  23. package/dist/parser/index.js +22 -1
  24. package/dist/typechecker/index.js +30 -0
  25. package/dist/types/entity-hierarchy.d.ts +29 -0
  26. package/dist/types/entity-hierarchy.js +107 -0
  27. package/editors/vscode/out/extension.js +29 -4
  28. package/editors/vscode/package-lock.json +6 -4
  29. package/editors/vscode/package.json +3 -3
  30. package/package.json +1 -1
  31. package/src/__tests__/compile-all.test.ts +6 -0
  32. package/src/__tests__/entity-types.test.ts +236 -0
  33. package/src/__tests__/var-allocator.test.ts +75 -0
  34. package/src/ast/types.ts +8 -4
  35. package/src/cli.ts +28 -8
  36. package/src/codegen/mcfunction/index.ts +55 -48
  37. package/src/codegen/structure/index.ts +9 -14
  38. package/src/codegen/var-allocator.ts +71 -0
  39. package/src/compile.ts +18 -0
  40. package/src/examples/capture_the_flag.mcrs +34 -34
  41. package/src/examples/hunger_games.mcrs +60 -60
  42. package/src/examples/new_features_demo.mcrs +32 -32
  43. package/src/examples/parkour_race.mcrs +58 -58
  44. package/src/examples/zombie_survival.mcrs +73 -73
  45. package/src/index.ts +11 -7
  46. package/src/lowering/index.ts +73 -8
  47. package/src/optimizer/dce.ts +18 -2
  48. package/src/parser/index.ts +20 -1
  49. package/src/typechecker/index.ts +30 -0
  50. package/src/types/entity-hierarchy.ts +120 -0
  51. package/dist/data/arena/function/__load.mcfunction +0 -6
  52. package/dist/data/arena/function/__tick.mcfunction +0 -2
  53. package/dist/data/arena/function/announce_leaders/else_1.mcfunction +0 -3
  54. package/dist/data/arena/function/announce_leaders/foreach_0/merge_2.mcfunction +0 -1
  55. package/dist/data/arena/function/announce_leaders/foreach_0/then_0.mcfunction +0 -3
  56. package/dist/data/arena/function/announce_leaders/foreach_0.mcfunction +0 -7
  57. package/dist/data/arena/function/announce_leaders/foreach_1/merge_2.mcfunction +0 -1
  58. package/dist/data/arena/function/announce_leaders/foreach_1/then_0.mcfunction +0 -4
  59. package/dist/data/arena/function/announce_leaders/foreach_1.mcfunction +0 -6
  60. package/dist/data/arena/function/announce_leaders/merge_2.mcfunction +0 -1
  61. package/dist/data/arena/function/announce_leaders/then_0.mcfunction +0 -4
  62. package/dist/data/arena/function/announce_leaders.mcfunction +0 -6
  63. package/dist/data/arena/function/arena_tick/merge_2.mcfunction +0 -1
  64. package/dist/data/arena/function/arena_tick/then_0.mcfunction +0 -4
  65. package/dist/data/arena/function/arena_tick.mcfunction +0 -11
  66. package/dist/data/counter/function/__load.mcfunction +0 -5
  67. package/dist/data/counter/function/__tick.mcfunction +0 -2
  68. package/dist/data/counter/function/counter_tick/merge_2.mcfunction +0 -1
  69. package/dist/data/counter/function/counter_tick/then_0.mcfunction +0 -3
  70. package/dist/data/counter/function/counter_tick.mcfunction +0 -11
  71. package/dist/data/minecraft/tags/function/load.json +0 -5
  72. package/dist/data/minecraft/tags/function/tick.json +0 -5
  73. package/dist/data/quiz/function/__load.mcfunction +0 -16
  74. package/dist/data/quiz/function/__tick.mcfunction +0 -6
  75. package/dist/data/quiz/function/__trigger_quiz_a_dispatch.mcfunction +0 -4
  76. package/dist/data/quiz/function/__trigger_quiz_b_dispatch.mcfunction +0 -4
  77. package/dist/data/quiz/function/__trigger_quiz_c_dispatch.mcfunction +0 -4
  78. package/dist/data/quiz/function/__trigger_quiz_start_dispatch.mcfunction +0 -4
  79. package/dist/data/quiz/function/answer_a.mcfunction +0 -4
  80. package/dist/data/quiz/function/answer_b.mcfunction +0 -4
  81. package/dist/data/quiz/function/answer_c.mcfunction +0 -4
  82. package/dist/data/quiz/function/ask_question/else_1.mcfunction +0 -5
  83. package/dist/data/quiz/function/ask_question/else_4.mcfunction +0 -5
  84. package/dist/data/quiz/function/ask_question/else_7.mcfunction +0 -4
  85. package/dist/data/quiz/function/ask_question/merge_2.mcfunction +0 -1
  86. package/dist/data/quiz/function/ask_question/merge_5.mcfunction +0 -2
  87. package/dist/data/quiz/function/ask_question/merge_8.mcfunction +0 -2
  88. package/dist/data/quiz/function/ask_question/then_0.mcfunction +0 -4
  89. package/dist/data/quiz/function/ask_question/then_3.mcfunction +0 -4
  90. package/dist/data/quiz/function/ask_question/then_6.mcfunction +0 -4
  91. package/dist/data/quiz/function/ask_question.mcfunction +0 -7
  92. package/dist/data/quiz/function/finish_quiz.mcfunction +0 -6
  93. package/dist/data/quiz/function/handle_answer/else_1.mcfunction +0 -5
  94. package/dist/data/quiz/function/handle_answer/else_10.mcfunction +0 -3
  95. package/dist/data/quiz/function/handle_answer/else_16.mcfunction +0 -3
  96. package/dist/data/quiz/function/handle_answer/else_4.mcfunction +0 -3
  97. package/dist/data/quiz/function/handle_answer/else_7.mcfunction +0 -5
  98. package/dist/data/quiz/function/handle_answer/merge_11.mcfunction +0 -2
  99. package/dist/data/quiz/function/handle_answer/merge_14.mcfunction +0 -2
  100. package/dist/data/quiz/function/handle_answer/merge_17.mcfunction +0 -2
  101. package/dist/data/quiz/function/handle_answer/merge_2.mcfunction +0 -8
  102. package/dist/data/quiz/function/handle_answer/merge_5.mcfunction +0 -2
  103. package/dist/data/quiz/function/handle_answer/merge_8.mcfunction +0 -2
  104. package/dist/data/quiz/function/handle_answer/then_0.mcfunction +0 -5
  105. package/dist/data/quiz/function/handle_answer/then_12.mcfunction +0 -5
  106. package/dist/data/quiz/function/handle_answer/then_15.mcfunction +0 -6
  107. package/dist/data/quiz/function/handle_answer/then_3.mcfunction +0 -6
  108. package/dist/data/quiz/function/handle_answer/then_6.mcfunction +0 -5
  109. package/dist/data/quiz/function/handle_answer/then_9.mcfunction +0 -6
  110. package/dist/data/quiz/function/handle_answer.mcfunction +0 -11
  111. package/dist/data/quiz/function/start_quiz.mcfunction +0 -5
  112. package/dist/data/shop/function/__load.mcfunction +0 -7
  113. package/dist/data/shop/function/__tick.mcfunction +0 -3
  114. package/dist/data/shop/function/__trigger_shop_buy_dispatch.mcfunction +0 -4
  115. package/dist/data/shop/function/complete_purchase/else_1.mcfunction +0 -5
  116. package/dist/data/shop/function/complete_purchase/else_4.mcfunction +0 -5
  117. package/dist/data/shop/function/complete_purchase/else_7.mcfunction +0 -3
  118. package/dist/data/shop/function/complete_purchase/merge_2.mcfunction +0 -2
  119. package/dist/data/shop/function/complete_purchase/merge_5.mcfunction +0 -2
  120. package/dist/data/shop/function/complete_purchase/merge_8.mcfunction +0 -2
  121. package/dist/data/shop/function/complete_purchase/then_0.mcfunction +0 -4
  122. package/dist/data/shop/function/complete_purchase/then_3.mcfunction +0 -4
  123. package/dist/data/shop/function/complete_purchase/then_6.mcfunction +0 -4
  124. package/dist/data/shop/function/complete_purchase.mcfunction +0 -7
  125. package/dist/data/shop/function/handle_shop_trigger.mcfunction +0 -3
  126. package/dist/data/turret/function/__load.mcfunction +0 -5
  127. package/dist/data/turret/function/__tick.mcfunction +0 -4
  128. package/dist/data/turret/function/__trigger_deploy_turret_dispatch.mcfunction +0 -4
  129. package/dist/data/turret/function/deploy_turret.mcfunction +0 -8
  130. package/dist/data/turret/function/turret_tick/at_1.mcfunction +0 -2
  131. package/dist/data/turret/function/turret_tick/foreach_0.mcfunction +0 -2
  132. package/dist/data/turret/function/turret_tick/foreach_2.mcfunction +0 -2
  133. package/dist/data/turret/function/turret_tick/tick_body.mcfunction +0 -3
  134. package/dist/data/turret/function/turret_tick/tick_skip.mcfunction +0 -1
  135. package/dist/data/turret/function/turret_tick.mcfunction +0 -5
  136. package/dist/pack.mcmeta +0 -6
@@ -1,8 +1,8 @@
1
1
  // ============================================
2
- // Parkour Race - 跑酷竞速
2
+ // Parkour Race - Parkour Race
3
3
  // ============================================
4
- // 场景:玩家从起点跑到终点,记录最快时间
5
- // 设有多个检查点,掉落会传送回最近检查点
4
+ // Scenario: Players race from start to finish, recording the fastest time
5
+ // Multiple checkpoints set; falling respawns the player at the nearest checkpoint
6
6
  // Scenario: Race from start to finish with checkpoints
7
7
  // ============================================
8
8
 
@@ -11,28 +11,28 @@ import "../stdlib/world.mcrs"
11
11
  import "../stdlib/bossbar.mcrs"
12
12
  import "../stdlib/particles.mcrs"
13
13
 
14
- // ===== 配置 =====
14
+ // ===== Configuration =====
15
15
  const START_X: int = 0;
16
16
  const START_Y: int = 64;
17
17
  const START_Z: int = 0;
18
- const FALL_Y: int = 50; // 低于此高度视为掉落
18
+ const FALL_Y: int = 50; // Below this height is considered a fall
19
19
 
20
20
  const CHECKPOINT_COUNT: int = 5;
21
21
 
22
- // ===== 游戏状态 =====
23
- // 记分板:
24
- // - pk_time: 当前用时 (ticks)
25
- // - pk_best: 最佳记录
26
- // - pk_checkpoint: 当前检查点
27
- // - pk_running: 是否在比赛中
22
+ // ===== Game State =====
23
+ // Scoreboards:
24
+ // - pk_time: Current elapsed time (ticks)
25
+ // - pk_best: Best record
26
+ // - pk_checkpoint: Current checkpoint
27
+ // - pk_running: Whether in a race
28
28
 
29
- // 检查点坐标 (简化为直线跑酷)
30
- // CP0: 0,64,0 (起点)
29
+ // Checkpoint coordinates (simplified to linear parkour)
30
+ // CP0: 0,64,0 (start)
31
31
  // CP1: 0,64,50
32
32
  // CP2: 0,70,100
33
33
  // CP3: 0,75,150
34
34
  // CP4: 0,80,200
35
- // CP5: 0,64,250 (终点)
35
+ // CP5: 0,64,250 (finish)
36
36
 
37
37
  @load
38
38
  fn init() {
@@ -41,21 +41,21 @@ fn init() {
41
41
  scoreboard_add_objective("pk_checkpoint", "dummy");
42
42
  scoreboard_add_objective("pk_running", "dummy");
43
43
 
44
- // 显示最佳时间
44
+ // Display best time
45
45
  scoreboard_display("sidebar", "pk_best");
46
46
 
47
47
  set_day();
48
48
  weather_clear();
49
49
 
50
- announce("§b[跑酷] §f已加载!踩压力板开始");
50
+ announce("§b[Parkour] §fLoaded! Step on pressure plate to start");
51
51
  }
52
52
 
53
- // ===== 开始比赛 =====
53
+ // ===== Start Race =====
54
54
  fn start_race(player: selector) {
55
- // 检查是否已在比赛中
55
+ // Check if already in a race
56
56
  let running: int = scoreboard_get(player, "pk_running");
57
57
  if (running == 1) {
58
- tell(player, "§c你已经在比赛中了!");
58
+ tell(player, "§cYou are already in a race!");
59
59
  return;
60
60
  }
61
61
 
@@ -63,53 +63,53 @@ fn start_race(player: selector) {
63
63
  scoreboard_set(player, "pk_time", 0);
64
64
  scoreboard_set(player, "pk_checkpoint", 0);
65
65
 
66
- // 传送到起点
66
+ // Teleport to start
67
67
  tp(player, START_X, START_Y, START_Z);
68
68
 
69
- // 清除效果,给速度
69
+ // Clear effects, give speed
70
70
  effect_clear(player);
71
71
 
72
- title(player, "§b开始!");
73
- subtitle(player, "§7跑向终点!");
72
+ title(player, "§bGo!");
73
+ subtitle(player, "§7Race to the finish!");
74
74
 
75
- // 创建计时 bossbar
76
- tell(player, "§b[跑酷] §a比赛开始!到达终点完成比赛");
75
+ // Create timer bossbar
76
+ tell(player, "§b[Parkour] §aRace started! Reach the finish to complete");
77
77
 
78
78
  sparkles(player);
79
79
  }
80
80
 
81
- // ===== tick =====
81
+ // ===== Every Tick =====
82
82
  @tick
83
83
  fn race_tick() {
84
- // 对每个比赛中的玩家
84
+ // For each player in a race
85
85
  foreach (p in @a) {
86
86
  let running: int = scoreboard_get(p, "pk_running");
87
87
  if (running == 1) {
88
- // 增加时间
88
+ // Increment time
89
89
  scoreboard_add(p, "pk_time", 1);
90
90
 
91
- // 显示当前时间
91
+ // Display current time
92
92
  let time: int = scoreboard_get(p, "pk_time");
93
93
  let seconds: int = time / 20;
94
94
  let ms: int = (time % 20) * 5;
95
- actionbar(p, "§e⏱ " + seconds + "." + ms + "");
95
+ actionbar(p, "§e⏱ " + seconds + "." + ms + "s");
96
96
 
97
- // 检查掉落
97
+ // Check fall
98
98
  check_fall(p);
99
99
 
100
- // 检查检查点
100
+ // Check checkpoints
101
101
  check_checkpoints(p);
102
102
  }
103
103
  }
104
104
  }
105
105
 
106
106
  fn check_fall(player: selector) {
107
- // 如果玩家低于 FALL_Y,传送回检查点
108
- // 使用 execute positioned 检查
107
+ // If player is below FALL_Y, teleport back to checkpoint
108
+ // Using execute positioned to check
109
109
  execute if entity player[y=..50] run {
110
110
  let cp: int = scoreboard_get(player, "pk_checkpoint");
111
111
  respawn_at_checkpoint(player, cp);
112
- tell(player, "§c掉落!返回检查点 " + cp);
112
+ tell(player, "§cFell! Returning to checkpoint " + cp);
113
113
  angry(player);
114
114
  }
115
115
  }
@@ -117,35 +117,35 @@ fn check_fall(player: selector) {
117
117
  fn check_checkpoints(player: selector) {
118
118
  let current_cp: int = scoreboard_get(player, "pk_checkpoint");
119
119
 
120
- // 检查点 1 (0, 64, 50)
120
+ // Checkpoint 1 (0, 64, 50)
121
121
  if (current_cp == 0) {
122
122
  execute if entity player[x=-2..2, y=62..68, z=48..52] run {
123
123
  reach_checkpoint(player, 1);
124
124
  }
125
125
  }
126
126
 
127
- // 检查点 2 (0, 70, 100)
127
+ // Checkpoint 2 (0, 70, 100)
128
128
  if (current_cp == 1) {
129
129
  execute if entity player[x=-2..2, y=68..74, z=98..102] run {
130
130
  reach_checkpoint(player, 2);
131
131
  }
132
132
  }
133
133
 
134
- // 检查点 3 (0, 75, 150)
134
+ // Checkpoint 3 (0, 75, 150)
135
135
  if (current_cp == 2) {
136
136
  execute if entity player[x=-2..2, y=73..79, z=148..152] run {
137
137
  reach_checkpoint(player, 3);
138
138
  }
139
139
  }
140
140
 
141
- // 检查点 4 (0, 80, 200)
141
+ // Checkpoint 4 (0, 80, 200)
142
142
  if (current_cp == 3) {
143
143
  execute if entity player[x=-2..2, y=78..84, z=198..202] run {
144
144
  reach_checkpoint(player, 4);
145
145
  }
146
146
  }
147
147
 
148
- // 终点 (0, 64, 250)
148
+ // Finish (0, 64, 250)
149
149
  if (current_cp == 4) {
150
150
  execute if entity player[x=-2..2, y=62..68, z=248..252] run {
151
151
  finish_race(player);
@@ -157,7 +157,7 @@ fn reach_checkpoint(player: selector, cp: int) {
157
157
  scoreboard_set(player, "pk_checkpoint", cp);
158
158
 
159
159
  title(player, "");
160
- subtitle(player, "§a检查点 " + cp + " / " + CHECKPOINT_COUNT);
160
+ subtitle(player, "§aCheckpoint " + cp + " / " + CHECKPOINT_COUNT);
161
161
 
162
162
  happy(player);
163
163
  playsound("minecraft:entity.experience_orb.pickup", "player", player);
@@ -189,45 +189,45 @@ fn finish_race(player: selector) {
189
189
  let seconds: int = time / 20;
190
190
  let ms: int = (time % 20) * 5;
191
191
 
192
- // 检查是否是新纪录
192
+ // Check if it's a new record
193
193
  if (best == 0) {
194
- // 第一次完成
194
+ // First completion
195
195
  scoreboard_set(player, "pk_best", time);
196
- title(player, "§6完成!");
197
- subtitle(player, "§e" + seconds + "." + ms + " §7(首次记录)");
198
- announce("§b[跑酷] §f玩家完成比赛!用时 §e" + seconds + "." + ms + "");
196
+ title(player, "§6Finished!");
197
+ subtitle(player, "§e" + seconds + "." + ms + "s §7(first record)");
198
+ announce("§b[Parkour] §fA player finished! Time: §e" + seconds + "." + ms + "s");
199
199
  } else {
200
200
  if (time < best) {
201
- // 新纪录!
201
+ // New record!
202
202
  scoreboard_set(player, "pk_best", time);
203
- title(player, "§6新纪录!");
204
- subtitle(player, "§e" + seconds + "." + ms + "");
205
- announce("§b[跑酷] §6新纪录!§f用时 §e" + seconds + "." + ms + "");
203
+ title(player, "§6New Record!");
204
+ subtitle(player, "§e" + seconds + "." + ms + "s");
205
+ announce("§b[Parkour] §6New Record! §fTime: §e" + seconds + "." + ms + "s");
206
206
  totem_effect(player);
207
207
  } else {
208
- title(player, "§a完成!");
209
- subtitle(player, "§e" + seconds + "." + ms + "");
208
+ title(player, "§aFinished!");
209
+ subtitle(player, "§e" + seconds + "." + ms + "s");
210
210
  }
211
211
  }
212
212
 
213
- // 特效
213
+ // Effects
214
214
  sparkles(player);
215
215
  playsound("minecraft:ui.toast.challenge_complete", "player", player);
216
216
  }
217
217
 
218
- // ===== 放弃比赛 =====
218
+ // ===== Quit Race =====
219
219
  fn quit_race(player: selector) {
220
220
  let running: int = scoreboard_get(player, "pk_running");
221
221
  if (running == 1) {
222
222
  scoreboard_set(player, "pk_running", 0);
223
- tell(player, "§c已放弃比赛");
223
+ tell(player, "§cRace abandoned");
224
224
  tp(player, START_X, START_Y, START_Z);
225
225
  }
226
226
  }
227
227
 
228
- // ===== 查看排行榜 =====
228
+ // ===== View Leaderboard =====
229
229
  fn show_leaderboard() {
230
- announce("§b===== 跑酷排行榜 =====");
231
- // 显示前 5 (需要记分板排序)
230
+ announce("§b===== Parkour Leaderboard =====");
231
+ // Display top 5 (requires scoreboard sorting)
232
232
  scoreboard_display("sidebar", "pk_best");
233
233
  }
@@ -1,8 +1,8 @@
1
1
  // ============================================
2
- // Zombie Survival - 僵尸生存模式
2
+ // Zombie Survival - Zombie Survival Mode
3
3
  // ============================================
4
- // 场景:玩家在竞技场中心抵御一波波僵尸
5
- // 每波结束后可以购买装备升级
4
+ // Scenario: Players defend against waves of zombies in the arena center
5
+ // Players can purchase equipment upgrades between waves
6
6
  // Scenario: Survive zombie waves, buy upgrades between rounds
7
7
  // ============================================
8
8
 
@@ -12,19 +12,19 @@ import "../stdlib/inventory.mcrs"
12
12
  import "../stdlib/bossbar.mcrs"
13
13
  import "../stdlib/particles.mcrs"
14
14
 
15
- // ===== 配置 =====
15
+ // ===== Configuration =====
16
16
  const ARENA_X: int = 0;
17
17
  const ARENA_Y: int = 64;
18
18
  const ARENA_Z: int = 0;
19
19
  const ARENA_RADIUS: int = 30;
20
- const WAVE_DELAY: int = 200; // 10秒准备时间
20
+ const WAVE_DELAY: int = 200; // 10-second preparation time
21
21
 
22
- // ===== 游戏状态 =====
22
+ // ===== Game State =====
23
23
  struct SurvivalState {
24
24
  running: int,
25
25
  wave: int,
26
26
  zombies_left: int,
27
- phase: int, // 0=准备, 1=战斗
27
+ phase: int, // 0=prep, 1=combat
28
28
  prep_timer: int,
29
29
  total_kills: int
30
30
  }
@@ -38,33 +38,33 @@ let state: SurvivalState = {
38
38
  total_kills: 0
39
39
  };
40
40
 
41
- // ===== 玩家数据 =====
42
- // 金币记分板: zs_coins
43
- // 击杀数: zs_kills
41
+ // ===== Player Data =====
42
+ // Coin scoreboard: zs_coins
43
+ // Kill count: zs_kills
44
44
 
45
- // ===== 初始化 =====
45
+ // ===== Initialization =====
46
46
  @load
47
47
  fn init() {
48
48
  scoreboard_add_objective("zs_coins", "dummy");
49
49
  scoreboard_add_objective("zs_kills", "dummy");
50
50
  scoreboard_add_objective("zs_display", "dummy");
51
51
 
52
- // 显示记分板
52
+ // Display scoreboard
53
53
  scoreboard_display("sidebar", "zs_display");
54
54
 
55
55
  set_night();
56
56
  disable_mob_griefing();
57
57
 
58
- announce("§4[僵尸生存] §f已加载!输入 /trigger start 开始");
58
+ announce("§4[Zombie Survival] §fLoaded! Type /trigger start to begin");
59
59
  }
60
60
 
61
- // ===== 开始游戏 =====
61
+ // ===== Start Game =====
62
62
  fn start_game() {
63
63
  state.running = 1;
64
64
  state.wave = 0;
65
65
  state.total_kills = 0;
66
66
 
67
- // 初始化玩家
67
+ // Initialize players
68
68
  foreach (p in @a) {
69
69
  scoreboard_set(p, "zs_coins", 0);
70
70
  scoreboard_set(p, "zs_kills", 0);
@@ -74,74 +74,74 @@ fn start_game() {
74
74
  tp(p, ARENA_X, ARENA_Y, ARENA_Z);
75
75
  }
76
76
 
77
- // 创建 bossbar
78
- create_progress_bar("zs_wave", "§c僵尸剩余", 10);
77
+ // Create bossbar
78
+ create_progress_bar("zs_wave", "§cZombies Remaining", 10);
79
79
 
80
- title(@a, "§4僵尸生存");
81
- subtitle(@a, "§7准备战斗...");
80
+ title(@a, "§4Zombie Survival");
81
+ subtitle(@a, "§7Prepare for battle...");
82
82
 
83
- // 开始第一波
83
+ // Start first wave
84
84
  start_prep_phase();
85
85
  }
86
86
 
87
- // ===== 阶段控制 =====
87
+ // ===== Phase Control =====
88
88
  fn start_prep_phase() {
89
89
  state.phase = 0;
90
90
  state.prep_timer = WAVE_DELAY;
91
91
  state.wave = state.wave + 1;
92
92
 
93
- announce("§4[僵尸生存] §e第 " + state.wave + " 波即将来袭!");
94
- announce("§7准备时间 10 秒...");
93
+ announce("§4[Zombie Survival] §eWave " + state.wave + " incoming!");
94
+ announce("§7Preparation time: 10 seconds...");
95
95
 
96
- // 商店提示
96
+ // Shop hint
97
97
  if (state.wave > 1) {
98
- announce("§a[商店] §f输入 /trigger buy 购买装备");
98
+ announce("§a[Shop] §fType /trigger buy to purchase equipment");
99
99
  }
100
100
  }
101
101
 
102
102
  fn start_combat_phase() {
103
103
  state.phase = 1;
104
104
 
105
- // 计算僵尸数量 (每波增加)
105
+ // Calculate zombie count (increases each wave)
106
106
  let zombie_count: int = 3 + (state.wave * 2);
107
107
  state.zombies_left = zombie_count;
108
108
 
109
- // 更新 bossbar
109
+ // Update bossbar
110
110
  bossbar_set_max("zs_wave", zombie_count);
111
111
  bossbar_set_value("zs_wave", zombie_count);
112
112
 
113
- title(@a, "§c第 " + state.wave + " 波");
113
+ title(@a, "§cWave " + state.wave);
114
114
 
115
- // 生成僵尸
115
+ // Spawn zombies
116
116
  spawn_zombies(zombie_count);
117
117
  }
118
118
 
119
119
  fn spawn_zombies(count: int) {
120
120
  for i in 0..count {
121
- // 在竞技场边缘随机生成
122
- let angle: int = i * 30; // 分散生成
121
+ // Spawn randomly at arena edge
122
+ let _angle: int = i * 30; // spread spawning
123
123
  let spawn_x: int = ARENA_X + (ARENA_RADIUS - 5);
124
124
  let spawn_z: int = ARENA_Z;
125
125
 
126
- // 根据波数增加僵尸强度
126
+ // Increase zombie difficulty based on wave number
127
127
  if (state.wave < 3) {
128
128
  summon("minecraft:zombie", spawn_x, ARENA_Y, spawn_z);
129
129
  } else {
130
130
  if (state.wave < 5) {
131
- // 穿盔甲的僵尸
131
+ // Armored zombies
132
132
  summon("minecraft:zombie", spawn_x, ARENA_Y, spawn_z,
133
133
  {ArmorItems: [{}, {}, {id: "iron_chestplate", Count: 1}, {}]});
134
134
  } else {
135
- // 快速僵尸
135
+ // Fast zombies
136
136
  summon("minecraft:husk", spawn_x, ARENA_Y, spawn_z);
137
137
  }
138
138
  }
139
139
  }
140
140
 
141
- announce("§c" + count + " 只僵尸出现了!");
141
+ announce("§c" + count + " zombies have appeared!");
142
142
  }
143
143
 
144
- // ===== tick =====
144
+ // ===== Every Tick =====
145
145
  @tick
146
146
  fn game_tick() {
147
147
  if (state.running == 0) {
@@ -149,10 +149,10 @@ fn game_tick() {
149
149
  }
150
150
 
151
151
  if (state.phase == 0) {
152
- // 准备阶段
152
+ // Preparation phase
153
153
  prep_tick();
154
154
  } else {
155
- // 战斗阶段
155
+ // Combat phase
156
156
  combat_tick();
157
157
  }
158
158
 
@@ -162,15 +162,15 @@ fn game_tick() {
162
162
  fn prep_tick() {
163
163
  state.prep_timer = state.prep_timer - 1;
164
164
 
165
- // 倒计时提示
165
+ // Countdown hints
166
166
  if (state.prep_timer == 100) {
167
- actionbar(@a, "§e5 秒...");
167
+ actionbar(@a, "§e5 seconds...");
168
168
  }
169
169
  if (state.prep_timer == 60) {
170
- actionbar(@a, "§e3 秒...");
170
+ actionbar(@a, "§e3 seconds...");
171
171
  }
172
172
  if (state.prep_timer == 20) {
173
- actionbar(@a, "§c1 秒...");
173
+ actionbar(@a, "§c1 second...");
174
174
  }
175
175
 
176
176
  if (state.prep_timer <= 0) {
@@ -179,20 +179,20 @@ fn prep_tick() {
179
179
  }
180
180
 
181
181
  fn combat_tick() {
182
- // 检查僵尸数量
182
+ // Check zombie count
183
183
  let zombies: int = count_entities(@e[type=zombie, distance=..50]);
184
184
  let husks: int = count_entities(@e[type=husk, distance=..50]);
185
185
  state.zombies_left = zombies + husks;
186
186
 
187
- // 更新 bossbar
187
+ // Update bossbar
188
188
  update_bar("zs_wave", state.zombies_left);
189
189
 
190
- // 检查波次完成
190
+ // Check wave completion
191
191
  if (state.zombies_left <= 0) {
192
192
  wave_complete();
193
193
  }
194
194
 
195
- // 检查玩家存活
195
+ // Check player survival
196
196
  let alive: int = count_entities(@a[gamemode=survival]);
197
197
  if (alive <= 0) {
198
198
  game_over();
@@ -200,17 +200,17 @@ fn combat_tick() {
200
200
  }
201
201
 
202
202
  fn wave_complete() {
203
- announce("§4[僵尸生存] §a第 " + state.wave + " 波完成!");
203
+ announce("§4[Zombie Survival] §aWave " + state.wave + " complete!");
204
204
 
205
- // 奖励金币
205
+ // Reward coins
206
206
  let reward: int = 50 + (state.wave * 25);
207
207
  foreach (p in @a) {
208
208
  scoreboard_add(p, "zs_coins", reward);
209
209
  happy(p);
210
210
  }
211
- announce("§6+" + reward + " 金币");
211
+ announce("§6+" + reward + " coins");
212
212
 
213
- // 检查特殊波
213
+ // Check special wave
214
214
  if (state.wave == 10) {
215
215
  victory();
216
216
  return;
@@ -219,65 +219,65 @@ fn wave_complete() {
219
219
  start_prep_phase();
220
220
  }
221
221
 
222
- // ===== 商店系统 =====
222
+ // ===== Shop System =====
223
223
  fn buy_item(player: selector, item_id: int) {
224
224
  let coins: int = scoreboard_get(player, "zs_coins");
225
225
 
226
226
  if (item_id == 1) {
227
- // 铁剑 - 100 金币
227
+ // Iron sword - 100 coins
228
228
  if (coins >= 100) {
229
229
  scoreboard_add(player, "zs_coins", -100);
230
230
  give(player, "minecraft:iron_sword", 1);
231
- tell(player, "§a购买成功:铁剑");
231
+ tell(player, "§aPurchased: Iron Sword");
232
232
  } else {
233
- tell(player, "§c金币不足!需要 100");
233
+ tell(player, "§cNot enough coins! Need 100");
234
234
  }
235
235
  }
236
236
 
237
237
  if (item_id == 2) {
238
- // 铁甲 - 200 金币
238
+ // Iron armor - 200 coins
239
239
  if (coins >= 200) {
240
240
  scoreboard_add(player, "zs_coins", -200);
241
241
  give(player, "minecraft:iron_chestplate", 1);
242
242
  give(player, "minecraft:iron_leggings", 1);
243
243
  give(player, "minecraft:iron_boots", 1);
244
- tell(player, "§a购买成功:铁甲套装");
244
+ tell(player, "§aPurchased: Iron Armor Set");
245
245
  } else {
246
- tell(player, "§c金币不足!需要 200");
246
+ tell(player, "§cNot enough coins! Need 200");
247
247
  }
248
248
  }
249
249
 
250
250
  if (item_id == 3) {
251
- // 弓箭 - 150 金币
251
+ // Bow and arrows - 150 coins
252
252
  if (coins >= 150) {
253
253
  scoreboard_add(player, "zs_coins", -150);
254
254
  give(player, "minecraft:bow", 1);
255
255
  give(player, "minecraft:arrow", 32);
256
- tell(player, "§a购买成功:弓 + 32 ");
256
+ tell(player, "§aPurchased: Bow + 32 Arrows");
257
257
  } else {
258
- tell(player, "§c金币不足!需要 150");
258
+ tell(player, "§cNot enough coins! Need 150");
259
259
  }
260
260
  }
261
261
 
262
262
  if (item_id == 4) {
263
- // 金苹果 - 75 金币
263
+ // Golden apple - 75 coins
264
264
  if (coins >= 75) {
265
265
  scoreboard_add(player, "zs_coins", -75);
266
266
  give(player, "minecraft:golden_apple", 2);
267
- tell(player, "§a购买成功:金苹果 x2");
267
+ tell(player, "§aPurchased: Golden Apple x2");
268
268
  } else {
269
- tell(player, "§c金币不足!需要 75");
269
+ tell(player, "§cNot enough coins! Need 75");
270
270
  }
271
271
  }
272
272
  }
273
273
 
274
- // ===== 结束 =====
274
+ // ===== End =====
275
275
  fn victory() {
276
276
  state.running = 0;
277
277
 
278
- title(@a, "§6胜利!");
279
- subtitle(@a, "§a你们生存了 10 波!");
280
- announce("§4[僵尸生存] §6恭喜!完成全部 10 波!");
278
+ title(@a, "§6Victory!");
279
+ subtitle(@a, "§aYou survived 10 waves!");
280
+ announce("§4[Zombie Survival] §6Congratulations! Completed all 10 waves!");
281
281
 
282
282
  foreach (p in @a) {
283
283
  totem_effect(p);
@@ -290,11 +290,11 @@ fn victory() {
290
290
  fn game_over() {
291
291
  state.running = 0;
292
292
 
293
- title(@a, "§c游戏结束");
294
- subtitle(@a, "§7生存了 " + state.wave + " ");
295
- announce("§4[僵尸生存] §c全员阵亡!最高波数:" + state.wave);
293
+ title(@a, "§cGame Over");
294
+ subtitle(@a, "§7Survived " + state.wave + " waves");
295
+ announce("§4[Zombie Survival] §cAll players eliminated! Highest wave: " + state.wave);
296
296
 
297
- // 清理僵尸
297
+ // Clean up zombies
298
298
  kill(@e[type=zombie]);
299
299
  kill(@e[type=husk]);
300
300
 
@@ -307,8 +307,8 @@ fn update_scoreboard() {
307
307
  }
308
308
 
309
309
  fn count_entities(sel: selector) -> int {
310
- // 使用 execute store 计算实体数量
310
+ // Use execute store to count entities
311
311
  let count: int = 0;
312
- // 实际实现需要 execute store
312
+ // Actual implementation requires execute store
313
313
  return count;
314
314
  }