mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 10:21:11 +00:00
Xenoarch analysis machines NanoUI + hotkeys. (#16412)
* Gives the xenoarch anomaly machines a nicer UI, alt and ctrl click. * Bunsen burners get an alt-click * Rework basically everything. New Hyperspectral sprite. * More sanity. * Fix code review issues
This commit is contained in:
committed by
Shadowmech88
parent
d0e5d936d8
commit
9cd53f5b6a
@@ -9,6 +9,10 @@
|
||||
//How many joules of electrical energy produce how many joules of heat energy?
|
||||
#define XENOARCH_HEAT_COEFFICIENT 3
|
||||
|
||||
#define XENOARCH_SAFETY_TEMP 350
|
||||
#define XENOARCH_MAX_TEMP 400
|
||||
// I literally don't even know why this one is different from XENOARCH_MAX_TEMP.
|
||||
#define XENOARCH_MAX_HEAT_INCREASE_TEMP 450
|
||||
|
||||
/obj/machinery/anomaly
|
||||
name = "Analysis machine"
|
||||
@@ -24,68 +28,65 @@
|
||||
machine_flags = SCREWTOGGLE | CROWDESTROY | WRENCHMOVE | FIXED2WORK
|
||||
|
||||
var/obj/item/weapon/reagent_containers/glass/held_container
|
||||
var/obj/item/weapon/tank/fuel_container
|
||||
var/target_scan_ticks = 30
|
||||
var/report_num = 0
|
||||
// How far into a scan we are.
|
||||
// If it's zero we're not scanning.
|
||||
var/scan_process = 0
|
||||
var/temperature = 273 //measured in kelvin, if this exceeds 1200, the machine is damaged and requires repairs
|
||||
//if this exceeds 600 and safety is enabled it will shutdown
|
||||
//temp greater than 600 also requires a safety prompt to initiate scanning
|
||||
var/max_temp = 450
|
||||
|
||||
/obj/machinery/anomaly/New()
|
||||
..()
|
||||
//measured in kelvin, if this exceeds 1200, the machine is damaged and requires repairs
|
||||
//if this exceeds 600 and safety is enabled it will shutdown
|
||||
//temp greater than 600 also requires a safety prompt to initiate scanning
|
||||
var/temperature = T0C
|
||||
|
||||
//for analysis debugging
|
||||
/*var/obj/item/weapon/reagent_containers/glass/solution_tray/S = new(src.loc)
|
||||
var/turf/unsimulated/mineral/diamond/D
|
||||
for(var/turf/unsimulated/mineral/diamond/M in world)
|
||||
D = M
|
||||
break
|
||||
S.reagents.add_reagent(ANALYSIS_SAMPLE, 1, D.geological_data)
|
||||
S.reagents.add_reagent(CHLORINE, 1, null)*/
|
||||
|
||||
/obj/machinery/anomaly/RefreshParts()
|
||||
var/scancount = 0
|
||||
for(var/obj/item/weapon/stock_parts/SP in component_parts)
|
||||
if(istype(SP, /obj/item/weapon/stock_parts/scanning_module))
|
||||
scancount += SP.rating-1
|
||||
for(var/obj/item/weapon/stock_parts/scanning_module/SP in component_parts)
|
||||
scancount += SP.rating-1
|
||||
|
||||
target_scan_ticks = initial(target_scan_ticks) - scancount*4
|
||||
|
||||
/obj/machinery/anomaly/power_change()
|
||||
..()
|
||||
if (stat & NOPOWER && scan_process)
|
||||
stop()
|
||||
|
||||
else
|
||||
update_icon()
|
||||
|
||||
/obj/machinery/anomaly/process()
|
||||
//not sure if everything needs to heat up, or just the GLPC
|
||||
var/datum/gas_mixture/env = loc.return_air()
|
||||
var/environmental_temp = env.temperature
|
||||
if(scan_process)
|
||||
// Shouldn't be reachable, still can't hurt.
|
||||
if(stat & NOPOWER)
|
||||
stop()
|
||||
|
||||
if(scan_process++ > target_scan_ticks)
|
||||
FinishScan()
|
||||
else if(temperature > 400)
|
||||
src.visible_message("<span class='notice'>[bicon(src)] shuts down from the heat!</span>", 2)
|
||||
else if(temperature > XENOARCH_MAX_TEMP)
|
||||
visible_message("<span class='notice'>[bicon(src)] shuts down from the heat!</span>")
|
||||
scan_process = 0
|
||||
else if(temperature > 350 && prob(10))
|
||||
src.visible_message("<span class='notice'>[bicon(src)] bleets plaintively.</span>", 2)
|
||||
if(temperature > 400)
|
||||
scan_process = 0
|
||||
else if(temperature > XENOARCH_SAFETY_TEMP && prob(10))
|
||||
visible_message("<span class='notice'>[bicon(src)] bleets plaintively.</span>")
|
||||
|
||||
//show we're busy
|
||||
if(prob(5))
|
||||
src.visible_message("<span class='notice'>[bicon(src)] [pick("whirrs","chuffs","clicks")][pick(" quietly"," softly"," sadly"," excitedly"," energetically"," angrily"," plaintively")].</span>", 2)
|
||||
visible_message("<span class='notice'>[bicon(src)] [pick("whirrs","chuffs","clicks")][pick(" quietly"," softly"," sadly"," excitedly"," energetically"," angrily"," plaintively")].</span>")
|
||||
|
||||
use_power = 2
|
||||
|
||||
icon_state = "analyser_processing"
|
||||
else
|
||||
use_power = 1
|
||||
icon_state = "analyser"
|
||||
if(prob(10))
|
||||
flick(src, "analyser_processing")
|
||||
|
||||
//Add 3000 joules when active. This is about 0.6 degrees per tick.
|
||||
//May need adjustment
|
||||
if(use_power == 1)
|
||||
var/heat_added = active_power_usage *XENOARCH_HEAT_COEFFICIENT
|
||||
|
||||
if(temperature < max_temp)
|
||||
if(temperature < XENOARCH_MAX_HEAT_INCREASE_TEMP)
|
||||
temperature += heat_added/XENOARCH_HEAT_CAPACITY
|
||||
|
||||
var/temperature_difference = abs(environmental_temp-temperature)
|
||||
@@ -100,7 +101,7 @@
|
||||
removed.temperature = max(TCMB, removed.temperature + heat_added/heat_capacity)
|
||||
|
||||
if(temperature_difference > 10 && prob(5))
|
||||
src.visible_message("<span class='notice'>[bicon(src)] hisses softly.</span>", 2)
|
||||
visible_message("<span class='notice'>[bicon(src)] hisses softly.</span>", "You hear a soft hiss.")
|
||||
|
||||
else
|
||||
//heat up to match the air
|
||||
@@ -108,107 +109,112 @@
|
||||
removed.temperature = max(TCMB, removed.temperature - heat_added/heat_capacity)
|
||||
|
||||
if(temperature_difference > 10 && prob(5))
|
||||
src.visible_message("<span class='notice'>[bicon(src)] plinks quietly.</span>", 2)
|
||||
visible_message("<span class='notice'>[bicon(src)] plinks quietly.</span>", "You hear a soft hiss.")
|
||||
|
||||
env.merge(removed)
|
||||
|
||||
nanomanager.update_uis(src)
|
||||
|
||||
//this proc should be overriden by each individual machine
|
||||
/obj/machinery/anomaly/attack_hand(var/mob/user as mob)
|
||||
if(..())
|
||||
return
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return
|
||||
user.machine = src
|
||||
var/dat = "<B>[src.name]</B><BR>"
|
||||
/obj/machinery/anomaly/attack_hand(var/mob/user)
|
||||
ui_interact(user)
|
||||
|
||||
dat += {"Module heat level: [temperature] kelvin<br>
|
||||
Safeties set at 350k, shielding failure at 400k. Failure to maintain safe heat levels may result in equipment damage.<br>
|
||||
<hr>"}
|
||||
if(scan_process)
|
||||
dat += "Scan in progress<br><br><br>"
|
||||
else
|
||||
dat += "[held_container ? "<A href='?src=\ref[src];eject_beaker=1'>Eject beaker</a>" : "No beaker inserted."]<br>"
|
||||
//dat += "[fuel_container ? "<A href='?src=\ref[src];eject_fuel=1'>Eject fuel tank</a>" : "No fuel tank inserted."]<br>"
|
||||
dat += "[held_container ? "<A href='?src=\ref[src];begin=1'>Begin scanning</a>" : ""]"
|
||||
|
||||
dat += {"<hr>
|
||||
<A href='?src=\ref[src];refresh=1'>Refresh</a><BR>
|
||||
<A href='?src=\ref[src];close=1'>Close</a><BR>"}
|
||||
user << browse(dat, "window=anomaly;size=450x500")
|
||||
onclose(user, "anomaly")
|
||||
|
||||
obj/machinery/anomaly/attackby(obj/item/weapon/W as obj, mob/living/user as mob)
|
||||
obj/machinery/anomaly/attackby(obj/item/weapon/W, mob/living/user)
|
||||
if(istype(W, /obj/item/weapon/reagent_containers/glass))
|
||||
//var/obj/item/weapon/reagent_containers/glass/G = W
|
||||
if(held_container)
|
||||
to_chat(user, "<span class='warning'>You must remove the [held_container] first.</span>")
|
||||
else
|
||||
if(user.drop_item(W, src))
|
||||
to_chat(user, "<span class='notice'>You put the [W] into the [src].</span>")
|
||||
to_chat(user, "<span class='warning'>You must remove \the [held_container] first.</span>")
|
||||
return TRUE
|
||||
|
||||
held_container = W
|
||||
updateDialog()
|
||||
if(user.drop_item(W, src))
|
||||
to_chat(user, "<span class='notice'>You put \the [W] into the [src].</span>")
|
||||
|
||||
return 1 // avoid afterattack() being called
|
||||
/*else if(istype(W, /obj/item/weapon/tank))
|
||||
//var/obj/item/weapon/reagent_containers/glass/G = W
|
||||
if(fuel_container)
|
||||
to_chat(user, "<span class='warning'>You must remove the [fuel_container] first.</span>")
|
||||
else
|
||||
to_chat(user, "<span class='notice'>You put the [fuel_container] into the [src].</span>")
|
||||
user.drop_item(W, src)
|
||||
fuel_container.forceMove(src)
|
||||
fuel_container = W
|
||||
updateDialog()*/
|
||||
else
|
||||
return ..()
|
||||
held_container = W
|
||||
nanomanager.update_uis(src)
|
||||
|
||||
obj/machinery/anomaly/proc/ScanResults()
|
||||
//instantiate in children to produce unique scan behaviour
|
||||
return TRUE
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/machinery/anomaly/proc/ScanResults()
|
||||
// Override in children to produce unique scan behaviour.
|
||||
return "<span class='warning'>Error initialising scanning components.</span>"
|
||||
|
||||
obj/machinery/anomaly/proc/FinishScan()
|
||||
scan_process = 0
|
||||
updateDialog()
|
||||
/obj/machinery/anomaly/proc/FinishScan()
|
||||
stop()
|
||||
|
||||
//determine the results and print a report
|
||||
if(held_container)
|
||||
src.visible_message("<span class='notice'>[bicon(src)] makes an insistent chime.</span>", 2)
|
||||
var/obj/item/weapon/paper/P = new(src.loc)
|
||||
src.visible_message("<span class='notice'>[bicon(src)] makes an insistent chime.</span>", "You hear an insistent chime.")
|
||||
var/obj/item/weapon/paper/P = new(loc)
|
||||
P.name = "[src] report #[++report_num]"
|
||||
P.info = "<b>[src] analysis report #[report_num]</b><br><br>" + ScanResults()
|
||||
P.stamped = list(/obj/item/weapon/stamp)
|
||||
P.overlays = list("paper_stamp-qm")
|
||||
P.overlays += "paper_stamp-qm"
|
||||
else
|
||||
src.visible_message("<span class='notice'>[bicon(src)] makes a low buzzing noise.</span>", 2)
|
||||
visible_message("<span class='notice'>[bicon(src)] makes a low buzzing noise.</span>", "You hear a low buzz.")
|
||||
|
||||
obj/machinery/anomaly/Topic(href, href_list)
|
||||
if(..())
|
||||
. = ..()
|
||||
if (.)
|
||||
return
|
||||
usr.set_machine(src)
|
||||
if(href_list["close"])
|
||||
usr << browse(null, "window=anomaly")
|
||||
usr.machine = null
|
||||
if(href_list["eject_beaker"])
|
||||
held_container.forceMove(src.loc)
|
||||
held_container = null
|
||||
if(href_list["eject_fuel"])
|
||||
fuel_container.forceMove(src.loc)
|
||||
fuel_container = null
|
||||
if(href_list["begin"])
|
||||
if(temperature >= 350)
|
||||
var/proceed = input("Unsafe internal temperature detected, enter YES below to continue.","Warning")
|
||||
if(proceed == "YES" && !..()) //call parent again to run distance and power checks again.
|
||||
scan_process = 1
|
||||
else
|
||||
scan_process = 1
|
||||
|
||||
updateUsrDialog()
|
||||
if (href_list["eject"] && held_container && !scan_process)
|
||||
eject()
|
||||
. = 1
|
||||
|
||||
if (href_list["begin"] && !scan_process && held_container)
|
||||
start(usr)
|
||||
. = 1
|
||||
|
||||
if (href_list["stop"] && scan_process)
|
||||
stop()
|
||||
. = 1
|
||||
|
||||
/obj/machinery/anomaly/proc/eject()
|
||||
held_container.forceMove(loc)
|
||||
held_container = null
|
||||
nanomanager.update_uis(src)
|
||||
|
||||
/obj/machinery/anomaly/proc/start(var/mob/user)
|
||||
if (temperature >= XENOARCH_SAFETY_TEMP)
|
||||
var/proceed = input("Unsafe internal temperature detected, enter YES below to continue.","Warning")
|
||||
if (proceed != "YES" || user.incapacitated() || !user.Adjacent(src))
|
||||
return FALSE
|
||||
|
||||
scan_process = 1
|
||||
update_icon()
|
||||
nanomanager.update_uis(src)
|
||||
|
||||
/obj/machinery/anomaly/proc/stop()
|
||||
scan_process = 0
|
||||
update_icon()
|
||||
nanomanager.update_uis(src)
|
||||
|
||||
/obj/machinery/anomaly/update_icon()
|
||||
if (scan_process)
|
||||
icon_state = "analyser_processing"
|
||||
|
||||
else
|
||||
icon_state = "analyser"
|
||||
|
||||
|
||||
/obj/machinery/anomaly/AltClick(var/mob/user)
|
||||
if (user.incapacitated() || !user.Adjacent(src) || scan_process || !held_container || stat & NOPOWER)
|
||||
return
|
||||
|
||||
eject()
|
||||
|
||||
/obj/machinery/anomaly/CtrlClick(var/mob/user)
|
||||
if (!anchored)
|
||||
return ..()
|
||||
|
||||
if (user.incapacitated() || !user.Adjacent(src) || scan_process || !held_container || stat & NOPOWER)
|
||||
return
|
||||
|
||||
start(user)
|
||||
|
||||
//whether the carrier sample matches the possible finds
|
||||
//results greater than a threshold of 0.6 means a positive result
|
||||
obj/machinery/anomaly/proc/GetResultSpecifity(var/datum/geosample/scanned_sample, var/carrier_name)
|
||||
/obj/machinery/anomaly/proc/GetResultSpecifity(var/datum/geosample/scanned_sample, var/carrier_name)
|
||||
var/specifity = 0
|
||||
if(scanned_sample && carrier_name)
|
||||
|
||||
@@ -218,3 +224,37 @@ obj/machinery/anomaly/proc/GetResultSpecifity(var/datum/geosample/scanned_sample
|
||||
specifity = rand(0, 0.5)
|
||||
|
||||
return specifity
|
||||
|
||||
/obj/machinery/anomaly/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = NANOUI_FOCUS)
|
||||
if (stat & NOPOWER)
|
||||
return
|
||||
|
||||
var/list/data[0]
|
||||
data["max_temperature"] = XENOARCH_MAX_TEMP
|
||||
data["safety_temperature"] = XENOARCH_SAFETY_TEMP
|
||||
data["temperature"] = temperature
|
||||
|
||||
data["target_ticks"] = target_scan_ticks
|
||||
data["scan_process"] = scan_process
|
||||
|
||||
data["beaker"] = !!held_container
|
||||
if (held_container)
|
||||
data["beaker_name"] = held_container.name
|
||||
var/list/beaker_contents[0]
|
||||
for(var/datum/reagent/R in held_container.reagents.reagent_list)
|
||||
beaker_contents[++beaker_contents.len] = list(
|
||||
"name" = R.name,
|
||||
"volume" = R.volume
|
||||
)
|
||||
|
||||
data["beaker_contents"] = beaker_contents
|
||||
|
||||
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
|
||||
if (!ui)
|
||||
// the ui does not exist, so we'll create a new() one
|
||||
// for a list of parameters and their descriptions see the code docs in \code\\modules\nano\nanoui.dm
|
||||
ui = new(user, src, ui_key, "xenoarch_analysis.tmpl", name, 480, 400)
|
||||
// when the ui is first opened this is the data it will use
|
||||
ui.set_initial_data(data)
|
||||
// open the new ui window
|
||||
ui.open()
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/obj/machinery/anomaly/hyperspectral
|
||||
name = "Hyperspectral Imager"
|
||||
icon = 'icons/obj/xenoarchaeology.dmi'
|
||||
icon_state = "scanner"
|
||||
icon_state = "hyperspectral"
|
||||
light_power = 0.75
|
||||
light_color = LIGHT_COLOR_GREEN
|
||||
|
||||
/obj/machinery/anomaly/hyperspectral/New()
|
||||
. = ..()
|
||||
@@ -15,15 +17,26 @@
|
||||
|
||||
RefreshParts()
|
||||
|
||||
/obj/machinery/anomaly/hyperspectral/process()
|
||||
..()
|
||||
if(scan_process)
|
||||
icon_state = "scanner_active"
|
||||
else
|
||||
icon_state = "scanner"
|
||||
if(prob(10))
|
||||
flick(src, "scanner_active")
|
||||
/obj/machinery/anomaly/hyperspectral/update_icon()
|
||||
overlays.Cut()
|
||||
if (stat & (NOPOWER | BROKEN))
|
||||
return
|
||||
|
||||
overlays += "hyperspectral_on"
|
||||
|
||||
if (scan_process)
|
||||
overlays += "hyperspectral_active"
|
||||
|
||||
if (panel_open)
|
||||
overlays += "hyperspectral_panel"
|
||||
|
||||
/obj/machinery/anomaly/hyperspectral/start(var/mob/user)
|
||||
..()
|
||||
set_light(2)
|
||||
|
||||
/obj/machinery/anomaly/hyperspectral/stop()
|
||||
..()
|
||||
set_light(0)
|
||||
|
||||
/obj/machinery/anomaly/hyperspectral/ScanResults()
|
||||
var/results = "The scan was inconclusive. Check sample integrity and carrier consistency."
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
if(held_container)
|
||||
held_container.forceMove(get_turf(src))
|
||||
held_container = null
|
||||
processing_objects.Remove(src)
|
||||
..()
|
||||
|
||||
/obj/machinery/bunsen_burner/attackby(obj/item/weapon/W, mob/user)
|
||||
@@ -128,14 +129,23 @@
|
||||
else
|
||||
toggle()
|
||||
|
||||
/obj/machinery/bunsen_burner/verb/toggle()
|
||||
/obj/machinery/bunsen_burner/verb/verb_toggle()
|
||||
set src in view(1)
|
||||
set name = "Toggle bunsen burner"
|
||||
set category = "Object"
|
||||
|
||||
if (!usr.Adjacent(src) || usr.incapacitated())
|
||||
return
|
||||
|
||||
toggle()
|
||||
|
||||
/obj/machinery/bunsen_burner/proc/toggle()
|
||||
heating = !heating
|
||||
update_icon()
|
||||
if(heating)
|
||||
processing_objects.Add(src)
|
||||
else
|
||||
processing_objects.Remove(src)
|
||||
|
||||
/obj/machinery/bunsen_burner/AltClick()
|
||||
toggle()
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 81 KiB |
50
nano/templates/xenoarch_analysis.tmpl
Normal file
50
nano/templates/xenoarch_analysis.tmpl
Normal file
@@ -0,0 +1,50 @@
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Temperature:
|
||||
</div>
|
||||
{{:helper.displayBar(data.temperature, 273.15, data.max_temperature, data.temperature > data.safety_temperature ? "bad" : "good")}}
|
||||
<div class="itemContent" style="width: 60px">
|
||||
{{:helper.round(data.temperature)}} K
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Scan Status:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.displayBar(data.scan_process-1, 0, data.target_ticks)}}
|
||||
<div style="clear: both; padding-top: 4px;">
|
||||
{{:helper.link("start", "check", {"begin": 1}, (data.scan_process || !data.beaker) ? "disabled" : null)}}
|
||||
{{:helper.link("abort", "cancel", {"stop": 1}, data.scan_process ? null : "disabled", data.scan_process ? "redBackground" : null)}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Holding Container Status</h3>
|
||||
{{if data.beaker}}
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Container:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
<div style="float: left; width: 180px;">{{:data.beaker_name}}</div> {{:helper.link('Eject', 'eject', {'eject' : 1}, data.scan_process ? "disabled" : null)}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="statusDisplay" style="min-height: 180px;">
|
||||
<div class="item">
|
||||
<div class="itemContent" style="width: 100%;">
|
||||
{{for data.beaker_contents}}
|
||||
<span class="highlight">{{:value.volume}} units of {{:value.name}}</span><br>
|
||||
{{empty}}
|
||||
<span class="bad">
|
||||
Container is empty.
|
||||
</span>
|
||||
{{/for}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="item"><span class="average"><i>No container inserted.</i></span></div>
|
||||
{{/if}}
|
||||
Reference in New Issue
Block a user