JS:
- showText 'Дёрни рычаги в нужном порядке (E)'
- onMessage 'lever' с {num} → click sound + pressed.push + проверка
совпадения с ORDER=[2,3,1]. Ошибка → reset + 'Неверно!' + lose
Полная последовательность → 'Верно! Дверь открыта' + win + tween двери
- onMessage 'win' → 'Победа!' + win + confetti
- лычаги: onInteract E (distance=3) → broadcast 'lever' {num}
- финиш: onTouch → broadcast 'win'
Lua (паритет):
- __rbxl_show_text + Sounds
- BindableEvents LeverPulled (с num аргументом) + WinReached
- g23_main: проверка порядка + tween двери (Position.Y+6) + CanCollide=false
- 3 g23_lever_N: Heartbeat distance-check (3), __rbxl_hud_set
'[E] Дёрнуть рычаг N' в нижней части экрана.
UserInputService.InputBegan E → LeverPulled:Fire(n)
- g23_finish: Touched → WinReached:Fire (fired-флаг)
2343 lines
94 KiB
JavaScript
2343 lines
94 KiB
JavaScript
/**
|
||
* docsGamesBuildersLua.js — Lua-эквиваленты скриптов для уроков.
|
||
*
|
||
* Структура: LUA_OVERRIDES[gameId][scriptId] = 'lua-code'
|
||
* Может быть строкой или функцией (script) => 'lua-code' для случаев,
|
||
* когда код зависит от target/name (например, имя примитива).
|
||
*
|
||
* Когда юзер нажимает «Открыть копию → Lua» в LessonPage,
|
||
* buildGameProject(id, {lang:'lua'}) подменяет JS-скрипт на Lua-версию
|
||
* отсюда. Геометрия (примитивы, блоки) остаётся той же — отличается
|
||
* только язык скриптов.
|
||
*
|
||
* Lua-код пишется в стандартном Roblox-стиле:
|
||
* game:GetService("Players"), workspace, Instance.new, Vector3, CFrame,
|
||
* :Connect, RunService.Heartbeat, BindableEvent через ReplicatedStorage.
|
||
*
|
||
* Конвенции:
|
||
* - target=null (глобальный JS-скрипт) → в Lua это просто script в workspace,
|
||
* общение через ReplicatedStorage:BindableEvent.
|
||
* - target.kind='primitive' (на объекте) → script лежит ВНУТРИ части,
|
||
* обращение к ней через script.Parent. Имя части совпадает с тем что
|
||
* в JS-builder указано (Монетка_N, Платформа_N и т.д.).
|
||
*
|
||
* Помощники общего назначения:
|
||
* getPlayerFromHit — извлекает Player из hit события Touched.
|
||
* getOrCreateEvent — общая BindableEvent в ReplicatedStorage для broadcast.
|
||
*/
|
||
|
||
// ══════════════════════════════════════════════════════════════════
|
||
// Общие сниппеты — вставляются в начало многих скриптов.
|
||
// ══════════════════════════════════════════════════════════════════
|
||
const SNIPPET_BROADCAST = `local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local function getEvent(name)
|
||
local ev = ReplicatedStorage:FindFirstChild(name)
|
||
if not ev then
|
||
ev = Instance.new("BindableEvent")
|
||
ev.Name = name
|
||
ev.Parent = ReplicatedStorage
|
||
end
|
||
return ev
|
||
end`;
|
||
|
||
const SNIPPET_PLAYER_HIT = `local Players = game:GetService("Players")
|
||
local function getPlayerFromHit(hit)
|
||
if not hit or not hit.Parent then return nil end
|
||
return Players:GetPlayerFromCharacter(hit.Parent)
|
||
end`;
|
||
|
||
export const LUA_OVERRIDES = {
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 1 — «Собери монетки»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'collect-coins': {
|
||
g1_main: `-- === ИГРА «СОБЕРИ МОНЕТКИ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local Players = game:GetService("Players")
|
||
local score = 0
|
||
local TOTAL = 8
|
||
|
||
-- HUD: счётчик в правом верхнем углу
|
||
local player = Players.LocalPlayer
|
||
local screenGui = Instance.new("ScreenGui", player.PlayerGui)
|
||
screenGui.Name = "CoinHUD"
|
||
|
||
local label = Instance.new("TextLabel", screenGui)
|
||
label.Size = UDim2.new(0, 220, 0, 50)
|
||
label.Position = UDim2.new(1, -240, 0, 20)
|
||
label.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
|
||
label.BackgroundTransparency = 0.4
|
||
label.TextColor3 = Color3.fromRGB(255, 215, 0)
|
||
label.TextScaled = true
|
||
label.Font = Enum.Font.SourceSansBold
|
||
label.Text = "Монеты: 0 / " .. TOTAL
|
||
|
||
-- Подсказка по центру (на 2 секунды)
|
||
local hintGui = Instance.new("ScreenGui", player.PlayerGui)
|
||
local hint = Instance.new("TextLabel", hintGui)
|
||
hint.Size = UDim2.new(0, 400, 0, 60)
|
||
hint.Position = UDim2.new(0.5, -200, 0.3, 0)
|
||
hint.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
|
||
hint.BackgroundTransparency = 0.4
|
||
hint.TextColor3 = Color3.fromRGB(255, 255, 255)
|
||
hint.TextScaled = true
|
||
hint.Text = "Собери все монетки!"
|
||
task.delay(2, function() hintGui:Destroy() end)
|
||
|
||
-- Звуки
|
||
local coinSound = Instance.new("Sound", workspace)
|
||
coinSound.SoundId = "coin"
|
||
coinSound.Volume = 1
|
||
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"
|
||
winSound.Volume = 1
|
||
|
||
-- Подписка на сбор монетки
|
||
local coinEvent = getEvent("CoinCollected")
|
||
coinEvent.Event:Connect(function()
|
||
score = score + 1
|
||
label.Text = "Монеты: " .. score .. " / " .. TOTAL
|
||
coinSound:Play()
|
||
if score >= TOTAL then
|
||
-- Победный текст
|
||
local winGui = Instance.new("ScreenGui", player.PlayerGui)
|
||
local winLabel = Instance.new("TextLabel", winGui)
|
||
winLabel.Size = UDim2.new(0, 500, 0, 80)
|
||
winLabel.Position = UDim2.new(0.5, -250, 0.4, 0)
|
||
winLabel.BackgroundColor3 = Color3.fromRGB(0, 100, 0)
|
||
winLabel.BackgroundTransparency = 0.2
|
||
winLabel.TextColor3 = Color3.fromRGB(255, 255, 0)
|
||
winLabel.TextScaled = true
|
||
winLabel.Font = Enum.Font.SourceSansBold
|
||
winLabel.Text = "Победа! Все монетки твои!"
|
||
winSound:Play()
|
||
end
|
||
end)`,
|
||
// Скрипт каждой монетки — генератор по script-объекту
|
||
g1_coin_1: makeCoinScript(),
|
||
g1_coin_2: makeCoinScript(),
|
||
g1_coin_3: makeCoinScript(),
|
||
g1_coin_4: makeCoinScript(),
|
||
g1_coin_5: makeCoinScript(),
|
||
g1_coin_6: makeCoinScript(),
|
||
g1_coin_7: makeCoinScript(),
|
||
g1_coin_8: makeCoinScript(),
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 2 — «Прыгай по платформам»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'platform-jump': {
|
||
g2_main: `-- === ИГРА «ПРЫГАЙ ПО ПЛАТФОРМАМ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local Players = game:GetService("Players")
|
||
local RunService = game:GetService("RunService")
|
||
local player = Players.LocalPlayer
|
||
local won = false
|
||
|
||
-- Подсказка по центру (паритет с JS game.ui.showText)
|
||
__rbxl_show_text("Допрыгай до зелёной площадки!", 3)
|
||
|
||
-- Звуки
|
||
local loseSound = Instance.new("Sound", workspace)
|
||
loseSound.SoundId = "lose"
|
||
loseSound.Volume = 1
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"
|
||
winSound.Volume = 1
|
||
|
||
-- Каждый кадр следим: не упал ли игрок
|
||
RunService.Heartbeat:Connect(function()
|
||
if won then return end
|
||
local char = player.Character
|
||
if not char then return end
|
||
local hrp = char:FindFirstChild("HumanoidRootPart")
|
||
if hrp and hrp.Position.Y < -3 then
|
||
player:LoadCharacter()
|
||
loseSound:Play()
|
||
__rbxl_show_text("Упал! Пробуй снова.", 1.5)
|
||
end
|
||
end)
|
||
|
||
-- Финиш-зона шлёт BindableEvent
|
||
local finishEvent = getEvent("FinishReached")
|
||
finishEvent.Event:Connect(function()
|
||
if won then return end
|
||
won = true
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Ты дошёл до финиша!", 5)
|
||
-- Конфетти над игроком (паритет с JS game.scene.spawnParticles)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g2_finish: `-- === Скрипт финиш-зоны (Lua) ===
|
||
-- Висит на невидимой зоне над зелёной площадкой.
|
||
-- Игрок встал — его тело внутри зоны — победа.
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("FinishReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 3 — «Не упади» (платформа сужается)
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'dont-fall': (function() {
|
||
const overrides = {
|
||
g3_main: `-- === ИГРА «НЕ УПАДИ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local Players = game:GetService("Players")
|
||
local RunService = game:GetService("RunService")
|
||
local player = Players.LocalPlayer
|
||
local won = false
|
||
|
||
__rbxl_show_text("Беги вперёд! Плитки исчезают!", 3)
|
||
|
||
local loseSound = Instance.new("Sound", workspace)
|
||
loseSound.SoundId = "lose"; loseSound.Volume = 1
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
RunService.Heartbeat:Connect(function()
|
||
if won then return end
|
||
local char = player.Character
|
||
if not char then return end
|
||
local hrp = char:FindFirstChild("HumanoidRootPart")
|
||
if hrp and hrp.Position.Y < -3 then
|
||
player:LoadCharacter()
|
||
loseSound:Play()
|
||
__rbxl_show_text("Упал! Снова.", 1.5)
|
||
end
|
||
end)
|
||
|
||
local finishEvent = getEvent("FinishReached")
|
||
finishEvent.Event:Connect(function()
|
||
if won then return end
|
||
won = true
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Ты добежал!", 5)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g3_finish: `-- === Скрипт финиш-зоны (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("FinishReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
};
|
||
// Скрипт каждой плитки — генератор (одинаковый код)
|
||
const tileScript = `-- === Скрипт исчезающей плитки (Lua) ===
|
||
local Debris = game:GetService("Debris")
|
||
local part = script.Parent
|
||
local triggered = false
|
||
local clickSound = Instance.new("Sound", part)
|
||
clickSound.SoundId = "click"; clickSound.Volume = 0.6
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if triggered then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
triggered = true
|
||
clickSound:Play()
|
||
-- через 1.2с плитка пропадает
|
||
Debris:AddItem(part, 1.2)
|
||
end)`;
|
||
for (let i = 1; i <= 14; i++) overrides['g3_tile_' + i] = tileScript;
|
||
return overrides;
|
||
})(),
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 4 — «Кнопка и дверь»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'button-door': {
|
||
g4_main: `-- === ИГРА «КНОПКА-ОТКРЫВАШКА» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
__rbxl_show_text("Подойди к красной кнопке и нажми E", 4)
|
||
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
local winEvent = getEvent("WinReached")
|
||
winEvent.Event:Connect(function()
|
||
__rbxl_show_text("Победа! Дверь открыта, ты прошёл!", 5)
|
||
winSound:Play()
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g4_button: `-- === Скрипт кнопки (Lua) ===
|
||
-- Висит на красной кнопке. Реагирует на E когда игрок рядом.
|
||
local UserInputService = game:GetService("UserInputService")
|
||
local TweenService = game:GetService("TweenService")
|
||
local RunService = game:GetService("RunService")
|
||
|
||
local part = script.Parent
|
||
local opened = false
|
||
local hintVisible = false
|
||
|
||
-- Подсказка над кнопкой. BillboardGui в shim — generic instance,
|
||
-- управляем видимостью через label.Visible.
|
||
local hintGui = Instance.new("BillboardGui", part)
|
||
hintGui.Size = UDim2.new(4, 0, 1, 0)
|
||
hintGui.StudsOffset = Vector3.new(0, 2, 0)
|
||
hintGui.AlwaysOnTop = true
|
||
local label = Instance.new("TextLabel", hintGui)
|
||
label.Size = UDim2.new(1, 0, 1, 0)
|
||
label.BackgroundTransparency = 1
|
||
label.TextColor3 = Color3.fromRGB(255, 255, 255)
|
||
label.TextStrokeTransparency = 0
|
||
label.TextScaled = true
|
||
label.Text = "[E] Открыть дверь"
|
||
label.Visible = false -- скрыт по умолчанию
|
||
|
||
local clickSound = Instance.new("Sound", part)
|
||
clickSound.SoundId = "click"; clickSound.Volume = 0.8
|
||
|
||
-- Каждый кадр проверяем расстояние до игрока. Подсказку показываем
|
||
-- только если игрок в радиусе 4 единиц.
|
||
RunService.Heartbeat:Connect(function()
|
||
if opened then return end
|
||
local px = __rbxl_player_x()
|
||
local pz = __rbxl_player_z()
|
||
local dx = part.Position.X - px
|
||
local dz = part.Position.Z - pz
|
||
local dist = math.sqrt(dx*dx + dz*dz)
|
||
local near = dist <= 4
|
||
if near ~= hintVisible then
|
||
hintVisible = near
|
||
label.Visible = near
|
||
end
|
||
end)
|
||
|
||
UserInputService.InputBegan:Connect(function(input, gp)
|
||
if gp then return end
|
||
if opened or not hintVisible then return end
|
||
if input.KeyCode ~= Enum.KeyCode.E then return end
|
||
|
||
opened = true
|
||
label.Visible = false -- скрываем подсказку (Destroy не уничтожает GUI-overlay)
|
||
label:Destroy()
|
||
hintGui:Destroy()
|
||
clickSound:Play()
|
||
__rbxl_show_text("Дверь открывается!", 2)
|
||
part.Color = Color3.fromRGB(100, 255, 100)
|
||
|
||
local door = workspace:FindFirstChild("Дверь")
|
||
if door then
|
||
local dp = door.Position
|
||
local goal = { Position = Vector3.new(dp.X, dp.Y + 6, dp.Z) }
|
||
TweenService:Create(door, TweenInfo.new(1.2), goal):Play()
|
||
door.CanCollide = false
|
||
end
|
||
end)`,
|
||
g4_finish: `-- === Скрипт финиша (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("WinReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 5 — «Лабиринт»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'maze': {
|
||
g5_main: `-- === ИГРА «ЛАБИРИНТ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
__rbxl_show_text("Найди выход из лабиринта!", 3)
|
||
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
local winEvent = getEvent("WinReached")
|
||
winEvent.Event:Connect(function()
|
||
__rbxl_show_text("Победа! Ты нашёл выход!", 5)
|
||
winSound:Play()
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g5_finish: `-- === Скрипт финиша лабиринта (Lua) ===
|
||
-- Висит на невидимой зоне над зелёным ковриком.
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("WinReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 6 — «Угадай цвет»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'color-tiles': (function() {
|
||
const overrides = {
|
||
g6_main: `-- === ИГРА «ЦВЕТНЫЕ ПЛИТКИ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local Players = game:GetService("Players")
|
||
local player = Players.LocalPlayer
|
||
local painted = 0
|
||
local TOTAL = 36
|
||
local won = false
|
||
|
||
__rbxl_show_text("Наступи на все плитки!", 3)
|
||
|
||
-- Счётчик в правом верхнем углу
|
||
local screenGui = Instance.new("ScreenGui", player.PlayerGui)
|
||
local label = Instance.new("TextLabel", screenGui)
|
||
label.Size = UDim2.new(0, 220, 0, 50)
|
||
label.Position = UDim2.new(1, -240, 0, 20)
|
||
label.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
|
||
label.BackgroundTransparency = 0.4
|
||
label.TextColor3 = Color3.fromRGB(160, 255, 160)
|
||
label.TextScaled = true
|
||
label.Font = Enum.Font.SourceSansBold
|
||
label.Text = "Плитки: 0 / " .. TOTAL
|
||
|
||
local pickupSound = Instance.new("Sound", workspace)
|
||
pickupSound.SoundId = "pickup"; pickupSound.Volume = 0.7
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
local paintEvent = getEvent("TilePainted")
|
||
paintEvent.Event:Connect(function()
|
||
if won then return end
|
||
painted = painted + 1
|
||
label.Text = "Плитки: " .. painted .. " / " .. TOTAL
|
||
pickupSound:Play()
|
||
if painted >= TOTAL then
|
||
won = true
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Все плитки раскрашены!", 5)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end
|
||
end)`,
|
||
};
|
||
// Скрипт для каждой из 36 плиток — одинаковый код через генератор
|
||
const tileScript = `-- === Скрипт цветной плитки (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local painted = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if painted then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
painted = true
|
||
part.Color = Color3.fromRGB(51, 221, 85) -- ярко-зелёный
|
||
local ev = ReplicatedStorage:FindFirstChild("TilePainted")
|
||
if ev then ev:Fire() end
|
||
end)`;
|
||
for (let i = 1; i <= 36; i++) overrides['g6_tile_' + i] = tileScript;
|
||
return overrides;
|
||
})(),
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 7 — «Ловишка предметов»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'catch-falling': {
|
||
g7_main: `-- === ИГРА «ПОЙМАЙ ПАДАЮЩЕЕ» — главный скрипт (Lua) ===
|
||
local Players = game:GetService("Players")
|
||
local Debris = game:GetService("Debris")
|
||
|
||
local player = Players.LocalPlayer
|
||
local score = 0
|
||
local GOAL = 15
|
||
local won = false
|
||
|
||
__rbxl_show_text("Лови падающие кубы! Нужно 15", 3)
|
||
|
||
-- Счётчик в правом верхнем углу
|
||
local screenGui = Instance.new("ScreenGui", player.PlayerGui)
|
||
local label = Instance.new("TextLabel", screenGui)
|
||
label.Size = UDim2.new(0, 220, 0, 50)
|
||
label.Position = UDim2.new(1, -240, 0, 20)
|
||
label.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
|
||
label.BackgroundTransparency = 0.4
|
||
label.TextColor3 = Color3.fromRGB(255, 215, 0)
|
||
label.TextScaled = true
|
||
label.Font = Enum.Font.SourceSansBold
|
||
label.Text = "Поймано: 0 / " .. GOAL
|
||
|
||
local coinSound = Instance.new("Sound", workspace)
|
||
coinSound.SoundId = "coin"; coinSound.Volume = 1
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
-- Каждые 1.5 сек роняем куб (через Heartbeat — task.spawn не умеет yield)
|
||
local RunService = game:GetService("RunService")
|
||
local _spawnTimer = 0
|
||
|
||
local function spawnCube()
|
||
-- Используем хелпер __rbxl_spawn_part — он сразу создаёт примитив
|
||
-- с правильными свойствами (включая anchored=false → реальная гравитация).
|
||
local cube = __rbxl_spawn_part({
|
||
type = "cube",
|
||
x = math.random(-6, 6), y = 14, z = math.random(-6, 6),
|
||
sx = 0.8, sy = 0.8, sz = 0.8,
|
||
color = "#ffcc33",
|
||
anchored = false, -- падает
|
||
canCollide = true,
|
||
})
|
||
if not cube then return end
|
||
Debris:AddItem(cube, 6)
|
||
|
||
local caught = false
|
||
cube.Touched:Connect(function(hit)
|
||
if caught or won then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
caught = true
|
||
score = score + 1
|
||
label.Text = "Поймано: " .. score .. " / " .. GOAL
|
||
coinSound:Play()
|
||
cube:Destroy()
|
||
if score >= GOAL then
|
||
won = true
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Ты поймал 15 кубов!", 5)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end
|
||
end)
|
||
end
|
||
|
||
RunService.Heartbeat:Connect(function(dt)
|
||
if won then return end
|
||
_spawnTimer = _spawnTimer + (dt or 0.016)
|
||
if _spawnTimer >= 1.5 then
|
||
_spawnTimer = 0
|
||
spawnCube()
|
||
end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 8 — «Беги до финиша»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'run-to-finish': {
|
||
g8_main: `-- === ИГРА «БЕГИ К ФИНИШУ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local Players = game:GetService("Players")
|
||
local RunService = game:GetService("RunService")
|
||
local player = Players.LocalPlayer
|
||
local finished = false
|
||
local time = 0
|
||
|
||
__rbxl_show_text("Беги к зелёному финишу — на время!", 3)
|
||
|
||
-- Секундомер вверху по центру
|
||
local screenGui = Instance.new("ScreenGui", player.PlayerGui)
|
||
local timerLabel = Instance.new("TextLabel", screenGui)
|
||
timerLabel.Size = UDim2.new(0, 220, 0, 60)
|
||
timerLabel.Position = UDim2.new(0.5, -110, 0, 20)
|
||
timerLabel.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
|
||
timerLabel.BackgroundTransparency = 0.4
|
||
timerLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
|
||
timerLabel.TextScaled = true
|
||
timerLabel.Font = Enum.Font.SourceSansBold
|
||
timerLabel.Text = "0.0 сек"
|
||
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
-- Каждый кадр прибавляем dt к таймеру
|
||
RunService.Heartbeat:Connect(function(dt)
|
||
if finished then return end
|
||
time = time + (dt or 0.016)
|
||
-- Округляем до одного знака для отображения
|
||
local rounded = math.floor(time * 10) / 10
|
||
timerLabel.Text = string.format("%.1f сек", rounded)
|
||
end)
|
||
|
||
-- Финиш-зона шлёт BindableEvent
|
||
local finishEvent = getEvent("FinishReached")
|
||
finishEvent.Event:Connect(function()
|
||
if finished then return end
|
||
finished = true
|
||
local t = math.floor(time * 10) / 10
|
||
winSound:Play()
|
||
__rbxl_show_text("Финиш! Твоё время: " .. string.format("%.1f", t) .. " сек", 6)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g8_finish: `-- === Скрипт финиша (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("FinishReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 9 — «Светофор»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'traffic-light': {
|
||
g9_main: `-- === ИГРА «СВЕТОФОР» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local Players = game:GetService("Players")
|
||
local RunService = game:GetService("RunService")
|
||
local player = Players.LocalPlayer
|
||
local won = false
|
||
local phase = "green" -- "green" (беги) или "red" (замри)
|
||
local phaseTimer = 0
|
||
local GREEN_TIME = 3
|
||
local RED_TIME = 2.5
|
||
|
||
__rbxl_show_text("Зелёный — беги! Красный — замри!", 3)
|
||
|
||
local loseSound = Instance.new("Sound", workspace)
|
||
loseSound.SoundId = "lose"; loseSound.Volume = 1
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
-- Находим светофор и сразу красим в зелёный
|
||
local light = workspace:FindFirstChild("Светофор")
|
||
if light then light.Color = Color3.fromRGB(34, 221, 85) end
|
||
__rbxl_show_text("ЗЕЛЁНЫЙ — беги!", 1.2)
|
||
|
||
-- Каждый кадр считаем таймер фазы и проверяем движение
|
||
local prevX, prevZ = nil, nil
|
||
RunService.Heartbeat:Connect(function(dt)
|
||
if won then return end
|
||
dt = dt or 0.016
|
||
|
||
-- Переключение фаз
|
||
phaseTimer = phaseTimer + dt
|
||
if phase == "green" and phaseTimer >= GREEN_TIME then
|
||
phaseTimer = 0
|
||
phase = "red"
|
||
if light then light.Color = Color3.fromRGB(226, 59, 59) end
|
||
__rbxl_show_text("КРАСНЫЙ — замри!", 1.2)
|
||
elseif phase == "red" and phaseTimer >= RED_TIME then
|
||
phaseTimer = 0
|
||
phase = "green"
|
||
if light then light.Color = Color3.fromRGB(34, 221, 85) end
|
||
__rbxl_show_text("ЗЕЛЁНЫЙ — беги!", 1.2)
|
||
end
|
||
|
||
-- Если красный и игрок шевелится — респаун
|
||
local px = __rbxl_player_x()
|
||
local pz = __rbxl_player_z()
|
||
if prevX and phase == "red" then
|
||
local dx = px - prevX
|
||
local dz = pz - prevZ
|
||
local moved = math.sqrt(dx*dx + dz*dz)
|
||
if moved / dt > 0.8 then
|
||
player:LoadCharacter()
|
||
loseSound:Play()
|
||
__rbxl_show_text("Двинулся на красный! На старт.", 2)
|
||
end
|
||
end
|
||
prevX, prevZ = px, pz
|
||
end)
|
||
|
||
-- Финиш-зона шлёт BindableEvent
|
||
local winEvent = getEvent("WinReached")
|
||
winEvent.Event:Connect(function()
|
||
if won then return end
|
||
won = true
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Ты дошёл до финиша!", 5)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g9_finish: `-- === Скрипт финиша (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("WinReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 10 — «Прыжки на пружинах»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'spring-jump': (function() {
|
||
const overrides = {
|
||
g10_main: `-- === ИГРА «ПРЫЖОК-ПРУЖИНА» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local Players = game:GetService("Players")
|
||
local RunService = game:GetService("RunService")
|
||
local player = Players.LocalPlayer
|
||
local won = false
|
||
|
||
__rbxl_show_text("Прыгай по батутам всё выше!", 3)
|
||
|
||
local loseSound = Instance.new("Sound", workspace)
|
||
loseSound.SoundId = "lose"; loseSound.Volume = 1
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
-- Каждый кадр проверяем: упал вниз — на старт
|
||
RunService.Heartbeat:Connect(function()
|
||
if won then return end
|
||
local py = __rbxl_player_y()
|
||
if py < -3 then
|
||
player:LoadCharacter()
|
||
loseSound:Play()
|
||
end
|
||
end)
|
||
|
||
-- Финиш-зона шлёт BindableEvent
|
||
local winEvent = getEvent("WinReached")
|
||
winEvent.Event:Connect(function()
|
||
if won then return end
|
||
won = true
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Ты допрыгал до верха!", 5)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g10_finish: `-- === Скрипт финиша (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("WinReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
};
|
||
// Скрипт каждого батута — одинаковый код
|
||
const trampScript = `-- === Скрипт батута (Lua) ===
|
||
-- Игрок встал на батут — мощный подброс вверх.
|
||
local part = script.Parent
|
||
local jumpSound = Instance.new("Sound", part)
|
||
jumpSound.SoundId = "jump"; jumpSound.Volume = 0.7
|
||
|
||
local lastBoost = 0
|
||
part.Touched:Connect(function(hit)
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
-- Не зацикливаем подброс — минимум 0.5с между активациями
|
||
local now = tick()
|
||
if now - lastBoost < 0.5 then return end
|
||
lastBoost = now
|
||
__rbxl_boost_jump(3.2) -- 3.2 = втрое выше обычного прыжка
|
||
jumpSound:Play()
|
||
end)`;
|
||
// Батуты в JS-builder имеют id 4, 5, 6 (после трёх этажей)
|
||
for (const tid of [4, 5, 6]) {
|
||
overrides['g10_tramp_' + tid] = trampScript;
|
||
}
|
||
return overrides;
|
||
})(),
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 11 — «Эхо» (нажми кнопку → звук)
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'echo-room': (function() {
|
||
// Звуки и цвета для 6 плиток — должны совпадать с JS-builder
|
||
const tiles = [
|
||
{ sound: 'coin', color: '#e23b3b' }, // 1
|
||
{ sound: 'jump', color: '#f59e0b' }, // 2
|
||
{ sound: 'pickup', color: '#facc15' }, // 3
|
||
{ sound: 'click', color: '#22c55e' }, // 4
|
||
{ sound: 'hit', color: '#3b82f6' }, // 5
|
||
{ sound: 'coin', color: '#a855f7' }, // 6
|
||
];
|
||
const TOTAL = tiles.length;
|
||
|
||
const overrides = {
|
||
g11_main: `-- === ИГРА «ЭХО-КОМНАТА» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local Players = game:GetService("Players")
|
||
local player = Players.LocalPlayer
|
||
local stepped = 0
|
||
local TOTAL = ${TOTAL}
|
||
local won = false
|
||
|
||
__rbxl_show_text("Наступи на все цветные плитки!", 3)
|
||
|
||
-- Счётчик в правом верхнем углу
|
||
local screenGui = Instance.new("ScreenGui", player.PlayerGui)
|
||
local label = Instance.new("TextLabel", screenGui)
|
||
label.Size = UDim2.new(0, 240, 0, 50)
|
||
label.Position = UDim2.new(1, -260, 0, 20)
|
||
label.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
|
||
label.BackgroundTransparency = 0.4
|
||
label.TextColor3 = Color3.fromRGB(255, 255, 255)
|
||
label.TextScaled = true
|
||
label.Font = Enum.Font.SourceSansBold
|
||
label.Text = "Плитки: 0 / " .. TOTAL
|
||
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
-- Плитка впервые засчитана
|
||
local stepEvent = getEvent("EchoStep")
|
||
stepEvent.Event:Connect(function()
|
||
stepped = stepped + 1
|
||
label.Text = "Плитки: " .. stepped .. " / " .. TOTAL
|
||
if stepped >= TOTAL then
|
||
__rbxl_show_text("Все плитки звучали! Иди на финиш.", 3)
|
||
end
|
||
end)
|
||
|
||
-- Игрок встал на финиш
|
||
local finishEvent = getEvent("EchoFinish")
|
||
finishEvent.Event:Connect(function()
|
||
if won then return end
|
||
if stepped < TOTAL then
|
||
__rbxl_show_text("Сначала пройди все " .. TOTAL .. " плиток!", 2)
|
||
return
|
||
end
|
||
won = true
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Эхо-комната пройдена!", 5)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g11_finish: `-- === Скрипт финиша (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
|
||
part.Touched:Connect(function(hit)
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
local ev = ReplicatedStorage:FindFirstChild("EchoFinish")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
};
|
||
|
||
// Скрипт каждой звуковой плитки — со своим звуком и цветом
|
||
for (let i = 0; i < TOTAL; i++) {
|
||
const t = tiles[i];
|
||
overrides['g11_tile_' + (i + 1)] = `-- === Скрипт звуковой плитки (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local used = false
|
||
local lastSound = 0
|
||
|
||
local tileSound = Instance.new("Sound", part)
|
||
tileSound.SoundId = "${t.sound}"; tileSound.Volume = 0.8
|
||
|
||
part.Touched:Connect(function(hit)
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
-- Звук эхом — каждый раз, но не чаще 0.4с
|
||
local now = tick()
|
||
if now - lastSound > 0.4 then
|
||
lastSound = now
|
||
tileSound:Play()
|
||
-- Вспышка частиц над плиткой
|
||
local pos = part.Position
|
||
__rbxl_spawn_particles("sparks", pos.X, pos.Y + 1, pos.Z, 0.6, 1)
|
||
end
|
||
-- Засчитываем плитку только в первый раз
|
||
if not used then
|
||
used = true
|
||
local ev = ReplicatedStorage:FindFirstChild("EchoStep")
|
||
if ev then ev:Fire() end
|
||
end
|
||
end)`;
|
||
}
|
||
return overrides;
|
||
})(),
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 12 — «Кодовая дверь»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'code-door': (function() {
|
||
const overrides = {
|
||
g12_main: `-- === ИГРА «ДВЕРЬ ПО КОДУ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local TweenService = game:GetService("TweenService")
|
||
local CODE = { 3, 1, 4, 2 }
|
||
local entered = {}
|
||
local opened = false
|
||
local won = false
|
||
|
||
__rbxl_show_text("Нажми кнопки в правильном порядке (E)", 4)
|
||
|
||
local clickSound = Instance.new("Sound", workspace)
|
||
clickSound.SoundId = "click"; clickSound.Volume = 0.7
|
||
local loseSound = Instance.new("Sound", workspace)
|
||
loseSound.SoundId = "lose"; loseSound.Volume = 0.8
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
local pressEvent = getEvent("ButtonPress")
|
||
pressEvent.Event:Connect(function(num)
|
||
if opened then return end
|
||
clickSound:Play()
|
||
table.insert(entered, num)
|
||
local i = #entered
|
||
if entered[i] ~= CODE[i] then
|
||
-- ошибка — сброс
|
||
entered = {}
|
||
__rbxl_show_text("Неверно! Код сброшен.", 1.5)
|
||
loseSound:Play()
|
||
return
|
||
end
|
||
if #entered == #CODE then
|
||
opened = true
|
||
__rbxl_show_text("Код верный! Дверь открывается.", 3)
|
||
winSound:Play()
|
||
local door = workspace:FindFirstChild("Дверь")
|
||
if door then
|
||
local dp = door.Position
|
||
local goal = { Position = Vector3.new(dp.X, dp.Y + 6, dp.Z) }
|
||
TweenService:Create(door, TweenInfo.new(1.2), goal):Play()
|
||
door.CanCollide = false
|
||
end
|
||
else
|
||
__rbxl_show_text("Верно! Дальше...", 1)
|
||
end
|
||
end)
|
||
|
||
local winEvent = getEvent("WinReached")
|
||
winEvent.Event:Connect(function()
|
||
if won then return end
|
||
won = true
|
||
__rbxl_show_text("Победа! Ты разгадал код!", 5)
|
||
winSound:Play()
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g12_finish: `-- === Скрипт финиша (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("WinReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
};
|
||
// 4 кнопки — каждая шлёт свой номер при нажатии E (если игрок рядом)
|
||
for (let num = 1; num <= 4; num++) {
|
||
overrides['g12_btn_' + num] = `-- === Скрипт кнопки-цифры ${num} (Lua) ===
|
||
local UserInputService = game:GetService("UserInputService")
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local RunService = game:GetService("RunService")
|
||
local part = script.Parent
|
||
local hintVisible = false
|
||
|
||
-- Подсказка над кнопкой (виден когда игрок рядом)
|
||
local hintGui = Instance.new("BillboardGui", part)
|
||
hintGui.Size = UDim2.new(4, 0, 1, 0)
|
||
hintGui.StudsOffset = Vector3.new(0, 1.5, 0)
|
||
hintGui.AlwaysOnTop = true
|
||
local label = Instance.new("TextLabel", hintGui)
|
||
label.Size = UDim2.new(1, 0, 1, 0)
|
||
label.BackgroundTransparency = 1
|
||
label.TextColor3 = Color3.fromRGB(255, 255, 255)
|
||
label.TextStrokeTransparency = 0
|
||
label.TextScaled = true
|
||
label.Text = "[E] Нажать ${num}"
|
||
label.Visible = false
|
||
|
||
-- Каждый кадр проверяем дистанцию до игрока
|
||
RunService.Heartbeat:Connect(function()
|
||
local px = __rbxl_player_x()
|
||
local pz = __rbxl_player_z()
|
||
local dx = part.Position.X - px
|
||
local dz = part.Position.Z - pz
|
||
local dist = math.sqrt(dx*dx + dz*dz)
|
||
local near = dist <= 3
|
||
if near ~= hintVisible then
|
||
hintVisible = near
|
||
label.Visible = near
|
||
end
|
||
end)
|
||
|
||
UserInputService.InputBegan:Connect(function(input, gp)
|
||
if gp then return end
|
||
if not hintVisible then return end
|
||
if input.KeyCode ~= Enum.KeyCode.E then return end
|
||
local ev = ReplicatedStorage:FindFirstChild("ButtonPress")
|
||
if ev then ev:Fire(${num}) end
|
||
end)`;
|
||
}
|
||
return overrides;
|
||
})(),
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 13 — «Торговец»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'trader': {
|
||
g13_main: `-- === ИГРА «ТОРГОВЕЦ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local Players = game:GetService("Players")
|
||
local TweenService = game:GetService("TweenService")
|
||
local player = Players.LocalPlayer
|
||
local hasKey = false
|
||
local won = false
|
||
|
||
__rbxl_show_text("Поговори с торговцем — нажми E у прилавка", 4)
|
||
|
||
local pickupSound = Instance.new("Sound", workspace)
|
||
pickupSound.SoundId = "pickup"; pickupSound.Volume = 0.8
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
-- Спавним NPC-торговца за прилавком (паритет с JS spawnNpc)
|
||
local traderRef = __rbxl_spawn_npc("character-a", 0, 1, 5, "Торговец Боб", 100, 0)
|
||
|
||
-- Определяем итем "Ключ" в инвентаре и показываем hotbar
|
||
__rbxl_inventory_define("key", "Ключ", "#ffd700")
|
||
|
||
-- Игрок заговорил с торговцем
|
||
local talkEvent = getEvent("TalkTrader")
|
||
talkEvent.Event:Connect(function()
|
||
if hasKey then
|
||
__rbxl_npc_say(traderRef, "Иди к двери, ключ у тебя!", 3)
|
||
return
|
||
end
|
||
hasKey = true
|
||
__rbxl_npc_say(traderRef, "Привет! Вот тебе ключ от двери. Удачи!", 4)
|
||
__rbxl_inventory_add("key", 1)
|
||
__rbxl_show_text("Ты получил Ключ!", 2)
|
||
pickupSound:Play()
|
||
end)
|
||
|
||
-- Игрок пытается открыть дверь
|
||
local openEvent = getEvent("OpenDoor")
|
||
openEvent.Event:Connect(function()
|
||
if not __rbxl_inventory_has("key") then
|
||
__rbxl_show_text("Дверь заперта. Нужен ключ от торговца.", 2)
|
||
return
|
||
end
|
||
__rbxl_show_text("Ключ подошёл! Дверь открыта.", 3)
|
||
winSound:Play()
|
||
local door = workspace:FindFirstChild("Дверь")
|
||
if door then
|
||
local dp = door.Position
|
||
local goal = { Position = Vector3.new(dp.X, dp.Y + 6, dp.Z) }
|
||
TweenService:Create(door, TweenInfo.new(1.2), goal):Play()
|
||
door.CanCollide = false
|
||
end
|
||
end)
|
||
|
||
-- Игрок встал на финиш
|
||
local winEvent = getEvent("WinReached")
|
||
winEvent.Event:Connect(function()
|
||
if won then return end
|
||
won = true
|
||
__rbxl_show_text("Победа! Ты прошёл лавку торговца!", 5)
|
||
winSound:Play()
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g13_counter: `-- === Скрипт прилавка (Lua) ===
|
||
-- Подойди и нажми E чтобы поговорить с торговцем.
|
||
local UserInputService = game:GetService("UserInputService")
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local RunService = game:GetService("RunService")
|
||
local part = script.Parent
|
||
local hintVisible = false
|
||
|
||
RunService.Heartbeat:Connect(function()
|
||
local px = __rbxl_player_x()
|
||
local pz = __rbxl_player_z()
|
||
local dx = part.Position.X - px
|
||
local dz = part.Position.Z - pz
|
||
local dist = math.sqrt(dx*dx + dz*dz)
|
||
local near = dist <= 4
|
||
if near ~= hintVisible then
|
||
hintVisible = near
|
||
if near then
|
||
__rbxl_hud_set("g13_counter_hint", "[E] Поговорить с торговцем", 50, 75, "#ffe44a", 20)
|
||
else
|
||
__rbxl_hud_set("g13_counter_hint", nil)
|
||
end
|
||
end
|
||
end)
|
||
|
||
UserInputService.InputBegan:Connect(function(input, gp)
|
||
if gp then return end
|
||
if not hintVisible then return end
|
||
if input.KeyCode ~= Enum.KeyCode.E then return end
|
||
local ev = ReplicatedStorage:FindFirstChild("TalkTrader")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
g13_door: `-- === Скрипт двери (Lua) ===
|
||
-- Подойди и нажми E чтобы открыть дверь (нужен ключ).
|
||
local UserInputService = game:GetService("UserInputService")
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local RunService = game:GetService("RunService")
|
||
local part = script.Parent
|
||
local hintVisible = false
|
||
|
||
RunService.Heartbeat:Connect(function()
|
||
local px = __rbxl_player_x()
|
||
local pz = __rbxl_player_z()
|
||
local dx = part.Position.X - px
|
||
local dz = part.Position.Z - pz
|
||
local dist = math.sqrt(dx*dx + dz*dz)
|
||
local near = dist <= 4
|
||
if near ~= hintVisible then
|
||
hintVisible = near
|
||
if near then
|
||
__rbxl_hud_set("g13_door_hint", "[E] Открыть дверь", 50, 75, "#ffe44a", 20)
|
||
else
|
||
__rbxl_hud_set("g13_door_hint", nil)
|
||
end
|
||
end
|
||
end)
|
||
|
||
UserInputService.InputBegan:Connect(function(input, gp)
|
||
if gp then return end
|
||
if not hintVisible then return end
|
||
if input.KeyCode ~= Enum.KeyCode.E then return end
|
||
local ev = ReplicatedStorage:FindFirstChild("OpenDoor")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
g13_finish: `-- === Скрипт финиша (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("WinReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 14 — «Собери по тегу»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'collect-by-tag': (function() {
|
||
const TOTAL = 7;
|
||
const overrides = {
|
||
g14_main: `-- === ИГРА «СОБЕРИ ПО ТЕГАМ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local CollectionService = game:GetService("CollectionService")
|
||
local Players = game:GetService("Players")
|
||
local player = Players.LocalPlayer
|
||
local TOTAL = ${TOTAL}
|
||
local won = false
|
||
|
||
__rbxl_show_text("Собери все ЖЁЛТЫЕ звёзды!", 3)
|
||
|
||
-- Счётчик в правом верхнем углу
|
||
local screenGui = Instance.new("ScreenGui", player.PlayerGui)
|
||
local label = Instance.new("TextLabel", screenGui)
|
||
label.Size = UDim2.new(0, 220, 0, 50)
|
||
label.Position = UDim2.new(1, -240, 0, 20)
|
||
label.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
|
||
label.BackgroundTransparency = 0.4
|
||
label.TextColor3 = Color3.fromRGB(255, 215, 0)
|
||
label.TextScaled = true
|
||
label.Font = Enum.Font.SourceSansBold
|
||
label.Text = "Звёзды: 0 / " .. TOTAL
|
||
|
||
local coinSound = Instance.new("Sound", workspace)
|
||
coinSound.SoundId = "coin"; coinSound.Volume = 0.8
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
-- Помечаем все звёзды тегом 'звезда' (с небольшой задержкой —
|
||
-- скрипты звёзд должны успеть запуститься и зарегистрировать part).
|
||
task.delay(0.2, function()
|
||
for i = 1, TOTAL do
|
||
local star = workspace:FindFirstChild("Звезда_" .. i)
|
||
if star then CollectionService:AddTag(star, "звезда") end
|
||
end
|
||
end)
|
||
|
||
-- Звёзды сообщают о сборе. Главный скрипт считает оставшиеся через
|
||
-- CollectionService:GetTagged — паритет с JS game.scene.getTagged.
|
||
local collectEvent = getEvent("StarCollected")
|
||
collectEvent.Event:Connect(function()
|
||
if won then return end
|
||
local left = #CollectionService:GetTagged("звезда")
|
||
label.Text = "Звёзды: " .. (TOTAL - left) .. " / " .. TOTAL
|
||
coinSound:Play()
|
||
if left == 0 then
|
||
won = true
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Все звёзды собраны!", 5)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end
|
||
end)`,
|
||
};
|
||
// Скрипт каждой звезды — одинаковый: на touch → untag + destroy + Fire
|
||
const starScript = `-- === Скрипт звезды (Lua) ===
|
||
local CollectionService = game:GetService("CollectionService")
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local picked = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if picked then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
picked = true
|
||
-- Снимаем тег и удаляем звезду, потом шлём событие.
|
||
CollectionService:RemoveTag(part, "звезда")
|
||
part:Destroy()
|
||
local ev = ReplicatedStorage:FindFirstChild("StarCollected")
|
||
if ev then ev:Fire() end
|
||
end)`;
|
||
for (let i = 1; i <= TOTAL; i++) {
|
||
overrides['g14_star_' + i] = starScript;
|
||
}
|
||
return overrides;
|
||
})(),
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 15 — «Тир»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'shooting-range': (function() {
|
||
// Мишени имеют id 2, 4, 6, 8, 10, 12, 14, 16 (постамент → нечётный, мишень → чётный)
|
||
const TARGET_IDS = [2, 4, 6, 8, 10, 12, 14, 16];
|
||
const TOTAL = TARGET_IDS.length;
|
||
const overrides = {
|
||
g15_main: `-- === ИГРА «ТИР» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local Players = game:GetService("Players")
|
||
local player = Players.LocalPlayer
|
||
local score = 0
|
||
local TOTAL = ${TOTAL}
|
||
local won = false
|
||
|
||
__rbxl_show_text("Кликай по красным мишеням!", 3)
|
||
|
||
-- Счётчик в правом верхнем углу
|
||
local screenGui = Instance.new("ScreenGui", player.PlayerGui)
|
||
local label = Instance.new("TextLabel", screenGui)
|
||
label.Size = UDim2.new(0, 220, 0, 50)
|
||
label.Position = UDim2.new(1, -240, 0, 20)
|
||
label.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
|
||
label.BackgroundTransparency = 0.4
|
||
label.TextColor3 = Color3.fromRGB(255, 100, 100)
|
||
label.TextScaled = true
|
||
label.Font = Enum.Font.SourceSansBold
|
||
label.Text = "Мишени: 0 / " .. TOTAL
|
||
|
||
local hitSound = Instance.new("Sound", workspace)
|
||
hitSound.SoundId = "hit"; hitSound.Volume = 0.7
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
local hitEvent = getEvent("TargetHit")
|
||
hitEvent.Event:Connect(function()
|
||
if won then return end
|
||
score = score + 1
|
||
label.Text = "Мишени: " .. score .. " / " .. TOTAL
|
||
hitSound:Play()
|
||
if score >= TOTAL then
|
||
won = true
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Все мишени выбиты!", 5)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end
|
||
end)`,
|
||
};
|
||
// Скрипт каждой мишени — ClickDetector + взрыв искр + сообщение
|
||
const targetScript = `-- === Скрипт мишени (Lua) ===
|
||
-- Клик ЛКМ по мишени = выстрел. ClickDetector ловит клик в 3D.
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local hit = false
|
||
|
||
local clickDet = Instance.new("ClickDetector", part)
|
||
clickDet.MaxActivationDistance = 50
|
||
|
||
clickDet.MouseClick:Connect(function()
|
||
if hit then return end
|
||
hit = true
|
||
-- Взрыв искр на месте мишени
|
||
local pos = part.Position
|
||
__rbxl_spawn_particles("explosion", pos.X, pos.Y, pos.Z, 0.5, 1)
|
||
-- Сообщаем главному скрипту
|
||
local ev = ReplicatedStorage:FindFirstChild("TargetHit")
|
||
if ev then ev:Fire() end
|
||
-- Мишень исчезает
|
||
part:Destroy()
|
||
end)`;
|
||
for (const tid of TARGET_IDS) {
|
||
overrides['g15_target_' + tid] = targetScript;
|
||
}
|
||
return overrides;
|
||
})(),
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 16 — «Лавовый пол»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'lava-floor': {
|
||
g16_main: `-- === ИГРА «ЛАВА-ПОЛ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local Players = game:GetService("Players")
|
||
local RunService = game:GetService("RunService")
|
||
local player = Players.LocalPlayer
|
||
local won = false
|
||
|
||
__rbxl_show_text("Прыгай по островкам! Лава жжёт!", 3)
|
||
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
-- Если упал в озеро вниз — респаун
|
||
RunService.Heartbeat:Connect(function()
|
||
if won then return end
|
||
local py = __rbxl_player_y()
|
||
if py < -2 then
|
||
player:LoadCharacter()
|
||
end
|
||
end)
|
||
|
||
-- Финиш сообщает о победе
|
||
local winEvent = getEvent("WinReached")
|
||
winEvent.Event:Connect(function()
|
||
if won then return end
|
||
won = true
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Ты перебрался через лаву!", 5)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g16_lava: `-- === Скрипт лавы (Lua) ===
|
||
-- Игрок коснулся лавы — урон. У damage есть защита (i-frames),
|
||
-- так что урон не каждый кадр, а раз в ~0.5 секунды.
|
||
-- ВАЖНО: проверяем что игрок НЕ над островком (по X/Z),
|
||
-- иначе урон срабатывает на островке из-за пересечения AABB.
|
||
local RunService = game:GetService("RunService")
|
||
local part = script.Parent
|
||
local hitSound = Instance.new("Sound", part)
|
||
hitSound.SoundId = "hit"; hitSound.Volume = 0.7
|
||
|
||
-- Координаты островков (из builder): { x, z }
|
||
local ISLES = {
|
||
{0, 5}, {3, 9}, {-2, 13}, {2, 17}, {-3, 21}, {1, 25},
|
||
}
|
||
local ISLE_HW = 1.4 -- половина ширины островка sx=2.4/2 + небольшой запас
|
||
local FINISH_X, FINISH_Z = -0.5, 29
|
||
local FINISH_HW, FINISH_HD = 3, 2.5
|
||
|
||
local function isOverSafeSpot()
|
||
local px = __rbxl_player_x()
|
||
local pz = __rbxl_player_z()
|
||
-- Островки
|
||
for _, isle in ipairs(ISLES) do
|
||
if math.abs(px - isle[1]) <= ISLE_HW
|
||
and math.abs(pz - isle[2]) <= ISLE_HW then
|
||
return true
|
||
end
|
||
end
|
||
-- Финишная площадка
|
||
if math.abs(px - FINISH_X) <= FINISH_HW
|
||
and math.abs(pz - FINISH_Z) <= FINISH_HD then
|
||
return true
|
||
end
|
||
return false
|
||
end
|
||
|
||
-- Проверяем каждый кадр пока игрок касается лавы — наносим урон если он
|
||
-- НЕ над безопасным местом. Touched нам не нужен — лучше Heartbeat-проверка.
|
||
local inLava = false
|
||
part.Touched:Connect(function(hit)
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
inLava = true
|
||
end)
|
||
part.TouchEnded:Connect(function(hit)
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
inLava = false
|
||
end)
|
||
|
||
RunService.Heartbeat:Connect(function()
|
||
if not inLava then return end
|
||
if isOverSafeSpot() then return end -- стоит над островком/финишем
|
||
__rbxl_damage_player(20)
|
||
hitSound:Play()
|
||
end)`,
|
||
g16_finish: `-- === Скрипт финиша (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("WinReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 17 — «Ключ от сундука»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'key-chest': {
|
||
g17_main: `-- === ИГРА «КЛЮЧ И СУНДУК» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local won = false
|
||
|
||
__rbxl_show_text("Найди ключ и открой сундук!", 3)
|
||
|
||
local pickupSound = Instance.new("Sound", workspace)
|
||
pickupSound.SoundId = "pickup"; pickupSound.Volume = 0.8
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
local loseSound = Instance.new("Sound", workspace)
|
||
loseSound.SoundId = "lose"; loseSound.Volume = 0.6
|
||
|
||
-- Определяем итем "Ключ" в инвентаре (показывает иконку в hotbar)
|
||
__rbxl_inventory_define("key", "Ключ", "#ffd700")
|
||
|
||
-- Игрок подобрал ключ
|
||
local takeEvent = getEvent("TakeKey")
|
||
takeEvent.Event:Connect(function()
|
||
__rbxl_inventory_add("key", 1)
|
||
__rbxl_show_text("Ты нашёл Ключ!", 2)
|
||
pickupSound:Play()
|
||
end)
|
||
|
||
-- Игрок пытается открыть сундук
|
||
local openEvent = getEvent("OpenChest")
|
||
openEvent.Event:Connect(function()
|
||
if won then return end
|
||
if not __rbxl_inventory_has("key") then
|
||
__rbxl_show_text("Сундук заперт. Сначала найди ключ.", 2)
|
||
loseSound:Play()
|
||
return
|
||
end
|
||
won = true
|
||
__rbxl_show_text("Победа! Сундук открыт — там сокровище!", 5)
|
||
winSound:Play()
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g17_key: `-- === Скрипт ключа (Lua) ===
|
||
-- При касании игроком — отправляем событие и удаляем ключ.
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local taken = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if taken then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
taken = true
|
||
local ev = ReplicatedStorage:FindFirstChild("TakeKey")
|
||
if ev then ev:Fire() end
|
||
part:Destroy()
|
||
end)`,
|
||
g17_chest: `-- === Скрипт сундука (Lua) ===
|
||
-- Подойти и нажать E чтобы открыть.
|
||
local UserInputService = game:GetService("UserInputService")
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local RunService = game:GetService("RunService")
|
||
local part = script.Parent
|
||
local hintVisible = false
|
||
|
||
RunService.Heartbeat:Connect(function()
|
||
local px = __rbxl_player_x()
|
||
local pz = __rbxl_player_z()
|
||
local dx = part.Position.X - px
|
||
local dz = part.Position.Z - pz
|
||
local dist = math.sqrt(dx*dx + dz*dz)
|
||
local near = dist <= 4
|
||
if near ~= hintVisible then
|
||
hintVisible = near
|
||
if near then
|
||
__rbxl_hud_set("g17_chest_hint", "[E] Открыть сундук", 50, 75, "#ffe44a", 20)
|
||
else
|
||
__rbxl_hud_set("g17_chest_hint", nil)
|
||
end
|
||
end
|
||
end)
|
||
|
||
UserInputService.InputBegan:Connect(function(input, gp)
|
||
if gp then return end
|
||
if not hintVisible then return end
|
||
if input.KeyCode ~= Enum.KeyCode.E then return end
|
||
local ev = ReplicatedStorage:FindFirstChild("OpenChest")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 18 — «Качели»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'swing': {
|
||
g18_main: `-- === ИГРА «КАЧЕЛИ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local Players = game:GetService("Players")
|
||
local RunService = game:GetService("RunService")
|
||
local player = Players.LocalPlayer
|
||
local won = false
|
||
|
||
__rbxl_show_text("Запрыгни на качели и прокатись!", 3)
|
||
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
-- Раскачиваем качели туда-сюда через изменение Position.Z.
|
||
-- WaitForChild может зависнуть — берём напрямую с задержкой.
|
||
local swing = nil
|
||
local startZ = 0
|
||
|
||
task.delay(0.2, function()
|
||
swing = workspace:FindFirstChild("Качели")
|
||
if swing then
|
||
startZ = swing.Position.Z
|
||
end
|
||
end)
|
||
|
||
local elapsed = 0
|
||
RunService.Heartbeat:Connect(function(dt)
|
||
if won then return end
|
||
if not swing then return end
|
||
elapsed = elapsed + (dt or 0.016)
|
||
-- Синусоидальное качание с амплитудой 4 и периодом ~2.8 сек
|
||
local amp = 4
|
||
local period = 2.8
|
||
local offsetZ = amp * math.sin(elapsed * 2 * math.pi / period)
|
||
local pos = swing.Position
|
||
swing.Position = Vector3.new(pos.X, pos.Y, startZ + offsetZ)
|
||
|
||
-- Если упал — респаун
|
||
local py = __rbxl_player_y()
|
||
if py < -3 then
|
||
player:LoadCharacter()
|
||
end
|
||
end)
|
||
|
||
-- Финиш сообщает о победе
|
||
local winEvent = getEvent("WinReached")
|
||
winEvent.Event:Connect(function()
|
||
if won then return end
|
||
won = true
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Ты перебрался на качелях!", 5)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g18_finish: `-- === Скрипт финиша (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("WinReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 19 — «Лифт»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'elevator': {
|
||
g19_main: `-- === ИГРА «ЛИФТ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local Players = game:GetService("Players")
|
||
local RunService = game:GetService("RunService")
|
||
local player = Players.LocalPlayer
|
||
local won = false
|
||
|
||
__rbxl_show_text("Встань на синий лифт — он повезёт наверх", 3)
|
||
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
-- Лифт ездит вверх-вниз. WaitForChild зависает, поэтому FindFirstChild
|
||
-- с задержкой через task.delay.
|
||
local lift = nil
|
||
local startY = 1
|
||
local TOP_Y = 12.3
|
||
local PERIOD = 7 -- полный цикл вниз→вверх→вниз (3.5с вверх + 3.5с вниз)
|
||
local elapsed = 0
|
||
|
||
task.delay(0.2, function()
|
||
lift = workspace:FindFirstChild("Лифт")
|
||
if lift then startY = lift.Position.Y end
|
||
end)
|
||
|
||
RunService.Heartbeat:Connect(function(dt)
|
||
if won then return end
|
||
dt = dt or 0.016
|
||
-- Лифт двигается
|
||
if lift then
|
||
elapsed = elapsed + dt
|
||
-- Yo-yo: 0..PERIOD/2 — вверх, PERIOD/2..PERIOD — вниз
|
||
local t = (elapsed % PERIOD) / PERIOD
|
||
local k
|
||
if t < 0.5 then
|
||
k = t * 2 -- 0..1
|
||
else
|
||
k = (1 - t) * 2 -- 1..0
|
||
end
|
||
local y = startY + (TOP_Y - startY) * k
|
||
local pos = lift.Position
|
||
lift.Position = Vector3.new(pos.X, y, pos.Z)
|
||
end
|
||
-- Падение
|
||
local py = __rbxl_player_y()
|
||
if py < -3 then
|
||
player:LoadCharacter()
|
||
end
|
||
end)
|
||
|
||
-- Финиш
|
||
local winEvent = getEvent("WinReached")
|
||
winEvent.Event:Connect(function()
|
||
if won then return end
|
||
won = true
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Ты поднялся на лифте!", 5)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g19_finish: `-- === Скрипт финиша (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("WinReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 20 — «Имена врагов»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'enemy-names': {
|
||
g20_main: `-- === ИГРА «ИМЕНА НАД ВРАГАМИ» — главный скрипт (Lua) ===
|
||
local UserInputService = game:GetService("UserInputService")
|
||
|
||
__rbxl_show_text("Победи всех врагов! Кликай по ним", 3)
|
||
|
||
local hitSound = Instance.new("Sound", workspace)
|
||
hitSound.SoundId = "hit"; hitSound.Volume = 0.6
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
-- Данные врагов: имя, позиция, HP
|
||
local enemies = {
|
||
{ name = "Гоблин", x = -5, z = 3, hp = 60, maxHp = 60, ref = nil },
|
||
{ name = "Скелет", x = 4, z = 5, hp = 80, maxHp = 80, ref = nil },
|
||
{ name = "Орк", x = 0, z = 8, hp = 100, maxHp = 100, ref = nil },
|
||
}
|
||
|
||
local alive = #enemies
|
||
local won = false
|
||
|
||
-- Спавним всех врагов и метки над ними
|
||
for i, e in ipairs(enemies) do
|
||
e.ref = __rbxl_spawn_npc("character-b", e.x, 1, e.z, e.name, e.hp, 0)
|
||
__rbxl_set_label(e.ref, e.name .. " HP: " .. e.hp, "#ff5555", 2.5)
|
||
-- Callback на смерть NPC
|
||
__rbxl_npc_on_death(e.ref, function()
|
||
if e._dead then return end
|
||
e._dead = true
|
||
__rbxl_clear_label(e.ref)
|
||
alive = alive - 1
|
||
hitSound:Play()
|
||
if alive <= 0 and not won then
|
||
won = true
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Все враги повержены!", 5)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end
|
||
end)
|
||
end
|
||
|
||
-- Клик по конкретному NPC (как в Тире — pick по 3D-объекту).
|
||
-- BabylonScene выполняет raycast при ЛКМ и шлёт click с target=NPC.
|
||
-- Регистрируем callback для каждого врага по его локальному ref.
|
||
for _, e in ipairs(enemies) do
|
||
local enemy = e -- замыкание
|
||
__rbxl_npc_on_click(enemy.ref, function()
|
||
if enemy._dead or won then return end
|
||
enemy.hp = enemy.hp - 30
|
||
if enemy.hp < 0 then enemy.hp = 0 end
|
||
__rbxl_npc_damage(enemy.ref, 30)
|
||
__rbxl_set_label(enemy.ref, enemy.name .. " HP: " .. enemy.hp, "#ff5555", 2.5)
|
||
__rbxl_spawn_particles("sparks", enemy.x, 2, enemy.z, 0.4, 1)
|
||
hitSound:Play()
|
||
end)
|
||
end`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 21 — «Догонялки»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'chaser': {
|
||
g21_main: `-- === ИГРА «ПРЕСЛЕДОВАТЕЛЬ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local Players = game:GetService("Players")
|
||
local RunService = game:GetService("RunService")
|
||
local player = Players.LocalPlayer
|
||
local won = false
|
||
|
||
__rbxl_show_text("Убегай от врага! Добеги до укрытия!", 3)
|
||
|
||
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
|
||
|
||
-- Спавним NPC-преследователя (speed=4, follow за игроком)
|
||
local enemyRef = __rbxl_spawn_npc("character-b", 0, 1, -3, "Охотник", 100, 4)
|
||
-- Велим NPC следовать за игроком
|
||
__rbxl_npc_follow(enemyRef, "player")
|
||
|
||
-- Каждый кадр проверяем — не догнал ли враг
|
||
local lastCaughtTime = 0
|
||
RunService.Heartbeat:Connect(function()
|
||
if won then return end
|
||
local px = __rbxl_player_x()
|
||
local pz = __rbxl_player_z()
|
||
local ex = __rbxl_npc_x(enemyRef)
|
||
local ez = __rbxl_npc_z(enemyRef)
|
||
-- Если позиции NPC ещё не пришли (ex=0,ez=0 = до спавна) — пропускаем
|
||
if ex == 0 and ez == 0 then return end
|
||
local dx = px - ex
|
||
local dz = pz - ez
|
||
local dist = math.sqrt(dx*dx + dz*dz)
|
||
if dist < 1.6 then
|
||
local now = tick()
|
||
if now - lastCaughtTime > 2 then
|
||
lastCaughtTime = now
|
||
player:LoadCharacter()
|
||
__rbxl_show_text("Пойман! Беги снова!", 2)
|
||
loseSound:Play()
|
||
end
|
||
end
|
||
end)
|
||
|
||
-- Финиш сообщает о победе
|
||
local winEvent = getEvent("WinReached")
|
||
winEvent.Event:Connect(function()
|
||
if won then return end
|
||
won = true
|
||
__rbxl_npc_stop(enemyRef)
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Ты убежал от врага!", 5)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g21_finish: `-- === Скрипт финиша (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("WinReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 22 — «Опасная зона»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'danger-zone': {
|
||
g22_main: `-- === ИГРА «ЗОНА ОПАСНОСТИ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local RunService = game:GetService("RunService")
|
||
local inZone = false
|
||
local won = false
|
||
local damageTimer = 0
|
||
|
||
__rbxl_show_text("Пробеги через красную зону к финишу!", 3)
|
||
|
||
local hitSound = Instance.new("Sound", workspace)
|
||
hitSound.SoundId = "hit"; hitSound.Volume = 0.6
|
||
local winSound = Instance.new("Sound", workspace)
|
||
winSound.SoundId = "win"; winSound.Volume = 1
|
||
|
||
-- Слушатели событий зоны
|
||
local enterEvent = getEvent("ZoneEnter")
|
||
enterEvent.Event:Connect(function()
|
||
inZone = true
|
||
__rbxl_show_text("Опасно! Беги быстрее!", 1.5)
|
||
end)
|
||
local leaveEvent = getEvent("ZoneLeave")
|
||
leaveEvent.Event:Connect(function()
|
||
inZone = false
|
||
end)
|
||
|
||
-- Урон каждые 0.6с пока игрок в зоне
|
||
RunService.Heartbeat:Connect(function(dt)
|
||
if won then return end
|
||
if not inZone then return end
|
||
damageTimer = damageTimer + (dt or 0.016)
|
||
if damageTimer >= 0.6 then
|
||
damageTimer = 0
|
||
__rbxl_damage_player(12)
|
||
hitSound:Play()
|
||
end
|
||
end)
|
||
|
||
-- Финиш сообщает о победе
|
||
local winEvent = getEvent("WinReached")
|
||
winEvent.Event:Connect(function()
|
||
if won then return end
|
||
won = true
|
||
winSound:Play()
|
||
__rbxl_show_text("Победа! Ты прошёл зону опасности!", 5)
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g22_zone: `-- === Скрипт зоны опасности (Lua) ===
|
||
-- Touched при входе, TouchEnded при выходе.
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
|
||
part.Touched:Connect(function(hit)
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
local ev = ReplicatedStorage:FindFirstChild("ZoneEnter")
|
||
if ev then ev:Fire() end
|
||
end)
|
||
part.TouchEnded:Connect(function(hit)
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
local ev = ReplicatedStorage:FindFirstChild("ZoneLeave")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
g22_heal: `-- === Скрипт аптечки (Lua) ===
|
||
local part = script.Parent
|
||
local taken = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if taken then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
taken = true
|
||
-- Лечим на 60 HP (через damage с отрицательным значением неудобно;
|
||
-- используем напрямую player.Health прибавлением).
|
||
__rbxl_heal_player(60)
|
||
__rbxl_show_text("+60 HP", 1.5)
|
||
local pickupSound = Instance.new("Sound", part)
|
||
pickupSound.SoundId = "pickup"; pickupSound.Volume = 0.8
|
||
pickupSound:Play()
|
||
part:Destroy()
|
||
end)`,
|
||
g22_finish: `-- === Скрипт финиша (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("WinReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 23 — «3 переключателя»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'switches': (function() {
|
||
const overrides = {
|
||
g23_main: `-- === ИГРА «ПЕРЕКЛЮЧАТЕЛИ» — главный скрипт (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local TweenService = game:GetService("TweenService")
|
||
local ORDER = { 2, 3, 1 } -- правильный порядок рычагов
|
||
local pressed = {}
|
||
local opened = false
|
||
local won = false
|
||
|
||
__rbxl_show_text("Дёрни рычаги в нужном порядке (E)", 4)
|
||
|
||
local clickSound = Instance.new("Sound", workspace)
|
||
clickSound.SoundId = "click"; clickSound.Volume = 0.7
|
||
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
|
||
|
||
-- Рычаги шлют ev:Fire(num) с номером
|
||
local leverEvent = getEvent("LeverPulled")
|
||
leverEvent.Event:Connect(function(num)
|
||
if opened then return end
|
||
clickSound:Play()
|
||
table.insert(pressed, num)
|
||
local i = #pressed
|
||
if pressed[i] ~= ORDER[i] then
|
||
pressed = {}
|
||
__rbxl_show_text("Неверно! Рычаги сброшены.", 1.5)
|
||
loseSound:Play()
|
||
return
|
||
end
|
||
if #pressed == #ORDER then
|
||
opened = true
|
||
__rbxl_show_text("Верно! Дверь открыта.", 3)
|
||
winSound:Play()
|
||
local door = workspace:FindFirstChild("Дверь")
|
||
if door then
|
||
local dp = door.Position
|
||
local goal = { Position = Vector3.new(dp.X, dp.Y + 6, dp.Z) }
|
||
TweenService:Create(door, TweenInfo.new(1.2), goal):Play()
|
||
door.CanCollide = false
|
||
end
|
||
else
|
||
__rbxl_show_text("Так держать!", 1)
|
||
end
|
||
end)
|
||
|
||
-- Финиш
|
||
local winEvent = getEvent("WinReached")
|
||
winEvent.Event:Connect(function()
|
||
if won then return end
|
||
won = true
|
||
__rbxl_show_text("Победа! Ты разгадал порядок!", 5)
|
||
winSound:Play()
|
||
local px = __rbxl_player_x()
|
||
local py = __rbxl_player_y()
|
||
local pz = __rbxl_player_z()
|
||
__rbxl_spawn_particles("confetti", px, py + 3, pz, 3, 3)
|
||
end)`,
|
||
g23_finish: `-- === Скрипт финиша (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
local fired = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if fired then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fired = true
|
||
local ev = ReplicatedStorage:FindFirstChild("WinReached")
|
||
if ev then ev:Fire() end
|
||
end)`,
|
||
};
|
||
// 3 рычага — каждый ждёт E когда игрок рядом, шлёт свой номер
|
||
for (let n = 1; n <= 3; n++) {
|
||
overrides['g23_lever_' + n] = `-- === Скрипт рычага ${n} (Lua) ===
|
||
local UserInputService = game:GetService("UserInputService")
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local RunService = game:GetService("RunService")
|
||
local part = script.Parent
|
||
local hintVisible = false
|
||
|
||
RunService.Heartbeat:Connect(function()
|
||
local px = __rbxl_player_x()
|
||
local pz = __rbxl_player_z()
|
||
local dx = part.Position.X - px
|
||
local dz = part.Position.Z - pz
|
||
local dist = math.sqrt(dx*dx + dz*dz)
|
||
local near = dist <= 3
|
||
if near ~= hintVisible then
|
||
hintVisible = near
|
||
if near then
|
||
__rbxl_hud_set("g23_lever_${n}_hint", "[E] Дёрнуть рычаг ${n}", 50, 75, "#ffe44a", 20)
|
||
else
|
||
__rbxl_hud_set("g23_lever_${n}_hint", nil)
|
||
end
|
||
end
|
||
end)
|
||
|
||
UserInputService.InputBegan:Connect(function(input, gp)
|
||
if gp then return end
|
||
if not hintVisible then return end
|
||
if input.KeyCode ~= Enum.KeyCode.E then return end
|
||
local ev = ReplicatedStorage:FindFirstChild("LeverPulled")
|
||
if ev then ev:Fire(${n}) end
|
||
end)`;
|
||
}
|
||
return overrides;
|
||
})(),
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 24 — «Падающий мост»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'falling-bridge': {
|
||
g24_main: `-- === ИГРА «ПАДАЮЩИЙ МОСТ» (Lua) ===
|
||
print("Беги по мосту — плиты падают!")`,
|
||
g24_plate: `-- === Скрипт падающей плиты (Lua) ===
|
||
local part = script.Parent
|
||
local fell = false
|
||
part.Touched:Connect(function(hit)
|
||
if fell then return end
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
fell = true
|
||
task.delay(0.5, function()
|
||
part.Anchored = false
|
||
part.CanCollide = false
|
||
game:GetService("Debris"):AddItem(part, 3)
|
||
end)
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 25 — «Облёт камеры»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'flyby-camera': {
|
||
g25_main: `-- === ИГРА «ОБЛЁТ КАМЕРЫ» (Lua) ===
|
||
local TweenService = game:GetService("TweenService")
|
||
local camera = workspace.CurrentCamera
|
||
camera.CameraType = Enum.CameraType.Scriptable
|
||
|
||
local points = {
|
||
CFrame.new(Vector3.new(0, 20, -30), Vector3.new(0, 5, 0)),
|
||
CFrame.new(Vector3.new(20, 15, 0), Vector3.new(0, 5, 0)),
|
||
CFrame.new(Vector3.new(0, 25, 30), Vector3.new(0, 5, 0)),
|
||
}
|
||
|
||
for _, cf in ipairs(points) do
|
||
local tween = TweenService:Create(camera, TweenInfo.new(2), { CFrame = cf })
|
||
tween:Play(); tween.Completed:Wait()
|
||
end
|
||
|
||
camera.CameraType = Enum.CameraType.Custom
|
||
print("Облёт окончен — теперь играй!")`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 26 — «Магнит монет»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'coin-magnet': {
|
||
g26_main: `-- === ИГРА «МАГНИТ МОНЕТ» (Lua) ===
|
||
local Players = game:GetService("Players")
|
||
local RunService = game:GetService("RunService")
|
||
local CollectionService = game:GetService("CollectionService")
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local score = 0
|
||
local ev = getEvent("CoinCollected")
|
||
ev.Event:Connect(function()
|
||
score = score + 1
|
||
print("Собрано: " .. score)
|
||
end)
|
||
|
||
RunService.Heartbeat:Connect(function(dt)
|
||
local player = Players:GetPlayers()[1]
|
||
if not player or not player.Character then return end
|
||
local hrp = player.Character:FindFirstChild("HumanoidRootPart")
|
||
if not hrp then return end
|
||
for _, coin in ipairs(CollectionService:GetTagged("magnetcoin")) do
|
||
local dist = (coin.Position - hrp.Position).Magnitude
|
||
if dist < 8 then
|
||
coin.Position = coin.Position + (hrp.Position - coin.Position).Unit * 20 * dt
|
||
if dist < 1 then
|
||
ev:Fire()
|
||
coin:Destroy()
|
||
end
|
||
end
|
||
end
|
||
end)
|
||
print("Монетки сами летят к тебе!")`,
|
||
g26_coin: `-- === Скрипт магнит-монетки (Lua) ===
|
||
local CollectionService = game:GetService("CollectionService")
|
||
CollectionService:AddTag(script.Parent, "magnetcoin")`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 27 — «Двойной прыжок»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'double-jump': {
|
||
g27_main: `-- === ИГРА «ДВОЙНОЙ ПРЫЖОК» (Lua) ===
|
||
local Players = game:GetService("Players")
|
||
local UserInputService = game:GetService("UserInputService")
|
||
|
||
local function setupDoubleJump(player)
|
||
local jumpsLeft = 2
|
||
local char = player.Character or player.CharacterAdded:Wait()
|
||
local h = char:WaitForChild("Humanoid")
|
||
|
||
-- Восстанавливаем прыжки при касании земли
|
||
h.StateChanged:Connect(function(_, newState)
|
||
if newState == Enum.HumanoidStateType.Landed then
|
||
jumpsLeft = 2
|
||
end
|
||
end)
|
||
|
||
UserInputService.InputBegan:Connect(function(input, gp)
|
||
if gp then return end
|
||
if input.KeyCode == Enum.KeyCode.Space and jumpsLeft > 0 then
|
||
jumpsLeft = jumpsLeft - 1
|
||
if jumpsLeft == 1 then
|
||
local hrp = char:FindFirstChild("HumanoidRootPart")
|
||
if hrp then
|
||
hrp.Velocity = Vector3.new(hrp.Velocity.X, 50, hrp.Velocity.Z)
|
||
end
|
||
end
|
||
end
|
||
end)
|
||
end
|
||
|
||
Players.PlayerAdded:Connect(setupDoubleJump)
|
||
for _, p in ipairs(Players:GetPlayers()) do setupDoubleJump(p) end
|
||
print("Жми Space дважды — двойной прыжок!")`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 28 — «Призрачные стены»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'ghost-walls': {
|
||
g28_main: `-- === ИГРА «ПРИЗРАЧНЫЕ СТЕНЫ» (Lua) ===
|
||
print("Некоторые стены — призрачные. Найди проход!")`,
|
||
g28_ghost: `-- === Скрипт призрачной стены (Lua) ===
|
||
local part = script.Parent
|
||
part.CanCollide = false
|
||
part.Transparency = 0.5`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 29 — «Магазин»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'shop': {
|
||
g29_main: `-- === ИГРА «МАГАЗИН» (Lua) ===
|
||
local Players = game:GetService("Players")
|
||
Players.PlayerAdded:Connect(function(player)
|
||
local stats = Instance.new("Folder", player); stats.Name = "leaderstats"
|
||
local coins = Instance.new("IntValue", stats); coins.Name = "Монеты"; coins.Value = 20
|
||
end)
|
||
for _, p in ipairs(Players:GetPlayers()) do
|
||
if not p:FindFirstChild("leaderstats") then
|
||
local stats = Instance.new("Folder", p); stats.Name = "leaderstats"
|
||
local coins = Instance.new("IntValue", stats); coins.Name = "Монеты"; coins.Value = 20
|
||
end
|
||
end
|
||
print("У тебя 20 монет — купи что-нибудь!")`,
|
||
g29_item: `-- === Скрипт товара (Lua) ===
|
||
local Players = game:GetService("Players")
|
||
local part = script.Parent
|
||
local price = part:GetAttribute("Price") or 5
|
||
local bought = false
|
||
|
||
part.Touched:Connect(function(hit)
|
||
if bought then return end
|
||
local player = Players:GetPlayerFromCharacter(hit.Parent)
|
||
if not player then return end
|
||
local stats = player:FindFirstChild("leaderstats")
|
||
if not stats then return end
|
||
if stats['Монеты'].Value >= price then
|
||
stats['Монеты'].Value = stats['Монеты'].Value - price
|
||
bought = true
|
||
print("Куплено! Цена: " .. price)
|
||
part.Transparency = 0.7
|
||
else
|
||
print("Не хватает! Нужно " .. price .. " монет")
|
||
end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРА 30 — «Квесты»
|
||
// ═══════════════════════════════════════════════════════════════
|
||
'quest-tasks': {
|
||
g30_main: `-- === ИГРА «КВЕСТЫ» (Lua) ===
|
||
${SNIPPET_BROADCAST}
|
||
|
||
local quests = {
|
||
{ name = "Собери 5 ягод", goal = 5, current = 0 },
|
||
{ name = "Победи врага", goal = 1, current = 0 },
|
||
{ name = "Дойди до башни", goal = 1, current = 0 },
|
||
}
|
||
|
||
print("Квесты:")
|
||
for i, q in ipairs(quests) do print(" " .. i .. ". " .. q.name) end
|
||
|
||
local ev = getEvent("QuestProgress")
|
||
ev.Event:Connect(function(idx, amount)
|
||
quests[idx].current = quests[idx].current + (amount or 1)
|
||
local q = quests[idx]
|
||
print(q.name .. ": " .. q.current .. "/" .. q.goal)
|
||
if q.current >= q.goal then
|
||
print("Квест выполнен: " .. q.name)
|
||
end
|
||
end)`,
|
||
},
|
||
|
||
// ═══════════════════════════════════════════════════════════════
|
||
// ИГРЫ 31-50: явных Lua-версий пока нет.
|
||
// buildGameProject в docsGamesBuilders.js использует generateFallbackLua
|
||
// (главный скрипт → показ подсказки + слушает FinishReached →
|
||
// победа+конфетти; скрипт на финиш-примитиве → шлёт FinishReached;
|
||
// остальные target-скрипты → красят примитив на касание).
|
||
// Это даёт «хоть что-то рабочее» в любой игре до того как напишем
|
||
// полноценный Lua-скрипт. Когда дописываем игру — добавляем сюда явный override.
|
||
'clicker': { g46_main: simpleClicker() },
|
||
};
|
||
|
||
// ══════════════════════════════════════════════════════════════════
|
||
// Хелперы для генерации часто повторяющихся скриптов
|
||
// ══════════════════════════════════════════════════════════════════
|
||
|
||
/** Возвращает Lua-код скрипта монетки. */
|
||
function makeCoinScript() {
|
||
return `-- === Скрипт монетки (Lua) ===
|
||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||
local part = script.Parent
|
||
|
||
part.Touched:Connect(function(hit)
|
||
local h = hit.Parent and hit.Parent:FindFirstChild("Humanoid")
|
||
if not h then return end
|
||
local ev = ReplicatedStorage:FindFirstChild("CoinCollected")
|
||
if ev then ev:Fire() end
|
||
part:Destroy()
|
||
end)`;
|
||
}
|
||
|
||
/** Кликер. */
|
||
function simpleClicker() {
|
||
return `-- === КЛИКЕР (Lua) ===
|
||
local Players = game:GetService("Players")
|
||
local UserInputService = game:GetService("UserInputService")
|
||
|
||
Players.PlayerAdded:Connect(function(player)
|
||
local stats = Instance.new("Folder", player); stats.Name = "leaderstats"
|
||
local cnt = Instance.new("IntValue", stats); cnt.Name = "Клики"; cnt.Value = 0
|
||
end)
|
||
for _, p in ipairs(Players:GetPlayers()) do
|
||
if not p:FindFirstChild("leaderstats") then
|
||
local stats = Instance.new("Folder", p); stats.Name = "leaderstats"
|
||
local cnt = Instance.new("IntValue", stats); cnt.Name = "Клики"; cnt.Value = 0
|
||
end
|
||
end
|
||
|
||
local function onClick(player)
|
||
local stats = player:FindFirstChild("leaderstats")
|
||
if stats and stats:FindFirstChild("Клики") then
|
||
stats['Клики'].Value = stats['Клики'].Value + 1
|
||
end
|
||
end
|
||
|
||
UserInputService.InputBegan:Connect(function(input, gp)
|
||
if gp then return end
|
||
if input.UserInputType == Enum.UserInputType.MouseButton1 then
|
||
onClick(Players.LocalPlayer)
|
||
end
|
||
end)
|
||
print("Кликай ЛКМ — копи клики!")`;
|
||
}
|