Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Built using Titanium Packager (Harry Felton - hbomb79)
- ]]
- local exportDirectory = select( 1, ... ) or ""
- local classSource = {
- [ "MAuthentication.ti" ] = "class \"MAuthentication\" abstract() {\
- static = {\
- PERMITTED_DRIVES = { [\"drive_1\"] = true, [\"drive_0\"] = true },\
- PERMITTED_KEYS = { [\"harry\"] = true, [\"rugby\"] = true },\
- DISK_TIMEOUT = 5,\
- BLINK_SIDE = \"top\",\
- LAUNCH_CODE_TIMEOUT = 15,\
- ALERT_SIDE = \"right\",\
- LAUNCH_CODE = \"test\"\
- };\
- \
- lastKey = false;\
- }\
- \
- function MAuthentication:MAuthentication()\
- self:on(\"disk\", function( _, event )\
- if MAuthentication.PERMITTED_DRIVES[ event.data[ 2 ] ] then\
- local diskMount = disk.getMountPath( event.data[ 2 ] )\
- if not fs.exists( fs.combine( diskMount, \".key.cfg\" ) ) then\
- self.lastKey = false\
- else\
- local h = fs.open( fs.combine( diskMount, \".key.cfg\" ), \"r\" )\
- local c = h.readAll()\
- h.close()\
- \
- if not MAuthentication.PERMITTED_KEYS[ c ] then\
- self.lastKey = false\
- elseif self.lastKey then\
- if not self.lastKey[ 3 ][ c ] and os.clock() - self.lastKey[ 1 ] < MAuthentication.DISK_TIMEOUT and event.data[ 2 ] ~= self.lastKey[ 2 ] then\
- self:prime()\
- end\
- \
- self.lastKey = false\
- else\
- self.lastKey = { os.clock(), event.data[ 2 ], { [ c ] = true } }\
- end\
- end\
- \
- disk.eject( event.data[ 2 ] )\
- end\
- end)\
- end\
- \
- function MAuthentication:beginNotificationBlink()\
- local t = false\
- self:schedule( function()\
- t = not t\
- redstone.setOutput( MAuthentication.BLINK_SIDE, t )\
- end, 0.2, true, \"notif_blink\" )\
- \
- self:schedule( function()\
- self:stopNotificationBlink()\
- self:unprime()\
- end, MAuthentication.LAUNCH_CODE_TIMEOUT, false, \"notif_cancel\" )\
- end\
- \
- function MAuthentication:stopNotificationBlink()\
- self:unschedule( \"notif_blink\" )\
- redstone.setOutput( MAuthentication.BLINK_SIDE, false )\
- \
- self:unschedule \"alert_blink\"\
- redstone.setOutput( MAuthentication.ALERT_SIDE, false )\
- end\
- \
- function MAuthentication:unprime( noSwitch )\
- if not noSwitch then self:error(\"Launch Aborted\", \"Launch key was not entered quickly enough. The launch has been aborted to help protect the facility\") end\
- \
- self:stopNotificationBlink()\
- self:query \"Input#launch_code\":set {\
- value = \"\",\
- position = 0\
- }\
- \
- self.primed = false\
- end\
- \
- function MAuthentication:prime()\
- self:beginNotificationBlink()\
- self.cache.pages:selectPage \"primed\"\
- \
- self.primed = true\
- end\
- \
- function MAuthentication:commenceLaunchSequence()\
- if not self.primed then return end\
- \
- self.cache.pages:selectPage \"pinging\"\
- self:unschedule \"notif_cancel\"\
- \
- self:pingMissiles()\
- self:on(\"ping_complete\", function( _, success )\
- self:off( \"ping_complete\", \"launch_ping_check\" )\
- if not success then\
- self:abortLaunch( true )\
- self:error(\"Launch Aborted\", \"Silos not ready for launch, or offline. Check overhead display before attempting to commence launch.\")\
- else\
- self:syncPosition()\
- self:on(\"sync_complete\", function( _, success )\
- if success then\
- self.cache.pages:selectPage \"launch\"\
- \
- local t = false\
- self:schedule( function()\
- t = not t\
- redstone.setOutput( MAuthentication.ALERT_SIDE, t )\
- end, 0.4, true, \"alert_blink\" )\
- \
- local countdown = self:query \"Label#countdown_T\"\
- local timeRemaining = MissileController.LAUNCH_DELAY\
- \
- countdown:set( \"text\", \"T-\" .. timeRemaining .. \" seconds to launch\" )\
- self:schedule( function()\
- timeRemaining = timeRemaining - 1\
- countdown:set( \"text\", \"T-\" .. timeRemaining .. \" seconds to launch\" )\
- countdown:setClass(\"RED\", not countdown:hasClass \"RED\" )\
- \
- if timeRemaining == 0 then\
- self:launch()\
- self:unschedule \"launch_countdown\"\
- end\
- end, 1, true, \"launch_countdown\" )\
- else\
- self:abortLaunch( true )\
- end\
- end )\
- end\
- end, \"launch_ping_check\")\
- end\
- \
- function MAuthentication:abortLaunch( noMan )\
- self:unprime( true )\
- self:stopNotificationBlink()\
- \
- self:unschedule \"launch_countdown\"\
- \
- if not noMan then\
- self:error(\"Launch Aborted\", \"Launch was manually aborted\")\
- end\
- end\
- ",
- [ "MissileController.ti" ] = "local function populateKeyPair( list )\
- local new = {}\
- for i = 1, #list do\
- new[ list[ i ] ] = false\
- end\
- \
- return new\
- end\
- \
- --[[\
- WIP\
- ]]\
- \
- class \"MissileController\" extends \"Application\" mixin \"MAuthentication\" {\
- static = {\
- MISSILE_INFO_COMPUTERS = { 11, 12, 13, 14, 15, 16, 23, 24, 19, 20, 21, 22 };\
- LAUNCH_DELAY = 60;\
- LAUNCH_STAGGER_DELAY = 6;\
- \
- LAUNCH_REDSTONE_SIDE = \"bottom\";\
- \
- REDNET_PROTOCOL = \"RUGBY_MISSILE\";\
- PING_TIMER = 30;\
- \
- MISSILE_REDSTONE = { colours.white, colours.orange, colours.magenta, colours.lightBlue, colours.yellow, colours.lime, colours.pink, colours.grey, colours.lightGrey, colours.cyan, colours.purple, colours.blue };\
- };\
- \
- backgroundColour = 128;\
- \
- cache = {};\
- ping = {\
- unreachable = false;\
- pending = false;\
- reachable = false;\
- launchable = false;\
- untilNext = false;\
- }\
- }\
- \
- --[[\
- @constructor\
- @desc WIP\
- ]]\
- function MissileController:__init__( ... )\
- self:super( ... )\
- \
- self:importFromTML \"missile/ui/master.tml\"\
- self:importTheme( \"master\", \"missile/ui/master.theme\" )\
- end\
- \
- --[[\
- @instance\
- @desc Cache important nodes for use later, avoids using 'query' too often\
- ]]\
- function MissileController:cacheNodes()\
- self.cache = {\
- monitor = self:query \"Container#monitor\".result[ 1 ],\
- pages = self:query \"PageContainer#master\".result[ 1 ],\
- pingNotif = self:query \"Label#ping_count\",\
- err = self:query \"Page#error\".result[ 1 ]\
- }\
- \
- self.cache.pages:selectPage \"home\"\
- \
- self:loadPosition()\
- end\
- \
- --[[\
- @instance\
- @desc WIP\
- ]]\
- function MissileController:queuePing()\
- local c = MissileController.PING_TIMER\
- self:schedule( function()\
- c = c - 1\
- self.cache.pingNotif:set( \"text\", c..\"s\" )\
- \
- if c == 0 then\
- self:unschedule \"ping_repeat\"\
- self:pingMissiles()\
- end\
- end, 1, true, \"ping_repeat\" )\
- end\
- \
- --[[\
- @instance\
- @desc Pings the missile sub-computers, returning a table of responsive controllers and a boolean representing whether all are online (launch ready)\
- @return <boolean - allOnline>, <table - responsiveMissiles>\
- ]]\
- function MissileController:pingMissiles()\
- -- Send a ping to all computers and wait for a response from the computers\
- local missiles, monitor = MissileController.MISSILE_INFO_COMPUTERS, self.cache.monitor\
- \
- -- Reset the ping result when we start pinging clients\
- self.ping = { pending = populateKeyPair( missiles ), unreachable = 0, reachable = 0, launchable = 0 }\
- self:checkPings()\
- for i = 1, #missiles do\
- local missileLabel = monitor:query( ( \"Label#%s_missile_status\" ):format( missiles[ i ] ) ).result[ 1 ]\
- \
- -- Ping the client\
- rednet.send( missiles[ i ], \"PING\", MissileController.REDNET_PROTOCOL )\
- missileLabel.text = \"PINGING\"\
- missileLabel.classes = {}\
- missileLabel:filterThemes()\
- \
- self:schedule( function()\
- -- Missile ping timed out\
- missileLabel:set {\
- text = \"Offline\",\
- classes = { [\"error\"] = true }\
- }\
- \
- missileLabel:filterThemes()\
- \
- self.ping.pending[ missiles[ i ] ] = nil\
- self.ping.unreachable = self.ping.unreachable + 1\
- \
- self:checkPings()\
- end, 1, false, ( \"MISSILE_%s_PING_TIMEOUT\" ):format( missiles[ i ] ) )\
- end\
- end\
- \
- --[[\
- @instance\
- @desc WIP\
- ]]\
- function MissileController:checkPings()\
- -- Update the status labels\
- local status = self:query \"Label#status\"\
- status:removeClass \"pending\"\
- status:removeClass \"error\"\
- status:removeClass \"OK\"\
- \
- self.ready = false\
- if not next( self.ping.pending ) then\
- -- Ping is complete, however clients might be unreachable\
- if self.ping.unreachable > 0 then\
- -- Ping is complete. No silos online\
- status:set( \"text\", \"Missile Silos Not Online\" )\
- status:addClass \"error\"\
- \
- self:executeCallbacks( \"ping_complete\", false )\
- elseif self.ping.reachable > 0 then\
- status:set( \"text\", \"Missile Silos Not Ready For Launch\" )\
- status:addClass \"error\"\
- \
- self:executeCallbacks( \"ping_complete\", false )\
- elseif self.ping.launchable == #MissileController.MISSILE_INFO_COMPUTERS then\
- -- Ping is complete. All silos accessible\
- status:set( \"text\", \"Ready for Launch\" )\
- status:addClass \"OK\"\
- \
- self:executeCallbacks( \"ping_complete\", true )\
- \
- self.ready = true\
- end\
- \
- self:queuePing()\
- else\
- -- Still pinging the clients\
- status:set( \"text\", \"Syncing Missile Silos\" )\
- status:addClass \"pending\"\
- \
- self.cache.pingNotif:set( \"text\", \"PINGING\" )\
- end\
- end\
- \
- function MissileController:error( title, body )\
- local err = self.cache.err\
- err:query \"Label#title\":set(\"text\", title or \"\")\
- err:query \"TextContainer#body\":set(\"text\", body or \"\")\
- \
- self.cache.pages:selectPage \"error\"\
- end\
- \
- function MissileController:syncPosition()\
- local d = Thread( function()\
- local f = fs.open(\".location.cfg\", \"r\")\
- local pos = f.readAll()\
- f.close()\
- \
- local missiles = MissileController.MISSILE_INFO_COMPUTERS\
- for i = 1, #missiles do\
- rednet.send( missiles[ i ], \"UPDATE_POSITION:PAYLOAD\" .. pos, MissileController.REDNET_PROTOCOL )\
- \
- local t, crash = os.startTimer( 1 )\
- while true do\
- local e = { coroutine.yield() }\
- if e[ 1 ] == \"rednet_message\" and e[ 2 ] == missiles[ i ] and e[ 3 ] == \"SUCCESS\" and e[ 4 ] == MissileController.REDNET_PROTOCOL then\
- os.cancelTimer( t )\
- break\
- elseif e[ 1 ] == \"timer\" and e[ 2 ] == t then\
- self:executeCallbacks( \"sync_complete\", false )\
- self:error(\"Failed to sync silo coordinates\", \"Silo #\" .. i .. \" didn't respond when trying to update the missile location tracking systems -- unsafe to launch, aborting\")\
- return false\
- end\
- end\
- end\
- \
- self:executeCallbacks( \"sync_complete\", true )\
- end )\
- \
- self:addThread( d )\
- return d\
- end\
- \
- function MissileController:updatePosition()\
- local f = fs.open(\".location.cfg\", \"w\")\
- f.write( textutils.serialise( { X = self:query \"Input#X_input\".result[ 1 ].value, Z = self:query \"Input#Z_input\".result[ 1 ].value, Y = self:query \"Input#det_input\".result[ 1 ].value } ) )\
- f.close()\
- \
- self:syncPosition()\
- end\
- \
- function MissileController:loadPosition()\
- if not fs.exists \".location.cfg\" then return end\
- \
- local h = fs.open(\".location.cfg\", \"r\")\
- local positions = textutils.unserialise( h.readAll() )\
- h.close()\
- \
- local toSet = { X = \"X_input\", Z = \"Z_input\", Y = \"det_input\"}\
- for prop, query in pairs( toSet ) do\
- local n = self:query( \"Input#\" .. query ).result[ 1 ]\
- n.value = positions[ prop ]\
- n.position = #n.value\
- end\
- end\
- \
- function MissileController:launch()\
- self.cache.pages:selectPage \"launching\"\
- local missiles = MissileController.MISSILE_REDSTONE\
- local launch = self:query \"Label#silo_launch\"\
- \
- for i = 1, #missiles do\
- self:schedule(function()\
- redstone.setBundledOutput( MissileController.LAUNCH_REDSTONE_SIDE, missiles[ i ] )\
- launch:set( \"text\", \"Launching Silo #\" .. i )\
- \
- if i == #missiles then\
- self:error(\"Launch Success\", \"Missiles have been successfully launched to target location\")\
- \
- self:stopNotificationBlink()\
- self:schedule( function() redstone.setBundledOutput( MissileController.LAUNCH_REDSTONE_SIDE, 0 ) end, 1 )\
- end\
- end, ( i - 1 ) * MissileController.LAUNCH_STAGGER_DELAY, false, \"MISSILE_\" .. i )\
- end\
- end\
- \
- --[[\
- @instance\
- @desc WIP\
- ]]\
- function MissileController:start( ... )\
- self:cacheNodes()\
- self:pingMissiles()\
- self.super:start( ... )\
- end\
- \
- configureConstructor {\
- argumentTypes = {\
- ready = \"boolean\"\
- }\
- }",
- }
- local vfsAssets = {
- [ "missile/startup" ] = "--[[\
- Missile Control Computer\
- ========================\
- \
- Controls:\
- ---------\
- - Co-ordinates\
- - Detonation distance\
- - Countdown\
- - Launch\
- - Display\
- \
- Copyright (c) Harry Felton 2017\
- ]]\
- \
- local function isInfoComputer( target )\
- for i = 1, #MissileController.MISSILE_INFO_COMPUTERS do\
- if MissileController.MISSILE_INFO_COMPUTERS[ i ] == target then\
- return true\
- end\
- end\
- \
- return false\
- end\
- \
- local m, f = peripheral.getNames()\
- for i = 1, #m do\
- if peripheral.getType( m[ i ] ) == \"modem\" then\
- rednet.open( m[ i ] )\
- \
- f = true\
- end\
- end\
- \
- if not f then error \"no modem\" end\
- \
- local missile = MissileController():set( \"terminatable\", true )\
- local rednet = Thread( function()\
- while true do\
- local message = { coroutine.yield \"rednet_message\" }\
- table.remove( message, 1 )\
- if message[ 3 ] == MissileController.REDNET_PROTOCOL then\
- if isInfoComputer( message[ 1 ] ) then\
- if message[ 2 ]:match \"CLIENT_PING:PAYLOAD\" then\
- local missileLabel = missile.cache.monitor:query( ( \"Label#%s_missile_status\" ):format( message[ 1 ] ) ).result[ 1 ]\
- \
- if message[ 2 ]:match \"CLIENT_PING:PAYLOAD(.*)\" == \"true\" then\
- missileLabel:set( \"text\", \"Launchable\" ).classes = { [\"OK\"] = true }\
- missile.ping.launchable = missile.ping.launchable + 1\
- else\
- missileLabel:set( \"text\", \"Not Ready\" ).classes = { [\"pending\"] = true }\
- missile.ping.reachable = missile.ping.reachable + 1\
- end\
- \
- missileLabel:filterThemes()\
- missile.ping.pending[ message[ 1 ] ] = nil\
- missile:unschedule( ( \"MISSILE_%s_PING_TIMEOUT\" ):format( message[ 1 ] ) )\
- \
- missile:checkPings()\
- elseif message[ 2 ] == \"MASTER_PING\" then\
- rednet.send( message[ 1 ], \"PING_PONG\", MissileController.REDNET_PROTOCOL )\
- end\
- end\
- end\
- end\
- end )\
- \
- missile:query \"#coord_move\":on(\"trigger\", function()\
- missile:loadPosition()\
- missile.cache.pages:selectPage \"coord\"\
- end)\
- \
- missile:query \"#coord_cancel\":on(\"trigger\", function()\
- missile.cache.pages:selectPage \"home\"\
- end)\
- \
- missile:query \"#coord_confirm\":on(\"trigger\", function( self )\
- missile:on(\"sync_complete\", function( this, success )\
- self.enabled = true\
- if success then missile.cache.pages:selectPage \"home\" end\
- end)\
- \
- missile:updatePosition()\
- self.enabled = false\
- end)\
- \
- missile:query \"#home_return\":on(\"trigger\", function()\
- missile.cache.pages:selectPage \"home\"\
- end)\
- \
- missile:query \"#launch_return\":on(\"trigger\", function()\
- missile:unprime( true )\
- missile.cache.pages:selectPage \"home\"\
- end)\
- \
- missile:query \"#launch_code\":on(\"trigger\", function( self )\
- if missile.primed and self.value == MAuthentication.LAUNCH_CODE then\
- self:set { value = \"\", position = 0 }\
- missile:commenceLaunchSequence()\
- else\
- missile:unprime( true )\
- missile:error(\"Incorrect Launch Key\", \"Launch key provided was incorrect. To help protect the facility, the launch has been aborted\")\
- end\
- end)\
- \
- missile:query \"#ABORT\":on(\"trigger\", function( self )\
- missile:abortLaunch()\
- end)\
- \
- missile:addThread( rednet )\
- missile:addProjector( Projector( \"main\", \"monitor\", \"monitor_0\" ) )\
- \
- missile:start()",
- [ "missile/ui/master.theme" ] = "<Any>\
- <!-- <colour>256</colour> -->\
- </Any>\
- \
- <Any class=\"header\">\
- <colour>orange</colour>\
- </Any>\
- \
- <Any class=\"centre\">\
- <X dynamic>( parent.width / 2 ) - self.width / 2</X>\
- </Any>\
- \
- <Button>\
- <horizontalAlign>centre</horizontalAlign>\
- <width dynamic>#self.text + 2</width>\
- <backgroundColour>cyan</backgroundColour>\
- <colour important>white</colour>\
- </Button>\
- \
- <Label class=\"missile_title\">\
- <colour important>orange</colour>\
- </Label>\
- \
- <Label class=\"error\">\
- <colour important>red</colour>\
- </Label>\
- \
- <Label class=\"OK\">\
- <colour important>cyan</colour>\
- </Label>\
- \
- <Label class=\"pending\">\
- <colour important>orange</colour>\
- </Label>\
- \
- <Label id=\"countdown_T\" class=\"RED\">\
- <colour important>white</colour>\
- <backgroundColour important>red</backgroundColour>\
- </Label>",
- [ "missile/ui/master.tml" ] = "<Container id=\"monitor\" projector=\"main\" width=\"50\" height=\"19\" backgroundColour=\"128\" colour=\"orange\">\
- <Label class=\"header centre\" colour=\"orange\" Y=\"2\">Missile Control Status Panel</Label>\
- <Label class=\"centre\" Y=\"4\" colour=\"256\" id=\"status\">Starting</Label>\
- <Label colour=\"256\" text=\"...\" X=\"$parent.width - self.width\" id=\"ping_count\"/>\
- \
- <Container width=\"$parent.width\" height=\"$parent.height - 7\" Y=7>\
- <Label X=\"2\" Y=\"1\" id=\"11_missile_title\" class=\"missile_title\">Silo 1</Label>\
- <Label id=\"11_missile_status\" Y=\"${#11_missile_title}.Y\" X=\"${#11_missile_title}.X + {#11_missile_title}.width + 1\">Pinging</Label>\
- \
- <Label X=\"2\" Y=\"3\" id=\"12_missile_title\" class=\"missile_title\">Silo 2</Label>\
- <Label id=\"12_missile_status\" Y=\"${#12_missile_title}.Y\" X=\"${#12_missile_title}.X + {#12_missile_title}.width + 1\">Pinging</Label>\
- \
- <Label X=\"2\" Y=\"5\" id=\"13_missile_title\" class=\"missile_title\">Silo 3</Label>\
- <Label id=\"13_missile_status\" Y=\"${#13_missile_title}.Y\" X=\"${#13_missile_title}.X + {#13_missile_title}.width + 1\">Pinging</Label>\
- \
- <Label X=\"2\" Y=\"7\" id=\"14_missile_title\" class=\"missile_title\">Silo 4</Label>\
- <Label id=\"14_missile_status\" Y=\"${#14_missile_title}.Y\" X=\"${#14_missile_title}.X + {#14_missile_title}.width + 1\">Pinging</Label>\
- \
- <Label X=\"2\" Y=\"9\" id=\"15_missile_title\" class=\"missile_title\">Silo 5</Label>\
- <Label id=\"15_missile_status\" Y=\"${#15_missile_title}.Y\" X=\"${#15_missile_title}.X + {#15_missile_title}.width + 1\">Pinging</Label>\
- \
- <Label X=\"2\" Y=\"11\" id=\"16_missile_title\" class=\"missile_title\">Silo 6</Label>\
- <Label id=\"16_missile_status\" Y=\"${#16_missile_title}.Y\" X=\"${#16_missile_title}.X + {#16_missile_title}.width + 1\">Pinging</Label>\
- \
- <Label X=\"${#23_missile_status}.X - self.width - 1\" Y=\"1\" id=\"23_missile_title\" class=\"missile_title\">Silo 7</Label>\
- <Label id=\"23_missile_status\" X=\"$parent.width - self.width - 2\" Y=\"1\">Pinging</Label>\
- \
- <Label X=\"${#24_missile_status}.X - self.width - 1\" Y=\"3\" id=\"24_missile_title\" class=\"missile_title\">Silo 8</Label>\
- <Label id=\"24_missile_status\" X=\"$parent.width - self.width - 2\" Y=\"3\">Pinging</Label>\
- \
- <Label X=\"${#19_missile_status}.X - self.width - 1\" Y=\"5\" id=\"19_missile_title\" class=\"missile_title\">Silo 9</Label>\
- <Label id=\"19_missile_status\" X=\"$parent.width - self.width - 2\" Y=\"5\">Pinging</Label>\
- \
- <Label X=\"${#20_missile_status}.X - self.width - 1\" Y=\"7\" id=\"20_missile_title\" class=\"missile_title\">Silo 10</Label>\
- <Label id=\"20_missile_status\" X=\"$parent.width - self.width - 2\" Y=\"7\">Pinging</Label>\
- \
- <Label X=\"${#21_missile_status}.X - self.width - 1\" Y=\"9\" id=\"21_missile_title\" class=\"missile_title\">Silo 11</Label>\
- <Label id=\"21_missile_status\" X=\"$parent.width - self.width - 2\" Y=\"9\">Pinging</Label>\
- \
- <Label X=\"${#22_missile_status}.X - self.width - 1\" Y=\"11\" id=\"22_missile_title\" class=\"missile_title\">Silo 12</Label>\
- <Label id=\"22_missile_status\" X=\"$parent.width - self.width - 2\" Y=\"11\">Pinging</Label>\
- </Container>\
- </Container>\
- \
- <Container height=\"3\" width=\"$application.width\" backgroundColour=\"orange\">\
- <Label colour=\"128\">Missile Control Station</Label>\
- </Container>\
- \
- <PageContainer width=\"$application.width\" height=\"$application.height - 2\" id=\"master\" Y=3>\
- <Page id=\"home\">\
- <Label class=\"centre\" Y=4 id=\"status\">...</Label>\
- \
- <TextContainer X=\"6\" width=\"$parent.width - 10\" height=\"$parent.height - 7\" Y=\"7\" colour=\"256\" horizontalAlign=\"centre\" text=\"Use two-person authentication to start launch sequence whenever ready.\\nSilo verification and location sync will occur before any launch occurs.\"/>\
- \
- <Button class=\"centre\" Y=\"$parent.height - 1\" id=\"coord_move\">Set Co-Ords</Button>\
- </Page>\
- <Page id=\"coord\">\
- <Label class=\"centre\" Y=4 colour=\"1\">Set Co-ordinates</Label>\
- \
- <Label Y=6 X=2 id=\"X\" colour=\"lightGrey\">X</Label>\
- <Input Y=\"${Label#X}.Y\" X=\"${Label#X}.X + {Label#X}.width + 2\" id=\"X_input\" width=\"6\" limit=\"6\" backgroundColour=\"lightGrey\"/>\
- \
- <Label Y=8 X=2 id=\"Z\" colour=\"lightGrey\">Z</Label>\
- <Input Y=\"${Label#Z}.Y\" X=\"${Label#Z}.X + {Label#Z}.width + 2\" id=\"Z_input\" width=\"6\" limit=\"6\" backgroundColour=\"lightGrey\"/>\
- \
- <Label Y=10 X=2 id=\"det\" colour=\"lightGrey\">Detonation Height</Label>\
- <Input Y=\"${Label#det}.Y\" X=\"${Label#det}.X + {Label#det}.width + 2\" width=\"6\" limit=\"6\" id=\"det_input\" backgroundColour=\"lightGrey\"/>\
- \
- <Button X=2 backgroundColour=\"red\" id=\"coord_cancel\" Y=\"$parent.height - 1\">Cancel</Button>\
- <Button X=\"${#coord_cancel}.X + {#coord_cancel}.width + 2\" id=\"coord_confirm\" Y=\"$parent.height - 1\">Set</Button>\
- </Page>\
- <Page id=\"primed\">\
- <Label class=\"centre header\" id=\"title\" Y=\"5\" color=\"1\">Missile Silos Primed</Label>\
- <TextContainer id=\"body\" X=\"6\" width=\"$parent.width - 10\" height=\"3\" Y=\"7\" colour=\"256\" horizontalAlign=\"centre\">All twelve silos are primed for launch. Enter the launch code to initiate launch sequence</TextContainer>\
- \
- <Input backgroundColour=\"lightGrey\" width=\"20\" limit=\"64\" Y=\"11\" id=\"launch_code\" class=\"centre\" mask=\"*\"/>\
- <Button class=\"centre\" id=\"launch_return\" Y=\"$parent.height - 1\" backgroundColour=\"red\">Cancel</Button>\
- </Page>\
- <Page id=\"launch\">\
- <Label class=\"centre header\" Y=\"5\" color=\"1\">LAUNCH COMMENCED</Label>\
- <TextContainer id=\"body\" text=\"Commencing launch. Clear the area immediately!\\n\\nCancel the launch IMMEDIATELY if a fault is detected\" Y=\"7\" X=\"6\" width=\"$parent.width - 10\" height=\"$parent.height - 10\" colour=\"256\" horizontalAlign=\"centre\"/>\
- <Label text=\"T-60 seconds to launch\" Y=\"$parent.height - 1\" colour=\"red\" class=\"centre\" id=\"countdown_T\"/>\
- <Button class=\"centre\" id=\"ABORT\" Y=\"$parent.height - 3\" backgroundColour=\"red\">ABORT LAUNCH</Button>\
- </Page>\
- <Page id=\"launching\">\
- <Label class=\"centre header\" Y=\"5\" color=\"1\">LAUNCHING</Label>\
- <TextContainer id=\"body\" text=\"LAUNCH PHASE REACHED -- UN-ABORTABLE.\\n\\nEVACUATE ALL PERSONNEL, FATAL CONDITIONS TO FOLLOW\" Y=\"7\" X=\"6\" width=\"$parent.width - 10\" height=\"$parent.height - 10\" colour=\"256\" horizontalAlign=\"centre\"/>\
- <Label text=\"\" Y=\"$parent.height - 1\" colour=\"red\" class=\"centre\" id=\"silo_launch\"/>\
- </Page>\
- <Page id=\"pinging\">\
- <Label class=\"centre header\" Y=\"5\" color=\"1\">Validating Silos</Label>\
- <TextContainer id=\"body\" text=\"Checking Silo launch state, and syncing locational tracking information before commencing launch countdown\" Y=\"7\" X=\"6\" width=\"$parent.width - 10\" height=\"$parent.height - 10\" colour=\"256\" horizontalAlign=\"centre\"/>\
- </Page>\
- <Page id=\"error\">\
- <Label class=\"centre header\" id=\"title\" Y=\"5\" color=\"1\">...</Label>\
- <TextContainer id=\"body\" X=\"6\" width=\"$parent.width - 10\" height=\"$parent.height - 7\" Y=\"7\" colour=\"256\" horizontalAlign=\"centre\">...</TextContainer>\
- \
- <Button class=\"centre\" id=\"home_return\" Y=\"$parent.height - 1\">Return</Button>\
- </Page>\
- </PageContainer>",
- }local env = type( getfenv ) == "function" and getfenv() or _ENV or _G
- if env.TI_VFS_RAW then env = env.TI_VFS_RAW end
- local fallbackFS = env.fs
- local RAW = setmetatable({
- fs = setmetatable( {}, { __index = _G["fs"] }),
- os = setmetatable( {}, { __index = _G["os"] } )
- }, { __index = env })
- local VFS = RAW["fs"]
- local VFS_ENV = setmetatable({},{__index = function( _, key )
- if key == "TI_VFS_RAW" then return RAW end
- return RAW[ key ]
- end})
- VFS_ENV._G = env
- VFS_ENV._ENV = env
- local VFS_DIRS = {
- missile = true,
- [ "missile/ui" ] = true,
- }
- local matches = { ["^"] = "%^", ["$"] = "%$", ["("] = "%(", [")"] = "%)", ["%"] = "%%", ["*"] = "[^/]*", ["."] = "%.", ["["] = "%[", ["]"] = "%]", ["+"] = "%+", ["-"] = "%-" }
- function VFS_ENV.load(src, name, mode, env)
- return load( src, name or '(load)', mode, env or VFS_ENV )
- end
- function VFS_ENV.loadstring(src, name)
- return VFS_ENV.load( src, name, 't', VFS_ENV )
- end
- function VFS_ENV.loadfile(file, env)
- local _ENV = VFS_ENV
- local h = fs.open( file, "r" )
- if h then
- local fn, e = load(h.readAll(), fs.getName(file), 't', env or VFS_ENV)
- h.close()
- return fn, e
- end
- return nil, 'File not found'
- end
- if type( setfenv ) == "function" then setfenv( VFS_ENV.loadfile, VFS_ENV ) end
- function VFS_ENV.os.run( _tEnv, _sPath, ... )
- local _ENV = VFS_ENV
- local tArgs, tEnv = { ... }, _tEnv
- setmetatable( tEnv, { __index = VFS_ENV } )
- local fnFile, err = loadfile( _sPath, tEnv )
- if fnFile then
- local ok, err = pcall( function()
- fnFile( table.unpack( tArgs ) )
- end )
- if not ok then
- if err and err ~= "" then
- printError( err )
- end
- return false
- end
- return true
- end
- if err and err ~= "" then
- printError( err )
- end
- return false
- end
- local tAPIsLoading = {}
- function VFS_ENV.os.loadAPI( _sPath )
- local _ENV, sName = VFS_ENV, fs.getName( _sPath )
- if tAPIsLoading[sName] == true then
- printError( "API "..sName.." is already being loaded" )
- return false
- end
- tAPIsLoading[sName] = true
- local tEnv = setmetatable( {}, { __index = VFS_ENV } )
- local fnAPI, err = loadfile( _sPath, tEnv )
- if fnAPI then
- local ok, err = pcall( fnAPI )
- if not ok then
- printError( err )
- tAPIsLoading[sName] = nil
- return false
- end
- else
- printError( err )
- tAPIsLoading[sName] = nil
- return false
- end
- local tAPI = {}
- for k,v in pairs( tEnv ) do if k ~= "_ENV" then tAPI[k] = v end end
- VFS_ENV[sName], tAPIsLoading[sName] = tAPI, nil
- return true
- end
- VFS_ENV.os.loadAPI "/rom/apis/io"
- function VFS_ENV.dofile(file)
- local _ENV = VFS_ENV
- local fn, e = loadfile(file, VFS_ENV)
- if fn then return fn()
- else error(e, 2) end
- end
- if type( setfenv ) == "function" then setfenv( VFS_ENV.dofile, VFS_ENV ) end
- function VFS.open( path, mode )
- path = fs.combine( "", path )
- if vfsAssets[ path ] then
- if mode == "w" or mode == "wb" or mode == "a" or mode == "ab" then
- return error("Cannot open file in mode '"..tostring( mode ).."'. File is inside of Titanium VFS and is read only")
- end
- local content, handle = vfsAssets[ path ], {}
- if mode == "rb" then
- handle.read = function()
- if #content == 0 then return end
- local b = content:sub( 1, 1 ):byte()
- content = content:sub( 2 )
- return b
- end
- end
- handle.readLine = function()
- if #content == 0 then return end
- local line, rest = content:match "^([^\n\r]*)(.*)$"
- content = rest and rest:gsub("^[\n\r]", "") or ""
- return line or content
- end
- handle.readAll = function()
- if #content == 0 then return end
- local c = content
- content = ""
- return c
- end
- handle.close = function() content = "" end
- return handle
- else return fallbackFS.open( fs.combine( exportDirectory, path ), mode ) end
- end
- function VFS.isReadOnly( path )
- path = fs.combine( "", path )
- if vfsAssets[ path ] then return true end
- return fallbackFS.isReadOnly( fs.combine( exportDirectory, path ) )
- end
- function VFS.getSize( path )
- return vfsAssets[ path ] and #vfsAssets[ path ] or fallbackFS.getSize( path )
- end
- function VFS.list( target )
- target = fs.combine( "", target )
- local list = fallbackFS.isDir( target ) and fallbackFS.list( target ) or {}
- local function addResult( res )
- for i = 1, #list do if list[ i ] == res then return end end
- list[ #list + 1 ] = res
- end
- if VFS_DIRS[ target ] then
- for path in pairs( vfsAssets ) do
- if path:match( ("^%s/"):format( target ) ) then
- addResult( path:match( ("^%s/([^/]+)"):format( target ) ) )
- end
- end
- elseif target == "" then
- for path in pairs( vfsAssets ) do addResult( path:match "^([^/]+)" ) end
- end
- return list
- end
- function VFS.find( target )
- target = fs.combine( "", target )
- local list = fallbackFS.find( target ) or {}
- target = ("^(%s)(.*)$"):format( target:gsub( ".", matches ) )
- for path in pairs( vfsAssets ) do
- local res, tail = path:match( target )
- if res and ( tail == "" or tail:sub( 1, 1 ) == "/" ) then
- local isMatch
- for i = 1, #list do if list[ i ] == res then isMatch = true; break end end
- if not isMatch then list[ #list + 1 ] = res end
- end
- end
- return list
- end
- function VFS.isDir( path )
- path = fs.combine( "", path )
- return VFS_DIRS[ path ] or fallbackFS.isDir( fs.combine( exportDirectory, path ) )
- end
- function VFS.exists( path )
- path = fs.combine( "", path )
- if vfsAssets[ path ] or VFS_DIRS[ path ] then return true end
- return fallbackFS.exists( fs.combine( exportDirectory, path ) )
- end
- if not fs.exists( "/.tpm/bin/tpm" ) then
- local h = http.get "https://gitlab.com/hbomb79/Titanium-Package-Manager/raw/master/tpm"
- if not h then return error "Failed to download TPM" end
- local f = fs.open( "/.tpm/bin/tpm", "w" )
- f.write( h.readAll() )
- h.close()
- f.close()
- end
- local ok, err = loadfile "/.tpm/bin/tpm"
- if not ok then return error("Failed to load TPM '"..tostring( err ).."'") end
- ok( "fetch" )
- ok( "--disposable", "--depend", shell.getRunningProgram(), "install", "Titanium:latest" )
- local FAILURE = "Failed to execute Titanium package. Latest Titanium version cannot be found %s (/.tpm/cache)"
- if not fs.exists("/.tpm/cache") then
- return error( FAILURE:format "because TPM cache is missing" )
- end
- local cacheHandle = fs.open("/.tpm/cache", "r")
- local cache = textutils.unserialise( cacheHandle.readAll() )
- cacheHandle.close()
- if not cache then
- return error( FAILURE:format "because TPM cache is malformed" )
- elseif not cache.Titanium then
- return error( FAILURE:format "because TPM cache missing Titanium version information" )
- end
- if not VFS_ENV.Titanium then VFS_ENV.dofile( "/.tpm/packages/Titanium/"..cache.Titanium[1] ) end
- local ti = VFS_ENV.Titanium
- if not ti then
- return error "Failed to execute Titanium package. Titanium is not loaded. Please load Titanium before executing this package (or use a --titanium-init), or repackage this application using the --titanium flag."
- end
- local loaded = {}
- local function loadClass( name, source )
- if not source then return error( "Failed to load class '"..name.."'. No source found within class assets" )
- elseif loaded[ name ] then return end
- local className = name:gsub( "%..*", "" )
- if not ti.getClass( className ) then
- local output, err = ( VFS_ENV or _G ).loadstring( source, name )
- if not output or err then return error( "Failed to load Lua chunk. File '"..name.."' has a syntax error: "..tostring( err ), 0 ) end
- local ok, err = pcall( output )
- if not ok or err then return error( "Failed to execute Lua chunk. File '"..name.."' crashed: "..tostring( err ), 0 ) end
- local class = ti.getClass( className )
- if class then
- if not class:isCompiled() then class:compile() end
- loaded[ name ] = true
- else return error( "File '"..name.."' failed to create class '"..className.."'" ) end
- else
- print( "WARNING: Class " .. className .. " failed to load because a class with the same name already exists." )
- end
- end
- ti.setClassLoader(function( c )
- local name = classSource[ c .. ".lua" ] and c .. ".lua" or c .. ".ti"
- loadClass( name, classSource[ name ] )
- end)
- for name, source in pairs( classSource ) do
- loadClass( name, source )
- end
- local fn, err = VFS_ENV.loadfile "missile/startup"
- if fn then fn()
- else return error( "Failed to run file from bundle vfs: "..tostring( err ) ) end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement