Make NanoUI resistant to Topic spoofs

Move Topic() into a NanoUI-specific ui_act proc
Update to @YotaXP's latest JSON code.
Return focus to the mapwindow if a key is pressed in a NanoUI.
This commit is contained in:
Bjorn Neergaard
2015-12-15 22:37:52 -06:00
parent 070a081db8
commit da4842dddf
29 changed files with 354 additions and 168 deletions
@@ -149,22 +149,21 @@ Passive gate is similar to the regular pump except:
return
interact(user)
/obj/machinery/atmospherics/components/binary/passive_gate/Topic(href, href_list)
/obj/machinery/atmospherics/components/binary/passive_gate/ui_act(action, params)
if(..())
return
switch(href_list["nano"])
switch(action)
if("power")
on = !on
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
if("pressure")
switch(href_list["set"])
switch(params["set"])
if ("max")
target_pressure = MAX_OUTPUT_PRESSURE
if ("custom")
target_pressure = max(0, min(MAX_OUTPUT_PRESSURE, safe_input("Pressure control", "Enter new output pressure (0-[MAX_OUTPUT_PRESSURE] kPa)", target_pressure)))
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
add_fingerprint(usr)
update_icon()
return 1
@@ -157,22 +157,21 @@ Thus, the two variables affect pump operation are set in New():
return
interact(user)
/obj/machinery/atmospherics/components/binary/pump/Topic(href,href_list)
/obj/machinery/atmospherics/components/binary/pump/ui_act(action, params)
if(..())
return
switch(href_list["nano"])
switch(action)
if("power")
on = !on
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
if("pressure")
switch(href_list["set"])
switch(params["set"])
if ("max")
target_pressure = MAX_OUTPUT_PRESSURE
if ("custom")
target_pressure = max(0, min(MAX_OUTPUT_PRESSURE, safe_input("Pressure control", "Enter new output pressure (0-[MAX_OUTPUT_PRESSURE] kPa)", target_pressure)))
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
add_fingerprint(usr)
update_icon()
return 1
@@ -155,22 +155,21 @@ Thus, the two variables affect pump operation are set in New():
return
interact(user)
/obj/machinery/atmospherics/components/binary/volume_pump/Topic(href,href_list)
/obj/machinery/atmospherics/components/binary/volume_pump/ui_act(action, params)
if(..())
return
switch(href_list["nano"])
switch(action)
if("power")
on = !on
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
if("transfer")
switch(href_list["set"])
switch(params)
if ("max")
transfer_rate = MAX_TRANSFER_RATE
if ("custom")
transfer_rate = max(0, min(MAX_TRANSFER_RATE, safe_input("Pressure control", "Enter new transfer rate (0-[MAX_TRANSFER_RATE] L/s)", transfer_rate)))
investigate_log("was set to [transfer_rate] L/s by [key_name(usr)]", "atmos")
add_fingerprint(usr)
update_icon()
return 1
@@ -137,10 +137,6 @@ Pipenet stuff; housekeeping
T.assume_air(to_release)
air_update_turf(1)
/*
I think this is NanoUI?
*/
/obj/machinery/atmospherics/components/proc/safe_input(var/title, var/text, var/default_set)
var/new_value = input(usr,text,title,default_set) as num
if(usr.canUseTopic(src))
@@ -182,23 +182,23 @@ Filter types:
data["filter_type"] = filter_type
return data
/obj/machinery/atmospherics/components/trinary/filter/Topic(href, href_list)
/obj/machinery/atmospherics/components/trinary/filter/ui_act(action, params)
if(..())
return
switch(href_list["nano"])
switch(action)
if("power")
on=!on
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
if("pressure")
switch(href_list["set"])
switch(params["set"])
if("max")
target_pressure = MAX_OUTPUT_PRESSURE
if("custom")
target_pressure = max(0, min(MAX_OUTPUT_PRESSURE, safe_input("Pressure control", "Enter new output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", target_pressure)))
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
if("filter")
src.filter_type = text2num(href_list["mode"])
src.filter_type = text2num(params["mode"])
var/filtering_name = "nothing"
switch(filter_type)
if(FILTER_PLASMA)
@@ -212,6 +212,5 @@ Filter types:
if(FILTER_NITROUSOXIDE)
filtering_name = "nitrous oxide"
investigate_log("was set to filter [filtering_name] by [key_name(usr)]", "atmos")
add_fingerprint(usr)
update_icon()
return 1
@@ -147,31 +147,30 @@
data["node2_concentration"] = round(node2_concentration*100)
return data
/obj/machinery/atmospherics/components/trinary/mixer/Topic(href,href_list)
/obj/machinery/atmospherics/components/trinary/mixer/ui_act(action, params)
if(..())
return
switch(href_list["nano"])
switch(action)
if("power")
on = !on
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos")
if("pressure")
switch(href_list["set"])
switch(params["set"])
if("max")
target_pressure = MAX_OUTPUT_PRESSURE
if("custom")
target_pressure = max(0, min(MAX_OUTPUT_PRESSURE, safe_input("Pressure control", "Enter new output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", target_pressure)))
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos")
if("node1")
var/value = text2num(href_list["concentration"])
var/value = text2num(params["concentration"])
src.node1_concentration = max(0, min(1, src.node1_concentration + value))
src.node2_concentration = max(0, min(1, src.node2_concentration - value))
investigate_log("was set to [node1_concentration] % on node 1 by [key_name(usr)]", "atmos")
if("node2")
var/value = text2num(href_list["concentration"])
var/value = text2num(params["concentration"])
src.node2_concentration = max(0, min(1, src.node2_concentration + value))
src.node1_concentration = max(0, min(1, src.node1_concentration - value))
investigate_log("was set to [node2_concentration] % on node 2 by [key_name(usr)]", "atmos")
add_fingerprint(usr)
update_icon()
return 1
@@ -166,11 +166,11 @@
data["beakerContents"] = beakerContents
return data
/obj/machinery/atmospherics/components/unary/cryo_cell/Topic(href, href_list)
/obj/machinery/atmospherics/components/unary/cryo_cell/ui_act(action, params)
if(..())
return
switch(href_list["nano"])
switch(action)
if("open")
open_machine()
if("close")
@@ -186,7 +186,6 @@
if(beaker)
beaker.loc = get_step(loc, SOUTH)
beaker = null
add_fingerprint(usr)
update_icon()
return 1
-1
View File
@@ -1 +0,0 @@
#define writeJson(value) list2text(_jsonHelper.WriteValue(list(), (value)))
+14 -14
View File
@@ -387,7 +387,7 @@
data["thresholds"] = thresholds
/obj/machinery/alarm/Topic(href, href_list)
/obj/machinery/alarm/ui_act(action, params)
if(..())
return
@@ -400,17 +400,17 @@
if (usr.has_unlimited_silicon_privilege && src.aidisabled)
return
switch(href_list["nano"])
switch(action)
if("toggleaccess")
if(usr.has_unlimited_silicon_privilege && !wires.IsIndexCut(AALARM_WIRE_IDSCAN))
locked = !locked
if("adjust")
var/device_id = href_list["id_tag"]
switch(href_list["command"])
var/device_id = params["id_tag"]
switch(params["command"])
if("set_external_pressure")
var/input_pressure = input("Enter target pressure:", "Pressure Controls") as num|null
if(isnum(input_pressure))
send_signal(device_id, list(href_list["command"] = input_pressure))
send_signal(device_id, list(params["command"] = input_pressure))
if("reset_external_pressure")
send_signal(device_id, list("set_external_pressure" = ONE_ATMOSPHERE))
if(
@@ -422,14 +422,14 @@
"widenet",
"scrubbing"
)
send_signal(device_id, list (href_list["command"] = text2num(href_list["val"])))
send_signal(device_id, list (params["command"] = text2num(params["val"])))
if ("excheck")
send_signal(device_id, list ("checks" = text2num(href_list["val"])^1))
send_signal(device_id, list ("checks" = text2num(params["val"])^1))
if ("incheck")
send_signal(device_id, list ("checks" = text2num(href_list["val"])^2))
send_signal(device_id, list ("checks" = text2num(params["val"])^2))
if("set_threshold")
var/env = href_list["env"]
var/varname = href_list["var"]
var/env = params["env"]
var/varname = params["var"]
var/datum/tlv/tlv = TLV[env]
var/newval = input("Enter [varname] for [env]:", "Alarm Triggers", tlv.vars[varname]) as num|null
if (isnull(newval))
@@ -446,16 +446,16 @@
newval = round(newval,0.01)
tlv.vars[varname] = newval
if("screen")
screen = text2num(href_list["screen"])
screen = text2num(params["screen"])
if("mode")
mode = text2num(href_list["mode"])
mode = text2num(params["mode"])
apply_mode()
if("alarm")
if (alarm_area.atmosalert(2, src))
if(alarm_area.atmosalert(2, src))
post_alert(2)
update_icon()
if("reset")
if (alarm_area.atmosalert(0, src))
if(alarm_area.atmosalert(0, src))
post_alert(0)
update_icon()
return 1
+3 -3
View File
@@ -298,11 +298,11 @@ update_flag
data["holdingTank"]["tankPressure"] = round(holding.air_contents.return_pressure())
return data
/obj/machinery/portable_atmospherics/canister/Topic(href, href_list)
/obj/machinery/portable_atmospherics/canister/ui_act(action, params)
if(..())
return
switch(href_list["nano"])
switch(action)
if("relabel")
if (can_label)
var/list/colors = list(\
@@ -320,7 +320,7 @@ update_flag
src.icon_state = colors[label]
src.name = "canister: [label]"
if("pressure")
switch(href_list["set"])
switch(params["set"])
if("custom")
var/custom = input(usr, "What rate do you set the regulator to? The dial reads from [CAN_MIN_RELEASE_PRESSURE] to [CAN_MAX_RELEASE_PRESSURE].") as null|num
if(custom)
@@ -40,18 +40,18 @@
return data
/obj/item/weapon/electronics/airlock/Topic(href, href_list)
/obj/item/weapon/electronics/airlock/ui_act(action, params)
if(..())
return
switch(href_list["nano"])
switch(action)
if("clear")
accesses = list()
one_access = 0
if("one_access")
one_access = !one_access
if("set")
var/access = text2num(href_list["access"])
var/access = text2num(params["access"])
if (!(access in accesses))
accesses += access
else
+7
View File
@@ -209,6 +209,13 @@ Class Procs:
add_fingerprint(usr)
return 0
/obj/machinery/ui_act(action, params)
..()
if(!can_be_used_by(usr))
return 1
add_fingerprint(usr)
return 0
/obj/machinery/proc/can_be_used_by(mob/user)
if(!interact_offline && stat & (NOPOWER|BROKEN))
return 0
+6 -6
View File
@@ -162,28 +162,28 @@
ui = new(user, src, ui_key, "space_heater", name, 490, 340, state = physical_state)
ui.open()
/obj/machinery/space_heater/Topic(href, href_list)
if(stat & BROKEN || ..())
/obj/machinery/space_heater/ui_act(action, params)
if(..())
return
switch(href_list["nano"])
switch(action)
if("power")
on = !on
mode = HEATER_MODE_STANDBY
usr.visible_message("[usr] switches [on ? "on" : "off"] \the [src].", "<span class='notice'>You switch [on ? "on" : "off"] \the [src].</span>")
update_icon()
if("mode")
setMode = href_list["mode"]
setMode = params["mode"]
if("temp")
if(panel_open)
var/value
if(href_list["set"] == "custom")
if(params["set"] == "custom")
value = input("Please input the target temperature", name) as num|null
if(isnull(value))
return
value += T0C
else
value = targetTemperature + text2num(href_list["set"])
value = targetTemperature + text2num(params["set"])
var/minTemp = max(settableTemperatureMedian - settableTemperatureRange, TCMB)
var/maxTemp = settableTemperatureMedian + settableTemperatureRange
@@ -157,13 +157,13 @@
data["maskConnected"] = 1
return data
/obj/item/weapon/tank/Topic(href, href_list)
/obj/item/weapon/tank/ui_act(action, params)
if (..())
return
switch(href_list["nano"])
switch(action)
if("pressure")
switch(href_list["set"])
switch(params["set"])
if("custom")
var/custom = input(usr, "What rate do you set the regulator to? The dial reads from 0 to [TANK_MAX_RELEASE_PRESSURE].") as null|num
if(isnum(custom))
+13 -12
View File
@@ -173,6 +173,19 @@ You can set verify to TRUE if you want send() to sleep until the client has the
//DEFINITIONS FOR ASSET DATUMS START HERE.
/datum/asset/simple/nanoui
assets = list(
"nanoui.lib.js" = 'nano/assets/nanoui.lib.js',
"nanoui.main.js" = 'nano/assets/nanoui.main.js',
"nanoui.templates.js" = 'nano/assets/nanoui.templates.js',
"nanoui.lib.css" = 'nano/assets/nanoui.lib.css',
"nanoui.common.css" = 'nano/assets/nanoui.common.css',
"nanoui.generic.css" = 'nano/assets/nanoui.generic.css',
"nanoui.nanotrasen.css" = 'nano/assets/nanoui.nanotrasen.css',
"fontawesome-webfont.eot" = 'nano/assets/fontawesome-webfont.eot',
"fontawesome-webfont.woff2" = 'nano/assets/fontawesome-webfont.woff2'
)
/datum/asset/simple/pda
assets = list(
"pda_atmos.png" = 'icons/pda_icons/pda_atmos.png',
@@ -219,18 +232,6 @@ You can set verify to TRUE if you want send() to sleep until the client has the
"large_stamp-law.png" = 'icons/stamp_icons/large_stamp-law.png'
)
/datum/asset/simple/nanoui
assets = list(
"nanoui.lib.js" = 'nano/assets/nanoui.lib.js',
"nanoui.main.js" = 'nano/assets/nanoui.main.js',
"nanoui.templates.js" = 'nano/assets/nanoui.templates.js',
"nanoui.lib.css" = 'nano/assets/nanoui.lib.css',
"nanoui.common.css" = 'nano/assets/nanoui.common.css',
"nanoui.generic.css" = 'nano/assets/nanoui.generic.css',
"nanoui.nanotrasen.css" = 'nano/assets/nanoui.nanotrasen.css',
"fontawesome-webfont.eot" = 'nano/assets/fontawesome-webfont.eot',
"fontawesome-webfont.woff2" = 'nano/assets/fontawesome-webfont.woff2'
)
//Registers HTML Interface assets.
/datum/asset/HTML_interface/register()
+201 -2
View File
@@ -1,6 +1,14 @@
/var/datum/jsonHelper/_jsonHelper = new // Solely as a namespace for procs.
/* Usage:
JSON.stringify(obj) - Converts lists and values into a JSON string.
JSON.parse(json) - Converts a JSON string into lists and values.
*/
/var/datum/jsonHelper/JSON = new // A namespace for procs.
// ************************************ WRITER ************************************
/datum/jsonHelper/proc/stringify(value)
return list2text(WriteValue(list(), value))
/datum/jsonHelper/proc/WriteValue(list/json, value)
. = json
if(isnum(value))
@@ -82,4 +90,195 @@
#undef Either
#undef CannotBeFlat
#undef CannotBeAssoc
#undef BadList
#undef BadList
// ************************************ READER ************************************
#define aBackspace 0x08
#define aTab 0x09
#define aLineBreak 0x0A
#define aVertTab 0x0B
#define aFormFeed 0x0C
#define aCarriageReturn 0x0D
#define aSpace 0x20
#define aZero 0x30
#define aNonBreakSpace 0xA0
#define Advance if(++readPos > jsonLen) { curAscii = 0; curChar = "" } else { curAscii = text2ascii(json, readPos); curChar = ascii2text(curAscii) } // Deal with it.
#define SkipWhitespace while(curAscii in whitespace) Advance
#define AdvanceWS Advance; SkipWhitespace
/datum/jsonHelper/var
readPos
jsonLen
json
curAscii
curChar
static/list/whitespace = list(aTab, aLineBreak, aVertTab, aFormFeed, aCarriageReturn, aSpace, aNonBreakSpace)
/datum/jsonHelper/proc/parse(json)
readPos = 0
jsonLen = length(json)
src.json = json
curAscii = 0
curChar = ""
AdvanceWS
var/value = ParseValue()
if(readPos < jsonLen)
throw EXCEPTION("Expected: End of JSON")
return value
/datum/jsonHelper/proc/ParseValue()
if(curChar == "\"")
return ParseString()
else if(curChar == "-" || (curAscii >= aZero && curAscii <= aZero + 9))
return ParseNumber()
else if(curChar == "{")
return ParseObject()
else if(curChar == "\[")
return ParseArray()
else if(curChar == "t")
if(copytext(json, readPos, readPos+4) == "true")
readPos += 3
AdvanceWS
return TRUE
else
throw EXCEPTION("Expected: 'true'")
else if(curChar == "f")
if(copytext(json, readPos, readPos+5) == "false")
readPos += 4
AdvanceWS
return FALSE
else
throw EXCEPTION("Expected: 'false'")
else if(curChar == "n")
if(copytext(json, readPos, readPos+4) == "null")
readPos += 3
AdvanceWS
return null
else
throw EXCEPTION("Expected: 'null'")
else if(curChar == "")
throw EXCEPTION("Unexpected: End of JSON")
else
throw EXCEPTION("Unexpected: '[curChar]'")
/datum/jsonHelper/proc/ParseString()
ASSERT(curChar == "\"")
Advance
var/list/chars = list()
while(readPos <= jsonLen)
if(curChar == "\"")
AdvanceWS
return list2text(chars)
else if(curChar == "\\")
Advance
switch(curChar)
if("\"", "\\", "/")
chars += ascii2text(curAscii)
if("b")
chars += ascii2text(aBackspace)
if("f")
chars += ascii2text(aFormFeed)
if("n")
chars += "\n"
if("r")
chars += ascii2text(aCarriageReturn) // Should we ignore these?
if("t")
chars += "\t"
if("u")
throw EXCEPTION("JSON \\uXXXX escape sequence not supported")
else
throw EXCEPTION("Invalid escape sequence")
Advance
else
chars += ascii2text(curAscii)
Advance
throw EXCEPTION("Unterminated string")
/datum/jsonHelper/proc/ParseNumber()
var/firstPos = readPos
if(curChar == "-")
Advance
if(curAscii >= aZero + 1 && curAscii <= aZero + 9)
do
Advance
while(curAscii >= aZero && curAscii <= aZero + 9)
else if(curAscii == aZero)
Advance
else
throw EXCEPTION("Expected: digit")
if(curChar == ".")
Advance
var/found = FALSE
while(curAscii >= aZero && curAscii <= aZero + 9)
found = TRUE
Advance
if(!found)
throw EXCEPTION("Expected: digit")
if(curChar == "E" || curChar == "e")
Advance
var/found = FALSE
if(curChar == "-")
Advance
else if(curChar == "+")
Advance
while(curAscii >= aZero && curAscii <= aZero + 9)
found = TRUE
Advance
if(!found)
throw EXCEPTION("Expected: digit")
SkipWhitespace
return text2num(copytext(json, firstPos, readPos))
/datum/jsonHelper/proc/ParseObject()
ASSERT(curChar == "{")
var/list/object = list()
AdvanceWS
while(curChar == "\"")
var/key = ParseString()
if(curChar != ":")
throw EXCEPTION("Expected: ':'")
AdvanceWS
object[key] = ParseValue()
if(curChar == ",")
AdvanceWS
else
break
if(curChar != "}")
throw EXCEPTION("Expected: string or '}'")
AdvanceWS
return object
/datum/jsonHelper/proc/ParseArray()
ASSERT(curChar == "\[")
var/list/array = list()
AdvanceWS
while(curChar != "]")
array += list(ParseValue()) // Wrapped in a list in case ParseValue() returns a list.
if(curChar == ",")
AdvanceWS
else
break
if(curChar != "]")
throw EXCEPTION("Expected: ']'")
AdvanceWS
return array
#undef aBackspace
#undef aTab
#undef aLineBreak
#undef aVertTab
#undef aFormFeed
#undef aCarriageReturn
#undef aSpace
#undef aZero
#undef aNonBreakSpace
#undef Advance
#undef SkipWhitespace
#undef AdvanceWS
+14
View File
@@ -27,6 +27,20 @@
datum/topic_state/state = default_state)
return -1 // Sorta implemented.
/**
* public
*
* Called on a NanoUI when the UI receieves a href.
* Think of this as Topic().
*
* required action string The action/button that has been invoked by the user.
* required params list A list of parameters attached to the button.
*
* return bool If the UI should be updated or not.
**/
/atom/movable/proc/ui_act(action, list/params)
return // Not implemented.
/**
* public
*
+6 -3
View File
@@ -214,7 +214,7 @@
// Generate JSON.
var/list/send_data = get_send_data(initial_data)
var/initial_data_json = replacetext(writeJson(send_data), "'", "\\'")
var/initial_data_json = replacetext(JSON.stringify(send_data), "'", "\\'")
// Generate the HTML document.
return {"
@@ -318,7 +318,7 @@
var/list/send_data = get_send_data(data) // Get the data to send.
// Send the new data to the recieveUpdate() Javascript function.
user << output(list2params(list(writeJson(send_data))), "[window_id].browser:receiveUpdate")
user << output(list2params(list(JSON.stringify(send_data))), "[window_id].browser:receiveUpdate")
/**
* private
@@ -332,7 +332,10 @@
if (status != NANO_INTERACTIVE || user != usr)
return // If UI is not interactive or usr calling Topic is not the UI user.
var/update = src_object.Topic(href, href_list, 0, state) // Call Topic() on the src_object.
var/action = href_list["nano"] // Pull the action out.
href_list -= "nano"
var/update = src_object.ui_act(action, href_list, state) // Call Topic() on the src_object.
if (src_object && update)
SSnano.update_uis(src_object) // If we have a src_object and its Topic() told us to update.
+10 -32
View File
@@ -721,22 +721,8 @@
/obj/machinery/power/apc/proc/can_use(mob/user, loud = 0) //used by attack_hand() and Topic()
if (IsAdminGhost(user))
if(IsAdminGhost(user))
return 1
if (user.stat)
user << "<span class='warning'>You must be conscious to use [src]!</span>"
return 0
if(!user.client)
return 0
if(!user.IsAdvancedToolUser())
user << "<span class='warning'>You don't have the dexterity to use [src]!</span>"
return 0
if(user.restrained())
user << "<span class='warning'>You must have free hands to use [src].</span>"
return 0
if(user.lying)
user << "<span class='warning'>You must stand to use [src]!</span>"
return 0
if(user.has_unlimited_silicon_privilege)
var/mob/living/silicon/ai/AI = user
var/mob/living/silicon/robot/robot = user
@@ -754,24 +740,16 @@
else
if ((!in_range(src, user) || !istype(src.loc, /turf)))
return 0
var/mob/living/carbon/human/H = user
if (istype(H))
if(H.getBrainLoss() >= 60)
H.visible_message("[H] stares cluelessly at [src] and drools.")
return 0
else if(prob(H.getBrainLoss()))
user << "<span class='danger'>You momentarily forget how to use [src].</span>"
return 0
return 1
/obj/machinery/power/apc/Topic(href, href_list)
/obj/machinery/power/apc/ui_act(action, params)
if(..())
return
if(!can_use(usr, 1))
return
switch(href_list["nano"])
switch(action)
if("lock")
coverlocked = !coverlocked
if ("breaker")
@@ -782,18 +760,18 @@
charging = 0
update_icon()
if("channel")
if (href_list["eqp"])
var/val = text2num(href_list["eqp"])
if (params["eqp"])
var/val = text2num(params["eqp"])
equipment = setsubsystem(val)
update_icon()
update()
else if (href_list["lgt"])
var/val = text2num(href_list["lgt"])
else if (params["lgt"])
var/val = text2num(params["lgt"])
lighting = setsubsystem(val)
update_icon()
update()
else if (href_list["env"])
var/val = text2num(href_list["env"])
else if (params["env"])
var/val = text2num(params["env"])
environ = setsubsystem(val)
update_icon()
update()
+4 -4
View File
@@ -350,11 +350,11 @@
)
return data
/obj/machinery/power/smes/Topic(href, href_list)
/obj/machinery/power/smes/ui_act(action, params)
if(..())
return
switch(href_list["nano"])
switch(action)
if("tryinput")
input_attempt = !input_attempt
log_smes(usr.ckey)
@@ -364,7 +364,7 @@
log_smes(usr.ckey)
update_icon()
if("input")
switch(href_list["set"])
switch(params["set"])
if("custom")
var/custom = input(usr, "What rate would you like this SMES to attempt to charge at? Max is [input_level_max].") as null|num
if(custom)
@@ -380,7 +380,7 @@
input_level = Clamp(input_level, 0, input_level_max)
log_smes(usr.ckey)
if("output")
switch(href_list["set"])
switch(params["set"])
if("custom")
var/custom = input(usr, "What rate would you like this SMES to attempt to output at? Max is [output_level_max].") as null|num
if(custom)
+7 -7
View File
@@ -437,24 +437,24 @@
targetdir = (targetdir + trackrate/abs(trackrate) + 360) % 360 //... do it
nexttime += 36000/abs(trackrate) //reset the counter for the next 1°
/obj/machinery/power/solar_control/Topic(href, href_list)
/obj/machinery/power/solar_control/ui_act(action, params)
if(..())
return
switch(href_list["nano"])
switch(action)
if("control")
if(href_list["cdir"])
src.cdir = dd_range(0,359,(360+src.cdir+text2num(href_list["cdir"]))%360)
if(params["cdir"])
src.cdir = dd_range(0,359,(360+src.cdir+text2num(params["cdir"]))%360)
src.targetdir = src.cdir
if(track == 2) //manual update, so losing auto-tracking
track = 0
spawn(1)
set_panels(cdir)
if(href_list["tdir"])
src.trackrate = dd_range(-7200,7200,src.trackrate+text2num(href_list["tdir"]))
if(params["tdir"])
src.trackrate = dd_range(-7200,7200,src.trackrate+text2num(params["tdir"]))
if(src.trackrate) nexttime = world.time + 36000/abs(trackrate)
if("tracking")
track = text2num(href_list["mode"])
track = text2num(params["mode"])
if(track == 2)
if(connected_tracker)
connected_tracker.set_angle(SSsun.angle)
@@ -7,6 +7,7 @@
icon_state = "dispenser"
use_power = 1
idle_power_usage = 40
interact_offline = 1
var/energy = 100
var/max_energy = 100
var/amount = 30
@@ -122,27 +123,27 @@
data["chemicals"] = chemicals
return data
/obj/machinery/chem_dispenser/Topic(href, href_list)
/obj/machinery/chem_dispenser/ui_act(action, params)
if(..())
return
switch(href_list["nano"])
switch(action)
if("amount")
amount = round(text2num(href_list["set"]), 5) // round to nearest 5
amount = round(text2num(params["set"]), 5) // round to nearest 5
if (amount < 0) // Since the user can actually type the commands himself, some sanity checking
amount = 0
if (amount > 100)
amount = 100
if("dispense")
if(beaker && dispensable_reagents.Find(href_list["reagent"]))
if(beaker && dispensable_reagents.Find(params["reagent"]))
var/datum/reagents/R = beaker.reagents
var/space = R.maximum_volume - R.total_volume
R.add_reagent(href_list["reagent"], min(amount, energy * 10, space))
R.add_reagent(params["reagent"], min(amount, energy * 10, space))
energy = max(energy - min(amount, energy * 10, space) / 10, 0)
if("remove")
if(beaker)
var/amount = text2num(href_list["amount"])
var/amount = text2num(params["amount"])
if(isnum(amount) && (amount > 0) && (amount in beaker.possible_transfer_amounts))
beaker.reagents.remove_all(amount)
if("eject")
@@ -150,7 +151,6 @@
beaker.loc = loc
beaker = null
overlays.Cut()
add_fingerprint(usr)
return 1
/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/user, params)
@@ -77,18 +77,17 @@
return
interact(user)
/obj/machinery/chem_heater/Topic(href, href_list)
/obj/machinery/chem_heater/ui_act(action, params)
if(..())
return
switch(href_list["nano"])
switch(action)
if("power")
on = !on
if("temperature")
desired_temp = Clamp(input("Please input the target temperature", name) as num, 0, 1000)
if("eject")
eject_beaker()
add_fingerprint(usr)
return 1
/obj/machinery/chem_heater/interact(mob/user)
File diff suppressed because one or more lines are too long
-34
View File
@@ -1,34 +0,0 @@
class @Handlers
constructor: (@bus, @fragment = document) ->
@bus.on "rendered", @updateStatus
@bus.on "rendered", @updateLinks
@bus.on "rendered", @attachLinks
updateStatus: (data) =>
statusicons = @fragment.queryAll ".statusicon"
statusicons.forEach (statusicon) ->
statusicon.className = statusicon.className.replace /good|bad|average/g, ""
switch data.config.status
when NANO.INTERACTIVE
klass = "good"
when NANO.UPDATE
klass = "average"
else
klass = "bad"
statusicon.classList.add klass
updateLinks: (data) =>
links = @fragment.queryAll ".link"
if data.config.status isnt NANO.INTERACTIVE
links.forEach (element) ->
element.className = "link disabled"
attachLinks: (data) =>
onClick = ->
action = @data "action"
params = JSON.parse @data "params"
if action? and params? and data.config.status is NANO.INTERACTIVE
nanoui.bycall action, params
@fragment.queryAll(".link.active").forEach (link) ->
link.on "click", onClick
-1
View File
@@ -2,7 +2,6 @@ document.when "ready", =>
coderbus = {}
@nanoui = new @NanoUI coderbus, document
@handlers = new @Handlers coderbus, document
@nanowindow = new @Window coderbus, document
coderbus.emit "memes"
+1 -1
View File
@@ -59,7 +59,7 @@ class @NanoUI
@data = @initialData
@bus.emit "initialized", data
bycall: (action, params = {}) =>
act: (action, params = {}) =>
params.src = @data.config.ref
params.nano = action
location.href = util.href null, params
+32
View File
@@ -12,6 +12,9 @@ class @Window
@attachDrag()
@attachResize()
@bus.on "rendered", @updateStatus
@bus.on "rendered", @updateLinks
@bus.on "rendered", @attachLinks
@fragment.on "keydown", @focusMap # If we get input, return focus.
setPos: (x, y) ->
@@ -86,3 +89,32 @@ class @Window
@xResize = event.screenX
@yResize = event.screenY
updateStatus: (data) =>
statusicons = @fragment.queryAll ".statusicon"
statusicons.forEach (statusicon) ->
statusicon.className = statusicon.className.replace /good|bad|average/g, ""
switch data.config.status
when NANO.INTERACTIVE
klass = "good"
when NANO.UPDATE
klass = "average"
else
klass = "bad"
statusicon.classList.add klass
updateLinks: (data) =>
links = @fragment.queryAll ".link"
if data.config.status isnt NANO.INTERACTIVE
links.forEach (element) ->
element.className = "link disabled"
attachLinks: (data) =>
onClick = ->
action = @data "action"
params = JSON.parse @data "params"
if action? and params? and data.config.status is NANO.INTERACTIVE
nanoui.act action, params
@fragment.queryAll(".link.active").forEach (link) ->
link.on "click", onClick
-1
View File
@@ -31,7 +31,6 @@
#include "code\__DEFINES\genetics.dm"
#include "code\__DEFINES\hud.dm"
#include "code\__DEFINES\is_helpers.dm"
#include "code\__DEFINES\json.dm"
#include "code\__DEFINES\machines.dm"
#include "code\__DEFINES\math.dm"
#include "code\__DEFINES\misc.dm"