Looking for help simplifying this monster of an if statement

I have here a checker which enables and disables alarms [they have scripts which check the values it sets]. Shouldn’t be too bad right, there’s only two?
Progression is Off < Minor Online < Minor + Major Online.

Problem is, the if statement is just a mess. I’m certain I can simplify this but I’m having a mind blank.
Any ideas?
Here’s the two sections. Brace yourself because it’s hideous. :sweat_smile:

Thermals.UpdateMonitors = function()
	local Temp = Core.Temperature
	local Pump1 = Core.PumpA
	local Pump2 = Core.PumpB
	local Fans = Core.Fans
	
	TempMonitor.TempLabel.Text = tostring(Temp).." °C"
	
	if Temp >= MeltdownValue and CurrentState ~= 'Meltdown' then
		CurrentState = 'Meltdown'
		Thermals.Data.Running = false
		CoreEvents.MeltDeltDownYesICanSpeel:Fire("Meltdown")
		TempMonitor.StatLabel.Text = "Meltdown"
		TempMonitor.StatLabel.TextColor3 = Color3.fromRGB(255, 0, 0)
	elseif Temp >= OverheatValue and CurrentState ~= 'Overheat' and Temp <= MeltdownValue then
		CurrentState = 'Overheat'
		TempMonitor.StatLabel.Text = "Overheat"
		TempMonitor.StatLabel.TextColor3 = Color3.fromRGB(255, 85, 0)
	elseif Temp >= UnstableValue and CurrentState ~= 'Unstable' and Temp <= OverheatValue then
		CurrentState = 'Unstable'
		TempMonitor.StatLabel.Text = "Unstable"
		TempMonitor.StatLabel.TextColor3 = Color3.fromRGB(255, 170, 0)
	elseif Temp <= UnstableValue and CurrentState ~= 'Stable' then
		CurrentState = 'Stable'
		TempMonitor.StatLabel.Text = "Stable"
		TempMonitor.StatLabel.TextColor3 = Color3.fromRGB(0, 170, 0)
	end
	
	Thermals.DoAlarmChecks()
end
local Alarm1 = Interfaces:WaitForChild("Alarms"):WaitForChild("Minor")
local Alarm2 = Interfaces:WaitForChild("Alarms"):WaitForChild("Major")

local AlarmStat = 'Stable'

Thermals.DoAlarmChecks = function()
	local Temp = Core.Temperature
	if Temp >= OverheatValue and AlarmStat ~= "Start_Running_Guys" then
		AlarmStat = "Start_Running_Guys"
		if AlarmsOn == false then
			AlarmsOn = true
			CoreEvents.Alarms:Fire("Meltdown")
		end
		if Alarm1.Active.Value == false or Alarm2.Active.Value == false then
			Alarm1.Active.Value = true
			Alarm2.Active.Value = true
		end
	elseif Temp >= UnstableValue and AlarmStat ~= "Unstable"  and Temp <= OverheatValue then
		AlarmStat = "Unstable"
		if AlarmsOn == true then
			AlarmsOn = false
			CoreEvents.Alarms:Fire("Offline")
		end
		if Alarm1.Active.Value == false then
			Alarm1.Active.Value = true
		end
		if Alarm2.Active.Value == true then
			Alarm2.Active.Value = false
		end
	elseif Temp <= UnstableValue and AlarmStat ~= "Stable" then
		AlarmStat = "Stable"
		if AlarmsOn == true then
			AlarmsOn = false
			CoreEvents.Alarms:Fire("Offline")
		end
		if Alarm1.Active.Value == true or Alarm2.Active.Value == true then
			Alarm1.Active.Value = false
			Alarm2.Active.Value = false
		end
	end
end

AlarmStat is a form of debounce, without it the alarms were toggled every cycle, when they should have remained on.
The two alarms are also defined at the beginning of DoAlarmChecks()
They both contain values called ‘Active’.

Wouldn’t be that worried but this runs every 5 seconds after Temperature is calculated.

Hi!

I hope this is an a solid optimization for the first script. You’ll get the second one back soon. So, this can either work well or make me look like a fool (because I can’t test the code and perhaps spot obvious mistakes). :laughing:

Here you go (OOF):

local Thermals = {}

-- All states share the same color function.
local function changeColor(state, color)
	TempMonitor.StatLabel.Text = state
	TempMonitor.StatLabel.TextColor3 = color
end

Thermals.stateActions = {
	['Meltdown'] = function(state)
		if (CurrentState ~= state) then
			CurrentState = state
			Thermals.Data.Running = false
			CoreEvents.MeltDeltDownYesICanSpeel:Fire('Meltdown')
			changeColor(CurrentState, Color3.fromRGB(255, 0, 0))
		end
	end;
	
	['Overheat'] = function(state)
		if (CurrentState ~= state) then
			CurrentState = state
			changeColor(CurrentState, Color3.fromRGB(255, 85, 0))
		end
	end;
	
	['Unstable'] = function(state)
		if (CurrentState ~= state) then
			CurrentState = state
			changeColor(CurrentState, Color3.fromRGB(255, 170, 0))
		end
	end;
	
	['Stable'] = function(state)
		if (CurrentState ~= state) then
			CurrentState = state
			changeColor(CurrentState, Color3.fromRGB(0, 170, 0))
		end
	end;
}

-- IMPORTANT: Start with critical temperature, because
-- we are comparing values from highest to lowest!
Thermals.TEMPERATURES = {
	{MeltdownValue, Thermals.stateActions.Meltdown};
	{OverheatValue, Thermals.stateActions.Overheat};
	{UnstableValue, Thermals.stateActions.Unstable};
}

function Thermals.updateMonitors()
	local Temp = Core.Temperature
	local Pump1 = Core.PumpA
	local Pump2 = Core.PumpB
	local Fans = Core.Fans

	TempMonitor.TempLabel.Text = tostring(Temp).." °C"
	
	for i, state in ipairs(Thermals.TEMPERATURES) do
		if (Temp >= state[1]) then
			-- Call the method and send it's name as an argument.
			state[2](state[1])
		else
			Thermals.stateActions.Stable('Stable')
		end
	end
	Thermals.DoAlarmChecks()
end

Since these two scripts are actually one script broken into two parts, you can check the states instead of checking temperature values. Each time state changes, alarms adapt.

local Alarm1 = Interfaces:WaitForChild('Alarms'):WaitForChild('Minor')
local Alarm2 = Interfaces:WaitForChild('Alarms'):WaitForChild('Major')

local AlarmStat = 'Stable'

local alarmStates = {
	['Meltdown'] = {'Start_Running_Guys'};
	['Overheat'] = {'Start_Running_Guys'};
}

function Thermals.DoAlarmChecks(state)
	if (AlarmStat ~= state) then
		AlarmStat = alarmStates[state] or state
		
		if (AlarmStat == 'Start_Running_Guys') then
			if (AlarmsOn) then AlarmsOn = true; CoreEvents.Alarms:Fire('Meltdown') end
			Alarm1.Active.Value = true; Alarm2.Active.Value = true
		else
			AlarmsOn = false
			Alarm2.Active.Value = false
			CoreEvents.Alarms:Fire('Offline')
			if (AlarmStat == 'Unstable') then
				Alarm1.Active.Value = true
			else
				Alarm1.Active.Value = false
			end
		end
	end
end
2 Likes

Thanks for this, didn’t even think about doing it that way.
I’ll go and swap that out so it’s in the thermals module and give it a test. :sweat_smile:

No problem! Please tell me if something doesn’t work right so we can correct it and correct the post too. Maybe you can optimize this even more. The script eventually got a form of module script, so I suggest you make necessary changes, add a return statement at the end and put the whole code in module script.

1 Like

This is already inside of a module script, required by CFMS [just a central script] so that it can interact with other services[i.e. meltdown]

1 Like

I did get one error, but I believe I can quickly fix that since it’s a ‘nil value’. I’ll replace some stuff and get back to you.
Fixed it, was just a lowercase ‘u’ on UpdateMonitors()

1 Like

The module functions as intended, only bug is that where the status should update to ‘Unstable’ it switched to the temperature unit.
I can fix that though, thank you for the help!

Excuse me for late replying. Now I updated the previous post with the other part of the script. Keep in mind that this can be optimized even further, but better optimization requires changes in your system. For example, is table with alarm states really needed, or can you use values?

I hope you succeed with your project!

1 Like

I tried some other ways of ‘debouncing’ it, but as there’s two alarms and they’re manipulated in multiple places it immidiately shut off the alarms after enabling them. I’m alright with having longer sections considering this script is the longest one anyway, it’s bound to be memory intensive no matter what I do with it. :joy:
Thanks for all the help! I need to use arrays more.

1 Like

I don’t think your script is as performance demanding as you believe. However, instead of routinely checking the temperature in time intervals, perhaps listen for property changes by using :GetPropertyChangedSignal(). That way your script will only run when temperature changes. Currently, state actions are activated each time loop runs. What you can do alternatively is compare current state and the state temperature allows, and execute the rest of the code only in case state changes.

1 Like

The temperature is changed within the Thermal System, every 5 seconds. It’s the script I use to calculate the change in temperature when coolant, fan level, etc are factored in.