diff --git a/src/community/docsGamesBuildersLua.js b/src/community/docsGamesBuildersLua.js index 84cfddd..8ab55dc 100644 --- a/src/community/docsGamesBuildersLua.js +++ b/src/community/docsGamesBuildersLua.js @@ -2734,7 +2734,129 @@ end)`, }, // ═══════════════════════════════════════════════════════════════ - // ИГРЫ 31-50: явных Lua-версий пока нет. + // ИГРА 31 — «Защита базы» + // ═══════════════════════════════════════════════════════════════ + 'base-defense': { + g31_main: `-- === ИГРА «ЗАЩИТА БАЗЫ» — главный скрипт (Lua) === +${SNIPPET_BROADCAST} + +local RunService = game:GetService("RunService") +local UserInputService = game:GetService("UserInputService") + +local killed = 0 +local leaked = 0 +local total = 0 +local over = false +local GOAL = 12 +local MAX_LEAK = 5 + +__rbxl_score_set(0) +__rbxl_show_text("Защити базу! Кликай по врагам", 3) + +local hitSound = Instance.new("Sound", workspace) +hitSound.SoundId = "hit"; hitSound.Volume = 0.6 +local loseSound = Instance.new("Sound", workspace) +loseSound.SoundId = "lose"; loseSound.Volume = 0.7 +local winSound = Instance.new("Sound", workspace) +winSound.SoundId = "win"; winSound.Volume = 1 + +-- Все живые враги: { ref, dead } +local enemies = {} + +-- Клик по NPC (target.kind=npc) — наносим урон ближайшему в радиусе 5 +local clickEvent = getEvent("EnemyClicked") +clickEvent.Event:Connect(function(localRef) + if over then return end + for _, e in ipairs(enemies) do + if not e.dead and e.ref == localRef then + -- Проверка расстояния (в радиусе 5) + local px = __rbxl_player_x() + local pz = __rbxl_player_z() + local ex = __rbxl_npc_x(e.ref) + local ez = __rbxl_npc_z(e.ref) + local dx = px - ex + local dz = pz - ez + local dist = math.sqrt(dx*dx + dz*dz) + if dist < 5 then + e.dead = true + __rbxl_spawn_particles("explosion", ex, 2, ez, 0.4, 1) + __rbxl_npc_remove(e.ref) + hitSound:Play() + killed = killed + 1 + __rbxl_score_set(killed) + if killed >= GOAL and not over then + over = true + winSound:Play() + __rbxl_show_text("Победа! База защищена!", 5) + local px2 = __rbxl_player_x() + local py2 = __rbxl_player_y() + local pz2 = __rbxl_player_z() + __rbxl_spawn_particles("confetti", px2, py2 + 3, pz2, 3, 3) + end + end + return + end + end +end) + +-- Регистрируем общий callback на клик по NPC — он шлёт ref в общий event +-- (фейерим один раз — при появлении каждого врага зовём __rbxl_npc_on_click) + +-- Спавн врага каждые 2 секунды +local spawnTimer = 0 +RunService.Heartbeat:Connect(function(dt) + if over then return end + if total >= GOAL + MAX_LEAK then return end + spawnTimer = spawnTimer + dt + if spawnTimer >= 2 then + spawnTimer = 0 + total = total + 1 + local x = math.random(-8, 8) + local ref = __rbxl_spawn_npc("character-b", x, 1, 38, "Враг", 30, 2.5) + local e = { ref = ref, dead = false } + table.insert(enemies, e) + -- Отложим moveTo пока NPC создастся + task.delay(0.3, function() + __rbxl_npc_moveto(ref, 0, 2) + end) + -- Клик по этому NPC → шлём в общий event + __rbxl_npc_on_click(ref, function() + local ev = game:GetService("ReplicatedStorage"):FindFirstChild("EnemyClicked") + if ev then ev:Fire(ref) end + end) + end +end) + +-- Проверка прорыва каждые 0.4с +local leakTimer = 0 +RunService.Heartbeat:Connect(function(dt) + if over then return end + leakTimer = leakTimer + dt + if leakTimer < 0.4 then return end + leakTimer = 0 + for _, e in ipairs(enemies) do + if not e.dead then + local ez = __rbxl_npc_z(e.ref) + local ex = __rbxl_npc_x(e.ref) + -- ez=0 ex=0 пока NPC не зарезолвлен — пропускаем + if not (ex == 0 and ez == 0) and ez < 4 then + e.dead = true + __rbxl_npc_remove(e.ref) + leaked = leaked + 1 + loseSound:Play() + __rbxl_show_text("Враг прорвался! (" .. leaked .. "/" .. MAX_LEAK .. ")", 2) + if leaked >= MAX_LEAK and not over then + over = true + __rbxl_show_text("База разрушена! Поражение.", 5) + end + end + end + end +end)`, + }, + + // ═══════════════════════════════════════════════════════════════ + // ИГРЫ 32-50: явных Lua-версий пока нет. // buildGameProject в docsGamesBuilders.js использует generateFallbackLua // (главный скрипт → показ подсказки + слушает FinishReached → // победа+конфетти; скрипт на финиш-примитиве → шлёт FinishReached; diff --git a/src/community/docsLessons.jsx b/src/community/docsLessons.jsx index 80ff32e..bdb1036 100644 --- a/src/community/docsLessons.jsx +++ b/src/community/docsLessons.jsx @@ -4197,7 +4197,7 @@ game.self.onTouch(() => { по заданиям.

- {`// === ИГРА «КВЕСТ С ЗАДАНИЯМИ» — главный скрипт === + {`// === ИГРА «КВЕСТ С ЗАДАНИЯМИ» — главный скрипт === // этап квеста: 0=не начат, 1=собрать монетку, 2=дойти до флага, // 3=вернуться к NPC, 4=готово @@ -4245,7 +4245,7 @@ game.onMessage('flag-done', () => { stage = 3; game.sound.play('pickup'); game.ui.showText('Квест: вернись к квестодателю', 3); -});`} +});`}

Главное здесь — переменная stage: