View difference between Paste ID: JqFxutFr and GQ7tuA5k
SHOW: | | - or go back to the newest paste.
1
--[[
2
Created By: Augur ShicKla
3
Special Thanks To: TRC & matousss
4
v0.8.16
5
6
System Requirements:
7
Tier 3.5 Memory
8
Tier 3 GPU
9
Tier 3 Screen
10
]]--
11
12
local Version = "0.8.16"
13
local component = require("component")
14
local computer = require("computer")
15
local event = require("event")
16
local os = require("os")
17
local term = require("term")
18
local thread = require("thread")
19
local serialization = require("serialization")
20
local unicode = require("unicode")
21
local filesystem = require("filesystem")
22
local sides = require("sides")
23
local screen = component.screen
24
local gpu = component.gpu
25
local modem = {}
26
27
-- Checking System Requirements are Met --------------------------------------------
28
if gpu.maxResolution() ~= 160 then
29
  io.stderr:write("Tier 3 GPU and Screen Required")
30
  os.exit(1)
31
end
32
if computer.totalMemory() < 1048576 then
33
  io.stderr:write("Not Enough Memory To Run. Please Install More Memory.")
34
  os.exit(1)
35
end
36
if not component.isAvailable("stargate") then
37
  io.stderr:write("No Stargate Connected.")
38
  os.exit(1)
39
end
40
NumberOfGates = 0
41
for k,v in component.list() do
42
  if v == "stargate" then NumberOfGates = NumberOfGates+1 end
43
end
44
if NumberOfGates > 1 then
45
  io.stderr:write("Too Many Stargates Connected to Computer.")
46
  os.exit(1)
47
end
48
-- End of Checking System Requirements ---------------------------------------------
49
50
-- Checking to see if AGS properly closed last time --------------------------------
51
if _G.agsProperlyClosed ~= nil and _G.agsProperlyClosed == false then
52
  io.stderr:write("AGS was not properly shut down last time, and the computer needs to be rebooted.")
53
  os.exit(1)
54
end
55
_G.agsProperlyClosed = false
56
-- End of Checking to see if AGS properly closed last time -------------------------
57
58
-- Declarations --------------------------------------------------------------------
59
local sg = component.stargate
60
61
local GlyphsMW = {"Andromeda","Aquarius","Aries","Auriga","Bootes","Cancer","Canis Minor","Capricornus","Centaurus","Cetus","Corona Australis","Crater","Equuleus","Eridanus","Gemini","Hydra","Leo","Leo Minor","Libra","Lynx","Microscopium","Monoceros","Norma","Orion","Pegasus","Perseus","Pisces","Piscis Austrinus","Sagittarius","Scorpius","Sculptor","Scutum","Serpens Caput","Sextans","Taurus","Triangulum","Virgo"}
62
local GlyphsPG = {"Aaxel","Abrin","Acjesis","Aldeni","Alura","Amiwill","Arami","Avoniv","Baselai","Bydo","Ca Po","Danami","Dawnre","Ecrumig","Elenami","Gilltin","Hacemill","Hamlinto","Illume","Laylox","Lenchan","Olavii","Once El","Poco Re","Ramnon","Recktic","Robandus","Roehi","Salma","Sandovi","Setas","Sibbron","Tahnan","Zamilloz","Zeo"}
63
64
GateType = ""
65
GateTypeName = ""
66
ConnectionErrorString = "Communication error with Stargate. Please disconnect and reconnect.\nIf problem persists verify AUNIS 1.9.6 or greater is installed, and replace Stargate base block."
67
local DatabaseFile = "gateEntries.ff"
68
local DatabaseFileBackup = "gateEntries.bak"
69
local configFile = "dialer.cfg"
70
gateEntries = {}
71
historyEntries = {}
72
AddressBuffer = {}
73
local keyCombo = {}
74
buttons = {}
75
ActiveButtons = {}
76
gateName = ""
77
addAddressMode = false
78
local GoodAddress = false
79
adrEntryType = ""
80
ComputerDialingInterlocked = false
81
local ComputerDialingWithDHD = false
82
editGateEntryMode = false
83
manualAdrEntryMode = false
84
isDirectDialing = false
85
AbortingDialing = false
86
WasCanceled = false
87
wasTerminated = false
88
MainLoop = true
89
HadNoError = true
90
ErrorMessage = nil
91
OutgoingWormhole = false
92
DialingInterlocked = false
93
DebugMode = false
94
RootDrive = nil
95
DialedAddress = {}
96
IncomingWormhole = false
97
GateStatusString, GateStatusBool = nil
98
local UNGateResetting = false
99
local DHD_AdrEntryMode = false
100
local freeMemoryPercent = ""
101
local infoExtensionMode = nil
102
local IrisType = nil
103
local IrisMetaType = nil
104
local DatabaseWriteTimer = nil
105
local IrisSettings = {IDC = nil, AutoCloseIris = true, ModemIDCPort = nil}
106
local IDC = nil
107
local ModemIDCPort = nil
108
local IrisDurability = ""
109
local OutgoingIDC = nil
110
local ChildThread = {}
111
local HasModem = false
112
local AdminList = {}
113
local User = ""
114
local AdminOnlySettings = {Quit = true, AddEntry = true, EditEntry = true, History = true, ToggleIris = true, AdminCanForceDialDHD = false}
115
local MiscSettings = {HideLocalAddr = false, dialWithDHD = false, LudicrousSpeed = false}
116
local HasRedstone = false
117
local RS_Settings = {ExhaustVentSide="north", ChevronEngagedSide="top", WormholeOpenSide="bottom", GateIsActiveSide="east"}
118
local AdminDialed = false
119
local ForceDialDHD = false
120
local DialingPaused = false
121
local WormholeConnected = false
122
-- End of Declarations -------------------------------------------------------------
123
124
-- Pre-Initialization --------------------------------------------------------------
125
if sg.getGateType() == "MILKYWAY" then
126
  GateType = "MW"
127
  GateTypeName = "Milky Way"
128
  if not pcall(function() sg.getEnergyRequiredToDial({GlyphsMW[1]}) end) then
129
    io.stderr:write("MW: "..ConnectionErrorString)
130
    os.exit(1)
131
  end
132
elseif sg.getGateType() == "UNIVERSE" then
133
  GateType = "UN"
134
  GateTypeName = "Universe"
135
  if not pcall(function() sg.getEnergyRequiredToDial({"G1"}) end) then
136
    io.stderr:write("UN: "..ConnectionErrorString)
137
    os.exit(1)
138
  end
139
elseif sg.getGateType() == "PEGASUS" then
140
  GateType = "PG"
141
  GateTypeName = "Pegasus"
142
  if not pcall(function() sg.getEnergyRequiredToDial({GlyphsPG[1]}) end) then
143
    io.stderr:write("PG: "..ConnectionErrorString)
144
    os.exit(1)
145
  end
146
else
147
  io.stderr:write("Gate Type Not Recognized")
148
  os.exit(1)
149
end
150
151
for k,v in filesystem.mounts() do -- Searches for the filesystem that holds root and assigns it to the RootDrive variable
152
  if v == "/" then
153
    RootDrive = k
154
  end
155
end
156
157
if component.isAvailable("modem") then
158
  HasModem = true
159
  modem = component.modem
160
end
161
162
if component.isAvailable("redstone") then
163
  HasRedstone = true
164
  redstone = component.redstone
165
  for i=0,5,1 do
166
    redstone.setOutput(i, 0)
167
  end
168
end
169
-- End of Pre-Initialization -------------------------------------------------------
170
171
-- Config File IO ------------------------------------------------------------------
172
local function readConfig()
173
  local file = io.open("dialer.cfg", "r")
174
  if file == nil then return end
175
  file:close()
176
  if not pcall(function() dofile("dialer.cfg") end) then
177
    io.stderr:write("Failed to load config file!\n")
178
  end
179
end
180
181
function IrisConfig(options)
182
  if type(options.IDC) == "number" and options.IDC >= 0 and options.IDC < 1e9 and math.floor(options.IDC) == options.IDC then
183
    IDC = options.IDC
184
  elseif options.IDC == nil then
185
    io.stderr:write("No IDC Provided\n")
186
  else
187
    io.stderr:write("IDC in config file is invalid\n")
188
  end
189
  
190
  if type(options.AutoCloseIris) == "boolean" then
191
    IrisSettings.AutoCloseIris = options.AutoCloseIris
192
  else
193
    io.stderr:write("AutoCloseIris in config file is invalid\n")
194
  end
195
  
196
  if type(options.NetworkPort) == "number" and options.NetworkPort > 0 and options.NetworkPort <= 65535 and math.floor(options.NetworkPort) == options.NetworkPort then
197
    ModemIDCPort = options.NetworkPort
198
    if HasModem then modem.open(ModemIDCPort) end
199
  elseif options.NetworkPort == nil then
200
    io.stderr:write("No IDC Network Port Provided\n")
201
  else
202
    io.stderr:write("IDC Network Port in config file is invalid\n")
203
  end  
204
  
205
  IrisConfig = nil
206
end
207
208
function AdminAccess(options)
209
  if type(options.Quit) == "boolean" then AdminOnlySettings.Quit = options.Quit end
210
  if type(options.AddEntry) == "boolean" then AdminOnlySettings.AddEntry = options.AddEntry end
211
  if type(options.EditEntry) == "boolean" then AdminOnlySettings.EditEntry = options.EditEntry end
212
  if type(options.History) == "boolean" then AdminOnlySettings.History = options.History end
213
  if type(options.ToggleIris) == "boolean" then AdminOnlySettings.ToggleIris = options.ToggleIris end
214
  if type(options.AdminCanForceDialDHD) == "boolean" then AdminOnlySettings.AdminCanForceDialDHD = options.AdminCanForceDialDHD end
215
  AdminAccess = nil
216
end
217
218
function OtherSettings(options)
219
  if type(options.HideLocalAddr) == "boolean" then MiscSettings.HideLocalAddr = options.HideLocalAddr end
220
  if type(options.dialWithDHD) == "boolean" then MiscSettings.dialWithDHD = options.dialWithDHD end
221
  if type(options.LudicrousSpeed) == "boolean" then MiscSettings.LudicrousSpeed = options.LudicrousSpeed end
222
  OtherSettings = nil
223
end
224
225
function RedstoneSettings(options)
226
  if type(options.ExhaustVentSide) == "string" then RS_Settings.ExhaustVentSide = options.ExhaustVentSide end
227
  if type(options.ChevronEngagedSide) == "string" then RS_Settings.ChevronEngagedSide = options.ChevronEngagedSide end
228
  if type(options.WormholeOpenSide) == "string" then RS_Settings.WormholeOpenSide = options.WormholeOpenSide end
229
  if type(options.GateIsActiveSide) == "string" then RS_Settings.GateIsActiveSide = options.GateIsActiveSide end
230
  RedstoneSettings = nil
231
end
232
233
local function tableFormatter(tbl)
234
  local bufString = serialization.serialize(tbl)
235
  bufString = bufString:gsub("{","{\n  ")
236
  bufString = bufString:gsub(",}","}")
237
  bufString = bufString:gsub(",",",\n  ")
238
  bufString = bufString:gsub("}","\n}\n\n")
239
  return bufString
240
end
241
242
local function writeConfig()
243
  local file = io.open("dialer.cfg", "w")
244
  file:write("-- Do not edit this file directly unless you know what you are doing.\n\n")
245
  file:write("IrisConfig{\n  IDC="..tostring(IDC)..",\n  AutoCloseIris="..tostring(IrisSettings.AutoCloseIris)..",\n  NetworkPort="..tostring(ModemIDCPort).."\n}\n\n")
246
  file:write("AdminAccess"..tableFormatter(AdminOnlySettings))
247
  file:write("OtherSettings"..tableFormatter(MiscSettings))
248
  file:write("RedstoneSettings"..tableFormatter(RS_Settings))
249
  file:close()
250
end
251
252
readConfig()
253
writeConfig()
254
-- Config File IO End --------------------------------------------------------------
255
256
-- AdminList File IO ---------------------------------------------------------------
257
local function readAdminList()
258
  if filesystem.exists(shell.getWorkingDirectory().."/adminList.txt") then
259
    for line in io.lines("adminList.txt") do
260
      table.insert(AdminList, line)
261
    end
262
  else
263
    file = io.open("adminList.txt", "w")
264
    file:close()
265
  end
266
end
267
268
readAdminList()
269
-- AdminList File IO End -----------------------------------------------------------
270
271
-- Button Object -------------------------------------------------------------------
272
local Button = {}
273
Button.__index = Button
274
function Button.new(xPos, yPos, width, height, label, func, border)
275
  local self = setmetatable({}, Button)
276
  if xPos < 1 or xPos > term.window.width then xPos = 1 end
277
  if yPos < 1 or yPos > term.window.height then yPos = 1 end
278
  if (width-2) < unicode.len(label) then width = unicode.len(label)+2 end
279
  if height < 3 then height = 3 end
280
  if border == nil then
281
    self.border = true
282
  else
283
    self.border = border
284
  end
285
  self.xPos = xPos
286
  self.yPos = yPos
287
  self.width = width
288
  self.height = height
289
  self.label = label
290
  self.func = func
291
  self.visible = false
292
  self.disabled = false
293
  return self
294
end
295
296
function Button.display(self, x, y)
297
  table.insert(ActiveButtons, 1, self)
298
  if (self.width-2) < unicode.len(self.label) then self.width = unicode.len(self.label)+2 end
299
  if x ~= nil and y ~= nil then
300
    self.xPos = x
301
    self.yPos = y
302
  end
303
  if self.border then
304
    gpu.fill(self.xPos+1, self.yPos, self.width-2, 1, "─")
305
    gpu.fill(self.xPos+1, self.yPos+self.height-1, self.width-2, 1, "─")
306
    gpu.fill(self.xPos, self.yPos+1, 1, self.height-2, "│")
307
    gpu.fill(self.xPos+self.width-1, self.yPos+1, 1, self.height-2, "│")
308
    gpu.set(self.xPos, self.yPos, "┌")
309
    gpu.set(self.xPos+self.width-1, self.yPos, "┐")
310
    gpu.set(self.xPos, self.yPos+self.height-1, "└")
311
    gpu.set(self.xPos+self.width-1, self.yPos+self.height-1, "┘")
312
  end
313
  gpu.set(self.xPos+1, self.yPos+1, self.label)
314
  self.visible = true
315
end
316
317
function Button.hide(self)
318
  self.visible = false
319
  for i,v in ipairs(ActiveButtons) do
320
    if v == self then table.remove(ActiveButtons, i) end
321
  end
322
  if self.border then
323
    gpu.fill(self.xPos, self.yPos, self.width, self.height, " ")
324
  else
325
    gpu.fill(self.xPos+1, self.yPos+1, self.width-2, 1, " ")
326
  end
327
end
328
329
function Button.disable(self, bool)
330
  if bool == nil then
331
    self.disabled = false
332
  else
333
    self.disabled = bool
334
  end
335
  if self.disabled then gpu.setForeground(0x0F0F0F) end
336
  if self.visible then self:display() end
337
  gpu.setForeground(0xFFFFFF)
338
end
339
340
function Button.touch(self, x, y)
341
  local wasTouched = false
342
  if self.visible and not self.disabled then  
343
    if self.border then
344
      if x >= self.xPos and x <= (self.xPos+self.width-1) and y >= self.yPos and y <= (self.yPos+self.height-1) then wasTouched = true end
345
    else
346
      if x >= self.xPos+1 and x <= (self.xPos+self.width-2) and y >= self.yPos+1 and y <= (self.yPos+self.height-2) then wasTouched = true end
347
    end
348
  end
349
  if wasTouched then
350
    gpu.setBackground(0x878787)
351
    gpu.set(self.xPos+1, self.yPos+1, self.label)
352
    gpu.setBackground(0x000000)
353
    if self.visible then gpu.set(self.xPos+1, self.yPos+1, self.label) end
354
    self.func()
355
  end
356
  return wasTouched
357
end
358
359
function Button.forceTouch(self)
360
  self:touch(self.xPos+1, self.yPos+1)
361
end
362
-- End of Button Object ------------------------------------------------------------
363
364
-- Check Box Object ----------------------------------------------------------------
365
local CheckBox = {}
366
CheckBox.__index = CheckBox
367
function CheckBox.new(xPos, yPos, tbl, tblKey, func)
368
  local self = setmetatable({}, CheckBox)
369
  self.xPos = xPos
370
  self.yPos = yPos
371
  self.tbl = tbl
372
  self.tblKey = tblKey
373
  self.visible = false
374
  self.disabled = false
375
  self.isChecked = self.tbl[self.tblKey]
376
  self.func = func
377
  return self
378
end
379
380
function CheckBox.display(self, isChecked, x, y)
381
  table.insert(ActiveButtons, 1, self)
382
  if isChecked ~= nil then
383
    self.isChecked = isChecked
384
  end  
385
  if x ~= nil and y ~= nil then
386
    self.xPos = x
387
    self.yPos = y
388
  end
389
  gpu.set(self.xPos, self.yPos, "[ ]")
390
  if self.isChecked then
391
    gpu.setForeground(0x00FF00)
392
    gpu.set(self.xPos+1, self.yPos, "X")
393
    gpu.setForeground(0xFFFFFF)
394
  end
395
  self.visible = true
396
end
397
398
function CheckBox.hide(self)
399
  self.visible = false
400
  for i,v in ipairs(ActiveButtons) do
401
    if v == self then table.remove(ActiveButtons, i) end
402
  end
403
  gpu.fill(self.xPos, self.yPos, 3, 1, " ")
404
end
405
406
function CheckBox.disable(self, bool)
407
  if bool == nil then
408
    self.disabled = false
409
  else
410
    self.disabled = bool
411
  end
412
  if self.disabled then gpu.setForeground(0x0F0F0F) end
413
  if self.visible then self:display() end
414
  gpu.setForeground(0xFFFFFF)
415
end
416
417
function CheckBox.touch(self, x, y)
418
  local wasTouched = false
419
  if self.visible and not self.disabled and x >= self.xPos and x < (self.xPos+3) and y == self.yPos then
420
    wasTouched = true
421
  end
422
  if wasTouched then
423
    if self.isChecked then
424
      self.isChecked = false
425
    elseif not self.isChecked then
426
      self.isChecked = true
427
    end
428
    self.tbl[self.tblKey] = self.isChecked
429
    self.func()
430
    self:display()
431
  end
432
  return wasTouched
433
end
434
-- End Check Box Object ------------------------------------------------------------
435
436
-- Special Functions ---------------------------------------------------------------
437
local function alert(msg, lvl)
438
  if lvl == nil or lvl < 0 then lvl = 3 end
439
  if type(msg) ~= "string" then error("alert() requires a string") end
440
  if ChildThread.AlertThread ~= nil then ChildThread.AlertThread:kill() end
441
  if lvl >= 0 then
442
    ChildThread.AlertThread = thread.create(function()
443
        gpu.setForeground(0x000000)
444
        if lvl == 0 or lvl == 1 then
445
          gpu.setBackground(0x00FF00)
446
          if lvl == 1 then computer.beep(1000) end
447
        elseif lvl == 2 then
448
          computer.beep()
449
          gpu.setBackground(0xFFFF00)
450
        elseif lvl == 3 then
451
          computer.beep(450, 0.5)
452
          gpu.setForeground(0xFFFFFF)
453
          gpu.setBackground(0xFF0000)
454
        end
455
        gpu.fill(1, 1, term.window.width, 1, " ")
456
        gpu.fill(1, term.window.height, term.window.width, 1, " ")
457
        gpu.set ((term.window.width/2)-(unicode.len(msg)/2), 1, msg)
458
        gpu.setForeground(0xFFFFFF)
459
        gpu.setBackground(0x000000)
460
        os.sleep(10)
461
        gpu.setForeground(0xFFFFFF)
462
        gpu.setBackground(0x000000)
463
        gpu.fill(1, 1, term.window.width, 1, " ")
464
        gpu.fill(1, term.window.height, term.window.width, 1, " ")
465
    end)
466
  else
467
    gpu.fill(1, 1, term.window.width, 1, " ")
468
    gpu.fill(1, term.window.height, term.window.width, 1, " ")
469
  end
470
end
471
472
local function checkGlyph(glyph, adrType)
473
  local isGood = false
474
  local fixedGlyph = "Unknown"
475
  local glyphsTbl = {}
476
  if adrType == "UN" then
477
    for i=1,36,1 do
478
      if string.lower(glyph) == "g"..i or string.lower(glyph) == "glyph "..i or string.lower(glyph) == "glyph"..i then
479
        fixedGlyph = "Glyph "..i
480
        isGood = true
481
        break
482
      end
483
    end
484
  else
485
    if adrType == "MW" then
486
      glyphsTbl = GlyphsMW
487
      if glyph == "PointofOrigin" or glyph == "Point of Origin" or glyph == "Origin" then
488
        fixedGlyph = "Point of Origin"
489
        isGood = true
490
        return isGood, fixedGlyph 
491
      end
492
    elseif adrType == "PG" then
493
      glyphsTbl = GlyphsPG
494
      if glyph == "Subido" then
495
        fixedGlyph = "Subido"
496
        isGood = true
497
        return isGood, fixedGlyph 
498
      end
499
    end
500
    for i,v in ipairs(glyphsTbl) do
501
      if string.lower(string.gsub(glyph,"%s+","")) == string.lower(string.gsub(v,"%s+","")) then
502
        fixedGlyph = v
503
        isGood = true
504
        break
505
      end
506
    end
507
  end
508
  return isGood, fixedGlyph  
509
end
510
511
function GateEntry(ge)
512
  if ge.gateAddress.UN ~= nil and #ge.gateAddress.UN ~= 0 then
513
    for i,v in ipairs(ge.gateAddress.UN) do
514
      _,ge.gateAddress.UN[i] = checkGlyph(v, "UN")
515
    end
516
  end
517
  if ge.fave == nil then ge.fave = false end
518
  table.insert(gateEntries, ge)
519
end
520
521
function HistoryEntry(ge)
522
  if ge.gateAddress.UN ~= nil and #ge.gateAddress.UN ~= 0 then
523
    for i,v in ipairs(ge.gateAddress.UN) do
524
      _,ge.gateAddress.UN[i] = checkGlyph(v, "UN")
525
    end
526
  end
527
  table.insert(historyEntries, ge)
528
end
529
530
local function initialLoadAddressFile()
531
  local file = io.open(DatabaseFile, "r")
532
  if file == nil then
533
    file = io.open(DatabaseFile, "w")
534
  end
535
  file:close()
536
  gateEntries = {}
537
  historyEntries = {}
538
  dofile(DatabaseFile)
539
  if #gateEntries > 0 then
540
      file, msg = io.open(DatabaseFileBackup, "w")
541
      for i,v in ipairs(gateEntries) do
542
        file:write("GateEntry"..serialization.serialize(v).."\n")
543
      end
544
      file:write("\n")
545
      for i,v in ipairs(historyEntries) do
546
        file:write("HistoryEntry"..serialization.serialize(v).."\n")
547
      end
548
      file:close()  
549
  else
550
    file = io.open(DatabaseFileBackup, "r")
551
    if file ~= nil then
552
      file:close()
553
      dofile(DatabaseFileBackup)
554
    end  
555
  end
556
end
557
558
local function readAddressFile()
559
  local file = io.open(DatabaseFile, "r")
560
  if file == nil then
561
    file = io.open(DatabaseFile, "w")
562
  end
563
  file:close()
564
  gateEntries = {}
565
  historyEntries = {}
566
  dofile(DatabaseFile)
567
end
568
569
local function writeToDatabase()
570
  local status, value = pcall(function() return ChildThread.databaseWrite:status() end)
571
  if status == true then
572
    while ChildThread.databaseWrite:status() ~= "dead" do end
573
  end
574
  ChildThread.databaseWrite = thread.create(function()
575
    local file, msg = io.open(DatabaseFile, "w")
576
    for i,v in ipairs(gateEntries) do
577
      file:write("GateEntry"..serialization.serialize(v).."\n")
578
    end
579
    file:write("\n")
580
    for i,v in ipairs(historyEntries) do
581
      file:write("HistoryEntry"..serialization.serialize(v).."\n")
582
    end
583
    file:close()
584
    readAddressFile()
585
  end)
586
587
  -- if DatabaseWriteTimer ~= nil then
588
    -- event.cancel(DatabaseWriteTimer)
589
    -- DatabaseWriteTimer = nil
590
  -- end
591
  -- DatabaseWriteTimer = event.timer(5, function()
592
    -- -- alert("Database Saved", 1) -- For Debug
593
    -- local file, msg = io.open(DatabaseFile, "w")
594
    -- for i,v in ipairs(gateEntries) do
595
      -- file:write("GateEntry"..serialization.serialize(v).."\n")
596
    -- end
597
    -- file:write("\n")
598
    -- for i,v in ipairs(historyEntries) do
599
      -- file:write("HistoryEntry"..serialization.serialize(v).."\n")
600
    -- end
601
    -- file:close()
602
    -- readAddressFile()
603
    -- DatabaseWriteTimer = nil
604
  -- end)
605
  GateEntriesWindow.update() 
606
end
607
608
local function runPlugin()
609
  if io.open("plugin.lua", "r") == nil then
610
    return
611
  end
612
  
613
  ChildThread.pluginThread = thread.create(function()
614
    local status, err = xpcall(function()
615
      dofile("plugin.lua")
616
    end, debug.traceback)
617
    if err ~= nil then
618
      ErrorMessage = "Error in Plugin \n"..err
619
    end
620
    HadNoError = status
621
  end)
622
end
623
624
local function addressToString(tbl)
625
  local str = "["
626
  for i,v in ipairs(tbl) do
627
    str = str..v
628
    if #tbl ~= i then str = str.." - " end
629
  end
630
  str = str.."]"
631
  return str
632
end
633
634
local function clearDisplay()
635
  for k in pairs(buttons) do buttons[k]:hide() end
636
  gateRingDisplay.isActive = false
637
  gpu.fill(41, 2, 120-(2*glyphListWindow.width), 39, " ")
638
  gpu.fill(43, 2, 118-(2*glyphListWindow.width), 42, " ")
639
end
640
641
function entriesDuplicateCheck(adr, entriesTable, adrType, pos)
642
  local hasDuplicate = false
643
  local duplicateNames = {}
644
  local entriesBuffer = {}
645
  local glyph = ""
646
  if #entriesTable ~= 0 then
647
    if pos > 6 then
648
      hasDuplicate = true
649
      for i,v in ipairs(entriesTable) do table.insert(duplicateNames, v.name) end
650
    else
651
      for i,v in ipairs(entriesTable) do
652
        if v.gateAddress[adrType] ~= nil and #v.gateAddress[adrType] ~= 0 then
653
          _,glyph = checkGlyph(adr[pos], adrType)
654
          if glyph == v.gateAddress[adrType][pos] then
655
            table.insert(entriesBuffer, v)
656
          end
657
        end
658
      end
659
      pos = pos + 1
660
      hasDuplicate, duplicateNames = entriesDuplicateCheck(adr, entriesBuffer, adrType, pos)
661
    end
662
  end
663
  return hasDuplicate, duplicateNames
664
end
665
666
function parseAddressString(adrStr, adrType)
667
  local adrBuf = {}
668
  if type(adrStr) == "string" then
669
    for w in string.gmatch(string.gsub(adrStr, "%s", ""), "%w+") do
670
      table.insert(adrBuf, w)
671
    end
672
    if #adrBuf > 0 then
673
      for i,v in ipairs(adrBuf) do
674
        _,adrBuf[i] = checkGlyph(v, adrType)
675
      end
676
    end
677
  end
678
  return adrBuf
679
end
680
681
local function userInput(x, y, maxLength, touchExits, timeoutEnabled)
682
  local threadStates = {}
683
  for _,v in pairs(ChildThread) do
684
    threadStates[v] = v:status()
685
    v:suspend()
686
  end
687
  local success = true
688
  local inputString = ""
689
  local strLength = 0
690
  if maxLength == nil or maxLength == 0 then maxLength = 32 end
691
  term.setCursor(x, y)
692
  term.setCursorBlink(true)
693
  gpu.setBackground(0x878787)
694
  gpu.fill(x, y, maxLength, 1, " ")
695
  gpu.setBackground(0x000000)
696
  local timeoutTimer = 0
697
  if timeoutEnabled then
698
    timeoutTimer = event.timer(10, function()
699
      alert("User Input Timed Out", 1)
700
      computer.pushSignal("touch", nil, 0, 0, 0, "FakePlayer")
701
    end)
702
  end
703
  while true do
704
    -- term.setCursorBlink(true)
705
    local e, address, arg1, arg2, arg3 = term.pull()
706
    if e == "touch" and touchExits then
707
      success = false
708
      break
709
    end
710
    if e == "key_down" then
711
      if arg2 ~= 28 and arg2 ~= 14 and arg1 ~= 0 and strLength < maxLength then -- Not Enter, Backspace, or Other
712
        inputString = inputString..unicode.char(arg1)
713
      elseif arg2 == 14 then -- Backspace Key
714
        inputString = unicode.wtrunc(inputString, strLength)
715
      elseif arg2 == 28 then -- Enter Key
716
        break
717
      end
718
      strLength = unicode.len(inputString)
719
      gpu.setBackground(0x878787)
720
      gpu.fill(x, y, maxLength, 1, " ")
721
      gpu.set(x, y, inputString)
722
      gpu.setBackground(0x000000)
723
      term.setCursor(x+strLength, y)
724
    end
725
    -- if WasCanceled then
726
      -- WasCanceled = false
727
      -- inputString = ""
728
      -- break
729
    -- end
730
  end
731
  event.cancel(timeoutTimer)
732
  -- gpu.setBackground(0x000000)
733
  -- term.setCursorBlink(false)
734
  -- gpu.fill(x, y, maxLength, 1, " ")
735
  for k,v in pairs(threadStates) do
736
    if v == "running" then k:resume() end
737
  end
738
  -- alert("Input Closed", 1) -- For Debug
739
  return inputString, success
740
end
741
742
function updateHistory()
743
  if #DialedAddress < 6 then return end
744
  local adrName = "UNKNOWN"
745
  local address = {}
746
  local timeString = os.date("%H:%M %d/%m", getRealTime())..""
747
  for i,v in ipairs(DialedAddress) do
748
    if i < #DialedAddress then
749
      table.insert(address, v)
750
    end
751
  end
752
  local inDatabase, duplicateNames = entriesDuplicateCheck(address, gateEntries, GateType, 1)
753
  if inDatabase then
754
    adrName = duplicateNames[1]
755
  end
756
  table.insert(historyEntries, 1, {name=adrName, gateAddress={[GateType]=address}, t=getRealTime(), AdminOnly=AdminDialed})
757
  while #historyEntries > 50 do
758
    table.remove(historyEntries)
759
  end
760
  GateEntriesWindow.range.botH = 1
761
  GateEntriesWindow.range.topH = GateEntriesWindow.range.height
762
  writeToDatabase()
763
  AdminDialed = false
764
end
765
766
function getRealTime()
767
  local tmpFile = io.open("/tmp/.time", "w")
768
  tmpFile:write()
769
  tmpFile:close()
770
  return math.floor(filesystem.lastModified("/tmp/.time") / 1000)
771
end
772
773
local function isAuthorized(name, isEnabled)
774
  local authorized = false
775
  if type(isEnabled) ~= "boolean" then isEnabled = true end
776
  if isEnabled then 
777
    if #AdminList == 0 then
778
      authorized = true
779
    else
780
      for _,v in ipairs(AdminList) do
781
        if string.lower(v) == string.lower(name) then
782
          authorized = true
783
          break
784
        end
785
      end
786
    end
787
  else
788
    authorized = true
789
  end
790
  if not authorized then alert("ACCESS DENIED", 2) end
791
  return authorized
792
end
793
-- End of Special Functions --------------------------------------------------------
794
795
-- Info Center ---------------------------------------------------------------------
796
local function displaySystemStatus()
797
  local xPos = 2
798
  local yPos = 45
799
  local energyStored = 0
800
  local energyMax = 0
801
  local capCount = 0
802
  local irisState = nil
803
  local status, err = pcall(function()
804
    energyStored = sg.getEnergyStored()
805
    energyMax = sg.getMaxEnergyStored()
806
    capCount = sg.getCapacitorsInstalled()  
807
  end)
808
  if status == false then
809
    ErrorMessage = "Stargate Has Been Disconnected"
810
    HadNoError = false
811
  end
812
  pcall(function() 
813
    irisState = sg.getIrisState()
814
  end)
815
  -- local freeMemory = computer.freeMemory()
816
  -- local totalComputerMemory = computer.totalMemory()
817
  gpu.set(17, term.window.height-6, "╡")
818
  gpu.set(29, term.window.height-6, "╞")
819
  gpu.setForeground(0x000000)
820
  if GateStatusString == "open" then
821
    gpu.setBackground(0xFFFF00)
822
    gpu.set(18, term.window.height-6, " GATE OPEN ")
823
  else
824
    gpu.setBackground(0x00FF00)
825
    gpu.set(18, term.window.height-6, "GATE CLOSED")
826
  end
827
  gpu.setForeground(0xFFFFFF)
828
  gpu.setBackground(0x000000)
829
  gpu.set(30, term.window.height-6, "═════════════")
830
  if IrisType ~= nil and IrisType ~= "NULL" then
831
    if IrisType == "SHIELD" then
832
      gpu.set(30, term.window.height-6, "╡░░░░░░░░░░╞")
833
      if irisState == "OPENED" then
834
        if GateStatusString == "open" and GateStatusBool == false then
835
          gpu.setForeground(0x000000)
836
          gpu.setBackground(0xFFFF00)
837
        end
838
        gpu.set(31, term.window.height-6, "SHIELD OFF")
839
      elseif irisState == "CLOSED" then
840
        gpu.set(31, term.window.height-6, "SHIELD ON ")
841
      end
842
    else
843
      gpu.set(30, term.window.height-6, "╡░░░░░░░░░░░╞")
844
      if irisState == "OPENED" then
845
        if GateStatusString == "open" and GateStatusBool == false then
846
          gpu.setForeground(0x000000)
847
          gpu.setBackground(0xFFFF00)
848
        end
849
        gpu.set(31, term.window.height-6, " IRIS OPEN ")
850
      elseif irisState == "CLOSED" then
851
        gpu.set(31, term.window.height-6, "IRIS CLOSED")
852
      end
853
    end
854
    gpu.setForeground(0xFFFFFF)
855
    gpu.setBackground(0x000000)
856
  end
857
  gpu.fill(xPos, yPos, 44, 4, " ")
858
  gpu.set(xPos+1, yPos, "Energy Level: "..energyStored.."/"..energyMax.." RF "..math.floor((energyStored/energyMax)*100).."%")
859
  gpu.set(xPos+1, yPos+1, "Capacitors Installed: "..capCount.."/3")
860
  -- gpu.set(xPos+1, yPos+3, "Computer Memory Remaining: "..math.floor((freeMemory/totalComputerMemory)*100).."%")
861
  gpu.set(xPos+1, yPos+3, "Computer Memory Remaining: "..freeMemoryPercent)
862
  if IrisType ~= nil and IrisType ~= "NULL" then
863
    gpu.set(xPos+1, yPos+2, "Iris Durability: "..IrisDurability)
864
  end
865
end
866
867
local infoExtensionSwitch = function() end
868
869
local function displayLocalAddress()
870
  gpu.set(48, 45, "Milky Way ")
871
  gpu.set(48, 46, "Universe  ")
872
  gpu.set(48, 47, "Pegasus   ")
873
  if MiscSettings.HideLocalAddr then
874
    gpu.setForeground(0xFF0000)
875
    gpu.set(58, 45, "REDACTED")
876
    gpu.set(58, 46, "REDACTED")
877
    gpu.set(58, 47, "REDACTED")
878
    gpu.setForeground(0xFFFFFF)
879
  else
880
    gpu.set(58, 45, addressToString(localMWAddress))
881
    gpu.set(58, 46, addressToString(localUNAddress))
882
    gpu.set(58, 47, addressToString(localPGAddress))
883
  end
884
end
885
886
local ConfigPage = {}
887
ConfigPage.timer = 0
888
ConfigPage.autoIrisCheckBox = CheckBox.new(64, 46, IrisSettings, "AutoCloseIris", writeConfig)
889
890
ConfigPage.changeIDCButton = Button.new(65, 46, 0, 0, "         ", function()
891
  ConfigPage.changeIDCButton:hide()
892
  -- if not event.cancel(ConfigPage.timer) then alert("FAILED",2) end -- For debug
893
  local newIDC, successful = userInput(66, 47, 9, true, true)
894
  if successful then
895
    if newIDC == "" then
896
      alert("IDC Was Cleared", 2)
897
      IDC = nil
898
      writeConfig()
899
    else
900
      newIDC = tonumber(newIDC)
901
      if type(newIDC) == "number" and newIDC >= 0 and newIDC < 1e9 and math.floor(newIDC) == newIDC then
902
        alert("IDC Has Been Changed", 1)
903
        IDC = newIDC
904
        writeConfig()
905
      else
906
        alert("Invalid IDC", 2)
907
      end
908
    end
909
  end
910
  if infoExtensionMode == "CONFIG" then ConfigPage.show() end
911
end, false)
912
913
ConfigPage.changePortButton = Button.new(65, 47, 0, 0, "     ", function()
914
  ConfigPage.changePortButton:hide()
915
  if not event.cancel(ConfigPage.timer) then alert("FAILED",2) end
916
  local newPort, successful = userInput(66, 48, 5, true, true)
917
  if successful then
918
    if newPort == "" then
919
      alert("IDC Network Port Was Closed", 2)
920
      if ModemIDCPort ~= nil then modem.close(ModemIDCPort) end
921
      ModemIDCPort = nil
922
      writeConfig()
923
    else
924
      newPort = tonumber(newPort)
925
      if type(newPort) == "number" and newPort > 0 and newPort <= 65535 and math.floor(newPort) == newPort then
926
        alert("IDC Network Port Has Been Changed", 1)
927
        if ModemIDCPort ~= nil then modem.close(ModemIDCPort) end
928
        ModemIDCPort = newPort
929
        modem.open(ModemIDCPort)
930
        writeConfig()
931
      else
932
        alert("Invalid Port Number", 2)
933
      end
934
    end
935
  end
936
  if infoExtensionMode == "CONFIG" then ConfigPage.show() end
937
end, false)
938
939
ConfigPage.adminOffset = 75
940
ConfigPage.adminQuitCheckBox = CheckBox.new(ConfigPage.adminOffset+15, 46, AdminOnlySettings, "Quit", writeConfig)
941
ConfigPage.adminAddEntryCheckBox = CheckBox.new(ConfigPage.adminOffset+21, 47, AdminOnlySettings, "AddEntry", writeConfig)
942
ConfigPage.adminEditEntryCheckBox = CheckBox.new(ConfigPage.adminOffset+18, 48, AdminOnlySettings, "EditEntry", writeConfig)
943
ConfigPage.adminHistoryCheckBox = CheckBox.new(ConfigPage.adminOffset+43, 46, AdminOnlySettings, "History", writeConfig)
944
ConfigPage.adminToggleIrisCheckBox = CheckBox.new(ConfigPage.adminOffset+39, 47, AdminOnlySettings, "ToggleIris", writeConfig)
945
946
ConfigPage.otherOffset = 121
947
ConfigPage.hideLocalAddrCheckBox = CheckBox.new(ConfigPage.otherOffset+23, 46, MiscSettings, "HideLocalAddr", writeConfig)
948
ConfigPage.dialWithDHDCheckBox = CheckBox.new(ConfigPage.otherOffset+18, 47, MiscSettings, "dialWithDHD", writeConfig)
949
950
function ConfigPage.show()
951
  ConfigPage.timer = event.timer(10, function() infoExtensionSwitch("ADDRESS") end)
952
  ConfigPage.autoIrisCheckBox:display()
953
  gpu.set(47, 45, "╭Iris / Shield Settings─────")
954
  gpu.fill(47, 46, 1, 3, "│")
955
  gpu.set(48, 46, "Auto Close Iris [ ]")
956
  ConfigPage.changeIDCButton:display()
957
  if IrisSettings.AutoCloseIris == true then
958
    gpu.setForeground(0x00FF00)
959
    gpu.set(65, 46, "X")
960
    gpu.setForeground(0xFFFFFF)
961
  end
962
  gpu.set(48, 47, "Iris/Shield Code:")
963
  gpu.setBackground(0x878787)
964
  gpu.set(66, 47, "         ")
965
  if IDC ~= nil then gpu.set(66, 47, tostring(IDC)) end
966
  gpu.setBackground(0x000000)
967
  gpu.set(48,48, "IDC Network Port:")
968
  if HasModem then
969
    ConfigPage.changePortButton:display()
970
    gpu.setBackground(0x878787)
971
    gpu.set(66, 48, "     ")
972
    if ModemIDCPort ~= nil then gpu.set(66, 48, tostring(ModemIDCPort)) end
973
    gpu.setBackground(0x000000)
974
  else
975
    gpu.set(66, 48, "No Card")
976
  end
977
  gpu.fill(ConfigPage.adminOffset, 46, 1, 3, "│")
978
  gpu.set(ConfigPage.adminOffset, 45, "┬Admin Only Access Settings──────────────────────────╮")
979
  if #AdminList > 0 then
980
    gpu.set(ConfigPage.adminOffset+1, 46, "Quit Program: [ ]")
981
    ConfigPage.adminQuitCheckBox:display()
982
    gpu.set(ConfigPage.adminOffset+1, 47, "Add New Gate Entry: [ ]")
983
    ConfigPage.adminAddEntryCheckBox:display()
984
    gpu.set(ConfigPage.adminOffset+1, 48, "Edit Gate Entry: [ ]")
985
    ConfigPage.adminEditEntryCheckBox:display()
986
    gpu.set(ConfigPage.adminOffset+26, 46, "Dialing History: [ ]")
987
    ConfigPage.adminHistoryCheckBox:display()
988
    gpu.set(ConfigPage.adminOffset+26, 47, "Toggle Iris: [ ]")
989
    ConfigPage.adminToggleIrisCheckBox:display()
990
  else
991
    gpu.setForeground(0xFFFF00)
992
    gpu.set(ConfigPage.adminOffset+5, 47, "There are no Names in the Admin List")
993
    gpu.setForeground(0xFFFFFF)
994
  end
995
  gpu.fill(ConfigPage.otherOffset, 46, 1, 3, "│")
996
  gpu.set(ConfigPage.otherOffset, 45, "┬Other Settings───────────────────────╮")
997
  gpu.set(ConfigPage.otherOffset+1, 46, "Hide Local Addresses: [ ]")
998
  ConfigPage.hideLocalAddrCheckBox:display()
999
  if component.isAvailable("dhd") then
1000
    gpu.set(ConfigPage.otherOffset+1, 47, "Use DHD to Dial: [ ]")
1001
    ConfigPage.dialWithDHDCheckBox:display()
1002
  end
1003
  gpu.fill(ConfigPage.otherOffset+38, 46, 1, 3, "│")
1004
end
1005
1006
function ConfigPage.hide()
1007
  event.cancel(ConfigPage.timer)
1008
  ConfigPage.autoIrisCheckBox:hide()
1009
  ConfigPage.changeIDCButton:hide()
1010
  ConfigPage.changePortButton:hide()
1011
  
1012
  ConfigPage.adminQuitCheckBox:hide()
1013
  ConfigPage.adminAddEntryCheckBox:hide()
1014
  ConfigPage.adminEditEntryCheckBox:hide()
1015
  ConfigPage.adminHistoryCheckBox:hide()
1016
  ConfigPage.adminToggleIrisCheckBox:hide()
1017
  
1018
  ConfigPage.hideLocalAddrCheckBox:hide()
1019
  ConfigPage.dialWithDHDCheckBox:hide()
1020
end
1021
1022
function infoExtensionSwitch(mode)
1023
  if DebugMode then
1024
    gpu.set(47, 44, "╡This Stargate's Addresses╞═╡Settings╞═╡Debug╞")
1025
  else
1026
    gpu.set(47, 44, "╡This Stargate's Addresses╞═╡Settings╞════════")
1027
  end
1028
  gpu.fill(47, 45, 113, 4, " ")
1029
  ChildThread.debugWindowThread:suspend()
1030
  if infoExtensionMode == "CONFIG" then ConfigPage.hide() end
1031
  if mode == "ADDRESS" then
1032
    gpu.setBackground(0x878787)
1033
    gpu.set(48, 44, "This Stargate's Addresses")
1034
    gpu.setBackground(0x000000)
1035
    displayLocalAddress()
1036
    infoExtensionMode = "ADDRESS"
1037
  elseif mode == "CONFIG" then
1038
    gpu.setBackground(0x878787)
1039
    gpu.set(76, 44, "Settings")
1040
    gpu.setBackground(0x000000)
1041
    infoExtensionMode = "CONFIG"
1042
    ConfigPage.show()
1043
  elseif mode == "DEBUG" then
1044
    gpu.setBackground(0x878787)
1045
    gpu.set(87, 44, "Debug")
1046
    gpu.setBackground(0x000000)
1047
    infoExtensionMode = "DEBUG"
1048
    ChildThread.debugWindowThread:resume()
1049
  end
1050
end
1051
1052
local addressButton = Button.new(47, 43, 0, 0, "This Stargate's Addresses", function() infoExtensionSwitch("ADDRESS") end, false)
1053
local configButton = Button.new(75, 43, 0, 0, "Settings", function() 
1054
  if isAuthorized(User) then
1055
    infoExtensionSwitch("CONFIG")
1056
  end
1057
end, false)
1058
local debugButton = Button.new(86, 43, 0, 0, "Debug", function() infoExtensionSwitch("DEBUG") end, false)
1059
1060
local function toggleDebugMode()
1061
    if not DebugMode then
1062
      alert("DEBUG MODE ACTIVATED", 1)
1063
      DebugMode = true
1064
      debugButton:display()
1065
      infoExtensionSwitch("DEBUG")
1066
      ChildThread.debugWindowThread:resume()
1067
    elseif DebugMode then
1068
      debugButton:hide()
1069
      gpu.set(86, 44, "═══════")
1070
      alert("DEBUG MODE DEACTIVATED", 1)
1071
      DebugMode = false
1072
      ChildThread.debugWindowThread:suspend()
1073
      if infoExtensionMode == "DEBUG" then infoExtensionSwitch("ADDRESS") end
1074
      gpu.fill(150, 43, 10, 1, " ")
1075
    end 
1076
end
1077
1078
local function displayInfoCenter()
1079
  gpu.setBackground(0x000000)
1080
  gpu.fill(1, term.window.height-6, term.window.width, 1, "═")
1081
  gpu.fill(1, term.window.height-5, 1, 4, "║")
1082
  gpu.fill(46, term.window.height-5, 1, 4, "║")
1083
  gpu.fill(term.window.width, term.window.height-5, 1, 4, "║")
1084
  gpu.fill(1, term.window.height-1, term.window.width, 1, "═")
1085
  gpu.set(1, term.window.height-6, "╔╡System Status╞")
1086
  gpu.set(46, term.window.height-6, "╦")
1087
  gpu.set(47, term.window.height-6, "╡This Stargate's Addresses╞")
1088
  gpu.set(term.window.width, term.window.height-6, "╗")
1089
  gpu.set(1, term.window.height-1, "╚")
1090
  gpu.set(46, term.window.height-1, "╩")
1091
  gpu.set(term.window.width, term.window.height-1, "╝")
1092
  addressButton:display()
1093
  configButton:display()
1094
  infoExtensionSwitch("ADDRESS")
1095
end
1096
1097
ChildThread.statusThread = thread.create(function()
1098
  local status, err = xpcall(function()
1099
    while HadNoError do
1100
      displaySystemStatus()
1101
      os.sleep(0.05)
1102
    end
1103
  end, debug.traceback)
1104
  if err ~= nil then ErrorMessage = err end
1105
  HadNoError = status
1106
end)
1107
1108
ChildThread.debugWindowThread = thread.create(function() -- For Debug
1109
  local status, err = xpcall(function()
1110
    while HadNoError do
1111
      local used = RootDrive.spaceUsed()
1112
      local total = RootDrive.spaceTotal()
1113
      local dialedAddress = nil
1114
      pcall(function() dialedAddress = sg.dialedAddress end)
1115
      if DebugMode then
1116
        gpu.fill(48, 45, 110, 4, " ")
1117
        -- gpu.set(48, 45, "DHD_AdrEntryMode: "..tostring(DHD_AdrEntryMode))
1118
        gpu.set(48, 45, "ComputerDialingWithDHD: "..tostring(ComputerDialingWithDHD))
1119
        gpu.set(48, 46, "DialingInterlocked: "..tostring(DialingInterlocked))
1120
        gpu.set(48, 47, "ComputerDialingInterlocked: "..tostring(ComputerDialingInterlocked))
1121
        -- gpu.set(48, 47, "adrEntryType: "..tostring(adrEntryType))
1122
        gpu.set(84, 46, "dialerAdrEntryMode: "..tostring(dialerAdrEntryMode))
1123
        gpu.set(84, 45, "glyphListWindow.locked: "..tostring(glyphListWindow.locked))
1124
        gpu.set(48, 48, tostring(dialedAddress))
1125
        gpu.set(84, 47, "Gate Status: "..tostring(GateStatusString).." | "..tostring(GateStatusBool))
1126
        -- gpu.set(84, 47, "WasCanceled: "..tostring(WasCanceled))
1127
        -- gpu.set(120, 45, "Drive Usage: "..used.."/"..total.." "..math.floor((used/total)*100).."%")
1128
        -- gpu.set(120, 45, "Index: "..tostring(GateEntriesWindow.selectedIndex))
1129
        -- gpu.set(120, 45, "UNGateResetting: "..tostring(UNGateResetting))
1130
        gpu.set(120, 45, "manualAdrEntryMode: "..tostring(manualAdrEntryMode))
1131
        gpu.set(120, 46, "editGateEntryMode: "..tostring(editGateEntryMode))
1132
        gpu.set(120, 47, "OutgoingWormhole: "..tostring(OutgoingWormhole))
1133
        -- gpu.set(120, 47, "addAddressMode: "..tostring(addAddressMode))
1134
        -- gpu.set(120, 47, "DatabaseWriteTimer ID: "..tostring(DatabaseWriteTimer))
1135
        -- gpu.set(120, 46, "IrisState: "..tostring(sg.getIrisState()))
1136
        -- gpu.set(120, 47, "IrisType: "..tostring(IrisType))
1137
        -- gpu.set(120, 46, "AdminOnlyQuit: "..tostring(AdminOnlySettings["Quit"]))
1138
        -- gpu.set(120, 47, "MainLoop: "..tostring(MainLoop))
1139
      end
1140
      os.sleep(0.1)
1141
    end
1142
  end, debug.traceback)
1143
  if err ~= nil then ErrorMessage = err end
1144
  HadNoError = status
1145
end)
1146
-- End of Info Center --------------------------------------------------------------
1147
1148
1149
-- Gate Entries Window -------------------------------------------------------------
1150
GateEntriesWindow = {}
1151
function GateEntriesWindow.set()
1152
  local self = GateEntriesWindow
1153
  self.xPos = 2
1154
  self.yPos = 3
1155
  self.width = 37
1156
  self.height = 37
1157
  gpu.fill(1, 2, 40, 39, " ")
1158
  self.entries = {}
1159
  self.range = {}
1160
  self.range.bot = 1
1161
  self.range.height = 37
1162
  self.range.top = self.range.height
1163
  self.range.botH = 1
1164
  self.range.topH = self.range.height
1165
  self.scrollingTimer = nil
1166
  self.locked = false
1167
  if GateType == "MW" then self.localAddress = localMWAddress
1168
  elseif GateType == "UN" then self.localAddress = localUNAddress
1169
  elseif GateType == "PG" then self.localAddress = localPGAddress
1170
  end
1171
  self.mode = "database"
1172
  gpu.set(1, 2,  "╔╡Gate Entries╞══════════════╡History╞╗")
1173
  gpu.set(1, 40, "╚═════════════════════════════════════╝")
1174
  gpu.fill(1, 3, 1, 37, "║")
1175
  gpu.fill(39, 3, 1, 37, "║")
1176
  self.scrollUpButton = Button.new(3, 39, 0, 0, "↑PgUp↑", function()
1177
    GateEntriesWindow.increment(-1)
1178
  end, false)
1179
  self.scrollDnButton = Button.new(30, 39, 0, 0, "↓PgDn↓", function()
1180
    GateEntriesWindow.increment(1)
1181
  end, false)
1182
  self.clearHistoryButton = Button.new(13, 39, 0, 0, "Clear History", function()
1183
    historyEntries = {}
1184
    writeToDatabase()
1185
    -- GateEntriesWindow.clearHistoryButton:hide()
1186
  end, false)
1187
  self.update()
1188
end
1189
1190
function GateEntriesWindow.increment(inc)
1191
  local self = GateEntriesWindow
1192
  if self.scrollingTimer == nil then
1193
    self.scrollingTimer = event.timer(0.05, function() self.scrollingTimer = nil end)
1194
    if self.mode == "database" then
1195
      if (self.range.top + inc) > #gateEntries or (self.range.bot + inc) < 1 then
1196
        return
1197
      else
1198
        self.range.bot = self.range.bot + inc
1199
        self.range.top = self.range.top + inc
1200
        self.display()
1201
      end
1202
    elseif self.mode == "history" then
1203
      if (self.range.topH + inc) > #historyEntries or (self.range.botH + inc) < 1 then
1204
        return
1205
      else
1206
        self.range.botH = self.range.botH + inc
1207
        self.range.topH = self.range.topH + inc
1208
        self.display()
1209
      end
1210
    end
1211
  end
1212
end
1213
1214
function GateEntriesWindow.update()
1215
  local self = GateEntriesWindow
1216
  local strBuf = ""
1217
  local dialable = true
1218
  self.entryStrings = {}
1219
  self.canDial = {}
1220
  gpu.setBackground(0x878787)
1221
  if self.mode == "database" then
1222
    gpu.set(3, 2,  "Gate Entries")
1223
    gpu.setBackground(0x000000)
1224
    gpu.set(31, 2,  "History")
1225
    self.loadedEntries = gateEntries
1226
    self.clearHistoryButton:hide()
1227
    gpu.set(13, 40, "═══════════════")
1228
  elseif self.mode == "history" then
1229
    gpu.set(31, 2,  "History")
1230
    gpu.setBackground(0x000000)
1231
    gpu.set(3, 2,  "Gate Entries")
1232
    self.loadedEntries = historyEntries
1233
    if #historyEntries > 0 then
1234
      self.clearHistoryButton:display()
1235
      gpu.set(13, 40, "╡░░░░░░░░░░░░░╞")
1236
      self.clearHistoryButton:display()
1237
    else
1238
      self.clearHistoryButton:hide()
1239
      gpu.set(13, 40, "═══════════════")
1240
    end
1241
  end
1242
  for i,v in ipairs(self.loadedEntries) do
1243
    strBuf = v.name
1244
    if self.mode == "database" then
1245
      if entriesDuplicateCheck(self.localAddress, {v}, GateType, 1) then
1246
        -- strBuf = strBuf.." [This Stargate]"
1247
        strBuf = "[This Stargate] "..strBuf
1248
        dialable = false
1249
      elseif v.gateAddress[GateType] ~= nil and #v.gateAddress[GateType] ~= 0 then
1250
        -- strBuf = strBuf.." ("..(#v.gateAddress[GateType]+1).." Glyphs)"
1251
        dialable = true
1252
      else
1253
        strBuf = strBuf.." [Empty "..GateType.." Address]"
1254
        dialable = false
1255
      end
1256
    end
1257
    if self.mode == "database" then
1258
      while unicode.len(strBuf) < self.width-8 do
1259
        strBuf = strBuf.." "
1260
      end
1261
    end
1262
    if unicode.len(strBuf) > self.width-6 then strBuf = unicode.wtrunc(strBuf, self.width-7) end -- Truncate String to not go past border
1263
    if self.mode == "history" and v.t ~= nil then
1264
      if v.gateAddress[GateType] ~= nil and #v.gateAddress[GateType] > 0 then
1265
        dialable = true
1266
      else
1267
        dialable = false
1268
      end
1269
      while unicode.len(strBuf) < 23 do
1270
        strBuf = strBuf.." "
1271
      end
1272
      strBuf = strBuf.." "..os.date("%d/%m %H:%M", v.t)
1273
    end
1274
    table.insert(self.entryStrings, strBuf)
1275
    table.insert(self.canDial, dialable)
1276
  end
1277
  if #self.entryStrings > self.range.height then
1278
    gpu.set(3, 40, "╡░░░░░░╞")
1279
    gpu.set(30, 40, "╡░░░░░░╞")
1280
    self.scrollUpButton:display()
1281
    self.scrollDnButton:display()
1282
  else
1283
    self.scrollUpButton:hide()
1284
    self.scrollDnButton:hide()
1285
    gpu.set(3, 40, "════════")
1286
    gpu.set(30, 40, "════════")
1287
  end
1288
  self.display()
1289
end
1290
1291
function GateEntriesWindow.display()
1292
  local self = GateEntriesWindow
1293
  if #gateEntries == 0 then alert("WARNING: NO ADDRESSES IN DATABASE!", 2) end
1294
  gpu.fill(2, 3, 37, 37, " ")
1295
  self.currentIndices = {}
1296
  local displayCount = 0
1297
  local top
1298
  local bot
1299
  if self.mode == "database" then
1300
    top = self.range.top
1301
    bot = self.range.bot
1302
  elseif self.mode == "history" then
1303
    top = self.range.topH
1304
    bot = self.range.botH
1305
  end
1306
  for i,v in ipairs(self.entryStrings) do
1307
    if i >= bot and i <= top then
1308
      displayCount = displayCount + 1
1309
      self.currentIndices[displayCount] = i
1310
      -- gpu.set(3, 2+displayCount, tostring(i)) -- Display Number
1311
      if i == self.selectedIndex then 
1312
        gpu.setBackground(0x878787)
1313
      end
1314
      -- gpu.set(7, 2+displayCount, v) -- Old Position
1315
      if self.canDial[i] == false then
1316
        gpu.setForeground(0xB4B4B4)
1317
      end
1318
      gpu.set(3, 2+displayCount, v)
1319
      gpu.setBackground(0x000000)
1320
      if self.mode == "database" then
1321
        if gateEntries[i].fave ~= nil and gateEntries[i].fave == true then
1322
          gpu.setForeground(0xFFFF00)
1323
        else
1324
          gpu.setForeground(0xB4B4B4)
1325
        end
1326
        gpu.set(37, 2+displayCount, "*")
1327
        if i == 1 or gateEntries[i].fave ~= gateEntries[i-1].fave then
1328
          gpu.setForeground(0x0F0F0F)
1329
        else
1330
          gpu.setForeground(0xFFFFFF)
1331
        end
1332
        gpu.set(33, 2+displayCount, "⇧ ") -- Move Up Arrow
1333
        if i == #self.entryStrings or gateEntries[i].fave ~= gateEntries[i+1].fave then
1334
          gpu.setForeground(0x0F0F0F)
1335
        else
1336
          gpu.setForeground(0xFFFFFF)
1337
        end
1338
        gpu.set(35, 2+displayCount, "⇩ ") -- Move Down Arrow
1339
      end
1340
      gpu.setForeground(0xFFFFFF)
1341
    end
1342
  end
1343
  if bot <= 1 then
1344
    self.scrollUpButton:disable(true)
1345
  else
1346
    self.scrollUpButton:disable(false)
1347
  end
1348
  if top >= #self.entryStrings then
1349
    self.scrollDnButton:disable(true)
1350
  else
1351
    self.scrollDnButton:disable(false)
1352
  end
1353
1354
  -- gpu.fill(1, 42, 23, 1, "░") -- For Debug
1355
  -- gpu.set(1, 42, tostring(gateEntries[self.selectedIndex])) -- For Debug
1356
end
1357
1358
function GateEntriesWindow.addressInfo()
1359
  local self = GateEntriesWindow
1360
  if gateRingDisplay.isActive == false then return end
1361
  gpu.fill(42,5,35,2," ")
1362
  if self.selectedIndex ~= nil and self.selectedIndex > 1 then
1363
    local gateEntry = nil
1364
    if self.mode == "database" then
1365
      gateEntry = gateEntries[self.selectedIndex]
1366
    elseif self.mode == "history" then
1367
      gateEntry = historyEntries[self.selectedIndex]
1368
    end
1369
    local gateAddress = gateEntry.gateAddress[GateType]
1370
    if gateAddress ~= nil and #gateAddress > 0 then
1371
      local requirement = sg.getEnergyRequiredToDial(table.unpack(gateAddress))
1372
      if type(requirement) == "table" then
1373
        local storedEnergy = sg.getEnergyStored()
1374
        local operatingTicks = (storedEnergy - requirement.open) / requirement.keepAlive
1375
        local operatingSeconds = math.floor(operatingTicks / 20)
1376
        gpu.set(42, 5, "Energy to Dial:   ")
1377
        if requirement.canOpen == false then
1378
          gpu.setForeground(0xFF0000) -- Red
1379
        elseif operatingSeconds < 10 then
1380
          gpu.setForeground(0xFFFF00) -- Yellow
1381
        else
1382
          gpu.setForeground(0x00FF00) -- Green
1383
        end
1384
        gpu.set(60, 5, requirement.open.." RF")
1385
        gpu.setForeground(0xFFFFFF) -- White
1386
        gpu.set(42, 6, "Keep Open Energy: ")
1387
        if operatingSeconds < 2 then
1388
          gpu.setForeground(0xFF0000) -- Red
1389
        elseif operatingSeconds < 5 then
1390
          gpu.setForeground(0xFF6D00) -- Orange
1391
        elseif operatingSeconds < 10 then
1392
          gpu.setForeground(0xFFFF00) -- Yellow
1393
        else
1394
          gpu.setForeground(0x00FF00) -- Green
1395
        end
1396
        gpu.set(60, 6 , requirement.keepAlive.." RF/t")
1397
        gpu.setForeground(0xFFFFFF) -- White
1398
      else
1399
        gpu.setForeground(0xFF0000) -- Red
1400
        gpu.set(42, 5, "No Gate Detected at Address")
1401
        gpu.setForeground(0xFFFFFF) -- White
1402
      end
1403
    end
1404
  end
1405
end
1406
1407
function GateEntriesWindow.touch(x, y)
1408
  local self = GateEntriesWindow
1409
  if x >= self.xPos and x <= 38 and y >= self.yPos and y <= 40 then
1410
    if not ComputerDialingInterlocked and not addAddressMode and not editGateEntryMode then
1411
      self.selectedIndex = self.currentIndices[y - 2]
1412
      if self.selectedIndex == nil then self.selectedIndex = 0 end
1413
      if (x == 33 or x== 35 or x == 37) and self.mode == "database" then
1414
        self.changePosition(x, y)
1415
      end
1416
      self.addressInfo()
1417
      self.display()
1418
      updateButtons()
1419
      if self.selectedIndex ~= 0 then
1420
        local gateEntry = nil
1421
        if self.mode == "database" then
1422
          gateEntry = gateEntries[self.selectedIndex]
1423
        else
1424
          gateEntry = historyEntries[self.selectedIndex]
1425
        end
1426
        if not gateEntry.AdminOnly or #AdminList == 0 then
1427
          glyphListWindow.insertAddress(gateEntry.gateAddress[GateType])
1428
        else
1429
          glyphListWindow.selectedGlyphs = {}
1430
          glyphListWindow.display()
1431
        end
1432
      end
1433
    end
1434
  elseif ((x >= 3 and x <= 13) or (x >= 31 and x <= 37)) and y == 2 then
1435
    if x >= 3 and x <= 13 then
1436
      self.mode = "database"
1437
    elseif x >= 31 and x <= 37 and isAuthorized(User, AdminOnlySettings.History) then
1438
      self.mode = "history"
1439
    end
1440
    self.selectedIndex = 0
1441
    self.addressInfo()
1442
    updateButtons()
1443
    self.update()
1444
  end
1445
end
1446
1447
function GateEntriesWindow.changePosition(x, y)
1448
  local self = GateEntriesWindow
1449
  local wasInserted = false
1450
  if x == 33 then
1451
    if self.selectedIndex == 1 or gateEntries[self.selectedIndex].fave ~= gateEntries[self.selectedIndex-1].fave then
1452
      return
1453
    else
1454
      -- alert("Going Up", 1) -- For Debug
1455
      local entryBuf = table.remove(gateEntries, self.selectedIndex)
1456
      table.insert(gateEntries, self.selectedIndex-1, entryBuf)
1457
      self.selectedIndex = self.selectedIndex-1
1458
      wasInserted = true
1459
    end
1460
  elseif x == 35 then
1461
    if self.selectedIndex == #self.entryStrings or gateEntries[self.selectedIndex].fave ~= gateEntries[self.selectedIndex+1].fave then
1462
      return
1463
    else
1464
      -- alert("Going Down", 1) -- For Debug
1465
      gpu.set(x, y, "⇩") -- Move Down Arrow
1466
      local entryBuf = table.remove(gateEntries, self.selectedIndex)
1467
      table.insert(gateEntries, self.selectedIndex+1, entryBuf)
1468
      self.selectedIndex = self.selectedIndex+1
1469
      wasInserted = true
1470
    end  
1471
  elseif x == 37 then
1472
    local entryBuf = table.remove(gateEntries, self.selectedIndex)
1473
    if entryBuf.fave == nil or entryBuf.fave == false then
1474
      entryBuf.fave = true
1475
    else
1476
      entryBuf.fave = false
1477
    end
1478
    for i,v in ipairs(gateEntries) do
1479
      if v.fave == nil or v.fave == false then
1480
        table.insert(gateEntries, i, entryBuf)
1481
        self.selectedIndex = i
1482
        wasInserted = true
1483
        break
1484
      end
1485
    end
1486
    if not wasInserted then
1487
      table.insert(gateEntries, entryBuf)
1488
      self.selectedIndex = #gateEntries
1489
      wasInserted = true
1490
    end
1491
  end
1492
  if wasInserted then
1493
    self.update()
1494
    writeToDatabase()
1495
  end
1496
end
1497
-- End of Gate Entries Window ------------------------------------------------------
1498
1499
-- Glyph List Window ---------------------------------------------------------------
1500
glyphListWindow = {xPos=term.window.width, yPos=2, width=0, height=0, locked=false}
1501
function glyphListWindow.initialize(glyphType)
1502
  local self = glyphListWindow
1503
  self.glyphType = glyphType
1504
  self.glyphs = nil
1505
  self.selectedGlyphs = {}
1506
  if glyphType == "MW" then
1507
    self.glyphs = GlyphsMW
1508
  elseif glyphType == "UN" then
1509
    self.glyphs = {}
1510
    for i=1,36,1 do
1511
      if i ~= 17 then table.insert(self.glyphs, "Glyph "..i) end
1512
    end
1513
  elseif glyphType == "PG" then
1514
    self.glyphs = GlyphsPG
1515
  end
1516
  gpu.fill(self.xPos-self.width, self.yPos, 2*self.width, term.window.height-8, " ")
1517
  self.width = 1
1518
  self.xPos = term.window.width
1519
  for i,v in ipairs(self.glyphs) do
1520
    if unicode.len(v)+2 > self.width then self.width = unicode.len(v)+2 end
1521
  end
1522
  if self.width < 12 then self.width = 12 end
1523
  if self.xPos+self.width-1 > term.window.width then self.xPos = term.window.width-self.width+1 end
1524
  self.glyphsHeight = #self.glyphs
1525
  self.height = 4+self.glyphsHeight
1526
  buttons.glyphResetButton.xPos = self.xPos-self.width
1527
  gpu.set(self.xPos, self.yPos, "╓")
1528
  gpu.fill(self.xPos+1, self.yPos, self.width-2, 1, "─")
1529
  gpu.set(self.xPos+self.width-1, self.yPos, "╖")
1530
  gpu.set(self.xPos, self.yPos+1, "║")
1531
  gpu.set(self.xPos+self.width-1, self.yPos+1, "║")
1532
  gpu.set(self.xPos, self.yPos+2, "╠")
1533
  gpu.fill(self.xPos+1, self.yPos+2, self.width-2, 1, "═")
1534
  gpu.set(self.xPos+self.width-1, self.yPos+2, "╣")
1535
  gpu.fill(self.xPos, self.yPos+3, 1, self.glyphsHeight, "║")
1536
  gpu.fill(self.xPos+self.width-1, self.yPos+3, 1, self.glyphsHeight, "║")
1537
  gpu.set(self.xPos, self.yPos+3+self.glyphsHeight, "╚")
1538
  gpu.fill(self.xPos+1, self.yPos+3+self.glyphsHeight, self.width-2, 1, "═")
1539
  gpu.set(self.xPos+self.width-1, self.yPos+3+self.glyphsHeight, "╝")
1540
  gpu.set(self.xPos, self.yPos+3, "╢")
1541
  self.display()
1542
end
1543
1544
function glyphListWindow.display()
1545
  local self = glyphListWindow
1546
  local oStr = ""
1547
  if self.glyphType == "MW" then
1548
    oStr = "Origin"
1549
  elseif self.glyphType == "UN" then
1550
    oStr = "Glyph 17"
1551
  elseif self.glyphType == "PG" then
1552
    oStr = "Subido"
1553
  end
1554
  local yOffset = self.yPos + 2
1555
  local xOffset = self.xPos-self.width
1556
  local resetButton = buttons.glyphResetButton
1557
  resetButton.xPos = xOffset+(self.width/2-resetButton.width/2)
1558
  gpu.fill(self.xPos+1, yOffset+1, self.width-2, self.glyphsHeight, " ")
1559
  gpu.fill(xOffset+1, 7, self.width-2, 8, " ")
1560
  for i,v in ipairs(self.selectedGlyphs) do
1561
    if v == -1 then gpu.setBackground(0x878787) end
1562
  end
1563
  gpu.set(self.xPos+(self.width/2-unicode.len(oStr)/2), self.yPos+1, oStr)
1564
  gpu.setBackground(0x000000)
1565
  for i,v in ipairs(self.glyphs) do
1566
    for i2,v2 in ipairs(self.selectedGlyphs) do
1567
      if i == v2 then gpu.setBackground(0x878787) end
1568
    end
1569
    if v == "Orion" or v == "Urion" then v = "Orion" end
1570
    gpu.set(self.xPos+(self.width/2-unicode.len(v)/2), yOffset+i, tostring(v))
1571
    gpu.setBackground(0x000000)
1572
  end
1573
  if #self.selectedGlyphs > 0 then
1574
    if not self.locked then
1575
      resetButton:display()
1576
    end
1577
    gpu.setForeground(0xFFFFFF)
1578
  else
1579
    resetButton:hide()
1580
    gpu.setForeground(0x0F0F0F)
1581
  end
1582
  gpu.set(xOffset, yOffset+2, "┌")
1583
  gpu.fill(xOffset+1, yOffset+2, self.width-2, 1, "─")
1584
  gpu.set(xOffset+self.width-1, yOffset+2, "┐")
1585
  gpu.set(xOffset+(self.width/2)-1, yOffset+2, "┴")
1586
  gpu.set(xOffset+(self.width/2)-1, yOffset+1, "┌")
1587
  gpu.fill(xOffset+(self.width/2), yOffset+1, (self.width/2), 1, "─")
1588
  if gateRingDisplay.isActive then
1589
    gpu.fill(xOffset, yOffset+3, 1, 8, "┤")
1590
  else
1591
    gpu.fill(xOffset, 3, self.width, 1, " ")
1592
    gpu.fill(xOffset, yOffset+3, 1, 8, "│")
1593
  end
1594
  gpu.fill(xOffset+self.width-1, yOffset+3, 1, 8, "│")
1595
  gpu.set(xOffset, yOffset+11, "└")
1596
  gpu.fill(xOffset+1, yOffset+11, self.width-2, 1, "─")
1597
  gpu.set(xOffset+self.width-1, yOffset+11, "┘")
1598
  for i,v in ipairs(self.selectedGlyphs) do
1599
    local glyph = self.glyphs[v]
1600
    -- if v ~= -1 then gpu.set(xOffset+(self.width/2-unicode.len(glyph)/2), yOffset+2+i, glyph) end
1601
    
1602
    if v == -1 and (#self.selectedGlyphs < 7 or i < #self.selectedGlyphs) then
1603
      glyph = oStr
1604
      gpu.setForeground(0xFF0000)
1605
    elseif v == -2 then
1606
      glyph = "Unknown"
1607
      gpu.setForeground(0xFF0000)
1608
    end
1609
    if glyph ~= nil and i < 9 then gpu.set(xOffset+(self.width/2-unicode.len(glyph)/2), yOffset+2+i, glyph) end
1610
    gpu.setForeground(0xFFFFFF)
1611
  end
1612
  gpu.setForeground(0xFFFFFF)
1613
end
1614
1615
function glyphListWindow.touch(x,y)
1616
  local self = glyphListWindow
1617
  if not ComputerDialingInterlocked and not dialerAdrEntryMode and not self.locked then
1618
    if x > self.xPos and x < self.xPos+self.width-1 and y > self.yPos and y < self.yPos+self.height-1 then
1619
      local selection = y-self.yPos-2
1620
      local newSelection = true
1621
      for i,v in ipairs(self.selectedGlyphs) do
1622
        if selection == v then newSelection = false end
1623
      end
1624
      if newSelection and #self.selectedGlyphs < 9 then
1625
        if selection > 0 and #self.selectedGlyphs < 8 then
1626
          table.insert(self.selectedGlyphs, selection)
1627
        end
1628
        self.display()
1629
        if selection == -1 then
1630
          AddressBuffer = {}
1631
          local glyph = ""
1632
          for i,v in ipairs(self.selectedGlyphs) do
1633
            if v ~= -1 then
1634
              glyph = self.glyphs[v]
1635
              if self.glyphType == "UN" then _,glyph = checkGlyph(glyph, "UN") end
1636
              table.insert(AddressBuffer, glyph)
1637
            end
1638
          end
1639
          if #AddressBuffer >= 6 then
1640
            if addAddressMode then
1641
              GoodAddress = true
1642
              -- manualAdrEntryMode = false
1643
              -- completeAddressEntry(self.glyphType)
1644
            else
1645
              directDial()
1646
            end
1647
            self.display()
1648
          elseif #AddressBuffer < 6 then
1649
            AddressBuffer = {}
1650
            self.display()
1651
            alert("ADDRESS IS TOO SHORT", 2)
1652
          end
1653
        end
1654
      end
1655
    end
1656
  end
1657
end
1658
1659
function glyphListWindow.insertGlyph(glyph)
1660
  if IncomingWormhole then return end
1661
  if GateType == "UN" and glyph:sub(1, 5) ~= "Glyph" then
1662
    glyph = string.gsub(glyph, "G", "Glyph ")
1663
  end
1664
  if glyph == "Glyph 17" or glyph == "Point of Origin" or glyph == "Subido" then table.insert(glyphListWindow.selectedGlyphs, -1) end
1665
  if glyph == "Unknown" then table.insert(glyphListWindow.selectedGlyphs, -2) end
1666
  for i2,v2 in ipairs(glyphListWindow.glyphs) do
1667
    if glyph == v2 then table.insert(glyphListWindow.selectedGlyphs, i2) end
1668
  end
1669
  glyphListWindow.display()
1670
end
1671
1672
function glyphListWindow.insertAddress(address)
1673
  glyphListWindow.selectedGlyphs = {}
1674
  if type(address) == "table" and #address > 0 then
1675
    for i,glyph in ipairs(address) do
1676
      if GateType == "UN" and glyph:sub(1, 5) ~= "Glyph" then
1677
        glyph = string.gsub(glyph, "G", "Glyph ")
1678
      end
1679
      if glyph == "Glyph 17" or glyph == "Point of Origin" or glyph == "Subido" then table.insert(glyphListWindow.selectedGlyphs, -1) end
1680
      if glyph == "Unknown" then table.insert(glyphListWindow.selectedGlyphs, -2) end
1681
      for i2,v2 in ipairs(glyphListWindow.glyphs) do
1682
        if glyph == v2 then table.insert(glyphListWindow.selectedGlyphs, i2) end
1683
      end
1684
    end
1685
  end
1686
  glyphListWindow.display()
1687
end
1688
1689
function glyphListWindow.showAddress()
1690
  DialedAddress = parseAddressString(sg.dialedAddress, GateType)
1691
  if #DialedAddress ~= #glyphListWindow.selectedGlyphs then
1692
  -- if #DialedAddress > #glyphListWindow.selectedGlyphs then
1693
    glyphListWindow.selectedGlyphs = {}
1694
    for i,v in ipairs(DialedAddress) do
1695
      glyphListWindow.insertGlyph(v)
1696
    end
1697
  end
1698
  -- local str = ""
1699
  -- for i,v in ipairs(glyphListWindow.selectedGlyphs) do
1700
    -- str = str.."  "..tostring(v)
1701
  -- end
1702
  -- alert(str, 2)
1703
end
1704
1705
function glyphListWindow.reset()
1706
  local self = glyphListWindow
1707
  self.selectedGlyphs = {}
1708
  buttons.glyphResetButton:hide()
1709
  self.display()
1710
  if not editGateEntryMode then
1711
    GateEntriesWindow.selectedIndex = 0
1712
  end
1713
  GateEntriesWindow.display()
1714
  updateButtons()
1715
end
1716
-- End of Glyph List Window -------------------------------------------------------------
1717
1718
-- Direct Dialing -----------------------------------------------------------------------
1719
function directDial()
1720
  local glyph = ""
1721
  if not isDirectDialing then isDirectDialing = true end
1722
  local directEntry = {name="Direct Dial", gateAddress={}}
1723
  directEntry.gateAddress[GateType] = AddressBuffer
1724
  if #AddressBuffer < 6 then
1725
    alert("ENTERED ADDRESS TOO SHORT", 2)
1726
  else
1727
    dialAddress(directEntry, 0)
1728
  end
1729
  isDirectDialing = false
1730
end
1731
-- End of Direct Dialing ----------------------------------------------------------------
1732
1733
-- Address Dialing ----------------------------------------------------------------------
1734
function dialAddress(gateEntry, num)
1735
  if gateEntry == nil then
1736
    alert("NO GATE ENTRY SELECTED", 2)
1737
    return
1738
  end
1739
  if sg.getGateStatus() == "open" then
1740
    alert("CAN NOT DIAL DUE TO STARGATE BEING OPEN", 2)
1741
    return
1742
  end
1743
  if sg.getGateStatus() ~= "idle" or sg.dialedAddress ~= "[]" then
1744
    alert("CAN NOT DIAL DUE TO EXISTING GATE ACTIVITY", 2)
1745
    return
1746
  end
1747
  local localAddress = nil
1748
  if GateType == "MW" then localAddress = localMWAddress
1749
  elseif GateType == "UN" then localAddress = localUNAddress
1750
  elseif GateType == "PG" then localAddress = localPGAddress
1751
  end
1752
  if gateEntry.gateAddress[GateType] == nil or #gateEntry.gateAddress[GateType] == 0 then
1753
    alert("CAN NOT DIAL DUE TO NO GATE ADDRESS ENTRY", 2)
1754
    return
1755
  end
1756
  AddressBuffer = {}
1757
  for i,v in ipairs(gateEntry.gateAddress[GateType]) do table.insert(AddressBuffer, v) end
1758
  -- local requirement, msg = sg.getEnergyRequiredToDial(AddressBuffer) -- Broken in Lua 5.3
1759
  local requirement, msg = sg.getEnergyRequiredToDial(table.unpack(AddressBuffer)) -- Temp Workaround
1760
  if type(requirement) == "string" then
1761
    if requirement == "address_malformed" then
1762
      if entriesDuplicateCheck(localAddress, {gateEntry}, GateType, 1) then
1763
        alert("GATE CAN NOT DIAL ITSELF", 2)
1764
      else
1765
        alert("NO GATE FOUND AT PROVIDED ADDRESS", 2)
1766
      end
1767
    end
1768
    return
1769
  elseif type(requirement) == "table" then
1770
    if requirement.canOpen == false then
1771
      alert("NOT ENOUGH POWER TO OPEN ... "..tostring(requirement.open).." RF NEEDED", 2)
1772
      return
1773
    end
1774
  else
1775
    alert(tostring("\""..msg.."\" RETURNED FROM getEnergyRequiredToDial()"), 3)
1776
    return
1777
  end
1778
  -- Smart Dialing --
1779
  if #AddressBuffer > 6 then
1780
    local shorterAdr = {}
1781
    for i=1,6 do table.insert(shorterAdr, AddressBuffer[i]) end
1782
    for i=7,8 do
1783
      requirement, msg = sg.getEnergyRequiredToDial(table.unpack(shorterAdr))
1784
      if type(requirement) == "table" then
1785
        alert("SMART DIALING ACTIVE", 1)
1786
        break
1787
      else
1788
        table.insert(shorterAdr, AddressBuffer[i])
1789
      end
1790
    end
1791
    AddressBuffer = {}
1792
    for i,v in ipairs(shorterAdr) do table.insert(AddressBuffer, v) end
1793
  end
1794
  -- End of Smart Dialing --
1795
  if GateType == "MW" then
1796
    table.insert(AddressBuffer,"Point of Origin")
1797
  elseif GateType == "UN" then
1798
    table.insert(AddressBuffer,"Glyph 17")
1799
  elseif GateType == "PG" then
1800
    table.insert(AddressBuffer,"Subido")
1801
  end 
1802
  if gateEntry.IDC ~= nil then
1803
    OutgoingIDC = gateEntry.IDC
1804
  end
1805
  -- Preparing to Dial --
1806
  clearDisplay()
1807
  HelpButton:disable(true)
1808
  gateRingDisplay.draw()
1809
  glyphListWindow.reset()
1810
  buttons.abortDialingButton:disable(false)
1811
  buttons.abortDialingButton:display()
1812
  ComputerDialingInterlocked = true
1813
  AbortingDialing = false
1814
  glyphListWindow.locked = true
1815
  DialingPaused = false
1816
  ChildThread.computerDialing = thread.create(dialNext, 0)
1817
  -- dialNext(0)
1818
end
1819
1820
function dialNext(dialed)
1821
  while DialingPaused do os.sleep(0.05) end
1822
  if not AbortingDialing then
1823
    -- dialAddressWindow.display(gateEntry) --Deprecated?!
1824
    local glyph = AddressBuffer[dialed + 1]
1825
    -- dialAddressWindow.glyph = glyph --Deprecated?!
1826
    if component.isAvailable("dhd") and GateType ~= "UN" and (MiscSettings.dialWithDHD or ForceDialDHD) then
1827
      ComputerDialingWithDHD = true
1828
    end
1829
    glyphListWindow.insertGlyph(glyph)
1830
    if (dialed+1) < 7 then
1831
      gateRingDisplay.traces(dialed+1, 1)
1832
    elseif (dialed+1) == #AddressBuffer then
1833
      gateRingDisplay.traces(7, 1)
1834
      buttons.abortDialingButton:disable(true)
1835
    else
1836
      gateRingDisplay.traces(dialed+2, 1)
1837
    end
1838
    if dialed == 0 or ComputerDialingWithDHD then -- and GateType ~= "PG") then
1839
      gateRingDisplay.glyphImage(glyph)
1840
    else
1841
      event.timer(0.5, function() gateRingDisplay.glyphImage(glyph) end)
1842
    end
1843
    if ComputerDialingWithDHD then
1844
      local _,result,msg = component.dhd.pressButton(glyph)
1845
      if result ~= "dhd_pressed" then
1846
        if result == "dhd_not_connected" then
1847
          computer.pushSignal("stargate_failed","",true,result)
1848
        else
1849
          component.dhd.pressBRB()
1850
        end
1851
        os.exit() -- Only the thread exits, AGS continues to run.
1852
      end
1853
      if GateType == "PG" or not MiscSettings.LudicrousSpeed then
1854
        os.sleep(0.05)
1855
        while sg.getGateStatus() == "dialing" do os.sleep() end
1856
      end
1857
      if (dialed + 1) == #AddressBuffer then
1858
        local _,result,msg = component.dhd.pressBRB()
1859
        if result == "dhd_engage" then
1860
          os.sleep(1)
1861
          gateRingDisplay.eventHorizon(true)
1862
        end
1863
      else
1864
        gateRingDisplay.dialedChevrons(dialed+1, true)
1865
        dialNext(dialed+1)
1866
      end
1867
    else
1868
      sg.engageSymbol(glyph)
1869
    end
1870
  end
1871
end
1872
1873
function finishDialing()
1874
  if ComputerDialingInterlocked then
1875
    ComputerDialingInterlocked = false
1876
    ComputerDialingWithDHD = false
1877
    ForceDialDHD = false
1878
    isDirectDialing = false
1879
    gpu.fill(41, 2, 38, 5, " ")
1880
    mainInterface("noClear")
1881
  end
1882
end
1883
1884
local function IncomingWormholeAbortDialing()
1885
  pcall(function() ChildThread.computerDialing:kill() end)
1886
  finishDialing()
1887
end
1888
1889
local function directAbortDialing()
1890
  if ChildThread.computerDialing ~= nil then ChildThread.computerDialing:kill() end
1891
  local abortResult = ""
1892
  while abortResult ~= "stargate_aborting" do
1893
    _,abortResult = sg.abortDialing()
1894
  end
1895
  -- sg.abortDialing()
1896
  -- if AbortingDialing then
1897
    -- if GateType == "UN" then
1898
      -- alert("ABORTING DIALING... PLEASE WAIT", 2)
1899
      -- while sg.getGateStatus() == "dialing_computer" do os.sleep() end
1900
    -- end
1901
    -- alert("DIALING ABORTED", 2)
1902
  -- end
1903
  
1904
  if GateType ~= "UN" then
1905
    gateRingDisplay.glyphImage()
1906
    gateRingDisplay.reset()
1907
    if DialingInterlocked then DialingInterlocked = false end
1908
    finishDialing()
1909
    glyphListWindow.locked = false
1910
    glyphListWindow.display()
1911
    AbortingDialing = false
1912
  end
1913
  alert("DIALING ABORTED", 2)
1914
end
1915
1916
function abortDialing()
1917
  if DialingPaused then
1918
    alert("Can Not Abort While Dialing is Paused",2)
1919
    return
1920
  end
1921
  AbortingDialing = true
1922
  buttons.abortDialingButton:disable(true)
1923
  -- if sg.abortDialing ~= nil and GateType ~= "UN" then 
1924
  if sg.abortDialing ~= nil then
1925
    directAbortDialing()
1926
  else
1927
    alert("ABORTING DIALING... PLEASE WAIT", 2)
1928
    while sg.getGateStatus() ~= "idle" do os.sleep() end
1929
    alert("DIALING ABORTED", 2)
1930
    sg.engageGate()
1931
    while sg.getGateStatus() == "failing" do os.sleep() end
1932
    ComputerDialingInterlocked = false
1933
    AbortingDialing = false
1934
    gpu.fill(41, 2, 38, 5, " ")
1935
    mainInterface("noClear")
1936
  end
1937
end
1938
-- End Address Dialing -------------------------------------------------------------
1939
1940
-- Address Entry -------------------------------------------------------------------
1941
local AddressEntry = {}
1942
AddressEntry.entryAccepted = nil
1943
AddressEntry.yesButton = Button.new(92, 8, 0, 0, "Yes", function() AddressEntry.entryAccepted = true end)
1944
AddressEntry.noButton = Button.new(98, 8, 0, 0, "No", function() AddressEntry.entryAccepted = false end)
1945
1946
local function addNewGateEntry()
1947
  table.insert(gateEntries, {name="New Entry",gateAddress={MW={},PG={},UN={}},fave=false})
1948
  GateEntriesWindow.selectedIndex = #gateEntries
1949
  writeToDatabase()
1950
  editGateEntry(GateEntriesWindow.selectedIndex)
1951
  alert("Please Enter a Name for the New Gate Entry", 1)
1952
  buttons.renameButton:forceTouch()
1953
end
1954
1955
local function completeAddressEntry(adrType)
1956
  clearDisplay()
1957
  buttons.cancelButton:display()
1958
  glyphListWindow.locked = true
1959
  local index = nil
1960
  local addressName = ""
1961
  local isDuplicate, duplicateNames = entriesDuplicateCheck(AddressBuffer, gateEntries, adrType, 1)
1962
  if editGateEntryMode then index = GateEntriesWindow.selectedIndex end
1963
  if index ~= nil and index > 0 then addressName = gateEntries[index].name end
1964
  for i,v in ipairs(duplicateNames) do
1965
    if v == addressName then table.remove(duplicateNames, i) end
1966
  end
1967
  if #duplicateNames == 0 then isDuplicate = false end
1968
  if isDuplicate then
1969
    alert("ATTENTION",2)
1970
    gpu.set(42, 6, "Possible duplicate address with the following gate entries:")
1971
    term.setCursor(42, 7)
1972
    for i,v in ipairs(duplicateNames) do
1973
      io.write("'"..v.."'")
1974
      if i ~= #duplicateNames then io.write(", ") end
1975
    end
1976
    gpu.set(42, 9, "Would you still like to have the address entered?")
1977
    term.setCursor(104, 8)
1978
    AddressEntry.yesButton:display()
1979
    AddressEntry.noButton:display()
1980
    AddressEntry.entryAccepted = nil
1981
    while AddressEntry.entryAccepted == nil and not WasCanceled do
1982
      os.sleep(0.05)
1983
    end
1984
    AddressEntry.yesButton:hide()
1985
    AddressEntry.noButton:hide()
1986
    if not AddressEntry.entryAccepted then
1987
      alert("ADDRESS ENTRY CANCELED", 1)
1988
    end
1989
  else
1990
    AddressEntry.entryAccepted = true
1991
  end
1992
  if AddressEntry.entryAccepted then
1993
    gateEntries[index].gateAddress[adrType] = {}
1994
    for i,v in ipairs(AddressBuffer) do table.insert(gateEntries[index].gateAddress[adrType], v) end
1995
    writeToDatabase()
1996
    alert("ADDRESS HAS BEEN UPDATED", 1)
1997
  end
1998
  glyphListWindow.locked = false
1999
  addAddressMode = false
2000
  manualAdrEntryMode = false
2001
  editGateEntry(index)
2002
end
2003
2004
local function manualAddressEntry()
2005
  manualAdrEntryMode = true
2006
  GoodAddress = false
2007
  glyphListWindow.locked = false
2008
  clearDisplay()
2009
  buttons.cancelButton:display()
2010
  if glyphListWindow.glyphType ~= adrEntryType then
2011
    glyphListWindow.initialize(adrEntryType)
2012
  else
2013
    glyphListWindow.display()
2014
  end
2015
  local oStr = ""
2016
  if glyphListWindow.glyphType == "MW" then
2017
    oStr = "Origin"
2018
  elseif glyphListWindow.glyphType == "UN" then
2019
    oStr = "Glyph 17"
2020
  elseif glyphListWindow.glyphType == "PG" then
2021
    oStr = "Subido"
2022
  end
2023
  gpu.set(42, 6, "Enter the address using the glyphs to the right. Then hit '"..oStr.."' to complete.")
2024
  while not GoodAddress and manualAdrEntryMode and not WasCanceled do 
2025
    os.sleep(0.05)
2026
  end
2027
  if GoodAddress then
2028
    completeAddressEntry(adrEntryType)
2029
  end
2030
  manualAdrEntryMode = false
2031
  glyphListWindow.initialize(GateType)
2032
end
2033
2034
local function addressEntry(adrType)
2035
  addAddressMode = true;
2036
  adrEntryType = adrType
2037
  AddressBuffer = {}
2038
  clearDisplay()
2039
  buttons.cancelButton:display()
2040
  if adrType ~= GateType then
2041
    -- manualAddressEntry()
2042
    ChildThread.manualAddressEntry = thread.create(manualAddressEntry)
2043
    return
2044
  end
2045
  gpu.set(42, 6, "Select one of the below options to enter the address.")
2046
  buttons.manualEntryButton:display()
2047
  if GateType == "MW" or GateType == "PG" then
2048
    buttons.dhdEntryButton:display()
2049
  elseif GateType == "UN" then
2050
    buttons.dialerEntryButton:display()
2051
  end
2052
end
2053
2054
local function dhdAddressEntry()
2055
  DHD_AdrEntryMode = true
2056
  GoodAddress = false
2057
  WasCanceled = false -- Redundant?
2058
  clearDisplay()
2059
  buttons.cancelButton:display()
2060
  glyphListWindow.reset()
2061
  gpu.set(42, 6, "Use the DHD to dial the glyphs of the address, excluding the 'Point of Origin'.")
2062
  if GateType == "MW" then
2063
    gpu.set(42, 7, "Then hit the 'Big Red Button'")
2064
  elseif GateType == "PG" then
2065
    gpu.set(42, 7, "Then hit the 'Big Blue Button'")
2066
  end
2067
  while DHD_AdrEntryMode and not WasCanceled and not GoodAddress do
2068
    os.sleep(0.05)
2069
  end
2070
  if GoodAddress then
2071
    AddressBuffer = {}
2072
    local glyph = ""
2073
    for i,v in ipairs(glyphListWindow.selectedGlyphs) do
2074
      if v ~= -1 then
2075
        glyph = glyphListWindow.glyphs[v]
2076
        if GateType == "UN" then _,glyph = checkGlyph(glyph, "UN") end
2077
        table.insert(AddressBuffer, glyph)
2078
      end
2079
    end
2080
    completeAddressEntry(GateType)
2081
  end
2082
  addAddressMode = false
2083
  DHD_AdrEntryMode = false
2084
end
2085
2086
local function dialerAddressEntry()
2087
  local allGood = true
2088
  local dialing = false
2089
  clearDisplay()
2090
  glyphListWindow.reset()
2091
  buttons.cancelButton:display()
2092
  dialerAdrEntryMode = true
2093
  gpu.fill(41, 6, 91, 10, " ")
2094
  gpu.set(42, 6, "Dial the gate using your Universe Dialer. The address will be captured once the gate opens.")
2095
  gpu.setForeground(0xFFFF00)
2096
  gpu.set(42, 7, "Warning this process will use power since the gate will open.")
2097
  gpu.set(42, 8, "The gate will close automatically after address capture.")
2098
  gpu.setForeground(0xFFFFFF)
2099
  gpu.set(42, 9, "Please begin dialing or push 'Cancel'")
2100
  while dialerAdrEntryMode do
2101
    os.sleep(0.05)
2102
    if WasCanceled then
2103
      allGood = false
2104
      WasCanceled = false
2105
      dialerAdrEntryMode = false
2106
    end
2107
    if not dialing and sg.getGateStatus() == "dialing" then dialing = true end
2108
    if dialing and not UNGateResetting then
2109
      alert("PLEASE WAIT", 0)
2110
      if sg.getGateStatus() == "idle" then
2111
        alert("DIALING WAS ABORTED", 2)
2112
        dialing = false
2113
        -- allGood = false
2114
        -- dialerAdrEntryMode = false
2115
      elseif sg.getGateStatus() == "open" then -- (Backup check of Opening Event)
2116
        event.timer(1, function() sg.disengageGate() end, 3)
2117
        dialerAdrEntryMode = false
2118
      end
2119
    end
2120
  end
2121
  if allGood then
2122
    AddressBuffer = {}
2123
    for i,v in ipairs(glyphListWindow.selectedGlyphs) do
2124
      if v ~= -1 then
2125
        glyph = glyphListWindow.glyphs[v]
2126
        table.insert(AddressBuffer, glyph)
2127
      end
2128
    end
2129
    alert("ADDRESS WAS CAPTURED", 1)
2130
    completeAddressEntry("UN")
2131
    addAddressMode = false
2132
  end
2133
  dialerAdrEntryMode = false
2134
end
2135
-- End of Address Entry ------------------------------------------------------------
2136
2137
-- Edit Gate Entry -----------------------------------------------------------------
2138
local GateEntryEdit = {}
2139
GateEntryEdit.adminCheckBox = CheckBox.new(109, 6, {}, "NotUsed", function()
2140
  local gateEntry = gateEntries[GateEntriesWindow.selectedIndex]
2141
  if #AdminList == 0 then
2142
    alert("Admin List Needs to Be Setup to Use This Option", 2)
2143
  elseif isAuthorized(User) then
2144
    gateEntry.AdminOnly = (not gateEntry.AdminOnly)
2145
    writeToDatabase()
2146
  end
2147
  GateEntryEdit.adminCheckBox.isChecked = (gateEntry.AdminOnly)
2148
end)
2149
buttons.GEE_adminCheckBox = GateEntryEdit.adminCheckBox
2150
2151
function editGateEntry(index)
2152
  local gateEntry = gateEntries[index]
2153
  -- if gateEntry == nil then
2154
    -- alert("SELECT A GATE ENTRY TO EDIT", 2)
2155
    -- mainInterface()
2156
    -- return
2157
  -- end
2158
  editGateEntryMode = true
2159
  clearDisplay()
2160
  HelpButton:disable(true)
2161
  buttons.cancelButton:display()
2162
  buttons.renameButton:display()
2163
  buttons.changeEntryIDCButton:display()
2164
  buttons.deleteButton:display()
2165
  if type(gateEntry.AdminOnly) ~= "boolean" then gateEntry.AdminOnly = false end
2166
  GateEntryEdit.adminCheckBox:display(gateEntry.AdminOnly)
2167
  glyphListWindow.display()
2168
  glyphListWindow.locked = true
2169
  if gateEntry.gateAddress.MW == nil then gateEntry.gateAddress["MW"] = {} end
2170
  if gateEntry.gateAddress.UN == nil then gateEntry.gateAddress["UN"] = {} end
2171
  if gateEntry.gateAddress.PG == nil then gateEntry.gateAddress["PG"] = {} end
2172
  gpu.set(42, 6, "Name:")
2173
  gpu.set(73, 6, "IDC:")
2174
  gpu.set(91, 6, "Admin Only Access")
2175
  gpu.setBackground(0x878787)
2176
  gpu.fill(48, 6, 21, 1, " ")
2177
  gpu.fill(78, 6, 9, 1, " ")
2178
  gpu.set(48, 6, gateEntry.name)
2179
  if gateEntry.IDC ~= nil then gpu.set(78, 6, tostring(gateEntry.IDC)) end
2180
  gpu.setBackground(0x000000)
2181
  gpu.set(41, 7, "┌────────────────┐  ┌────────────────┐  ┌────────────────┐")
2182
  gpu.set(41, 8, "│   ░░░░░░░░░    │  │    ░░░░░░░░    │  │    ░░░░░░░     │")
2183
  gpu.set(41, 9, "├────────────────┤  ├────────────────┤  ├────────────────┤")
2184
  buttons.addressEntry_MW_Button.border = false
2185
  buttons.addressEntry_UN_Button.border = false
2186
  buttons.addressEntry_PG_Button.border = false
2187
  buttons.addressEntry_MW_Button:display(44, 7)
2188
  buttons.addressEntry_UN_Button:display(65, 7)
2189
  buttons.addressEntry_PG_Button:display(85, 7)
2190
  gpu.fill(41, 10, 1, 8, "│")
2191
  gpu.fill(58, 10, 1, 8, "│")
2192
  gpu.fill(61, 10, 1, 8, "│")
2193
  gpu.fill(78, 10, 1, 8, "│")
2194
  gpu.fill(81, 10, 1, 8, "│")
2195
  gpu.fill(98, 10, 1, 8, "│")
2196
  gpu.set(41, 18, "└────────────────┘  └────────────────┘  └────────────────┘")
2197
  -- gpu.set(49, 19, "To change an address click on its name.")
2198
  gpu.set(42, 19, "To change the entry Name or IDC, directly click on their")
2199
  gpu.set(42, 20, "text field. To change an address click on its name.")
2200
  for i,v in ipairs(gateEntry.gateAddress.MW) do
2201
    gpu.set(41+(9-math.floor(unicode.len(v)/2)), 9+i, v)
2202
  end
2203
  for i,v in ipairs(gateEntry.gateAddress.UN) do
2204
    gpu.set(61+(9-math.ceil(unicode.len(v)/2)), 9+i, v)
2205
  end
2206
  for i,v in ipairs(gateEntry.gateAddress.PG) do
2207
    gpu.set(81+(8-math.floor(unicode.len(v)/2)), 9+i, v)
2208
  end
2209
  if #gateEntry.gateAddress.MW == 0 then gpu.fill(42, 10, 16, 8, "░") end
2210
  if #gateEntry.gateAddress.UN == 0 then gpu.fill(62, 10, 16, 8, "░") end
2211
  if #gateEntry.gateAddress.PG == 0 then gpu.fill(82, 10, 16, 8, "░") end
2212
end
2213
2214
local function renameGateEntry(index)
2215
  buttons.deleteButton:disable(true)
2216
  local oldName = gateEntries[index].name
2217
  local newName, successful = userInput(48, 6, 21, true)
2218
  if successful then
2219
    if newName ~= "" then
2220
      gateEntries[index].name = newName
2221
      alert("\""..oldName.."\" HAS BEEN RENAMED TO \""..gateEntries[index].name.."\"", 1)
2222
      writeToDatabase()
2223
    end
2224
  end
2225
  buttons.deleteButton:disable(false)
2226
  if editGateEntryMode then
2227
    gpu.setBackground(0x878787)
2228
    gpu.fill(48, 6, 21, 1, " ")
2229
    gpu.set(48, 6, gateEntries[index].name)
2230
    gpu.setBackground(0x000000)
2231
  end
2232
end
2233
2234
local function changeEntryIDC(index)
2235
  buttons.deleteButton:disable(true)
2236
  local newIDC, successful = userInput(78, 6, 9, true)
2237
  if successful then
2238
    if newIDC == "" then
2239
      alert("IDC Was Cleared", 2)
2240
      gateEntries[index].IDC = nil
2241
      writeToDatabase()
2242
    else
2243
      newIDC = tonumber(newIDC)
2244
      if type(newIDC) == "number" and newIDC >= 0 and newIDC < 1e9 and math.floor(newIDC) == newIDC then
2245
        alert("IDC Has Been Changed", 1)
2246
        gateEntries[index].IDC = newIDC
2247
        writeToDatabase()
2248
      else
2249
        alert("Invalid IDC", 2)
2250
      end
2251
    end
2252
  end
2253
  buttons.deleteButton:disable(false)
2254
  if editGateEntryMode then
2255
    gpu.setBackground(0x878787)
2256
    gpu.fill(78, 6, 9, 1, " ")
2257
    if gateEntries[index].IDC ~= nil then gpu.set(78, 6, tostring(gateEntries[index].IDC)) end
2258
    gpu.setBackground(0x000000)
2259
  end
2260
end
2261
2262
local function deleteGateEntry(value)
2263
  buttons.renameButton:disable(true)
2264
  if value == 0 then
2265
    gpu.set(44, 23, "┬─────┬")
2266
    gpu.set(44, 24, "│     │")
2267
    gpu.set(44, 25, "├─────┤")
2268
    gpu.set(44, 26, "│     │")
2269
    gpu.set(44, 27, "└─────┘")
2270
    buttons.deleteYesButton:display()
2271
    buttons.deleteNoButton:display()
2272
  elseif value == 1 then
2273
    local index = GateEntriesWindow.selectedIndex
2274
    alert("GATE ENTRY '"..gateEntries[index].name.."' REMOVED", 1)
2275
    table.remove(gateEntries, index)
2276
    writeToDatabase()
2277
    glyphListWindow.locked = false
2278
    editGateEntryMode = false
2279
    buttons.renameButton:disable(false)
2280
    mainInterface()
2281
  elseif value == -1 then
2282
    gpu.fill(44, 23, 7, 5, " ")
2283
    gpu.set(44, 23, "───────")
2284
    buttons.deleteYesButton:hide()
2285
    buttons.deleteNoButton:hide()
2286
    -- alert("DELETE CANCELED", 1) -- For Debug
2287
    buttons.renameButton:disable(false)
2288
  end
2289
end
2290
-- End Edit Gate Entry -------------------------------------------------------------
2291
2292
-- Gate Ring Display ---------------------------------------------------------------
2293
gateRingDisplay = {}
2294
function gateRingDisplay.initialize()
2295
  local self = gateRingDisplay
2296
  self.isActive = false
2297
  if sg.getGateStatus() == "open" then
2298
    self.eventHorizonState = true
2299
  else
2300
    self.eventHorizonState = false
2301
  end
2302
  self.chevronStates = {}
2303
  self.traceStates = {}
2304
  self.engagedChevronCount = 0
2305
  if GateStatusBool == false then
2306
    for i=1,9 do table.insert(self.chevronStates, true) end
2307
  else
2308
    for i=1,9 do table.insert(self.chevronStates, false) end
2309
  end
2310
  for i=1,9 do table.insert(self.traceStates, 0) end
2311
  dofile("gateRing.ff") -- Loads the gate ring graphics
2312
  if GateType == "MW" then
2313
    dofile("glyphsMW.ff") -- Loads MW Glyph Images
2314
  elseif GateType == "UN" then
2315
    dofile("glyphsUN.ff") -- Loads UN Glyph Images
2316
  elseif GateType == "PG" then
2317
    dofile("glyphsPG.ff") -- Loads UN Glyph Images
2318
  end
2319
  self.ringTbl, self.topTbl, self.midTbl, self.botTbl = {},{},{},{}
2320
  self.chevTbl = {"⢤⣤⣤⣤⣤⡤","⠀⢻⣿⣿⡟","⠀⠀⢻⡟"}
2321
  self.dotTbl = {"⢀⣴⣶⣦⡀","⣿⣿⣿⣿⣿","⠈⠻⠿⠟⠁"}
2322
  self.dot2Tbl = {"⣠⣾⣿⣷⣄", "⢿⣿⣿⣿⡿", "⠙⠛⠋"}
2323
  if GateType == "MW" then
2324
    self.offColor = 0x662400
2325
    -- self.offColor = 0x662400
2326
    self.onColor = 0x994900
2327
    self.ringColor = 0x5A5A5A
2328
    -- self.ringColor = 0x696969
2329
    -- self.ringColor = 0x4B4B4B
2330
    self.horizonColor = 0x006DFF
2331
  elseif GateType == "UN" then
2332
    self.offColor = 0xA5A5A5
2333
    self.onColor = 0xFFFFFF
2334
    self.ringColor = 0x1E1E1E
2335
    self.horizonColor = 0x787878
2336
  elseif GateType == "PG" then
2337
    -- self.offColor = 0x4B4B4B
2338
    self.offColor = 0x000040
2339
    self.onColor = 0x0092FF
2340
    -- self.ringColor = 0x5A5A5A
2341
    self.ringColor = 0x4B4B4B
2342
    -- self.ringColor = 0x696969
2343
    self.horizonColor = 0x006DFF
2344
  else
2345
    self.offColor = 0xA5A5A5
2346
    self.onColor = 0xFFFFFF
2347
    self.ringColor = 0x1E1E1E
2348
    self.horizonColor = 0x787878
2349
  end
2350
  for line in GateRing.wholeRing:gmatch("[^\r\n]+") do table.insert(self.ringTbl, line) end
2351
  for line in GateRing.horizonTop:gmatch("[^\r\n]+") do table.insert(self.topTbl, line) end
2352
  for line in GateRing.horizonMid:gmatch("[^\r\n]+") do table.insert(self.midTbl, line) end
2353
  for line in GateRing.horizonBot:gmatch("[^\r\n]+") do table.insert(self.botTbl, line) end
2354
end
2355
2356
function gateRingDisplay.draw()
2357
  local self = gateRingDisplay
2358
  self.isActive = true
2359
  gpu.setForeground(self.ringColor)
2360
  for i,v in ipairs(self.ringTbl) do
2361
    gpu.set(50, 7+i, v)
2362
  end
2363
  self.eventHorizon()
2364
  self.traces()
2365
end
2366
2367
function gateRingDisplay.glyphImage(glyphName, isEngaged)
2368
  local self = gateRingDisplay
2369
  local xPos = 0
2370
  local yPos = 0
2371
  if GateType == "MW" or GateType == "PG" then
2372
    xPos = 64
2373
    yPos = 15
2374
    gpu.fill(xPos, yPos, 32, 16, " ")
2375
  elseif GateType == "UN" then
2376
    xPos = 77
2377
    yPos = 14
2378
    gpu.fill(xPos, yPos, 6, 18, " ")
2379
  end
2380
  if (glyphName == nil and isEngaged == nil) or glyphName == "Unknown" then return end
2381
  if IncomingWormhole then return end
2382
  if isEngaged then
2383
    gpu.setForeground(self.onColor)
2384
  else
2385
    gpu.setForeground(self.offColor)
2386
  end
2387
  if glyphName ~= nil or glyphName ~= "" then
2388
    local glyphImage = GlyphImages[glyphName]
2389
    for line in glyphImage:gmatch("[^\r\n]+") do
2390
      gpu.set(xPos, yPos, line)
2391
      yPos = yPos + 1
2392
    end
2393
  end
2394
  gpu.setForeground(0xFFFFFF)
2395
end
2396
2397
function gateRingDisplay.traces(num, state)
2398
  local self = gateRingDisplay
2399
  if not self.isActive then return end
2400
  if num == nil or num == -1 then
2401
    for i,v in ipairs(self.traceStates) do self.traces(i, v) end
2402
    return
2403
  end
2404
  local glw = glyphListWindow
2405
  local glyphBoxX = 161 - (2 * glw.width)
2406
  local traceEndOffset = 0
2407
  if glw.width ~= nil then
2408
    traceEndOffset = 2*glw.width
2409
  else
2410
    traceEndOffset = 35
2411
  end
2412
  if state == nil or state == 0 then
2413
    gpu.setForeground(0x0F0F0F)
2414
  elseif state == 1 then
2415
    gpu.setForeground(self.offColor)
2416
  elseif state == 2 then
2417
    gpu.setForeground(self.onColor)
2418
  end
2419
  self.traceStates[num] = state
2420
  
2421
  if num == 1 then
2422
    gpu.set(93, 8, "┌─┴─┐") -- 1
2423
    gpu.set(95, 7, "┌") -- 1
2424
    gpu.fill(96, 7, 65-traceEndOffset, 1, "─") -- 1
2425
  elseif num == 2 then
2426
    gpu.set(110, 18, "┐├┘", true) -- 2
2427
    gpu.set(111, 19, "─┘") -- 2
2428
    gpu.fill(112, 9, 1, 10, "│") -- 2
2429
    gpu.set(112, 8, "┌") -- 2
2430
    gpu.fill(113, 8, 48-traceEndOffset, 1, "─") -- 2
2431
  elseif num == 3 then  
2432
    gpu.set(109, 27, "┐├┘", true) -- 3
2433
    gpu.set(110, 28, "────┘") -- 3
2434
    gpu.fill(114, 10, 1, 18, "│") -- 3
2435
    gpu.set(114, 9, "┌") -- 3
2436
    gpu.fill(115, 9, 46-traceEndOffset, 1, "─") -- 3
2437
  elseif num == 4 then  
2438
    gpu.set(50, 27, "┌┤└", true) -- 4
2439
    gpu.set(48, 28, "┌─") -- 4
2440
    gpu.fill(48, 29, 1, 10, "│") -- 4
2441
    gpu.set(48, 39, "└") -- 4
2442
    gpu.fill(49, 39, 20, 1, "─") -- 4
2443
    gpu.fill(70, 39, 20, 1, "─") -- 4
2444
    gpu.fill(91, 39, 25, 1, "─") -- 4
2445
    gpu.set(116, 39, "┘") -- 4
2446
    gpu.fill(116, 11, 1, 28, "│") -- 4
2447
    gpu.set(116, 10, "┌") -- 4
2448
    gpu.fill(117, 10, 44-traceEndOffset, 1, "─") -- 4
2449
  elseif num == 5 then  
2450
    gpu.set(49, 18, "┌┤└", true) -- 5
2451
    gpu.set(46, 19, "┌──") -- 5
2452
    gpu.fill(46, 20, 1, 20, "│") -- 5
2453
    gpu.set(46, 40, "└") -- 5
2454
    gpu.fill(47, 40, 22, 1, "─") -- 5
2455
    gpu.fill(70, 40, 20, 1, "─") -- 5
2456
    gpu.fill(91, 40, 27, 1, "─") -- 5
2457
    gpu.set(118, 40, "┘") -- 5
2458
    gpu.fill(118, 12, 1, 28, "│") -- 5
2459
    gpu.set(118, 11, "┌") -- 5
2460
    gpu.fill(119, 11, 42-traceEndOffset, 1, "─") -- 5
2461
  elseif num == 6 then  
2462
    gpu.set(62, 8, "┌─┴─┐") -- 6
2463
    gpu.set(64, 7, "┐") -- 6
2464
    gpu.fill(45, 7, 19, 1, "─") -- 6
2465
    gpu.set(44, 7, "┌") -- 6
2466
    gpu.fill(44, 8, 1, 33, "│") -- 6
2467
    gpu.set(44, 41, "└") -- 6
2468
    gpu.fill(45, 41, 24, 1, "─") -- 6
2469
    gpu.fill(70, 41, 20, 1, "─") -- 6
2470
    gpu.fill(91, 41, 29, 1, "─") -- 6
2471
    gpu.set(120, 41, "┘") -- 6
2472
    gpu.fill(120, 13, 1, 28, "│") -- 6
2473
    gpu.set(120, 12, "┌") -- 6
2474
    gpu.fill(121, 12, 40-traceEndOffset, 1, "─") -- 6
2475
  elseif num == 7 then  
2476
    gpu.set(76, 7, "⠏⠉⠉⠉⠉⠉⠉⠹") -- 7
2477
    gpu.fill(79, 4, 1, 3, "⢸") -- 7
2478
    gpu.fill(80, 4, 1, 3, "⡇") -- 7
2479
    gpu.set(79, 3, "⢰⡶") -- 7
2480
    gpu.fill(81, 3, 80-glw.width, 1, "⠶") -- 7
2481
  elseif num == 8 then  
2482
    gpu.set(88, 38, "└─┬─┘") -- 8
2483
    gpu.fill(90, 39, 1, 3, "│") -- 8
2484
    gpu.set(90, 42, "└") -- 8
2485
    gpu.fill(91, 42, 31, 1, "─") -- 8
2486
    gpu.set(122, 42, "┘") -- 8
2487
    gpu.fill(122, 14, 1, 28, "│") -- 8
2488
    gpu.set(122, 13, "┌") -- 8
2489
    gpu.fill(123, 13, 38-traceEndOffset, 1, "─") -- 8
2490
  elseif num == 9 then  
2491
    gpu.set(67, 38, "└─┬─┘") -- 9
2492
    gpu.fill(69, 39, 1, 4, "│") -- 9
2493
    gpu.set(69, 43, "└") -- 9
2494
    gpu.fill(70, 43, 54, 1, "─") -- 9
2495
    gpu.set(124, 43, "┘") -- 9
2496
    gpu.fill(124, 15, 1, 28, "│")
2497
    gpu.set(124, 14, "┌") --9
2498
    gpu.fill(125, 14, 36-traceEndOffset, 1, "─") -- 9
2499
  end
2500
  
2501
  gpu.setForeground(0xFFFFFF)
2502
end
2503
2504
function gateRingDisplay.reset()
2505
  local self = gateRingDisplay
2506
  self.engagedChevronCount = 0
2507
  for i,v in ipairs(self.chevronStates) do self.chevronStates[i] = false end
2508
  for i,v in ipairs(self.traceStates) do self.traceStates[i] = 0 end
2509
  if self.isActive then
2510
    for i,v in ipairs(self.chevronStates) do self.setChevron(i, v) end
2511
    for i,v in ipairs(self.traceStates) do self.traces(i, v) end
2512
  end
2513
end
2514
2515
function gateRingDisplay.eventHorizon(isOpen)
2516
  local self = gateRingDisplay
2517
  if isOpen == nil then isOpen = self.eventHorizonState end
2518
  if isOpen then
2519
    self.eventHorizonState = true
2520
  else
2521
    self.eventHorizonState = false
2522
  end
2523
  if self.isActive then
2524
    gpu.setForeground(self.ringColor)
2525
    if isOpen then
2526
      gpu.setBackground(self.horizonColor)
2527
    else
2528
      gpu.setBackground(0x000000)
2529
    end
2530
    for i,v in ipairs(self.topTbl) do
2531
      gpu.set(66, 10+i, v)
2532
    end
2533
    for i,v in ipairs(self.midTbl) do
2534
      gpu.set(57, 13+i, v)
2535
    end
2536
    for i,v in ipairs(self.botTbl) do
2537
      gpu.set(66, 31+i, v)
2538
    end
2539
    for i,v in ipairs(self.chevronStates) do self.setChevron(i, v) end
2540
  end
2541
end
2542
2543
function gateRingDisplay.setChevron(num, isEngaged)
2544
  local self = gateRingDisplay
2545
  local stateColor = nil
2546
  self.chevronStates[num] = isEngaged
2547
  
2548
  if num == 7 and HasRedstone then
2549
    if self.chevronStates[7] and not UNGateResetting then
2550
      redstone.setOutput(sides[RS_Settings.WormholeOpenSide], 15)
2551
    -- else
2552
      -- redstone.setOutput(sides[RS_Settings.WormholeOpenSide], 0)
2553
    end
2554
  end
2555
2556
  if not self.isActive then return end
2557
  if isEngaged then
2558
    stateColor = self.onColor
2559
  else
2560
    stateColor = self.offColor
2561
  end
2562
  gpu.setBackground(self.ringColor)
2563
  gpu.setForeground(stateColor)
2564
  if num == 1 then
2565
    for i,v in ipairs(self.dotTbl) do -- 1
2566
      gpu.set(93, 10+i, v)
2567
    end
2568
  elseif num == 2 then
2569
    for i,v in ipairs(self.dotTbl) do -- 2
2570
      gpu.set(103, 17+i, v)
2571
    end
2572
  elseif num == 3 then
2573
    for i,v in ipairs(self.dotTbl) do -- 3
2574
      gpu.set(101, 26+i, v)
2575
    end
2576
  elseif num == 4 then
2577
    for i,v in ipairs(self.dotTbl) do -- 4
2578
      gpu.set(54, 26+i, v)
2579
    end
2580
  elseif num == 5 then
2581
    for i,v in ipairs(self.dotTbl) do -- 5
2582
      gpu.set(52, 17+i, v)
2583
    end
2584
  elseif num == 6 then
2585
    for i,v in ipairs(self.dotTbl) do -- 6
2586
      gpu.set(62, 10+i, v)
2587
    end
2588
  elseif num == 7 then
2589
    for i,v in ipairs(self.chevTbl) do -- 7
2590
      gpu.set(77, 7+i, v)
2591
    end
2592
  elseif num == 8 then
2593
    for i,v in ipairs(self.dot2Tbl) do -- 8
2594
      if i ~= 3 then gpu.set(88, 33+i, v)
2595
      else gpu.set(89, 33+i, v) end
2596
    end
2597
  elseif num == 9 then
2598
    for i,v in ipairs(self.dot2Tbl) do -- 9
2599
      if i ~= 3 then gpu.set(67, 33+i, v)
2600
      else gpu.set(68, 33+i, v) end
2601
    end
2602
  end
2603
  gpu.setBackground(0x000000)
2604
  gpu.setForeground(0xFFFFFF)
2605
end
2606
2607
function gateRingDisplay.dialedChevrons(count, hideImage)
2608
  -- if IncomingWormhole then return end
2609
  local self = gateRingDisplay
2610
  if count == 0 then engagedChevronCount = 0 end
2611
  if count <= self.engagedChevronCount then return end
2612
2613
  if HasRedstone and not UNGateResetting then
2614
    redstone.setOutput(sides[RS_Settings.ChevronEngagedSide], 15)
2615
    if DialingInterlocked then
2616
      event.timer(0.25, function() redstone.setOutput(sides[RS_Settings.ChevronEngagedSide], 0) end)
2617
    end
2618
  end
2619
2620
  -- computer.beep() -- For debug
2621
  local glyphName = DialedAddress[count]
2622
  if glyphName == "" then 
2623
    if GateType == "MW" then
2624
      glyphName = "Point of Origin"
2625
    elseif GateType == "PG" then
2626
      glyphName = "Subido"
2627
    end
2628
  end
2629
  if editGateEntryMode and not addAddressMode then hideImage = true end
2630
  if not hideImage then self.glyphImage(glyphName, true) end
2631
  if count < 7 then
2632
    self.setChevron(count, true)
2633
    self.traces(count, 2)
2634
  else
2635
    if glyphName == "Point of Origin" or glyphName == "Glyph 17" or glyphName == "Subido" then
2636
      self.setChevron(7, true)
2637
      self.traces(7, 2)
2638
    else
2639
      self.setChevron(count+1, true)
2640
      self.traces(count+1, 2)
2641
    end
2642
  end
2643
  self.engagedChevronCount = self.engagedChevronCount + 1
2644
end
2645
2646
function gateRingDisplay.UNreset()
2647
  if UNGateResetting then
2648
    return
2649
  end
2650
  UNGateResetting = true
2651
  -- while true do
2652
    -- os.sleep()
2653
    -- local status = sg.getGateStatus()
2654
    -- if status == "dialing" or status == "failing" then break end
2655
  -- end
2656
  local self = gateRingDisplay
2657
  alert("STARGATE IS RESETTING", 1)
2658
  local sequence = {[1]=7,[2]=1,[3]=2,[4]=3,[5]=8,[6]=9,[7]=4,[8]=5,[9]=6}
2659
  local pos = 1
2660
  while UNGateResetting do
2661
    local status,_ = sg.getGateStatus()
2662
    if pos > 9 then pos = 1 end
2663
    self.setChevron(sequence[pos], true)
2664
    os.sleep()
2665
    self.setChevron(sequence[pos], false)
2666
    pos = pos + 1
2667
  end
2668
  self.setChevron(sequence[pos], false)
2669
  alert("STARGATE HAS RESET", 1)
2670
end
2671
-- End of Gate Ring Display --------------------------------------------------------
2672
2673
-- Event Section -------------------------------------------------------------------
2674
local EventListeners = {
2675
  stargate_spin_chevron_engaged = event.listen("stargate_spin_chevron_engaged", function(_, _, caller, num, lock, glyph)
2676
    if not ComputerDialingWithDHD then
2677
      if ComputerDialingInterlocked then
2678
        if HasRedstone then
2679
          redstone.setOutput(sides[RS_Settings.ChevronEngagedSide], 0)
2680
          -- event.timer(0.5, function() redstone.setOutput(sides[RS_Settings.ChevronEngagedSide], 0) end)
2681
        end
2682
        
2683
        if lock then
2684
          alert("CHEVRON "..math.floor(num).." LOCKED", 1)
2685
          if not AbortingDialing then sg.engageGate() end
2686
          if not caller then os.sleep() end
2687
        else
2688
          if (num) < 7 then
2689
          else
2690
          end        
2691
          if not caller then os.sleep() end
2692
          if not AbortingDialing then 
2693
            alert("CHEVRON "..math.floor(num).." ENGAGED", 0)
2694
            dialNext(num)
2695
          end
2696
        end
2697
      else
2698
        -- os.sleep(0.1)
2699
        local status, err = xpcall(glyphListWindow.showAddress, debug.traceback)
2700
        if err ~= nil then ErrorMessage = err end
2701
        HadNoError = status
2702
        -- glyphListWindow.showAddress()
2703
      end
2704
    end
2705
  end),
2706
  
2707
  stargate_dhd_chevron_engaged = event.listen("stargate_dhd_chevron_engaged", function(_, _, caller, num, lock, glyph)
2708
    if not ComputerDialingWithDHD then
2709
      local status, err = xpcall(glyphListWindow.showAddress, debug.traceback)
2710
      if err ~= nil then ErrorMessage = err end
2711
      HadNoError = status
2712
    end
2713
  end),
2714
  
2715
  stargate_incoming_wormhole = event.listen("stargate_incoming_wormhole", function(_, _, caller, dialedAddressSize)
2716
    AddressBuffer = {}
2717
2718
    if IncomingWormhole == false then
2719
      IncomingWormhole = true
2720
      if ComputerDialingInterlocked then
2721
        IncomingWormholeAbortDialing()
2722
      end
2723
      if IDC ~= nil and IrisSettings.AutoCloseIris == true and sg.getIrisState() == "OPENED" then
2724
        sg.toggleIris()
2725
      end
2726
      if HasRedstone then
2727
        redstone.setOutput(sides[RS_Settings.WormholeOpenSide], 15)
2728
      end
2729
      alert("INCOMING WORMHOLE", 2)
2730
      if gateRingDisplay.isActive then
2731
        gateRingDisplay.glyphImage()
2732
        gateRingDisplay.reset()
2733
        for i=1,dialedAddressSize do gateRingDisplay.chevronStates[i] = true end
2734
        for i,v in ipairs(gateRingDisplay.chevronStates) do 
2735
          if i > 6 and i < dialedAddressSize then
2736
            gateRingDisplay.setChevron(i+1, v)
2737
          elseif i == dialedAddressSize then
2738
           gateRingDisplay.setChevron(7, v)
2739
          else
2740
            gateRingDisplay.setChevron(i, v)
2741
          end
2742
          os.sleep(0.25)
2743
        end
2744
      end
2745
      updateButtons()
2746
      os.sleep(3)
2747
      IncomingWormhole = false
2748
    end
2749
  end),
2750
2751
  stargate_open = event.listen("stargate_open", function(_, _, caller, isInitiating)
2752
    local status, err = xpcall(function()
2753
      WormholeConnected = true
2754
      event.timer(0.05, function() gateRingDisplay.eventHorizon(true) end)
2755
      -- gateRingDisplay.eventHorizon(true)
2756
      if isInitiating then
2757
        finishDialing()
2758
        updateHistory()
2759
      end
2760
      if DialingInterlocked then DialingInterlocked = false end
2761
      glyphListWindow.locked = false
2762
      glyphListWindow.display()
2763
      os.sleep(1)
2764
    end, debug.traceback)
2765
    if err ~= nil then ErrorMessage = err end
2766
    HadNoError = status 
2767
  end),
2768
  
2769
  stargate_wormhole_stabilized = event.listen("stargate_wormhole_stabilized", function(_, _, caller, isInitiating)
2770
    local status, err = xpcall(function()
2771
      -- if dialerAdrEntryMode then
2772
        -- event.timer(0.5, function()
2773
          -- sg.disengageGate()
2774
          -- dialerAdrEntryMode = false
2775
        -- end)
2776
      -- end
2777
      if isInitiating and OutgoingIDC ~= nil then
2778
        event.timer(1.5, function()
2779
          alert("Sending IDC",1)
2780
          os.sleep(0.5)
2781
          sg.sendIrisCode(OutgoingIDC)
2782
        end)
2783
      end
2784
    end, debug.traceback)
2785
    if err ~= nil then ErrorMessage = err end
2786
    HadNoError = status 
2787
  end),
2788
2789
  stargate_close = event.listen("stargate_close", function(_, _, caller, reason)
2790
    local status, err = xpcall(function()
2791
      if HasRedstone then
2792
        redstone.setOutput(sides[RS_Settings.WormholeOpenSide], 0)
2793
      end
2794
2795
      if not addAddressMode then
2796
        -- if glyphListWindow.selectedGlyphs[#glyphListWindow.selectedGlyphs] < 1 then
2797
          -- table.remove(glyphListWindow.selectedGlyphs) -- Redundant?
2798
        -- end
2799
        glyphListWindow.locked = false
2800
        glyphListWindow.display()
2801
      end
2802
      gateRingDisplay.reset()
2803
      os.sleep(1.5)
2804
      alert("CONNECTION HAS CLOSED", 1)
2805
      gateRingDisplay.eventHorizon(false)
2806
    end, debug.traceback)
2807
    if err ~= nil then ErrorMessage = err end
2808
    HadNoError = status
2809
  end),
2810
2811
  stargate_wormhole_closed_fully = event.listen("stargate_wormhole_closed_fully", function(_, _, caller, isInitiating)
2812
    if sg.getIrisState() == "CLOSED" then
2813
      sg.toggleIris()
2814
    end
2815
    OutgoingWormhole = false
2816
    if GateType == "UN" then
2817
      gateRingDisplay.UNreset()
2818
    end
2819
    updateButtons()
2820
  end),
2821
2822
  stargate_failed = event.listen("stargate_failed", function(_, _, caller, reason)
2823
    if reason == nil then return end
2824
    if not AbortingDialing and not DHD_AdrEntryMode and not ComputerDialingWithDHD then
2825
      if reason == "address_malformed" then
2826
        alert("UNABLE TO ESTABLISH CONNECTION", 3)
2827
      elseif reason == "not_enough_power" then
2828
        alert("NOT ENOUGH POWER TO CONNECT", 3)
2829
      elseif reason == "aborted" then
2830
        alert("ABORTED BY HAND DIALER", 2)
2831
      end
2832
    end
2833
    if GateType == "UN" and reason ~= "aborted" then
2834
      gateRingDisplay.UNreset()
2835
    end
2836
    if ComputerDialingWithDHD then
2837
      if reason == "address_malformed" then
2838
        alert("UNABLE TO FINISH DIALING. MAKE SURE DHD HAS A DHD GLYPH CRYSTAL", 3)
2839
      elseif reason == "dhd_not_connected" then
2840
        alert("DHD IS NOT LINKED TO THE STARGATE",3)
2841
      end
2842
    end
2843
    if not editGateEntryMode then gateRingDisplay.glyphImage() end
2844
    if DHD_AdrEntryMode then gateRingDisplay.glyphImage() end
2845
    gateRingDisplay.reset()
2846
    if DialingInterlocked then DialingInterlocked = false end
2847
    finishDialing()
2848
    if not dialerAdrEntryMode and not DHD_AdrEntryMode then
2849
      glyphListWindow.locked = false
2850
      glyphListWindow.display()
2851
    end
2852
    if DHD_AdrEntryMode and not GoodAddress and #glyphListWindow.selectedGlyphs > 0 then
2853
      if #glyphListWindow.selectedGlyphs >= 6 then
2854
        local allGood = true
2855
        for i,v in ipairs(glyphListWindow.selectedGlyphs) do
2856
          if v < 1 then
2857
            allGood = false
2858
            break
2859
          end
2860
        end
2861
        GoodAddress = allGood
2862
      end
2863
      if not GoodAddress then
2864
        alert("Address is Invalid", 2)
2865
      end
2866
    end
2867
    if AbortingDialing then AbortingDialing = false end
2868
  end),
2869
2870
  modem_message = event.listen("modem_message", function(_, _, sender, port, _, msg)
2871
    if port == ModemIDCPort and tonumber(msg) ~= nil then
2872
      local code = tonumber(msg)
2873
      if IDC == code then
2874
        if sg.getIrisState() == "CLOSED" then
2875
          sg.toggleIris()
2876
          modem.send(sender, ModemIDCPort, "IDC Accepted!")
2877
        else
2878
          if IrisType == "SHIELD" then
2879
            modem.send(sender, ModemIDCPort, "Shield is Off!")
2880
          else
2881
            modem.send(sender, ModemIDCPort, "Iris is Open!")
2882
          end
2883
        end
2884
      elseif IDC ~= code and sg.getIrisState() == "CLOSED" then
2885
        modem.send(sender, ModemIDCPort, "IDC is Incorrect!")
2886
      end
2887
    end
2888
  end),
2889
  
2890
  received_code = event.listen("received_code", function(_, _, _, code)
2891
    if IDC == code then
2892
      if sg.getIrisState() == "CLOSED" then
2893
        sg.toggleIris()
2894
        sg.sendMessageToIncoming("IDC Accepted!")
2895
      else
2896
        if IrisType == "SHIELD" then
2897
          sg.sendMessageToIncoming("Shield is Off!")
2898
        else
2899
          sg.sendMessageToIncoming("Iris is Open!")
2900
        end
2901
      end
2902
    elseif IDC ~= code and sg.getIrisState() == "CLOSED" then
2903
      sg.sendMessageToIncoming("IDC is Incorrect!")
2904
    end
2905
  end),
2906
2907
  code_respond = event.listen("code_respond", function(_, _, caller, msg)
2908
    msg = string.sub(msg, 1, -3)
2909
    alert(msg, 2)
2910
    OutgoingIDC = nil
2911
  end),
2912
2913
  key_down = event.listen("key_down", function(_, keyboardAddress, chr, code, playerName)
2914
    User = playerName
2915
    table.insert(keyCombo, code)
2916
    if #keyCombo > 1 and (keyCombo[1] == 29 and keyCombo[2] == 16) and isAuthorized(User, AdminOnlySettings.Quit) then -- Ctrl+Q to Completely Exit
2917
      if _G.agsKioskMode then _G.agsKioskMode = false end
2918
      WasCanceled = true
2919
      MainLoop = false
2920
    end
2921
    if code == 201 then GateEntriesWindow.increment(-1) end -- PgUp
2922
    if code == 209 then GateEntriesWindow.increment(1) end  -- PgDn
2923
  end),
2924
2925
  key_up = event.listen("key_up", function(_, keyboardAddress, chr, code, playerName)
2926
    keyCombo = {}
2927
    if code == 59 and not HelpButton.disabled then -- Toggles the instructions if F1 is pressed then released
2928
      HelpWindow.toggle()
2929
    end
2930
    if code == 88 then toggleDebugMode() end -- F12 to toggle debug
2931
    if code == 62 and not screen.isTouchModeInverted() then
2932
      alert("TOUCH SCREEN MODE ACTIVATED", 1)
2933
      screen.setTouchModeInverted(true)
2934
    elseif code == 62 and screen.isTouchModeInverted() then
2935
      alert("TOUCH SCREEN MODE DEACTIVATED", 1)
2936
      screen.setTouchModeInverted(false)
2937
    end
2938
    if code == 65 then -- F7 Key
2939
      DialingPaused = not DialingPaused
2940
      if DialingPaused then
2941
        alert("Dialing Has Been Paused", 2)
2942
      elseif not DialingPaused then
2943
        alert("Dialing Pause Has Been Released", 2)
2944
      end
2945
    end
2946
    if code == 66 and component.isAvailable("dhd") then component.dhd.pressBRB() end -- F8 Key For Debug
2947
    User = ""
2948
  end),
2949
2950
  touch = event.listen("touch", function(_, screenAddress, x, y, button, playerName)
2951
    local status, err = xpcall(function()
2952
      User = playerName
2953
      term.setCursor(0,0)
2954
      if DebugMode then
2955
        gpu.fill(150, 43, 10, 1, " ") -- For Debug
2956
        gpu.set(150, 43, x..", "..y)  -- For Debug
2957
      end
2958
      if button == 0 then
2959
        for i,v in ipairs(ActiveButtons) do
2960
          if v:touch(x,y) then break end
2961
        end
2962
        glyphListWindow.touch(x, y)
2963
        GateEntriesWindow.touch(x, y)
2964
      end
2965
      User = ""
2966
    end, debug.traceback)
2967
    if err ~= nil then ErrorMessage = err end
2968
    HadNoError = status 
2969
  end),
2970
2971
  scroll = event.listen("scroll", function(_, screenAddress, x, y, direction, playerName)
2972
      GateEntriesWindow.increment(direction*-1)
2973
  end),
2974
2975
  -- component_unavailable = event.listen("component_unavailable", function(_, componentString)
2976
    -- if componentString == "stargate" then
2977
      -- alert(componentString, 3)
2978
      -- error("Stargate Has Been Disconnected")
2979
      -- ErrorMessage = "Stargate Has Been Disconnected"
2980
      -- HadNoError = false
2981
      -- while MainLoop do 
2982
        -- MainLoop = false
2983
      -- end
2984
    -- end
2985
  -- end),
2986
2987
  interruptedEvent = event.listen("interrupted", function()
2988
    if isAuthorized(User, AdminOnlySettings.Quit) then
2989
      wasTerminated = true
2990
      MainLoop = false
2991
    end
2992
  end),
2993
}
2994
-- End of Event Section ------------------------------------------------------------
2995
2996
-- Buttons -------------------------------------------------------------------------
2997
buttons.dialButton = Button.new(41, 2, 0, 3, "  Dial  ", function()
2998
  local gateEntry = nil
2999
  if GateEntriesWindow.mode == "database" then
3000
    gateEntry = gateEntries[GateEntriesWindow.selectedIndex]
3001
  elseif GateEntriesWindow.mode == "history" then
3002
    gateEntry = historyEntries[GateEntriesWindow.selectedIndex]
3003
  end
3004
  if AdminOnlySettings.AdminCanForceDialDHD and isAuthorized(User) and keyCombo[1] == 29 then
3005
    ForceDialDHD = true
3006
  end
3007
  if not gateEntry.AdminOnly then
3008
    dialAddress(gateEntry)
3009
  elseif isAuthorized(User) then
3010
    AdminDialed = (gateEntry.AdminOnly)
3011
    dialAddress(gateEntry)
3012
  end
3013
end)
3014
buttons.editButton = Button.new(64, 2, 0, 3, "Edit Entry", function()
3015
  local gateEntry = gateEntries[GateEntriesWindow.selectedIndex]
3016
  if gateEntry ~= nil then
3017
    if isAuthorized(User, AdminOnlySettings.EditEntry) then
3018
      if not gateEntry.AdminOnly then
3019
        editGateEntry(GateEntriesWindow.selectedIndex)
3020
      elseif isAuthorized(User) then
3021
        editGateEntry(GateEntriesWindow.selectedIndex)
3022
      end
3023
    end
3024
  else
3025
    alert("SELECT A GATE ENTRY TO EDIT", 2)
3026
  end
3027
end)
3028
buttons.renameButton = Button.new(47, 5, 23, 3, "", function()
3029
  renameGateEntry(GateEntriesWindow.selectedIndex)
3030
end, false)
3031
buttons.changeEntryIDCButton = Button.new(77, 5, 11, 3, "", function()
3032
  changeEntryIDC(GateEntriesWindow.selectedIndex)
3033
end, false)
3034
buttons.deleteButton = Button.new(41, 21, 0, 3, "Delete Entry", function() --56
3035
  deleteGateEntry(0)
3036
end)
3037
buttons.deleteYesButton = Button.new(44, 23, 0, 3, " Yes ", function()
3038
  deleteGateEntry(1)
3039
end, false)
3040
buttons.deleteNoButton = Button.new(44, 25, 0, 3, " No  ", function()
3041
  deleteGateEntry(-1)
3042
end, false)
3043
buttons.addEntryButton = Button.new(52, 2, 0, 3, "Add Entry", function()
3044
  if isAuthorized(User, AdminOnlySettings.AddEntry) then
3045
    addNewGateEntry()
3046
  end
3047
end)
3048
buttons.abortDialingButton = Button.new(41, 2, 0, 3, "Abort Dialing", function()
3049
  abortDialing()
3050
end)
3051
buttons.glyphResetButton = Button.new(term.window.width-36, 16, 0, 0, "Reset", function()
3052
  if GateStatusBool == nil and sg.dialedAddress ~= nil and sg.dialedAddress ~= "[]" then
3053
    DHD_AdrEntryMode = true
3054
    alert("CLEARING ENGAGED CHEVRONS", 2)
3055
    if sg.abortDialing ~= nil and GateType ~= "UN" then
3056
      directAbortDialing()
3057
    else
3058
      sg.engageGate()
3059
    end
3060
  end
3061
  glyphListWindow.reset()
3062
  for i,v in ipairs(gateRingDisplay.traceStates) do gateRingDisplay.traceStates[i] = 0 end
3063
  if gateRingDisplay.isActive then
3064
    for i,v in ipairs(gateRingDisplay.traceStates) do gateRingDisplay.traces(i, v) end
3065
  end
3066
end)
3067
buttons.dhdEntryButton = Button.new(54, 7, 0, 0, "DHD", function()
3068
  ChildThread.dhdAddressEntry = thread.create(dhdAddressEntry)
3069
end)
3070
buttons.dialerEntryButton = Button.new(54, 7, 0, 0, "Dialer", function()
3071
  ChildThread.dialerAddressEntry = thread.create(dialerAddressEntry)
3072
end)
3073
buttons.manualEntryButton = Button.new(42, 7, 0, 0, "Manually", function()
3074
  ChildThread.manualAddressEntry = thread.create(manualAddressEntry)
3075
end)
3076
buttons.addressEntry_MW_Button = Button.new(41, 9, 0, 0, "Milky Way", function()
3077
  addressEntry("MW")
3078
end, false)
3079
buttons.addressEntry_UN_Button = Button.new(41, 10, 0, 0, "Universe", function()
3080
  addressEntry("UN")
3081
end, false)
3082
buttons.addressEntry_PG_Button = Button.new(41, 11, 0, 0, "Pegasus", function()
3083
  addressEntry("PG")
3084
end, false)
3085
buttons.cancelButton = Button.new(41, 2, 0, 0, "←─Back", function() -- Button.new(41, 2, 0, 0, "Cancel", function()
3086
  glyphListWindow.locked = false
3087
  WasCanceled = true
3088
  manualAdrEntryMode = false
3089
  glyphListWindow.initialize(GateType)
3090
  if editGateEntryMode and addAddressMode then
3091
    editGateEntry(GateEntriesWindow.selectedIndex)
3092
  else
3093
    editGateEntryMode = false
3094
    mainInterface()
3095
  end
3096
  addAddressMode = false
3097
  event.timer(0.5, function() WasCanceled = false end)
3098
end)
3099
3100
QuitButton = Button.new(1, 41, 0, 3, "Quit", function()
3101
  if isAuthorized(User, AdminOnlySettings.Quit) then
3102
    if _G.agsKioskMode then _G.agsKioskMode = false end
3103
    WasCanceled = true
3104
    MainLoop = false
3105
  end
3106
end)
3107
HelpButton = Button.new(8, 41, 0, 0, "Help", function()
3108
  HelpWindow.toggle()
3109
end)
3110
CloseGateButton = Button.new(15, 41, 0, 3, "Close Gate", function()
3111
  local s,f = sg.disengageGate()
3112
  if f == "stargate_failure_wrong_end" then
3113
    alert("CAN NOT CLOSE AN INCOMING CONNECTION", 2)
3114
  elseif f == "stargate_failure_not_open" then
3115
    alert("GATE IS NOT OPEN", 1)
3116
  end
3117
end)
3118
IrisToggleButton = Button.new(28, 41, 0, 0, " ", function()
3119
  if isAuthorized(User, AdminOnlySettings.ToggleIris) then
3120
    sg.toggleIris()
3121
  end
3122
end)
3123
-- IDCButton = Button.new(126, 41, 0, 0, "IDC", function()
3124
  -- alert("Sending IDC: "..tostring(OutgoingIDC), 1)
3125
  -- sg.sendIrisCode(OutgoingIDC)
3126
-- end)
3127
3128
3129
function updateButtons()
3130
  if GateEntriesWindow.canDial[GateEntriesWindow.selectedIndex] == true and GateStatusString == "idle" then
3131
    buttons.dialButton:disable(false)
3132
    -- buttons.dialButton:display()
3133
  else
3134
    buttons.dialButton:disable(true)
3135
    -- if sg.abortDialing ~= nil and DialingInterlocked then
3136
      -- buttons.dialButton:hide()
3137
      -- buttons.abortDialingButton:display()
3138
    -- end
3139
  end
3140
  if GateEntriesWindow.mode == "database" then
3141
    buttons.editButton:disable(false)
3142
    buttons.addEntryButton:disable(false)
3143
  elseif GateEntriesWindow.mode == "history" then
3144
    buttons.editButton:disable(true)
3145
    buttons.addEntryButton:disable(true)
3146
  end
3147
end
3148
-- End of Buttons ------------------------------------------------------------------
3149
3150
-- Help Window ---------------------------------------------------------------------
3151
HelpWindow = {visible=false}
3152
function HelpWindow.toggle()
3153
  local helpMessage = {
3154
    "DIALING:",
3155
    " To dial out select a Gate Entry from the list to the left, and click the",
3156
    " 'Dial' button. You can also directly enter an address with the glyphs to",
3157
    " the right, then click 'Origin' to begin dialing.",
3158
    " ",
3159
    "ADD ENTRY:",
3160
    " To add a Gate to the 'Gate Entries' list click the 'Add Entry' button and",
3161
    " follow the prompts.",
3162
    " ",
3163
    "EDIT ENTRY:",
3164
    " To edit a Gate Entry, select it from the list and click the 'Edit Entry'",
3165
    " button. On the 'Edit Entry' screen you can rename the entry, delete it, or",
3166
    " change it's gate addresses.",
3167
    " ",
3168
    "KEY BINDS:",
3169
    " F4: Toggles Touch Screen Mode",
3170
    " F12: Toggles Debug Information",
3171
    " Ctrl+Q: Closes the Dialer Program",
3172
    " Ctrl+C: Forces the Dialer to Close",
3173
    " ",
3174
    "Dialer Version: "..Version
3175
  }
3176
  local self = HelpWindow
3177
  self.xPos = 41
3178
  self.yPos = 5
3179
  self.width = 80
3180
  self.height = 2 + #helpMessage
3181
  if self.visible then
3182
    self.visible = false
3183
    mainInterface()
3184
  elseif not self.visible then
3185
    self.visible = true
3186
    gateRingDisplay.isActive = false
3187
    gpu.fill(self.xPos, self.yPos, self.width, self.height, " ")
3188
    gpu.set(self.xPos, self.yPos,               "╔══════════════════════════════════════════════════════════════════════════════╗")
3189
    gpu.set(self.xPos, self.yPos+self.height-1, "╚══════════════════════════════════════════════════════════════════════════════╝")
3190
    gpu.fill(self.xPos, self.yPos+1, 1, self.height-2, "║")
3191
    gpu.fill(self.xPos+self.width-1, self.yPos+1, 1, self.height-2, "║")
3192
    for i,line in ipairs(helpMessage) do
3193
      gpu.set(self.xPos+1, self.yPos+i, line)
3194
    end
3195
  end
3196
end
3197
-- End of Help Window --------------------------------------------------------------
3198
3199
3200
-- Display Main Interface ----------------------------------------------------------
3201
function mainInterface(shouldClear)
3202
  if shouldClear == nil then 
3203
    clearDisplay() 
3204
    gateRingDisplay.draw()
3205
  end
3206
  if glyphListWindow.glyphType ~= GateType then glyphListWindow.initialize(GateType) end
3207
  glyphListWindow.display()
3208
  buttons.dialButton:display()
3209
  buttons.editButton:display()
3210
  buttons.addEntryButton:display()
3211
  updateButtons()
3212
  if HelpButton.disabled then HelpButton:disable(false) end
3213
end
3214
-- End of Display Main Interface ---------------------------------------------------
3215
3216
3217
-- Initialization ------------------------------------------------------------------
3218
local status, err = xpcall(function()
3219
  localMWAddress = sg.stargateAddress.MILKYWAY
3220
  localUNAddress = sg.stargateAddress.UNIVERSE
3221
  localPGAddress = sg.stargateAddress.PEGASUS
3222
  term.clear()
3223
  initialLoadAddressFile()
3224
  GateEntriesWindow.set()
3225
3226
  ChildThread.debugWindowThread:suspend()
3227
  QuitButton:display()
3228
  HelpWindow.visible = false
3229
  HelpButton:display()
3230
  glyphListWindow.initialize(GateType)
3231
  gateRingDisplay.initialize()
3232
  gateRingDisplay.draw()
3233
  if sg.dialedAddress ~= nil and sg.dialedAddress ~= "[]" then
3234
    DialedAddress = parseAddressString(sg.dialedAddress, GateType)
3235
    glyphListWindow.showAddress()
3236
    for i in ipairs(DialedAddress) do gateRingDisplay.dialedChevrons(i, true) end
3237
  end
3238
  mainInterface()
3239
  displayInfoCenter()
3240
  CloseGateButton:display()
3241
3242
  ChildThread.gateStatusThread = thread.create(function()
3243
    while MainLoop and HadNoError do 
3244
      local status, err = xpcall(function()
3245
        GateStatusString = nil
3246
        GateStatusBool = nil
3247
        pcall(function() GateStatusString, GateStatusBool = sg.getGateStatus() end)
3248
        if GateStatusBool ~= nil and GateStatusBool == true then
3249
          OutgoingWormhole = true
3250
          if CloseGateButton.disabled then
3251
            CloseGateButton:disable(false)
3252
          end
3253
        elseif not CloseGateButton.disabled then
3254
          CloseGateButton:disable(true)
3255
        end
3256
        if HasRedstone then
3257
          if GateStatusString ~= "idle" or ComputerDialingInterlocked then
3258
            redstone.setOutput(sides[RS_Settings.GateIsActiveSide], 15)
3259
          else
3260
            redstone.setOutput(sides[RS_Settings.GateIsActiveSide], 0)
3261
          end
3262
        end
3263
        if GateStatusString == "dialing" and not UNGateResetting and not ComputerDialingWithDHD then --and not DialingInterlocked then
3264
          DialingInterlocked = true
3265
          if sg.dialedAddress == "[]" then
3266
            glyphListWindow.reset()
3267
          end
3268
        end
3269
        if DialingInterlocked or ComputerDialingInterlocked then
3270
          if not UNGateResetting and not IncomingWormhole then
3271
            DialedAddress = parseAddressString(sg.dialedAddress, GateType)
3272
            gateRingDisplay.dialedChevrons(#DialedAddress)
3273
            -- glyphListWindow.insertAddress(DialedAddress)
3274
            if buttons.glyphResetButton.visible then buttons.glyphResetButton:hide() end
3275
            if not glyphListWindow.locked then glyphListWindow.locked = true end
3276
            if GateStatusString == "dialing" and GateType == "UN" then
3277
              -- glyphListWindow.insertAddress(DialedAddress)
3278
              glyphListWindow.showAddress()
3279
            end
3280
          end
3281
        end
3282
        if GateStatusString == "idle" and not ComputerDialingInterlocked then
3283
          if UNGateResetting then
3284
            UNGateResetting = false
3285
            if HasRedstone and WormholeConnected then
3286
              redstone.setOutput(sides[RS_Settings.ExhaustVentSide], 15)
3287
              event.timer(3.5, function()
3288
                redstone.setOutput(sides[RS_Settings.ExhaustVentSide], 0)
3289
              end)
3290
            end
3291
          end
3292
          WormholeConnected = false
3293
          if DialingInterlocked then
3294
            DialingInterlocked = false
3295
          end
3296
          if glyphListWindow.locked and not editGateEntryMode then
3297
            glyphListWindow.locked = false
3298
            -- glyphListWindow.display()
3299
          end
3300
          if #glyphListWindow.selectedGlyphs > 0 and not buttons.glyphResetButton.visible then
3301
            buttons.glyphResetButton:display()
3302
          end
3303
        end
3304
        if GateStatusString == "dialing" and ComputerDialingInterlocked and not ComputerDialingWithDHD and not AbortingDialing then abortDialing() end -- If DHD is used while the computer is dialing, abort dialing.
3305
      end, debug.traceback)
3306
      if err ~= nil then ErrorMessage = err end
3307
      HadNoError = status
3308
      pcall(function() IrisType = sg.getIrisType() end)
3309
      if IrisType == nil or IrisType == "NULL" then
3310
        IrisToggleButton:hide()
3311
      else
3312
        local labelString = nil
3313
        if IrisType == "SHIELD" then
3314
          labelString = "Toggle Shield"
3315
          IrisDurability = "∞ Shield ∞"
3316
        else
3317
          labelString = "Toggle Iris"
3318
          IrisDurability = sg.getIrisDurability()
3319
        end
3320
        if not IrisToggleButton.visible or labelString ~= IrisToggleButton.label then
3321
          IrisToggleButton:hide()
3322
          IrisToggleButton.label = labelString
3323
          IrisToggleButton.width = 1
3324
          IrisToggleButton:display()
3325
        end
3326
      end
3327
      freeMemoryPercent = tostring(math.floor((computer.freeMemory()/computer.totalMemory())*100)).."%"
3328
      os.sleep()
3329
    end
3330
  end)
3331
3332
  runPlugin()
3333
3334
  -- Main Loop just to keep AGS alive. --
3335
  while MainLoop and HadNoError do
3336
    os.sleep(1)
3337
  end
3338
  
3339
end, debug.traceback)
3340
if err ~= nil then ErrorMessage = err end
3341
HadNoError = status
3342
-- Initialization End --------------------------------------------------------------
3343
3344
3345
-- Closing Procedures --------------------------------------------------------------
3346
DialingPaused = false
3347
writeToDatabase()
3348
while ChildThread.databaseWrite:status() ~= "dead" do end
3349
term.clear()
3350
3351
-- Clean up buttons
3352
for k,v in pairs(buttons) do
3353
  k = nil
3354
end
3355
buttons = nil
3356
3357
-- Turn off all redstone
3358
if HasRedstone then
3359
  for i=0,5,1 do
3360
    redstone.setOutput(i, 0)
3361
  end
3362
end
3363
3364
-- Clean up functions and variables
3365
GateEntry = nil
3366
HistoryEntry = nil
3367
editGateEntry = nil
3368
3369
-- Clean up threads
3370
for k,v in pairs(ChildThread) do
3371
  if (wasTerminated or not HadNoError) and v:status() == "dead" then
3372
    print(k..": dead already")
3373
  else
3374
    v:kill()
3375
    if wasTerminated or not HadNoError then print(k..": "..v:status()) end -- For Debug
3376
  end
3377
end
3378
event.cancel(ConfigPage.timer)
3379
3380
-- Clean up event listeners
3381
for k,v in pairs(EventListeners) do
3382
  if wasTerminated or not HadNoError then print("Canceling Event Listener: "..k) end -- For Debug
3383
  event.cancel(v)
3384
end
3385
if wasTerminated or not HadNoError then
3386
  print("Dialer Program Terminated")
3387
else
3388
  print("Dialer Program Closed")
3389
end
3390
3391
-- Close Modem port if it was open
3392
if HasModem and ModemIDCPort ~= nil then modem.close(ModemIDCPort) end
3393
3394
-- If error happen report the error
3395
if ErrorMessage ~= nil then io.stderr:write(tostring(ErrorMessage)) end
3396
3397
-- If touch screen was on, turn it off
3398
screen.setTouchModeInverted(false)
3399
3400
-- If cursor blink was off, turn it on
3401
if not term.getCursorBlink() then term.setCursorBlink(true) end
3402
3403
-- Set global flag indicating AGS completed closing procedures
3404
_G.agsProperlyClosed = true
3405
3406
-- End of Closing Procedures -------------------------------------------------------
3407
3408
3409