Files
BarotraumaLuaProjects/AirlockRTL.lua

290 lines
12 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- AirlockRTL.lua — Контроллер шлюза (State Machine)
-- =================================================
--
-- Физическая схема:
-- [Сухой отсек] — [Внутр.дверь] — [ШЛЮЗ] — [Наруж.дверь] — [Снаружи/вода]
--
-- Входы:
-- 1 — состояние наружней (левой) двери (1=открыта)
-- 2 — состояние внутренней (правой) двери (1=открыта)
-- 3 — кнопка внутри шлюза (слева) — вход в шлюз из сухого отсека
-- 4 — кнопка внутри шлюза (центр) — выход из шлюза (контекстно)
-- 5 — кнопка снаружи — вход в шлюз снаружи
-- 6 — уровень воды в шлюзе (0 = пусто, 100 = полно)
--
-- Выходы:
-- 1 — наружняя дверь (1=открыть, 0=закрыть)
-- 2 — внутренняя дверь (1=открыть, 0=закрыть)
-- 3 — насос (1=вкл, 0=выкл)
-- 4 — целевой уровень воды (-100=осушить, +100=заполнить)
-- 5 — текст статуса
-- 6 — цвет текста (rrr,ggg,bbb)
--
-- Принцип: любое нажатие сначала управляет водой, затем дверью.
-- Слева всегда море (вода), справа отсек (сухо).
-- Направление (flow) запоминается при входе.
--
-- Сценарий FLOW_OUT (в море):
-- btn3 → если воды >10% — осушить → открыть внутрь → войти
-- → авто/btn4 → закрыть внутрь → затопить → открыть внешнюю
-- → выйти → авто/btn4 → закрыть внешнюю → IDLE
--
-- Сценарий FLOW_IN (в отсек):
-- btn5 → затопить → открыть внешнюю → войти
-- → авто/btn4 → закрыть внешнюю → осушить → открыть внутрь
-- → войти → авто/btn4 → закрыть внутрь → IDLE
--
-- btn4/timer: таймер 2с; btn4 = пропустить ожидание сейчас.
-- В DRAIN/FLOOD: btn4 или таймаут 15с — пропустить и открыть дверь.
-- btn4 из IDLE: направление по flow (запомнен при входе), иначе по воде.
-- Состояния автомата
local ST_IDLE = 0 -- Ожидание команд
local ST_OPEN_IN = 1 -- Открытие внутренней двери
local ST_WAIT_IN = 2 -- Ожидание прохода через внутреннюю дверь
local ST_CLOSE_IN = 3 -- Закрытие внутренней двери
local ST_DRAIN_EXIT = 4 -- Осушение для выхода наружу
local ST_FLOOD = 5 -- Заполнение для входа снаружи
local ST_DRAIN_RET = 6 -- Осушение для возврата в сухой отсек
local ST_OPEN_OUT = 7 -- Открытие внешней двери
local ST_WAIT_OUT = 8 -- Ожидание прохода через внешнюю дверь
local ST_CLOSE_OUT = 9 -- Закрытие внешней двери
-- Сценарии
local FLOW_NONE = 0
local FLOW_OUT = 1 -- Из сухого наружу
local FLOW_IN = 2 -- Снаружи в сухой
-- Параметры (шкала воды: 0 = пусто, 100 = полно)
local WAIT_TIMEOUT = 3 -- секунд ожидания у открытой двери
local PUMP_TIMEOUT = 15 -- макс. секунд работы насоса до принудительного продолжения
local DRAIN_THRESHOLD = 10 -- почти пусто (выход в море)
local INNER_THRESHOLD = 10 -- можно открыть внутрь (по запросу: вода ниже 10%)
local FLOOD_THRESHOLD = 90 -- почти полно (вход снаружи)
local WATER_OPEN_SAFE = 10 -- при btn3: если воды > 10%, сначала осушить
-- Переменные состояния
local state = ST_IDLE
local flow = FLOW_NONE
local timer = 0
local pumpTimer = 0 -- сколько работает насос в текущем цикле
-- Предыдущие значения кнопок для детекции фронта
local prev3 = false
local prev4 = false
local prev5 = false
-- Установка текста и цвета статуса
local function setStatus(text, color)
out[5] = text
out[6] = color
end
-- Сброс в IDLE: закрыть двери, выключить насос, контекст (flow) сохраняется
local function goIdle()
out[1] = 0
out[2] = 0
out[3] = 0
setStatus("Готов", "0,255,0")
state = ST_IDLE
timer = 0
end
-- Инициализация при старте
out[1] = 0
out[2] = 0
out[3] = 0
setStatus("Готов", "0,255,0")
inp = {}
-- Главная функция, вызывается каждый кадр
function upd(dt)
dt = dt or 0
-- Чтение входов
local doorOut = inp[1] == 1
local doorIn = inp[2] == 1
local btn3 = inp[3] == 1
local btn4 = inp[4] == 1
local btn5 = inp[5] == 1
local water = inp[6] or 0
-- Детекция фронта кнопок (только нажатие, не удержание)
local press3 = btn3 and not prev3
local press4 = btn4 and not prev4
local press5 = btn5 and not prev5
prev3 = btn3
prev4 = btn4
prev5 = btn5
-- Сброс таймера насоса при входе в состояния с насосом
if state == ST_DRAIN_EXIT or state == ST_FLOOD or state == ST_DRAIN_RET then
pumpTimer = pumpTimer + dt
else
pumpTimer = 0
end
-- Флаг: была ли кнопка 4 обработана в машине состояний
local press4consumed = false
-- === Машина состояний ===
if state == ST_IDLE then
-- IDLE: ожидание команд. Обе двери закрыты, оборудование выключено.
if press3 then
-- Вход из сухого отсека: если есть вода — сначала осушаем, затем внутрь
if water > WATER_OPEN_SAFE then
setStatus("Осушение перед входом...", "0,200,255")
out[3] = 1
out[4] = -100
flow = FLOW_OUT
state = ST_DRAIN_RET
else
setStatus("Открытие внутр. двери...", "0,255,0")
out[2] = 1
flow = FLOW_OUT
state = ST_OPEN_IN
end
elseif press5 then
-- Вход снаружи → заполнить шлюз водой, затем открыть внешнюю дверь
setStatus("Заполнение шлюза...", "255,200,0")
out[3] = 1
out[4] = 100
flow = FLOW_IN
state = ST_FLOOD
elseif press4 then
-- Выход из шлюза. Направление: flow (запомнен при входе), иначе уровень воды.
press4consumed = true
local dir = flow
if dir == FLOW_NONE then
dir = (water <= DRAIN_THRESHOLD) and FLOW_OUT or FLOW_IN
flow = dir
end
if dir == FLOW_OUT then
setStatus("Осушение для выхода...", "0,200,255")
out[3] = 1
out[4] = -100
state = ST_DRAIN_EXIT
else
setStatus("Осушение для отсека...", "0,200,255")
out[3] = 1
out[4] = -100
state = ST_DRAIN_RET
end
end
elseif state == ST_OPEN_IN then
-- Открытие внутренней двери. Ждём сигнала от двери.
out[2] = 1
if doorIn then
timer = 0
setStatus("Внутр. дверь открыта. Войдите.", "0,255,0")
state = ST_WAIT_IN
end
elseif state == ST_WAIT_IN then
-- Внутренняя дверь открыта. Ждём прохода человека (btn4 или таймер).
out[2] = 1
timer = timer + dt
if press4 or timer >= WAIT_TIMEOUT then
press4consumed = press4
setStatus("Закрытие внутр. двери...", "255,200,0")
out[2] = 0
state = ST_CLOSE_IN
end
elseif state == ST_CLOSE_IN then
-- Закрытие внутренней двери. Ждём полного закрытия.
if not doorIn then
if flow == FLOW_OUT then
-- Сценарий "в море": после входа → заполнить (давление) и открыть внешнюю
setStatus("Заполнение шлюза...", "255,200,0")
out[3] = 1
out[4] = 100
state = ST_FLOOD
else
-- Вернулись в отсек: завершено
setStatus("Готов", "0,255,0")
flow = FLOW_NONE
state = ST_IDLE
end
end
elseif state == ST_DRAIN_EXIT then
-- Осушение шлюза перед выходом в море.
out[3] = 1
out[4] = -100
if water <= DRAIN_THRESHOLD or press4 or pumpTimer >= PUMP_TIMEOUT then
press4consumed = press4
setStatus("Открытие внеш. двери...", "0,200,255")
out[3] = 0
out[1] = 1
state = ST_OPEN_OUT
end
elseif state == ST_FLOOD then
-- Заполнение шлюза для входа снаружи (уравнивание давления).
out[3] = 1
out[4] = 100
if water >= FLOOD_THRESHOLD or press4 or pumpTimer >= PUMP_TIMEOUT then
press4consumed = press4
setStatus("Открытие внеш. двери...", "255,200,0")
out[3] = 0
out[1] = 1
state = ST_OPEN_OUT
end
elseif state == ST_DRAIN_RET then
-- Осушение шлюза для входа в сухой отсек (можно раньше, порог INNER_THRESHOLD).
out[3] = 1
out[4] = -100
if water <= INNER_THRESHOLD or press4 or pumpTimer >= PUMP_TIMEOUT then
press4consumed = press4
setStatus("Открытие внутр. двери...", "0,255,0")
out[3] = 0
out[2] = 1
state = ST_OPEN_IN
end
elseif state == ST_OPEN_OUT then
-- Открытие внешней двери. Ждём сигнала от двери.
out[1] = 1
if doorOut then
timer = 0
setStatus("Внеш. дверь открыта. Выходите.", "0,200,255")
state = ST_WAIT_OUT
end
elseif state == ST_WAIT_OUT then
-- Внешняя дверь открыта. Ждём прохода человека (btn4 или таймер).
out[1] = 1
timer = timer + dt
if press4 or timer >= WAIT_TIMEOUT then
press4consumed = press4
setStatus("Закрытие внеш. двери...", "255,200,0")
out[1] = 0
state = ST_CLOSE_OUT
end
elseif state == ST_CLOSE_OUT then
-- Закрытие внешней двери. Ждём полного закрытия.
if not doorOut then
if flow == FLOW_IN then
-- Сценарий "снаружи": после закрытия — осушение и вход в отсек
setStatus("Осушение после входа...", "0,200,255")
out[3] = 1
out[4] = -100
state = ST_DRAIN_RET
else
-- Сценарий "наружу": завершён
setStatus("Готов", "0,255,0")
state = ST_IDLE
flow = FLOW_NONE
end
end
end
table.clear(inp)
end