Updated LUA scripts for CC and OC

- changed general color and controls styles
- fixed keyboard responsiveness
- added weapon controller's enum handler to common library
- added accelerator controller
- added autorefresh
- fixed common library duplication
- fixed confirmation input so 'enter' means 'yes'
- implemented LUA API changes
- improved inputs handling in weapon controller
- removed eXit command in favor of terminate shortcut (Ctrl-T / Ctrl-C)
- splitted ship controls into 3 different sections
- added more explicit help on home page, input controls, confirmation popup, etc.
- added workaround for CC internal Java crash while connected to an Enantiomorphic reactor
This commit is contained in:
LemADEC 2017-05-12 20:42:44 +02:00
parent 78e2d187e2
commit 99221df636
17 changed files with 6401 additions and 5647 deletions
build.gradle
src/main/resources/assets/warpdrive
lua.ComputerCraft
common
warpdriveAccelerator
warpdriveEnanReactorCore
warpdriveMainframe
warpdriveShipController
warpdriveWeaponController
lua.OpenComputers
common
warpdriveAccelerator
warpdriveEnanReactorCore
warpdriveShipController
warpdriveWeaponController

View file

@ -49,7 +49,7 @@ dependencies {
// or you may define them like so..
//compile "some.group:artifact:version:classifier"
//compile "some.group:artifact:version"
// real examples
//compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
//compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
@ -60,8 +60,7 @@ dependencies {
}
processResources
{
processResources {
// this will ensure that this task is redone when the versions change.
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
@ -69,7 +68,7 @@ processResources
// skip source assets
exclude '**/*.pdn'
exclude '**/*.psd'
// replace stuff in mcmod.info, nothing else
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
@ -77,14 +76,34 @@ processResources
// replace version and mcversion
expand 'version':project.version, 'mcversion':project.minecraft.version
}
// copy everything else, thats not the mcmod.info
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
}
}
//copies the commons folder to all instances
task copyOpenComputersCommons1(type: Copy) {
from 'src/main/resources/assets/warpdrive/lua.OpenComputers/common'
into('build/resources/main/assets/warpdrive/lua.OpenComputers/warpdriveShipController')
}
task copyOpenComputersCommons2(type: Copy) {
from 'src/main/resources/assets/warpdrive/lua.OpenComputers/common'
into('build/resources/main/assets/warpdrive/lua.OpenComputers/warpdriveEnanReactorCore')
}
task copyOpenComputersCommons3(type: Copy) {
from 'src/main/resources/assets/warpdrive/lua.OpenComputers/common'
into('build/resources/main/assets/warpdrive/lua.OpenComputers/warpdriveWeaponController')
}
task copyOpenComputersCommons4(type: Copy) {
from 'src/main/resources/assets/warpdrive/lua.OpenComputers/common'
into('build/resources/main/assets/warpdrive/lua.OpenComputers/warpdriveAcceleratorController')
}
jar {
dependsOn copyOpenComputersCommons1, copyOpenComputersCommons2, copyOpenComputersCommons3, copyOpenComputersCommons4
manifest {
attributes 'FMLAT': 'CoFH_at.cfg'
attributes 'FMLCorePlugin': 'cr0s.warpdrive.core.FMLLoadingPlugin',

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,406 @@
if warpdriveCommons then os.unloadAPI("warpdriveCommons") end
if not os.loadAPI("warpdrive/warpdriveCommons") then error("missing warpdriveCommons") end
local w = warpdriveCommons.w
----------- Accelerator support
local lhc_isEnabled = false
local lhc_controlPoints = {}
local lhc_parameters = {}
local accelerator = nil
function lhc_boot(isDetailed)
if accelerator == nil then
return
end
if isDetailed == nil then
isDetailed = true
end
if isDetailed then
w.write("Booting Accelerator controller")
w.writeLn("...")
w.sleep(0.1)
end
-- getting control points
lhc_controlPoints = {}
local count = accelerator.getControlPointsCount()
lhc_controlChannels = { }
countParameters = 0
if count ~= nil and count > 0 then
for i = 0, count - 1 do
local success, x, y, z, tier, type, isEnabled, controlChannel = accelerator.getControlPoint(i)
if success then
if isDetailed then
w.write(type .. " " .. tier .. " #" .. controlChannel .. " @ (" .. w.format_integer(x, 6) .. " " .. w.format_integer(y, 3) .. " " .. w.format_integer(z, 6) .. ") ")
if isEnabled then
w.writeLn("Enabled")
else
w.writeLn("Disabled")
end
end
lhc_controlPoints[i + 1] = { x, y, z, tier, type, isEnabled, controlChannel }
lhc_controlChannels[controlChannel] = "true"
countParameters = countParameters + 1
elseif isDetailed then
w.setColorWarning();
w.writeLn("Error " .. x)
w.setColorNormal();
w.sleep(0.5)
end
end
elseif isDetailed then
w.setColorWarning();
w.writeLn("No control point detected!")
w.sleep(0.5)
end
-- getting parameters
local controlChannels = { accelerator.getParametersControlChannels() }
if controlChannels ~= nil and #controlChannels > 0 then
for key, value in pairs(controlChannels) do lhc_controlChannels[value] = { } end
countParameters = countParameters + 1
end
lhc_parameters = {}
if isDetailed then w.sleep(0.1) end
if countParameters ~= 0 then
local index = 1
for controlChannel, _ in pairs(lhc_controlChannels) do
local success, controlChannelCheck, isEnabled, threshold, description = accelerator.parameter(controlChannel)
if success ~= nil and success then
if isDetailed then
w.write("#" .. w.format_integer(controlChannelCheck, 9) .. " ")
if isEnabled then
w.write("Enabled")
else
w.write("Disabled")
end
w.writeLn(" " .. w.format_integer(threshold * 100, 3) .. "% '" .. description .. "'")
end
lhc_parameters[index] = { controlChannel, isEnabled, threshold, description }
index = index + 1
elseif isDetailed then
w.setColorWarning();
if controlChannelCheck ~= nil then
w.writeLn("Error " .. controlChannelCheck)
else
w.writeLn("Error nil?")
end
w.sleep(0.5)
w.setColorNormal();
end
if controlChannel ~= controlChannelCheck and isDetailed then
w.setColorWarning();
w.writeLn("Error: requested " .. controlChannel .. ", received " .. controlChannelCheck)
w.sleep(0.5)
w.setColorNormal();
end
end
elseif isDetailed then
w.setColorWarning();
w.writeLn("No control channel detected!")
w.sleep(0.5)
end
end
function lhc_page_parameter()
w.page_begin("<==== Change accelerator parameter ====>")
local _, indexSelected = lhc_parameter_getIndexes()
local controlChannel, isEnabled, threshold, description = lhc_parameter_get(indexSelected)
w.writeLn("Control channel #" .. w.format_integer(controlChannel, 9) .. " applies to:")
for key, controlPoint in ipairs(lhc_controlPoints) do
local cp_x, cp_y, cp_z, cp_tier, cp_type, cp_isEnabled, cp_controlChannel = unpack(controlPoint)
if cp_controlChannel == controlChannel then
w.write(string.format("%s %s @%s %s %s ",
w.format_string(cp_type, 10),
w.format_string(cp_tier, 1),
w.format_integer(cp_x, 7), w.format_integer(cp_y, 3), w.format_integer(cp_z, 7) ))
if isEnabled then
w.writeLn("Enabled")
else
w.writeLn("Disabled")
end
end
end
w.writeLn("")
w.writeLn("Current description is '" .. description .. "'")
w.write("Enter a description: ")
description = w.input_readText(description)
w.writeLn("")
w.writeLn("Current theshold is " .. (threshold * 100) .. "%")
w.write("Enter parameter threshold: ")
local new_threshold = w.input_readNumber(threshold * 100) / 100
threshold = math.min(2.0, math.max(0.0, new_threshold))
lhc_parameters[indexSelected] = { controlChannel, isEnabled, threshold, description }
accelerator.parameter(controlChannel, isEnabled, threshold, description)
end
lhc_parameter_indexSelected = 1
lhc_parameter_indexFirstLine = 1
lhc_parameter_lines = 7
function lhc_parameter_getIndexes()
if lhc_parameters ~= nil then
if lhc_parameter_indexSelected > #lhc_parameters then
lhc_parameter_indexSelected = 1
elseif lhc_parameter_indexSelected < 1 then
lhc_parameter_indexSelected = #lhc_parameters
end
if lhc_parameter_indexFirstLine > lhc_parameter_indexSelected then
lhc_parameter_indexFirstLine = lhc_parameter_indexSelected
elseif lhc_parameter_indexFirstLine + lhc_parameter_lines < lhc_parameter_indexSelected then
lhc_parameter_indexFirstLine = lhc_parameter_indexSelected - lhc_parameter_lines
end
return lhc_parameter_indexFirstLine, lhc_parameter_indexSelected
else
return 1, 1
end
end
function lhc_parameter_get(index)
local parameter = lhc_parameters[index]
local controlChannel, isEnabled, threshold, description = -1, false, 0, "-"
if parameter == nil or #parameter ~= 4 then
lhc_boot(false)
w.status_showWarning("Invalid parameter at index " .. index)
else
controlChannel, isEnabled, threshold, description = unpack(parameter)
end
return controlChannel, isEnabled, threshold, description
end
function lhc_parameter_updateThreshold(offset)
if lhc_parameters ~= nil and offset ~= nil then
local _, indexSelected = lhc_parameter_getIndexes()
local controlChannel, isEnabled, threshold, description = lhc_parameter_get(indexSelected)
threshold = math.min(2.0, math.max(0.0, threshold + offset / 100))
lhc_parameters[indexSelected] = { controlChannel, isEnabled, threshold, description }
accelerator.parameter(controlChannel, isEnabled, threshold, description)
end
end
function lhc_parameter_toggleEnable(forced)
if lhc_parameters ~= nil then
local _, index = lhc_parameter_getIndexes()
local controlChannel, isEnabled, threshold, description = lhc_parameter_get(index)
if forced == nil then
isEnabled = not isEnabled
else
isEnabled = forced
end
lhc_parameters[index] = { controlChannel, isEnabled, threshold, description }
accelerator.parameter(controlChannel, isEnabled, threshold, description)
end
end
function lhc_page()
w.page_begin(w.data_getName() .. " - Accelerator controller")
if accelerator ~= nil then
-- w.writeLn("")
local status, isEnabled, isPowered, energy, temperatureCurrent_K, temperatureTarget_K = accelerator.state()
if status == nil then
lhc_boot(false)
w.status_showWarning("Invalid accelerator status, rebooting...")
status, isEnabled, isPowered, energy, temperatureCurrent_K, temperatureTarget_K = "-", false, false, 0, 0, 0
end
w.writeLn("Accelerator status: " .. status)
w.write(" Controller is ")
if isEnabled then
w.setColorGood();
w.writeLn("Enabled")
else
w.setColorBad();
w.writeLn("Disabled")
end
local energy, energyMax = accelerator.energy()
if energy == nil then energy = 0 end
if energyMax == nil or energyMax == 0 then energyMax = 1 end
w.setColorNormal();
w.write(" Energy level is ")
if isPowered then
w.setColorGood();
elseif isEnabled then
w.setColorBad();
else
w.setColorDisabled();
end
w.writeLn(math.floor(energy / energyMax * 100) .. " % (" .. energy .. "EU)")
-- w.writeLn("")
w.setColorNormal();
w.write(" Magnets temperature is ")
if temperatureCurrent_K <= temperatureTarget_K then
w.setColorGood();
elseif isEnabled then
w.setColorBad();
else
w.setColorDisabled();
end
w.write(string.format("%fK", math.floor(temperatureCurrent_K * 10) / 10))
w.setColorNormal();
w.writeLn(". Target is " .. temperatureTarget_K .. "K")
-- w.writeLn("")
w.write("Parameters: ")
if #lhc_parameters == 0 then
w.setColorDisabled();
w.writeLn("")
w.writeCentered(" -no valid node detected-")
else
local indexFirstLine, indexSelected = lhc_parameter_getIndexes()
w.writeLn(indexSelected .. "/" .. #lhc_parameters)
local indexCurrent = indexFirstLine
local indexLastLine = math.min(indexFirstLine + lhc_parameter_lines, #lhc_parameters)
for indexCurrent = indexFirstLine, indexLastLine do
if indexCurrent == indexSelected then
w.setColorSelected()
w.clearLine()
w.write(">")
else
w.write(" ")
end
local controlChannel, isEnabled, threshold, description = lhc_parameter_get(indexCurrent)
if description == "-" then
description = "#" .. w.format_integer(controlChannel)
end
w.write(string.format("%s is ",
w.format_string(description, 25) ))
if isEnabled then
w.write("enabled ")
else
w.write("disabled")
end
w.writeLn(", set to " .. w.format_integer(threshold * 100, 3) .. "%")
w.setColorNormal()
end
end
else
w.status_showWarning("No accelerator controller detected")
end
w.setCursorPos(1, 15)
w.setColorControl()
w.writeFullLine(" Start accelerator (S), Stop accelerator (P)")
w.writeFullLine(" Select parameter (Up, Down), Enable parameter (E)")
w.writeFullLine(" Change parameter (Enter), Adjust threshold (+, -)")
end
function lhc_key(character, keycode)
if character == 's' or character == 'S' then
if accelerator ~= nil then
accelerator.enable(true)
else
w.status_showWarning("No accelerator detected")
end
return true
elseif character == 'p' or character == 'P' then
if accelerator ~= nil then
accelerator.enable(false)
else
w.status_showWarning("No accelerator detected")
end
return true
elseif keycode == 200 or keycode == 203 then -- Up or Left arrow
lhc_parameter_indexSelected = lhc_parameter_indexSelected - 1
return true
elseif keycode == 208 or keycode == 205 then -- Down or Right arrow
lhc_parameter_indexSelected = lhc_parameter_indexSelected + 1
return true
elseif keycode == 28 or character == 'c' or character == 'C' then -- Return or Enter
lhc_page_parameter()
return true
elseif character == '-' then
lhc_parameter_updateThreshold(-1)
return true
elseif character == '+' then
lhc_parameter_updateThreshold(1)
return true
elseif character == 'e' or character == 'E' or character == ' ' then
lhc_parameter_toggleEnable()
lhc_parameter_indexSelected = lhc_parameter_indexSelected + 1
return true
elseif character == 'y' or character == 'Y' then
lhc_parameter_toggleEnable(true)
lhc_parameter_indexSelected = lhc_parameter_indexSelected + 1
return true
elseif character == 'n' or character == 'N' then
lhc_parameter_toggleEnable(false)
lhc_parameter_indexSelected = lhc_parameter_indexSelected + 1
return true
end
return false
end
function lhc_register()
w.device_register("warpdriveAccelerator",
function(deviceType, address, wrap) accelerator = wrap end,
function() end)
w.event_register("particleBunchCollided" , function() w.status_showSuccess("Particle bunch have collided") return false end )
w.event_register("particleBunchInjected" , function() w.status_showSuccess("Particle bunch injection done") return false end )
w.event_register("acceleratorCoolingReset", function() w.status_showWarning("Accelerator coolant has leaked! restarting...") return true end )
w.event_register("acceleratorCoolingDone" , function() w.status_showSuccess("Accelerator cooling completed") return true end )
w.event_register("acceleratorUpdated" , function() w.status_showSuccess("Accelerator updated") lhc_boot(false) return true end )
end
----------- connections status
function connections_page(isBooting)
w.page_begin(w.data_getName() .. " - Connections")
w.writeLn("")
local monitors = w.device_getMonitors()
if #monitors == 0 then
w.setColorDisabled()
w.writeLn("No Monitor detected")
elseif #monitors == 1 then
w.setColorSuccess()
w.writeLn("1 monitor detected")
else
w.setColorSuccess()
w.writeLn(#monitors .. " Monitors detected")
end
if accelerator == nil then
w.setColorDisabled()
w.writeLn("No accelerator controller detected")
else
w.setColorSuccess()
w.writeLn("Accelerator controller detected")
lhc_boot(isBooting)
end
w.writeLn("")
w.setColorNormal()
w.writeLn("This is a keyboard controlled user interface.")
w.write("Key controls are written like so: ")
w.setColorControl()
w.write("Action (key)")
w.setColorNormal()
w.writeLn(".")
w.write("For example, typing ")
w.setColorControl()
w.write(" 1 ")
w.setColorNormal()
w.writeLn(" will open Accelerator")
w.writeLn("controls.")
end
----------- Boot sequence
w.page_setEndText(" Home (0), Accelerator controls (1)")
w.page_register('0', connections_page, nil)
w.page_register('1', lhc_page, lhc_key)
lhc_register()
w.boot()
w.run()
w.close()

View file

@ -1070,7 +1070,7 @@ function core_page()
WriteLn(" x, y, z = " .. X .. ", " .. Y .. ", " .. Z)
local energy, energyMax = ship.energy()
if energy == nil then energy = 0 end
if energyMax == nil then energyMax = 1 end
if energyMax == nil or energyMax == 0 then energyMax = 1 end
WriteLn(" Energy = " .. math.floor(energy / energyMax * 100) .. " % (" .. energy .. "EU)")
local playersString, playersArray = ship.getAttachedPlayers()
if playersString == "" then players = "-" end

View file

@ -0,0 +1 @@
{reboot=true}

View file

@ -0,0 +1,12 @@
alias l="ls -lhp"
alias ..="cd .."
alias df="df -h"
alias grep="grep --color"
# WarpDrive added stuff starts here
alias ll="ls -lhp"
# mimic CC autoboot
/startup

View file

@ -0,0 +1,393 @@
package.loaded.warpdriveCommons = nil
local w = require("warpdriveCommons")
----------- Accelerator support
local lhc_isEnabled = false
local lhc_controlPoints = {}
local lhc_parameters = {}
local accelerator = nil
function lhc_boot(isDetailed)
if accelerator == nil then
return
end
if isDetailed == nil then
isDetailed = true
end
if isDetailed then
w.write("Booting Accelerator controller")
w.writeLn("...")
w.sleep(0.1)
end
-- getting control points
lhc_controlPoints = {}
local count = accelerator.getControlPointsCount()
lhc_controlChannels = { }
countParameters = 0
if count ~= nil and count > 0 then
for i = 0, count - 1 do
local success, x, y, z, tier, type, isEnabled, controlChannel = accelerator.getControlPoint(i)
if success then
if isDetailed then
w.write(type .. " " .. tier .. " #" .. controlChannel .. " @ (" .. w.format_integer(x, 6) .. " " .. w.format_integer(y, 3) .. " " .. w.format_integer(z, 6) .. ") ")
if isEnabled then
w.writeLn("Enabled")
else
w.writeLn("Disabled")
end
end
lhc_controlPoints[i + 1] = { x, y, z, tier, type, isEnabled, controlChannel }
lhc_controlChannels[controlChannel] = "true"
countParameters = countParameters + 1
elseif isDetailed then
w.setColorWarning();
w.writeLn("Error " .. x)
w.setColorNormal();
w.sleep(0.5)
end
end
elseif isDetailed then
w.setColorWarning();
w.writeLn("No control point detected!")
w.sleep(0.5)
end
-- getting parameters
local controlChannels = { accelerator.getParametersControlChannels() }
if controlChannels ~= nil and #controlChannels > 0 then
for key, value in pairs(controlChannels) do lhc_controlChannels[value] = { } end
countParameters = countParameters + 1
end
lhc_parameters = {}
if isDetailed then w.sleep(0.1) end
if countParameters ~= 0 then
local index = 1
for controlChannel, _ in pairs(lhc_controlChannels) do
local success, controlChannelCheck, isEnabled, threshold, description = accelerator.parameter(controlChannel)
if success ~= nil and success then
if isDetailed then
w.write("#" .. w.format_integer(controlChannelCheck, 9) .. " ")
if isEnabled then
w.write("Enabled")
else
w.write("Disabled")
end
w.writeLn(" " .. w.format_integer(threshold * 100, 3) .. "% '" .. description .. "'")
end
lhc_parameters[index] = { controlChannel, isEnabled, threshold, description }
index = index + 1
elseif isDetailed then
w.setColorWarning();
if controlChannelCheck ~= nil then
w.writeLn("Error " .. controlChannelCheck)
else
w.writeLn("Error nil?")
end
w.sleep(0.5)
w.setColorNormal();
end
if controlChannel ~= controlChannelCheck and isDetailed then
w.setColorWarning();
w.writeLn("Error: requested " .. controlChannel .. ", received " .. controlChannelCheck)
w.sleep(0.5)
w.setColorNormal();
end
end
elseif isDetailed then
w.setColorWarning();
w.writeLn("No control channel detected!")
w.sleep(0.5)
end
end
function lhc_page_parameter()
w.page_begin("<==== Change accelerator parameter ====>")
local _, indexSelected = lhc_parameter_getIndexes()
local controlChannel, isEnabled, threshold, description = lhc_parameter_get(indexSelected)
w.writeLn("Control channel #" .. w.format_integer(controlChannel, 9) .. " applies to:")
for key, controlPoint in ipairs(lhc_controlPoints) do
local cp_x, cp_y, cp_z, cp_tier, cp_type, cp_isEnabled, cp_controlChannel = unpack(controlPoint)
if cp_controlChannel == controlChannel then
w.write(string.format("%s %s @%s %s %s ",
w.format_string(cp_type, 10),
w.format_string(cp_tier, 1),
w.format_integer(cp_x, 7), w.format_integer(cp_y, 3), w.format_integer(cp_z, 7) ))
if isEnabled then
w.writeLn("Enabled")
else
w.writeLn("Disabled")
end
end
end
w.writeLn("")
w.writeLn("Current description is '" .. description .. "'")
w.write("Enter a description: ")
description = w.input_readText(description)
w.writeLn("")
w.writeLn("Current theshold is " .. (threshold * 100) .. "%")
w.write("Enter parameter threshold: ")
local new_threshold = w.input_readNumber(threshold * 100) / 100
threshold = math.min(2.0, math.max(0.0, new_threshold))
lhc_parameters[indexSelected] = { controlChannel, isEnabled, threshold, description }
accelerator.parameter(controlChannel, isEnabled, threshold, description)
end
lhc_parameter_indexSelected = 1
lhc_parameter_indexFirstLine = 1
lhc_parameter_lines = 7
function lhc_parameter_getIndexes()
if lhc_parameters ~= nil then
if lhc_parameter_indexSelected > #lhc_parameters then
lhc_parameter_indexSelected = 1
elseif lhc_parameter_indexSelected < 1 then
lhc_parameter_indexSelected = #lhc_parameters
end
if lhc_parameter_indexFirstLine > lhc_parameter_indexSelected then
lhc_parameter_indexFirstLine = lhc_parameter_indexSelected
elseif lhc_parameter_indexFirstLine + lhc_parameter_lines < lhc_parameter_indexSelected then
lhc_parameter_indexFirstLine = lhc_parameter_indexSelected - lhc_parameter_lines
end
return lhc_parameter_indexFirstLine, lhc_parameter_indexSelected
else
return 1, 1
end
end
function lhc_parameter_get(index)
local parameter = lhc_parameters[index]
local controlChannel, isEnabled, threshold, description = -1, false, 0, "-"
if parameter == nil or #parameter ~= 4 then
lhc_boot(false)
w.status_showWarning("Invalid parameter at index " .. index)
else
controlChannel, isEnabled, threshold, description = unpack(parameter)
end
return controlChannel, isEnabled, threshold, description
end
function lhc_parameter_updateThreshold(offset)
if lhc_parameters ~= nil and offset ~= nil then
local _, indexSelected = lhc_parameter_getIndexes()
local controlChannel, isEnabled, threshold, description = lhc_parameter_get(indexSelected)
threshold = math.min(2.0, math.max(0.0, threshold + offset / 100))
lhc_parameters[indexSelected] = { controlChannel, isEnabled, threshold, description }
accelerator.parameter(controlChannel, isEnabled, threshold, description)
end
end
function lhc_parameter_toggleEnable(forced)
if lhc_parameters ~= nil then
local _, index = lhc_parameter_getIndexes()
local controlChannel, isEnabled, threshold, description = lhc_parameter_get(index)
if forced == nil then
isEnabled = not isEnabled
else
isEnabled = forced
end
lhc_parameters[index] = { controlChannel, isEnabled, threshold, description }
accelerator.parameter(controlChannel, isEnabled, threshold, description)
end
end
function lhc_page()
w.page_begin(w.data_getName() .. " - Accelerator controller")
if accelerator ~= nil then
-- w.writeLn("")
local status, isEnabled, isPowered, energy, temperatureCurrent_K, temperatureTarget_K = accelerator.state()
if status == nil then
lhc_boot(false)
w.status_showWarning("Invalid accelerator status, rebooting...")
status, isEnabled, isPowered, energy, temperatureCurrent_K, temperatureTarget_K = "-", false, false, 0, 0, 0
end
w.writeLn("Accelerator status: " .. status)
w.write(" Controller is ")
if isEnabled then
w.setColorGood();
w.writeLn("Enabled")
else
w.setColorBad();
w.writeLn("Disabled")
end
local energy, energyMax = accelerator.energy()
if energy == nil then energy = 0 end
if energyMax == nil or energyMax == 0 then energyMax = 1 end
w.setColorNormal();
w.write(" Energy level is ")
if isPowered then
w.setColorGood();
elseif isEnabled then
w.setColorBad();
else
w.setColorDisabled();
end
w.writeLn(math.floor(energy / energyMax * 100) .. " % (" .. energy .. "EU)")
-- w.writeLn("")
w.setColorNormal();
w.write(" Magnets temperature is ")
if temperatureCurrent_K <= temperatureTarget_K then
w.setColorGood();
elseif isEnabled then
w.setColorBad();
else
w.setColorDisabled();
end
w.write(string.format("%fK", math.floor(temperatureCurrent_K * 10) / 10))
w.setColorNormal();
w.writeLn(". Target is " .. temperatureTarget_K .. "K")
-- w.writeLn("")
w.write("Parameters: ")
if #lhc_parameters == 0 then
w.setColorDisabled();
w.writeLn("")
w.writeCentered(" -no valid node detected-")
else
local indexFirstLine, indexSelected = lhc_parameter_getIndexes()
w.writeLn(indexSelected .. "/" .. #lhc_parameters)
local indexCurrent = indexFirstLine
local indexLastLine = math.min(indexFirstLine + lhc_parameter_lines, #lhc_parameters)
for indexCurrent = indexFirstLine, indexLastLine do
if indexCurrent == indexSelected then
w.setColorSelected()
w.clearLine()
w.write(">")
else
w.write(" ")
end
local controlChannel, isEnabled, threshold, description = lhc_parameter_get(indexCurrent)
if description == "-" then
description = "#" .. w.format_integer(controlChannel)
end
w.write(string.format("%s is ",
w.format_string(description, 25) ))
if isEnabled then
w.write("enabled ")
else
w.write("disabled")
end
w.writeLn(", set to " .. w.format_integer(threshold * 100, 3) .. "%")
w.setColorNormal()
end
end
else
w.status_showWarning("No accelerator controller detected")
end
w.setCursorPos(1, 19)
w.setColorControl()
w.writeFullLine(" Start accelerator (S), Stop accelerator (P)")
w.writeFullLine(" Select parameter (Up, Down), Enable parameter (E)")
w.writeFullLine(" Change parameter (Enter), Adjust threshold (+, -)")
end
function lhc_key(character, keycode)
if character == 's' or character == 'S' then
if accelerator ~= nil then
accelerator.enable(true)
else
w.status_showWarning("No accelerator detected")
end
return true
elseif character == 'p' or character == 'P' then
if accelerator ~= nil then
accelerator.enable(false)
else
w.status_showWarning("No accelerator detected")
end
return true
elseif keycode == 200 or keycode == 203 then -- Up or Left arrow
lhc_parameter_indexSelected = lhc_parameter_indexSelected - 1
return true
elseif keycode == 208 or keycode == 205 then -- Down or Right arrow
lhc_parameter_indexSelected = lhc_parameter_indexSelected + 1
return true
elseif keycode == 28 or character == 'c' or character == 'C' then -- Return or Enter
lhc_page_parameter()
return true
elseif character == '-' then
lhc_parameter_updateThreshold(-1)
return true
elseif character == '+' then
lhc_parameter_updateThreshold(1)
return true
elseif character == 'e' or character == 'E' or character == ' ' then
lhc_parameter_toggleEnable()
lhc_parameter_indexSelected = lhc_parameter_indexSelected + 1
return true
elseif character == 'y' or character == 'Y' then
lhc_parameter_toggleEnable(true)
lhc_parameter_indexSelected = lhc_parameter_indexSelected + 1
return true
elseif character == 'n' or character == 'N' then
lhc_parameter_toggleEnable(false)
lhc_parameter_indexSelected = lhc_parameter_indexSelected + 1
return true
end
return false
end
function lhc_register()
w.device_register("warpdriveAccelerator",
function(deviceType, address, wrap) accelerator = wrap end,
function() end)
w.event_register("particleBunchCollided" , function() w.status_showSuccess("Particle bunch have collided") return false end )
w.event_register("particleBunchInjected" , function() w.status_showSuccess("Particle bunch injection done") return false end )
w.event_register("acceleratorCoolingReset", function() w.status_showWarning("Accelerator coolant has leaked! restarting...") return true end )
w.event_register("acceleratorCoolingDone" , function() w.status_showSuccess("Accelerator cooling completed") return true end )
w.event_register("acceleratorUpdated" , function() w.status_showSuccess("Accelerator updated") lhc_boot(false) return true end )
end
----------- connections status
function connections_page(isBooting)
w.page_begin(w.data_getName() .. " - Connections")
w.writeLn("")
if accelerator == nil then
w.setColorDisabled()
w.writeLn("No accelerator controller detected")
else
w.setColorSuccess()
w.writeLn("Accelerator controller detected")
lhc_boot(isBooting)
end
w.writeLn("")
w.setColorNormal()
w.writeLn("This is a keyboard controlled user interface.")
w.write("Key controls are written like so: ")
w.setColorControl()
w.write("Action (key)")
w.setColorNormal()
w.writeLn(".")
w.write("For example, typing ")
w.setColorControl()
w.write(" 1 ")
w.setColorNormal()
w.writeLn(" will open Accelerator")
w.writeLn("controls.")
end
----------- Boot sequence
w.page_setEndText(" Home (0), Accelerator controls (1)")
w.page_register('0', connections_page, nil)
w.page_register('1', lhc_page, lhc_key)
lhc_register()
w.boot()
w.run()
w.close()

View file

@ -1,887 +0,0 @@
local component = require("component")
local computer = require("computer")
local term = require("term")
local event = require("event")
local fs = require("filesystem")
local serialization = require("serialization")
if not term.isAvailable() then
computer.beep()
return
end
Style = {
CDefault = 0xFFFFFF,
BGDefault = 0x0000FF,
CTitle = 0x000000,
BGTitle = 0x00FFFF,
CWarning = 0xFFFFFF,
BGWarning = 0xFF0000,
CSuccess = 0xFFFFFF,
BGSuccess = 0x32CD32,
CDisabled = 0x808080,
BGDisabled = 0x0000FF
}
----------- Monitor support
-- cache colors to reduce GPU load
local gpu_frontColor = 0xFFFFFF
local gpu_backgroundColor = 0x000000
function SetMonitorColorFrontBack(frontColor, backgroundColor)
if gpu_frontColor ~= frontColor then
gpu_frontColor = frontColor
component.gpu.setForeground(gpu_frontColor)
end
if gpu_backgroundColor ~= backgroundColor then
gpu_backgroundColor = backgroundColor
component.gpu.setBackground(gpu_backgroundColor)
end
end
function Write(text)
if term.isAvailable() then
local w, h = component.gpu.getResolution()
if w then
local xt, yt = term.getCursor()
component.gpu.set(xt, yt, text)
SetCursorPos(xt + #text, yt)
end
end
end
function SetCursorPos(x, y)
if term.isAvailable() then
term.setCursor(x, y)
end
end
function SetColorDefault()
SetMonitorColorFrontBack(Style.CDefault, Style.BGDefault)
end
function SetColorTitle()
SetMonitorColorFrontBack(Style.CTitle, Style.BGTitle)
end
function SetColorWarning()
SetMonitorColorFrontBack(Style.CWarning, Style.BGWarning)
end
function SetColorSuccess()
SetMonitorColorFrontBack(Style.CSuccess, Style.BGSuccess)
end
function SetColorDisabled()
SetMonitorColorFrontBack(Style.CDisabled, Style.BGDisabled)
end
function Clear()
clearWarningTick = -1
SetColorDefault()
term.clear()
SetCursorPos(1, 1)
end
function ClearLine()
SetColorDefault()
term.clearLine()
SetCursorPos(1, 1)
end
function WriteLn(text)
if term.isAvailable() then
Write(text)
local x, y = term.getCursor()
local width, height = component.gpu.getResolution()
if y > height - 1 then
y = 1
end
SetCursorPos(1, y + 1)
end
end
function WriteCentered(y, text)
if term.isAvailable() then
local sizeX, sizeY = component.gpu.getResolution()
if sizeX then
component.gpu.set((sizeX - text:len()) / 2, y, text)
end
local xt, yt = term.getCursor()
SetCursorPos(1, yt + 1)
end
end
function ShowTitle(text)
Clear()
SetColorTitle()
WriteCentered(1, text)
SetColorDefault()
end
function ShowMenu(text)
if term.isAvailable() then
Write(text)
local sizeX, sizeY = component.gpu.getResolution()
local xt, yt = term.getCursor()
for i = xt, sizeX do
Write(" ")
end
SetCursorPos(1, yt + 1)
end
end
local clearWarningTick = -1
function ShowWarning(text)
if term.isAvailable() then
local sizeX, sizeY = component.gpu.getResolution()
SetCursorPos(1, sizeY)
ClearLine()
SetColorWarning()
SetCursorPos((sizeX - text:len() - 2) / 2, sizeY)
Write(" " .. text .. " ")
SetColorDefault()
clearWarningTick = 5
end
end
function ClearWarning()
if clearWarningTick > 0 then
clearWarningTick = clearWarningTick - 1
elseif clearWarningTick == 0 then
if term.isAvailable() then
SetColorDefault()
local sizeX, sizeY = component.gpu.getResolution()
SetCursorPos(1, sizeY)
ClearLine()
clearWarningTick = -1
end
end
end
----------- Formatting & popups
function FormatFloat(value, nbchar)
local str = "?"
if value ~= nil then
str = string.format("%g", value)
end
if nbchar ~= nil then
str = string.sub(" " .. str, -nbchar)
end
return str
end
function FormatInteger(value, nbchar)
local str = "?"
if value ~= nil then
str = string.format("%d", value)
end
if nbchar ~= nil then
str = string.sub(" " .. str, -nbchar)
end
return str
end
function boolToYesNo(bool)
if bool then
return "YES"
else
return "no"
end
end
function readInputNumber(currentValue)
local inputAbort = false
local input = string.format(currentValue)
if input == "0" then
input = ""
end
local x, y = term.getCursor()
repeat
ClearWarning()
SetColorDefault()
SetCursorPos(x, y)
Write(input .. " ")
input = string.sub(input, -9)
local params = { event.pull() }
local eventName = params[1]
local address = params[2]
if address == nil then address = "none" end
if eventName == "key_down" then
local char = params[3]
local keycode = params[4]
if char >= 49 and char <= 57 then -- 1 to 9
input = input .. string.format(char - 48)
elseif keycode >= 2 and keycode <= 10 then -- 1 to 9
input = input .. string.format(keycode - 1)
elseif char == 48 or keycode == 11 then -- 0
input = input .. "0"
elseif char == 45 or char == 78 or char == 110
or keycode == 74 or keycode == 12 or keycode == 49 then -- - on numeric keypad or - on US top or n letter
if string.sub(input, 1, 1) == "-" then
input = string.sub(input, 2)
else
input = "-" .. input
end
elseif char == 43 or keycode == 78 then -- +
if string.sub(input, 1, 1) == "-" then
input = string.sub(input, 2)
end
elseif char == 8 then -- Backspace
input = string.sub(input, 1, string.len(input) - 1)
elseif char == 0 and keycode == 211 then -- Delete
input = ""
elseif char == 13 then -- Enter
inputAbort = true
elseif char ~= 0 then
ShowWarning("Key " .. char .. " " .. keycode .. " is invalid")
end
elseif eventName == "interrupted" then
inputAbort = true
elseif not common_event(eventName, params[3]) then
ShowWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
end
until inputAbort
SetCursorPos(1, y + 1)
if input == "" or input == "-" then
return currentValue
else
return tonumber(input)
end
end
function readInputText(currentValue)
local inputAbort = false
local input = string.format(currentValue)
local x, y = term.getCursor()
repeat
ClearWarning()
SetColorDefault()
SetCursorPos(x, y)
Write(input .. " ")
input = string.sub(input, -30)
local params = { event.pull() }
local eventName = params[1]
local address = params[2]
if address == nil then address = "none" end
if eventName == "key_down" then
local char = params[3]
local keycode = params[4]
if char >= 32 and char <= 127 then -- any ASCII table minus controls and DEL
input = input .. string.char(char)
elseif char == 8 then -- Backspace
input = string.sub(input, 1, string.len(input) - 1)
elseif char == 0 and keycode == 211 then -- Delete
input = ""
elseif char == 13 then -- Enter
inputAbort = true
elseif char ~= 0 then
ShowWarning("Key " .. char .. " " .. keycode .. " is invalid")
end
elseif eventName == "interrupted" then
inputAbort = true
elseif not common_event(eventName, params[3]) then
ShowWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
end
until inputAbort
SetCursorPos(1, y + 1)
if input == "" then
return currentValue
else
return input
end
end
function readConfirmation(msg)
if msg == nil then
ShowWarning("Are you sure? (y/n)")
else
ShowWarning(msg)
end
repeat
local params = { event.pull() }
local eventName = params[1]
local address = params[3]
if address == nil then address = "none" end
if eventName == "key_down" then
local char = params[3]
if char == 89 or char == 121 or keycode == 21 then -- Y
return true
else
return false
end
elseif eventName == "interrupted" then
return false
elseif not common_event(eventName, params[3]) then
ShowWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
end
until false
end
----------- commons: menu, event handlers, etc.
function common_event(eventName, param)
if eventName == "redstone" then
-- redstone_event(param)
elseif eventName == "timer" then
elseif eventName == "reactorPulse" then
reactor_pulse(param)
elseif eventName == "reactorDeactivation" then
ShowWarning("Reactor deactivated")
elseif eventName == "reactorActivation" then
ShowWarning("Reactor activated")
elseif eventName == "key_up" then
elseif eventName == "touch" then
elseif eventName == "drop" then
elseif eventName == "drag" then
elseif eventName == "component_added" then
elseif eventName == "component_removed" then
elseif eventName == "component_unavailable" then
-- ShowWarning("Event '" .. eventName .. "', " .. param .. " is unsupported")
else
return false
end
return true
end
function menu_common()
SetCursorPos(1, 23)
SetColorTitle()
ShowMenu("0 Connections, 1 Reactor, X Exit")
end
----------- Configuration
function data_save()
local file = fs.open("/disk/shipdata.txt", "w")
if file ~= nil then
file:write(serialization.serialize(data))
file:close()
else
ShowWarning("No file system")
os.sleep(0.1)
end
end
function data_read()
data = { }
if fs.exists("/disk/shipdata.txt") then
local file = fs.open("/disk/shipdata.txt", "r")
local size = fs.size("/disk/shipdata.txt")
local rawData = file:read(size)
if rawData ~= nil then
data = serialization.unserialize(rawData)
end
file:close()
if data == nil then data = {}; end
end
if data.reactor_mode == nil then data.reactor_mode = 0; end
if data.reactor_rate == nil then data.reactor_rate = 100; end
if data.reactor_targetStability == nil then data.reactor_targetStability = 50; end
if data.reactor_laserAmount == nil then data.reactor_laserAmount = 10000; end
end
function data_setName()
if ship ~= nil then
ShowTitle("<==== Set ship name ====>")
else
ShowTitle("<==== Set name ====>")
end
SetCursorPos(1, 2)
Write("Enter ship name: ")
label = readInputText(label)
-- FIXME os.setComputerLabel(label)
if ship ~= nil then
ship.coreFrequency(label)
end
-- FIXME computer.shutdown(true)
end
function string_split(source, sep)
local sep = sep or ":"
local fields = {}
local pattern = string.format("([^%s]+)", sep)
source:gsub(pattern, function(c) fields[#fields + 1] = c end)
return fields
end
----------- Reactor support
reactor_output = 0
function reactor_boot()
if reactor ~= nil then
WriteLn("Booting Reactor...")
local isActive, strMode, releaseRate = reactor.active()
if strMode == "OFF" then
data.reactor_mode = 0
elseif strMode == "MANUAL" then
data.reactor_mode = 1
elseif strMode == "ABOVE" then
data.reactor_mode = 2
elseif strMode == "RATE" then
data.reactor_mode = 3
else
data.reactor_mode = 0
end
end
end
function reactor_key(char, keycode)
if char == 83 or char == 115 or keycode == 31 then -- S
reactor_start()
return true
elseif char == 80 or char == 112 or keycode == 25 then -- P
reactor_stop()
return true
elseif char == 76 or char == 108 or keycode == 38 then -- L
reactor_laser()
return true
elseif char == 79 or char == 111 or keycode == 24 then -- O
data.reactor_mode = (data.reactor_mode + 1) % 4
reactor_setMode()
data_save()
return true
elseif char == 71 or char == 103 or keycode == 34 then -- G
data.reactor_rate = data.reactor_rate - 1000
reactor_setMode()
data_save()
return true
elseif char == 84 or char == 116 or keycode == 20 then -- T
data.reactor_rate = data.reactor_rate + 1000
reactor_setMode()
data_save()
return true
elseif char == 74 or char == 106 or keycode == 36 then -- J
data.reactor_laserAmount = data.reactor_laserAmount - 500
reactor_setLaser()
data_save()
return true
elseif char == 85 or char == 117 or keycode == 22 then -- U
data.reactor_laserAmount = data.reactor_laserAmount + 500
reactor_setLaser()
data_save()
return true
elseif char == 45 or keycode == 74 then -- -
data.reactor_targetStability = data.reactor_targetStability - 1
reactor_setTargetStability()
data_save()
return true
elseif char == 43 or keycode == 78 then -- +
data.reactor_targetStability = data.reactor_targetStability + 1
reactor_setTargetStability()
data_save()
return true
elseif char == 67 or char == 99 or keycode == 46 then -- C
reactor_config()
data_save()
return true
end
return false
end
function reactor_page()
ShowTitle(label .. " - Reactor status")
SetCursorPos(1, 2)
if reactor == nil then
SetColorDisabled()
Write("Reactor not detected")
else
SetColorDefault()
Write("Reactor stability")
instabilities = { reactor.instability() }
for key,instability in pairs(instabilities) do
SetCursorPos(12, 2 + key)
stability = math.floor((100.0 - instability) * 10) / 10
if stability >= data.reactor_targetStability then
SetColorSuccess()
else
SetColorWarning()
end
Write(FormatFloat(stability, 5) .. " %")
end
SetColorDefault()
local energy = { reactor.energy() }
SetCursorPos(1, 7)
Write("Energy : ")
if energy[2] ~= nil then
Write(FormatInteger(energy[1], 10) .. " / " .. energy[2] .. " RF +" .. FormatInteger(reactor_output, 5) .. " RF/t")
else
Write("???")
end
SetCursorPos(1, 8)
Write("Outputing: ")
if energy[3] ~= nil then
Write(energy[3] .. " RF/t")
end
SetColorDefault()
SetCursorPos(1, 9)
Write("Activated: ")
isActive = reactor.active()
if isActive then SetColorSuccess() else SetColorDefault() end
Write(boolToYesNo(isActive))
end
if #reactorlasers == 0 then
SetColorDisabled()
SetCursorPos(30, 2)
Write("Lasers not detected")
else
SetColorDefault()
SetCursorPos(30, 2)
Write("Lasers")
for key,reactorlaser in pairs(reactorlasers) do
local side = reactorlaser.side
if side ~= nil then
side = side % 4
SetColorDefault()
SetCursorPos(4, 3 + side)
Write("Side " .. side .. ":")
SetCursorPos(30, 3 + side)
local energy = reactorlaser.wrap.energy()
if not reactorlaser.wrap.hasReactor() then
SetColorDisabled()
elseif energy > 3 * data.reactor_laserAmount then
SetColorSuccess()
else
SetColorWarning()
end
Write(FormatInteger(energy, 6))
end
end
end
SetColorDefault()
SetCursorPos(1, 10)
Write(" -----------------------------------------------")
SetCursorPos(1, 11)
Write("Output mode : ")
if data.reactor_mode == 0 then
SetColorDisabled()
Write("hold")
elseif data.reactor_mode == 1 then
Write("manual/unlimited")
elseif data.reactor_mode == 2 then
Write("surplus above " .. data.reactor_rate .. " RF")
else
Write("rated at " .. data.reactor_rate .. " RF")
end
SetColorDefault()
SetCursorPos( 1, 12)
Write("Target stability: " .. data.reactor_targetStability .. "%")
SetCursorPos(30, 12)
Write("Laser amount: " .. data.reactor_laserAmount)
SetColorTitle()
SetCursorPos(1, 18)
ShowMenu("S - Start reactor, P - Stop reactor, L - Use lasers")
SetCursorPos(1, 19)
ShowMenu("O - Output mode, C - Configuration")
SetCursorPos(1, 20)
ShowMenu("+/- - Target stability, U/J - Laser amount")
SetCursorPos(1, 21)
ShowMenu("G/T - Output rate/threshold")
end
function reactor_setMode()
if data.reactor_rate < 1 then
data.reactor_rate = 1
elseif data.reactor_rate > 100000 then
data.reactor_rate = 100000
end
if reactor ~= nil then
if data.reactor_mode == 0 then
reactor.release(false)
elseif data.reactor_mode == 1 then
reactor.release(true)
elseif data.reactor_mode == 2 then
reactor.releaseAbove(data.reactor_rate)
else
reactor.releaseRate(data.reactor_rate)
end
end
end
function reactor_setLaser()
if data.reactor_laserAmount < 1 then
data.reactor_laserAmount = 1
elseif data.reactor_laserAmount > 100000 then
data.reactor_laserAmount = 100000
end
end
function reactor_setTargetStability()
if data.reactor_targetStability < 1 then
data.reactor_targetStability = 1
elseif data.reactor_targetStability > 100 then
data.reactor_targetStability = 100
end
end
function reactor_start()
if reactor ~= nil then
reactor_setMode()
reactor.active(true)
end
end
function reactor_stop()
if reactor ~= nil then
reactor.active(false)
end
end
function reactor_laser(side)
for key,reactorlaser in pairs(reactorlasers) do
if (side == nil) or (reactorlaser.side == side) then
reactorlaser.wrap.stabilize(data.reactor_laserAmount)
end
end
end
local reactor_configPageLoaded = false
local reactor_pulseStep = 0
function reactor_pulse(output)
reactor_output = output
if reactor == nil then
computer.shutdown(true)
end
local instabilities = { reactor.instability() }
for key,instability in pairs(instabilities) do
local stability = 100.0 - instability
if stability < data.reactor_targetStability then
reactor_laser(key - 1)
end
end
reactor_pulseStep = (reactor_pulseStep + 1) % 6
if page == reactor_page and (not reactor_configPageLoaded) then
if reactor_pulseStep == 0 then
for key,instability in pairs(instabilities) do
SetCursorPos(12, 2 + key)
stability = math.floor((100.0 - instability) * 10) / 10
if stability >= data.reactor_targetStability then
SetColorSuccess()
else
SetColorWarning()
end
Write(FormatFloat(stability, 5) .. " %")
end
elseif reactor_pulseStep == 2 then
SetColorDefault()
local energy = { reactor.energy() }
SetCursorPos(12, 7)
if energy[2] ~= nil then
Write(FormatInteger(energy[1], 10))
SetCursorPos(39, 7)
Write(FormatInteger(reactor_output, 5))
else
Write("???")
end
if energy[3] ~= nil then
SetCursorPos(12, 8)
Write(energy[3] .. " RF/t ")
end
elseif reactor_pulseStep == 4 then
if #reactorlasers ~= 0 then
for key,reactorlaser in pairs(reactorlasers) do
local side = reactorlaser.side
if side ~= nil then
side = side % 4
SetCursorPos(30, 3 + side)
local energy = reactorlaser.wrap.energy()
if not reactorlaser.wrap.hasReactor() then
SetColorDisabled()
elseif energy > 3 * data.reactor_laserAmount then
SetColorSuccess()
else
SetColorWarning()
end
Write(FormatInteger(energy, 6))
end
end
end
end
end
end
function reactor_config()
reactor_configPageLoaded = true
ShowTitle(label .. " - Reactor configuration")
SetCursorPos(1, 2)
if reactor == nil then
SetColorDisabled()
Write("Reactor not detected")
else
SetColorDefault()
SetCursorPos(1, 4)
Write("Reactor output rate (" .. data.reactor_rate .. " RF): ")
data.reactor_rate = readInputNumber(data.reactor_rate)
reactor_setMode()
SetCursorPos(1, 5)
Write("Reactor output rate set")
SetCursorPos(1, 7)
Write("Laser energy level (" .. data.reactor_laserAmount .. "): ")
data.reactor_laserAmount = readInputNumber(data.reactor_laserAmount)
reactor_setLaser()
SetCursorPos(1, 8)
Write("Laser energy level set")
SetCursorPos(1, 10)
Write("Reactor target stability (" .. data.reactor_targetStability .. "%): ")
data.reactor_targetStability = readInputNumber(data.reactor_targetStability)
reactor_setTargetStability()
SetCursorPos(1, 11)
Write("Reactor target stability set")
end
reactor_configPageLoaded = false
end
----------- Boot sequence
label = computer.address()
if not label then
label = "" .. computer.address()
end
-- read configuration
data_read()
-- initial scanning
ShowTitle(label .. " - Connecting...")
WriteLn("")
-- clear previous events
repeat
until event.pull(0) == nil
reactor = nil
reactorlasers = {}
for address, componentType in component.list() do
os.sleep(0)
Write("Checking " .. componentType .. " ")
if componentType == "warpdriveEnanReactorCore" then
Write("wrapping!")
reactor = component.proxy(address)
elseif componentType == "warpdriveEnanReactorLaser" then
Write("wrapping!")
local wrap = component.proxy(address)
table.insert(reactorlasers, { side = wrap.side(), wrap = wrap })
end
WriteLn("")
end
if not computer.address() and reactor ~= nil then
data_setName()
end
-- peripherals status
function connections_page()
ShowTitle(label .. " - Connections")
WriteLn("")
if reactor == nil then
SetColorDisabled()
WriteLn("No Enantiomorphic reactor detected")
else
SetColorSuccess()
WriteLn("Enantiomorphic reactor detected")
end
if #reactorlasers == 0 then
SetColorDisabled()
WriteLn("No reactor stabilisation laser detected")
elseif #reactorlasers == 1 then
SetColorSuccess()
WriteLn("1 reactor stabilisation laser detected")
else
SetColorSuccess()
WriteLn(#reactorlasers .. " reactor stabilisation lasers detected")
end
WriteLn("")
SetColorTitle()
WriteLn("Please refer to below menu for keyboard controls")
WriteLn("For example, press 1 to access Reactor page")
end
-- peripheral boot up
Clear()
connections_page()
SetColorDefault()
WriteLn("")
os.sleep(0)
reactor_boot()
os.sleep(0)
-- main loop
abort = false
refresh = true
page = connections_page
keyHandler = nil
repeat
ClearWarning()
if refresh then
Clear()
page()
menu_common()
refresh = false
end
params = { event.pull() }
eventName = params[1]
address = params[2]
if address == nil then address = "none" end
-- WriteLn("...")
-- WriteLn("Event '" .. eventName .. "', " .. address .. ", " .. params[3] .. " received")
-- os.sleep(0.2)
if eventName == "key_down" then
char = params[3]
keycode = params[4]
if char == 88 or char == 120 or keycode == 45 then -- x for eXit
abort = true
elseif char == 48 or keycode == 11 or keycode == 82 then -- 0
page = connections_page
keyHandler = nil
refresh = true
elseif char == 49 or keycode == 2 or keycode == 79 then -- 1
page = reactor_page
keyHandler = reactor_key
refresh = true
elseif keyHandler ~= nil and keyHandler(char, keycode) then
refresh = true
os.sleep(0)
elseif char == 0 then -- control chars
refresh = false
os.sleep(0)
else
ShowWarning("Key " .. char .. " " .. keycode .. " is invalid")
os.sleep(0.2)
end
elseif eventName == "interrupted" then
abort = true
elseif not common_event(eventName, params[3]) then
ShowWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
refresh = true
os.sleep(0.2)
end
until abort
-- clear screens on exit
SetMonitorColorFrontBack(0xFFFFFF, 0x000000)
term.clear()
SetCursorPos(1, 1)
WriteLn("Program terminated")
WriteLn("Type reboot to restart it")

View file

@ -0,0 +1,428 @@
package.loaded.warpdriveCommons = nil
local w = require("warpdriveCommons")
local data
----------- Reactor support
local reactor_output = 0
local reactor = nil
local reactorlasers = {}
function reactor_read(parData)
data = parData
if data.reactor_mode == nil then data.reactor_mode = 0 end
if data.reactor_rate == nil then data.reactor_rate = 100 end
if data.reactor_targetStability == nil then data.reactor_targetStability = 50 end
if data.reactor_laserAmount == nil then data.reactor_laserAmount = 10000 end
end
function reactor_boot()
if reactor ~= nil then
w.writeLn("Booting Reactor...")
local isActive, strMode, releaseRate = reactor.active()
if strMode == "OFF" then
data.reactor_mode = 0
elseif strMode == "MANUAL" then
data.reactor_mode = 1
elseif strMode == "ABOVE" then
data.reactor_mode = 2
elseif strMode == "RATE" then
data.reactor_mode = 3
else
data.reactor_mode = 0
end
end
end
function reactor_key(character, keycode)
if character == 's' or character == 'S' then -- S
reactor_start()
return true
elseif character == 'p' or character == 'P' then -- P
reactor_stop()
return true
elseif character == 'l' or character == 'L' then -- L
reactor_laser()
return true
elseif character == 'o' or character == 'O' then -- O
data.reactor_mode = (data.reactor_mode + 1) % 4
reactor_setMode()
w.data_save()
return true
elseif character == 'g' or character == 'G' then -- G
data.reactor_rate = data.reactor_rate - 1000
reactor_setMode()
w.data_save()
return true
elseif character == 't' or character == 'T' then -- T
data.reactor_rate = data.reactor_rate + 1000
reactor_setMode()
w.data_save()
return true
elseif character == 'j' or character == 'J' then -- J
data.reactor_laserAmount = data.reactor_laserAmount - 500
reactor_setLaser()
w.data_save()
return true
elseif character == 'u' or character == 'U' then -- U
data.reactor_laserAmount = data.reactor_laserAmount + 500
reactor_setLaser()
w.data_save()
return true
elseif character == '-' then -- -
data.reactor_targetStability = data.reactor_targetStability - 1
reactor_setTargetStability()
w.data_save()
return true
elseif character == '+' then -- +
data.reactor_targetStability = data.reactor_targetStability + 1
reactor_setTargetStability()
w.data_save()
return true
elseif character == 'c' or character == 'C' then -- C
reactor_config()
w.data_save()
return true
end
return false
end
function reactor_page()
w.page_begin(w.data_getName() .. " - Reactor status")
w.setCursorPos(1, 2)
if reactor == nil then
w.setColorDisabled()
w.write("Reactor not detected")
else
w.setColorNormal()
w.write("Reactor stability")
local instabilities = { reactor.instability() }
for key, instability in pairs(instabilities) do
w.setCursorPos(12, 2 + key)
local stability = math.floor((100.0 - instability) * 10) / 10
if stability >= data.reactor_targetStability then
w.setColorSuccess()
else
w.setColorWarning()
end
w.write(w.format_float(stability, 5) .. " %")
end
w.setColorNormal()
local energy = { reactor.energy() }
w.setCursorPos(1, 7)
w.write("Energy : ")
if energy[2] ~= nil then
w.write(w.format_integer(energy[1], 10) .. " / " .. energy[2] .. " RF +" .. w.format_integer(reactor_output, 5) .. " RF/t")
else
w.write("???")
end
w.setCursorPos(1, 8)
w.write("Outputing: ")
if energy[3] ~= nil then
w.write(energy[3] .. " RF/t")
end
w.setColorNormal()
w.setCursorPos(1, 9)
w.write("Activated: ")
local isActive = reactor.active()
if isActive then w.setColorSuccess() else w.setColorNormal() end
w.write(w.format_boolean(isActive, "YES", "no"))
end
if #reactorlasers == 0 then
w.setColorDisabled()
w.setCursorPos(30, 2)
w.write("Lasers not detected")
else
w.setColorNormal()
w.setCursorPos(30, 2)
w.write("Lasers")
for key, reactorlaser in pairs(reactorlasers) do
local side = reactorlaser.side
if side ~= nil then
side = side % 4
w.setColorNormal()
w.setCursorPos(4, 3 + side)
w.write("Side " .. side .. ":")
w.setCursorPos(30, 3 + side)
local energy = reactorlaser.wrap.energy()
if not reactorlaser.wrap.hasReactor() then
w.setColorDisabled()
elseif energy > 3 * data.reactor_laserAmount then
w.setColorSuccess()
else
w.setColorWarning()
end
w.write(w.format_integer(energy, 6))
end
end
end
w.setColorNormal()
w.setCursorPos(1, 10)
w.write(" -----------------------------------------------")
w.setCursorPos(1, 11)
w.write("Output mode : ")
if data.reactor_mode == 0 then
w.setColorDisabled()
w.write("hold")
elseif data.reactor_mode == 1 then
w.write("manual/unlimited")
elseif data.reactor_mode == 2 then
w.write("surplus above " .. data.reactor_rate .. " RF")
else
w.write("rated at " .. data.reactor_rate .. " RF")
end
w.setColorNormal()
w.setCursorPos( 1, 12)
w.write("Target stability: " .. data.reactor_targetStability .. "%")
w.setCursorPos(30, 12)
w.write("Laser amount: " .. data.reactor_laserAmount)
w.setColorControl()
w.setCursorPos(1, 18)
w.writeFullLine(" Start/stoP reactor (S/P), Use lasers (L)")
w.writeFullLine(" Output mode (O), Configuration (C)")
w.writeFullLine(" Target stability (+/-), Laser amount (U/J)")
w.writeFullLine(" Output rate/threshold (G/T)")
end
function reactor_setMode()
if data.reactor_rate < 1 then
data.reactor_rate = 1
elseif data.reactor_rate > 100000 then
data.reactor_rate = 100000
end
if reactor ~= nil then
if data.reactor_mode == 0 then
reactor.release(false)
elseif data.reactor_mode == 1 then
reactor.release(true)
elseif data.reactor_mode == 2 then
reactor.releaseAbove(data.reactor_rate)
else
reactor.releaseRate(data.reactor_rate)
end
end
end
function reactor_setLaser()
if data.reactor_laserAmount < 1 then
data.reactor_laserAmount = 1
elseif data.reactor_laserAmount > 100000 then
data.reactor_laserAmount = 100000
end
end
function reactor_setTargetStability()
if data.reactor_targetStability < 1 then
data.reactor_targetStability = 1
elseif data.reactor_targetStability > 100 then
data.reactor_targetStability = 100
end
end
function reactor_start()
if reactor ~= nil then
reactor_setMode()
reactor.active(true)
end
end
function reactor_stop()
if reactor ~= nil then
reactor.active(false)
end
end
function reactor_laser(side)
for key, reactorlaser in pairs(reactorlasers) do
if (side == nil) or (reactorlaser.side == side) then
reactorlaser.wrap.stabilize(data.reactor_laserAmount)
end
end
end
local reactor_configPageLoaded = false
local reactor_pulseStep = 0
function reactor_pulse(output)
reactor_output = output
if reactor == nil then
w.reboot()
end
local instabilities = { reactor.instability() }
for key, instability in pairs(instabilities) do
local stability = 100.0 - instability
if stability < data.reactor_targetStability then
reactor_laser(key - 1)
end
end
reactor_pulseStep = (reactor_pulseStep + 1) % 6
if w.page_getCallbackDisplay() == reactor_page and (not reactor_configPageLoaded) then
if reactor_pulseStep == 0 then
for key, instability in pairs(instabilities) do
w.setCursorPos(12, 2 + key)
stability = math.floor((100.0 - instability) * 10) / 10
if stability >= data.reactor_targetStability then
w.setColorSuccess()
else
w.setColorWarning()
end
w.write(w.format_float(stability, 5) .. " %")
end
elseif reactor_pulseStep == 2 then
w.setColorNormal()
local energy = { reactor.energy() }
w.setCursorPos(12, 7)
if energy[2] ~= nil then
w.write(w.format_integer(energy[1], 10))
w.setCursorPos(39, 7)
w.write(w.format_integer(reactor_output, 5))
else
w.write("???")
end
if energy[3] ~= nil then
w.setCursorPos(12, 8)
w.write(energy[3] .. " RF/t ")
end
elseif reactor_pulseStep == 4 then
if #reactorlasers ~= 0 then
for key, reactorlaser in pairs(reactorlasers) do
local side = reactorlaser.side
if side ~= nil and reactorlaser.wrap ~= nil then
side = side % 4
w.setCursorPos(30, 3 + side)
local energy = reactorlaser.wrap.energy()
if energy == nil then
energy = -1
end
if not reactorlaser.wrap.hasReactor() then
w.setColorDisabled()
elseif energy > 3 * data.reactor_laserAmount then
w.setColorSuccess()
else
w.setColorWarning()
end
w.write(w.format_integer(energy, 6))
end
end
end
end
end
end
function reactor_config()
reactor_configPageLoaded = true
w.page_begin(w.data_getName() .. " - Reactor configuration")
w.setCursorPos(1, 2)
if reactor == nil then
w.setColorDisabled()
w.write("Reactor not detected")
else
w.setColorNormal()
w.setCursorPos(1, 4)
w.write("Reactor output rate (" .. data.reactor_rate .. " RF): ")
data.reactor_rate = w.input_readNumber(data.reactor_rate)
reactor_setMode()
w.setCursorPos(1, 5)
w.write("Reactor output rate set")
w.setCursorPos(1, 7)
w.write("Laser energy level (" .. data.reactor_laserAmount .. "): ")
data.reactor_laserAmount = w.input_readNumber(data.reactor_laserAmount)
reactor_setLaser()
w.setCursorPos(1, 8)
w.write("Laser energy level set")
w.setCursorPos(1, 10)
w.write("Reactor target stability (" .. data.reactor_targetStability .. "%): ")
data.reactor_targetStability = w.input_readNumber(data.reactor_targetStability)
reactor_setTargetStability()
w.setCursorPos(1, 11)
w.write("Reactor target stability set")
end
reactor_configPageLoaded = false
end
function reactor_register()
w.device_register("warpdriveEnanReactorCore",
function(deviceType, address, wrap) reactor = wrap end,
function() end)
w.device_register("warpdriveEnanReactorLaser",
function(deviceType, address, wrap) table.insert(reactorlasers, { side = wrap.side(), wrap = wrap }) end,
function() end)
w.event_register("reactorPulse" , function() reactor_pulse(param) return false end )
w.event_register("reactorDeactivation", function() w.status_showWarning("Reactor deactivated") return false end )
w.event_register("reactorActivation" , function() w.status_showWarning("Reactor activated") return false end )
w.data_register("reactor", reactor_read, nil)
end
----------- connections status
function connections_page(isBooting)
w.page_begin(w.data_getName() .. " - Connections")
w.writeLn("")
if reactor == nil then
w.setColorDisabled()
w.writeLn("No Enantiomorphic reactor detected")
else
w.setColorSuccess()
w.writeLn("Enantiomorphic reactor detected")
if isBooting then
reactor_boot()
end
end
if #reactorlasers == 0 then
w.setColorDisabled()
w.writeLn("No reactor stabilisation laser detected")
elseif #reactorlasers == 1 then
w.setColorSuccess()
w.writeLn("1 reactor stabilisation laser detected")
else
w.setColorSuccess()
w.writeLn(#reactorlasers .. " reactor stabilisation lasers detected")
end
w.writeLn("")
w.setColorNormal()
w.writeLn("This is a keyboard controlled user interface.")
w.write("Key controls are written like so: ")
w.setColorControl()
w.write("Action (key)")
w.setColorNormal()
w.writeLn(".")
w.write("For example, typing ")
w.setColorControl()
w.write(" 1 ")
w.setColorNormal()
w.writeLn(" will open Reactor controls.")
end
----------- Boot sequence
w.page_setEndText(" Home (0), Reactor controls (1)")
w.page_register('0', connections_page, nil)
w.page_register('1', reactor_page, reactor_key)
reactor_register()
w.boot()
local success, message = pcall(w.run)
if not success then
print("failed with message")
print(message)
print("exiting")
else
w.close()
end

View file

@ -1,935 +0,0 @@
local component = require("component")
local computer = require("computer")
local term = require("term")
local event = require("event")
local fs = require("filesystem")
local serialization = require("serialization")
if not term.isAvailable() then
computer.beep()
return
end
Style = {
CDefault = 0xFFFFFF,
BGDefault = 0x0000FF,
CTitle = 0x000000,
BGTitle = 0x00FFFF,
CWarning = 0xFFFFFF,
BGWarning = 0xFF0000,
CSuccess = 0xFFFFFF,
BGSuccess = 0x32CD32,
CDisabled = 0x808080,
BGDisabled = 0x0000FF
}
----------- Monitor support
-- cache colors to reduce GPU load
local gpu_frontColor = 0xFFFFFF
local gpu_backgroundColor = 0x000000
function SetMonitorColorFrontBack(frontColor, backgroundColor)
if gpu_frontColor ~= frontColor then
gpu_frontColor = frontColor
component.gpu.setForeground(gpu_frontColor)
end
if gpu_backgroundColor ~= backgroundColor then
gpu_backgroundColor = backgroundColor
component.gpu.setBackground(gpu_backgroundColor)
end
end
function Write(text)
if term.isAvailable() then
local w, h = component.gpu.getResolution()
if w then
local xt, yt = term.getCursor()
component.gpu.set(xt, yt, text)
SetCursorPos(xt + #text, yt)
end
end
end
function SetCursorPos(x, y)
if term.isAvailable() then
term.setCursor(x, y)
end
end
function SetColorDefault()
SetMonitorColorFrontBack(Style.CDefault, Style.BGDefault)
end
function SetColorTitle()
SetMonitorColorFrontBack(Style.CTitle, Style.BGTitle)
end
function SetColorWarning()
SetMonitorColorFrontBack(Style.CWarning, Style.BGWarning)
end
function SetColorSuccess()
SetMonitorColorFrontBack(Style.CSuccess, Style.BGSuccess)
end
function SetColorDisabled()
SetMonitorColorFrontBack(Style.CDisabled, Style.BGDisabled)
end
function Clear()
clearWarningTick = -1
SetColorDefault()
term.clear()
SetCursorPos(1, 1)
end
function ClearLine()
SetColorDefault()
term.clearLine()
SetCursorPos(1, 1)
end
function WriteLn(text)
if term.isAvailable() then
Write(text)
local x, y = term.getCursor()
local width, height = component.gpu.getResolution()
if y > height - 1 then
y = 1
end
SetCursorPos(1, y + 1)
end
end
function WriteCentered(y, text)
if term.isAvailable() then
local sizeX, sizeY = component.gpu.getResolution()
if sizeX then
component.gpu.set((sizeX - text:len()) / 2, y, text)
end
local xt, yt = term.getCursor()
SetCursorPos(1, yt + 1)
end
end
function ShowTitle(text)
Clear()
SetColorTitle()
WriteCentered(1, text)
SetColorDefault()
end
function ShowMenu(text)
if term.isAvailable() then
Write(text)
local sizeX, sizeY = component.gpu.getResolution()
local xt, yt = term.getCursor()
for i = xt, sizeX do
Write(" ")
end
SetCursorPos(1, yt + 1)
end
end
local clearWarningTick = -1
function ShowWarning(text)
if term.isAvailable() then
local sizeX, sizeY = component.gpu.getResolution()
SetCursorPos(1, sizeY)
ClearLine()
SetColorWarning()
SetCursorPos((sizeX - text:len() - 2) / 2, sizeY)
Write(" " .. text .. " ")
SetColorDefault()
clearWarningTick = 5
end
end
function ClearWarning()
if clearWarningTick > 0 then
clearWarningTick = clearWarningTick - 1
elseif clearWarningTick == 0 then
if term.isAvailable() then
SetColorDefault()
local sizeX, sizeY = component.gpu.getResolution()
SetCursorPos(1, sizeY)
ClearLine()
clearWarningTick = -1
end
end
end
----------- Formatting & popups
function FormatFloat(value, nbchar)
local str = "?"
if value ~= nil then
str = string.format("%g", value)
end
if nbchar ~= nil then
str = string.sub(" " .. str, -nbchar)
end
return str
end
function FormatInteger(value, nbchar)
local str = "?"
if value ~= nil then
str = string.format("%d", value)
end
if nbchar ~= nil then
str = string.sub(" " .. str, -nbchar)
end
return str
end
function boolToYesNo(bool)
if bool then
return "YES"
else
return "no"
end
end
function readInputNumber(currentValue)
local inputAbort = false
local input = string.format(currentValue)
if input == "0" then
input = ""
end
local x, y = term.getCursor()
repeat
ClearWarning()
SetColorDefault()
SetCursorPos(x, y)
Write(input .. " ")
input = string.sub(input, -9)
local params = { event.pull() }
local eventName = params[1]
local address = params[2]
if address == nil then address = "none" end
if eventName == "key_down" then
local char = params[3]
local keycode = params[4]
if char >= 49 and char <= 57 then -- 1 to 9
input = input .. string.format(char - 48)
elseif keycode >= 2 and keycode <= 10 then -- 1 to 9
input = input .. string.format(keycode - 1)
elseif char == 48 or keycode == 11 then -- 0
input = input .. "0"
elseif char == 45 or char == 78 or char == 110
or keycode == 74 or keycode == 12 or keycode == 49 then -- - on numeric keypad or - on US top or n letter
if string.sub(input, 1, 1) == "-" then
input = string.sub(input, 2)
else
input = "-" .. input
end
elseif char == 43 or keycode == 78 then -- +
if string.sub(input, 1, 1) == "-" then
input = string.sub(input, 2)
end
elseif char == 8 then -- Backspace
input = string.sub(input, 1, string.len(input) - 1)
elseif char == 0 and keycode == 211 then -- Delete
input = ""
elseif char == 13 then -- Enter
inputAbort = true
elseif char ~= 0 then
ShowWarning("Key " .. char .. " " .. keycode .. " is invalid")
end
elseif eventName == "interrupted" then
inputAbort = true
elseif not common_event(eventName, params[3]) then
ShowWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
end
until inputAbort
SetCursorPos(1, y + 1)
if input == "" or input == "-" then
return currentValue
else
return tonumber(input)
end
end
function readInputText(currentValue)
local inputAbort = false
local input = string.format(currentValue)
local x, y = term.getCursor()
repeat
ClearWarning()
SetColorDefault()
SetCursorPos(x, y)
Write(input .. " ")
input = string.sub(input, -30)
local params = { event.pull() }
local eventName = params[1]
local address = params[2]
if address == nil then address = "none" end
if eventName == "key_down" then
local char = params[3]
local keycode = params[4]
if char >= 32 and char <= 127 then -- any ASCII table minus controls and DEL
input = input .. string.char(char)
elseif char == 8 then -- Backspace
input = string.sub(input, 1, string.len(input) - 1)
elseif char == 0 and keycode == 211 then -- Delete
input = ""
elseif char == 13 then -- Enter
inputAbort = true
elseif char ~= 0 then
ShowWarning("Key " .. char .. " " .. keycode .. " is invalid")
end
elseif eventName == "interrupted" then
inputAbort = true
elseif not common_event(eventName, params[3]) then
ShowWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
end
until inputAbort
SetCursorPos(1, y + 1)
if input == "" then
return currentValue
else
return input
end
end
function readConfirmation(msg)
if msg == nil then
ShowWarning("Are you sure? (y/n)")
else
ShowWarning(msg)
end
repeat
local params = { event.pull() }
local eventName = params[1]
local address = params[3]
if address == nil then address = "none" end
if eventName == "key_down" then
local char = params[3]
if char == 89 or char == 121 or keycode == 21 then -- Y
return true
else
return false
end
elseif eventName == "interrupted" then
return false
elseif not common_event(eventName, params[3]) then
ShowWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
end
until false
end
----------- commons: menu, event handlers, etc.
function common_event(eventName, param)
if eventName == "redstone" then
-- redstone_event(param)
elseif eventName == "timer" then
elseif eventName == "shipCoreCooldownDone" then
ShowWarning("Ship core cooldown done")
elseif eventName == "key_up" then
elseif eventName == "touch" then
elseif eventName == "drop" then
elseif eventName == "drag" then
elseif eventName == "component_added" then
elseif eventName == "component_removed" then
elseif eventName == "component_unavailable" then
-- ShowWarning("Event '" .. eventName .. "', " .. param .. " is unsupported")
else
return false
end
return true
end
function menu_common()
SetCursorPos(1, 23)
SetColorTitle()
ShowMenu("0 Connections, 1 Ship core, X Exit")
end
----------- Configuration
function data_save()
local file = fs.open("/disk/shipdata.txt", "w")
if file ~= nil then
file:write(serialization.serialize(data))
file:close()
else
ShowWarning("No file system")
os.sleep(3)
end
end
function data_read()
data = { }
if fs.exists("/disk/shipdata.txt") then
local file = fs.open("/disk/shipdata.txt", "r")
local size = fs.size("/disk/shipdata.txt")
local rawData = file:read(size)
if rawData ~= nil then
data = serialization.unserialize(rawData)
end
file:close()
if data == nil then data = {}; end
end
if data.core_summon == nil then data.core_summon = false; end
end
function data_setName()
if ship ~= nil then
ShowTitle("<==== Set ship name ====>")
else
ShowTitle("<==== Set name ====>")
end
SetCursorPos(1, 2)
Write("Enter ship name: ")
label = readInputText(label)
-- FIXME os.setComputerLabel(label)
if ship ~= nil then
ship.coreFrequency(label)
end
-- FIXME computer.shutdown(true)
end
function string_split(source, sep)
local sep = sep or ":"
local fields = {}
local pattern = string.format("([^%s]+)", sep)
source:gsub(pattern, function(c) fields[#fields + 1] = c end)
return fields
end
----------- Ship support
core_front = 0
core_right = 0
core_up = 0
core_back = 0
core_left = 0
core_down = 0
core_isInHyper = false
core_jumpCost = 0
core_shipSize = 0
core_movement = { 0, 0, 0 }
core_rotationSteps = 0
function core_boot()
if ship == nil then
return
end
Write("Booting Ship Core")
if data.core_summon then
ship.summon_all()
end
WriteLn("...")
core_front, core_right, core_up = ship.dim_positive()
core_back, core_left, core_down = ship.dim_negative()
core_isInHyper = ship.isInHyperspace()
core_rotationSteps = ship.rotationSteps()
core_movement = { ship.movement() }
if ship.direction ~= nil then
ship.direction(666)
ship.distance(0)
end
WriteLn("Ship core detected...")
repeat
pos = ship.position()
os.sleep(0.3)
until pos ~= nil
X, Y, Z = ship.position()
WriteLn("Ship position triangulated...")
repeat
isAttached = ship.isAttached()
os.sleep(0.3)
until isAttached ~= false
WriteLn("Ship core linked...")
repeat
core_shipSize = ship.getShipSize()
os.sleep(0.3)
until core_shipSize ~= nil
WriteLn("Ship size updated...")
ship.mode(1)
end
function core_writeMovement()
local message = " Movement = "
local count = 0
if core_movement[1] > 0 then
message = message .. core_movement[1] .. " front"
count = count + 1
elseif core_movement[1] < 0 then
message = message .. (- core_movement[1]) .. " back"
count = count + 1
end
if core_movement[2] > 0 then
if count > 0 then message = message .. ", "; end
message = message .. core_movement[2] .. " up"
count = count + 1
elseif core_movement[2] < 0 then
if count > 0 then message = message .. ", "; end
message = message .. (- core_movement[2]) .. " down"
count = count + 1
end
if core_movement[3] > 0 then
if count > 0 then message = message .. ", "; end
message = message .. core_movement[3] .. " right"
count = count + 1
elseif core_movement[3] < 0 then
if count > 0 then message = message .. ", "; end
message = message .. (- core_movement[3]) .. " left"
count = count + 1
end
if core_rotationSteps == 1 then
if count > 0 then message = message .. ", "; end
message = message .. "Turn right"
count = count + 1
elseif core_rotationSteps == 2 then
if count > 0 then message = message .. ", "; end
message = message .. "Turn back"
count = count + 1
elseif core_rotationSteps == 3 then
if count > 0 then message = message .. ", "; end
message = message .. "Turn left"
count = count + 1
end
if count == 0 then
message = message .. "(none)"
end
WriteLn(message)
end
function core_writeRotation()
if core_rotationSteps == 0 then
WriteLn(" Rotation = Front")
elseif core_rotationSteps == 1 then
WriteLn(" Rotation = Right +90")
elseif core_rotationSteps == 2 then
WriteLn(" Rotation = Back 180")
elseif core_rotationSteps == 3 then
WriteLn(" Rotation = Left -90")
end
end
function core_computeNewCoordinates(cx, cy, cz)
local res = { x = cx, y = cy, z = cz }
local dx, dy, dz = ship.getOrientation()
local worldMovement = { x = 0, y = 0, z = 0 }
worldMovement.x = dx * core_movement[1] - dz * core_movement[3]
worldMovement.y = core_movement[2]
worldMovement.z = dz * core_movement[1] + dx * core_movement[3]
core_actualDistance = math.ceil(math.sqrt(worldMovement.x * worldMovement.x + worldMovement.y * worldMovement.y + worldMovement.z * worldMovement.z))
core_jumpCost = ship.getEnergyRequired(core_actualDistance)
res.x = res.x + worldMovement.x
res.y = res.y + worldMovement.y
res.z = res.z + worldMovement.z
return res
end
function core_warp()
-- rs.setOutput(alarm_side, true)
if readConfirmation() then
-- rs.setOutput(alarm_side, false)
ship.movement(core_movement[1], core_movement[2], core_movement[3])
ship.rotationSteps(core_rotationSteps)
ship.mode(1)
ship.jump()
-- ship = nil
end
-- rs.setOutput(alarm_side, false)
end
function core_page_setMovement()
ShowTitle("<==== Set movement ====>")
SetCursorPos(1, 20)
SetColorTitle()
ShowMenu("Enter 0 to keep position on that axis")
ShowMenu("Use - or n keys to move in opposite direction")
ShowMenu("Press Enter to confirm")
SetColorDefault()
SetCursorPos(1, 3)
core_movement[1] = core_page_setDistanceAxis(2, "Forward" , "Front", "Back", core_movement[1], math.abs(core_front + core_back + 1))
core_movement[2] = core_page_setDistanceAxis(4, "Vertical", "Up" , "Down", core_movement[2], math.abs(core_up + core_down + 1))
core_movement[3] = core_page_setDistanceAxis(6, "Lateral" , "Right", "Left", core_movement[3], math.abs(core_left + core_right + 1))
core_movement = { ship.movement(core_movement[1], core_movement[2], core_movement[3]) }
end
function core_page_setDistanceAxis(line, axis, positive, negative, userEntry, shipLength)
local maximumDistance = shipLength + ship.getMaxJumpDistance()
SetColorDisabled()
SetCursorPos(3, line + 1)
Write(positive .. " is " .. ( shipLength + 1) .. ", maximum is " .. maximumDistance .. " ")
SetCursorPos(3, line + 2)
Write(negative .. " is " .. (-shipLength - 1) .. ", maximum is " .. -maximumDistance .. " ")
SetColorDefault()
repeat
SetCursorPos(1, line)
Write(axis .. " movement: ")
userEntry = readInputNumber(userEntry)
if userEntry ~= 0 and (math.abs(userEntry) <= shipLength or math.abs(userEntry) > maximumDistance) then
ShowWarning("Wrong distance. Try again.")
end
until userEntry == 0 or (math.abs(userEntry) > shipLength and math.abs(userEntry) <= maximumDistance)
SetCursorPos(1, line + 1)
ClearLine()
SetCursorPos(1, line + 2)
ClearLine()
return userEntry
end
function core_page_setRotation()
local inputAbort = false
local drun = true
repeat
ShowTitle("<==== Set rotation ====>")
core_writeRotation()
SetCursorPos(1, 21)
SetColorTitle()
ShowMenu("Use directional keys")
ShowMenu("Press Enter to confirm")
SetColorDefault()
local params = { event.pull() }
local eventName = params[1]
local address = params[2]
if address == nil then address = "none" end
if eventName == "key_down" then
local char = params[3]
local keycode = params[4]
if keycode == 200 then
core_rotationSteps = 0
elseif keycode == 203 then
core_rotationSteps = 3
elseif keycode == 205 then
core_rotationSteps = 1
elseif keycode == 208 then
core_rotationSteps = 2
elseif keycode == 28 then
inputAbort = true
else
ShowWarning("Key " .. char .. " " .. keycode .. " is invalid")
end
elseif eventName == "interrupted" then
inputAbort = true
elseif not common_event(eventName, params[3]) then
ShowWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
end
until inputAbort
core_rotationSteps = ship.rotationSteps(core_rotationSteps)
end
function core_page_setDimensions()
ShowTitle("<==== Set dimensions ====>")
Write(" Front (".. core_front ..") : ")
core_front = readInputNumber(core_front)
Write(" Right (".. core_right ..") : ")
core_right = readInputNumber(core_right)
Write(" Up (".. core_up ..") : ")
core_up = readInputNumber(core_up)
Write(" Back (".. core_back ..") : ")
core_back = readInputNumber(core_back)
Write(" Left (".. core_left ..") : ")
core_left = readInputNumber(core_left)
Write(" Down (".. core_down ..") : ")
core_down = readInputNumber(core_down)
Write("Setting dimensions...")
core_front, core_right, core_up = ship.dim_positive(core_front, core_right, core_up)
core_back, core_left, core_down = ship.dim_negative(core_back, core_left, core_down)
core_shipSize = ship.getShipSize()
if core_shipSize == nil then core_shipSize = 0 end
end
function core_page_summon()
ShowTitle("<==== Summon players ====>")
local playersString, playersArray = ship.getAttachedPlayers()
if #playersArray == 0 then
WriteLn("~ no players registered ~")
WriteLn("")
SetColorTitle()
ShowMenu("Press enter to exit")
SetColorDefault()
readInputNumber("")
return
end
for i = 1, #playersArray do
WriteLn(i .. ". " .. playersArray[i])
end
SetColorTitle()
ShowMenu("Enter player number")
ShowMenu("or press enter to summon everyone")
SetColorDefault()
Write(":")
local input = readInputNumber("")
if input == "" then
ship.summon_all()
else
input = tonumber(input)
ship.summon(input - 1)
end
end
function core_page_jumpToBeacon()
ShowTitle("<==== Jump to beacon ====>")
Write("Enter beacon frequency: ")
local freq = readInputText("")
-- rs.setOutput(alarm_side, true)
if readConfirmation() then
-- rs.setOutput(alarm_side, false)
ship.mode(4)
ship.beaconFrequency(freq)
ship.jump()
-- ship = nil
end
-- rs.setOutput(alarm_side, false)
end
function core_page_jumpToGate()
ShowTitle("<==== Jump to Jumpgate ====>")
Write("Enter jumpgate name: ")
local name = readInputText("")
-- rs.setOutput(alarm_side, true)
if readConfirmation() then
-- rs.setOutput(alarm_side, false)
ship.mode(6)
ship.targetJumpgate(name)
ship.jump()
-- ship = nil
end
-- rs.setOutput(alarm_side, false)
end
function core_page()
ShowTitle(label .. " - Ship status")
if ship ~= nil then
WriteLn("")
X, Y, Z = ship.position()
WriteLn("Core:")
WriteLn(" x, y, z = " .. X .. ", " .. Y .. ", " .. Z)
local energy, energyMax = ship.energy()
if energy == nil then energy = 0 end
if energyMax == nil then energyMax = 1 end
WriteLn(" Energy = " .. math.floor(energy / energyMax * 100) .. " % (" .. energy .. "EU)")
local playersString, playersArray = ship.getAttachedPlayers()
if playersString == "" then players = "-" end
WriteLn(" Attached players = " .. playersString)
WriteLn("")
WriteLn("Dimensions:")
WriteLn(" Front, Right, Up = " .. FormatInteger(core_front) .. ", " .. FormatInteger(core_right) .. ", " .. FormatInteger(core_up))
WriteLn(" Back, Left, Down = " .. FormatInteger(core_back) .. ", " .. FormatInteger(core_left) .. ", " .. FormatInteger(core_down))
WriteLn(" Size = " .. core_shipSize .. " blocks")
WriteLn("")
WriteLn("Warp data:")
core_writeMovement()
local dest = core_computeNewCoordinates(X, Y, Z)
WriteLn(" Distance = " .. core_actualDistance .. " (" .. core_jumpCost .. "EU, " .. math.floor(energy / core_jumpCost) .. " jumps)")
WriteLn(" Dest.coordinates = " .. FormatInteger(dest.x) .. ", " .. FormatInteger(dest.y) .. ", " .. FormatInteger(dest.z))
if data.core_summon then
WriteLn(" Summon after = Yes")
else
WriteLn(" Summon after = No")
end
else
ShowWarning("No ship controller detected")
end
SetCursorPos(1, 20)
SetColorTitle()
ShowMenu("D - Dimensions, N - set ship Name, M - set Movement")
ShowMenu("J - Jump, G - jump through Gate, B - jump to Beacon")
ShowMenu("H - Hyperspace, C - summon Crew, T - Toggle summon")
end
function core_key(char, keycode)
if char == 77 or char == 109 then -- M
core_page_setMovement()
core_page_setRotation()
return true
elseif char == 84 or char == 116 then -- T
if data.core_summon then
data.core_summon = false
else
data.core_summon = true
end
data_save()
return true
elseif char == 68 or char == 100 then -- D
core_page_setDimensions()
return true
elseif char == 74 or char == 106 then -- J
core_warp()
return true
elseif char == 67 or char == 99 or keycode == 46 then -- C
core_page_summon()
return true
elseif char == 66 or char == 98 then -- B
core_page_jumpToBeacon()
return true
elseif char == 71 or char == 103 then -- G
core_page_jumpToGate()
return true
elseif char == 72 or char == 104 then -- H
-- rs.setOutput(alarm_side, true)
if readConfirmation() then
-- rs.setOutput(alarm_side, false)
ship.mode(5)
ship.jump()
-- ship = nil
end
-- rs.setOutput(alarm_side, false)
return true
elseif char == 78 or char == 110 then -- N
data_setName()
return true
end
return false
end
----------- Boot sequence
label = computer.address()
if not label then
label = "" .. computer.address()
end
-- read configuration
data_read()
-- initial scanning
ShowTitle(label .. " - Connecting...")
WriteLn("")
-- clear previous events
repeat
until event.pull(0) == nil
ship = nil
for address, componentType in component.list() do
os.sleep(0)
Write("Checking " .. componentType .. " ")
if componentType == "warpdriveShipController" then
Write("wrapping!")
ship = component.proxy(address)
end
WriteLn("")
end
if not computer.address() and ship ~= nil then
data_setName()
end
-- peripherals status
function connections_page()
ShowTitle(label .. " - Connections")
WriteLn("")
if ship == nil then
SetColorDisabled()
WriteLn("No ship controller detected")
else
SetColorSuccess()
WriteLn("Ship controller detected")
end
WriteLn("")
SetColorTitle()
WriteLn("Please refer to below menu for keyboard controls")
WriteLn("For example, press 1 to access Ship core page")
end
-- peripheral boot up
Clear()
connections_page()
SetColorDefault()
WriteLn("")
os.sleep(0)
core_boot()
os.sleep(0)
-- main loop
abort = false
refresh = true
page = connections_page
keyHandler = nil
repeat
ClearWarning()
if refresh then
Clear()
page()
menu_common()
refresh = false
end
params = { event.pull() }
eventName = params[1]
address = params[2]
if address == nil then address = "none" end
-- WriteLn("...")
-- WriteLn("Event '" .. eventName .. "', " .. address .. ", " .. params[3] .. " received")
-- os.sleep(0.2)
if eventName == "key_down" then
char = params[3]
keycode = params[4]
if char == 88 or char == 120 or keycode == 45 then -- x for eXit
abort = true
elseif char == 48 or keycode == 11 or keycode == 82 then -- 0
page = connections_page
keyHandler = nil
refresh = true
elseif char == 49 or keycode == 2 or keycode == 79 then -- 1
page = core_page
keyHandler = core_key
refresh = true
elseif keyHandler ~= nil and keyHandler(char, keycode) then
refresh = true
os.sleep(0)
elseif char == 0 then -- control chars
refresh = false
os.sleep(0)
else
ShowWarning("Key " .. char .. " " .. keycode .. " is invalid")
os.sleep(0.2)
end
elseif eventName == "interrupted" then
abort = true
elseif not common_event(eventName, params[3]) then
ShowWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
refresh = true
os.sleep(0.2)
end
until abort
-- exiting
if data.core_summon then
data.core_summon = false
data_save()
end
if ship ~= nil then
ship.mode(0)
end
-- clear screens on exit
SetMonitorColorFrontBack(0xFFFFFF, 0x000000)
term.clear()
SetCursorPos(1, 1)
WriteLn("Program terminated")
WriteLn("Type reboot to restart it")

View file

@ -0,0 +1,680 @@
package.loaded.warpdriveCommons = nil
local w = require("warpdriveCommons")
local event = require("event")
local data
----------- Ship support
local ship_x, ship_y, ship_z = 0, 0, 0
local ship_front = 0
local ship_right = 0
local ship_up = 0
local ship_back = 0
local ship_left = 0
local ship_down = 0
local ship_isInHyper = false
local ship_jumpCost = 0
local ship_shipSize = 0
local ship_movement = { 0, 0, 0 }
local ship_rotationSteps = 0
local ship_indexPlayer = 0
local ship_indexTarget = 0
local ship = nil
function ship_read(parData)
data = parData
if data.ship_summon == nil then data.ship_summon = false; end
end
function ship_boot()
if ship == nil then
return
end
w.setColorNormal()
w.writeLn("Booting Ship")
if data.ship_summon then
ship.summon_all()
end
w.write("- internal parameters: ")
ship_front, ship_right, ship_up = ship.dim_positive()
ship_back, ship_left, ship_down = ship.dim_negative()
ship_isInHyper = ship.isInHyperspace()
ship_rotationSteps = ship.rotationSteps()
ship_movement = { ship.movement() }
if ship.direction ~= nil then
ship.direction(666)
ship.distance(0)
end
w.setColorSuccess()
w.writeLn("ok")
w.setColorNormal()
w.write("- detecting Ship Core: ")
local timeout = 10
repeat
isAttached = ship.isAttached()
w.sleep(0.05)
timeout = timeout - 1
until isAttached ~= false or timeout < 0
if timeout < 0 then
w.setColorWarning()
w.writeLn("failed")
w.writeLn("")
w.writeLn("Ship Core shall be attached horizontally")
w.writeLn("with Ship Controller!")
w.setColorNormal()
w.sleep(6)
w.reboot()
else
w.setColorSuccess()
w.writeLn("linked")
end
w.sleep(0.2)
w.setColorNormal()
w.write("- global position : ")
timeout = 10
repeat
pos = ship.position()
w.sleep(0.05)
timeout = timeout - 1
until pos ~= nil or timeout < 0
ship_x, ship_y, ship_z = ship.position()
if timeout < 0 then
w.setColorWarning()
w.writeLn("failed")
w.writeLn("")
w.writeLn("Something is wrong here, rebooting...")
w.setColorNormal()
w.sleep(2)
w.reboot()
else
w.setColorSuccess()
w.writeLn("triangulated")
end
w.sleep(0.2)
w.setColorNormal()
w.write("- integrity check : ")
timeout = 10
repeat
ship_shipSize = ship.getShipSize()
w.sleep(0.05)
timeout = timeout - 1
until ship_shipSize ~= nil or timeout < 0
if timeout < 0 then
w.setColorWarning()
w.writeLn("failed")
w.writeLn("")
w.writeLn("Ship is too big? ignoring for now...")
w.setColorNormal()
w.sleep(1)
else
w.setColorSuccess()
w.writeLn("passed")
end
ship.mode(1)
w.sleep(0.3)
end
function ship_writeMovement()
local message = " Movement = "
local count = 0
if ship_movement[1] > 0 then
message = message .. ship_movement[1] .. " front"
count = count + 1
elseif ship_movement[1] < 0 then
message = message .. (- ship_movement[1]) .. " back"
count = count + 1
end
if ship_movement[2] > 0 then
if count > 0 then message = message .. ", "; end
message = message .. ship_movement[2] .. " up"
count = count + 1
elseif ship_movement[2] < 0 then
if count > 0 then message = message .. ", "; end
message = message .. (- ship_movement[2]) .. " down"
count = count + 1
end
if ship_movement[3] > 0 then
if count > 0 then message = message .. ", "; end
message = message .. ship_movement[3] .. " right"
count = count + 1
elseif ship_movement[3] < 0 then
if count > 0 then message = message .. ", "; end
message = message .. (- ship_movement[3]) .. " left"
count = count + 1
end
if ship_rotationSteps == 1 then
if count > 0 then message = message .. ", "; end
message = message .. "Turn right"
count = count + 1
elseif ship_rotationSteps == 2 then
if count > 0 then message = message .. ", "; end
message = message .. "Turn back"
count = count + 1
elseif ship_rotationSteps == 3 then
if count > 0 then message = message .. ", "; end
message = message .. "Turn left"
count = count + 1
end
if count == 0 then
message = message .. "(none)"
end
w.writeLn(message)
end
function ship_writeRotation()
if ship_rotationSteps == 0 then
w.writeLn(" Rotation = Front ")
elseif ship_rotationSteps == 1 then
w.writeLn(" Rotation = Right +90")
elseif ship_rotationSteps == 2 then
w.writeLn(" Rotation = Back 180 ")
elseif ship_rotationSteps == 3 then
w.writeLn(" Rotation = Left -90 ")
end
end
function ship_computeNewCoordinates(cx, cy, cz)
local res = { x = cx, y = cy, z = cz }
local dx, dy, dz = ship.getOrientation()
if dx == nil then
dx, dy, dz = 0, 0, 0
end
local worldMovement = { x = 0, y = 0, z = 0 }
worldMovement.x = dx * ship_movement[1] - dz * ship_movement[3]
worldMovement.y = ship_movement[2]
worldMovement.z = dz * ship_movement[1] + dx * ship_movement[3]
ship_actualDistance = math.ceil(math.sqrt(worldMovement.x * worldMovement.x + worldMovement.y * worldMovement.y + worldMovement.z * worldMovement.z))
ship_jumpCost = ship.getEnergyRequired(ship_actualDistance)
res.x = res.x + worldMovement.x
res.y = res.y + worldMovement.y
res.z = res.z + worldMovement.z
return res
end
function ship_warp()
-- rs.setOutput(alarm_side, true)
if w.input_readConfirmation("Engage jump drive? (Y/n)") then
-- rs.setOutput(alarm_side, false)
ship.movement(ship_movement[1], ship_movement[2], ship_movement[3])
ship.rotationSteps(ship_rotationSteps)
ship.mode(1)
ship.jump()
-- ship = nil
end
-- rs.setOutput(alarm_side, false)
end
function ship_page_setMovement()
w.page_begin("<==== Set ship movement ====>")
w.setCursorPos(1, 18)
w.setColorControl()
w.writeFullLine(" Enter jump distance on each axis (0-9)")
w.writeFullLine(" Enter 0 to keep position on that axis")
w.writeFullLine(" Use - or n keys to move in opposite direction")
w.writeFullLine(" Press Enter to save your selection")
w.setColorNormal()
w.setCursorPos(1, 3)
ship_movement[1] = ship_page_setDistanceAxis(3, "Forward" , "Front", "Back", ship_movement[1], math.abs(ship_front + ship_back + 1))
ship_movement[2] = ship_page_setDistanceAxis(5, "Vertical", "Up" , "Down", ship_movement[2], math.abs(ship_up + ship_down + 1))
ship_movement[3] = ship_page_setDistanceAxis(7, "Lateral" , "Right", "Left", ship_movement[3], math.abs(ship_left + ship_right + 1))
ship_movement = { ship.movement(ship_movement[1], ship_movement[2], ship_movement[3]) }
end
function ship_page_setDistanceAxis(line, axis, positive, negative, userEntry, shipLength)
local maximumDistance = shipLength + ship.getMaxJumpDistance()
w.setColorDisabled()
w.setCursorPos(3, line + 1)
w.write(positive .. " is " .. ( shipLength + 1) .. " to " .. maximumDistance .. " blocks ")
w.setCursorPos(3, line + 2)
w.write(negative .. " is " .. (-shipLength - 1) .. " to " .. -maximumDistance .. " blocks ")
w.setColorNormal()
repeat
w.setCursorPos(1, line)
w.write(axis .. " movement: ")
userEntry = w.input_readNumber(userEntry)
if userEntry ~= 0 and (math.abs(userEntry) <= shipLength or math.abs(userEntry) > maximumDistance) then
w.status_showWarning("Wrong distance. Try again.")
end
until userEntry == 0 or (math.abs(userEntry) > shipLength and math.abs(userEntry) <= maximumDistance)
w.setCursorPos(1, line + 1)
w.clearLine()
w.setCursorPos(1, line + 2)
w.clearLine()
return userEntry
end
function ship_page_setRotation()
local inputAbort = false
local drun = true
w.page_begin("<==== Set ship rotation ====>")
w.setCursorPos(1, 19)
w.setColorControl()
w.writeFullLine(" Select ship rotation (Up, Down, Left, Right)")
w.writeFullLine(" Select Front to keep current orientation")
w.writeFullLine(" Press Enter to save your selection")
repeat
w.setCursorPos(1, 3)
w.setColorNormal()
ship_writeRotation()
local params = { event.pull() }
local eventName = params[1]
local address = params[2]
if address == nil then address = "none" end
local firstParam = params[3]
if firstParam == nil then firstParam = "none" end
if eventName == "key_down" then
local character = string.char(params[3])
local keycode = params[4]
if keycode == 200 then
ship_rotationSteps = 0
elseif keycode == 203 then
ship_rotationSteps = 3
elseif keycode == 205 then
ship_rotationSteps = 1
elseif keycode == 208 then
ship_rotationSteps = 2
elseif keycode == 28 then
inputAbort = true
else
w.status_showWarning("Key " .. keycode .. " is invalid")
end
elseif eventName == "interrupted" then
inputAbort = true
elseif not w.event_handler(eventName, params[2]) then
w.status_showWarning("Event '" .. eventName .. "', " .. address .. " is unsupported")
end
until inputAbort
ship_rotationSteps = ship.rotationSteps(ship_rotationSteps)
end
function ship_page_setDimensions()
w.page_begin("<==== Set ship dimensions ====>")
w.setCursorPos(1, 18)
w.setColorControl()
w.writeFullLine(" Enter ship size in blocks (0-9)")
w.writeFullLine(" First block next to Ship counts as 1")
w.writeFullLine(" Ship controller counts as 'Front = 1'")
w.writeFullLine(" Press Enter to save your selection")
w.setCursorPos(1, 3)
w.setColorNormal()
w.write(" Front (".. ship_front ..") : ")
ship_front = w.input_readNumber(ship_front)
w.write(" Right (".. ship_right ..") : ")
ship_right = w.input_readNumber(ship_right)
w.write(" Up (".. ship_up ..") : ")
ship_up = w.input_readNumber(ship_up)
w.write(" Back (".. ship_back ..") : ")
ship_back = w.input_readNumber(ship_back)
w.write(" Left (".. ship_left ..") : ")
ship_left = w.input_readNumber(ship_left)
w.write(" Down (".. ship_down ..") : ")
ship_down = w.input_readNumber(ship_down)
w.write("Setting dimensions...")
ship_front, ship_right, ship_up = ship.dim_positive(ship_front, ship_right, ship_up)
ship_back, ship_left, ship_down = ship.dim_negative(ship_back, ship_left, ship_down)
ship_shipSize = ship.getShipSize()
if ship_shipSize == nil then ship_shipSize = 0 end
end
function ship_page_summon() -- no longer used
w.page_begin("<==== Summon players ====>")
local stringPlayers, arrayPlayers = ship.getAttachedPlayers()
if stringPlayers == nil or #arrayPlayers == 0 then
w.writeLn("~ no players registered ~")
w.writeLn("")
w.setColorControl()
w.writeFullLine("Press enter to exit")
w.setColorNormal()
w.input_readNumber("")
return
end
for i = 1, #arrayPlayers do
w.writeLn(i .. ". " .. arrayPlayers[i])
end
w.setColorControl()
w.writeFullLine("Enter player number")
w.writeFullLine("or press enter to summon everyone")
w.setColorNormal()
w.write(":")
local input = w.input_readNumber("")
if input == "" then
ship.summon_all()
else
input = tonumber(input)
ship.summon(input - 1)
end
end
function ship_page_jumpToBeacon()
w.page_begin("<==== Jump to beacon ====>")
w.write("Enter beacon frequency: ")
local freq = w.input_readText("")
-- rs.setOutput(alarm_side, true)
if w.input_readConfirmation() then
-- rs.setOutput(alarm_side, false)
ship.mode(4)
ship.beaconFrequency(freq)
ship.jump()
-- ship = nil
end
-- rs.setOutput(alarm_side, false)
end
function ship_page_jumpToGate()
w.page_begin("<==== Jump through Jumpgate ====>")
w.writeLn("")
w.writeLn("Your ship should be already inside a jumpgate")
w.setCursorPos(1, 20)
w.setColorControl()
w.writeFullLine("Enter target jumpgate name (a-z, 0-9)")
w.writeFullLine("Press enter to save jumpgate name")
w.setCursorPos(1, 5)
w.setColorNormal()
w.write("Target jumpgate name: ")
local name = w.input_readText("")
-- rs.setOutput(alarm_side, true)
if w.input_readConfirmation("Engage gate jumping? (Y/n)") then
-- rs.setOutput(alarm_side, false)
ship.mode(6)
ship.targetJumpgate(name)
ship.jump()
-- ship = nil
end
-- rs.setOutput(alarm_side, false)
end
function ship_page_controls()
w.page_begin(w.data_getName() .. " - Ship controls")
if ship == nil then
w.status_showWarning("No ship controller detected")
elseif ship.isAttached() ~= true then
w.status_showWarning("No ship core detected")
else
-- w.writeLn("")
ship_x, ship_y, ship_z = ship.position()
if ship_x == nil then
ship_x, ship_y, ship_z = 0, 0, 0
end
w.writeLn("Ship:")
w.writeLn(" Current position = " .. ship_x .. ", " .. ship_y .. ", " .. ship_z)
local energy, energyMax = ship.energy()
if energy == nil then energy = 0 end
if energyMax == nil or energyMax == 0 then energyMax = 1 end
w.writeLn(" Energy = " .. math.floor(energy / energyMax * 100) .. " % (" .. energy .. " EU)")
w.writeLn("")
-- w.writeLn("")
w.writeLn("Dimensions:")
w.writeLn(" Front, Right, Up = " .. w.format_integer(ship_front) .. ", " .. w.format_integer(ship_right) .. ", " .. w.format_integer(ship_up) .. " blocks")
w.writeLn(" Back, Left, Down = " .. w.format_integer(ship_back) .. ", " .. w.format_integer(ship_left) .. ", " .. w.format_integer(ship_down) .. " blocks")
w.writeLn(" Size = " .. ship_shipSize .. " blocks")
w.writeLn("")
w.writeLn("Warp data:")
ship_writeMovement()
local dest = ship_computeNewCoordinates(ship_x, ship_y, ship_z)
w.writeLn(" Distance = " .. ship_actualDistance .. " (" .. ship_jumpCost .. " EU, " .. math.floor(energy / ship_jumpCost) .. " jumps)")
w.writeLn(" Target position = " .. w.format_integer(dest.x) .. ", " .. w.format_integer(dest.y) .. ", " .. w.format_integer(dest.z))
end
w.setCursorPos(1, 20)
w.setColorControl()
w.writeFullLine(" set ship Name (N), Dimensions (D), Movement (M)")
if ship_isInHyper then
w.writeFullLine(" Jump to move ship (M/J), exit Hyperspace (H)")
else
w.writeFullLine(" Jump to move ship (M/J), enter Hyperspace (H)")
end
end
function ship_key_controls(character, keycode)
if character == 'm' or character == 'M' then -- M
ship_page_setMovement()
ship_page_setRotation()
ship_warp()
return true
elseif character == 'd' or character == 'D' then -- D
ship_page_setDimensions()
return true
elseif character == 'j' or character == 'J' then -- J
ship_warp()
return true
elseif character == 'h' or character == 'H' then -- H
-- rs.setOutput(alarm_side, true)
if w.input_readConfirmation("Engage hyperdrive? (Y/n)") then
-- rs.setOutput(alarm_side, false)
ship.mode(5)
ship.jump()
-- ship = nil
end
-- rs.setOutput(alarm_side, false)
return true
elseif character == 'n' or character == 'N' then
w.data_setName()
return true
end
return false
end
function ship_writeArray(arrayValues, indexSelected)
if indexSelected then
indexSelected = (indexSelected + #arrayValues) % #arrayValues
end
local indexSplit = math.ceil(#arrayValues / 2)
for i = 1, indexSplit do
if indexSelected and i == indexSelected + 1 then
w.setColorSelected()
w.write(">" .. string.sub(arrayValues[i] .. " ", 1, 24))
w.setColorNormal()
else
w.write(" " .. string.sub(arrayValues[i] .. " ", 1, 24))
end
if arrayValues[i + indexSplit] ~= nil then
if indexSelected and i + indexSplit == indexSelected + 1 then
w.setColorSelected()
w.writeLn(">" .. string.sub(arrayValues[i + indexSplit] .. " ", 1, 24))
w.setColorNormal()
else
w.writeLn(" " .. arrayValues[i + indexSplit])
end
else
w.writeLn("")
end
end
return indexSelected
end
function ship_page_crew()
w.page_begin(w.data_getName() .. " - Ship crew")
if ship == nil then
w.status_showWarning("No ship controller detected")
elseif ship.isAttached() ~= true then
w.status_showWarning("No ship core detected")
else
w.writeLn("Attached players:")
local stringPlayers, _ = ship.getAttachedPlayers()
if stringPlayers == nil or stringPlayers == "" then
stringPlayers = "~ no registered player ~"
end
local arrayPlayers = w.data_splitString(stringPlayers, ",")
ship_indexPlayer = ship_writeArray(arrayPlayers, ship_indexPlayer)
w.writeLn("")
w.writeLn("Summon crew after short jump = " .. w.format_boolean(data.ship_summon, "YES", "no"))
-- w.writeLn("")
-- w.writeLn("Beacon jump: -admin only-")
end
w.setCursorPos(1, 20)
w.setColorControl()
w.writeFullLine(" Summon all crew (S), Toggle summon after jump (T)")
w.writeFullLine(" select crew (arrows), summon selected crew (enter)")
end
function ship_key_crew(character, keycode)
if character == 't' or character == 'T' then -- T
if data.ship_summon then
data.ship_summon = false
else
data.ship_summon = true
end
w.data_save()
return true
elseif character == 's' or character == 'S' then -- S
ship.summon_all()
return true
elseif keycode == 28 then -- Enter
local success, namePlayer = ship.summon(ship_indexPlayer)
if success then
w.status_showSuccess("Engaging teleportation for " .. namePlayer .. "...")
else
w.status_showWarning("Failed to summon crew member")
end
return true
elseif character == 'g' or character == 'G' then -- G
ship_page_jumpToGate()
return true
elseif keycode == 200 or keycode == 203 or character == '-' then -- Up or Left or -
ship_indexPlayer = ship_indexPlayer - 1
return true
elseif keycode == 208 or keycode == 205 or character == '+' then -- Down or Right or +
ship_indexPlayer = ship_indexPlayer + 1
return true
end
return false
end
function ship_page_navigation()
w.page_begin(w.data_getName() .. " - Ship navigation")
if ship == nil then
w.status_showWarning("No ship controller detected")
elseif ship.isAttached() ~= true then
w.status_showWarning("No ship core detected")
else
local locationCurrent = "somewhere..." -- @TODO ship.getLocation()
w.writeLn("Current ship location : " .. locationCurrent)
w.writeLn("Jumpgates or beacons in range:")
local stringTargets, _ = "not implemented" -- ship.getTargets()
if stringTargets == nil or stringTargets == "" then
stringTargets = "~ no beacon nor jumpgate in range ~"
end
local arrayTargets = w.data_splitString(stringTargets, ",")
ship_indexTarget = ship_writeArray(arrayTargets, ship_indexTarget)
-- w.writeLn("")
-- w.writeLn("Beacon jump: -admin only-")
end
w.setCursorPos(1, 20)
w.setColorControl()
w.writeFullLine(" select target (arrows), register target (enter)")
w.writeFullLine(" jump through Gate (G)")
end
function ship_key_navigation(character, keycode)
if keycode == 28 then -- Enter
-- local success, xxx = ship.xxx(ship_indexTarget)
-- if success then
-- w.status_showSuccess("Engaging jumpgate jump to " .. xxx .. "...")
-- else
-- w.status_showWarning("Failed to summon crew member")
-- end
return true
-- elseif character == 'b' or character == 'B' then -- B
-- ship_page_jumpToBeacon()
-- return true
elseif character == 'g' or character == 'G' then -- G
ship_page_jumpToGate()
return true
elseif keycode == 200 or keycode == 203 or character == '-' then -- Up or Left or -
ship_indexTarget = ship_indexTarget - 1
return true
elseif keycode == 208 or keycode == 205 or character == '+' then -- Down or Right or +
ship_indexTarget = ship_indexTarget + 1
return true
end
return false
end
function ship_register()
w.device_register("warpdriveShipController",
function(deviceType, address, wrap) ship = wrap end,
function() end)
w.event_register("shipCoreCooldownDone" , function() w.status_showWarning("Ship core cooldown done") return false end )
w.data_register("ship", ship_read, nil)
end
----------- connections status
function connections_page(isBooting)
w.page_begin(w.data_getName() .. " - Connections")
w.writeLn("")
if ship == nil then
w.setColorDisabled()
w.writeLn("No ship controller detected")
else
w.setColorSuccess()
w.writeLn("Ship controller detected")
if isBooting then
ship_boot()
end
end
w.writeLn("")
w.setColorNormal()
w.writeLn("This is a keyboard controlled user interface.")
w.write("Key controls are written like so: ")
w.setColorControl()
w.write("Action (key)")
w.setColorNormal()
w.writeLn(".")
w.write("For example, typing ")
w.setColorControl()
w.write(" 1 ")
w.setColorNormal()
w.writeLn(" will open Ship controls.")
end
----------- Boot sequence
w.page_setEndText(" Home (0), Controls (1), Crew (2), Navigation (3)")
w.page_register('0', connections_page, nil)
w.page_register('1', ship_page_controls, ship_key_controls)
w.page_register('2', ship_page_crew, ship_key_crew)
w.page_register('3', ship_page_navigation, ship_key_navigation)
ship_register()
w.boot()
w.run()
if data.ship_summon then
data.ship_summon = false
w.data_save()
end
if ship ~= nil then
ship.mode(0)
end
w.close()

View file

@ -0,0 +1,887 @@
package.loaded.warpdriveCommons = nil
local w = require("warpdriveCommons")
local data
----------- Attack lasers support
local laser_batteryIndex = 1
local laser_batteries = {}
local laser_stationIndex = 1
local laser_stations = {}
local laserAddresses = {}
local lasercamAddresses = {}
function laser_save(parData)
-- rebuild a clean structure, skipping the device objects
data.laser_batteries = {}
for keyBattery, laserbattery in pairs(laser_batteries) do
data.laser_batteries[keyBattery] = {
name = laserbattery.name,
frequency = laserbattery.frequency,
headAddress = laserbattery.headAddress,
boosterAddresses = laserbattery.boosterAddresses }
end
data.laser_stations = {}
for keyStation, laserstation in pairs(laser_stations) do
data.laser_stations[keyStation] = {
name = laserstation.name,
cameraAddress = laserstation.cameraAddress,
batteries = {}}
for keyBattery, laserbattery in pairs(laser_stations[keyStation].batteries) do
data.laser_stations[keyStation].batteries[keyBattery] = {
name = laserbattery.name,
enabled = laserbattery.enabled }
end
end
end
function laser_read(parData)
data = parData
if data.laser_batteries == nil then data.laser_batteries = {}; end
laser_batteries = data.laser_batteries
for keyBattery, laserbattery in pairs(laser_batteries) do
if laserbattery.headAddress ~= nil then
laserbattery.head = w.device_get(laserbattery.headAddress)
end
if laserbattery.name == nil then
laserbattery.name = "noname"
end
if laserbattery.boosterAddresses == nil then
laserbattery.boosterAddresses = {}
end
laserbattery.boosters = {}
for boosterKey, boosterAddress in pairs(laserbattery.boosterAddresses) do
laserbattery.boosters[boosterKey] = w.device_get(boosterAddress)
end
end
if data.laser_stations == nil then data.laser_stations = {}; end
laser_stations = data.laser_stations
for keyStation, laserstation in pairs(laser_stations) do
if laserstation.cameraAddress ~= nil then
laserstation.camera = w.device_get(laserstation.cameraAddress)
end
if laserstation.name == nil then
laserstation.name = "noname"
end
if laserstation.batteries == nil then
laserstation.batteries = {}
end
end
if data.laser_firingMode == nil then data.laser_firingMode = "boosted"; end
if data.laser_firingScatter == nil then data.laser_firingScatter = false; end
end
function laser_getDescription(address)
if address == nil then
return "~not defined~"
end
local laser = w.device_get(address)
if laser == nil or laser.position == nil then
return "~invalid~"
end
local x, y, z = laser.position()
return "@ " .. w.format_integer(x, 7) .. " " .. w.format_integer(y, 3) .. " " .. w.format_integer(z, 7)
end
function laser_getName(address)
return address
end
function laser_battery_key(character, keycode)
if character == 'a' or character == 'A' then -- A or keycode == 30
table.insert(laser_batteries, {
name = "noname",
frequency = -1,
headAddress = nil,
boosterAddresses = {},
head = nil,
boosters = {} })
laser_batteryIndex = #laser_batteries
laser_battery_linkLasers()
laser_battery_config()
w.data_save()
return true
elseif character == 'r' or character == 'R' then -- R or keycode == 19
table.remove(laser_batteries, laser_batteryIndex)
-- laser_batteryIndex = laser_batteryIndex - 1
w.data_save()
return true
elseif character == 'f' or character == 'F' then -- F or keycode == 33
if data.laser_firingMode == "boosted" then data.laser_firingMode = "single"
elseif data.laser_firingMode == "single" then data.laser_firingMode = "multi"
elseif data.laser_firingMode == "multi" then data.laser_firingMode = "boosted" end
w.data_save()
return true
elseif character == 's' or character == 'S' then -- S or keycode == 31
data.laser_firingScatter = not data.laser_firingScatter
w.data_save()
return true
elseif character == 'l' or character == 'L' then -- L or keycode == 38
laser_battery_linkLasers()
w.data_save()
return true
elseif character == 'c' or character == 'C' then -- C or keycode == 46
laser_battery_config()
w.data_save()
return true
elseif keycode == 200 or keycode == 203 or character == '-' then -- Up or Left or -
laser_batteryIndex = laser_batteryIndex - 1
return true
elseif keycode == 208 or keycode == 205 or character == '+' then -- Down or Right or +
laser_batteryIndex = laser_batteryIndex + 1
return true
end
return false
end
function laser_battery_getCurrent()
if laser_batteries ~= nil then
if laser_batteryIndex > #laser_batteries then
laser_batteryIndex = 1
elseif laser_batteryIndex < 1 then
laser_batteryIndex = #laser_batteries
end
return laser_batteries[laser_batteryIndex]
else
return nil
end
end
function laser_battery_getByName(name)
if laser_batteries ~= nil and name ~= nil then
for key, laserbattery in pairs(laser_batteries) do
if laserbattery.name == name then
return laserbattery
end
end
end
return { frequency = -1, boosterAddresses = {}, name = "-not defined-", boosters = {} }
end
function laser_battery_page()
w.page_begin(w.data_getName() .. " - Laser batteries")
local laserbattery = laser_battery_getCurrent()
-- w.setCursorPos(1, 2)
if #laser_batteries == 0 then
w.setColorDisabled()
w.writeCentered(2, "No laser battery defined, press A to add one")
elseif laserbattery == nil then
w.setColorWarning()
w.writeCentered(2, "Laser battery " .. laser_batteryIndex .. " of " .. #laser_batteries .. " is not defined")
else
w.setColorNormal()
w.writeCentered(2, "'" .. laserbattery.name .. "' (" .. laser_batteryIndex .. " of " .. #laser_batteries .. ")")
w.setCursorPos(1, 3)
local headX = 0
local headY = 0
local headZ = 0
local headFrequency = -1
if laserbattery.head == nil then
w.setColorDisabled()
w.write("Laser head is not defined, press L to link one")
else
w.setColorNormal()
headX, headY, headZ = laserbattery.head.position()
headFrequency = laserbattery.head.beamFrequency()
w.writeLn("Laser head:")
if headFrequency == -1 then
w.setColorWarning()
end
w.write(w.format_integer(headFrequency, 5))
w.setColorNormal()
w.write(" @ " .. w.format_integer(headX, 7) .. " " .. w.format_integer(headY, 3) .. " " .. w.format_integer(headZ, 7)
.. " " .. string.sub(laserbattery.headAddress, 10, 100))
end
w.setCursorPos(1, 5)
if laserbattery.boosters == nil or #laserbattery.boosters == 0 then
w.setColorDisabled()
w.write("Boosting lasers aren't set, press L to link one")
else
w.setColorNormal()
w.write("Boosting lasers:")
for key, booster in pairs(laserbattery.boosters) do
w.setCursorPos(1, 5 + key)
local x, y, z = booster.position()
if booster.beamFrequency() == headFrequency and headFrequency ~= -1 then
w.setColorNormal()
else
w.setColorWarning()
end
w.write(w.format_integer(booster.beamFrequency(), 5))
w.setColorNormal()
w.write(" @ " .. w.format_integer(x - headX, 7) .. " " .. w.format_integer(y - headY, 3) .. " " .. w.format_integer(z - headZ, 7)
.. " " .. string.sub(laserbattery.boosterAddresses[key], 10, 100))
end
end
end
w.setColorNormal()
w.setCursorPos(1, 14)
w.write(" -----------------------------------------------")
w.setCursorPos(1, 16)
w.write(" Firing mode: " .. data.laser_firingMode)
w.setCursorPos(30, 16)
w.write("Scatter mode: ")
if data.laser_firingScatter then
w.setColorSuccess()
w.write("ON")
w.setColorNormal()
else
w.write("off")
end
w.setColorControl()
w.setCursorPos(1, 19)
w.writeFullLine(" Add/Remove/Configure selected battery (A/R/C)")
w.writeFullLine(" select battery (Arrows), Link lasers (L)")
w.writeFullLine(" change Firing mode (F), toggle Scatter mode (S)")
end
function laser_battery_config()
local laserbattery = laser_battery_getCurrent()
if laserbattery == nil then
return
end
w.page_begin(w.data_getName() .. " - Laser battery configuration")
w.setColorNormal()
w.setCursorPos(1, 3)
w.writeLn("Battery name (" .. laserbattery.name .. "):")
laserbattery.name = w.input_readText(laserbattery.name)
w.setCursorPos(1, 3)
w.clearLine()
w.writeLn("Battery name set to " .. laserbattery.name)
w.clearLine()
if laserbattery.head == nil then
return
end
w.setColorDisabled()
w.setCursorPos(1, 4)
local headX, headY, headZ = laserbattery.head.position()
local headFrequency = laserbattery.head.beamFrequency()
w.write("@ " .. w.format_integer(headX, 7) .. " " .. w.format_integer(headY, 3) .. " " .. w.format_integer(headZ, 7))
w.setCursorPos(1, 5)
w.write("With " .. #laserbattery.boosters .. " boosters")
w.setCursorPos(1, 8)
w.setColorDisabled()
w.write(" Valid values are 0 to 65000 ")
w.setColorNormal()
local frequency
repeat
w.setCursorPos(1, 7)
w.clearLine()
w.write("Battery beam frequency (" .. w.format_integer(headFrequency, 5) .. "): ")
frequency = w.input_readNumber(headFrequency)
if frequency ~= 0 and (frequency < 0 or frequency > 65000) then
w.status_showWarning("This is not a valid beam frequency. Try again.")
end
until frequency > 0 and frequency <= 65000
w.setCursorPos(1, 8)
w.clearLine()
w.setCursorPos(1, 8)
w.clearLine()
local newFrequency = laserbattery.head.beamFrequency(frequency)
w.write("Head beam frequency set to " .. newFrequency)
for key, booster in pairs(laserbattery.boosters) do
w.setCursorPos(1, 8 + (key % 5))
newFrequency = booster.beamFrequency(frequency)
w.write("Booster beam frequency set to " .. newFrequency)
end
end
function laser_battery_linkLasers()
local laserbattery = laser_battery_getCurrent()
if laserbattery == nil then
return
end
w.page_begin(w.data_getName() .. " - Linking lasers")
w.setColorDisabled()
w.setCursorPos(1, 3)
w.writeLn("Help: Use arrows to select lasers.")
w.writeLn("Press backspace/delete to remove laser.")
w.writeLn("Press enter to validate.")
w.writeLn("Validate with '-no laser-' to stop adding lasers.")
w.setColorNormal()
if laserbattery.boosters == nil then
laserbattery.boosters = {}
end
w.writeCentered(2, "Battery '" .. laserbattery.name .. "' with " .. #laserbattery.boosters .. " boosters")
local laserAddresses_left = {}
for keyAddress, laserAddress in pairs(laserAddresses) do
laserAddresses_left[keyAddress] = laserAddress
end
w.setCursorPos(1, 8)
if laserbattery.headAddress == nil then
w.writeLn("Laser head (not defined): ")
else
w.writeLn("Laser head (" .. laserbattery.headAddress .. "): ")
end
laserbattery.headAddress = w.input_readEnum(laserbattery.headAddress, laserAddresses_left, laser_getName, laser_getDescription, "-no laser-")
w.setColorNormal()
w.setCursorPos(1, 8)
w.clearLine()
if laserbattery.headAddress == nil then
w.writeLn("Laser head set to (not defined)")
laserbattery.head = nil
else
-- remove selected laser from potentials
for keyLaser, laserAddress in pairs(laserAddresses_left) do
if laser_getName(laserAddress) == laserbattery.headAddress then
table.remove(laserAddresses_left, keyLaser)
break
end
end
w.writeLn("Laser head set to " .. laserbattery.headAddress)
laserbattery.head = w.device_get(laserbattery.headAddress)
w.setColorDisabled()
w.setCursorPos(1, 9)
local headX, headY, headZ = laserbattery.head.position()
local headFrequency = laserbattery.head.beamFrequency()
w.write("@ " .. w.format_integer(headX, 7) .. " " .. w.format_integer(headY, 3) .. " " .. w.format_integer(headZ, 7))
end
local key = 1
local addressCurrent = nil
repeat
w.setColorNormal()
w.setCursorPos(1, 10 + (key % 5))
w.write("Booster #" .. key)
addressCurrent = nil
if key <= #laserbattery.boosterAddresses then
addressCurrent = laserbattery.boosterAddresses[key]
w.write(" (" .. addressCurrent .. "): ")
else
w.write(" (-no laser-): ")
end
addressCurrent = w.input_readEnum(addressCurrent, laserAddresses_left, laser_getName, laser_getDescription, "-no laser-")
if addressCurrent == nil then
if key > #laserbattery.boosterAddresses then
key = -1
else
table.remove(laserbattery.boosterAddresses, key)
table.remove(laserbattery.boosters, key)
w.success("Removed")
end
else
-- remove selected laser from potentials
for keyLaser, laserAddress in pairs(laserAddresses_left) do
if laser_getName(laserAddress) == addressCurrent then
table.remove(laserAddresses_left, keyLaser)
break
end
end
laserbattery.boosterAddresses[key] = addressCurrent
laserbattery.boosters[key] = w.device_get(addressCurrent)
w.setColorNormal()
w.setCursorPos(1, 10 + (key % 5))
w.clearLine()
w.write("Booster #" .. key .. " set to " .. addressCurrent)
key = key + 1
end
until key == -1
end
function laser_battery_getName(laserbattery)
return laserbattery.name
end
function laser_battery_getDescription(laserbattery)
local msg = ""
local x, y, z
local found = false
if laserbattery.head == nil then
msg = msg .. 0
else
x, y, z = laserbattery.head.position()
found = true
msg = msg .. 1
end
msg = msg .. "+"
if laserbattery.boosters == nil then
msg = msg .. 0
else
msg = msg .. #laserbattery.boosters
if not found then
for key, booster in pairs(laserbattery.boosters) do
if booster ~= nil and not found then
x, y, z = booster.position()
found = true
end
end
end
end
return string.sub(laserbattery.name .. " ", 1, 20)
.. msg
.. " @ " .. w.format_integer(x, 7) .. " " .. w.format_integer(y, 3) .. " " .. w.format_integer(z, 7)
end
function laser_station_key(character, keycode)
if character == 'a' or character == 'A' then -- A or keycode == 30
table.insert(laser_stations, { name = "noname", cameraFrequency = -1, camera = nil, batteries = {} })
laser_stationIndex = #laser_stations
laser_station_linkBatteries()
laser_station_config()
w.data_save()
return true
elseif character == 'r' or character == 'R' then -- R or keycode == 19
table.remove(laser_stations, laser_stationIndex)
-- laser_stationIndex = laser_stationIndex - 1
w.data_save()
return true
elseif character == 'f' or character == 'F' then -- F or keycode == 33
if data.laser_firingMode == "boosted" then data.laser_firingMode = "single"
elseif data.laser_firingMode == "single" then data.laser_firingMode = "multi"
elseif data.laser_firingMode == "multi" then data.laser_firingMode = "boosted" end
w.data_save()
return true
elseif character == 's' or character == 'S' then -- S or keycode == 31
data.laser_firingScatter = not data.laser_firingScatter
w.data_save()
return true
elseif character == 'l' or character == 'L' then -- L or keycode == 38
laser_station_linkBatteries()
w.data_save()
return true
elseif character == 'c' or character == 'C' then -- C or keycode == 46
laser_station_config()
w.data_save()
return true
elseif keycode == 200 or keycode == 203 or character == '-' then -- Up or Left or -
laser_stationIndex = laser_stationIndex - 1
return true
elseif keycode == 208 or keycode == 205 or character == '+' then -- Down or Right or +
laser_stationIndex = laser_stationIndex + 1
return true
end
return false
end
function laser_station_getCurrent()
if laser_stations ~= nil then
if laser_stationIndex > #laser_stations then
laser_stationIndex = 1
elseif laser_stationIndex < 1 then
laser_stationIndex = #laser_stations
end
return laser_stations[laser_stationIndex]
else
return nil
end
end
function laser_station_page()
w.page_begin(w.data_getName() .. " - Laser stations")
local laserstation = laser_station_getCurrent()
-- w.setCursorPos(1, 2)
if #laser_stations == 0 then
w.setColorDisabled()
w.writeCentered(2, "No laser stations configured")
elseif laserstation == nil then
w.setColorWarning()
w.writeCentered(2, "Laser station " .. laser_stationIndex .. " of " .. #laser_stations .. " is invalid")
else
w.setColorNormal()
w.writeCentered(2, "'" .. laserstation.name .. "' (" .. laser_stationIndex .. " of " .. #laser_stations .. ")")
w.setCursorPos(1, 3)
if laserstation.camera == nil then
w.setColorDisabled()
w.write("Laser camera is not defined, press L to link one")
else
w.setColorNormal()
local camX, camY, camZ = laserstation.camera.position()
local camVideoChannel = laserstation.camera.videoChannel()
w.writeLn("Laser camera:")
if camVideoChannel == -1 then
w.setColorWarning()
end
w.write(w.format_integer(camVideoChannel, 5))
w.setColorNormal()
w.write(" @ " .. w.format_integer(camX, 7) .. " " .. w.format_integer(camY, 3) .. " " .. w.format_integer(camZ, 7)
.. " " .. string.sub(laserstation.cameraAddress, 10, 100))
end
w.setCursorPos(1, 5)
if laserstation.batteries == nil or #laserstation.batteries == 0 then
w.setColorDisabled()
w.write("Laser batteries aren't set, press L to link one")
else
w.setColorNormal()
w.write("Laser batteries:")
for key, battery in pairs(laserstation.batteries) do
w.setCursorPos(1, 5 + key)
laserbattery = laser_battery_getByName(battery.name)
if battery.enabled then
w.setColorSuccess()
else
w.setColorDisabled()
end
w.write(laser_battery_getDescription(laserbattery))
end
end
end
w.setColorNormal()
w.setCursorPos(1, 14)
w.write(" -----------------------------------------------")
w.setCursorPos(1, 16)
w.write(" Firing mode: " .. data.laser_firingMode)
w.setCursorPos(30, 16)
w.write("Scatter mode: ")
if data.laser_firingScatter then
w.setColorSuccess()
w.write("ON")
w.setColorNormal()
else
w.write("off")
end
w.setColorControl()
w.setCursorPos(1, 19)
w.writeFullLine(" Add/Remove/Configure laser station (A/R/C)")
w.writeFullLine(" select station (Arrows), Link batteries (L)")
w.writeFullLine(" change Firing mode (F), toggle Scatter mode (S)")
end
function laser_station_config()
local laserstation = laser_station_getCurrent()
if laserstation == nil then
return
end
w.page_begin(w.data_getName() .. " - Laser station configuration")
w.setColorNormal()
w.setCursorPos(1, 3)
w.writeLn("Laser station name (" .. laserstation.name .. "):")
laserstation.name = w.input_readText(laserstation.name)
w.setCursorPos(1, 3)
w.clearLine()
w.writeLn("Laser station name set to " .. laserstation.name)
w.clearLine()
if laserstation.camera == nil then
return
end
w.setCursorPos(1, 5)
local camX, camY, camZ = laserstation.camera.position()
local camVideoChannel = laserstation.camera.videoChannel()
w.write("Camera @ " .. w.format_integer(camX, 7) .. " " .. w.format_integer(camY, 3) .. " " .. w.format_integer(camZ, 7))
w.setCursorPos(1, 6)
w.write("With " .. #laserstation.batteries .. " batteries")
w.setCursorPos(1, 8)
w.setColorDisabled()
w.write(" Valid values are 0 to 268435455 ")
w.setColorNormal()
local channel
repeat
w.setCursorPos(1, 7)
w.write("Camera video frequency (" .. w.format_integer(camVideoChannel, 5) .. "): ")
channel = w.input_readNumber(camVideoChannel)
if channel ~= 0 and (channel < 0 or channel > 268435455) then
w.status_showWarning("This is not a valid video channel. Try again.")
end
until channel > 0 and channel <= 268435455
w.setCursorPos(1, 8)
w.clearLine()
w.setCursorPos(1, 7)
w.clearLine()
local newVideoChannel = laserstation.camera.videoChannel(channel)
laserstation.camera.beamFrequency(1420)
w.write("Camera video channel set to " .. newVideoChannel)
w.setCursorPos(1, 11)
w.write("Battery enabling: ")
for key, battery in pairs(laserstation.batteries) do
laserbattery = laser_battery_getByName(battery.name)
local msg = laser_battery_getDescription(laserbattery)
w.setCursorPos(1, 11 + (key % 5))
if battery.enabled then
w.setColorSuccess()
w.write(msg)
battery.enabled = w.input_readConfirmation("Keep battery '" .. battery.name .. "' enabled? (Y/n)")
else
w.setColorDisabled()
w.write(msg)
battery.enabled = w.input_readConfirmation("Enable battery '" .. battery.name .. "'? (Y/n)")
end
w.setCursorPos(1, 11 + (key % 5))
if battery.enabled then
w.setColorSuccess()
w.write(msg)
else
w.setColorDisabled()
w.write(msg)
end
end
end
function laser_station_linkBatteries()
local laserstation = laser_station_getCurrent()
if laserstation == nil then
return
end
w.page_begin(w.data_getName() .. " - Linking batteries")
w.setColorDisabled()
w.setCursorPos(1, 3)
w.writeLn("Instruction: use arrows to select batteries.")
w.writeLn("Press backspace/delete to remove battery.")
w.writeLn("Press enter to validate.")
w.writeLn("Validate '-no battery-' to stop adding batteries.")
w.setColorNormal()
if laserstation.batteries == nil then
laserstation.batteries = {}
end
w.writeCentered(2, "Station '" .. laserstation.name .. "' with " .. #laserstation.batteries .. " batteries linked")
w.setCursorPos(1, 8)
if laserstation.cameraAddress == nil then
w.writeLn("Laser camera (not defined): ")
else
w.writeLn("Laser camera (" .. laserstation.cameraAddress .. "): ")
end
laserstation.cameraAddress = w.input_readEnum(laserstation.cameraAddress, lasercamAddresses, laser_getName, laser_getDescription, "-no laser camera-")
if laserstation.cameraAddress == nil then
laserstation.camera = nil
else
laserstation.camera = w.device_get(laserstation.cameraAddress)
w.setColorNormal()
w.setCursorPos(1, 8)
w.clearLine()
w.writeLn("Laser camera set to " .. laserstation.cameraAddress)
w.setColorDisabled()
w.setCursorPos(1, 9)
w.clearLine()
local camX, camY, camZ = laserstation.camera.position()
local camVideoChannel = laserstation.camera.videoChannel()
w.write("@ " .. w.format_integer(camX, 7) .. " " .. w.format_integer(camY, 3) .. " " .. w.format_integer(camZ, 7))
end
local key = 1
local nameCurrent = nil
local laser_batteries_left = {}
for keyBattery, laserbattery in pairs(laser_batteries) do
laser_batteries_left[keyBattery] = laserbattery
end
repeat
w.setColorNormal()
w.setCursorPos(1, 10 + (key % 5))
w.write("Battery #" .. key)
nameCurrent = nil
if key <= #laserstation.batteries then
nameCurrent = laserstation.batteries[key].name
w.write(" (" .. nameCurrent .. "): ")
else
w.write(" (-no battery-): ")
end
nameCurrent = w.input_readEnum(nameCurrent, laser_batteries_left, laser_battery_getName, laser_battery_getDescription, "-no battery-")
if nameCurrent == nil then
if key > #laserstation.batteries then
key = -1
else
table.remove(laserstation.batteries, key)
w.success("Removed")
end
else
-- remove selected battery from potentials
for keyBattery, laserbattery in pairs(laser_batteries_left) do
if laser_battery_getName(laserbattery) == nameCurrent then
table.remove(laser_batteries_left, keyBattery)
break
end
end
laserstation.batteries[key] = { name = nameCurrent, enabled = true }
w.setColorNormal()
w.setCursorPos(1, 10 + (key % 5))
w.clearLine()
w.write("Battery #" .. key .. " set to " .. nameCurrent)
key = key + 1
end
until key == -1
end
function laser_battery_shoot(batteryName, targetX, targetY, targetZ)
local laserbattery = laser_battery_getByName(batteryName)
if laserbattery == nil then
w.status_showWarning("Invalid battery name '" .. batteryName .. "'")
return
end
local x, y, z
if data.laser_firingMode == "boosted" and laserbattery.head ~= nil and laserbattery.boosters ~= nil then
local frequency = laserbattery.head.beamFrequency()
local headX, headY, headZ = laserbattery.head.position()
for key, booster in pairs(laserbattery.boosters) do
booster.beamFrequency(frequency)
end
w.sleep(0)
for key, booster in pairs(laserbattery.boosters) do
x, y, z = booster.position()
booster.emitBeam(headX - x, headY - y, headZ - z)
end
w.sleep(0.1)
if data.laser_firingScatter then
headX = headX + math.random(-1, 1)
headY = headY + math.random(-1, 1)
headZ = headZ + math.random(-1, 1)
end
laserbattery.head.emitBeam(targetX - headX, targetY - headY, targetZ - headZ)
elseif data.laser_firingMode == "single" and laserbattery.head ~= nil then
x, y, z = laserbattery.head.position()
if data.laser_firingScatter then
x = x + math.random(-1, 1)
y = y + math.random(-1, 1)
z = z + math.random(-1, 1)
end
laserbattery.head.emitBeam(targetX - x, targetY - y, targetZ - z)
else
if laserbattery.head ~= nil then
x, y, z = laserbattery.head.position()
if z ~= nil then
if data.laser_firingScatter then
x = x + math.random(-1, 1)
y = y + math.random(-1, 1)
z = z + math.random(-1, 1)
end
laserbattery.head.emitBeam(targetX - x, targetY - y, targetZ - z)
end
end
if laserbattery.boosters ~= nil then
for key, booster in pairs(laserbattery.boosters) do
x, y, z = booster.position()
if z ~= nil then
if data.laser_firingScatter then
x = x + math.random(-1, 1)
y = y + math.random(-1, 1)
z = z + math.random(-1, 1)
end
booster.emitBeam(targetX - x, targetY - y, targetZ - z)
end
end
end
end
end
function laser_boot()
-- nothing
end
function laser_sendEvent()
if #laser_stations == 0 then
w.status_showWarning("No laser station configured")
elseif #laser_batteries == 0 then
w.status_showWarning("No laser battery configured")
else
w.status_showWarning("Laser sent!")
for keyStation, laserstation in pairs(laser_stations) do
if laserstation.camera ~= nil then
local resType, x, y, z, id, meta, res = laserstation.camera.getScanResult()
if res ~= -1 then
w.status_showWarning("Firing at " .. x .. " " .. y .. " " .. z)
for batteryKey, battery in pairs(laserstation.batteries) do
if battery.enabled then
laser_battery_shoot(battery.name, x, y, z)
end
end
end
end
end
end
end
function laser_register()
w.device_register("warpdriveLaserCamera",
function(deviceType, address, wrap) table.insert(lasercamAddresses, address) end,
function() end)
w.device_register("warpdriveLaser",
function(deviceType, address, wrap) table.insert(laserAddresses, address) end,
function() end)
w.event_register("laserScanning", function() laser_sendEvent() return false end )
w.event_register("laserSend" , function() return false end )
w.data_register("laser", laser_read, laser_save)
end
----------- connections status
function connections_page(isBooting)
w.page_begin(w.data_getName() .. " - Connections")
w.writeLn("")
if #laserAddresses == 0 then
w.setColorDisabled()
w.writeLn("No attack laser detected")
elseif #laserAddresses == 1 then
w.setColorSuccess()
w.writeLn("1 attack laser detected")
else
w.setColorSuccess()
w.writeLn(#laserAddresses .. " attack lasers detected")
end
if #lasercamAddresses == 0 then
w.setColorDisabled()
w.writeLn("No laser camera detected")
elseif #lasercamAddresses == 1 then
w.setColorSuccess()
w.writeLn("1 laser camera detected")
else
w.setColorSuccess()
w.writeLn(#lasercamAddresses .. " laser cameras detected")
end
if isBooting then
laser_boot()
end
w.writeLn("")
w.setColorNormal()
w.writeLn("This is a keyboard controlled user interface.")
w.write("Key controls are written like so: ")
w.setColorControl()
w.write("Action (key)")
w.setColorNormal()
w.writeLn(".")
w.write("For example, typing ")
w.setColorControl()
w.write(" 1 ")
w.setColorNormal()
w.writeLn(" will open Laser batteries.")
end
----------- Boot sequence
w.page_setEndText(" Home (0), Laser batteries (1), Laser stations (2)")
w.page_register('0', connections_page, nil)
w.page_register('1', laser_battery_page, laser_battery_key)
w.page_register('2', laser_station_page, laser_station_key)
laser_register()
w.boot()
w.run()
w.close()