46 Commits

Author SHA1 Message Date
min
59769932e5 feat(g22): полный паритет «Зона опасности»
JS:
- showText 'Пробеги через красную зону к финишу!'
- every(0.6): если inZone — damage(12) + hit
- onMessage 'zone-enter' → inZone=true + 'Опасно! Беги быстрее!'
- onMessage 'zone-leave' → inZone=false
- onMessage 'win' → 'Победа!' + win + confetti
- g22_zone: onTouch → 'zone-enter', onUntouch → 'zone-leave'
- g22_heal: onTouch → heal(60) + '+60 HP' + pickup + delete
- g22_finish: onTouch → 'win'

Lua (паритет):
- __rbxl_show_text + Sounds
- BindableEvents ZoneEnter/ZoneLeave/WinReached
- Heartbeat-таймер 0.6с для урона пока inZone
- g22_zone: Touched/TouchEnded → ev:Fire
- g22_heal: Touched → __rbxl_heal_player(60) + pickup Sound + Destroy
- g22_finish: Touched → WinReached:Fire

Shim добавил __rbxl_heal_player(amount) → cmd 'player.heal'.
2026-06-09 21:29:32 +03:00
min
ea1308d539 feat(g21): полный паритет «Преследователь» + npc.follow/stop/pos в shim
JS:
- spawnNpc 'Охотник' speed=4 follow('player')
- onTick: dist(player,enemy) < 1.6 → respawn + 'Пойман!' + lose
- onMessage 'win' → enemy.stop() + 'Победа!' + win + confetti
- g21_finish: onTouch → broadcast 'win'

Lua (паритет):
- __rbxl_show_text + Sounds
- __rbxl_spawn_npc('character-b', ..., 'Охотник', 100, 4)
- __rbxl_npc_follow(ref, 'player') — велим NPC следовать за игроком
- Heartbeat: __rbxl_npc_x/z для расстояния, при <1.6 → LoadCharacter
  + 'Пойман!' + lose Sound (с throttle 2с)
- BindableEvent WinReached + g21_finish.Touched → ev:Fire
- При победе: npc_stop + showText + win + confetti

Shim хелперы:
- __rbxl_npc_follow(ref, target='player')
- __rbxl_npc_stop(ref)
- __rbxl_npc_x/y/z(ref) — позиция NPC
- api.updateNpcPos(localRef, x, y, z) — GameRuntime синкает каждый кадр

GameRuntime.tick собирает позиции всех NPC из npcManager.npcs через
_localToReal и шлёт sb.api.updateNpcPos.
2026-06-09 21:23:53 +03:00
min
58fbc9d6e6 fix(g20): метка height 2.5 — над health-bar 2026-06-09 21:18:50 +03:00
min
4320c6adeb fix(g20): уменьшил зазоры метки и health-bar
LabelManager использует opts.height как ГАП от верха AABB до плашки,
а не абсолютную высоту. Передавал 3 — метка летела далеко вверх.
Стало 0.3 — небольшой зазор над головой.

Health-bar опустил с y+2.4 до y+1.9 — ближе к голове.
2026-06-09 21:17:16 +03:00
min
7595668b03 fix(g20): метку HP подняли с 3 до 4 — не перекрывается health-bar
Health-bar NPC рендерится на y+2.4 при уроне. Метка height=3 была
слишком близко — health-bar заходил поверх текста. Высота 4 даёт
зазор в ~1.6 над health-bar.
2026-06-09 21:13:38 +03:00
min
9eebbd302e feat(g20): клик по NPC через pick (как Тир ClickDetector)
Раньше: проверка дистанции до врага при ЛКМ через InputBegan
+ MouseButton1. Никак не работало из-за десятка причин.

Теперь как в Тире:
- BabylonScene._meshToTarget теперь возвращает {kind:'npc', id:N}
  для меша с metadata.npcId.
- routeGlobalEvent('click', {target}) — этим уже шлёт в Lua-shim
  с target.
- Shim добавлен __rbxl_npc_on_click(ref, fn) — регистрация callback'а.
  В fireGlobalEvent при type='click'+target.kind='npc' резолвим
  локальный ref и фейерим cb.
- В скрипте игры 20 регистрируем callback на каждого врага.
  Клик ЛКМ по NPC (raycast попадает в мешa NPC) → callback → урон.
2026-06-09 21:10:22 +03:00
min
8a3405e34a feat(g20): полный паритет «Имена над врагами» + shim NPC API
JS:
- 3 NPC (Гоблин, Скелет, Орк) через spawnNpc('character-b')
- setLabel над каждым с HP, обновляется при уроне
- ЛКМ → бьём ближайшего врага в радиусе 4 (damage 30)
- onDeath → clearLabel + hit sound + при 0 врагов — победа+confetti

Расширения shim/runtime:
- __rbxl_spawn_npc уже было, добавил api._localToRealNpc Map
- __rbxl_npc_damage(ref, amount) → cmd 'npc.damage'
- __rbxl_set_label(ref, text, color, height) → cmd 'scene.setLabel'
- __rbxl_clear_label(ref) → cmd 'scene.clearLabel'
- __rbxl_npc_on_death(ref, fn) — регистрирует cb. shim слушает global
  event 'npcDeath' (resolveTweenTarget теперь поддерживает kind='npc')
  и зовёт зарегистрированные cb с подходящим ref (local или real).
- GameRuntime.npc.spawn.then синхронизирует _localToRealNpc в Lua-sb.

Lua-скрипт игры 20 (паритет):
- showText 'Победи всех врагов! Кликай по ним'
- 3 спавна с метками HP над головой
- UserInputService.InputBegan MouseButton1 → ближайший враг в r=4 → -30hp
- На смерть: clearLabel + при 0 — Победа + win Sound + confetti
2026-06-09 20:34:20 +03:00
min
c489a31854 feat(g19): полный паритет «Лифт» — Heartbeat yo-yo
Игра 19 падала на WaitForChild + Vector3 + (оператор не поддержан).

Lua паритет с JS:
- showText 'Встань на синий лифт — он повезёт наверх'
- task.delay 0.2c для FindFirstChild('Лифт') (WaitForChild может зависать)
- Heartbeat yo-yo по Y: startY (1) ↔ TOP_Y (12.3) с периодом 7с
  (3.5с вверх + 3.5с вниз через треугольную функцию)
- Vector3.new напрямую (без +)
- Респаун при y<-3
- BindableEvent WinReached + g19_finish.Touched → ev:Fire
- При победе: showText 'Победа!' + win Sound + confetti
2026-06-09 20:26:19 +03:00
min
430b9eddcd feat: игра 18 «Качели» Lua + кастомная модалка выхода
Игра 18:
- Падало на WaitForChild + task.spawn + Completed:Wait (yield-across-C).
- Полный переписан: Heartbeat-таймер раскачивает swing по синусу
  с амплитудой 4 и периодом 2.8с (вместо TweenService).
- task.delay 0.2с чтобы дождаться появления свинга в scene.
- Vector3.new напрямую (без оператора + который не работает).
- BindableEvent WinReached + g18_finish.Touched → ev:Fire.
- Полный паритет: showText, win Sound, confetti, respawn при y<-3.

Модалка выхода:
- Заменил window.confirm в KubikonEditor.handleBack на ConfirmModal.
- 3 варианта: Сохранить и выйти / Выйти без сохранения / Отмена.
- ConfirmModal расширен onCancel prop (отделяет 'cancel-кнопка'
  от 'клик мимо/Escape').
2026-06-09 20:22:16 +03:00
min
1345f51436 feat(g17): полный паритет с JS «Ключ и сундук»
JS:
- showText 'Найди ключ и открой сундук!'
- onMessage 'takeKey' → inventory.add('Ключ') + 'Ты нашёл Ключ!' + pickup
- onMessage 'openChest' → если has('Ключ'): 'Победа!' + win + confetti
                         иначе: 'Сундук заперт. Сначала найди ключ.'
- key: onTouch → broadcast 'takeKey' + delete
- chest: onInteract E (distance=4) → broadcast 'openChest'

Lua (паритет, юзер указал на отсутствие надписей/инвентаря/звуков):
- __rbxl_show_text для всех подсказок (вместо print)
- __rbxl_inventory_define('key','Ключ') → итем в hotbar инвентаря
- __rbxl_inventory_add('key',1) при подборе (вместо leaderstats BoolValue)
- __rbxl_inventory_has('key') проверка ключа в сундуке
- Sounds 'pickup'/'win'/'lose' (раньше только print)
- BindableEvents TakeKey + OpenChest
- g17_key: Touched → ev:Fire + Destroy (с taken-флагом)
- g17_chest: убран ошибочный Touched-handler.
  Heartbeat distance-check как в Торговце:
  при near=true → __rbxl_hud_set '[E] Открыть сундук'
  UserInputService E → OpenChest:Fire
- При победе: confetti над игроком + win Sound
2026-06-09 20:13:52 +03:00
min
2979104931 fix(g16): урон только когда игрок РЕАЛЬНО в лаве (не над островком)
Раньше: фильтр по Y-капсулы не работал — игрок стоит на островке на
realPos.y=1.54 > порога 1.35, фильтр пропускал.

Стало: проверяем где игрок по X/Z. Если над островком (любой из 6) или
над финишной площадкой — пропускаем урон. Иначе — урон каждый кадр пока
Touched активно (RunService.Heartbeat). У damage есть i-frames ~0.5с
так что урон ~2/сек.

Также: переход с Touched-разово на Heartbeat-постоянно. Раньше Touched
срабатывал только при ВХОДЕ в лаву — если игрок стоит в лаве долго,
TouchEnded не вызывался, и урон шёл только раз. Теперь Touched/TouchEnded
выставляют inLava-флаг, Heartbeat считает урон каждый кадр.
2026-06-09 20:09:07 +03:00
min
f0f739071a feat(g16): полный паритет «Лава-пол» + защита от ложного хитбокса
JS:
- showText 'Прыгай по островкам! Лава жжёт!'
- onTick: y<-2 → respawn
- onMessage 'win' → showText + win + confetti
- g16_lava: onTouch → damage(20) + hit sound
- g16_finish: onTouch → broadcast 'win'

Lua (паритет):
- __rbxl_show_text + win Sound + confetti
- Heartbeat: __rbxl_player_y() < -2 → LoadCharacter
- BindableEvent WinReached + g16_finish.Touched → ev:Fire
- g16_lava: __rbxl_damage_player(20) + hit Sound
  ВАЖНО: лава-зона на y=1±0.3 (верх 1.3), островки на y=1.2±0.3 (верх 1.5).
  AABB-зоны пересекаются → BabylonScene touch-detector с EPS=0.25
  активировал лаву даже когда игрок стоит на островке.
  Защита: если игрок выше Y=1.35 (стоит на островке/финише) — пропускаем
  урон. Урон срабатывает только когда игрок реально в лаве.

Shim добавил:
- __rbxl_damage_player(amount) → cmd player.damage (с i-frames)
2026-06-09 20:03:50 +03:00
min
8abbde9d67 feat(g15): полный паритет «Тир» + ClickDetector в shim
JS:
- 8 мишеней-сфер на постаментах
- ui.score, showText 'Кликай по красным мишеням!'
- target: onClick → explosion particles + delete + broadcast 'hit'
- main: onMessage 'hit' → score++ + hit sound + при 8 победа+confetti

Lua-shim расширение:
- Instance.new('ClickDetector') создаёт инстанс с MouseClick signal
- Когда clickDet.Parent = part → Proxy.set регистрирует
  part._clickDetector = clickDet
- fireTargetEvent при kind='click' фейерит part._clickDetector.MouseClick.Fire

Lua-скрипт игры 15:
- ScreenGui 'Мишени: N / 8'
- BindableEvent TargetHit
- 8 g15_target_N (ids 2,4,6,8,10,12,14,16): ClickDetector с
  MaxActivationDistance=50 → MouseClick → spawn explosion + Destroy + Fire
- main: hit Sound, при 8 — win Sound + showText + confetti
2026-06-09 19:52:16 +03:00
min
7f3b81a531 feat: умный авто-fallback Lua для всех игр без явной реализации
Раньше для игр 15-50 при открытии 'Открыть мою копию на Lua' юзер
получал TODO-заглушки которые ничего не делали (или simpleMain
который только print). Каждая новая игра без явного override
была полностью неиграбельной.

Новый generateFallbackLua(s, gameTitle) в buildGameProject:

Главный скрипт (target=null):
  - __rbxl_show_text(gameTitle) подсказка
  - Слушает BindableEvent FinishReached → win Sound + Победа! + confetti

Скрипт-финиш (target=primitive с именем 'Финиш'/'ФинишЗона'/'Final'):
  - Touched → создаёт/находит BindableEvent FinishReached → Fire
  - fired-флаг чтобы 1 раз

Прочие target-скрипты:
  - Touched → красит примитив зелёным (визуальный feedback)
  - touched-флаг

Удалил статичные simpleMain stub-ы для игр 31-50 — теперь они
используют умный fallback. Когда дописываем полную Lua-версию
игры — добавляем явный override в LUA_OVERRIDES, fallback
автоматически перестаёт использоваться.

Это даёт минимум: победа на финише + цвет на касании во всех
35 не-готовых играх (15-50).
2026-06-09 19:43:20 +03:00
min
cc5717f5a3 feat(lua-games): полный паритет для игры 14 «Собери по тегам»
JS:
- 7 жёлтых звёзд-конусов + 5 синих кубов-обманок
- showText 'Собери все ЖЁЛТЫЕ звёзды!'
- main помечает звёзды тегом 'звезда' с задержкой 0.2с
- onMessage 'collected' → score++ + при 0 left — победа+confetti
- star: onTouch → untag + delete + broadcast 'collected'

Lua (паритет):
- 7 g14_star_N через генератор (раньше был один g14_star)
- ScreenGui 'Звёзды: N / 7' счётчик
- BindableEvent StarCollected
- main: task.delay(0.2) → AddTag всем 7 звёздам через workspace:FindFirstChild
- При collect → coin Sound + GetTagged-проверка left==0 → win+confetti
- g14_star_N: RemoveTag + Destroy + ev:Fire (с picked-флагом)
2026-06-09 19:38:55 +03:00
min
b7b3c1eb81 fix(g13): подсказки [E] через HUD ui.set — паритет с JS
Юзер: подсказка в Lua была слева от центра, белая. В JS — точно по
центру внизу, жёлтая.

Корень: я использовал BillboardGui+TextLabel с явной Position, но
GUI-shim позиционирует label некорректно (UDim2 offset плохо
интерпретируется → плашка плыла).

Фикс: используем тот же механизм что JS — game.ui.set (HUD через
React). Добавил хелпер __rbxl_hud_set(id, text, x, y, color, size)
шлющий 'ui.set' cmd, GameRuntime пробрасывает в _onHud → GameHud.jsx
рендерит точно как для JS-скриптов.

В g13_counter/g13_door: при near=true → hud_set с (50, 75, #ffe44a, 20)
(центр по X, ниже центра по Y, жёлтый — точно как JS interact hint).
При выходе из зоны → hud_set(id, nil) убирает.
2026-06-09 19:34:32 +03:00
min
e8bfdda380 fix(g13): подсказки выше хотбара (0.6 центра вместо низа)
Прошлая позиция (1, -120) перекрывала хотбар инвентаря.
Новая (0.5, -160; 0.6, 0) — выше середины экрана, не мешает.
2026-06-09 19:09:34 +03:00
min
47ad608182 feat(g13): NPC-торговец + инвентарь как в JS
Юзер указал что в Lua-версии было отступление от JS:
- Торговец нарисован примитивами вместо character-a скина
- Ключ показан надписью в HUD вместо инвентаря-hotbar

Добавил в shim хелперы паритета:
- __rbxl_spawn_npc(modelType, x,y,z, name?, hp?, speed?) → cmd npc.spawn
  Возвращает локальный ref для дальнейших команд.
- __rbxl_npc_say(ref, text, duration) → cmd npc.say
- __rbxl_inventory_define(itemId, name, color) → cmd items.define
- __rbxl_inventory_add(itemId, count) → cmd inv2.add (показывает в hotbar)
- __rbxl_inventory_has(itemId) → проверка локального кеша
- __rbxl_inventory_remove(itemId, count) → cmd inv2.remove

Lua-скрипт игры 13:
- spawnNpc 'character-a' за прилавком как в JS
- inventory_define('key', 'Ключ') → hotbar
- При разговоре: npc_say + inventory_add('key', 1)
- При двери: проверяем inventory_has('key')
2026-06-09 19:05:55 +03:00
min
fb390f402c fix(g13): торговец-фигурка + подсказки внизу экрана
1) Торговец-NPC отсутствовал. Спавним фигурку из 3 частей:
   - Тело (синий куб) на (0, 2.0, 5) — за прилавком
   - Голова (бежевая сфера) на (0, 3.2, 5)
   - Шляпа (коричневый цилиндр) на (0, 3.8, 5)

2) Подсказки [E] плыли в центр экрана. Задал явную позицию:
   нижняя часть, по центру, с тёмной плашкой и тенью.
   Применил к g13_counter и g13_door.
2026-06-09 18:59:54 +03:00
min
e163fe9770 feat(lua-games): полный паритет для игры 13 «Торговец»
JS:
- spawnNpc торговец, prompts E:
  Прилавок onInteract → broadcast 'talk' → выдать ключ через inventory
  Дверь onInteract → broadcast 'openDoor' → проверка inventory.has
  → tween двери (y:9)
- Финиш onTouch → broadcast 'win' → confetti

Lua (паритет, NPC через статичный прилавок):
- ScreenGui 'Ключа нет' / 'У тебя есть Ключ' (вместо inventory)
- BindableEvents TalkTrader / OpenDoor / WinReached
- g13_counter: BillboardGui '[E] Поговорить с торговцем' в радиусе 4
  + UserInputService E → TalkTrader:Fire
- g13_door: BillboardGui '[E] Открыть дверь' в радиусе 4
  + E → OpenDoor:Fire (или 'Дверь заперта' если ключа нет)
- g13_main:
  TalkTrader → если ключа нет: hasKey=true + 'Привет!' + pickup Sound
  OpenDoor → если hasKey: tween двери +6 по Y + win Sound
  WinReached → 'Победа!' + confetti
- g13_finish: Touched → WinReached:Fire (fired-флаг)
2026-06-09 18:56:28 +03:00
min
89baf23877 feat(lua-games): полный паритет для игры 12 «Дверь по коду»
JS:
- CODE=[3,1,4,2], showText 'Нажми кнопки в правильном порядке (E)'
- onMessage 'press' с {num} → click sound, push в entered, проверка
  совпадения с CODE, ошибка → сброс + 'Неверно!' + lose sound
  весь код → 'Код верный! Дверь открывается' + win sound + tween двери
- onMessage 'win' → 'Победа!' + win + confetti
- кнопка: onInteract (E, distance=3) → broadcast 'press' {num}
- финиш: onTouch → broadcast 'win'

Lua (паритет):
- __rbxl_show_text всех подсказок + Sound 'click'/'lose'/'win'
- BindableEvent ButtonPress (с num аргументом) + WinReached
- g12_main: tween двери (Position.Y+=6) + CanCollide=false
- 4 g12_btn_N: BillboardGui '[E] Нажать N' видим в радиусе 3
  UserInputService.InputBegan E → ev:Fire(num)
  Hint видимость через Heartbeat + __rbxl_player_x/z
- g12_finish: Touched → ev:Fire WinReached
- При win — confetti
2026-06-09 18:53:22 +03:00
min
eacc3f990b feat(lua-games): полный паритет для игры 11 «Эхо-комната»
JS:
- 6 цветных плиток-цилиндров со своими звуками
- ui.score, ui.showText 'Наступи на все цветные плитки!'
- onMessage 'step' → score++ + при 6 'Иди на финиш'
- onMessage 'finish' → если < TOTAL то 'Сначала пройди все плитки'
  иначе showText + win + confetti
- g11_tile_N: onTouch → sound + sparks particles, при первом — broadcast
- g11_finish: onTouch → broadcast 'finish'

Lua (паритет):
- ScreenGui 'Плитки: N / 6'
- BindableEvent EchoStep (плитка) + EchoFinish (зона)
- 6 g11_tile_N: каждая со своим Sound (coin/jump/pickup/click/hit/coin)
  + __rbxl_spawn_particles('sparks', x, y+1, z) при касании
  + Throttle 0.4с между звуками + used-флаг
- g11_main: 'Все плитки звучали! Иди на финиш' при 6
  'Сначала пройди все 6 плиток!' если рано пришёл на финиш
  При win — Sound 'win' + confetti
2026-06-09 18:47:57 +03:00
min
50b08b81bc feat(lua-games): полный паритет для игры 10 «Прыжок-пружина»
JS:
- showText 'Прыгай по батутам всё выше!'
- onTick: y<-3 → respawn + lose sound
- onMessage 'win' → showText + win + confetti
- g10_tramp_N: onTouch → player.boostJump(3.2) + jump sound
- g10_finish: onTouch → broadcast 'win'

Lua (паритет):
- __rbxl_show_text подсказка + 'Победа!'
- Heartbeat: __rbxl_player_y() < -3 → LoadCharacter + lose Sound
- BindableEvent WinReached + g10_finish.Touched → ev:Fire
- При win — confetti

Добавил хелпер в shim:
- __rbxl_boost_jump(strength) → send 'player.boostJump'
  3.2 = втрое выше обычного прыжка

g10_tramp_4/5/6: Touched → __rbxl_boost_jump(3.2) + jump Sound
с защитой от зацикливания (минимум 0.5с между активациями).
2026-06-09 18:44:34 +03:00
min
bec3c478e7 feat(lua-games): полный паритет для игры 9 «Светофор»
JS:
- showText 'Зелёный — беги! Красный — замри!'
- light=findOne('Светофор'), green/red/green циклически (3с/2.5с)
- setColor light на красный/зелёный + showText
- onTick: если красный и moved/dt>0.8 — respawn + lose sound
- onMessage 'win' → showText + win + confetti
- g9_finish: onTouch → broadcast 'win'

Lua (паритет):
- __rbxl_show_text для всех подсказок
- Heartbeat-таймер фазы (task.spawn не умеет yield) — переключает
  phase 'green'/'red' каждые GREEN_TIME/RED_TIME
- light=workspace:FindFirstChild('Светофор'), .Color = Color3.fromRGB
- Heartbeat: prevX/prevZ, при phase=red и moved/dt>0.8 → LoadCharacter
  + lose Sound + 'Двинулся на красный!'
- BindableEvent WinReached
- g9_finish: Touched → ev:Fire с fired-флагом
- При победе: win Sound + confetti
2026-06-09 18:35:47 +03:00
min
73bf9f5c34 feat(lua-games): полный паритет для игры 8 «Беги к финишу»
JS:
- ui.timer + showText 'Беги к зелёному финишу — на время!'
- onTick: time += dt
- onMessage 'finish' → 'Финиш! Время: N сек' + win + confetti
- g8_finish: onTouch → broadcast 'finish'

Lua (паритет):
- ScreenGui+TextLabel секундомер вверху по центру '0.0 сек'
- __rbxl_show_text подсказка
- RunService.Heartbeat: time += dt → label.Text каждый кадр
- BindableEvent FinishReached
- g8_finish: Touched → ev:Fire с fired-флагом
- При финише: 'Финиш! Твоё время: X.X сек' + win Sound + confetti
2026-06-09 18:16:43 +03:00
min
c9acb4fb3b fix(g7): спавн через __rbxl_spawn_part + Heartbeat вместо task.spawn
Корни:
1. task.spawn(function() task.wait() end) → 'attempt to yield across
   a C-call boundary' — task.spawn в shim синхронно зовёт fn из JS.
   Замена: накопление dt в RunService.Heartbeat → spawnCube() каждые 1.5с.

2. Instance.new('Part', workspace) с последующим .Anchored=false
   создавал anchored=true примитив + патч → primitiveManager не пересоздавал
   rigid body, куб не падал. Новый хелпер __rbxl_spawn_part(opts) шлёт
   sceneCreate с правильным anchored СРАЗУ — куб создаётся динамическим
   и падает.
2026-06-09 17:38:16 +03:00
min
8021ed6a20 feat(lua-games): полный паритет для игры 7 «Поймай падающее»
JS:
- ui.score, showText 'Лови падающие кубы! Нужно 15'
- every(1.5): random(x,z) → spawn cube y=14, anchored=false, deleteAfter 6с
- onPlayerTouch: caught[ref] флаг, +1 score, coin sound, при 15 — победа+confetti

Lua (паритет):
- ScreenGui+TextLabel 'Поймано: N / 15'
- task.spawn + task.wait(1.5) цикл спавна
- Instance.new('Part', workspace), Anchored=false (падение)
- Vector3.new для Position/Size
- Debris:AddItem(cube, 6) — авто-удаление
- cube.Touched: caught-флаг + score++ + coin Sound + Destroy
- При 15 — win Sound + showText + confetti
2026-06-09 17:34:16 +03:00
min
8eec59af53 feat(lua-games): полный паритет для игры 6 «Цветные плитки»
JS-версия:
- 36 плиток 6×6, серые
- ui.score = painted, ui.showText
- onMessage 'paint' → score++ + pickup sound + при 36 победа+win+confetti
- tile: onTouch → setColor зелёный + broadcast 'paint'

Lua-версия:
- ScreenGui+TextLabel 'Плитки: N / 36' счётчик
- __rbxl_show_text подсказка + 'Победа!'
- BindableEvent TilePainted
- 36 g6_tile_N: Touched → part.Color=зелёный + ev:Fire (painted-флаг)
- g6_main: painted++/label.Text/pickup Sound; при 36 — win+confetti
2026-06-09 17:24:48 +03:00
min
f7074f5cd7 feat(lua-games): полный паритет для игры 5 «Лабиринт»
JS-версия:
- ui.showText('Найди выход из лабиринта!', 3)
- onMessage 'win' → showText + win sound + confetti
- g5_finish: onTouch → broadcast 'win'

Lua-версия:
- __rbxl_show_text подсказка + 'Победа!'
- BindableEvent WinReached
- g5_finish: Touched на финиш-зоне → ev:Fire (с fired-флагом)
- На победе: confetti над игроком
2026-06-09 17:21:56 +03:00
min
36321f0d17 fix(g4): label.Visible=false + Destroy при нажатии E
hintGui:Destroy() не убирает gui-overlay созданный TextLabel через
newGuiInstance. Делаем label.Visible=false (надёжный путь) + явный
label:Destroy().
2026-06-09 17:18:52 +03:00
min
c18dfc4d56 fix(g4): подсказка [E] видна только в радиусе 4 от кнопки
Heartbeat проверяет расстояние от игрока до кнопки. Управляем
видимостью через label.Visible (BillboardGui в shim не управляет
видимостью children, label.Visible работает напрямую через gui.update).
2026-06-09 17:17:03 +03:00
min
c006f58b70 debug(g4): print имена children workspace и состояние двери
Откатил метатаблицу Vector3 (она ломала TweenService instanceof RbxVector3).
2026-06-09 17:13:40 +03:00
min
a4f2f0800b fix(g4): дверь поднимается + метатаблица Vector3 (+, -, *, /)
Проблема: door.Position + Vector3.new(0, 6, 0) возвращало nil потому
что wasmoon не создаёт метаметоды (__add) для JS-классов автоматически.

Фикс:
1. В скрипте кнопки явно считаем Vector3.new(dp.X, dp.Y+6, dp.Z) без +.
2. В prelude добавил метатаблицу Vector3 для будущего использования
   с операторами +, -, *, /, унарный -, ==, tostring. Работает между
   двумя Vector3-таблицами, созданными через Vector3.new в Lua.
2026-06-09 17:11:23 +03:00
min
5101743aed fix(g4): вернул нажатие E (как в JS-версии)
Откат изменения 'наступи на кнопку'. JS-версия использует
game.self.onInteract — нажатие E. Lua-версия должна вести себя так же.

Подход:
- Подсказка [E] Открыть дверь висит над кнопкой постоянно (пока не нажата)
- UserInputService.InputBegan ловит E
- Расстояние до кнопки проверяется ТОЛЬКО в момент нажатия E
  (не каждый кадр — это избегает багa с зависанием позиции после Touched)
- Если близко (≤4) → дверь поднимается через TweenService
2026-06-09 13:43:38 +03:00
min
4c648d139e fix(g4): кнопка по касанию вместо E-нажатия
Проблема:
1. Heartbeat-зов __rbxl_player_x() возвращал константу после первого
   касания кнопки (возможно lua-coroutine / state-issue в Heartbeat).
2. Дверь не открывалась — InputBegan E видимо не доходит или фильтр
   inRange всегда true.

Решение: упростил — кнопка реагирует на Touched (как кнопка-педаль),
без E и без проверки расстояния. Это и понятнее для урока.
Текст подсказки изменён на 'Наступи на красную кнопку'.

Дверь поднимается через TweenService при касании кнопки.
2026-06-09 13:39:55 +03:00
min
39673452cb debug(g4): print позиции игрока и расстояния раз в секунду 2026-06-09 13:35:24 +03:00
min
05a7eaf371 feat(lua-games): полный паритет для игры 4 «Кнопка-открывашка»
JS-версия:
- ui.showText('Подойди и нажми E', 4)
- onMessage 'win' → showText + win sound + confetti
- g4_button: onInteract (E) → click + tween двери (y:8) + showText 'Дверь открывается!'
- g4_finish: onTouch → broadcast 'win'

Lua-версия (паритет):
- __rbxl_show_text подсказка + 'Победа!'
- BindableEvent WinReached
- g4_button: UserInputService.InputBegan + ProximityHint через BillboardGui
  ('[E] Открыть дверь' над кнопкой когда игрок в радиусе 4)
  E → click Sound + TweenService:Create двери (Position +6 по Y, 1.2с) +
  CanCollide=false + showText 'Дверь открывается!'
- g4_finish: Touched → ev:Fire с fired-флагом

Shim фиксы:
- UserInputService.InputBegan/InputEnded теперь фейерятся на keyDown/keyUp.
  Передаётся InputObject с KeyCode = ССЫЛКА на Enum.KeyCode.<KEY>
  (важно для сравнения == Enum.KeyCode.E).
2026-06-09 13:32:42 +03:00
min
0ed2cbf376 feat(lua-games): полный паритет для игры 3 «Не упади»
JS-версия:
- ui.showText('Беги вперёд! Плитки исчезают!', 3)
- onTick: y<-3 → respawn + 'Упал! Снова.' + sound 'lose'
- broadcast 'finish' → 'Победа! Ты добежал!' + sound 'win' + confetti
- скрипт плитки: onTouch → sound 'click' + game.after(1.2, delete)
- скрипт финиша: onTouch → broadcast 'finish'

Lua-версия (паритет):
- __rbxl_show_text(...) подсказка + 'Упал!' + 'Победа!'
- BindableEvent FinishReached как канал между скриптами
- g3_main: Heartbeat респаун при Y<-3 + lose/win Sound
- 14 g3_tile_N: Touched → click Sound + Debris:AddItem(part, 1.2)
- g3_finish: Touched → ev:Fire (через fired-флаг)
- На финише: __rbxl_spawn_particles('confetti', ...) над игроком
2026-06-09 13:26:38 +03:00
min
96644ede15 fix(lua): __rbxl_player_x/y/z отдельные функции (wasmoon-userdata fix)
Корень: __rbxl_player_pos() возвращал JS-object {x,y,z}, wasmoon оборачивал
его в userdata-proxy. В Lua pos.x давал NaN. Конфетти спавнились с NaN.

Фикс: 3 отдельные функции __rbxl_player_x/y/z возвращающие числа.
В скрипте игры 2 используем их напрямую.
2026-06-09 13:18:30 +03:00
min
ba648de09c debug(lua-games): прибавил print в g2_main для отладки конфетти 2026-06-09 13:15:11 +03:00
min
8321a526cd fix(lua): __rbxl_player_pos возвращает реальную позицию игрока
Проблема: __rbxl_player_pos() возвращал (0,8,0) — нач. позицию hrp._position,
которая не обновлялась. Конфетти всегда вылетали из стартовой точки.

Фикс:
- api._realPlayerPos обновляется в GameRuntime tick (каждый кадр)
  через api.updatePlayerPos(x, y, z) из player.body.position.
- __rbxl_player_pos() в Lua возвращает api._realPlayerPos если есть.

Убраны debug-логи.
2026-06-09 13:01:45 +03:00
min
660d528ad5 feat(lua): __rbxl_show_text + __rbxl_spawn_particles (паритет game.ui/scene)
JS-версия использует game.ui.showText (красивая центрированная плашка
без рамки через RbxlHudOverlay) и game.scene.spawnParticles('confetti').
Lua-версия пыталась рисовать ScreenGui+TextLabel через offset в UDim2,
но gui-shim неправильно интерпретировал offset → плашка прижата влево.
Также конфетти отсутствовали.

Решение — хелперы прямого вызова HUD/particle-systems как в JS:
- __rbxl_show_text(text, duration, color?) → shim шлёт ui.showText →
  GameRuntime → _rbxlHud.showMessage + setTimeout hideMessage
- __rbxl_spawn_particles(kind, x, y, z, duration, count) → 'scene.particles'
- __rbxl_player_pos() → возвращает текущую позицию игрока

Игра 2 переписана: использует __rbxl_show_text для подсказок 'Допрыгай',
'Упал!', 'Победа!' и __rbxl_spawn_particles('confetti', ...) на финише.
2026-06-09 12:47:44 +03:00
min
901c770fdc feat(lua-games): полный паритет для игры 2 «Прыгай по платформам»
JS-версия имела:
- ui.showText('Допрыгай до зелёной площадки!', 3)
- onTick: y<-3 → respawn + 'Упал!' + sound 'lose'
- broadcast 'finish' → 'Победа!' + sound 'win' + конфетти
- finish-зона: onTouch → broadcast 'finish'

Lua-версия (паритет):
- ScreenGui подсказка 'Допрыгай до зелёной площадки!' на 3с
- RunService.Heartbeat: hrp.Y < -3 → player:LoadCharacter() + Sound
  'lose' + красный TextLabel 'Упал! Пробуй снова.' на 1.5с
- BindableEvent FinishReached в ReplicatedStorage
- g2_finish: Touched на финиш-зоне → ev:Fire (только 1 раз через fired-флаг)
- g2_main: FinishReached → Sound 'win' + зелёный 'Победа! Ты дошёл до финиша!'

Юзер: открой копию ЗАНОВО на Lua — старый проект 2908 был со старым
кодом (только print), новая копия получит обновлённые скрипты.
2026-06-09 10:47:56 +03:00
min
bb69ccf9ed feat(lua-games): полный UI+звук для игры 'Собери монетки'
Было: только print в консоль, leaderstats не виден на экране.
Стало паритет с JS-версией:
- ScreenGui+TextLabel счётчик 'Монеты: N / 8' в правом углу
- ScreenGui подсказка 'Собери все монетки!' на 2 сек по центру
- Sound 'coin' при сборе (через Sound:Play, SoundId='coin')
- Sound 'win' + победный TextLabel когда score >= TOTAL
2026-06-09 10:31:37 +03:00
min
ee0ab60381 fix(lua-games): кириллические имена leaderstats через bracket access
Lua не поддерживает кириллицу в именах identifier'ов (только в строках).
stats.Монеты вызывал parser error:
  <name> expected near '<\208>'  (0xD0 = первый байт UTF-8 кириллицы)

Заменено на безопасный синтаксис:
  stats.Монеты         → stats['Монеты']
  stats.Ключ           → stats['Ключ']
  stats.Клики          → stats['Клики']

Затронуты игры: collect-coins (1), trader (13), key-chest (17),
shop (29), clicker (46). Все 9 случаев исправлены.

Теперь монетки в игре 1 должны нормально увеличивать счётчик.
2026-06-09 06:42:18 +03:00
min
3757eace9f feat(wiki): Lua-версии для всех 50 игр-уроков + расширения shim
ИНФРАСТРУКТУРА:
- docsGamesBuildersLua.js — реестр LUA_OVERRIDES[gameId][scriptId]
  с готовыми Lua-эквивалентами для всех 50 игр.
- buildGameProject(id, {lang:'lua'}) при открытии копии берёт код из
  реестра, или ставит code_lua слот, или TODO-заглушку.
- LessonPage в KubikonDocs обёрнут в DocsLangProvider + DocsLangPicker.
- Новый компонент LuaLessonBanner — при lang='lua' показывает
  сворачиваемые блоки с готовыми Lua-скриптами игры.

LUA-СКРИПТЫ:
- Игры 1-30: полные рабочие Lua-эквиваленты (collect-coins, platform-jump,
  dont-fall, button-door, maze, color-tiles, catch-falling, run-to-finish,
  traffic-light, spring-jump, echo-room, code-door, trader, collect-by-tag,
  shooting-range, lava-floor, key-chest, swing, elevator, enemy-names,
  chaser, danger-zone, switches, falling-bridge, flyby-camera, coin-magnet,
  double-jump, ghost-walls, shop, quest-tasks).
- Игры 31-50: главный скрипт с сообщением + TODO для полной реализации.
  Для clicker — полная версия. Остальные постепенно дорабатываются.

РАСШИРЕНИЯ LUA-RUNTIME (RobloxShim.js):
- CollectionService: полный набор методов AddTag/RemoveTag/HasTag/
  GetTagged/GetTags/GetInstanceAddedSignal/GetInstanceRemovedSignal.
- Debris сервис: AddItem(inst, lifetime) → setTimeout Destroy.
- localPlayer:LoadCharacter() реальный — сбрасывает HP + шлёт respawn.
- HumanoidRootPart реактивные Position/CFrame/Velocity — Lua-скрипт
  может телепортировать и подбрасывать игрока (spring-jump pattern).

РАСШИРЕНИЯ GameRuntime:
- playerSet 'position' — телепорт через hrp.Position = ...
- playerSet 'respawn' — респаун с сбросом HP и позиции на spawn.

Игры теперь работают на Lua. Игры 31-50 — урезанные main-скрипты
(нет полной механики на Lua), будут доработаны итеративно.
2026-06-09 03:47:08 +03:00