Coordinated Alarm System: Assistance with setup

Greetings, Roblox Forum. This is my first post; I’m excited to ask questions and learn more on the platform! :smiley:
Now, my issue:

For quite some time I’ve been looking to accomplish making an alarm system that utilizes multiple systems to let you know that… there is an alarm for something happening. The first rendition of this, thanks to a scripting friend long ago, was to have a script in every single instance to accomplish this, and for a long while it worked at the great expense of lag and slowdown of the game.
In the past couple years I have taken to learning coding myself, and I’ve recently discovered the value of the CollectionService and tagging to which I’ve used elaborately for individual items activated by players via prompt.

Utilizing this, I dared to condense the entire system into a single script, and it actually works!- With a catch, however; one that I can’t seem to find a way around no matter how hard I try.
To run it down, there is a console with 4 buttons for 4 values: 0 is disabled, 1-3 is raising levels of alarm. I was able to successfully make all the components align with this, however, with how I have been traditionally scripting, (instances working independently) it worked more like a row of dominos… (So if there was a row of lightbulbs they would turn on one by one)

To just grasp how to rewrite all of this (after many hours of fruitlessly failing at comprehending coroutines and considering I may be approaching this wrong), I want to share how it’s scripted so far, and get help figuring out where I’m going wrong. (Sorry if this is such a huge blurb, first time lol) I think I can figure out improving it if I just get a point in the right direction.

Here’s my coding!

local CollectionService = game:GetService("CollectionService") --roblox stuff
local ProximityPromptService = game:GetService("ProximityPromptService")

local button = workspace.AMBRESEVSystem.Console.BRESEVButton --the console
local bresev = script.AlarmValues.BRESEV --"alarm" values 0-3
local breach = script.AlarmValues.Breach --true/false value

local debounce = script.AlarmValues.Debounce --debounce

ProximityPromptService.PromptTriggered:Connect(function(Prompt,Player) --the player interacts with the console
	if (CollectionService:HasTag(Prompt.Parent,"BRESEV")) then --the console has a special tag "BRESEV"
		--Console
		if debounce.Value == false then --checksum to not allow spam
			debounce.Value = true
			if Prompt.KeyboardKeyCode == Enum.KeyCode.H then --BRESEV 0
				bresev.Value = 0
				breach.Value = false
			elseif Prompt.KeyboardKeyCode == Enum.KeyCode.J then --BRESEV 1
				bresev.Value = 1
				breach.Value = true
			elseif Prompt.KeyboardKeyCode == Enum.KeyCode.K then --BRESEV 2
				bresev.Value = 2
				breach.Value = true
			elseif Prompt.KeyboardKeyCode == Enum.KeyCode.L then --BRESEV 3
				bresev.Value = 3
				breach.Value = true
			end --the system enters a different value based on what the player selects

			--Alarm Lights
			for _, part in pairs(CollectionService:GetTagged("BSAL")) do --each light instance is tagged with this
				local part = part --the tagged brick
				local LT = part:FindFirstChild('LightType') --a variable to check for the light; there are 3 types

				local function flash()
					while breach.Value == true do
						wait(0.775)
						part.Light.Enabled = false
						part.Parent.Alarm.Material = Enum.Material.SmoothPlastic
						wait(0.934)
						part.Light.Enabled = true
						part.Parent.Alarm.Material = Enum.Material.Neon
					end
				end

				local function spin()
					while breach.Value == true do
						part.CFrame = part.CFrame * CFrame.fromEulerAnglesXYZ(0.15, 0, 0)
						wait(0.05)
					end
				end

				local function lightsoff()
					if LT.Value == 1 then --a light that just turns on
						wait(1.5)
						part.effectsAtt.Light.Enabled = false
						part.Material = Enum.Material.Ice
					elseif LT.Value == 2 then --a light that flashes on and off
						wait(1.5)
						part.Light.Enabled = false
						part.Parent.Alarm.Material = Enum.Material.SmoothPlastic
					elseif LT.Value == 3 then --a light that spins
						wait(1.5)
						part.Parent.Case.BrickColor = BrickColor.New("Dusty Rose")
						part.LightF.Enabled = false
						part.LightB.Enabled = false
					end
				end

				if breach.Value == true then
					if LT.Value == 1 then --red
						part.effectsAtt.Light.Enabled = true
						part.Material = Enum.Material.Neon
					elseif LT.Value == 2 then --flash
						spawn(flash)
					elseif LT.Value == 3 then --spin
						part.LightF.Enabled = true
						part.LightB.Enabled = true
						part.Parent.Case.BrickColor = BrickColor.New("Really Red")
						spawn(spin)
					end
				elseif breach.Value == false then
					spawn(lightsoff)
				end
			end
		end
		wait(5)
		debounce.Value = false
	end
end)

So this coding does work as I mentioned, but again, acts like a row of dominos where it has to go through each at a time (let’s say for example there are 50 lights). What are some tips on reformatting this? Thanks in advance!!

1 Like

I would recommend setting up a system where you fire a bindable event that triggers the alarm sequence. For each light you can make a basic trigger script, and when the game starts it will clone the basic script into each light. Then you can change your settings and also get all the alarms to sound at the same time without delay.

1 Like

OK, I’m not entirely sure how this would be engaged (I haven’t yet had the time to rework everything).
So basically wouldn’t I have to make a listening script for when the event is triggered in order for this to work? I’m also a little confused on the trigger script cloning into each of the lights; does that mean I’m running a script to discover all tagged instances, and further is that to put disabled scripts waiting to be enabled, or an enabled script that will trigger a script already there / the system, to which then should I just start with it being there in the first place?
Sorry if this is worded weirdly, thank you for your advice!

1 Like

Sorry I didn’t word it properly lol. What I would do is create a folder or group of some sort with all the lights in it. When the game starts, I would make a script clone a listener script into each of the lights. Next, all you need to do is fire a bindable event (which the listener scripts watch for) and all the lights should work together at the same time. If you need further help please let me know!

1 Like

I think this would defeat the purpose of what I’ve been working on, although the idea of course has merit to it.
This is a revamp off of a system that actually did that exact thing; bindable event, listener scripts, and simultaneous triggers, and it was very effective at doing the simultaneous in which I was looking for–
this was of course at a staunch cost of memory and resources, totaling at the time over 457 scripts that I gutted to finally make my game playable, lol. It seems to be the easiest way to tackle the problem but one of the most costly (although I suppose in worst case scenario I’ll just have to reroll and disembowel everything to its skeletal minimum…)

Thanks again for the advice of course, could you think of any other way this might be approached? Prior to this reach out I had begun to notice people talking about the differences in coroutines vs spawn ,(I use spawn as you can see and I heard it has inbuilt delay, although I don’t know if I have to tackle a deeper problem first…) I don’t know if that’d change anything in any big way. I feel like I just have to reformat how the trigger works. (I did have one attempt that seemed to be good but it couldn’t turn off, I’ll scrounge for that coding later this week if I still have it.)
sorry for the wall lol ty!!! :smile:

Yeah it would be costly in the sense of memory. I don’t know if I could think of any other methods, but coroutines would help, just make sure to save the coroutine so later you can stop it. Personally I’ve used the system of bindable events and listener scripts and it worked, but if you have a lot of lights then maybe using a different route may be best? I’ll let you know if I think of anything.

2 Likes

Not sure exactly why it has a domino effect since I have an alarm system of my own which loops through lights and it does not cause that effect, may be due to the fact that you are giving each light its own pair of functions for spinning, lightsoff, etc which is causing delays for each “round” of the loop (round as in going through each part)

My advice would be have those functions outside of the for loop and the PromptTriggered event.

local function flash(part)
	while breach.Value == true do
		wait(0.775)
		part.Light.Enabled = false
		part.Parent.Alarm.Material = Enum.Material.SmoothPlastic
		wait(0.934)
		part.Light.Enabled = true
		part.Parent.Alarm.Material = Enum.Material.Neon
	end
end

local function spin(part)
	while breach.Value == true do
		part.CFrame = part.CFrame * CFrame.fromEulerAnglesXYZ(0.15, 0, 0)
		wait(0.05)
	end
end

local function lightsoff(part)
	if LT.Value == 1 then --a light that just turns on
		wait(1.5)
		part.effectsAtt.Light.Enabled = false
		part.Material = Enum.Material.Ice
	elseif LT.Value == 2 then --a light that flashes on and off
		wait(1.5)
		part.Light.Enabled = false
		part.Parent.Alarm.Material = Enum.Material.SmoothPlastic
	elseif LT.Value == 3 then --a light that spins
		wait(1.5)
		part.Parent.Case.BrickColor = BrickColor.New("Dusty Rose")
		part.LightF.Enabled = false
		part.LightB.Enabled = false
	end
end

ProximityPromptService.PromptTriggered:Connect(function(Prompt,Player)
	--code here
	for _, part in pairs(CollectionService:GetTagged("BSAL")) do
		local part = part --the tagged brick
		local LT = part:FindFirstChild('LightType')
		if breach.Value == true then
			if LT.Value == 1 then --red
				part.effectsAtt.Light.Enabled = true
				part.Material = Enum.Material.Neon
			elseif LT.Value == 2 then --flash
				task.spawn(flash, part)
			elseif LT.Value == 3 then --spin
				part.LightF.Enabled = true
				part.LightB.Enabled = true
				part.Parent.Case.BrickColor = BrickColor.New("Really Red")
				task.spawn(spin, part)
			end
		elseif breach.Value == false then
			task.spawn(lightsoff, part)
		end
	end
	--rest of the code here
end)

Because we spawn those functions with task.spawn() and because those functions are outside of the for loop and have no reference of part, we add part to the functions arguments. For task.spawn(), you cannot just use task.spawn(function(part)), we must pass the argument like this task.spawn(function, part).
Maybe you already knew that, but just making sure you understand

2 Likes

Hey! Thank you so so much for this tip!!! :smile:
I infact did not know how task.spawn worked; I had only just uncovered it recently and some frail studying I did gave me a headache, but I do learn better by actually working, which I did with your coding, and now kinda understand it!
It seems very successful! The lights went from being all sorts of seconds off from one another to only a few millis-1 second, which I would call a success!- atleast until I can polish up the rest of the script. (Attempt 1 at attaching a clip)
Video (hope I posted it right)

With that said, I attempted to plaster task.spawn for the rest of the code, namely those neon boards in the back to prevent that delay, but instead got errors regarding “nil Values”. It took me a moment before I realized it was because in these cases “part” is not used, but now I’m not sure what to put in its place when its mostly bool value changing vs changing properties in some bricks- if you could help me with that too!!

I tried to put these two functions outside of the script, adding “part” into the function bit:

local function check(part) --checks to see what level the board is at
						if BSN.Value == 0 then
							SelectionHI = B0 --highlight target
						elseif BSN.Value == 1 then
							SelectionHI = B1
						elseif BSN.Value == 2 then
							SelectionHI = B2
						elseif BSN.Value == 3 then
							SelectionHI = B3
						end
					end

					local function highlight(part)
						local c = SelectionHI:GetChildren() --highlight parts that are highlighted (function inside of function seems to break this conversion super bad)

						for index, child in pairs(c) do --CHILDS
							if child.Name == "Part" then
								child.Material = Enum.Material.Neon
							end
						end
					end

From that, I get the torrent of “nil Values” and “nil GetChildren” from each of the instances. How do I fix this: do I change the function’s parentheses to whatever the brick is (in this case now defined “BST” in the code), do I change that when the task is called, or is there something more I’ll have to do?

Sorry again if these are looong-winded, I do as much independent work as I can possibly get and this is by far one of the few times I am completely sunk in the mud. Thanks again!!!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.