Das Script (V1.0)
Dieses Script einfach auf einen IC (Lua) kopieren:
-- Version: 1.0
ss.pin_label(0, "Wähle das Schild aus ForceField")
ss.pin_label(1, "Wähle deine Tür")
ss.pin_label(2, "Wähle den Gassensor der links vom Display ist.")
ss.pin_label(3, "Wähle den Gassensor der rechts vom Display ist.")
ss.pin_label(4, "Wähle die Backup-Batterie")
ss.pin_label(5, "Wähle das Licht (optional)")
-- #########################
-- Einstellungen
-- #########################
local FORCEFIELD = 0
local DOOR = 1
local GS_LEFT = 2
local GS_RIGHT = 3
local BATTERY = 4
local LIGHT = 5
local Settings = {
AutoOpen = false,
Manually = -1
}
function loadSettings()
if ic.persist.has("Settings") then
Settings = util.json.decode(ic.persist.get("Settings"))
end
end
function saveSettings()
ic.persist.set("Settings", util.json.encode(Settings))
end
loadSettings()
-- Hilfsvariablen
local LT = ic.enums.LogicType
local SUM = ic.enums.LogicBatchMethod.Sum
local AVG = ic.enums.LogicBatchMethod.Average
local LST = ic.enums.LogicSlotType
local SI = ic.enums.SorterInstruction
local pos_x = 0
local pos_y = 0
local battery_last_charge = 0
local battery_current_charge = 0
local battery_discharge = 0
-- Daten
local gases = {
{ id = "O2", type = "gas", icon = ss.ui.icons.gas.Oxygen, filter = "ItemGasFilterOxygen", ratio=LT.RatioOxygen, sh = 21.1, mpl = 0, temp_liq = 162, temp_ice = 57},
{ id = "N2", type = "gas", icon = ss.ui.icons.gas.Nitrogen, filter = "ItemGasFilterNitrogen", ratio=LT.RatioNitrogen, sh = 20.6, mpl = 0, temp_liq = 190, temp_ice = 40},
{ id = "CH4", type = "gas", icon = ss.ui.icons.gas.Methane, filter = "ItemGasFilterVolatiles", ratio=LT.RatioMethane, sh = 20.4, mpl = 0, temp_liq = 195, temp_ice = 82},
{ id = "X", type = "gas", icon = ss.ui.icons.gas.Pollutant, filter = "ItemGasFilterPollutants", ratio=LT.RatioPollutant, sh = 24.8, mpl = 0, temp_liq = 434, temp_ice = 173},
{ id = "N2O", type = "gas", icon = ss.ui.icons.gas.NitrousOxide, filter = "ItemGasFilterNitrousOxide", ratio=LT.RatioNitrousOxide, sh = 37.2, mpl = 0, temp_liq = 431, temp_ice = 251},
{ id = "H2O", type = "gas", icon = ss.ui.icons.gas.Steam, filter = "ItemGasFilterWater", ratio=LT.RatioSteam, sh = 72.0, mpl = 0, temp_liq = 644, temp_ice = 274},
{ id = "CO2", type = "gas", icon = ss.ui.icons.gas.CarbonDioxide, filter = "ItemGasFilterCarbonDioxide", ratio=LT.RatioCarbonDioxide, sh = 28.2, mpl = 0, temp_liq = 266, temp_ice = 218},
{ id = "H2", type = "gas", icon = ss.ui.icons.gas.Hydrogen, filter = "ItemGasFilterHydrogen", ratio=LT.RatioHydrogen, sh = 20.4, mpl = 0, temp_liq = 71, temp_ice = 16 },
{ id = "N2H4", type = "gas", icon = ss.ui.icons.gas.Hydrazine, filter = "ItemGasFilterHydrazine", ratio=LT.RatioHydrazine, sh = 48.4, mpl = 0, temp_liq = 521, temp_ice = 246 },
{ id = "He", type = "gas", icon = ss.ui.icons.gas.Helium, filter = "ItemGasFilterHelium", ratio=LT.RatioHelium, sh = 20.8, mpl = 0, temp_liq = 0, temp_ice = 0 },
{ id = "Sil", type = "gas", icon = ss.ui.icons.gas.Silanol, filter = "ItemGasFilterSilanol", ratio=LT.RatioSilanol, sh = 101, mpl = 0, temp_liq = 823, temp_ice = 143 },
{ id = "HCI", type = "gas", icon = ss.ui.icons.gas.HydrochloricAcid, filter = "ItemGasFilterHCl", ratio=LT.RatioHydrochloricAcid, sh = 37.0, mpl = 0, temp_liq = 431, temp_ice = 247 },
{ id = "O3", type = "gas", icon = ss.ui.icons.gas.Ozone, filter = "ItemGasFilterOzone", ratio=LT.RatioOzone, sh = 38.6, mpl = 0, temp_liq = 305, temp_ice = 51 },
{ id = "l_O2", type = "liq", icon = ss.ui.icons.gas.LiquidOxygen, filter = "ItemGasFilterOxygen", ratio=LT.RatioLiquidOxygen, sh = 21.1, mpl = 33.3, temp_liq = 162, temp_ice = 57},
{ id = "l_N2", type = "liq", icon = ss.ui.icons.gas.LiquidNitrogen, filter = "ItemGasFilterNitrogen", ratio=LT.RatioLiquidNitrogen, sh = 20.6, mpl = 28.7, temp_liq = 190, temp_ice = 40},
{ id = "l_CH4", type = "liq", icon = ss.ui.icons.gas.LiquidMethane, filter = "ItemGasFilterVolatiles", ratio=LT.RatioLiquidMethane, sh = 20.4, mpl = 25, temp_liq = 195, temp_ice = 82},
{ id = "l_X", type = "liq", icon = ss.ui.icons.gas.LiquidPollutant, filter = "ItemGasFilterPollutants", ratio=LT.RatioLiquidPollutant, sh = 24.8, mpl = 25, temp_liq = 434, temp_ice = 173},
{ id = "l_N2O", type = "liq", icon = ss.ui.icons.gas.LiquidNitrousOxide, filter = "ItemGasFilterNitrousOxide", ratio=LT.RatioLiquidNitrousOxide, sh = 37.2, mpl = 38.5, temp_liq = 431, temp_ice = 251},
{ id = "l_H2O", type = "liq", icon = ss.ui.icons.gas.Water, filter = "ItemGasFilterWater", ratio=LT.RatioWater, sh = 72.0, mpl = 55.6, temp_liq = 644, temp_ice = 274},
{ id = "l_PH2O", type = "liq", icon = ss.ui.icons.gas.PollutedWater, filter = "ItemGasFilterPollutedWater", ratio=LT.RatioPollutedWater, sh = 64.0, mpl = 55.6, temp_liq = 644, temp_ice = 274},
{ id = "l_CO2", type = "liq", icon = ss.ui.icons.gas.LiquidCarbonDioxide, filter = "ItemGasFilterCarbonDioxide", ratio=LT.RatioLiquidCarbonDioxide, sh = 28.2, mpl = 25, temp_liq = 266, temp_ice = 218 },
{ id = "l_H2", type = "liq", icon = ss.ui.icons.gas.LiquidHydrogen, filter = "ItemGasFilterHydrogen", ratio=LT.RatioLiquidHydrogen, sh = 20.4, mpl = 35.7, temp_liq = 71, temp_ice = 16 },
{ id = "l_N2H4", type = "liq", icon = ss.ui.icons.gas.LiquidHydrazine, filter = "ItemGasFilterHydrazine", ratio=LT.RatioLiquidHydrazine, sh = 48.4, mpl = 33.3, temp_liq = 521, temp_ice = 246 },
{ id = "l_Sil", type = "liq", icon = ss.ui.icons.gas.LiquidSilanol, filter = "ItemGasFilterSilanol", ratio=LT.RatioLiquidSilanol, sh = 101, mpl = 6.25, temp_liq = 823, temp_ice = 143 },
{ id = "l_HCI", type = "liq", icon = ss.ui.icons.gas.LiquidHydrochloricAcid, filter = "ItemGasFilterHCl", ratio=LT.RatioLiquidHydrochloricAcid, sh = 37.0, mpl = 35.7, temp_liq = 431, temp_ice = 247 },
{ id = "l_O3", type = "liq", icon = ss.ui.icons.gas.LiquidOzone, filter = "ItemGasFilterOzone", ratio=LT.RatioLiquidOzone, sh = 38.6, mpl = 38.5, temp_liq = 305, temp_ice = 51 },
{ id = "l_NaCi", type = "liq", icon = ss.ui.icons.gas.LiquidSodiumChloride, filter = "ItemGasFilterSalt", ratio=LT.RatioLiquidSodiumChloride, sh = 130, mpl = 25, temp_liq = 2799,temp_ice = 606},
{ id = "l_ALC", type = "liq", icon = ss.ui.icons.gas.LiquidAlcohol, filter = "ItemGasFilterAlcohol", ratio=LT.RatioLiquidAlcohol, sh = 33.0, mpl = 17.2, temp_liq = 424, temp_ice = 232},
}
-- Screens
local ui_main = ss.ui.surface("main")
local ui_settings = ss.ui.surface("settings")
local ui_devices = ss.ui.surface("devices")
local size = ui_main:size()
local W, H = size.w, size.h
ui_main:clear()
ui_settings:clear()
ui_devices:clear()
-- Anzeigeelemente
-- #########################
-- Funktionen
-- #########################
function genDeviceList()
local devices = ic.device_list()
local help_i = 1
devices_options = {}
devices_ids = {}
for i, dev in ipairs(devices) do
devices_ids[help_i] = { name = dev.display_name, name_hash = dev.name_hash, prefab_hash = dev.prefab_hash }
devices_options[help_i] = dev.display_name
help_i = help_i + 1
end
ui_device:get("select_gs"):set_props({options = devices_options})
for i, dev in ipairs(devices_ids) do
if Settings.Device.GasSensor.prefab_hash == dev.prefab_hash and Settings.Device.GasSensor.name_hash == dev.name_hash then
ui_device:get("select_gs"):set_props({selected = i-1})
end
end
end
function formatPressure(kPa, decimals)
decimals = decimals or 2
local pa = kPa * 1000 -- alles auf Pa als Basis umrechnen
local units = {
{ name = "GPa", factor = 1e9 },
{ name = "MPa", factor = 1e6 },
{ name = "kPa", factor = 1e3 },
{ name = "Pa", factor = 1 },
{ name = "mPa", factor = 1e-3 },
}
local absPa = math.abs(pa)
local unit = units[#units] -- Fallback: kleinste Einheit (mPa)
for _, u in ipairs(units) do
if absPa >= u.factor then
unit = u
break
end
end
local value = pa / unit.factor
return string.format("%." .. decimals .. "f %s", value, unit.name)
end
function isBreathable(sensor)
local press = ic.read(sensor, LT.Pressure)
local temp = ic.read(sensor, LT.Temperature)
local totalMols = ic.read(sensor, LT.TotalMoles)
local o2_prec = ic.read(sensor, LT.RatioOxygen)
local x_prec = ic.read(sensor, LT.RatioPollutant)
local ch4_prec = ic.read(sensor, LT.RatioMethane)
local h2_prec = ic.read(sensor, LT.RatioHydrogen)
local n2h4_prec = ic.read(sensor, LT.RatioHydrazine)
local n2o_prec = ic.read(sensor, LT.RatioNitrousOxide)
local o2_mols = o2_prec * totalMols
local toxin_mols = x_prec * totalMols + ch4_prec * totalMols + n2h4_prec * totalMols + h2_prec * totalMols
local n2o_mols = n2o_prec * totalMols
if temp < 273.15 then
return {
state = false,
comment = "Zu kalt"
}
elseif temp > 323.15 then
return {
state = false,
comment = "Zu heiß"
}
elseif press < 20 then
return {
state = false,
comment = "Zu wenig druck"
}
elseif press > 400 then
return {
state = false,
comment = "Zu viel Druck"
}
elseif o2_mols < 54 then
return {
state = false,
comment = "Zu wenig O2"
}
elseif toxin_mols > 2 then
return {
state = false,
comment = "Toxine erkannt"
}
elseif n2o_mols > 15 then
return {
state = false,
comment = "Narkosegas erkannt"
}
end
return {
state = true,
comment = "Atembar"
}
end
-- Gibt alle vorhanden gase aus die ein Sensor ermittelt
function printGasList(target_surface, sensor_prefabhash, sensor_namehash, iconsize, fontsize, start_x, start_y, width)
local labelheight = 16
local gap = 8
local cols = width / (iconsize + gap)
local grid_x = start_x
local grid_y = start_y
local grid_w = W - 20
local cellW = (grid_w - (cols - 1) * gap) / cols
local y_offset = 0
local i = 1
-- vorhandene elemente löschen
for _, g in ipairs(gases) do
target_surface:remove("icon_" .. g.id)
target_surface:remove("label_" .. g.id)
end
for _, g in ipairs(gases) do
local ratio = ic.batch_read_name(sensor_prefabhash, sensor_namehash, g.ratio, AVG)
if ratio ~= nil and ratio > 0 then
local col = (i - 1) % cols
local row = math.floor((i - 1) / cols)
local x = grid_x + col * (cellW + gap)
local y = grid_y + row * (iconsize + labelheight + gap)
local icon_x = x + (cellW - iconsize) / 2
target_surface:element({
id = "icon_" .. g.id, type = "icon",
rect = { unit = "px", x = icon_x, y = y, w = iconsize, h = iconsize },
props = { name = g.icon },
})
target_surface:element({
id = "label_" .. g.id, type = "label",
rect = { unit = "px", x = x, y = y + iconsize, w = cellW, h = labelheight },
props = { text = string.format("%.1f%%", ratio * 100) },
style = { font_size = fontsize, color = "#94A3B8", align = "center" },
})
i = i + 1
y_offset = y + iconsize + labelheight
end
end
return y_offset
end
-- ####################################################
-- START: MENÜ MAIN
-- ####################################################
function printSide(surface, sensor, start_x, wide)
local temp = ic.read(sensor, LT.Temperature)
local press = ic.read(sensor, LT.Pressure)
local breath = isBreathable(sensor)
local breath_text
local breath_color
if breath.state then
breath_text = breath.comment
breath_color = "#1e9c08"
else
breath_text = breath.comment
breath_color = "#9c0808"
end
local col1 = start_x
local col2 = start_x + wide / 2 - 20
local y = pos_y
surface:element({
id = "gauge_temp_" .. sensor .. "_text", type = "gauge",
rect = { unit = "px", x = col1, y = y, w = wide, h = 80 },
props = {
value = util.temp(temp),
min = 0,
max = 50,
unit = "°C"
},
style = { font_size = 20, color = "#FFFFFF", align = "left" }
})
y = y + 80
surface:element({
id = "gauge_press_" .. sensor .. "_text", type = "gauge",
rect = { unit = "px", x = col1, y = y, w = wide, h = 80 },
props = {
value = press,
min = 20,
max = 150,
unit = "kPa"
},
style = { font_size = 20, color = "#FFFFFF", align = "left" }
})
y = y + 90
surface:element({
id = "panel_breath_" .. sensor .. "_text", type = "panel",
rect = { unit = "px", x = col1, y = y, w = wide, h = 50 },
style = { bg = breath_color }
})
surface:element({
id = "label_breath_" .. sensor .. "_value", type = "label",
rect = { unit = "px", x = col1, y = y, w = wide, h = 50 },
props = { text = breath_text },
style = { font_size = 20, color = "#FFFFFF", align = "center" }
})
end
function rebuildMain()
ui_main:clear()
local margin = 15
local start_left = margin
local start_right = W / 2 + margin
-- Hintergrund
ui_main:element({ id = "panel_main_bg", type = "panel",
rect = { unit = "px", x = 0, y = 0, w = W, h = H },
style = { bg = "#0B1120", radius = 16 }
})
-- Einteilung
ui_main:element({
id = "panel_sep1", type = "panel",
rect = { unit = "px", x = W / 2 - 1, y = 0, w = 2, h = 260 },
style = { bg = "#FFFFFF" }
})
ui_main:element({
id = "panel_sep2", type = "panel",
rect = { unit = "px", x = 0, y = 260, w = W, h = 2 },
style = { bg = "#FFFFFF" }
})
pos_x = margin
pos_y = margin
printSide(ui_main, GS_LEFT, start_left, W / 2 - (margin * 2))
printSide(ui_main, GS_RIGHT, start_right, W / 2 - (margin * 2))
pos_y = 260 + margin
ui_main:element({
id = "icon_battery", type = "icon",
rect = { unit = "px", x = pos_x, y = pos_y, w = 80, h = 80 },
props = { icon_type = "prefab", name = prefab_name(ic.read(BATTERY, LT.PrefabHash)) },
})
ui_main:element({
id = "gauge_battery_charge", type = "gauge",
rect = { unit = "px", x = pos_x + 90, y = pos_y, w = 110, h = 80 },
props = {
value = ic.read(BATTERY, LT.Ratio) * 100,
min = 0,
max = 100,
warn = 0.1,
danger = 0.9,
unit = "%",
invert = true
},
style = { font_size = 20, color = "#FFFFFF", align = "left" }
})
ui_main:element({
id = "gauge_battery_power", type = "gauge",
rect = { unit = "px", x = pos_x + 200, y = pos_y, w = 110, h = 80 },
props = {
value = ic.read(BATTERY, LT.PowerActual),
min = 0,
max = 5000,
unit = "W"
},
style = { font_size = 20, color = "#FFFFFF", align = "left" }
})
if battery_discharge_per_min > 0 then
local remaining = battery_current_charge / battery_discharge_per_min
ui_main:element({
id = "lbl_battery_remaining", type = "label",
rect = { unit = "px", x = pos_x + 320, y = pos_y, w = 110, h = 80 },
props = { text = string.format("Leer in:\n%.0f min", remaining ), },
style = { font_size = 20, color = "#FFFFFF", align = "center" }
})
elseif battery_discharge_per_min < 0 then
ui_main:element({
id = "lbl_battery_remaining", type = "label",
rect = { unit = "px", x = pos_x + 320, y = pos_y, w = 110, h = 80 },
props = { text = "Batterie lädt", },
style = { font_size = 20, color = "#FFFFFF", align = "center" }
})
end
pos_y = pos_y + 90
local btn_text = "Mode: Manual"
local btn_color = "#334155"
if Settings.AutoOpen then
btn_text = "Mode: Auto"
btn_color = "#1e9c08"
end
ui_main:element({
id = "btn_mode", type = "button",
rect = { unit = "px", x = pos_x, y = pos_y, w = 230 - 30, h = 90 },
props = { text = btn_text },
style = { bg = btn_color, text = "#FFFFFF", font_size = 20 },
on_click = function(playerName)
if Settings.AutoOpen then
if ic.read(DOOR, LT.Open) == 1 and ic.read(FORCEFIELD, LT.On) == 0 then
Settings.Manually = 1
else
Settings.Manually = -1
end
Settings.AutoOpen = false
else
Settings.AutoOpen = true
Settings.Manually = 0
end
saveSettings()
ui_main:get("btn_mode"):set_props({ text = "Working..." })
end
})
btn_text = "Öffnen"
if Settings.Manually == -1 and Settings.AutoOpen then
btn_text = "Manuell geschlossen deaktivieren"
elseif Settings.Manually == 1 and Settings.AutoOpen then
btn_text = "Manuell geöffnet deaktivieren"
elseif Settings.Manually == 1 and not Settings.AutoOpen then
btn_text = "Schließen"
elseif Settings.Manually == -1 and not Settings.AutoOpen then
btn_text = "Öffnen"
else
if ic.read(DOOR, LT.Open) == 1 and ic.read(FORCEFIELD, LT.On) == 0 then
btn_text = "Schließen"
end
end
ui_main:element({
id = "btn_change", type = "button",
rect = { unit = "px", x = 245, y = pos_y, w = 230 - 30, h = 90 },
props = { text = btn_text },
style = { bg = "#334155", text = "#FFFFFF", font_size = 20 },
on_click = function(playerName)
if Settings.Manually ~= 0 and Settings.AutoOpen then
Settings.Manually = 0
elseif Settings.Manually == 0 and Settings.AutoOpen then
if ic.read(DOOR, LT.Open) == 1 and ic.read(FORCEFIELD, LT.On) == 0 then
Settings.Manually = -1
else
Settings.Manually = 1
end
elseif Settings.Manually == 1 and not Settings.AutoOpen then
Settings.Manually = -1
elseif Settings.Manually == -1 and not Settings.AutoOpen then
Settings.Manually = 1
end
saveSettings()
ui_main:get("btn_change"):set_props({ text = "Working..." })
end
})
ui_main:commit()
end
-- ####################################################
-- ENDE: MENÜ MAIN
-- ####################################################
ss.ui.activate("main")
-- ####################################################
-- START: TICK
-- ####################################################
local timer = 0
function tick(dt)
-- Grundeinstellung
ic.write(DOOR, LT.Mode, 1)
-- Sensoren
local breath_left = isBreathable(GS_LEFT)
local breath_right = isBreathable(GS_RIGHT)
local temp_left = ic.read(GS_LEFT, LT.Temperature)
local press_left = ic.read(GS_LEFT, LT.Pressure)
local temp_right = ic.read(GS_RIGHT, LT.Temperature)
local press_right = ic.read(GS_RIGHT, LT.Pressure)
local battery_charge = ic.read(BATTERY, LT.Ratio)
-- Helfer
local open_runway = false
-- Prüfen ob der Durchgang geöffnet werden dürfte
print(string.format("BL: %s, BR: %s, T: %s, P: %s", tostring(breath_left.state), tostring(breath_right.state), math.abs(temp_left - temp_right), math.abs(press_left - press_right)))
if
breath_left.state and breath_right.state and
math.abs(temp_left - temp_right) < 2 and
math.abs(press_left - press_right) < 10
then
open_runway = true
end
-- Batterieberechnung
battery_last_charge = battery_current_charge
battery_current_charge = ic.read(BATTERY, LT.Charge)
battery_discharge_per_min = ((battery_last_charge - battery_current_charge) * 5 * 60)
-- Akkubetrieb: Alles abschalten was geht um Energy zu sparen
if battery_charge <= 0.9 and battery_discharge_per_min > 0 then
ic.write(LIGHT, LT.On, 0)
ic.write(DOOR, LT.On, 1)
ic.write(FORCEFIELD, LT.On, 0)
if ic.read(DOOR, LT.Open) == 0 and ic.read(DOOR, LT.Setting) == 1 then
ic.write(DOOR, LT.Open, 1)
ic.write(FORCEFIELD, LT.On, 1)
timer = util.game_time()
elseif ic.read(DOOR, LT.Open) == 1 and timer + 2 < util.game_time() then
ic.write(DOOR, LT.Open, 0)
ic.write(FORCEFIELD, LT.On, 0)
end
-- Normalbetrieb
else
-- Durgang ist Manuell geöffnet worden
if Settings.Manually == 1 then
print("Mode: Manuell geöffnet")
ic.write(FORCEFIELD, LT.On, 0)
ic.write(DOOR, LT.Open, 1)
-- Sofern der Automodus aktiv ist, wird die Manuelle einstellung überschrieben
-- sobald der Runway sowieso geöffnet worden wäre (so kann er sich schließen wenn was
-- schief geht)
if Settings.AutoOpen and open_runway then
Settings.Manually = 0
end
-- Durgang ist Manuell geschlossen worden
elseif Settings.Manually == -1 then
print("Mode: Manuell geschlossen")
ic.write(FORCEFIELD, LT.On, 1)
ic.write(DOOR, LT.Open, 1)
else
print("Mode: Kein Manuell")
if Settings.AutoOpen and open_runway then
print("Mode: Automatik, öffnet durchgang")
ic.write(FORCEFIELD, LT.On, 0)
ic.write(DOOR, LT.Open, 1)
else
print("Mode: Automatik, schließe durchgang")
ic.write(FORCEFIELD, LT.On, 1)
ic.write(DOOR, LT.Open, 1)
end
end
ic.write(DOOR, LT.On, 1)
ic.write(LIGHT, LT.On, 1)
end
rebuildMain()
sleep(0.2)
end
-- ####################################################
-- ENDE: TICK
-- ####################################################
No comments to display
No comments to display