· 4 years ago · Dec 18, 2020, 04:28 AM
1local version = "0.02"
2-- Script by Kotevski
3
4
5-- Skips a single line
6local function skip_line()
7 print(" ")
8end
9
10
11-- Takes user input in a fancy way
12local function prep_input(prompt)
13 term.setCursorPos(1, 18)
14 term.write("--------------------------------------------------")
15 term.setCursorPos(1, 19)
16 term.write(prompt..": ")
17 response = read()
18 return response
19 end
20
21
22-- Clear the screen and reset the cursor position
23local function clear()
24 term.setBackgroundColor(colours.black)
25 term.clear()
26 term.setCursorPos(1,1)
27 print("ccController v"..version.." by Kotevski")
28 skip_line()
29end
30
31
32-- Really stupid shit added for asthetics
33local function pretty()
34 sleep(.005)
35end
36
37
38-- Remove a string from a table
39local function purge_string(local_called_string, local_called_table)
40 for key, value in pairs(local_called_table) do
41 if value == local_called_string then
42 table.remove(local_called_table, key)
43 return local_called_table
44 end
45 end
46end
47
48
49-- User input checker, iterates through
50-- target input list to see if its there
51local function verify_input(local_called_input, local_called_target)
52 for key, value in pairs(local_called_target) do
53 if value == local_called_input then
54 return 1
55 end
56 end
57 return 0
58end
59
60
61-- Split function, lua doesn't have one native
62function split(pString, pPattern)
63 local Table = {} -- NOTE: use {n = 0} in Lua-5.0
64 local fpat = "(.-)" .. pPattern
65 local last_end = 1
66 local s, e, cap = pString:find(fpat, 1)
67 while s do
68 if s ~= 1 or cap ~= "" then
69 table.insert(Table,cap)
70 end
71 last_end = e+1
72 s, e, cap = pString:find(fpat, last_end)
73 end
74 if last_end <= #pString then
75 cap = pString:sub(last_end)
76 table.insert(Table, cap)
77 end
78 return Table
79end
80
81
82-- Modem Detection, returns the side the modem is on
83function detect_modem()
84 side_list = {"top", "bottom", "left", "right", "front", "back"}
85 for key, value in pairs(side_list) do
86 if peripheral.isPresent(value) then
87 if peripheral.getType(value) == "modem" then
88 return value
89 end
90 end
91 end
92 print("ERROR: NO MODEM DETECTED! ADD AN ENDER MODEM!")
93 os.exit()
94end
95
96
97-- Statefile unpacker, the worst function here
98local function unpack_statefile()
99 file = fs.open("statefile.txt", "r")
100 -- Dump every line into an array and then split
101 -- This is super shitty don't judge me i'm tired
102 func_1_dict = {["Number"] = nil, ["Side"] = nil, ["RestCurrent"] = nil, ["Name"] = nil, ["State"] = "off"}
103 func_2_dict = {["Number"] = nil, ["Side"] = nil, ["RestCurrent"] = nil, ["Name"] = nil, ["State"] = "off"}
104 func_3_dict = {["Number"] = nil, ["Side"] = nil, ["RestCurrent"] = nil, ["Name"] = nil, ["State"] = "off"}
105 func_4_dict = {["Number"] = nil, ["Side"] = nil, ["RestCurrent"] = nil, ["Name"] = nil, ["State"] = "off"}
106 func_5_dict = {["Number"] = nil, ["Side"] = nil, ["RestCurrent"] = nil, ["Name"] = nil, ["State"] = "off"}
107 func_6_dict = {["Number"] = nil, ["Side"] = nil, ["RestCurrent"] = nil, ["Name"] = nil, ["State"] = "off"}
108 func_array = {func_1_dict, func_2_dict, func_3_dict, func_4_dict, func_5_dict, func_6_dict}
109 line_number = 0
110 clear()
111 skip_line()
112 print("Opening statefile...")
113 pretty()
114 for line in file.readLine do
115 print("Reading line...")
116 pretty()
117 line_number = line_number+1
118 print("Parsing line number "..line_number)
119 split1 = split(line, "/")
120 for key, value in pairs(split1) do
121 print("Splitting line terms...")
122 pretty()
123 split2 = split(split1[key], "=")
124 print("Assigning terms...")
125 pretty()
126 if key == 1 then
127 func_array[line_number]["Number"] = split2[2]
128 elseif key == 2 then
129 func_array[line_number]["Side"] = split2[2]
130 elseif key == 3 then
131 func_array[line_number]["RestCurrent"] = split2[2]
132 elseif key == 4 then
133 func_array[line_number]["Name"] = split2[2]
134 end
135 end
136 end
137 clear()
138 skip_line()
139 print("Unpacking complete")
140 for key, value in pairs(func_array) do
141 if value["Name"] ~= nil then
142 print("Function: "..value["Number"])
143 print("Name: "..value["Name"])
144 print("Side: "..value["Side"])
145 print("Resting Current: "..value["RestCurrent"])
146 print(" ")
147 end
148 end
149 sleep(2)
150file.close()
151return func_array
152end
153
154
155-- Check to see if a statefile exists
156local function statefile_checker()
157 local statefile_name = "statefile.txt"
158 while true do
159 if fs.exists(statefile_name) == true then
160 clear()
161 skip_line()
162 print("A pre-existing statefile has been found...")
163 skip_line()
164 print("Loading this statefile will resume previous function. Press 1 to use this statefile or 2 to start fresh.")
165 local_input = tonumber(prep_input("Selection"))
166 local_tgt_input = {1, 2}
167 if verify_input(local_input, local_tgt_input) == 1 then
168 if local_input == 1 then
169 -- Keep the old statefile
170 break
171 else
172 -- Create a new statefile
173 fs.delete(statefile_name)
174 statefile_setup()
175 end
176 else
177 print("Invalid input.")
178 end
179 else
180 print("Statefile not found, querying user")
181 state = statefile_setup()
182 if state == 1 then
183 break
184 end
185 end
186 end
187end
188
189
190-- Perform first time setup if statefile missing
191function statefile_setup()
192 file = fs.open("statefile.txt", "w")
193 face_table = {"top", "bottom", "left", "right", "front", "back"}
194 while true do
195 clear()
196 skip_line()
197 print("ccController has not be set up on this computer yet")
198 skip_line()
199 print("How many redstone faces are needed?")
200 local_input = tonumber(prep_input("Number of faces"))
201 face_target = local_input
202 local_tgt_input = {1, 2, 3, 4, 5, 6}
203 if verify_input(local_input, local_tgt_input) == 1 then
204 break
205 end
206 end
207 for i = 1, face_target do
208 -- Get the name of the function from the user and validate
209 while true do
210 clear()
211 skip_line()
212 print("Face "..i.."/"..face_target.." configuration, part 1/3")
213 skip_line()
214 print("Select the name of the function. This is the name that will be broadcasted to the entire network so please make it intuitive as to what it does, like 'Sieve gravel feed' or 'Main door'")
215 skip_line()
216 print("MUST BE UNDER 35 CHARS, ABBREVIATE IF NECESSARY. COMPUTERCRAFT SCREENS ARE SMALL!")
217 face_function_name = tostring(prep_input("Function Name"))
218 if string.len(face_function_name) <= 35 then
219 break
220 end
221 end
222 -- Get the side of the computer for the function and validate
223 local_step_bool = false
224 while local_step_bool == false do
225 clear()
226 skip_line()
227 print("Face "..i.."/"..face_target.." configuration, part 2/3")
228 skip_line()
229 print("Designated: "..face_function_name)
230 skip_line()
231 print("Select the side that will control the redstone")
232 skip_line()
233 term.write("Options: ")
234 for key, value in pairs(face_table) do
235 if key == 1 then
236 term.write(value)
237 else
238 term.write(", "..value)
239 end
240 end
241 local_input = tostring(prep_input("Desired Face"))
242 for key, value in pairs(face_table) do
243 if local_input == value then
244 face_function_side = local_input
245 -- Remove the side from the list of sides
246 face_table = purge_string(local_input, face_table)
247 local_step_bool = true
248 end
249 end
250 end
251 -- Get the resting on/off state of the redstone and validate
252 while true do
253 clear()
254 skip_line()
255 print("Face "..i.."/"..face_target.." configuration, part 3/3")
256 skip_line()
257 print("Designated: "..face_function_name)
258 print("Side: "..face_function_side)
259 skip_line()
260 print("Select the resting redstone state")
261 skip_line()
262 print("Is the redstone signal inverted?")
263 print("(Is the machine on when the redstone is off?)")
264 skip_line()
265 print("Simply enter 'yes' or 'no'")
266 skip_line()
267 local_input = prep_input("Desired Invert Setting")
268 local_input = string.lower(local_input)
269 if local_input == "no" or local_input == "yes" then
270 if local_input == "no" then
271 face_function_resting_state = "on"
272 break
273 elseif local_input == "yes" then
274 face_function_resting_state = "off"
275 break
276 end
277 end
278 end
279 -- Write that shit to the save file
280 file.writeLine("func="..i.."/side="..face_function_side.."/state="..face_function_resting_state.."/name="..face_function_name)
281 end
282 -- Close the file to save the data. Setup is complete
283 file.close()
284 return 1
285end
286
287
288 -- Primary listener function
289function main(func_table, modem_face)
290 rednet.open(modem_face)
291 -- First, let's set really set the states to 'off'
292 for key, value in pairs(func_table) do
293 if value["Name"] ~= nil then
294 -- We have to turn on the redstone to turn it off
295 if value["RestCurrent"] == "off" then
296 redstone.setOutput(value["Side"], true)
297 end
298 end
299 end
300 -- Begin listening loop
301 while true do
302 target_func = {["RestCurrent"] = nil, ["State"] = nil}
303 clear()
304 skip_line()
305 -- Print the states of the programs
306 for key, value in pairs(func_table)do
307 if value["Name"] ~= nil then
308 print(value["Name"].."("..value["Side"]..")".." is "..value["State"])
309 end
310 end
311 skip_line()
312 print("The controller is listening for commands")
313 senderId, message = rednet.receive("Fortuna")
314 -- Swap the on/off state of the target function
315 for key, value in pairs(func_table) do
316 if message == value["Name"] then
317 if value["State"] == "off" then
318 value["State"] = "on"
319 else
320 value["State"] = "off"
321 end
322 target_func = value
323 end
324 end
325 if message == "ping" then
326 sleep(1)
327 rednet.broadcast(func_table, "Fortuna")
328 end
329 -- Apply the changed state to the redstone current
330 if target_func["RestCurrent"] == "off" then
331 if target_func["State"] == "on" then
332 redstone.setOutput(target_func["Side"], false)
333 else
334 redstone.setOutput(target_func["Side"], true)
335 end
336 elseif target_func["RestCurrent"] == "on" then
337 if target_func["State"] == "on" then
338 redstone.setOutput(target_func["Side"], true)
339 else
340 redstone.setOutput(target_func["Side"], false)
341 end
342 end
343 end
344end
345
346
347modem_side = detect_modem()
348
349statefile_checker()
350
351func_array = unpack_statefile()
352
353main(func_array, modem_side)