Merge remote-tracking branch 'citadel/master' into auxtools-atmos

This commit is contained in:
silicons
2021-04-27 00:59:45 -07:00
679 changed files with 317691 additions and 310960 deletions
+12 -5
View File
@@ -137,7 +137,7 @@ Class Procs:
GLOB.machines += src
if(ispath(circuit, /obj/item/circuitboard))
circuit = new circuit
circuit = new circuit(src)
circuit.apply_default_parts(src)
if(!speed_process && init_process)
@@ -361,11 +361,11 @@ Class Procs:
/obj/machinery/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
on_deconstruction()
if(component_parts && component_parts.len)
if(LAZYLEN(component_parts))
spawn_frame(disassembled)
for(var/obj/item/I in component_parts)
I.forceMove(loc)
component_parts.Cut()
LAZYCLEARLIST(component_parts)
qdel(src)
/obj/machinery/proc/spawn_frame(disassembled)
@@ -519,6 +519,8 @@ Class Procs:
//called on machinery construction (i.e from frame to machinery) but not on initialization
/obj/machinery/proc/on_construction()
for(var/obj/I in contents)
I.moveToNullspace()
return
//called on deconstruction before the final deletion
@@ -539,12 +541,17 @@ Class Procs:
/obj/machinery/Exited(atom/movable/AM, atom/newloc)
. = ..()
// if(AM == occupant)
// set_occupant(null)
if (AM == occupant)
SEND_SIGNAL(src, COMSIG_MACHINE_EJECT_OCCUPANT, occupant)
occupant = null
if(AM == circuit && circuit.loc != src)
component_parts -= AM //TODO: make the cmp part functions use lazyX
circuit = null
/obj/machinery/proc/adjust_item_drop_location(atom/movable/AM) // Adjust item drop location to a 3x3 grid inside the tile, returns slot id from 0 to 8
var/md5 = md5(AM.name) // Oh, and it's deterministic too. A specific item will always drop from the same slot.
/obj/machinery/proc/adjust_item_drop_location(atom/movable/AM) // Adjust item drop location to a 3x3 grid inside the tile, returns slot id from 0 to 8
var/md5 = md5(AM.name) // Oh, and it's deterministic too. A specific item will always drop from the same slot.
for (var/i in 1 to 32)
. += hex2num(md5[i])
. = . % 9
+13 -1
View File
@@ -8,7 +8,19 @@
max_integrity = 200
var/obj/item/bodypart/storedpart
var/initial_icon_state
var/static/list/style_list_icons = list("standard" = 'icons/mob/augmentation/augments.dmi', "engineer" = 'icons/mob/augmentation/augments_engineer.dmi', "security" = 'icons/mob/augmentation/augments_security.dmi', "mining" = 'icons/mob/augmentation/augments_mining.dmi')
var/static/list/style_list_icons = list("standard" = 'icons/mob/augmentation/augments.dmi',
"engineer" = 'icons/mob/augmentation/augments_engineer.dmi',
"security" = 'icons/mob/augmentation/augments_security.dmi',
"mining" = 'icons/mob/augmentation/augments_mining.dmi',
"Talon" = 'icons/mob/augmentation/cosmetic_prosthetic/talon.dmi',
"Nanotrasen" = 'icons/mob/augmentation/cosmetic_prosthetic/nanotrasen.dmi',
"Hephaesthus" = 'icons/mob/augmentation/cosmetic_prosthetic/hephaestus.dmi',
"Bishop" = 'icons/mob/augmentation/cosmetic_prosthetic/bishop.dmi',
"Xion" = 'icons/mob/augmentation/cosmetic_prosthetic/xion.dmi',
"Grayson" = 'icons/mob/augmentation/cosmetic_prosthetic/grayson.dmi',
"Cybersolutions" = 'icons/mob/augmentation/cosmetic_prosthetic/cybersolutions.dmi',
"Ward" = 'icons/mob/augmentation/cosmetic_prosthetic/ward.dmi'
)
/obj/machinery/aug_manipulator/examine(mob/user)
. = ..()
+17 -3
View File
@@ -48,13 +48,14 @@
)
/obj/machinery/autolathe/Initialize()
AddComponent(/datum/component/material_container, SSmaterials.materialtypes_by_category[MAT_CATEGORY_RIGID], 0, TRUE, null, null, CALLBACK(src, .proc/AfterMaterialInsert))
. = ..()
wires = new /datum/wires/autolathe(src)
stored_research = new /datum/techweb/specialized/autounlocking/autolathe
matching_designs = list()
/obj/machinery/autolathe/ComponentInitialize()
AddComponent(/datum/component/material_container, SSmaterials.materialtypes_by_category[MAT_CATEGORY_RIGID], 0, TRUE, null, null, CALLBACK(src, .proc/AfterMaterialInsert))
/obj/machinery/autolathe/Destroy()
QDEL_NULL(wires)
return ..()
@@ -439,6 +440,9 @@
/obj/machinery/autolathe/secure/Initialize()
. = ..()
// let's not leave the parent datum floating, right?
if(stored_research)
QDEL_NULL(stored_research)
stored_research = new /datum/techweb/specialized/autounlocking/autolathe/public
/obj/machinery/autolathe/toy
@@ -457,8 +461,18 @@
"Misc",
"Imported"
)
/obj/machinery/autolathe/toy/Initialize()
. = ..()
// let's not leave the parent datum floating, right?
if(stored_research)
QDEL_NULL(stored_research)
stored_research = new /datum/techweb/specialized/autounlocking/autolathe/toy
/obj/machinery/autolathe/toy/hacked/Initialize()
. = ..()
adjust_hacked(TRUE)
stored_research = new /datum/techweb/specialized/autounlocking/autolathe/toy
// override the base to allow plastics
/obj/machinery/autolathe/ComponentInitialize()
var/list/extra_mats = list(/datum/material/plastic)
AddComponent(/datum/component/material_container, SSmaterials.materialtypes_by_category[MAT_CATEGORY_RIGID] + extra_mats, 0, TRUE, null, null, CALLBACK(src, .proc/AfterMaterialInsert))
+31 -23
View File
@@ -17,20 +17,16 @@
/obj/machinery/computer/Initialize(mapload, obj/item/circuitboard/C)
. = ..()
power_change()
if(!QDELETED(C))
qdel(circuit)
circuit = C
C.moveToNullspace()
/obj/machinery/computer/Destroy()
QDEL_NULL(circuit)
return ..()
. = ..()
/obj/machinery/computer/process()
if(stat & (NOPOWER|BROKEN))
return 0
return 1
return FALSE
return TRUE
/obj/machinery/computer/ratvar_act()
if(!clockwork)
@@ -87,25 +83,32 @@
switch(damage_type)
if(BRUTE)
if(stat & BROKEN)
playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1)
playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 70, TRUE)
else
playsound(src.loc, 'sound/effects/glasshit.ogg', 75, 1)
playsound(src.loc, 'sound/effects/glasshit.ogg', 75, TRUE)
if(BURN)
playsound(src.loc, 'sound/items/welder.ogg', 100, 1)
playsound(src.loc, 'sound/items/welder.ogg', 100, TRUE)
/obj/machinery/computer/obj_break(damage_flag)
if(circuit && !(flags_1 & NODECONSTRUCT_1)) //no circuit, no breaking
if(!(stat & BROKEN))
playsound(loc, 'sound/effects/glassbr3.ogg', 100, 1)
stat |= BROKEN
update_icon()
set_light(0)
if(!circuit) //no circuit, no breaking
return
. = ..()
if(. && !(stat & BROKEN))
stat |= BROKEN
playsound(loc, 'sound/effects/glassbr3.ogg', 100, TRUE)
set_light(0)
update_icon()
/obj/machinery/computer/emp_act(severity)
. = ..()
if (!(. & EMP_PROTECT_SELF))
if(prob(severity/1.8))
obj_break("energy")
switch(severity)
if(1)
if(prob(50))
obj_break("energy")
if(2)
if(prob(10))
obj_break("energy")
/obj/machinery/computer/deconstruct(disassembled = TRUE, mob/user)
on_deconstruction()
@@ -114,12 +117,14 @@
var/obj/structure/frame/computer/A = new /obj/structure/frame/computer(src.loc)
A.setDir(dir)
A.circuit = circuit
A.setAnchored(TRUE)
// Circuit removal code is handled in /obj/machinery/Exited()
circuit.forceMove(A)
A.set_anchored(TRUE)
if(stat & BROKEN)
if(user)
to_chat(user, "<span class='notice'>The broken glass falls out.</span>")
else
playsound(src, 'sound/effects/hit_on_shattered_glass.ogg', 70, 1)
playsound(src, 'sound/effects/hit_on_shattered_glass.ogg', 70, TRUE)
new /obj/item/shard(drop_location())
new /obj/item/shard(drop_location())
A.state = 3
@@ -129,8 +134,11 @@
to_chat(user, "<span class='notice'>You disconnect the monitor.</span>")
A.state = 4
A.icon_state = "4"
circuit = null
for(var/obj/C in src)
C.forceMove(loc)
qdel(src)
/obj/machinery/computer/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, !issilicon(user)) || !(stat & (NOPOWER|BROKEN)))
return
+56 -16
View File
@@ -3,7 +3,7 @@
icon_state = "0"
state = 0
/obj/structure/frame/computer/attackby(obj/item/P, mob/user, params)
/obj/structure/frame/computer/attackby(obj/item/P, mob/living/user, params)
add_fingerprint(user)
switch(state)
if(0)
@@ -11,7 +11,7 @@
to_chat(user, "<span class='notice'>You start wrenching the frame into place...</span>")
if(P.use_tool(src, user, 20, volume=50))
to_chat(user, "<span class='notice'>You wrench the frame into place.</span>")
setAnchored(TRUE)
set_anchored(TRUE)
state = 1
return
if(P.tool_behaviour == TOOL_WELDER)
@@ -19,7 +19,7 @@
return
to_chat(user, "<span class='notice'>You start deconstructing the frame...</span>")
if(P.use_tool(src, user, 20, volume=50) && state == 0)
if(P.use_tool(src, user, 20, volume=50))
to_chat(user, "<span class='notice'>You deconstruct the frame.</span>")
var/obj/item/stack/sheet/metal/M = new (drop_location(), 5)
M.add_fingerprint(user)
@@ -28,15 +28,15 @@
if(1)
if(P.tool_behaviour == TOOL_WRENCH)
to_chat(user, "<span class='notice'>You start to unfasten the frame...</span>")
if(P.use_tool(src, user, 20, volume=50) && state == 1)
if(P.use_tool(src, user, 20, volume=50))
to_chat(user, "<span class='notice'>You unfasten the frame.</span>")
setAnchored(FALSE)
set_anchored(FALSE)
state = 0
return
if(istype(P, /obj/item/circuitboard/computer) && !circuit)
if(!user.transferItemToLoc(P, src))
return
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
to_chat(user, "<span class='notice'>You place [P] inside the frame.</span>")
icon_state = "1"
circuit = P
@@ -71,8 +71,10 @@
if(istype(P, /obj/item/stack/cable_coil))
if(!P.tool_start_check(user, amount=5))
return
if(state != 2)
return
to_chat(user, "<span class='notice'>You start adding cables to the frame...</span>")
if(P.use_tool(src, user, 20, 5, 50, CALLBACK(src, .proc/check_state, 2)))
if(P.use_tool(src, user, 20, volume=50, amount=5))
to_chat(user, "<span class='notice'>You add cables to the frame.</span>")
state = 3
icon_state = "3"
@@ -90,9 +92,11 @@
if(istype(P, /obj/item/stack/sheet/glass))
if(!P.tool_start_check(user, amount=2))
return
playsound(src, 'sound/items/deconstruct.ogg', 50, 1)
if(state != 3)
return
playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE)
to_chat(user, "<span class='notice'>You start to put in the glass panel...</span>")
if(P.use_tool(src, user, 20, 2, 0, CALLBACK(src, .proc/check_state, 3)))
if(P.use_tool(src, user, 20, amount=2))
to_chat(user, "<span class='notice'>You put in the glass panel.</span>")
state = 4
src.icon_state = "4"
@@ -109,14 +113,51 @@
if(P.tool_behaviour == TOOL_SCREWDRIVER)
P.play_tool_sound(src)
to_chat(user, "<span class='notice'>You connect the monitor.</span>")
var/obj/B = new circuit.build_path (loc, circuit)
B.setDir(dir)
transfer_fingerprints_to(B)
var/obj/machinery/new_machine = new circuit.build_path(loc)
new_machine.setDir(dir)
transfer_fingerprints_to(new_machine)
if(istype(new_machine, /obj/machinery/computer))
var/obj/machinery/computer/new_computer = new_machine
// Machines will init with a set of default components.
// Triggering handle_atom_del will make the machine realise it has lost a component_parts and then deconstruct.
// Move to nullspace so we don't trigger handle_atom_del, then qdel.
// Finally, replace new machine's parts with this frame's parts.
if(new_computer.circuit)
// Move to nullspace and delete.
new_computer.circuit.moveToNullspace()
QDEL_NULL(new_computer.circuit)
for(var/old_part in new_computer.component_parts)
var/atom/movable/movable_part = old_part
// Move to nullspace and delete.
movable_part.moveToNullspace()
qdel(movable_part)
// Set anchor state and move the frame's parts over to the new machine.
// Then refresh parts and call on_construction().
new_computer.set_anchored(anchored)
new_computer.component_parts = list()
circuit.forceMove(new_computer)
new_computer.component_parts += circuit
new_computer.circuit = circuit
for(var/new_part in src)
var/atom/movable/movable_part = new_part
movable_part.forceMove(new_computer)
new_computer.component_parts += movable_part
new_computer.RefreshParts()
new_computer.on_construction()
qdel(src)
return
if(user.a_intent == INTENT_HARM)
return ..()
/obj/structure/frame/computer/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
if(state == 4)
@@ -127,13 +168,12 @@
..()
/obj/structure/frame/computer/AltClick(mob/user)
. = ..()
if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
..()
if(!user.canUseTopic(src, BE_CLOSE, TRUE, FALSE))
return
if(anchored)
to_chat(usr, "<span class='warning'>You must unwrench [src] before rotating it!</span>")
return TRUE
return
setDir(turn(dir, -90))
return TRUE
+225 -304
View File
@@ -13,7 +13,7 @@
var/temp = "Inactive"
var/scantemp_ckey
var/scantemp_name
var/scantemp = "Ready to Scan"
var/scantemp = "Inactive"
var/menu = 1 //Which menu screen to display
var/datum/data/record/active_record = null
var/obj/item/disk/data/diskette = null //Mostly so the geneticist can steal everything.
@@ -132,7 +132,6 @@
src.diskette = W
to_chat(user, "<span class='notice'>You insert [W].</span>")
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
src.updateUsrDialog()
else if(W.tool_behaviour == TOOL_MULTITOOL)
if(istype(W.buffer, clonepod_type))
if(get_area(W.buffer) != get_area(src))
@@ -151,311 +150,233 @@
else
return ..()
/obj/machinery/computer/cloning/ui_interact(mob/user)
/obj/machinery/computer/cloning/AltClick(mob/user)
. = ..()
EjectDisk(user)
updatemodules(TRUE)
/obj/machinery/computer/cloning/proc/EjectDisk(mob/user)
if(diskette)
scantemp = "Disk Ejected"
diskette.forceMove(drop_location())
usr.put_in_active_hand(diskette)
diskette = null
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
var/dat = ""
dat += "<a href='byond://?src=[REF(src)];refresh=1'>Refresh</a>"
/obj/machinery/computer/cloning/proc/Save(mob/user, target)
var/datum/data/record/GRAB = null
for(var/datum/data/record/record in records)
if(record.fields["id"] == target)
GRAB = record
break
else
continue
if(!GRAB || !GRAB.fields)
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
scantemp = "Failed saving to disk: Data Corruption"
return FALSE
if(!diskette || diskette.read_only)
scantemp = !diskette ? "Failed saving to disk: No disk." : "Failed saving to disk: Disk refuses override attempt."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
diskette.fields = GRAB.fields.Copy()
diskette.name = "data disk - '[src.diskette.fields["name"]]'"
scantemp = "Saved to disk successfully."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
/obj/machinery/computer/cloning/proc/DeleteRecord(mob/user, target)
var/datum/data/record/GRAB = null
for(var/datum/data/record/record in records)
if(record.fields["id"] == target)
GRAB = record
break
else
continue
if(!GRAB)
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
scantemp = "Cannot delete: Data Corrupted."
return FALSE
var/obj/item/card/id/C = usr.get_idcard(hand_first = TRUE)
if(istype(C) || istype(C, /obj/item/pda) || istype(C, /obj/item/modular_computer/tablet))
if(check_access(C))
scantemp = "[GRAB.fields["name"]] => Record deleted."
records.Remove(GRAB)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
var/obj/item/circuitboard/computer/cloning/board = circuit
board.records = records
return TRUE
scantemp = "Cannot delete: Access Denied."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
/obj/machinery/computer/cloning/proc/Load(mob/user)
if(!diskette || !istype(diskette.fields) || !diskette.fields["name"] || !diskette.fields)
scantemp = "Failed loading: Load error."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
for(var/datum/data/record/R in records)
if(R.fields["key"] == diskette.fields["key"])
scantemp = "Failed loading: Data already exists!"
return FALSE
var/datum/data/record/R = new(src)
for(var/key in diskette.fields)
R.fields[key] = diskette.fields[key]
records += R
scantemp = "Loaded into internal storage successfully."
var/obj/item/circuitboard/computer/cloning/board = circuit
board.records = records
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
/obj/machinery/computer/cloning/proc/Clone(mob/user, target)
var/datum/data/record/C = find_record("id", target, records)
//Look for that player! They better be dead!
if(C)
var/obj/machinery/clonepod/pod = GetAvailablePod()
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!LAZYLEN(pods))
temp = "Error: No Clonepods detected."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!pod)
temp = "Error: No Clonepods available."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!CONFIG_GET(flag/revival_cloning))
temp = "Error: Unable to initiate cloning cycle."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.occupant)
temp = "Warning: Cloning cycle already in progress."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["blood_type"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"], C.fields["bank_account"], C.fields["traumas"]))
temp = "Notice: [C.fields["name"]] => Cloning cycle in progress..."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
records.Remove(C)
else
temp = "Error: [C.fields["name"]] => Initialisation failure."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
temp = "Failed to clone: Data corrupted."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
. = TRUE
/obj/machinery/computer/cloning/proc/Toggle_lock(mob/user)
if(!scanner.is_operational())
return
if(!scanner.locked && !scanner.occupant) //I figured out that if you're fast enough, you can lock an open pod
return
scanner.locked = !scanner.locked
playsound(src, scanner.locked ? 'sound/machines/terminal_prompt_deny.ogg' : 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
. = TRUE
/obj/machinery/computer/cloning/proc/Scan(mob/user)
if(!scanner.is_operational() || !scanner.occupant)
return
scantemp = "[scantemp_name] => Scanning..."
loading = TRUE
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
say("Initiating scan...")
var/prev_locked = scanner.locked
scanner.locked = TRUE
addtimer(CALLBACK(src, .proc/finish_scan, scanner.occupant, prev_locked), 2 SECONDS)
. = TRUE
/obj/machinery/computer/cloning/proc/Toggle_autoprocess(mob/user)
autoprocess = !autoprocess
if(autoprocess)
START_PROCESSING(SSmachines, src)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
else
STOP_PROCESSING(SSmachines, src)
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
. = TRUE
/obj/machinery/computer/cloning/ui_data(mob/user)
var/list/data = list()
data["useRecords"] = use_records
var/list/records_to_send = list()
if(use_records)
if(scanner && HasEfficientPod() && scanner.scan_level >= AUTOCLONING_MINIMAL_LEVEL)
if(!autoprocess)
dat += "<a href='byond://?src=[REF(src)];task=autoprocess'>Autoclone</a>"
else
dat += "<a href='byond://?src=[REF(src)];task=stopautoprocess'>Stop autoclone</a>"
else
dat += "<span class='linkOff'>Autoclone</span>"
dat += "<h3>Cloning Pod Status</h3>"
dat += "<div class='statusDisplay'>[temp]&nbsp;</div>"
switch(src.menu)
if(1)
// Modules
if (isnull(src.scanner) || !LAZYLEN(pods))
dat += "<h3>Modules</h3>"
//dat += "<a href='byond://?src=[REF(src)];relmodules=1'>Reload Modules</a>"
if (isnull(src.scanner))
dat += "<font class='bad'>ERROR: No Scanner detected!</font><br>"
if (!LAZYLEN(pods))
dat += "<font class='bad'>ERROR: No Pod detected</font><br>"
// Scanner
if (!isnull(src.scanner))
var/mob/living/scanner_occupant = get_mob_or_brainmob(scanner.occupant)
dat += "<h3>Scanner Functions</h3>"
dat += "<div class='statusDisplay'>"
if(!scanner_occupant)
dat += "Scanner Unoccupied"
else if(loading)
dat += "[scanner_occupant] => Scanning..."
else
if(use_records)
if(scanner_occupant.ckey != scantemp_ckey || scanner_occupant.name != scantemp_name)
scantemp = "Ready to Scan"
scantemp_ckey = scanner_occupant.ckey
scantemp_name = scanner_occupant.name
else
scantemp = "Ready to Clone"
dat += "[scanner_occupant] => [scantemp]"
dat += "</div>"
if(scanner_occupant)
dat += "<a href='byond://?src=[REF(src)];scan=1'>[use_records ? "Start Scan" : "Clone"]</a>"
dat += "<br><a href='byond://?src=[REF(src)];lock=1'>[scanner.locked ? "Unlock Scanner" : "Lock Scanner"]</a>"
else
dat += "<span class='linkOff'>[use_records ? "Start Scan" : "Clone"]</span>"
if(use_records)
// Database
dat += "<h3>Database Functions</h3>"
if (src.records.len && src.records.len > 0)
dat += "<a href='byond://?src=[REF(src)];menu=2'>View Records ([src.records.len])</a><br>"
else
dat += "<span class='linkOff'>View Records (0)</span><br>"
if (src.diskette)
dat += "<a href='byond://?src=[REF(src)];disk=eject'>Eject Disk</a><br>"
if(2)
dat += "<h3>Current records</h3>"
dat += "<a href='byond://?src=[REF(src)];menu=1'><< Back</a><br><br>"
data["hasAutoprocess"] = TRUE
if(length(records))
for(var/datum/data/record/R in records)
dat += "<h4>[R.fields["name"]]</h4>Scan ID [R.fields["id"]] <a href='byond://?src=[REF(src)];view_rec=[R.fields["id"]]'>View Record</a>"
if(3)
dat += "<h3>Selected Record</h3>"
dat += "<a href='byond://?src=[REF(src)];menu=2'><< Back</a><br>"
if (!src.active_record)
dat += "<font class='bad'>Record not found.</font>"
else
dat += "<h4>[src.active_record.fields["name"]]</h4>"
dat += "Scan ID [src.active_record.fields["id"]] <a href='byond://?src=[REF(src)];clone=[active_record.fields["id"]]'>Clone</a><br>"
var/obj/item/implant/health/H = locate(active_record.fields["imp"])
if ((H) && (istype(H)))
dat += "<b>Health Implant Data:</b><br />[H.sensehealth()]<br><br />"
var/list/record_entry = list()
record_entry["name"] = "[R.fields["name"]]"
record_entry["id"] = "[R.fields["id"]]"
var/obj/item/implant/health/H = locate(R.fields["imp"])
if(H && istype(H))
record_entry["damages"] = H.sensehealth(TRUE)
else
dat += "<font class='bad'>Unable to locate Health Implant.</font><br /><br />"
record_entry["damages"] = FALSE
record_entry["UI"] = "[R.fields["UI"]]"
record_entry["UE"] = "[R.fields["UE"]]"
record_entry["blood_type"] = "[R.fields["blood_type"]]"
records_to_send += list(record_entry)
data["records"] = records_to_send
else
data["records"] = list()
if(diskette && diskette.fields)
var/list/disk_data = list()
disk_data["name"] = "[diskette.fields["name"]]"
disk_data["id"] = "[diskette.fields["id"]]"
disk_data["UI"] = "[diskette.fields["UI"]]"
disk_data["UE"] = "[diskette.fields["UE"]]"
disk_data["blood_type"] = "[diskette.fields["blood_type"]]"
data["diskData"] = disk_data
else
data["diskData"] = list()
else
data["hasAutoprocess"] = FALSE
data["autoprocess"] = autoprocess
var/list/lack_machine = list()
if(isnull(src.scanner))
lack_machine += "ERROR: No Scanner Detected!"
if(!LAZYLEN(pods))
lack_machine += "ERROR: No Pod Detected!"
data["lacksMachine"] = lack_machine
data["temp"] = temp
var/build_temp = null
var/mob/living/scanner_occupant = get_mob_or_brainmob(scanner?.occupant)
if(scanner_occupant?.ckey != scantemp_ckey || scanner_occupant?.name != scantemp_name)
if(use_records)
build_temp = "Ready to Scan"
scantemp_ckey = scanner_occupant?.ckey
scantemp_name = scanner_occupant?.name
else
build_temp = "Ready to Clone"
scantemp = "[scanner_occupant] => [build_temp]"
data["scanTemp"] = scantemp
data["scannerLocked"] = scanner?.locked
data["hasOccupant"] = scanner?.occupant
data["recordsLength"] = "View Records ([length(records)])"
dat += "<b>Unique Identifier:</b><br /><span class='highlight'>[src.active_record.fields["UI"]]</span><br>"
dat += "<b>Structural Enzymes:</b><br /><span class='highlight'>[src.active_record.fields["SE"]]</span><br>"
return data
if(diskette && diskette.fields)
dat += "<div class='block'>"
dat += "<h4>Inserted Disk</h4>"
dat += "<b>Contents:</b> "
var/list/L = list()
if(diskette.fields["UI"])
L += "Unique Identifier"
if(diskette.fields["UE"] && diskette.fields["name"] && diskette.fields["blood_type"])
L += "Unique Enzymes"
if(diskette.fields["SE"])
L += "Structural Enzymes"
dat += english_list(L, "Empty", " + ", " + ")
dat += "<br /><a href='byond://?src=[REF(src)];disk=load'>Load from Disk</a>"
dat += "<br /><a href='byond://?src=[REF(src)];disk=save'>Save to Disk</a>"
dat += "</div>"
dat += "<font size=1><a href='byond://?src=[REF(src)];del_rec=1'>Delete Record</a></font>"
if(4)
if (!src.active_record)
src.menu = 2
dat = "[src.temp]<br>"
dat += "<h3>Confirm Record Deletion</h3>"
dat += "<b><a href='byond://?src=[REF(src)];del_rec=1'>Scan card to confirm.</a></b><br>"
dat += "<b><a href='byond://?src=[REF(src)];menu=3'>Cancel</a></b>"
var/datum/browser/popup = new(user, "cloning", "Cloning System Control")
popup.set_content(dat)
popup.open()
/obj/machinery/computer/cloning/Topic(href, href_list)
/obj/machinery/computer/cloning/ui_act(action, params)
if(..())
return
switch(action)
if("toggle_autoprocess")
Toggle_autoprocess(usr)
if("scan")
Scan(usr)
if("toggle_lock")
Toggle_lock(usr)
if("clone")
Clone(usr, params["target"])
if("delrecord")
DeleteRecord(usr, params["target"])
if("save")
Save(usr, params["target"])
if("load")
Load(usr)
if("eject")
EjectDisk(usr)
if(loading)
/obj/machinery/computer/cloning/ui_interact(mob/user, datum/tgui/ui)
if(..())
return
if(href_list["task"])
switch(href_list["task"])
if("autoprocess")
if(scanner && HasEfficientPod() && scanner.scan_level >= AUTOCLONING_MINIMAL_LEVEL)
autoprocess = TRUE
START_PROCESSING(SSmachines, src)
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
if("stopautoprocess")
autoprocess = FALSE
STOP_PROCESSING(SSmachines, src)
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
src.updateUsrDialog()
. = TRUE
else if ((href_list["scan"]) && !isnull(scanner) && scanner.is_operational())
scantemp = ""
loading = TRUE
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
say("Initiating scan...")
var/prev_locked = scanner.locked
scanner.locked = TRUE
src.updateUsrDialog()
addtimer(CALLBACK(src, .proc/finish_scan, scanner.occupant, prev_locked), 2 SECONDS)
. = TRUE
//No locking an open scanner.
else if ((href_list["lock"]) && !isnull(scanner) && scanner.is_operational())
if ((!scanner.locked) && (scanner.occupant))
scanner.locked = TRUE
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
scanner.locked = FALSE
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
src.updateUsrDialog()
. = TRUE
else if (href_list["refresh"])
src.updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
. = TRUE
if(. || !use_records)
return
if(href_list["view_rec"])
playsound(src, "terminal_type", 25, 0)
src.active_record = find_record("id", href_list["view_rec"], records)
if(active_record)
if(!active_record.fields["ckey"])
records -= active_record
active_record = null
src.temp = "<font class='bad'>Record Corrupt</font>"
else
src.menu = 3
else
src.temp = "Record missing."
src.updateUsrDialog()
. = TRUE
else if (href_list["del_rec"])
if ((!src.active_record) || (src.menu < 3))
return
if (src.menu == 3) //If we are viewing a record, confirm deletion
src.temp = "Delete record?"
src.menu = 4
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt.ogg', 50, 0)
else if (src.menu == 4)
var/obj/item/card/id/C = usr.get_active_held_item()
if (istype(C)||istype(C, /obj/item/pda))
if(src.check_access(C))
src.temp = "[src.active_record.fields["name"]] => Record deleted."
src.records.Remove(active_record)
active_record = null
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
src.menu = 2
var/obj/item/circuitboard/computer/cloning/board = circuit
board.records = records
else
src.temp = "<font class='bad'>Access Denied.</font>"
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
. = TRUE
else if (href_list["disk"] && use_records) //Load or eject.
switch(href_list["disk"])
if("load")
if (!diskette || !istype(diskette.fields) || !diskette.fields["name"] || !diskette.fields)
src.temp = "<font class='bad'>Load error.</font>"
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (!src.active_record)
src.temp = "<font class='bad'>Record error.</font>"
src.menu = 1
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
for(var/key in diskette.fields)
src.active_record.fields[key] = diskette.fields[key]
src.temp = "Load successful."
src.updateUsrDialog()
var/obj/item/circuitboard/computer/cloning/board = circuit
board.records = records
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
if("eject")
if(src.diskette)
src.diskette.forceMove(drop_location())
src.diskette = null
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0)
if("save")
if(!diskette || diskette.read_only || !active_record || !active_record.fields)
src.temp = "<font class='bad'>Save error.</font>"
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
diskette.fields = active_record.fields.Copy()
diskette.name = "data disk - '[src.diskette.fields["name"]]'"
src.temp = "Save successful."
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
. = TRUE
else if (href_list["clone"])
var/datum/data/record/C = find_record("id", href_list["clone"], records)
//Look for that player! They better be dead!
if(C)
var/obj/machinery/clonepod/pod = GetAvailablePod()
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!LAZYLEN(pods))
temp = "<font class='bad'>No Clonepods detected.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!pod)
temp = "<font class='bad'>No Clonepods available.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!CONFIG_GET(flag/revival_cloning))
temp = "<font class='bad'>Unable to initiate cloning cycle.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.growclone(C.fields["ckey"], C.fields["name"], C.fields["UI"], C.fields["SE"], C.fields["mind"], C.fields["blood_type"], C.fields["mrace"], C.fields["features"], C.fields["factions"], C.fields["quirks"], C.fields["bank_account"], C.fields["traumas"]))
temp = "[C.fields["name"]] => <font class='good'>Cloning cycle in progress...</font>"
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
records.Remove(C)
if(active_record == C)
active_record = null
menu = 1
src.updateUsrDialog()
else
temp = "[C.fields["name"]] => <font class='bad'>Initialisation failure.</font>"
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
temp = "<font class='bad'>Data corruption.</font>"
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
. = TRUE
else if (href_list["menu"] && use_records)
menu = text2num(href_list["menu"])
src.updateUsrDialog()
playsound(src, "terminal_type", 25, 0)
. = TRUE
updatemodules(TRUE)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "CloningConsole", "Cloning System Control")
ui.open()
/obj/machinery/computer/cloning/proc/finish_scan(mob/living/L, prev_locked)
if(!scanner || !L)
@@ -469,7 +390,6 @@
loading = FALSE
scanner.locked = prev_locked
src.updateUsrDialog()
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
@@ -568,44 +488,44 @@
var/obj/machinery/clonepod/pod = GetAvailablePod()
//Can't clone without someone to clone. Or a pod. Or if the pod is busy. Or full of gibs.
if(!LAZYLEN(pods))
temp = "<font class='bad'>No Clonepods detected.</font>"
temp = "No Clonepods detected."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(!pod)
temp = "<font class='bad'>No Clonepods available.</font>"
temp = "No Clonepods available."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else if(pod.occupant)
temp = "<font class='bad'>Cloning cycle already in progress.</font>"
temp = "Cloning cycle already in progress."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
else
pod.growclone(null, mob_occupant.real_name, dna.uni_identity, dna.mutation_index, null, dna.blood_type, clone_species, dna.features, mob_occupant.faction)
temp = "[mob_occupant.real_name] => <font class='good'>Cloning data sent to pod.</font>"
temp = "[mob_occupant.real_name] => Cloning data sent to pod."
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0)
/obj/machinery/computer/cloning/proc/can_scan(datum/dna/dna, mob/living/mob_occupant, experimental = FALSE, datum/bank_account/account)
if(!istype(dna))
scantemp = "<font class='bad'>Unable to locate valid genetic data.</font>"
scantemp = "Unable to locate valid genetic data."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(!experimental)
if(mob_occupant.suiciding || mob_occupant.hellbound)
scantemp = "<font class='bad'>Subject's brain is not responding to scanning stimuli.</font>"
scantemp = "Subject's brain is not responding to scanning stimuli."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if((HAS_TRAIT(mob_occupant, TRAIT_NOCLONE)) && (src.scanner.scan_level < 2))
scantemp = "<font class='bad'>Subject no longer contains the fundamental materials required to create a living clone.</font>"
scantemp = "Subject no longer contains the fundamental materials required to create a living clone."
playsound(src, 'sound/machines/terminal_alert.ogg', 50, 0)
return
if (!experimental)
if(!mob_occupant.ckey || !mob_occupant.client)
scantemp = "<font class='bad'>Mental interface failure.</font>"
scantemp = "Mental interface failure."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if (find_record("ckey", mob_occupant.ckey, records))
scantemp = "<font class='average'>Subject already in database.</font>"
scantemp = "Subject already in database."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
if(SSeconomy.full_ancap && !account)
scantemp = "<font class='average'>Subject is either missing an ID card with a bank account on it, or does not have an account to begin with. Please ensure the ID card is on the body before attempting to scan.</font>"
scantemp = "Subject is either missing an ID card with a bank account on it, or does not have an account to begin with. Please ensure the ID card is on the body before attempting to scan."
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
return
return TRUE
@@ -618,3 +538,4 @@
icon_keyboard = "med_key"
circuit = /obj/item/circuitboard/computer/cloning/prototype
clonepod_type = /obj/machinery/clonepod/experimental
use_records = FALSE //Wait, so you tell me it lacks records but you never set it as false?
+21 -6
View File
@@ -51,6 +51,11 @@
return FALSE
return ACCESS_CAPTAIN in authorize_access
/obj/machinery/computer/communications/proc/authenticated_as_non_silicon_command(mob/user)
if (issilicon(user))
return FALSE
return ACCESS_HEADS in authorize_access //Should always be the case if authorized as it usually needs head access to log in, buut lets be sure.
/// Are we a silicon, OR we're logged in as the captain?
/obj/machinery/computer/communications/proc/authenticated_as_silicon_or_captain(mob/user)
if (issilicon(user))
@@ -97,8 +102,14 @@
if ("answerMessage")
if (!authenticated(usr))
return
var/answer_index = text2num(params["answer"])
var/message_index = text2num(params["message"])
var/answer_index = params["answer"]
var/message_index = params["message"]
// If either of these aren't numbers, then bad voodoo.
if(!isnum(answer_index) || !isnum(message_index))
message_admins("[ADMIN_LOOKUPFLW(usr)] provided an invalid index type when replying to a message on [src] [ADMIN_JMP(src)]. This should not happen. Please check with a maintainer and/or consult tgui logs.")
CRASH("Non-numeric index provided when answering comms console message.")
if (!answer_index || !message_index || answer_index < 1 || message_index < 1)
return
var/datum/comm_message/message = messages[message_index]
@@ -151,7 +162,11 @@
if ("deleteMessage")
if (!authenticated(usr))
return
var/message_index = text2num(params["message"])
var/message_index = params["message"]
if(!isnum(message_index))
message_admins("[ADMIN_LOOKUPFLW(usr)] provided an invalid index type when deleting a message on [src] [ADMIN_JMP(src)]. This should not happen. Please check with a maintainer and/or consult tgui logs.")
CRASH("Non-numeric index provided when deleting comms console message.")
if (!message_index)
return
LAZYREMOVE(messages, LAZYACCESS(messages, message_index))
@@ -160,7 +175,7 @@
return
make_announcement(usr)
if ("messageAssociates")
if (!authenticated_as_non_silicon_captain(usr))
if (!authenticated_as_non_silicon_command(usr))
return
if (!COOLDOWN_FINISHED(src, important_action_cooldown))
return
@@ -361,9 +376,9 @@
data["shuttleCanEvacOrFailReason"] = SSshuttle.canEvac(user, TRUE)
if (authenticated_as_non_silicon_captain(user))
data["canMessageAssociates"] = TRUE
data["canRequestNuke"] = TRUE
if (authenticated_as_non_silicon_command(user))
data["canMessageAssociates"] = TRUE
if (can_send_messages_to_other_sectors(user))
data["canSendToSectors"] = TRUE
+1 -1
View File
@@ -200,6 +200,6 @@
if(is_centcom_level(T.z) || is_away_level(T.z))
return FALSE
var/area/A = get_area(T)
if(!A || A.noteleport)
if(!A || (A.area_flags & NOTELEPORT))
return FALSE
return TRUE
+64 -42
View File
@@ -36,7 +36,7 @@
/obj/structure/frame/machine/examine(user)
. = ..()
if(state == 3 && req_components && req_component_names)
var/hasContent = 0
var/hasContent = FALSE
var/requires = "It requires"
for(var/i = 1 to req_components.len)
@@ -46,10 +46,10 @@
continue
var/use_and = i == req_components.len
requires += "[(hasContent ? (use_and ? ", and" : ",") : "")] [amt] [amt == 1 ? req_component_names[tname] : "[req_component_names[tname]]\s"]"
hasContent = 1
hasContent = TRUE
if(hasContent)
. += requires + "."
. += "[requires]."
else
. += "It does not require any more components."
@@ -76,7 +76,7 @@
amt += req_components[path]
return amt
/obj/structure/frame/machine/attackby(obj/item/P, mob/user, params)
/obj/structure/frame/machine/attackby(obj/item/P, mob/living/user, params)
switch(state)
if(1)
if(istype(P, /obj/item/circuitboard/machine))
@@ -88,6 +88,7 @@
if(istype(P, /obj/item/stack/cable_coil))
if(!P.tool_start_check(user, amount=5))
return
to_chat(user, "<span class='notice'>You start to add cables to the frame...</span>")
if(P.use_tool(src, user, 20, volume=50, amount=5, extra_checks = CALLBACK(src, .proc/check_state, 1)))
to_chat(user, "<span class='notice'>You add cables to the frame.</span>")
@@ -97,39 +98,41 @@
return
if(P.tool_behaviour == TOOL_SCREWDRIVER && !anchored)
user.visible_message("<span class='warning'>[user] disassembles the frame.</span>", \
"<span class='notice'>You start to disassemble the frame...</span>", "You hear banging and clanking.")
"<span class='notice'>You start to disassemble the frame...</span>", "<span class='hear'>You hear banging and clanking.</span>")
if(P.use_tool(src, user, 40, volume=50, extra_checks = CALLBACK(src, .proc/check_state, 1)))
to_chat(user, "<span class='notice'>You disassemble the frame.</span>")
var/obj/item/stack/sheet/metal/M = new (loc, 5)
M.add_fingerprint(user)
qdel(src)
if(state == 1)
to_chat(user, "<span class='notice'>You disassemble the frame.</span>")
var/obj/item/stack/sheet/metal/M = new (loc, 5)
M.add_fingerprint(user)
qdel(src)
return
if(P.tool_behaviour == TOOL_WRENCH)
to_chat(user, "<span class='notice'>You start [anchored ? "un" : ""]securing [name]...</span>")
to_chat(user, "<span class='notice'>You start [anchored ? "un" : ""]securing [src]...</span>")
if(P.use_tool(src, user, 40, volume=75, extra_checks = CALLBACK(src, .proc/check_state, 1)))
to_chat(user, "<span class='notice'>You [anchored ? "un" : ""]secure [name].</span>")
setAnchored(!anchored)
if(state == 1)
to_chat(user, "<span class='notice'>You [anchored ? "un" : ""]secure [src].</span>")
set_anchored(!anchored)
return
if(2)
if(P.tool_behaviour == TOOL_WRENCH)
to_chat(user, "<span class='notice'>You start [anchored ? "un" : ""]securing [name]...</span>")
to_chat(user, "<span class='notice'>You start [anchored ? "un" : ""]securing [src]...</span>")
if(P.use_tool(src, user, 40, volume=75, extra_checks = CALLBACK(src, .proc/check_state, 2)))
to_chat(user, "<span class='notice'>You [anchored ? "un" : ""]secure [name].</span>")
setAnchored(!anchored)
to_chat(user, "<span class='notice'>You [anchored ? "un" : ""]secure [src].</span>")
set_anchored(!anchored)
return
if(istype(P, /obj/item/circuitboard/machine))
var/obj/item/circuitboard/machine/B = P
if(!B.build_path)
to_chat(user, "<span class'warning'>This circuitboard seems to be broken.</span>")
to_chat(user, "<span class='warning'>This circuitboard seems to be broken.</span>")
return
if(!anchored && B.needs_anchored)
to_chat(user, "<span class='warning'>The frame needs to be secured first!</span>")
return
if(!user.transferItemToLoc(B, src))
return
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
playsound(src.loc, 'sound/items/deconstruct.ogg', 50, TRUE)
to_chat(user, "<span class='notice'>You add the circuit board to the frame.</span>")
circuit = B
icon_state = "box_2"
@@ -171,34 +174,51 @@
return
if(P.tool_behaviour == TOOL_WRENCH && !circuit.needs_anchored)
to_chat(user, "<span class='notice'>You start [anchored ? "un" : ""]securing [name]...</span>")
to_chat(user, "<span class='notice'>You start [anchored ? "un" : ""]securing [src]...</span>")
if(P.use_tool(src, user, 40, volume=75, extra_checks = CALLBACK(src, .proc/check_state, 3)))
to_chat(user, "<span class='notice'>You [anchored ? "un" : ""]secure [name].</span>")
setAnchored(!anchored)
to_chat(user, "<span class='notice'>You [anchored ? "un" : ""]secure [src].</span>")
set_anchored(!anchored)
return
if(P.tool_behaviour == TOOL_SCREWDRIVER)
var/component_check = 1
var/component_check = TRUE
for(var/R in req_components)
if(req_components[R] > 0)
component_check = 0
component_check = FALSE
break
if(component_check)
P.play_tool_sound(src)
var/obj/machinery/new_machine = new circuit.build_path(loc)
if(new_machine.circuit)
QDEL_NULL(new_machine.circuit)
new_machine.circuit = circuit
new_machine.setAnchored(anchored)
new_machine.on_construction()
for(var/obj/O in new_machine.component_parts)
qdel(O)
new_machine.component_parts = list()
for(var/obj/O in src)
O.moveToNullspace()
new_machine.component_parts += O
circuit.moveToNullspace()
new_machine.RefreshParts()
if(istype(new_machine))
// Machines will init with a set of default components. Move to nullspace so we don't trigger handle_atom_del, then qdel.
// Finally, replace with this frame's parts.
if(new_machine.circuit)
// Move to nullspace and delete.
new_machine.circuit.moveToNullspace()
QDEL_NULL(new_machine.circuit)
for(var/obj/old_part in new_machine.component_parts)
// Move to nullspace and delete.
old_part.moveToNullspace()
qdel(old_part)
// Set anchor state and move the frame's parts over to the new machine.
// Then refresh parts and call on_construction().
new_machine.set_anchored(anchored)
new_machine.component_parts = list()
circuit.forceMove(new_machine)
new_machine.component_parts += circuit
new_machine.circuit = circuit
for(var/obj/new_part in src)
new_part.forceMove(new_machine)
new_machine.component_parts += new_part
new_machine.RefreshParts()
new_machine.on_construction()
// TODO: make sleepers not shit out parts PROPERLY THIS TIME.
new_machine.circuit.moveToNullspace()
qdel(src)
return
@@ -232,12 +252,15 @@
for(var/obj/item/part in added_components)
if(istype(part,/obj/item/stack))
var/obj/item/stack/S = part
var/obj/item/stack/NS = locate(S.merge_type) in components //find a stack to merge with
if(NS)
S.merge(NS)
var/obj/item/stack/incoming_stack = part
for(var/obj/item/stack/merge_stack in components)
if(incoming_stack.can_merge(merge_stack))
incoming_stack.merge(merge_stack)
if(QDELETED(incoming_stack))
break
if(!QDELETED(part)) //If we're a stack and we merged we might not exist anymore
components += part
part.forceMove(src)
to_chat(user, "<span class='notice'>[part.name] applied.</span>")
if(added_components.len)
replacer.play_rped_sound()
@@ -267,9 +290,9 @@
to_chat(user, "<span class='notice'>You add [P] to [src].</span>")
components += P
req_components[I]--
return 1
return TRUE
to_chat(user, "<span class='warning'>You cannot add that to the machine!</span>")
return 0
return FALSE
if(user.a_intent == INTENT_HARM)
return ..()
@@ -280,5 +303,4 @@
for(var/X in components)
var/obj/item/I = X
I.forceMove(loc)
..()
+4 -1
View File
@@ -409,7 +409,10 @@
visible_message("<span class='notice'>\The [src] hums and hisses as it moves [mob_occupant.real_name] into storage.</span>")
// Ghost and delete the mob.
if(!mob_occupant.get_ghost(1))
var/mob/dead/observer/G = mob_occupant.get_ghost(TRUE)
if(G)
G.voluntary_ghosted = TRUE
else
mob_occupant.ghostize(FALSE, penalize = TRUE, voluntary = TRUE, cryo = TRUE)
QDEL_NULL(occupant)
+3 -3
View File
@@ -79,7 +79,7 @@ GLOBAL_LIST_EMPTY(network_holopads)
var/secure = FALSE
/// If we are currently calling another holopad
var/calling = FALSE
/*
/obj/machinery/holopad/secure
name = "secure holopad"
desc = "It's a floor-mounted device for projecting holographic images. This one will refuse to auto-connect incoming calls."
@@ -90,7 +90,7 @@ GLOBAL_LIST_EMPTY(network_holopads)
var/obj/item/circuitboard/machine/holopad/board = circuit
board.secure = TRUE
board.build_path = /obj/machinery/holopad/secure
*/
/obj/machinery/holopad/tutorial
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
flags_1 = NODECONSTRUCT_1
@@ -372,7 +372,7 @@ GLOBAL_LIST_EMPTY(network_holopads)
if(force_answer_call && world.time > (HC.call_start_time + (HOLOPAD_MAX_DIAL_TIME / 2)))
HC.Answer(src)
break
if(!secure) //HC.head_call &&
if(HC.head_call && !secure)
HC.Answer(src)
break
if(outgoing_call)
+1
View File
@@ -178,6 +178,7 @@
limb.update_icon_dropped()
limb.name = "\improper synthetic [lowertext(selected.name)] [limb.name]"
limb.desc = "A synthetic [selected_category] limb that will morph on its first use in surgery. This one is for the [parse_zone(limb.body_zone)]."
limb.forcereplace = TRUE
for(var/obj/item/bodypart/BP in limb)
BP.base_bp_icon = selected.icon_limbs || DEFAULT_BODYPART_ICON_ORGANIC
BP.species_id = selected.limbs_id
+20
View File
@@ -21,6 +21,7 @@ Buildable meters
level = 2
var/piping_layer = PIPING_LAYER_DEFAULT
var/RPD_type
var/disposable = TRUE
/obj/item/pipe/directional
RPD_type = PIPE_UNARY
@@ -236,3 +237,22 @@ Buildable meters
/obj/item/pipe_meter/proc/setAttachLayer(new_layer = PIPING_LAYER_DEFAULT)
piping_layer = new_layer
PIPING_LAYER_DOUBLE_SHIFT(src, piping_layer)
/obj/item/pipe/bluespace
pipe_type = /obj/machinery/atmospherics/pipe/bluespace
var/bluespace_network_name = "default"
icon_state = "bluespace"
disposable = FALSE
/obj/item/pipe/bluespace/attack_self(mob/user)
var/new_name = input(user, "Enter identifier for bluespace pipe network", "bluespace pipe", bluespace_network_name) as text|null
if(!isnull(new_name))
bluespace_network_name = new_name
/obj/item/pipe/bluespace/make_from_existing(obj/machinery/atmospherics/pipe/bluespace/make_from)
bluespace_network_name = make_from.bluespace_network_name
return ..()
/obj/item/pipe/bluespace/build_pipe(obj/machinery/atmospherics/pipe/bluespace/A)
A.bluespace_network_name = bluespace_network_name
return ..()
@@ -243,13 +243,14 @@
// Check if the user can use it.
/obj/machinery/telecomms/proc/canInteract(mob/user)
var/get = user.get_active_held_item()
var/obj/item/I = get
if(I.tool_behaviour == TOOL_MULTITOOL)
return TRUE
var/obj/item/I = user.get_active_held_item()
if(!issilicon(user) && I)
if(I.tool_behaviour == TOOL_MULTITOOL)
return TRUE
if(hasSiliconAccessInArea(user))
return TRUE
return FALSE
// Check if the user is nearby and has a multitool.
/obj/machinery/telecomms/proc/canAccess(mob/user)
if((canInteract(user) && in_range(user, src)) || hasSiliconAccessInArea(user))
@@ -262,14 +263,13 @@
return null
var/obj/item/P = user.get_active_held_item()
// Is the ref not a null? and is it the actual type?
if(P.tool_behaviour == TOOL_MULTITOOL)
return P
else if(isAI(user))
if(isAI(user))
var/mob/living/silicon/ai/U = user
P = U.aiMulti
else if(iscyborg(user) && in_range(user, src))
var/get = user.get_active_held_item()
var/obj/item/I = get
if(I.tool_behaviour == TOOL_MULTITOOL)
I = user.get_active_held_item()
else if(iscyborg(user) && !in_range(user, src))
return null
if(!P)
return null
else if(P.tool_behaviour == TOOL_MULTITOOL)
return P
return P