Merge pull request #6889 from PsiOmegaDelta/APC

BYOND akbar
This commit is contained in:
Chinsky
2014-11-20 14:51:30 +03:00
22 changed files with 393 additions and 424 deletions

View File

@@ -957,7 +957,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
for(var/obj/machinery/power/smes/SMES in world)
if(SMES.anchored)
SMES.chargemode = 1
SMES.input_attempt = 1
/client/proc/setup_supermatter_engine()
set category = "Debug"
@@ -1017,16 +1017,16 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
else if(istype(M,/obj/machinery/power/smes)) //This is the SMES inside the engine room. We don't need much power.
var/obj/machinery/power/smes/SMES = M
SMES.chargemode = 1
SMES.chargelevel = 200000
SMES.output = 75000
SMES.input_attempt = 1
SMES.input_level = 200000
SMES.output_level = 75000
else if(istype(M.loc.loc,/area/engine/engine_smes)) //Set every SMES to charge and spit out 300,000 power between the 4 of them.
if(istype(M,/obj/machinery/power/smes))
var/obj/machinery/power/smes/SMES = M
SMES.chargemode = 1
SMES.chargelevel = 200000
SMES.output = 75000
SMES.input_attempt = 1
SMES.input_level = 200000
SMES.output_level = 75000
if(!found_the_pump && response == "Setup Completely")
src << "\red Unable to locate air supply to fill up with coolant, adding some coolant around the supermatter"

View File

@@ -161,9 +161,6 @@ var/list/debug_verbs = list (
,/client/proc/testZAScolors
,/client/proc/testZAScolors_remove
,/client/proc/setup_supermatter_engine
,/client/proc/view_power_update_stats_area
,/client/proc/view_power_update_stats_machines
,/client/proc/toggle_power_update_profiling
,/client/proc/atmos_toggle_debug
)

View File

@@ -1065,10 +1065,10 @@
if(!area.requires_power)
return
lastused_light = area.usage(LIGHT)
lastused_equip = area.usage(EQUIP)
lastused_environ = area.usage(ENVIRON)
area.clear_usage()
lastused_total = lastused_light + lastused_equip + lastused_environ
@@ -1079,45 +1079,33 @@
var/last_ch = charging
var/excess = surplus()
var/power_excess = 0
var/perapc = 0
if(terminal && terminal.powernet)
perapc = terminal.powernet.perapc
if(!src.avail())
main_status = 0
else if(excess < 0)
main_status = 1
else
main_status = 2
if(debug)
log_debug( "Status: [main_status] - Excess: [excess] - Last Equip: [lastused_equip] - Last Light: [lastused_light]")
if(area.powerupdate)
log_debug("power update in [area.name] / [name]")
log_debug("Status: [main_status] - Excess: [excess] - Last Equip: [lastused_equip] - Last Light: [lastused_light] - Longterm: [longtermpower]")
if(cell && !shorted)
//var/cell_charge = cell.charge
var/cell_maxcharge = cell.maxcharge
// draw power from cell as before to power the area
var/cellused = min(cell.charge, CELLRATE * lastused_total) // clamp deduction to a max, amount left in cell
cell.use(cellused)
// Calculate how much power the APC will try to get from the grid.
var/target_draw = lastused_total
if (src.attempt_charging())
target_draw += min((cell_maxcharge - cell.charge), (cell_maxcharge*CHARGELEVEL))/CELLRATE
target_draw = min(target_draw, perapc) //limit power draw by perapc
// try to draw power from the grid
var/power_drawn = 0
if (src.avail())
power_drawn = draw_power(target_draw) //get some power from the powernet
//figure out how much power is left over after meeting demand
power_excess = power_drawn - lastused_total
if (power_excess < 0) //couldn't get enough power from the grid, we will need to take from the power cell.
charging = 0
var/required_power = -power_excess
if(cell.charge >= required_power*CELLRATE) // can we draw enough from cell to cover what's left over?
cell.use(required_power*CELLRATE)
else if (autoflag != 0) // not enough power available to run the last tick!
if(excess > lastused_total) // if power excess recharge the cell
// by the same amount just used
var/draw = draw_power(cellused/CELLRATE) // draw the power needed to charge this cell
cell.give(draw * CELLRATE)
else // no excess, and not enough per-apc
if( (cell.charge/CELLRATE + excess) >= lastused_total) // can we draw enough from cell+grid to cover last usage?
var/draw = draw_power(excess)
cell.charge = min(cell.maxcharge, cell.charge + CELLRATE * draw) //recharge with what we can
charging = 0
else // not enough power available to run the last tick!
charging = 0
chargecount = 0
// This turns everything off in the case that there is still a charge left on the battery, just not enough to run the room.
equipment = autoset(equipment, 0)
@@ -1125,13 +1113,6 @@
environ = autoset(environ, 0)
autoflag = 0
//Set external power status
if (!power_drawn)
main_status = 0
else if (power_excess < 0)
main_status = 1
else
main_status = 2
// Set channels depending on how much charge we have left
@@ -1141,7 +1122,6 @@
else if(longtermpower > -10)
longtermpower -= 2
if(cell.charge >= 1250 || longtermpower > 0) // Put most likely at the top so we don't check it last, effeciency 101
if(autoflag != 3)
equipment = autoset(equipment, 1)
@@ -1174,28 +1154,33 @@
autoflag = 0
// now trickle-charge the cell
if(src.attempt_charging())
if (power_excess > 0) // check to make sure we have enough to charge
cell.give(power_excess*CELLRATE) // actually recharge the cell
if(excess > 0) // check to make sure we have enough to charge
// Max charge is capped to % per second constant
var/ch = min(excess*CELLRATE, cell.maxcharge*CHARGELEVEL)
ch = draw_power(ch/CELLRATE) // Removes the power we're taking from the grid
cell.give(ch*CELLRATE) // actually recharge the cell
else
charging = 0 // stop charging
chargecount = 0
// show cell as fully charged if so
if(cell.charge >= cell_maxcharge)
if(cell.charge >= cell.maxcharge)
cell.charge = cell.maxcharge
charging = 2
//if we have excess power for long enough, think about re-enable charging.
if(chargemode)
if(!charging)
//last_surplus() overestimates the amount of power available for charging, but it's equivalent to what APCs were doing before.
if(src.last_surplus()*CELLRATE >= cell_maxcharge*CHARGELEVEL)
if(excess > cell.maxcharge*CHARGELEVEL)
chargecount++
else
chargecount = 0
charging = 0
if(chargecount >= 10)
chargecount = 0
charging = 1
@@ -1213,7 +1198,6 @@
area.poweralert(0, src)
autoflag = 0
// update icon & area power if anything changed
if(last_lt != lighting || last_eq != equipment || last_en != environ)

View File

@@ -23,9 +23,9 @@
name = "power cell rack PSU"
desc = "A rack of power cells working as a PSU."
charge = 0 //you dont really want to make a potato PSU which already is overloaded
online = 0
chargelevel = 0
output = 0
output_attempt = 0
input_level = 0
output_level = 0
input_level_max = 0
output_level_max = 0
icon_state = "gsmes"
@@ -37,9 +37,9 @@
/obj/machinery/power/smes/batteryrack/substation
name = "Substation PSU"
desc = "A rack of power cells working as a PSU. This one seems to be equipped for higher power loads."
output = 150000
chargelevel = 150000
online = 1
output_level = 150000
input_level = 150000
output_attempt = 1
// One high capacity cell, two regular cells. Lots of room for engineer upgrades
// Also five basic capacitors. Again, upgradeable.
@@ -89,13 +89,13 @@
capacity = C * 40 //Basic cells are such crap. Hyper cells needed to get on normal SMES levels.
/obj/machinery/power/smes/batteryrack/updateicon()
/obj/machinery/power/smes/batteryrack/update_icon()
overlays.Cut()
if(stat & BROKEN) return
if (online)
if (output_attempt)
overlays += image('icons/obj/power.dmi', "gsmes_outputting")
if(charging)
if(inputting)
overlays += image('icons/obj/power.dmi', "gsmes_charging")
var/clevel = chargedisplay()
@@ -113,7 +113,7 @@
if(open_hatch)
if(istype(W, /obj/item/weapon/crowbar))
if (charge < (capacity / 100))
if (!online && !chargemode)
if (!output_attempt && !input_attempt)
playsound(get_turf(src), 'sound/items/Crowbar.ogg', 50, 1)
var/obj/machinery/constructable_frame/machine_frame/M = new /obj/machinery/constructable_frame/machine_frame(src.loc)
M.state = 2
@@ -130,7 +130,7 @@
user << "<span class='warning'>Better let [src] discharge before dismantling it.</span>"
else if ((istype(W, /obj/item/weapon/stock_parts/capacitor) && (capacitors_amount < 5)) || (istype(W, /obj/item/weapon/cell) && (cells_amount < 5)))
if (charge < (capacity / 100))
if (!online && !chargemode)
if (!output_attempt && !input_attempt)
user.drop_item()
component_parts += W
W.loc = src
@@ -163,13 +163,13 @@
return
/obj/machinery/power/smes/batteryrack/makeshift/updateicon()
/obj/machinery/power/smes/batteryrack/makeshift/update_icon()
overlays.Cut()
if(stat & BROKEN) return
if (online)
if (output_attempt)
overlays += image('icons/obj/power.dmi', "gsmes_outputting")
if(charging)
if(inputting)
overlays += image('icons/obj/power.dmi', "gsmes_charging")
if (overcharge_percent > 100)
overlays += image('icons/obj/power.dmi', "gsmes_overcharge")
@@ -234,35 +234,35 @@
//store machine state to see if we need to update the icon overlays
var/last_disp = chargedisplay()
var/last_chrg = charging
var/last_onln = online
var/last_chrg = inputting
var/last_onln = output_attempt
var/last_overcharge = overcharge_percent
if(terminal)
if(chargemode)
var/target_load = min((capacity-charge)/SMESRATE, chargelevel) // charge at set rate, limited to spare capacity
if(input_attempt)
var/target_load = min((capacity-charge)/SMESRATE, input_level) // charge at set rate, limited to spare capacity
var/actual_load = draw_power(target_load) // add the load to the terminal side network
charge += actual_load * SMESRATE // increase the charge
if (actual_load >= target_load) // did the powernet have enough power available for us?
charging = 1
inputting = 1
else
charging = 0
inputting = 0
if(online) // if outputting
lastout = min( charge/SMESRATE, output) //limit output to that stored
charge -= lastout*SMESRATE // reduce the storage (may be recovered in /restore() if excessive)
add_avail(lastout) // add output to powernet (smes side)
if(output_attempt) // if outputting
output_used = min( charge/SMESRATE, output_level) //limit output to that stored
charge -= output_used*SMESRATE // reduce the storage (may be recovered in /restore() if excessive)
add_avail(output_used) // add output to powernet (smes side)
if(charge < 0.0001)
online = 0 // stop output if charge falls to zero
outputting(0) // stop output if charge falls to zero
overcharge_percent = round((charge / capacity) * 100)
if (overcharge_percent > 115) //115% is the minimum overcharge for anything to happen
overcharge_consequences()
// only update icon if state changed
if(last_disp != chargedisplay() || last_chrg != charging || last_onln != online || ((overcharge_percent > 100) ^ (last_overcharge > 100)))
updateicon()
if(last_disp != chargedisplay() || last_chrg != inputting || last_onln != output_attempt || ((overcharge_percent > 100) ^ (last_overcharge > 100)))
update_icon()
return
#undef SMESRATE

View File

@@ -212,30 +212,6 @@ obj/structure/cable/proc/cableColor(var/colorC)
color_n = colorC
color = color_n
////////////////////////////////////////////
// Power related
///////////////////////////////////////////
obj/structure/cable/proc/add_avail(var/amount)
if(powernet)
powernet.newavail += amount
obj/structure/cable/proc/add_load(var/amount)
if(powernet)
powernet.load += amount
obj/structure/cable/proc/surplus()
if(powernet)
return powernet.avail-powernet.load
else
return 0
obj/structure/cable/proc/avail()
if(powernet)
return powernet.avail
else
return 0
/////////////////////////////////////////////////
// Cable laying helpers
////////////////////////////////////////////////

View File

@@ -601,11 +601,11 @@
#define LIGHTING_POWER_FACTOR 20 //20W per unit luminosity
/*
/obj/machinery/light/process()//TODO: remove/add this from machines to save on processing as needed ~Carn PRIORITY
/obj/machinery/light/process()
if(on)
use_power(luminosity * LIGHTING_POWER_FACTOR, LIGHT)
*/
// called when area power state changes
/obj/machinery/light/power_change()

View File

@@ -352,7 +352,7 @@
source_area.use_power(drained_energy/CELLRATE)
else if (istype(power_source,/datum/powernet))
var/drained_power = drained_energy/CELLRATE //convert from "joules" to "watts"
PN.load+=drained_power
drained_power = PN.draw_power(drained_power)
else if (istype(power_source, /obj/item/weapon/cell))
cell.use(drained_energy)
return drained_energy

View File

@@ -11,27 +11,31 @@
density = 1
anchored = 1
use_power = 0
//directwired = 0
var/output = 50000 //Amount of power it tries to output
var/lastout = 0 //Amount of power it actually outputs to the powernet
var/loaddemand = 0 //For use in restore()
var/capacity = 5e6 //Maximum amount of power it can hold
var/charge = 1.0e6 //Current amount of power it holds
var/charging = 0 //1 if it's actually charging, 0 if not
var/chargemode = 0 //1 if it's trying to charge, 0 if not.
//var/chargecount = 0
var/chargelevel = 0 //Amount of power it tries to charge from powernet
var/online = 1 //1 if it's outputting power, 0 if not.
var/name_tag = null
var/obj/machinery/power/terminal/terminal = null
var/capacity = 5e6 // maximum charge
var/charge = 1e6 // actual charge
var/input_attempt = 0 // 1 = attempting to charge, 0 = not attempting to charge
var/inputting = 0 // 1 = actually inputting, 0 = not inputting
var/input_level = 50000 // amount of power the SMES attempts to charge by
var/input_level_max = 200000 // cap on input_level
var/input_available = 0 // amount of charge available from input last tick
var/output_attempt = 1 // 1 = attempting to output, 0 = not attempting to output
var/outputting = 1 // 1 = actually outputting, 0 = not outputting
var/output_level = 50000 // amount of power the SMES attempts to output
var/output_level_max = 200000 // cap on output_level
var/output_used = 0 // amount of power actually outputted. may be less than output_level if the powernet returns excess power
//Holders for powerout event.
var/last_output = 0
var/last_charge = 0
var/last_online = 0
var/last_output_attempt = 0
var/last_input_attempt = 0
var/last_charge = 0
var/open_hatch = 0
var/name_tag = null
var/building_terminal = 0 //Suggestions about how to avoid clickspam building several terminals accepted!
var/input_level_max = 200000
var/output_level_max = 200000
var/obj/machinery/power/terminal/terminal = null
/obj/machinery/power/smes/New()
..()
@@ -52,21 +56,21 @@
terminal.master = src
if(!terminal.powernet)
terminal.connect_to_network()
updateicon()
update_icon()
return
/obj/machinery/power/smes/proc/updateicon()
/obj/machinery/power/smes/update_icon()
overlays.Cut()
if(stat & BROKEN) return
overlays += image('icons/obj/power.dmi', "smes-op[online]")
overlays += image('icons/obj/power.dmi', "smes-op[outputting]")
if(charging == 2)
if(inputting == 2)
overlays += image('icons/obj/power.dmi', "smes-oc2")
else if (charging == 1)
else if (inputting == 1)
overlays += image('icons/obj/power.dmi', "smes-oc1")
else
if(chargemode)
if(input_attempt)
overlays += image('icons/obj/power.dmi', "smes-oc0")
var/clevel = chargedisplay()
@@ -82,57 +86,62 @@
/obj/machinery/power/smes/process()
if(stat & BROKEN) return
//store machine state to see if we need to update the icon overlays
var/last_disp = chargedisplay()
var/last_chrg = charging
var/last_onln = online
var/last_chrg = inputting
var/last_onln = outputting
if(terminal)
//If chargemod is set, try to charge
//Use charging to let the player know whether we were able to obtain our target load.
//TODO: Add a meter to tell players how much charge we are actually getting, and only set charging to 0 when we are unable to get any charge at all.
if(chargemode)
var/target_load = min((capacity-charge)/SMESRATE, chargelevel) // charge at set rate, limited to spare capacity
var/actual_load = draw_power(target_load) // add the load to the terminal side network
charge += actual_load * SMESRATE // increase the charge
//inputting
if(input_attempt)
var/target_load = min((capacity-charge)/SMESRATE, input_level) // charge at set rate, limited to spare capacity
var/actual_load = draw_power(target_load) // add the load to the terminal side network
charge += actual_load * SMESRATE // increase the charge
if (actual_load >= target_load) // Did we charge at full rate?
charging = 2
else if (actual_load) // If not, did we charge at least partially?
charging = 1
else // Or not at all?
charging = 0
if (actual_load >= target_load) // Did we charge at full rate?
inputting = 2
else if (actual_load) // If not, did we charge at least partially?
inputting = 1
else // Or not at all?
inputting = 0
if(online) // if outputting
lastout = min( charge/SMESRATE, output) //limit output to that stored
charge -= lastout*SMESRATE // reduce the storage (may be recovered in /restore() if excessive)
add_avail(lastout) // add output to powernet (smes side)
if(charge < 0.0001)
online = 0 // stop output if charge falls to zero
//outputting
if(outputting)
output_used = min( charge/SMESRATE, output_level) //limit output to that stored
charge -= output_used*SMESRATE // reduce the storage (may be recovered in /restore() if excessive)
add_avail(output_used) // add output to powernet (smes side)
if(output_used < 0.0001) // either from no charge or set to 0
outputting = 0
investigate_log("lost power and turned <font color='red'>off</font>","singulo")
else if(output_attempt && charge > output_level && output_level > 0)
outputting = 1
else
output_used = 0
// only update icon if state changed
if(last_disp != chargedisplay() || last_chrg != charging || last_onln != online)
updateicon()
if(last_disp != chargedisplay() || last_chrg != inputting || last_onln != outputting)
update_icon()
return
// called after all power processes are finished
// restores charge level to smes if there was excess this ptick
/obj/machinery/power/smes/proc/restore()
if(stat & BROKEN)
return
if(!online)
loaddemand = 0
if(!outputting)
output_used = 0
return
var/excess = powernet.netexcess // this was how much wasn't used on the network last ptick, minus any removed by other SMESes
excess = min(lastout, excess) // clamp it to how much was actually output by this SMES last ptick
excess = min(output_used, excess) // clamp it to how much was actually output by this SMES last ptick
excess = min((capacity-charge)/SMESRATE, excess) // for safety, also limit recharge by space capacity of SMES (shouldn't happen)
@@ -140,13 +149,13 @@
var/clev = chargedisplay()
charge += excess * SMESRATE
charge += excess * SMESRATE // restore unused power
powernet.netexcess -= excess // remove the excess from the powernet, so later SMESes don't try to use it
loaddemand = lastout-excess
output_used -= excess
if(clev != chargedisplay() )
updateicon()
if(clev != chargedisplay() ) //if needed updates the icons overlay
update_icon()
return
//Will return 1 on failure
@@ -263,14 +272,14 @@
var/data[0]
data["nameTag"] = name_tag
data["storedCapacity"] = round(100.0*charge/capacity, 0.1)
data["charging"] = charging
data["chargeMode"] = chargemode
data["chargeLevel"] = chargelevel
data["charging"] = inputting
data["chargeMode"] = input_attempt
data["chargeLevel"] = input_level
data["chargeMax"] = input_level_max
data["outputOnline"] = online
data["outputLevel"] = output
data["outputOnline"] = output_attempt
data["outputLevel"] = output_level
data["outputMax"] = output_level_max
data["outputLoad"] = round(loaddemand)
data["outputLoad"] = round(output_used)
// update the ui if it exists, returns null if no ui is passed/found
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
@@ -301,40 +310,34 @@
if (!istype(src.loc, /turf) && !istype(usr, /mob/living/silicon/))
return 0 // Do not update ui
for(var/area/A in active_areas)
A.master.powerupdate = 3
if( href_list["cmode"] )
chargemode = !chargemode
if(!chargemode)
charging = 0
updateicon()
inputting(!inputting)
update_icon()
else if( href_list["online"] )
online = !online
updateicon()
outputting(!outputting)
update_icon()
else if( href_list["input"] )
switch( href_list["input"] )
if("min")
chargelevel = 0
input_level = 0
if("max")
chargelevel = input_level_max
input_level = input_level_max
if("set")
chargelevel = input(usr, "Enter new input level (0-[input_level_max])", "SMES Input Power Control", chargelevel) as num
chargelevel = max(0, min(input_level_max, chargelevel)) // clamp to range
input_level = input(usr, "Enter new input level (0-[input_level_max])", "SMES Input Power Control", input_level) as num
input_level = max(0, min(input_level_max, input_level)) // clamp to range
else if( href_list["output"] )
switch( href_list["output"] )
if("min")
output = 0
output_level = 0
if("max")
output = output_level_max
output_level = output_level_max
if("set")
output = input(usr, "Enter new output level (0-[output_level_max])", "SMES Output Power Control", output) as num
output = max(0, min(output_level_max, output)) // clamp to range
output_level = input(usr, "Enter new output level (0-[output_level_max])", "SMES Output Power Control", output_level) as num
output_level = max(0, min(output_level_max, output_level)) // clamp to range
investigate_log("input/output; [chargelevel>output?"<font color='green'>":"<font color='red'>"][chargelevel]/[output]</font> | Output-mode: [online?"<font color='green'>on</font>":"<font color='red'>off</font>"] | Input-mode: [chargemode?"<font color='green'>auto</font>":"<font color='red'>off</font>"] by [usr.key]","singulo")
investigate_log("input/output; [input_level>output_level?"<font color='green'>":"<font color='red'>"][input_level]/[output_level]</font> | Output-mode: [output_attempt?"<font color='green'>on</font>":"<font color='red'>off</font>"] | Input-mode: [input_attempt?"<font color='green'>auto</font>":"<font color='red'>off</font>"] by [usr.key]","singulo")
return 1
@@ -366,27 +369,33 @@
smoke.attach(src)
smoke.start()
/obj/machinery/power/smes/proc/inputting(var/do_input)
input_attempt = do_input
if(!input_attempt)
inputting = 0
/obj/machinery/power/smes/proc/outputting(var/do_output)
output_attempt = do_output
if(!output_attempt)
outputting = 0
/obj/machinery/power/smes/emp_act(severity)
online = 0
charging = 0
output = 0
inputting(rand(0,1))
outputting(rand(0,1))
output_level = rand(0, output_level_max)
input_level = rand(0, input_level_max)
charge -= 1e6/severity
if (charge < 0)
charge = 0
spawn(100)
output = initial(output)
charging = initial(charging)
online = initial(online)
update_icon()
..()
/obj/machinery/power/smes/magical
name = "magical power storage unit"
desc = "A high-capacity superconducting magnetic energy storage (SMES) unit. Magically produces power."
capacity = 9000000
output = 250000
output_level = 250000
/obj/machinery/power/smes/magical/process()
charge = 5000000

View File

@@ -177,7 +177,7 @@
A.set_broken()
// Failing SMES has special icon overlay.
/obj/machinery/power/smes/buildable/updateicon()
/obj/machinery/power/smes/buildable/update_icon()
if (failing)
overlays.Cut()
overlays += image('icons/obj/power.dmi', "smes-crit")
@@ -199,7 +199,7 @@
user << "<span class='warning'>Safety circuit of [src] is preventing modifications while it's charged!</span>"
return
if (online || chargemode)
if (output_attempt || input_attempt)
user << "<span class='warning'>Turn off the [src] first!</span>"
return

View File

@@ -195,10 +195,10 @@ var/list/solars_list = list()
T = locate( round(ax,0.5),round(ay,0.5),z)
if(T.x == 1 || T.x==world.maxx || T.y==1 || T.y==world.maxy) // not obscured if we reach the edge
if(!T || T.x == 1 || T.x==world.maxx || T.y==1 || T.y==world.maxy) // not obscured if we reach the edge
break
if(T.density) // if we hit a solid turf, panel is obscured
if(T.opacity) // if we hit a solid turf, panel is obscured
obscured = 1
return
@@ -386,7 +386,8 @@ var/list/solars_list = list()
/obj/machinery/power/solar_control/interact(mob/user)
var/t = "<B><span class='highlight'>Generated power</span></B> : [round(lastgen)] W<BR>"
t += "<B><span class='highlight'>Orientation</span></B>: [rate_control(src,"cdir","[cdir]&deg",1,15)] ([angle2text(cdir)])<BR>"
t += "<B><span class='highlight'>Star Orientation</span></B>: [sun.angle]&deg ([angle2text(sun.angle)])<BR>"
t += "<B><span class='highlight'>Array Orientation</span></B>: [rate_control(src,"cdir","[cdir]&deg",1,15)] ([angle2text(cdir)])<BR>"
t += "<B><span class='highlight'>Tracking:</B><div class='statusDisplay'>"
switch(track)
if(0)