feat: 50 игр на Lua + импорт Roblox для всех + поддержка Lua в плеере #39

Merged
min merged 215 commits from feat/lua-50-games-bundle into main 2026-06-09 21:59:25 +00:00
2 changed files with 68 additions and 39 deletions
Showing only changes of commit 47ad608182 - Show all commits

View File

@ -1059,60 +1059,30 @@ pickupSound.SoundId = "pickup"; pickupSound.Volume = 0.8
local winSound = Instance.new("Sound", workspace)
winSound.SoundId = "win"; winSound.Volume = 1
-- Спавним "торговца" фигурка из 3 кубов за прилавком на (0, ?, 5)
-- Прилавок на x=0, z=3, sz=1.5 задняя часть z=3.75. Ставим торговца на z=5.
-- Туловище
__rbxl_spawn_part({
type = "cube", name = "ТорговецТело",
x = 0, y = 2.0, z = 5,
sx = 1.2, sy = 1.6, sz = 0.6,
color = "#3b82f6", anchored = true, canCollide = false,
})
-- Голова
__rbxl_spawn_part({
type = "sphere", name = "ТорговецГолова",
x = 0, y = 3.2, z = 5,
sx = 0.8, sy = 0.8, sz = 0.8,
color = "#fcd9b6", anchored = true, canCollide = false,
})
-- Шляпа
__rbxl_spawn_part({
type = "cylinder", name = "ТорговецШляпа",
x = 0, y = 3.8, z = 5,
sx = 1.0, sy = 0.3, sz = 1.0,
color = "#7a4a26", anchored = true, canCollide = false,
})
-- Спавним NPC-торговца за прилавком (паритет с JS spawnNpc)
local traderRef = __rbxl_spawn_npc("character-a", 0, 1, 5, "Торговец Боб", 100, 0)
-- Простой "инвентарь" в HUD: ключ
local screenGui = Instance.new("ScreenGui", player.PlayerGui)
local invLabel = Instance.new("TextLabel", screenGui)
invLabel.Size = UDim2.new(0, 220, 0, 40)
invLabel.Position = UDim2.new(1, -240, 0, 20)
invLabel.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
invLabel.BackgroundTransparency = 0.4
invLabel.TextColor3 = Color3.fromRGB(255, 215, 0)
invLabel.TextScaled = true
invLabel.Font = Enum.Font.SourceSansBold
invLabel.Text = "Ключа нет"
-- Определяем итем "Ключ" в инвентаре и показываем hotbar
__rbxl_inventory_define("key", "Ключ", "#ffd700")
-- Игрок заговорил с торговцем
local talkEvent = getEvent("TalkTrader")
talkEvent.Event:Connect(function()
if hasKey then
__rbxl_show_text("Торговец: Иди к двери, ключ у тебя!", 3)
__rbxl_npc_say(traderRef, "Иди к двери, ключ у тебя!", 3)
return
end
hasKey = true
invLabel.Text = "У тебя есть Ключ"
invLabel.TextColor3 = Color3.fromRGB(100, 255, 100)
__rbxl_show_text("Торговец: Привет! Вот тебе ключ от двери. Удачи!", 4)
__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 hasKey then
if not __rbxl_inventory_has("key") then
__rbxl_show_text("Дверь заперта. Нужен ключ от торговца.", 2)
return
end

View File

@ -1816,6 +1816,65 @@ export function registerRobloxShim(lua, opts) {
color: color || '#ffffff',
});
});
// Спавн NPC — паритет с JS game.scene.spawnNpc(modelType, opts).
// Возвращает локальный ref (строку 'npc_lua_N'), который можно передавать
// в __rbxl_npc_say(ref, text, duration).
let _nextNpcRef = 0;
global.set('__rbxl_spawn_npc', (modelType, x, y, z, name, hp, speed) => {
const ref = 'npc_lua_' + (_nextNpcRef++);
send('npc.spawn', {
modelType: String(modelType || 'character-a'),
ref,
x: +x || 0, y: +y || 0, z: +z || 0,
name: name ? String(name) : undefined,
hp: hp != null ? +hp : undefined,
speed: speed != null ? +speed : undefined,
});
return ref;
});
global.set('__rbxl_npc_say', (ref, text, duration) => {
send('npc.say', {
ref: String(ref || ''),
text: String(text || ''),
duration: +duration || 3,
});
});
// Инвентарь invUI — паритет с JS game.inventory.add(itemId, count).
// Сначала определяем итем (один раз), потом добавляем.
const _localInventory = new Map();
const _definedItems = new Set();
global.set('__rbxl_inventory_define', (itemId, name, color) => {
const id = String(itemId || '');
if (!id || _definedItems.has(id)) return;
_definedItems.add(id);
send('items.define', {
def: {
id,
name: name ? String(name) : id,
color: color || '#ffd700',
stack: 99,
},
});
});
global.set('__rbxl_inventory_add', (itemId, count) => {
const id = String(itemId || '');
if (!id) return;
const c = Number(count) || 1;
_localInventory.set(id, (_localInventory.get(id) || 0) + c);
send('inv2.add', { itemId: id, count: c });
});
global.set('__rbxl_inventory_has', (itemId) => {
return (_localInventory.get(String(itemId || '')) || 0) > 0;
});
global.set('__rbxl_inventory_remove', (itemId, count) => {
const id = String(itemId || '');
const c = Number(count) || 1;
const cur = _localInventory.get(id) || 0;
const newCount = Math.max(0, cur - c);
if (newCount === 0) _localInventory.delete(id);
else _localInventory.set(id, newCount);
send('inv2.remove', { itemId: id, count: c });
});
// Подброс игрока — паритет с JS game.player.boostJump(strength).
// 1.0 = обычный прыжок, 3.0 = втрое выше, и т.д.
global.set('__rbxl_boost_jump', (strength) => {