From 4a155bfb50adaa17db07a0e15e7adffda46a2eb2 Mon Sep 17 00:00:00 2001 From: Markolie Date: Wed, 8 Feb 2017 23:27:08 +0100 Subject: [PATCH 001/164] Admin interaction update --- code/game/machinery/buttons.dm | 73 +-- code/game/machinery/door_control.dm | 20 +- code/game/machinery/doors/airlock.dm | 191 ++++--- code/game/machinery/doors/brigdoors.dm | 15 +- code/game/machinery/doors/door.dm | 53 +- code/game/machinery/doors/firedoor.dm | 11 +- code/game/machinery/doors/windowdoor.dm | 164 +++--- code/game/machinery/flasher.dm | 68 ++- code/game/machinery/newscaster.dm | 513 +++++++++--------- code/game/machinery/vending.dm | 138 ++--- code/game/objects/structures/morgue.dm | 24 +- code/modules/admin/admin_verbs.dm | 24 +- code/modules/client/client defines.dm | 5 +- code/modules/hydroponics/biogenerator.dm | 5 +- code/modules/hydroponics/gene_modder.dm | 8 +- code/modules/hydroponics/seed_extractor.dm | 10 +- code/modules/mob/dead/observer/observer.dm | 2 +- .../mob/living/simple_animal/bot/bot.dm | 5 + code/modules/paperwork/faxmachine.dm | 5 +- code/modules/paperwork/photocopier.dm | 10 +- 20 files changed, 701 insertions(+), 643 deletions(-) diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index a5c65f7cae7..e28bf145b74 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -53,7 +53,11 @@ /obj/machinery/driver_button/attack_ai(mob/user as mob) - return src.attack_hand(user) + return attack_hand(user) + +/obj/machinery/driver_button/attack_ghost(mob/user) + if(user.can_admin_interact()) + return attack_hand(user) /obj/machinery/driver_button/attackby(obj/item/weapon/W, mob/user as mob, params) @@ -72,7 +76,7 @@ qdel(src) return 1 - return src.attack_hand(user) + return attack_hand(user) /obj/machinery/driver_button/multitool_menu(var/mob/user, var/obj/item/device/multitool/P) return {" @@ -84,7 +88,7 @@ /obj/machinery/driver_button/attack_hand(mob/user as mob) - src.add_fingerprint(usr) + add_fingerprint(usr) if(stat & (NOPOWER|BROKEN)) return if(active) @@ -95,8 +99,6 @@ launch_sequence() - return - /obj/machinery/driver_button/proc/launch_sequence() active = 1 icon_state = "launcheract" @@ -121,20 +123,20 @@ radio_connection.post_signal(src, signal, filter = RADIO_LOGIC) for(var/obj/machinery/door/poddoor/M in range(src,range)) - if(M.id_tag == src.id_tag && !M.protected) + if(M.id_tag == id_tag && !M.protected) spawn() M.open() sleep(20) for(var/obj/machinery/mass_driver/M in range(src,range)) - if(M.id_tag == src.id_tag) + if(M.id_tag == id_tag) M.drive() sleep(50) for(var/obj/machinery/door/poddoor/M in range(src,range)) - if(M.id_tag == src.id_tag && !M.protected) + if(M.id_tag == id_tag && !M.protected) spawn() M.close() return @@ -163,14 +165,17 @@ idle_power_usage = 2 active_power_usage = 4 -/obj/machinery/ignition_switch/attack_ai(mob/user as mob) - return src.attack_hand(user) +/obj/machinery/ignition_switch/attack_ai(mob/user) + return attack_hand(user) + +/obj/machinery/ignition_switch/attack_ghost(mob/user) + if(user.can_admin_interact()) + return attack_hand(user) -/obj/machinery/ignition_switch/attackby(obj/item/weapon/W, mob/user as mob, params) - return src.attack_hand(user) - -/obj/machinery/ignition_switch/attack_hand(mob/user as mob) +/obj/machinery/ignition_switch/attackby(obj/item/weapon/W, mob/user, params) + return attack_hand(user) +/obj/machinery/ignition_switch/attack_hand(mob/user) if(stat & (NOPOWER|BROKEN)) return if(active) @@ -182,12 +187,12 @@ icon_state = "launcheract" for(var/obj/machinery/sparker/M in world) - if(M.id == src.id) + if(M.id == id) spawn( 0 ) M.spark() for(var/obj/machinery/igniter/M in world) - if(M.id == src.id) + if(M.id == id) use_power(50) M.on = !( M.on ) M.icon_state = text("igniter[]", M.on) @@ -195,38 +200,4 @@ sleep(50) icon_state = "launcherbtt" - active = 0 - - return - -////////////////////////////////////// -// Flasher Button // -////////////////////////////////////// - -/obj/machinery/flasher_button - name = "flasher button" - desc = "A remote control switch for a mounted flasher." - icon = 'icons/obj/objects.dmi' - icon_state = "launcherbtt" - var/id = null - var/active = 0 - anchored = 1.0 - use_power = 1 - idle_power_usage = 2 - active_power_usage = 4 - -////////////////////////////////////// -// Crematorium Switch // -////////////////////////////////////// - -/obj/machinery/crema_switch - desc = "Burn baby burn!" - name = "crematorium igniter" - icon = 'icons/obj/power.dmi' - icon_state = "crema_switch" - anchored = 1.0 - req_access = list(access_crematorium) - var/on = 0 - var/area/area = null - var/otherarea = null - var/id = 1 \ No newline at end of file + active = 0 \ No newline at end of file diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm index f952f8f2bc3..e9e4a40e465 100644 --- a/code/game/machinery/door_control.dm +++ b/code/game/machinery/door_control.dm @@ -33,7 +33,7 @@ /obj/machinery/door_control/attack_ai(mob/user as mob) if(wires & 2) - return src.attack_hand(user) + return attack_hand(user) else to_chat(user, "Error, no route to host.") @@ -54,22 +54,26 @@ */ if(istype(W, /obj/item/device/detective_scanner)) return - return src.attack_hand(user) + return attack_hand(user) /obj/machinery/door_control/emag_act(user as mob) if(!emagged) emagged = 1 req_access = list() req_one_access = list() - playsound(src.loc, "sparks", 100, 1) + playsound(loc, "sparks", 100, 1) + +/obj/machinery/door_control/attack_ghost(mob/user) + if(user.can_admin_interact()) + return attack_hand(user) /obj/machinery/door_control/attack_hand(mob/user as mob) - src.add_fingerprint(usr) + add_fingerprint(usr) if(stat & (NOPOWER|BROKEN)) return - if(!allowed(user) && (wires & 1)) - to_chat(user, "\red Access Denied") + if(!allowed(user) && (wires & 1) && !user.can_admin_interact()) + to_chat(user, "Access Denied.") flick("doorctrl-denied",src) return @@ -79,7 +83,7 @@ if(normaldoorcontrol) for(var/obj/machinery/door/airlock/D in range(range)) - if(D.id_tag == src.id) + if(D.id_tag == id) if(specialfunctions & OPEN) if(D.density) spawn(0) @@ -110,7 +114,7 @@ else for(var/obj/machinery/door/poddoor/M in airlocks) - if(M.id_tag == src.id) + if(M.id_tag == id) if(M.density) spawn( 0 ) M.open() diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 114bada5e19..549c99dfbd1 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -556,17 +556,10 @@ About the new airlock wires panel: flick("door_deny", src) return -/obj/machinery/door/airlock/attack_ai(mob/user as mob) - ui_interact(user) - -/obj/machinery/door/airlock/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "door_control.tmpl", "Door Controls - [src]", 600, 375) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/door/airlock/attack_ai(mob/user as mob) +/obj/machinery/door/airlock/attack_ghost(mob/user) + ui_interact(user) + +/obj/machinery/door/airlock/attack_ai(mob/user) ui_interact(user) /obj/machinery/door/airlock/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) @@ -682,17 +675,17 @@ About the new airlock wires panel: return /obj/machinery/door/airlock/CanUseTopic(var/mob/user) - if(!issilicon(user)) + if(!issilicon(user) && !isobserver(user)) return STATUS_CLOSE if(operating < 0) //emagged to_chat(user, "Unable to interface: Internal error.") return STATUS_CLOSE - if(!src.canAIControl()) - if(src.canAIHack(user)) - src.hack(user) + if(!canAIControl() && !isobserver(user)) + if(canAIHack(user)) + hack(user) else - if(src.isAllPowerLoss()) //don't really like how this gets checked a second time, but not sure how else to do it. + if(isAllPowerLoss()) //don't really like how this gets checked a second time, but not sure how else to do it. to_chat(user, "Unable to interface: Connection timed out.") else to_chat(user, "Unable to interface: Connection refused.") @@ -709,27 +702,27 @@ About the new airlock wires panel: if("idscan") if(src.isWireCut(AIRLOCK_WIRE_IDSCAN)) to_chat(usr, "The IdScan wire has been cut - IdScan feature permanently disabled.") - else if(activate && src.aiDisabledIdScanner) - src.aiDisabledIdScanner = 0 + else if(activate && aiDisabledIdScanner) + aiDisabledIdScanner = 0 to_chat(usr, "IdScan feature has been enabled.") - else if(!activate && !src.aiDisabledIdScanner) - src.aiDisabledIdScanner = 1 + else if(!activate && !aiDisabledIdScanner) + aiDisabledIdScanner = 1 to_chat(usr, "IdScan feature has been disabled.") if("main_power") if(!main_power_lost_until) - src.loseMainPower() + loseMainPower() if("backup_power") if(!backup_power_lost_until) - src.loseBackupPower() + loseBackupPower() if("bolts") - if(src.isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) + if(isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) to_chat(usr, "The door bolt control wire has been cut - Door bolts permanently dropped.") - else if(activate && src.lock()) + else if(activate && lock()) to_chat(usr, "The door bolts have been dropped.") - else if(!activate && src.unlock()) + else if(!activate && unlock()) to_chat(usr, "The door bolts have been raised.") if("electrify_temporary") - if(activate && src.isWireCut(AIRLOCK_WIRE_ELECTRIFY)) + if(activate && isWireCut(AIRLOCK_WIRE_ELECTRIFY)) to_chat(usr, text("The electrification wire is cut - Door permanently electrified.")) else if(!activate && electrified_until != 0) to_chat(usr, "The door is now un-electrified.") @@ -740,7 +733,7 @@ About the new airlock wires panel: to_chat(usr, "The door is now electrified for thirty seconds.") electrify(30) if("electrify_permanently") - if(src.isWireCut(AIRLOCK_WIRE_ELECTRIFY)) + if(isWireCut(AIRLOCK_WIRE_ELECTRIFY)) to_chat(usr, text("The electrification wire is cut - Cannot electrify the door.")) else if(!activate && electrified_until != 0) to_chat(usr, "The door is now un-electrified.") @@ -751,9 +744,9 @@ About the new airlock wires panel: to_chat(usr, "The door is now electrified.") electrify(-1) if("open") - if(src.welded) + if(welded) to_chat(usr, text("The airlock has been welded shut!")) - else if(src.locked) + else if(locked) to_chat(usr, text("The door bolts are down!")) else if(activate && density) open() @@ -761,33 +754,33 @@ About the new airlock wires panel: close() if("safeties") // Safeties! We don't need no stinking safeties! - if(src.isWireCut(AIRLOCK_WIRE_SAFETY)) + if(isWireCut(AIRLOCK_WIRE_SAFETY)) to_chat(usr, text("The safety wire is cut - Cannot secure the door.")) - else if(activate && src.safe) + else if(activate && safe) safe = 0 - else if(!activate && !src.safe) + else if(!activate && !safe) safe = 1 if("timing") // Door speed control - if(src.isWireCut(AIRLOCK_WIRE_SPEED)) + if(isWireCut(AIRLOCK_WIRE_SPEED)) to_chat(usr, text("The timing wire is cut - Cannot alter timing.")) - else if(activate && src.normalspeed) + else if(activate && normalspeed) normalspeed = 0 - else if(!activate && !src.normalspeed) + else if(!activate && !normalspeed) normalspeed = 1 if("lights") // Bolt lights - if(src.isWireCut(AIRLOCK_WIRE_LIGHT)) + if(isWireCut(AIRLOCK_WIRE_LIGHT)) to_chat(usr, "The bolt lights wire has been cut - The door bolt lights are permanently disabled.") - else if(!activate && src.lights) + else if(!activate && lights) lights = 0 to_chat(usr, "The door bolt lights have been disabled.") - else if(activate && !src.lights) + else if(activate && !lights) lights = 1 to_chat(usr, "The door bolt lights have been enabled.") if("emergency") // Emergency access - if(src.emergency) + if(emergency) emergency = 0 to_chat(usr, "Emergency access has been disabled.") else @@ -800,35 +793,35 @@ About the new airlock wires panel: /obj/machinery/door/airlock/attackby(C as obj, mob/user as mob, params) // to_chat(world, text("airlock attackby src [] obj [] mob []", src, C, user)) if(!istype(usr, /mob/living/silicon)) - if(src.isElectrified()) - if(src.shock(user, 75)) + if(isElectrified()) + if(shock(user, 75)) return if(istype(C, /obj/item/device/detective_scanner) || istype(C, /obj/item/taperoll)) return - src.add_fingerprint(user) - if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating ) && src.density)) + add_fingerprint(user) + if((istype(C, /obj/item/weapon/weldingtool) && !( operating ) && density)) var/obj/item/weapon/weldingtool/W = C if(W.remove_fuel(0,user)) if(frozen) frozen = 0 - if(!src.welded) - src.welded = 1 + if(!welded) + welded = 1 else - src.welded = null - src.update_icon() + welded = null + update_icon() return else return else if(istype(C, /obj/item/weapon/screwdriver)) - src.p_open = !( src.p_open ) - src.update_icon() + p_open = !( p_open ) + update_icon() else if(istype(C, /obj/item/weapon/wirecutters)) - return src.attack_hand(user) + return attack_hand(user) else if(istype(C, /obj/item/device/multitool)) - return src.attack_hand(user) + return attack_hand(user) else if(istype(C, /obj/item/device/assembly/signaler)) - return src.attack_hand(user) + return attack_hand(user) else if(istype(C, /obj/item/weapon/pai_cable)) // -- TLE var/obj/item/weapon/pai_cable/cable = C cable.plugin(src, user) @@ -838,13 +831,13 @@ About the new airlock wires panel: beingcrowbarred = 1 //derp, Agouri else beingcrowbarred = 0 - if( beingcrowbarred && src.p_open && (operating == -1 || (density && welded && operating != 1 && !src.arePowerSystemsOn() && !src.locked)) ) - playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) + if( beingcrowbarred && p_open && (operating == -1 || (density && welded && operating != 1 && !arePowerSystemsOn() && !locked)) ) + playsound(loc, 'sound/items/Crowbar.ogg', 100, 1) user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to remove electronics from the airlock assembly.") if(do_after(user,40, target = src)) to_chat(user, "\blue You removed the airlock electronics!") - var/obj/structure/door_assembly/da = new assembly_type(src.loc) + var/obj/structure/door_assembly/da = new assembly_type(loc) da.anchored = 1 if(mineral) da.glass = mineral @@ -852,23 +845,23 @@ About the new airlock wires panel: else if(glass && !da.glass) da.glass = 1 da.state = 1 - da.created_name = src.name + da.created_name = name da.update_state() var/obj/item/weapon/airlock_electronics/ae if(!electronics) - ae = new/obj/item/weapon/airlock_electronics( src.loc ) - if(!src.req_access) - src.check_access() - if(src.req_access.len) - ae.conf_access = src.req_access - else if(src.req_one_access.len) - ae.conf_access = src.req_one_access + ae = new/obj/item/weapon/airlock_electronics( loc ) + if(!req_access) + check_access() + if(req_access.len) + ae.conf_access = req_access + else if(req_one_access.len) + ae.conf_access = req_one_access ae.one_access = 1 else ae = electronics electronics = null - ae.loc = src.loc + ae.loc = loc if(operating == -1) ae.icon_state = "door_electronics_smoked" operating = 0 @@ -917,11 +910,11 @@ About the new airlock wires panel: return 0 use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people if(forced) - playsound(src.loc, 'sound/machines/airlockforced.ogg', 30, 1) + playsound(loc, 'sound/machines/airlockforced.ogg', 30, 1) else - playsound(src.loc, doorOpen, 30, 1) - if(src.closeOther != null && istype(src.closeOther, /obj/machinery/door/airlock/) && !src.closeOther.density) - src.closeOther.close() + playsound(loc, doorOpen, 30, 1) + if(closeOther != null && istype(closeOther, /obj/machinery/door/airlock/) && !closeOther.density) + closeOther.close() return ..() /obj/machinery/door/airlock/close(var/forced=0, var/override = 0) @@ -935,16 +928,16 @@ About the new airlock wires panel: if(safe) for(var/turf/turf in locs) if(locate(/mob/living) in turf) - // playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0) //THE BUZZING IT NEVER STOPS -Pete + // playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0) //THE BUZZING IT NEVER STOPS -Pete spawn (60) autoclose() return use_power(360) //360 W seems much more appropriate for an actuator moving an industrial door capable of crushing people if(forced) - playsound(src.loc, 'sound/machines/airlockforced.ogg', 30, 1) + playsound(loc, 'sound/machines/airlockforced.ogg', 30, 1) else - playsound(src.loc, doorClose, 30, 1) + playsound(loc, doorClose, 30, 1) var/obj/structure/window/killthis = (locate(/obj/structure/window) in get_turf(src)) if(killthis) killthis.ex_act(2)//Smashin windows @@ -953,9 +946,9 @@ About the new airlock wires panel: return 1 operating = 1 do_animate("closing") - src.layer = 3.1 + layer = 3.1 if(!override) sleep(5) - src.density = 1 + density = 1 if(!safe) crush() if(!override) sleep(5) @@ -977,19 +970,19 @@ About the new airlock wires panel: if(operating && !forced) return 0 - src.locked = 1 + locked = 1 playsound(src, boltDown, 30, 0, 3) update_icon() return 1 /obj/machinery/door/airlock/proc/unlock(var/forced=0) - if(!src.locked) + if(!locked) return if(!forced) - if(operating || !src.arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) return + if(operating || !arePowerSystemsOn() || isWireCut(AIRLOCK_WIRE_DOOR_BOLTS)) return - src.locked = 0 + locked = 0 playsound(src,boltUp, 30, 0, 3) update_icon() return 1 @@ -997,11 +990,11 @@ About the new airlock wires panel: /obj/machinery/door/airlock/New() ..() wires = new(src) - if(src.closeOtherId != null) + if(closeOtherId != null) spawn (5) for(var/obj/machinery/door/airlock/A in airlocks) - if(A.closeOtherId == src.closeOtherId && A != src) - src.closeOther = A + if(A.closeOtherId == closeOtherId && A != src) + closeOther = A break if(frozen) welded = 1 @@ -1010,8 +1003,8 @@ About the new airlock wires panel: /obj/machinery/door/airlock/hatch/gamma/attackby(C as obj, mob/user as mob, params) // to_chat(world, text("airlock attackby src [] obj [] mob []", src, C, user)) if(!istype(usr, /mob/living/silicon)) - if(src.isElectrified()) - if(src.shock(user, 75)) + if(isElectrified()) + if(shock(user, 75)) return if(istype(C, /obj/item/device/detective_scanner) || istype(C, /obj/item/taperoll)) return @@ -1024,17 +1017,17 @@ About the new airlock wires panel: to_chat(user, "The hatch is made of an advanced compound that cannot be deconstructed using an RCD.") return - src.add_fingerprint(user) - if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating > 0 ) && src.density)) + add_fingerprint(user) + if((istype(C, /obj/item/weapon/weldingtool) && !( operating > 0 ) && density)) var/obj/item/weapon/weldingtool/W = C if(W.remove_fuel(0,user)) if(frozen) frozen = 0 - if(!src.welded) - src.welded = 1 + if(!welded) + welded = 1 else - src.welded = null - src.update_icon() + welded = null + update_icon() return else return @@ -1043,23 +1036,23 @@ About the new airlock wires panel: /obj/machinery/door/airlock/highsecurity/red/attackby(C as obj, mob/user as mob, params) // to_chat(world, text("airlock attackby src [] obj [] mob []", src, C, user)) if(!istype(usr, /mob/living/silicon)) - if(src.isElectrified()) - if(src.shock(user, 75)) + if(isElectrified()) + if(shock(user, 75)) return if(istype(C, /obj/item/device/detective_scanner) || istype(C, /obj/item/taperoll)) return - src.add_fingerprint(user) - if((istype(C, /obj/item/weapon/weldingtool) && !( src.operating > 0 ) && src.density)) + add_fingerprint(user) + if((istype(C, /obj/item/weapon/weldingtool) && !( operating > 0 ) && density)) var/obj/item/weapon/weldingtool/W = C if(W.remove_fuel(0,user)) if(frozen) frozen = 0 - if(!src.welded) - src.welded = 1 + if(!welded) + welded = 1 else - src.welded = null - src.update_icon() + welded = null + update_icon() return else return @@ -1085,9 +1078,9 @@ About the new airlock wires panel: /obj/machinery/door/airlock/proc/prison_open() if(arePowerSystemsOn()) - src.unlock() - src.open() - src.lock() + unlock() + open() + lock() /obj/machinery/door/airlock/hostile_lockdown(mob/origin) // Must be powered and have working AI wire. diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index 0be61cde4b6..66547ff0759 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -172,8 +172,10 @@ //Allows AIs to use door_timer, see human attack_hand function below /obj/machinery/door_timer/attack_ai(mob/user) - return attack_hand(user) + interact(user) +/obj/machinery/door_timer/attack_ghost(mob/user) + interact(user) //Allows humans to use door_timer //Opens dialog window when someone clicks on door timer @@ -182,7 +184,9 @@ /obj/machinery/door_timer/attack_hand(mob/user) if(..()) return - + interact(user) + +/obj/machinery/door_timer/interact(mob/user) // Used for the 'time left' display var/second = round(timeleft() % 60) var/minute = round((timeleft() - second) / 60) @@ -239,9 +243,10 @@ // Also updates dialog window and timer icon /obj/machinery/door_timer/Topic(href, href_list) if(..()) - return - if(!allowed(usr)) - return + return 1 + + if(!allowed(usr) && !usr.can_admin_interact()) + return 1 usr.set_machine(src) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 7ef5406f1dc..27877c22c72 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -77,7 +77,7 @@ if(istype(AM, /obj/mecha)) var/obj/mecha/mecha = AM if(density) - if(mecha.occupant && (src.allowed(mecha.occupant) || src.check_access_list(mecha.operation_req_access) || emergency == 1)) + if(mecha.occupant && (allowed(mecha.occupant) || check_access_list(mecha.operation_req_access) || emergency == 1)) open() else do_animate("deny") @@ -111,38 +111,43 @@ do_animate("deny") return -/obj/machinery/door/attack_ai(mob/user as mob) - return src.attack_hand(user) +/obj/machinery/door/attack_ai(mob/user) + return attack_hand(user) -/obj/machinery/door/attack_hand(mob/user as mob) - return src.attackby(user, user) +/obj/machinery/door/attack_ghost(mob/user) + if(user.can_admin_interact()) + return attack_hand(user) + +/obj/machinery/door/attack_hand(mob/user) + return attackby(user, user) -/obj/machinery/door/attack_tk(mob/user as mob) +/obj/machinery/door/attack_tk(mob/user) if(requiresID() && !allowed(null)) return ..() -/obj/machinery/door/attackby(obj/item/I as obj, mob/user as mob, params) +/obj/machinery/door/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/device/detective_scanner)) return - if(src.operating || isrobot(user)) return //borgs can't attack doors open because it conflicts with their AI-like interaction with them. - src.add_fingerprint(user) - if(!Adjacent(user)) - user = null - if(!src.requiresID()) - user = null - if(src.density && (istype(I, /obj/item/weapon/card/emag)||istype(I, /obj/item/weapon/melee/energy/blade))) + + if(operating || isrobot(user)) + return //borgs can't attack doors open because it conflicts with their AI-like interaction with them. + + add_fingerprint(user) + + if(density && istype(I, /obj/item/weapon/melee/energy/blade)) emag_act(user) return 1 - if(src.allowed(user) || src.emergency == 1) - if(src.density) + + if(allowed(user) || emergency == 1 || user.can_admin_interact()) + if(density) open() else close() return - if(src.density) + + if(density) do_animate("deny") - return /obj/machinery/door/emag_act(user as mob) if(density) @@ -213,11 +218,11 @@ if(!operating) operating = 1 do_animate("opening") - src.set_opacity(0) + set_opacity(0) sleep(5) - src.density = 0 + density = 0 sleep(5) - src.layer = open_layer + layer = open_layer update_icon() set_opacity(0) operating = 0 @@ -242,9 +247,9 @@ autoclose_timer = 0 do_animate("closing") - src.layer = closed_layer + layer = closed_layer sleep(5) - src.density = 1 + density = 1 sleep(5) update_icon() if(visible && !glass) @@ -266,7 +271,7 @@ L.Weaken(5) else //for simple_animals & borgs L.adjustBruteLoss(DOOR_CRUSH_DAMAGE) - var/turf/simulated/location = src.loc + var/turf/simulated/location = loc if(istype(location, /turf/simulated)) //add_blood doesn't work for borgs/xenos, but add_blood_floor does. location.add_blood_floor(L) diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 09f4885dc07..f95612e6b89 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -173,12 +173,15 @@ if(alarmed) nextstate = CLOSED -/obj/machinery/door/firedoor/attack_ai(mob/user as mob) +/obj/machinery/door/firedoor/attack_ghost(mob/user as mob) + return attack_ai(user) + +/obj/machinery/door/firedoor/attack_ai(mob/user) if(operating || stat & NOPOWER) return //Already doing something or depowered. if(blocked) - to_chat(user, "\red \The [src] is welded solid!") + to_chat(user, "\The [src] is welded solid!") return var/area/A = get_area_master(src) @@ -186,11 +189,11 @@ var/alarmed = A.air_doors_activated || A.fire var/access_granted = 0 - if(isAI(user) || isrobot(user)) + if(isAI(user) || isrobot(user) || user.can_admin_interact()) access_granted = 1 if(access_granted == 1) - user.visible_message("\blue \The [src] [density ? "open" : "close"]s for \the [user].",\ + user.visible_message("\The [src] [density ? "open" : "close"]s for \the [user].",\ "\The [src] [density ? "open" : "close"]s.",\ "You hear a beep, and a door opening.") diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 76f6c7e94d3..7b6752f892b 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -13,9 +13,9 @@ /obj/machinery/door/window/New() ..() - if(src.req_access && src.req_access.len) - src.icon_state = "[src.icon_state]" - src.base_state = src.icon_state + if(req_access && req_access.len) + icon_state = "[icon_state]" + base_state = icon_state if(!color) color = color_windows(src) @@ -33,7 +33,7 @@ /obj/machinery/door/window/proc/open_and_close() open() - if(src.check_access(null)) + if(check_access(null)) sleep(50) else //secure doors close faster sleep(20) @@ -45,10 +45,10 @@ if(!ismob(AM)) if(istype(AM, /obj/mecha)) var/obj/mecha/mecha = AM - if(mecha.occupant && src.allowed(mecha.occupant)) + if(mecha.occupant && allowed(mecha.occupant)) open_and_close() else - flick(text("[]deny", src.base_state), src) + flick(text("[]deny", base_state), src) return if(!ticker) return @@ -58,16 +58,16 @@ return /obj/machinery/door/window/bumpopen(mob/user as mob) - if( operating || !src.density ) + if( operating || !density ) return - src.add_fingerprint(user) - if(!src.requiresID()) + add_fingerprint(user) + if(!requiresID()) user = null if(allowed(user)) open_and_close() else - flick(text("[]deny", src.base_state), src) + flick(text("[]deny", base_state), src) return /obj/machinery/door/window/CanPass(atom/movable/mover, turf/target, height=0) @@ -97,7 +97,7 @@ return 1 /obj/machinery/door/window/open(var/forced=0) - if(src.operating == 1) //doors can still open when emag-disabled + if(operating == 1) //doors can still open when emag-disabled return 0 if(!ticker) return 0 @@ -107,24 +107,24 @@ if(forced < 2) if(emagged) return 0 - if(!src.operating) //in case of emag - src.operating = 1 - flick(text("[]opening", src.base_state), src) - playsound(src.loc, 'sound/machines/windowdoor.ogg', 100, 1) - src.icon_state = text("[]open", src.base_state) + if(!operating) //in case of emag + operating = 1 + flick(text("[]opening", base_state), src) + playsound(loc, 'sound/machines/windowdoor.ogg', 100, 1) + icon_state = text("[]open", base_state) sleep(10) - src.density = 0 -// src.sd_set_opacity(0) //TODO: why is this here? Opaque windoors? ~Carn + density = 0 +// sd_set_opacity(0) //TODO: why is this here? Opaque windoors? ~Carn air_update_turf(1) update_freelook_sight() if(operating == 1) //emag again - src.operating = 0 + operating = 0 return 1 /obj/machinery/door/window/close(var/forced=0) - if(src.operating) + if(operating) return 0 if(!forced) if(stat & NOPOWER) @@ -132,33 +132,33 @@ if(forced < 2) if(emagged) return 0 - src.operating = 1 - flick(text("[]closing", src.base_state), src) - playsound(src.loc, 'sound/machines/windowdoor.ogg', 100, 1) - src.icon_state = src.base_state + operating = 1 + flick(text("[]closing", base_state), src) + playsound(loc, 'sound/machines/windowdoor.ogg', 100, 1) + icon_state = base_state - src.density = 1 -// if(src.visible) + density = 1 +// if(visible) // set_opacity(1) //TODO: why is this here? Opaque windoors? ~Carn air_update_turf(1) update_freelook_sight() sleep(10) - src.operating = 0 + operating = 0 return 1 /obj/machinery/door/window/proc/take_damage(var/damage) - src.health = max(0, src.health - damage) - if(src.health <= 0) + health = max(0, health - damage) + if(health <= 0) var/debris = list( - new /obj/item/weapon/shard(src.loc), - new /obj/item/weapon/shard(src.loc), - new /obj/item/stack/rods(src.loc, 2), - new /obj/item/stack/cable_coil(src.loc, 2) + new /obj/item/weapon/shard(loc), + new /obj/item/weapon/shard(loc), + new /obj/item/stack/rods(loc, 2), + new /obj/item/stack/cable_coil(loc, 2) ) for(var/obj/fragment in debris) transfer_fingerprints_to(fragment) - src.density = 0 + density = 0 qdel(src) return @@ -177,34 +177,37 @@ tforce = 40 else tforce = AM:throwforce - playsound(src.loc, 'sound/effects/Glasshit.ogg', 100, 1) + playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1) take_damage(tforce) //..() //Does this really need to be here twice? The parent proc doesn't even do anything yet. - Nodrak return /obj/machinery/door/window/mech_melee_attack(obj/mecha/M) if(M.damtype == "brute") - playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) + playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1) M.occupant_message("You hit [src].") visible_message("[src] has been hit by [M.name].") take_damage(M.force) return -/obj/machinery/door/window/attack_ai(mob/user as mob) - return src.attack_hand(user) +/obj/machinery/door/window/attack_ai(mob/user) + return attack_hand(user) + +/obj/machinery/door/window/attack_ghost(mob/user) + if(user.can_admin_interact()) + return attack_hand(user) /obj/machinery/door/window/proc/attack_generic(mob/user as mob, damage = 0) - if(src.operating) + if(operating) return user.changeNext_move(CLICK_CD_MELEE) user.do_attack_animation(src) - playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) - user.visible_message("[user] smashes against the [src.name].", \ - "[user] smashes against the [src.name].") + playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1) + user.visible_message("[user] smashes against the [name].", \ + "[user] smashes against the [name].") take_damage(damage) /obj/machinery/door/window/attack_alien(mob/living/user as mob) - if(islarva(user)) return attack_generic(user, 25) @@ -221,22 +224,21 @@ return attack_generic(user, 25) - /obj/machinery/door/window/attack_hand(mob/user as mob) - return src.attackby(user, user) + return attackby(user, user) /obj/machinery/door/window/emag_act(user as mob, weapon as obj) if(density) - src.operating = -1 - flick("[src.base_state]spark", src) + operating = -1 + flick("[base_state]spark", src) sleep(6) desc += "
Its access panel is smoking slightly." if(istype(weapon, /obj/item/weapon/melee/energy/blade)) var/datum/effect/system/spark_spread/spark_system = new /datum/effect/system/spark_spread() - spark_system.set_up(5, 0, src.loc) + spark_system.set_up(5, 0, loc) spark_system.start() - playsound(src.loc, "sparks", 50, 1) - playsound(src.loc, 'sound/weapons/blade1.ogg', 50, 1) + playsound(loc, "sparks", 50, 1) + playsound(loc, 'sound/weapons/blade1.ogg', 50, 1) visible_message(" The glass door was sliced open by [user]!") open(2) emagged = 1 @@ -248,33 +250,33 @@ /obj/machinery/door/window/attackby(obj/item/weapon/I as obj, mob/living/user as mob, params) //If it's in the process of opening/closing, ignore the click - if(src.operating) + if(operating) return add_fingerprint(user) //Ninja swords? You may pass. - if(src.density && (istype(I, /obj/item/weapon/card/emag)||istype(I, /obj/item/weapon/melee/energy/blade))) + if(density && (istype(I, /obj/item/weapon/card/emag)||istype(I, /obj/item/weapon/melee/energy/blade))) emag_act(user,I) return 1 if(istype(I, /obj/item/weapon/screwdriver)) - if(src.density || src.operating) + if(density || operating) to_chat(user, "You need to open the door to access the maintenance panel.") return - playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) - src.p_open = !( src.p_open ) - to_chat(user, "You [p_open ? "open":"close"] the maintenance panel of the [src.name].") + playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) + p_open = !( p_open ) + to_chat(user, "You [p_open ? "open":"close"] the maintenance panel of the [name].") return if(istype(I, /obj/item/weapon/crowbar)) - if(p_open && !src.density && !src.operating) - playsound(src.loc, 'sound/items/Crowbar.ogg', 100, 1) - user.visible_message("[user] removes the electronics from the [src.name].", \ - "You start to remove electronics from the [src.name].") + if(p_open && !density && !operating) + playsound(loc, 'sound/items/Crowbar.ogg', 100, 1) + user.visible_message("[user] removes the electronics from the [name].", \ + "You start to remove electronics from the [name].") if(do_after(user,40, target = src)) - if(src.p_open && !src.density && !src.operating && src.loc) - var/obj/structure/windoor_assembly/WA = new /obj/structure/windoor_assembly(src.loc) + if(p_open && !density && !operating && loc) + var/obj/structure/windoor_assembly/WA = new /obj/structure/windoor_assembly(loc) switch(base_state) if("left") WA.facing = "l" @@ -288,10 +290,10 @@ WA.secure = 1 WA.anchored = 1 WA.state= "02" - WA.dir = src.dir - WA.ini_dir = src.dir + WA.dir = dir + WA.ini_dir = dir WA.update_icon() - WA.created_name = src.name + WA.created_name = name if(emagged) to_chat(user, "You discard the damaged electronics.") @@ -302,18 +304,18 @@ var/obj/item/weapon/airlock_electronics/ae if(!electronics) - ae = new/obj/item/weapon/airlock_electronics( src.loc ) - if(!src.req_access) - src.check_access() - if(src.req_access.len) - ae.conf_access = src.req_access - else if(src.req_one_access.len) - ae.conf_access = src.req_one_access + ae = new/obj/item/weapon/airlock_electronics( loc ) + if(!req_access) + check_access() + if(req_access.len) + ae.conf_access = req_access + else if(req_one_access.len) + ae.conf_access = req_one_access ae.one_access = 1 else ae = electronics electronics = null - ae.loc = src.loc + ae.loc = loc qdel(src) return @@ -322,37 +324,37 @@ //If windoor is unpowered, crowbar, fireaxe and armblade can force it. if(istype(I, /obj/item/weapon/crowbar) || istype(I, /obj/item/weapon/twohanded/fireaxe)) if(stat & NOPOWER) - if(src.density) + if(density) open(2) else close(2) return //If it's a weapon, smash windoor. Unless it's an id card, agent card, ect.. then ignore it (Cards really shouldnt damage a door anyway) - if(src.density && istype(I, /obj/item/weapon) && !istype(I, /obj/item/weapon/card) ) + if(density && istype(I, /obj/item/weapon) && !istype(I, /obj/item/weapon/card) ) user.changeNext_move(CLICK_CD_MELEE) user.do_attack_animation(src) if( (I.flags&NOBLUDGEON) || !I.force ) return var/aforce = I.force - playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) + playsound(loc, 'sound/effects/Glasshit.ogg', 75, 1) visible_message("\The [src] has been hit by [user] with [I].") if(I.damtype == BURN || I.damtype == BRUTE) take_damage(aforce) return - if(!src.requiresID()) + if(!requiresID()) //don't care who they are or what they have, act as if they're NOTHING user = null - if(src.allowed(user)) - if(src.density) + if(allowed(user) || user.can_admin_interact()) + if(density) open() else close() - else if(src.density) - flick(text("[]deny", src.base_state), src) + else if(density) + flick(text("[]deny", base_state), src) return diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index 655ffd11634..bbc22aa8b2a 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -25,32 +25,32 @@ /* /obj/machinery/flasher/New() sleep(4) //<--- What the fuck are you doing? D= - src.sd_set_light(2) + sd_set_light(2) */ /obj/machinery/flasher/power_change() if( powered() ) stat &= ~NOPOWER icon_state = "[base_state]1" -// src.sd_set_light(2) +// sd_set_light(2) else stat |= ~NOPOWER icon_state = "[base_state]1-p" -// src.sd_set_light(0) +// sd_set_light(0) //Don't want to render prison breaks impossible /obj/machinery/flasher/attackby(obj/item/weapon/W as obj, mob/user as mob, params) if(istype(W, /obj/item/weapon/wirecutters)) add_fingerprint(user) - src.disable = !src.disable - if(src.disable) + disable = !disable + if(disable) user.visible_message("\red [user] has disconnected the [src]'s flashbulb!", "\red You disconnect the [src]'s flashbulb!") - if(!src.disable) + if(!disable) user.visible_message("\red [user] has connected the [src]'s flashbulb!", "\red You connect the [src]'s flashbulb!") //Let the AI trigger them directly. /obj/machinery/flasher/attack_ai() - if(src.anchored) - return src.flash() + if(anchored) + return flash() else return @@ -58,16 +58,16 @@ if(!(powered())) return - if((src.disable) || (src.last_flash && world.time < src.last_flash + 150)) + if((disable) || (last_flash && world.time < last_flash + 150)) return - playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1) + playsound(loc, 'sound/weapons/flash.ogg', 100, 1) flick("[base_state]_flash", src) - src.last_flash = world.time + last_flash = world.time use_power(1000) for(var/mob/living/L in viewers(src, null)) - if(get_dist(src, L) > src.range) + if(get_dist(src, L) > range) continue if(L.flash_eyes(affect_silicon = 1)) @@ -85,35 +85,51 @@ ..(severity) /obj/machinery/flasher/portable/HasProximity(atom/movable/AM as mob|obj) - if((src.disable) || (src.last_flash && world.time < src.last_flash + 150)) + if((disable) || (last_flash && world.time < last_flash + 150)) return if(istype(AM, /mob/living/carbon)) var/mob/living/carbon/M = AM - if((M.m_intent != "walk") && (src.anchored)) - src.flash() + if((M.m_intent != "walk") && (anchored)) + flash() /obj/machinery/flasher/portable/attackby(obj/item/weapon/W as obj, mob/user as mob, params) if(istype(W, /obj/item/weapon/wrench)) add_fingerprint(user) - src.anchored = !src.anchored + anchored = !anchored - if(!src.anchored) + if(!anchored) user.show_message(text("\red [src] can now be moved.")) - src.overlays.Cut() + overlays.Cut() - else if(src.anchored) + else if(anchored) user.show_message(text("\red [src] is now secured.")) - src.overlays += "[base_state]-s" + overlays += "[base_state]-s" +// Flasher button +/obj/machinery/flasher_button + name = "flasher button" + desc = "A remote control switch for a mounted flasher." + icon = 'icons/obj/objects.dmi' + icon_state = "launcherbtt" + var/id = null + var/active = 0 + anchored = 1.0 + use_power = 1 + idle_power_usage = 2 + active_power_usage = 4 + /obj/machinery/flasher_button/attack_ai(mob/user as mob) - return src.attack_hand(user) + return attack_hand(user) + +/obj/machinery/flasher_button/attack_ghost(mob/user) + if(user.can_admin_interact()) + return attack_hand(user) /obj/machinery/flasher_button/attackby(obj/item/weapon/W, mob/user as mob, params) - return src.attack_hand(user) + return attack_hand(user) /obj/machinery/flasher_button/attack_hand(mob/user as mob) - if(stat & (NOPOWER|BROKEN)) return if(active) @@ -125,13 +141,11 @@ icon_state = "launcheract" for(var/obj/machinery/flasher/M in world) - if(M.id == src.id) + if(M.id == id) spawn() M.flash() sleep(50) icon_state = "launcherbtt" - active = 0 - - return \ No newline at end of file + active = 0 \ No newline at end of file diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm index 1d8d9a1e22e..7f2c1706cbc 100644 --- a/code/game/machinery/newscaster.dm +++ b/code/game/machinery/newscaster.dm @@ -27,22 +27,22 @@ //var/page = null //For newspapers /datum/feed_message/proc/clear() - src.author = "" - src.body = "" - src.backup_body = "" - src.backup_author = "" - src.img = null - src.backup_img = null + author = "" + body = "" + backup_body = "" + backup_author = "" + img = null + backup_img = null view_count = 0 /datum/feed_channel/proc/clear() - src.channel_name = "" - src.messages = list() - src.locked = 0 - src.author = "" - src.backup_author = "" - src.censored = 0 - src.is_admin_channel = 0 + channel_name = "" + messages = list() + locked = 0 + author = "" + backup_author = "" + censored = 0 + is_admin_channel = 0 total_view_count = 0 /datum/feed_channel/proc/announce_news() @@ -113,10 +113,10 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co /obj/machinery/newscaster/New() //Constructor, ho~ allCasters += src - src.paper_remaining = 15 // Will probably change this to something better + paper_remaining = 15 // Will probably change this to something better for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) // Let's give it an appropriate unit number - src.unit_no++ - src.update_icon() //for any custom ones on the map... + unit_no++ + update_icon() //for any custom ones on the map... ..() //I just realised the newscasters weren't in the global machines list. The superconstructor call will tend to that /obj/machinery/newscaster/Destroy() @@ -129,21 +129,21 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co if(!ispowered || isbroken) icon_state = "newscaster_off" if(isbroken) //If the thing is smashed, add crack overlay on top of the unpowered sprite. - src.overlays.Cut() - src.overlays += image(src.icon, "crack3") + overlays.Cut() + overlays += image(icon, "crack3") return - src.overlays.Cut() //reset overlays + overlays.Cut() //reset overlays if(news_network.wanted_issue) //wanted icon state, there can be no overlays on it as it's a priority message icon_state = "newscaster_wanted" return if(alert) //new message alert overlay - src.overlays += "newscaster_alert" + overlays += "newscaster_alert" if(hitstaken > 0) //Cosmetic damage overlay - src.overlays += image(src.icon, "crack[hitstaken]") + overlays += image(icon, "crack[hitstaken]") icon_state = "newscaster_normal" return @@ -151,15 +151,15 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co /obj/machinery/newscaster/power_change() if(isbroken) //Broken shit can't be powered. return - if( src.powered() ) - src.ispowered = 1 + if( powered() ) + ispowered = 1 stat &= ~NOPOWER - src.update_icon() + update_icon() else spawn(rand(0, 15)) - src.ispowered = 0 + ispowered = 0 stat |= NOPOWER - src.update_icon() + update_icon() /obj/machinery/newscaster/ex_act(severity) @@ -168,36 +168,42 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co qdel(src) return if(2.0) - src.isbroken=1 + isbroken=1 if(prob(50)) qdel(src) else - src.update_icon() //can't place it above the return and outside the if-else. or we might get runtimes of null.update_icon() if(prob(50)) goes in. + update_icon() //can't place it above the return and outside the if-else. or we might get runtimes of null.update_icon() if(prob(50)) goes in. return else if(prob(50)) - src.isbroken=1 - src.update_icon() + isbroken=1 + update_icon() return return -/obj/machinery/newscaster/attack_ai(mob/user as mob) - return src.attack_hand(user) +/obj/machinery/newscaster/attack_ai(mob/user) + return attack_hand(user) + +/obj/machinery/newscaster/attack_ghost(mob/user) + return attack_hand(user) -/obj/machinery/newscaster/attack_hand(mob/user as mob) //########### THE MAIN BEEF IS HERE! And in the proc below this...############ - if(!src.ispowered || src.isbroken) +/obj/machinery/newscaster/attack_hand(mob/user) //########### THE MAIN BEEF IS HERE! And in the proc below this...############ + interact(user) + +/obj/machinery/newscaster/interact(mob/user) + if(!ispowered || isbroken) return - if(istype(user, /mob/living/carbon/human) || istype(user,/mob/living/silicon) ) - var/mob/living/human_or_robot_user = user + if(ishuman(user) || issilicon(user) || isobserver(user)) var/dat - dat = text("Newscaster

Newscaster Unit #[src.unit_no]

") + dat = text("Newscaster

Newscaster Unit #[unit_no]

") - src.scan_user(human_or_robot_user) //Newscaster scans you + if(can_scan(user)) + scan_user(user) //Newscaster scans you switch(screen) if(0) - dat += {"Welcome to Newscasting Unit #[src.unit_no].
Interface & News networks Operational. + dat += {"Welcome to Newscasting Unit #[unit_no].
Interface & News networks Operational.
Property of Nanotrasen"} if(news_network.wanted_issue) dat+= "
Read Wanted Issue" @@ -210,8 +216,8 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co else dat+= "
Unsilence unit" dat+= {"
Re-scan User -

Exit"} - if(src.securityCaster) +

Exit"} + if(securityCaster) var/wanted_already = 0 if(news_network.wanted_issue) wanted_already = 1 @@ -220,7 +226,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co
[(wanted_already) ? ("Manage") : ("Publish")] \"Wanted\" Issue
Censor Feed Stories
Mark Feed Channel with Nanotrasen D-Notice -

The newscaster recognises you as: [src.scanned_user]"} +

The newscaster recognises you as: [scanned_user]"} if(1) dat+= "Station Feed Channels
" if( isemptylist(news_network.network_channels) ) @@ -231,7 +237,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="[CHANNEL.channel_name]
" else dat+="[CHANNEL.channel_name] [(CHANNEL.censored) ? ("***") : ()]
" - /*for(var/datum/feed_channel/CHANNEL in src.channel_list) + /*for(var/datum/feed_channel/CHANNEL in channel_list) dat+="[CHANNEL.channel_name]:
\[created by: [CHANNEL.author]\]

" if( isemptylist(CHANNEL.messages) ) dat+="No feed messages found in channel...

" @@ -243,30 +249,30 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="
Back" if(2) dat+={"Creating new Feed Channel... -
Channel Name: [src.channel_name]
- Channel Author: [src.scanned_user]
- Will Accept Public Feeds: [(src.c_locked) ? ("NO") : ("YES")]

+
Channel Name: [channel_name]
+ Channel Author: [scanned_user]
+ Will Accept Public Feeds: [(c_locked) ? ("NO") : ("YES")]


Submit

Cancel
"} if(3) dat+={"Creating new Feed Message... -
Receiving Channel: [src.channel_name]
- Message Author: [src.scanned_user]
- Message Body: [src.msg]
- Attach Photo: [(src.photo ? "Photo Attached" : "No Photo")]
+
Receiving Channel: [channel_name]
+ Message Author: [scanned_user]
+ Message Body: [msg]
+ Attach Photo: [(photo ? "Photo Attached" : "No Photo")]

Submit

Cancel
"} if(4) - dat+="Feed story successfully submitted to [src.channel_name].

" + dat+="Feed story successfully submitted to [channel_name].

" dat+="
Return
" if(5) - dat+="Feed Channel [src.channel_name] created successfully.

" + dat+="Feed Channel [channel_name] created successfully.

" dat+="
Return
" if(6) dat+="ERROR: Could not submit Feed story to Network.

" - if(src.channel_name=="") + if(channel_name=="") dat+="Invalid receiving channel name.
" - if(src.scanned_user=="Unknown") + if(scanned_user=="Unknown") dat+="Channel author unverified.
" - if(src.msg == "" || src.msg == "\[REDACTED\]") + if(msg == "" || msg == "\[REDACTED\]") dat+="Invalid message body.
" dat+="
Return
" @@ -280,18 +286,18 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co existing_authors += FC.backup_author else existing_authors += FC.author - if(src.scanned_user in existing_authors) + if(scanned_user in existing_authors) dat+="There already exists a Feed channel under your name.
" - if(src.channel_name=="" || src.channel_name == "\[REDACTED\]") + if(channel_name=="" || channel_name == "\[REDACTED\]") dat+="Invalid channel name.
" var/check = 0 for(var/datum/feed_channel/FC in news_network.network_channels) - if(FC.channel_name == src.channel_name) + if(FC.channel_name == channel_name) check = 1 break if(check) dat+="Channel name already in use.
" - if(src.scanned_user=="Unknown") + if(scanned_user=="Unknown") dat+="Channel author unverified.
" dat+="
Return
" if(8) @@ -304,22 +310,22 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co else active_num-- dat+="Network currently serves a total of [total_num] Feed channels, [active_num] of which are active, and a total of [message_num] Feed Stories." //TODO: CONTINUE - dat+="

Liquid Paper remaining: [(src.paper_remaining) *100 ] cm^3" + dat+="

Liquid Paper remaining: [(paper_remaining) *100 ] cm^3" dat+="

Print Paper" dat+="
Cancel" if(9) - dat+="[src.viewing_channel.channel_name]: \[created by: [src.viewing_channel.author]\]
" + dat+="[viewing_channel.channel_name]: \[created by: [viewing_channel.author]\]
" dat+="Feed view count: [viewing_channel.total_view_count]
" viewing_channel.total_view_count++ - if(src.viewing_channel.censored) + if(viewing_channel.censored) dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a Nanotrasen D-Notice.
" dat+="No further feed story additions are allowed while the D-Notice is in effect.

" else - if( isemptylist(src.viewing_channel.messages) ) + if( isemptylist(viewing_channel.messages) ) dat+="No feed messages found in channel...
" else var/i = 0 - for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) + for(var/datum/feed_message/MESSAGE in viewing_channel.messages) i++ dat+="-[MESSAGE.body]
" if(MESSAGE.img) @@ -354,28 +360,28 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="
Back" if(12) - dat+="[src.viewing_channel.channel_name]: \[ created by: [src.viewing_channel.author] \]
" - dat+="[(src.viewing_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
" + dat+="[viewing_channel.channel_name]: \[ created by: [viewing_channel.author] \]
" + dat+="[(viewing_channel.author=="\[REDACTED\]") ? ("Undo Author censorship") : ("Censor channel Author")]
" - if( isemptylist(src.viewing_channel.messages) ) + if( isemptylist(viewing_channel.messages) ) dat+="No feed messages found in channel...
" else - for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) + for(var/datum/feed_message/MESSAGE in viewing_channel.messages) dat+="-[MESSAGE.body]
\[[MESSAGE.message_type] by [MESSAGE.author]\]
" dat+="[(MESSAGE.body == "\[REDACTED\]") ? ("Undo story censorship") : ("Censor story")] - [(MESSAGE.author == "\[REDACTED\]") ? ("Undo Author Censorship") : ("Censor message Author")]
" dat+="
Back" if(13) - dat+="[src.viewing_channel.channel_name]: \[ created by: [src.viewing_channel.author] \]
" - dat+="Channel messages listed below. If you deem them dangerous to the station, you can Bestow a D-Notice upon the channel.
" - if(src.viewing_channel.censored) + dat+="[viewing_channel.channel_name]: \[ created by: [viewing_channel.author] \]
" + dat+="Channel messages listed below. If you deem them dangerous to the station, you can Bestow a D-Notice upon the channel.
" + if(viewing_channel.censored) dat+="ATTENTION: This channel has been deemed as threatening to the welfare of the station, and marked with a Nanotrasen D-Notice.
" dat+="No further feed story additions are allowed while the D-Notice is in effect.

" else - if( isemptylist(src.viewing_channel.messages) ) + if( isemptylist(viewing_channel.messages) ) dat+="No feed messages found in channel...
" else - for(var/datum/feed_message/MESSAGE in src.viewing_channel.messages) + for(var/datum/feed_message/MESSAGE in viewing_channel.messages) dat+="-[MESSAGE.body]
\[[MESSAGE.message_type] by [MESSAGE.author]\]
" dat+="
Back" @@ -390,27 +396,27 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co if(wanted_already) dat+="
A wanted issue is already in Feed Circulation. You can edit or cancel it below.
" dat+="
" - dat+="Criminal Name: [src.channel_name]
" - dat+="Description: [src.msg]
" - dat+="Attach Photo: [(src.photo ? "Photo Attached" : "No Photo")]
" + dat+="Criminal Name: [channel_name]
" + dat+="Description: [msg]
" + dat+="Attach Photo: [(photo ? "Photo Attached" : "No Photo")]
" if(wanted_already) dat+="Wanted Issue created by: [news_network.wanted_issue.backup_author]
" else - dat+="Wanted Issue will be created under prosecutor: [src.scanned_user]
" + dat+="Wanted Issue will be created under prosecutor: [scanned_user]
" dat+="
[(wanted_already) ? ("Edit Issue") : ("Submit")]" if(wanted_already) dat+="
Take down Issue" dat+="
Cancel" if(15) - dat+="Wanted issue for [src.channel_name] is now in Network Circulation.

" + dat+="Wanted issue for [channel_name] is now in Network Circulation.

" dat+="
Return
" if(16) dat+="ERROR: Wanted Issue rejected by Network.

" - if(src.channel_name=="" || src.channel_name == "\[REDACTED\]") + if(channel_name=="" || channel_name == "\[REDACTED\]") dat+="Invalid name for person wanted.
" - if(src.scanned_user=="Unknown") + if(scanned_user=="Unknown") dat+="Issue author unverified.
" - if(src.msg == "" || src.msg == "\[REDACTED\]") + if(msg == "" || msg == "\[REDACTED\]") dat+="Invalid description.
" dat+="
Return
" if(17) @@ -428,7 +434,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="None" dat+="

Back
" if(19) - dat+="Wanted issue for [src.channel_name] successfully edited.

" + dat+="Wanted issue for [channel_name] successfully edited.

" dat+="
Return
" if(20) dat+="Printing successfull. Please receive your newspaper from the bottom of the machine.

" @@ -443,32 +449,24 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co var/datum/browser/popup = new(user, "newscaster_main", name, 400, 600) popup.set_content(dat) popup.open(0) - onclose(human_or_robot_user, "newscaster_main") - - /*if(src.isbroken) //debugging shit - return - src.hitstaken++ - if(src.hitstaken==3) - src.isbroken = 1 - src.update_icon()*/ - - + onclose(user, "newscaster_main") + /obj/machinery/newscaster/Topic(href, href_list) if(..()) return 1 usr.set_machine(src) if(href_list["set_channel_name"]) - src.channel_name = sanitizeSQL(strip_html_simple(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""))) - while(findtext(src.channel_name," ") == 1) - src.channel_name = copytext(src.channel_name,2,lentext(src.channel_name)+1) - src.updateUsrDialog() - //src.update_icon() + channel_name = sanitizeSQL(strip_html_simple(input(usr, "Provide a Feed Channel Name", "Network Channel Handler", ""))) + while(findtext(channel_name," ") == 1) + channel_name = copytext(channel_name,2,lentext(channel_name)+1) + updateUsrDialog() + //update_icon() else if(href_list["set_channel_lock"]) - src.c_locked = !src.c_locked - src.updateUsrDialog() - //src.update_icon() + c_locked = !c_locked + updateUsrDialog() + //update_icon() else if(href_list["submit_new_channel"]) //var/list/existing_channels = list() //OBSOLETE @@ -481,25 +479,25 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co existing_authors +=FC.author var/check = 0 for(var/datum/feed_channel/FC in news_network.network_channels) - if(FC.channel_name == src.channel_name) + if(FC.channel_name == channel_name) check = 1 break - if(src.channel_name == "" || src.channel_name == "\[REDACTED\]" || src.scanned_user == "Unknown" || check || (src.scanned_user in existing_authors) ) - src.screen=7 + if(channel_name == "" || channel_name == "\[REDACTED\]" || scanned_user == "Unknown" || check || (scanned_user in existing_authors) ) + screen=7 else var/choice = alert("Please confirm Feed channel creation","Network Channel Handler","Confirm","Cancel") if(choice=="Confirm") var/datum/feed_channel/newChannel = new /datum/feed_channel - newChannel.channel_name = src.channel_name - newChannel.author = src.scanned_user + newChannel.channel_name = channel_name + newChannel.author = scanned_user newChannel.locked = c_locked feedback_inc("newscaster_channels",1) /*for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) //Let's add the new channel in all casters. NEWSCASTER.channel_list += newChannel*/ //Now that it is sane, get it into the list. -OBSOLETE news_network.network_channels += newChannel //Adding channel to the global network - src.screen=5 - src.updateUsrDialog() - //src.update_icon() + screen=5 + updateUsrDialog() + //update_icon() else if(href_list["set_channel_receiving"]) //var/list/datum/feed_channel/available_channels = list() @@ -507,59 +505,59 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co for(var/datum/feed_channel/F in news_network.network_channels) if( (!F.locked || F.author == scanned_user) && !F.censored) available_channels += F.channel_name - src.channel_name = strip_html_simple(input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels ) - src.updateUsrDialog() + channel_name = strip_html_simple(input(usr, "Choose receiving Feed Channel", "Network Channel Handler") in available_channels ) + updateUsrDialog() else if(href_list["set_new_message"]) - src.msg = strip_html(input(usr, "Write your feed story", "Network Channel Handler", "")) - while(findtext(src.msg," ") == 1) - src.msg = copytext(src.msg,2,lentext(src.msg)+1) - src.updateUsrDialog() + msg = strip_html(input(usr, "Write your feed story", "Network Channel Handler", "")) + while(findtext(msg," ") == 1) + msg = copytext(msg,2,lentext(msg)+1) + updateUsrDialog() else if(href_list["set_attachment"]) AttachPhoto(usr) - src.updateUsrDialog() + updateUsrDialog() else if(href_list["submit_new_message"]) - if(src.msg =="" || src.msg=="\[REDACTED\]" || src.scanned_user == "Unknown" || src.channel_name == "" ) - src.screen=6 + if(msg =="" || msg=="\[REDACTED\]" || scanned_user == "Unknown" || channel_name == "" ) + screen=6 else var/datum/feed_message/newMsg = new /datum/feed_message - newMsg.author = src.scanned_user - newMsg.body = src.msg + newMsg.author = scanned_user + newMsg.body = msg if(photo) newMsg.img = photo.img feedback_inc("newscaster_stories",1) var/announcement = "" for(var/datum/feed_channel/FC in news_network.network_channels) - if(FC.channel_name == src.channel_name) + if(FC.channel_name == channel_name) FC.messages += newMsg //Adding message to the network's appropriate feed_channel announcement = FC.announce_news() break - src.screen=4 + screen=4 for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) NEWSCASTER.newsAlert(announcement) - src.updateUsrDialog() + updateUsrDialog() else if(href_list["create_channel"]) - src.screen=2 - src.updateUsrDialog() + screen=2 + updateUsrDialog() else if(href_list["create_feed_story"]) - src.screen=3 - src.updateUsrDialog() + screen=3 + updateUsrDialog() else if(href_list["menu_paper"]) - src.screen=8 - src.updateUsrDialog() + screen=8 + updateUsrDialog() else if(href_list["print_paper"]) - if(!src.paper_remaining) - src.screen=21 + if(!paper_remaining) + screen=21 else - src.print_paper() - src.screen = 20 - src.updateUsrDialog() + print_paper() + screen = 20 + updateUsrDialog() else if(href_list["silence_unit"]) silence=1 @@ -570,12 +568,12 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co updateUsrDialog() else if(href_list["menu_censor_story"]) - src.screen=10 - src.updateUsrDialog() + screen=10 + updateUsrDialog() else if(href_list["menu_censor_channel"]) - src.screen=11 - src.updateUsrDialog() + screen=11 + updateUsrDialog() else if(href_list["menu_wanted"]) var/already_wanted = 0 @@ -583,54 +581,54 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co already_wanted = 1 if(already_wanted) - src.channel_name = news_network.wanted_issue.author - src.msg = news_network.wanted_issue.body - src.screen = 14 - src.updateUsrDialog() + channel_name = news_network.wanted_issue.author + msg = news_network.wanted_issue.body + screen = 14 + updateUsrDialog() else if(href_list["set_wanted_name"]) - src.channel_name = strip_html(input(usr, "Provide the name of the Wanted person", "Network Security Handler", "")) - while(findtext(src.channel_name," ") == 1) - src.channel_name = copytext(src.channel_name,2,lentext(src.channel_name)+1) - src.updateUsrDialog() + channel_name = strip_html(input(usr, "Provide the name of the Wanted person", "Network Security Handler", "")) + while(findtext(channel_name," ") == 1) + channel_name = copytext(channel_name,2,lentext(channel_name)+1) + updateUsrDialog() else if(href_list["set_wanted_desc"]) - src.msg = strip_html(input(usr, "Provide the a description of the Wanted person and any other details you deem important", "Network Security Handler", "")) - while(findtext(src.msg," ") == 1) - src.msg = copytext(src.msg,2,lentext(src.msg)+1) - src.updateUsrDialog() + msg = strip_html(input(usr, "Provide the a description of the Wanted person and any other details you deem important", "Network Security Handler", "")) + while(findtext(msg," ") == 1) + msg = copytext(msg,2,lentext(msg)+1) + updateUsrDialog() else if(href_list["submit_wanted"]) var/input_param = text2num(href_list["submit_wanted"]) - if(src.msg == "" || src.channel_name == "" || src.scanned_user == "Unknown") - src.screen = 16 + if(msg == "" || channel_name == "" || scanned_user == "Unknown") + screen = 16 else var/choice = alert("Please confirm Wanted Issue [(input_param==1) ? ("creation.") : ("edit.")]","Network Security Handler","Confirm","Cancel") if(choice=="Confirm") if(input_param==1) //If input_param == 1 we're submitting a new wanted issue. At 2 we're just editing an existing one. See the else below var/datum/feed_message/WANTED = new /datum/feed_message - WANTED.author = src.channel_name - WANTED.body = src.msg - WANTED.backup_author = src.scanned_user //I know, a bit wacky + WANTED.author = channel_name + WANTED.body = msg + WANTED.backup_author = scanned_user //I know, a bit wacky if(photo) WANTED.img = photo.img news_network.wanted_issue = WANTED for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) NEWSCASTER.newsAlert() NEWSCASTER.update_icon() - src.screen = 15 + screen = 15 else if(news_network.wanted_issue.is_admin_message) alert("The wanted issue has been distributed by a Nanotrasen higherup. You cannot edit it.","Ok") return - news_network.wanted_issue.author = src.channel_name - news_network.wanted_issue.body = src.msg - news_network.wanted_issue.backup_author = src.scanned_user + news_network.wanted_issue.author = channel_name + news_network.wanted_issue.body = msg + news_network.wanted_issue.backup_author = scanned_user if(photo) news_network.wanted_issue.img = photo.img - src.screen = 19 + screen = 19 - src.updateUsrDialog() + updateUsrDialog() else if(href_list["cancel_wanted"]) if(news_network.wanted_issue.is_admin_message) @@ -641,12 +639,12 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co news_network.wanted_issue = null for(var/obj/machinery/newscaster/NEWSCASTER in allCasters) NEWSCASTER.update_icon() - src.screen=17 - src.updateUsrDialog() + screen=17 + updateUsrDialog() else if(href_list["view_wanted"]) - src.screen=18 - src.updateUsrDialog() + screen=18 + updateUsrDialog() else if(href_list["censor_channel_author"]) var/datum/feed_channel/FC = locate(href_list["censor_channel_author"]) if(FC.is_admin_channel) @@ -657,7 +655,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co FC.author = "\[REDACTED\]" else FC.author = FC.backup_author - src.updateUsrDialog() + updateUsrDialog() else if(href_list["censor_channel_story_author"]) var/datum/feed_message/MSG = locate(href_list["censor_channel_story_author"]) @@ -669,7 +667,7 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co MSG.author = "\[REDACTED\]" else MSG.author = MSG.backup_author - src.updateUsrDialog() + updateUsrDialog() else if(href_list["censor_channel_story_body"]) var/datum/feed_message/MSG = locate(href_list["censor_channel_story_body"]) @@ -686,13 +684,13 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co MSG.body = "\[REDACTED\]" else MSG.body = MSG.backup_body - src.updateUsrDialog() + updateUsrDialog() else if(href_list["pick_d_notice"]) var/datum/feed_channel/FC = locate(href_list["pick_d_notice"]) - src.viewing_channel = FC - src.screen=13 - src.updateUsrDialog() + viewing_channel = FC + screen=13 + updateUsrDialog() else if(href_list["toggle_d_notice"]) var/datum/feed_channel/FC = locate(href_list["toggle_d_notice"]) @@ -700,75 +698,75 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co alert("This channel was created by a Nanotrasen Officer. You cannot place a D-Notice upon it.","Ok") return FC.censored = !FC.censored - src.updateUsrDialog() + updateUsrDialog() else if(href_list["view"]) - src.screen=1 - src.updateUsrDialog() + screen=1 + updateUsrDialog() else if(href_list["setScreen"]) //Brings us to the main menu and resets all fields~ - src.screen = text2num(href_list["setScreen"]) - if(src.screen == 0) - src.scanned_user = "Unknown"; + screen = text2num(href_list["setScreen"]) + if(screen == 0) + scanned_user = "Unknown"; msg = ""; - src.c_locked=0; + c_locked=0; channel_name=""; - src.viewing_channel = null - src.updateUsrDialog() + viewing_channel = null + updateUsrDialog() else if(href_list["show_channel"]) var/datum/feed_channel/FC = locate(href_list["show_channel"]) - src.viewing_channel = FC - src.screen = 9 - src.updateUsrDialog() + viewing_channel = FC + screen = 9 + updateUsrDialog() else if(href_list["pick_censor_channel"]) var/datum/feed_channel/FC = locate(href_list["pick_censor_channel"]) - src.viewing_channel = FC - src.screen = 12 - src.updateUsrDialog() + viewing_channel = FC + screen = 12 + updateUsrDialog() else if(href_list["refresh"]) - src.updateUsrDialog() + updateUsrDialog() /obj/machinery/newscaster/attackby(obj/item/I as obj, mob/living/user as mob, params) if(istype(I, /obj/item/weapon/wrench)) to_chat(user, "Now [anchored ? "un" : ""]securing [name]") - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) if(do_after(user, 60, target = src)) new /obj/item/mounted/frame/newscaster_frame(loc) - playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1) + playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1) qdel(src) return if(isbroken) - playsound(src.loc, 'sound/effects/hit_on_shattered_glass.ogg', 100, 1) - visible_message("[user.name] further abuses the shattered [src.name].", null, 5 ) + playsound(loc, 'sound/effects/hit_on_shattered_glass.ogg', 100, 1) + visible_message("[user.name] further abuses the shattered [name].", null, 5 ) else if(istype(I, /obj/item/weapon) ) var/obj/item/weapon/W = I if(W.damtype == STAMINA) return if(W.force <15) - visible_message("[user.name] hits the [src.name] with the [W.name] with no visible effect.", null , 5 ) - playsound(src.loc, 'sound/effects/Glasshit.ogg', 100, 1) + visible_message("[user.name] hits the [name] with the [W.name] with no visible effect.", null , 5 ) + playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1) else hitstaken++ if(hitstaken==3) - visible_message("[user.name] smashes the [src.name]!", null, 5 ) + visible_message("[user.name] smashes the [name]!", null, 5 ) isbroken=1 - playsound(src.loc, 'sound/effects/Glassbr3.ogg', 100, 1) + playsound(loc, 'sound/effects/Glassbr3.ogg', 100, 1) else - visible_message("[user.name] forcefully slams the [src.name] with the [I.name]!", null, 5 ) - playsound(src.loc, 'sound/effects/Glasshit.ogg', 100, 1) + visible_message("[user.name] forcefully slams the [name] with the [I.name]!", null, 5 ) + playsound(loc, 'sound/effects/Glasshit.ogg', 100, 1) else to_chat(user, "This does nothing.") - src.update_icon() + update_icon() /obj/machinery/newscaster/proc/AttachPhoto(mob/user as mob) if(photo) if(!issilicon(user)) - photo.loc = src.loc + photo.loc = loc user.put_in_inactive_hand(photo) photo = null if(istype(user.get_active_hand(), /obj/item/weapon/photo)) @@ -813,34 +811,34 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co if(ishuman(user)) var/mob/living/carbon/human/human_user = user var/dat - src.pages = 0 + pages = 0 switch(screen) if(0) //Cover dat+="
The Griffon
" dat+="
Nanotrasen-standard newspaper, for use on Nanotrasen Space Facilities

" - if(isemptylist(src.news_content)) - if(src.important_message) - dat+="Contents:
" + if(isemptylist(news_content)) + if(important_message) + dat+="Contents:
" else dat+="Other than the title, the rest of the newspaper is unprinted..." else dat+="Contents:
" if(scribble_page==curr_page) - dat+="
There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" + dat+="
There is a small scribble near the end of this page... It reads: \"[scribble]\"" dat+= "
Next Page
Done reading
" if(1) // X channel pages inbetween. - for(var/datum/feed_channel/NP in src.news_content) - src.pages++ //Let's get it right again. - var/datum/feed_channel/C = src.news_content[src.curr_page] + for(var/datum/feed_channel/NP in news_content) + pages++ //Let's get it right again. + var/datum/feed_channel/C = news_content[curr_page] dat+="[C.channel_name] \[created by: [C.author]\]

" if(C.censored) dat+="This channel was deemed dangerous to the general welfare of the station and therefore marked with a D-Notice. Its contents were not transferred to the newspaper at the time of printing." @@ -859,12 +857,12 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co dat+="\[Story by [MESSAGE.author]\]

" dat+="" if(scribble_page==curr_page) - dat+="
There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" + dat+="
There is a small scribble near the end of this page... It reads: \"[scribble]\"" dat+= "

Previous Page
Next Page
" if(2) //Last page - for(var/datum/feed_channel/NP in src.news_content) - src.pages++ - if(src.important_message!=null) + for(var/datum/feed_channel/NP in news_content) + pages++ + if(important_message!=null) dat+="
Wanted Issue:


" dat+="Criminal name: [important_message.author]
" dat+="Description: [important_message.body]
" @@ -877,91 +875,96 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co else dat+="Apart from some uninteresting Classified ads, there's nothing on this page..." if(scribble_page==curr_page) - dat+="
There is a small scribble near the end of this page... It reads: \"[src.scribble]\"" + dat+="
There is a small scribble near the end of this page... It reads: \"[scribble]\"" dat+= "
Previous Page
" else dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com" - dat+="

[src.curr_page+1]
" + dat+="

[curr_page+1]
" human_user << browse(dat, "window=newspaper_main;size=300x400") onclose(human_user, "newspaper_main") else to_chat(user, "The paper is full of intelligible symbols!") -obj/item/weapon/newspaper/Topic(href, href_list) +/obj/item/weapon/newspaper/Topic(href, href_list) var/mob/living/U = usr ..() if((src in U.contents) || ( istype(loc, /turf) && in_range(src, U) )) U.set_machine(src) if(href_list["next_page"]) - if(curr_page==src.pages+1) + if(curr_page==pages+1) return //Don't need that at all, but anyway. - if(src.curr_page == src.pages) //We're at the middle, get to the end - src.screen = 2 + if(curr_page == pages) //We're at the middle, get to the end + screen = 2 else if(curr_page == 0) //We're at the start, get to the middle - src.screen=1 - src.curr_page++ - playsound(src.loc, "pageturn", 50, 1) + screen=1 + curr_page++ + playsound(loc, "pageturn", 50, 1) else if(href_list["prev_page"]) if(curr_page == 0) return if(curr_page == 1) - src.screen = 0 + screen = 0 else - if(curr_page == src.pages+1) //we're at the end, let's go back to the middle. - src.screen = 1 - src.curr_page-- - playsound(src.loc, "pageturn", 50, 1) + if(curr_page == pages+1) //we're at the end, let's go back to the middle. + screen = 1 + curr_page-- + playsound(loc, "pageturn", 50, 1) - if(istype(src.loc, /mob)) - src.attack_self(src.loc) + if(istype(loc, /mob)) + attack_self(loc) -obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user as mob, params) +/obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user as mob, params) if(istype(W, /obj/item/weapon/pen)) - if(src.scribble_page == src.curr_page) + if(scribble_page == curr_page) to_chat(user, "There's already a scribble in this page... You wouldn't want to make things too cluttered, would you?") else var/s = strip_html( input(user, "Write something", "Newspaper", "") ) s = sanitize(copytext(s, 1, MAX_MESSAGE_LEN)) if(!s) return - if(!in_range(src, usr) && src.loc != usr) + if(!in_range(src, usr) && loc != usr) return - src.scribble_page = src.curr_page - src.scribble = s - src.attack_self(user) + scribble_page = curr_page + scribble = s + attack_self(user) return ////////////////////////////////////helper procs - -/obj/machinery/newscaster/proc/scan_user(mob/living/user as mob) - if(istype(user,/mob/living/carbon/human)) //User is a human +/obj/machinery/newscaster/proc/scan_user(mob/user as mob) + if(ishuman(user)) //User is a human var/mob/living/carbon/human/human_user = user if(human_user.wear_id) //Newscaster scans you if(istype(human_user.wear_id, /obj/item/device/pda) ) //autorecognition, woo! var/obj/item/device/pda/P = human_user.wear_id if(P.id) - src.scanned_user = "[P.id.registered_name] ([P.id.assignment])" + scanned_user = "[P.id.registered_name] ([P.id.assignment])" else - src.scanned_user = "Unknown" + scanned_user = "Unknown" else if(istype(human_user.wear_id, /obj/item/weapon/card/id) ) var/obj/item/weapon/card/id/ID = human_user.wear_id - src.scanned_user ="[ID.registered_name] ([ID.assignment])" + scanned_user ="[ID.registered_name] ([ID.assignment])" else - src.scanned_user ="Unknown" + scanned_user = "Unknown" else - src.scanned_user ="Unknown" - else + scanned_user = "Unknown" + else if(issilicon(user)) var/mob/living/silicon/ai_user = user - src.scanned_user = "[ai_user.name] ([ai_user.job])" - + scanned_user = "[ai_user.name] ([ai_user.job])" + else + scanned_user = "Unknown" + +/obj/machinery/newscaster/proc/can_scan(mob/user as mob) + if(ishuman(user) || issilicon(user)) + . = TRUE + . = FALSE /obj/machinery/newscaster/proc/print_paper() feedback_inc("newscaster_newspapers_printed",1) @@ -971,7 +974,7 @@ obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user as mob, pa if(news_network.wanted_issue) NEWSPAPER.important_message = news_network.wanted_issue NEWSPAPER.loc = get_turf(src) - src.paper_remaining-- + paper_remaining-- return //Removed for now so these aren't even checked every tick. Left this here in-case Agouri needs it later. @@ -982,14 +985,14 @@ obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user as mob, pa if(news_call) atom_say("[news_call]!") - src.alert = 1 - src.update_icon() + alert = 1 + update_icon() spawn(300) - src.alert = 0 - src.update_icon() + alert = 0 + update_icon() if(!silence) - playsound(src.loc, 'sound/machines/twobeep.ogg', 75, 1) + playsound(loc, 'sound/machines/twobeep.ogg', 75, 1) else atom_say("Attention! Wanted issue distributed!") - playsound(src.loc, 'sound/machines/warning-buzzer.ogg', 75, 1) + playsound(loc, 'sound/machines/warning-buzzer.ogg', 75, 1) return diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 0992f8bb509..cbd0c4018fd 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -389,10 +389,13 @@ T.time = worldtime2text() vendor_account.transaction_log.Add(T) -/obj/machinery/vending/attack_ai(mob/user as mob) +/obj/machinery/vending/attack_ai(mob/user) + return attack_hand(user) + +/obj/machinery/vending/attack_ghost(mob/user) return attack_hand(user) -/obj/machinery/vending/attack_hand(mob/user as mob) +/obj/machinery/vending/attack_hand(mob/user) if(stat & (BROKEN|NOPOWER)) return @@ -465,7 +468,7 @@ usr.put_in_hands(coin) coin = null - to_chat(usr, "\blue You remove the [coin] from the [src]") + to_chat(usr, "You remove [coin] from [src].") categories &= ~CAT_COIN if(href_list["pay"]) @@ -479,76 +482,77 @@ else if(istype(usr.get_active_hand(), /obj/item/weapon/card)) paid = pay_with_card(usr.get_active_hand()) handled = 1 + else if(usr.can_admin_interact()) + paid = 1 + handled = 1 if(paid) - src.vend(currently_vending, usr) + vend(currently_vending, usr) return else if(handled) nanomanager.update_uis(src) return // don't smack that machine with your 2 credits - if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf)))) - if((href_list["vend"]) && (src.vend_ready) && (!currently_vending)) + if((href_list["vend"]) && vend_ready && !currently_vending) - if(issilicon(usr) && !isrobot(usr)) - to_chat(usr, "The vending machine refuses to interface with you, as you are not in its target demographic!") - return + if(issilicon(usr) && !isrobot(usr)) + to_chat(usr, "The vending machine refuses to interface with you, as you are not in its target demographic!") + return - if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH - to_chat(usr, "Access denied.")//Unless emagged of course + if((!allowed(usr) && !usr.can_admin_interact()) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH + to_chat(usr, "Access denied.") //Unless emagged of course + flick(icon_deny,src) + return - flick(icon_deny,src) - return + var/key = text2num(href_list["vend"]) + var/datum/data/vending_product/R = product_records[key] - var/key = text2num(href_list["vend"]) - var/datum/data/vending_product/R = product_records[key] + // This should not happen unless the request from NanoUI was bad + if(!(R.category & categories)) + return - // This should not happen unless the request from NanoUI was bad - if(!(R.category & src.categories)) - return - - if(R.price <= 0) - src.vend(R, usr) + if(R.price <= 0) + vend(R, usr) + else + currently_vending = R + if(!vendor_account || vendor_account.suspended) + status_message = "This machine is currently unable to process payments due to problems with the associated account." + status_error = 1 else - src.currently_vending = R - if(!vendor_account || vendor_account.suspended) - src.status_message = "This machine is currently unable to process payments due to problems with the associated account." - src.status_error = 1 - else - src.status_message = "Please swipe a card or insert cash to pay for the item." - src.status_error = 0 + status_message = "Please swipe a card or insert cash to pay for the item." + status_error = 0 - else if(href_list["cancelpurchase"]) - src.currently_vending = null + else if(href_list["cancelpurchase"]) + currently_vending = null - else if((href_list["togglevoice"]) && (src.panel_open)) - src.shut_up = !src.shut_up + else if(href_list["togglevoice"] && panel_open) + shut_up = !src.shut_up - src.add_fingerprint(usr) - nanomanager.update_uis(src) + add_fingerprint(usr) + nanomanager.update_uis(src) /obj/machinery/vending/proc/vend(datum/data/vending_product/R, mob/user) - if((!allowed(usr)) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH + if((!allowed(usr) || !usr.can_admin_interact()) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH to_chat(usr, "Access denied.")//Unless emagged of course + flick(icon_deny,src) + return - flick(src.icon_deny,src) - return if(!R.amount) - to_chat(user, "\red The vending machine has ran out of that product.") + to_chat(user, "The vending machine has ran out of that product.") return - src.vend_ready = 0 //One thing at a time!! - src.status_message = "Vending..." - src.status_error = 0 + vend_ready = 0 //One thing at a time!! + status_message = "Vending..." + status_error = 0 nanomanager.update_uis(src) if(R.category & CAT_COIN) if(!coin) - to_chat(user, "\blue You need to insert a coin to get this item.") + to_chat(user, "You need to insert a coin to get this item.") return if(coin.string_attached) if(prob(50)) - to_chat(user, "\blue You successfully pull the coin out before the [src] could swallow it.") + to_chat(user, "You successfully pull the coin out before the [src] could swallow it.") else - to_chat(user, "\blue You weren't able to pull the coin out fast enough, the machine ate it, string and all.") + to_chat(user, "You weren't able to pull the coin out fast enough, the machine ate it, string and all.") coin = null qdel(coin) categories &= ~CAT_COIN @@ -559,47 +563,47 @@ R.amount-- - if(((src.last_reply + (src.vend_delay + 200)) <= world.time) && src.vend_reply) + if(((last_reply + (vend_delay + 200)) <= world.time) && vend_reply) spawn(0) - src.speak(src.vend_reply) - src.last_reply = world.time + speak(src.vend_reply) + last_reply = world.time use_power(vend_power_usage) //actuators and stuff - if(src.icon_vend) //Show the vending animation if needed - flick(src.icon_vend,src) + if(icon_vend) //Show the vending animation if needed + flick(icon_vend,src) spawn(src.vend_delay) new R.product_path(get_turf(src)) - src.status_message = "" - src.status_error = 0 - src.vend_ready = 1 + status_message = "" + status_error = 0 + vend_ready = 1 currently_vending = null nanomanager.update_uis(src) /obj/machinery/vending/proc/stock(var/datum/data/vending_product/R, var/mob/user) - if(src.panel_open) + if(panel_open) to_chat(user, "\blue You stock the [src] with \a [R.product_name]") R.amount++ - src.updateUsrDialog() + updateUsrDialog() /obj/machinery/vending/process() if(stat & (BROKEN|NOPOWER)) return - if(!src.active) + if(!active) return if(src.seconds_electrified > 0) src.seconds_electrified-- //Pitch to the people! Really sell it! - if(((src.last_slogan + src.slogan_delay) <= world.time) && (src.slogan_list.len > 0) && (!src.shut_up) && prob(5)) + if(((last_slogan + src.slogan_delay) <= world.time) && (slogan_list.len > 0) && (!shut_up) && prob(5)) var/slogan = pick(src.slogan_list) - src.speak(slogan) - src.last_slogan = world.time + speak(slogan) + last_slogan = world.time - if(src.shoot_inventory && prob(shoot_chance)) - src.throw_item() + if(shoot_inventory && prob(shoot_chance)) + throw_item() return @@ -620,12 +624,12 @@ stat &= ~NOPOWER else spawn(rand(0, 15)) - src.icon_state = "[initial(icon_state)]-off" + icon_state = "[initial(icon_state)]-off" stat |= NOPOWER //Oh no we're malfunctioning! Dump out some product and break. /obj/machinery/vending/proc/malfunction() - for(var/datum/data/vending_product/R in src.product_records) + for(var/datum/data/vending_product/R in product_records) if(R.amount <= 0) //Try to use a record that actually has something to dump. continue var/dump_path = R.product_path @@ -633,12 +637,12 @@ continue while(R.amount>0) - new dump_path(src.loc) + new dump_path(loc) R.amount-- break stat |= BROKEN - src.icon_state = "[initial(icon_state)]-broken" + icon_state = "[initial(icon_state)]-broken" return //Somebody cut an important wire and now we're following a new definition of "pitch." @@ -648,7 +652,7 @@ if(!target) return 0 - for(var/datum/data/vending_product/R in src.product_records) + for(var/datum/data/vending_product/R in product_records) if(R.amount <= 0) //Try to use a record that actually has something to dump. continue var/dump_path = R.product_path @@ -656,13 +660,13 @@ continue R.amount-- - throw_item = new dump_path(src.loc) + throw_item = new dump_path(loc) break if(!throw_item) return 0 spawn(0) throw_item.throw_at(target, 16, 3, src) - src.visible_message("[src] launches [throw_item.name] at [target.name]!") + visible_message("[src] launches [throw_item.name] at [target.name]!") return 1 /* diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 69a4520ea5d..9d9dffba39e 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -469,16 +469,32 @@ connected.connected = null connected = null return ..() + +// Crematorium switch +/obj/machinery/crema_switch + desc = "Burn baby burn!" + name = "crematorium igniter" + icon = 'icons/obj/power.dmi' + icon_state = "crema_switch" + anchored = 1.0 + req_access = list(access_crematorium) + var/on = 0 + var/area/area = null + var/otherarea = null + var/id = 1 + +/obj/machinery/crema_switch/attack_ghost(mob/user) + if(user.can_admin_interact()) + return attack_hand(user) -/obj/machinery/crema_switch/attack_hand(mob/user as mob) - if(allowed(usr)) +/obj/machinery/crema_switch/attack_hand(mob/user) + if(allowed(usr) || user.can_admin_interact()) for(var/obj/structure/crematorium/C in world) if(C.id == id) if(!C.cremating) C.cremate(user) else - to_chat(usr, "\red Access denied.") - return + to_chat(usr, "Access denied.") /mob/proc/update_morgue() if(stat == DEAD) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 6b2224962f5..878e17407c7 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -76,7 +76,8 @@ var/list/admin_verbs_admin = list( /client/proc/show_snpc_verbs, /client/proc/reset_all_tcs, /*resets all telecomms scripts*/ /client/proc/cmd_admin_check_player_exp, /* shows players by playtime */ - /client/proc/toggle_mentor_chat + /client/proc/toggle_mentor_chat, + /client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/ ) var/list/admin_verbs_ban = list( /client/proc/unban_panel, @@ -965,20 +966,33 @@ var/list/admin_verbs_snpc = list( set name = "Show SNPC Verbs" set category = "Admin" - if(!holder) + if(!check_rights(R_ADMIN)) return verbs += admin_verbs_snpc verbs -= /client/proc/show_snpc_verbs - to_chat(src, "SNPC verbs on.") + to_chat(src, "SNPC verbs have been toggled on.") /client/proc/hide_snpc_verbs() set name = "Hide SNPC Verbs" set category = "Admin" - if(!holder) + if(!check_rights(R_ADMIN)) return verbs -= admin_verbs_snpc verbs += /client/proc/show_snpc_verbs - to_chat(src, "SNPC verbs off.") + to_chat(src, "SNPC verbs have been toggled off.") + +/client/proc/toggle_AI_interact() + set name = "Toggle Admin Observer Interaction" + set category = "Admin" + set desc = "Allows you to interact with most machines, computers and other objects while observing." + + if(!check_rights(R_ADMIN)) + return + + observer_interact = !observer_interact + + log_admin("[key_name(usr)] has [observer_interact ? "activated" : "deactivated"] their admin observer interaction.") + message_admins("[key_name_admin(usr)] has [observer_interact ? "activated" : "deactivated"] their admin observer interaction.") diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm index bb243c3e6aa..6ca9a5425ec 100644 --- a/code/modules/client/client defines.dm +++ b/code/modules/client/client defines.dm @@ -92,4 +92,7 @@ var/datum/chatOutput/chatOutput // Donator stuff. - var/donator_level = DONATOR_LEVEL_NONE \ No newline at end of file + var/donator_level = DONATOR_LEVEL_NONE + + // If set to true, this client can interact with most machines/computers/objects while observing + var/observer_interact = FALSE \ No newline at end of file diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm index 6635329c4cb..732e618866e 100644 --- a/code/modules/hydroponics/biogenerator.dm +++ b/code/modules/hydroponics/biogenerator.dm @@ -207,6 +207,9 @@ /obj/machinery/biogenerator/attack_hand(mob/user) interact(user) + +/obj/machinery/biogenerator/attack_ghost(mob/user) + interact(user) /obj/machinery/biogenerator/proc/activate() if(usr.stat != 0) @@ -302,7 +305,7 @@ /obj/machinery/biogenerator/Topic(href, href_list) if(..() || panel_open) - return + return 1 usr.set_machine(src) diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm index dcfd2601813..70eec9ae078 100644 --- a/code/modules/hydroponics/gene_modder.dm +++ b/code/modules/hydroponics/gene_modder.dm @@ -90,6 +90,9 @@ if(..()) return interact(user) + +/obj/machinery/plantgenes/attack_ghost(mob/user) + interact(user) /obj/machinery/plantgenes/interact(mob/user) user.set_machine(src) @@ -97,9 +100,6 @@ return var/datum/browser/popup = new(user, "plantdna", "Plant DNA Manipulator", 450, 600) - if(!(in_range(src, user) || issilicon(user))) - popup.close() - return var/dat = "" @@ -216,7 +216,7 @@ /obj/machinery/plantgenes/Topic(var/href, var/list/href_list) if(..()) - return + return 1 usr.set_machine(src) if(href_list["eject_seed"] && !operation) diff --git a/code/modules/hydroponics/seed_extractor.dm b/code/modules/hydroponics/seed_extractor.dm index 10860f45887..631e2ff7321 100644 --- a/code/modules/hydroponics/seed_extractor.dm +++ b/code/modules/hydroponics/seed_extractor.dm @@ -124,12 +124,16 @@ src.amount = am /obj/machinery/seed_extractor/attack_hand(mob/user) - user.set_machine(src) + interact(user) + +/obj/machinery/seed_extractor/attack_ghost(mob/user) interact(user) /obj/machinery/seed_extractor/interact(mob/user) - if (stat) + if(stat) return 0 + + user.set_machine(src) var/dat = "Stored seeds:
" @@ -149,7 +153,7 @@ /obj/machinery/seed_extractor/Topic(var/href, var/list/href_list) if(..()) - return + return 1 usr.set_machine(src) href_list["li"] = text2num(href_list["li"]) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index db6ef63ad22..0afdb576e99 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -648,7 +648,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return 0 /mob/dead/observer/can_admin_interact() - return check_rights(R_ADMIN, 0, src) + return client && client.observer_interact //this is a mob verb instead of atom for performance reasons //see /mob/verb/examinate() in mob.dm for more info diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 3ac858a8a6c..0897258fb1c 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -263,6 +263,9 @@ interact(H) else return ..() + +/mob/living/simple_animal/bot/attack_ghost(mob/M) + interact(M) /mob/living/simple_animal/bot/attack_ai(mob/user) if(!topic_denied(user)) @@ -867,6 +870,8 @@ Pass a positive integer as an argument to override a bot's default speed. qdel(src) /mob/living/simple_animal/bot/proc/topic_denied(mob/user) //Access check proc for bot topics! Remember to place in a bot's individual Topic if desired. + if(user.can_admin_interact()) + return 0 if(user.incapacitated() || !(issilicon(user) || in_range(src, user))) return 1 // 0 for access, 1 for denied. diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm index 80f45fa0eaf..a3a40d7d3f6 100644 --- a/code/modules/paperwork/faxmachine.dm +++ b/code/modules/paperwork/faxmachine.dm @@ -37,9 +37,12 @@ var/list/alldepartments = list() fax_network = "Central Command Quantum Entanglement Network" long_range_enabled = 1 -/obj/machinery/photocopier/faxmachine/attack_hand(mob/user as mob) +/obj/machinery/photocopier/faxmachine/attack_hand(mob/user) ui_interact(user) +/obj/machinery/photocopier/faxmachine/attack_ghost(mob/user) + ui_interact(user) + /obj/machinery/photocopier/faxmachine/attackby(obj/item/weapon/item, mob/user, params) if(istype(item,/obj/item/weapon/card/id) && !scan) scan(item) diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index d333ed1cf47..2a1b94d0f44 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -19,10 +19,13 @@ var/maxcopies = 10 //how many copies can be copied at once- idea shamelessly stolen from bs12's copier! var/mob/living/ass = null -/obj/machinery/photocopier/attack_ai(mob/user as mob) +/obj/machinery/photocopier/attack_ai(mob/user) + return attack_hand(user) + +/obj/machinery/photocopier/attack_ghost(mob/user) return attack_hand(user) -/obj/machinery/photocopier/attack_hand(mob/user as mob) +/obj/machinery/photocopier/attack_hand(mob/user) user.set_machine(src) var/dat = "Photocopier

" @@ -47,6 +50,9 @@ return /obj/machinery/photocopier/Topic(href, href_list) + if(..()) + return 1 + if(href_list["copy"]) if(stat & (BROKEN|NOPOWER)) return From 32a96111c35d28325475827f49f9537fc8c3382b Mon Sep 17 00:00:00 2001 From: Markolie Date: Thu, 9 Feb 2017 00:22:21 +0100 Subject: [PATCH 002/164] Bot interaction update --- code/modules/mob/living/simple_animal/bot/bot.dm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 0897258fb1c..14281d3728d 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -850,7 +850,7 @@ Pass a positive integer as an argument to override a bot's default speed. show_laws() bot_reset() if("ejectpai") - if(paicard && (!locked || issilicon(usr) || check_rights(R_ADMIN, 0, usr))) + if(paicard && (!locked || issilicon(usr) || usr.can_admin_interact())) to_chat(usr, "You eject [paicard] from [bot_name]") ejectpai(usr) update_controls() @@ -878,13 +878,13 @@ Pass a positive integer as an argument to override a bot's default speed. if(emagged == 2) //An emagged bot cannot be controlled by humans, silicons can if one hacked it. if(!hacked) //Manually emagged by a human - access denied to all. return 1 - else if(!issilicon(user) && !check_rights(R_ADMIN, 0, user)) //Bot is hacked, so only silicons and admins are allowed access. + else if(!issilicon(user)) //Bot is hacked, so only silicons are allowed access. return 1 return 0 /mob/living/simple_animal/bot/proc/hack(mob/user) var/hack - if(issilicon(user) || check_rights(R_ADMIN, 0, user)) //Allows silicons or admins to toggle the emag status of a bot. + if(issilicon(user) || user.can_admin_interact()) //Allows silicons or admins to toggle the emag status of a bot. hack += "[emagged == 2 ? "Software compromised! Unit may exhibit dangerous or erratic behavior." : "Unit operating normally. Release safety lock?"]
" hack += "Harm Prevention Safety System: [emagged ? "DANGER" : "Engaged"]
" else if(!locked) //Humans with access can use this option to hide a bot from the AI's remote control panel and PDA control. @@ -893,7 +893,7 @@ Pass a positive integer as an argument to override a bot's default speed. /mob/living/simple_animal/bot/proc/showpai(mob/user) var/eject = "" - if(!locked || issilicon(usr) || check_rights(R_ADMIN, 0, user)) + if(!locked || issilicon(usr) || user.can_admin_interact()) if(paicard || allow_pai) eject += "Personality card status: " if(paicard) From 476b5510f12c2bcc45bef547c9ba003964958723 Mon Sep 17 00:00:00 2001 From: Markolie Date: Thu, 9 Feb 2017 00:34:10 +0100 Subject: [PATCH 003/164] Light switch admin interaction --- code/game/machinery/lightswitch.dm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index c73cac81669..837779df22d 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -72,8 +72,11 @@ if(..(user, 1)) to_chat(user, "A light switch. It is [on? "on" : "off"].") +/obj/machinery/light_switch/attack_ghost(mob/user) + if(user.can_admin_observe()) + return attack_hand(user) + /obj/machinery/light_switch/attack_hand(mob/user) - on = !on updateicon() From 77a3c53f235101b785fc57ee181fe4b2e4da28ae Mon Sep 17 00:00:00 2001 From: Markolie Date: Thu, 9 Feb 2017 00:43:03 +0100 Subject: [PATCH 004/164] Derp, rename proc --- code/game/machinery/lightswitch.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index 837779df22d..8876bc83514 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -73,7 +73,7 @@ to_chat(user, "A light switch. It is [on? "on" : "off"].") /obj/machinery/light_switch/attack_ghost(mob/user) - if(user.can_admin_observe()) + if(user.can_admin_interact()) return attack_hand(user) /obj/machinery/light_switch/attack_hand(mob/user) From 3077fb42bf90495655e98338858f49645d86a74c Mon Sep 17 00:00:00 2001 From: Markolie Date: Thu, 9 Feb 2017 00:56:05 +0100 Subject: [PATCH 005/164] Add logging to opening/closing job slots and hacking bots --- code/game/machinery/computer/card.dm | 2 ++ code/modules/admin/verbs/custom_event.dm | 4 ++-- code/modules/mob/living/simple_animal/bot/bot.dm | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index 66e2ec25779..9d7a525b763 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -412,6 +412,7 @@ var/time_last_changed_position = 0 time_last_changed_position = world.time / 10 j.total_positions++ opened_positions[edit_job_target]++ + log_game("[key_name(usr)] has opened a job slot for job \"[j.name]\".") nanomanager.update_uis(src) if("make_job_unavailable") @@ -428,6 +429,7 @@ var/time_last_changed_position = 0 time_last_changed_position = world.time / 10 j.total_positions-- opened_positions[edit_job_target]-- + log_game("[key_name(usr)] has closed a job slot for job \"[j.name]\".") nanomanager.update_uis(src) if(modify) diff --git a/code/modules/admin/verbs/custom_event.dm b/code/modules/admin/verbs/custom_event.dm index 350ed9a8737..3dc31df8169 100644 --- a/code/modules/admin/verbs/custom_event.dm +++ b/code/modules/admin/verbs/custom_event.dm @@ -10,11 +10,11 @@ var/input = input(usr, "Enter the description of the custom event. Be descriptive. To cancel the event, make this blank or hit cancel.", "Custom Event", custom_event_msg) as message|null if(!input || input == "") custom_event_msg = null - log_admin("[usr.key] has cleared the custom event text.") + log_admin("[key)_name(usr)] has cleared the custom event text.") message_admins("[key_name_admin(usr)] has cleared the custom event text.") return - log_admin("[usr.key] has changed the custom event text.") + log_admin("[key_name(usr)] has changed the custom event text.") message_admins("[key_name_admin(usr)] has changed the custom event text.") custom_event_msg = input diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 14281d3728d..5bafceffcfc 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -841,6 +841,7 @@ Pass a positive integer as an argument to override a bot's default speed. to_chat(usr, "[text_hack]") show_laws() bot_reset() + add_logs(usr, src, "hacked") else if(!hacked) to_chat(usr, "[text_dehack_fail]") else @@ -849,6 +850,7 @@ Pass a positive integer as an argument to override a bot's default speed. to_chat(usr, "[text_dehack]") show_laws() bot_reset() + add_logs(usr, src, "dehacked") if("ejectpai") if(paicard && (!locked || issilicon(usr) || usr.can_admin_interact())) to_chat(usr, "You eject [paicard] from [bot_name]") From 28244f8f461963a99c893ecb3c373245e218a2f4 Mon Sep 17 00:00:00 2001 From: Markolie Date: Thu, 9 Feb 2017 01:00:23 +0100 Subject: [PATCH 006/164] Fix compile issue --- code/modules/admin/verbs/custom_event.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/admin/verbs/custom_event.dm b/code/modules/admin/verbs/custom_event.dm index 3dc31df8169..68d3301b11e 100644 --- a/code/modules/admin/verbs/custom_event.dm +++ b/code/modules/admin/verbs/custom_event.dm @@ -10,7 +10,7 @@ var/input = input(usr, "Enter the description of the custom event. Be descriptive. To cancel the event, make this blank or hit cancel.", "Custom Event", custom_event_msg) as message|null if(!input || input == "") custom_event_msg = null - log_admin("[key)_name(usr)] has cleared the custom event text.") + log_admin("[key_name(usr)] has cleared the custom event text.") message_admins("[key_name_admin(usr)] has cleared the custom event text.") return From efa7923718ea9453d7cc2e94385cd0dad25fb04e Mon Sep 17 00:00:00 2001 From: Markolie Date: Thu, 9 Feb 2017 01:05:48 +0100 Subject: [PATCH 007/164] Actually fix compile issue --- code/game/machinery/computer/card.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index 9d7a525b763..1588d990d80 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -412,7 +412,7 @@ var/time_last_changed_position = 0 time_last_changed_position = world.time / 10 j.total_positions++ opened_positions[edit_job_target]++ - log_game("[key_name(usr)] has opened a job slot for job \"[j.name]\".") + log_game("[key_name(usr)] has opened a job slot for job \"[j]\".") nanomanager.update_uis(src) if("make_job_unavailable") @@ -429,7 +429,7 @@ var/time_last_changed_position = 0 time_last_changed_position = world.time / 10 j.total_positions-- opened_positions[edit_job_target]-- - log_game("[key_name(usr)] has closed a job slot for job \"[j.name]\".") + log_game("[key_name(usr)] has closed a job slot for job \"[j]\".") nanomanager.update_uis(src) if(modify) From 77e54da0f6b1c075f7f4328b10c9eb569575a323 Mon Sep 17 00:00:00 2001 From: Markolie Date: Thu, 9 Feb 2017 01:21:02 +0100 Subject: [PATCH 008/164] Enable observing interacting by default --- code/modules/client/client defines.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm index 6ca9a5425ec..6b8acce8712 100644 --- a/code/modules/client/client defines.dm +++ b/code/modules/client/client defines.dm @@ -95,4 +95,4 @@ var/donator_level = DONATOR_LEVEL_NONE // If set to true, this client can interact with most machines/computers/objects while observing - var/observer_interact = FALSE \ No newline at end of file + var/observer_interact = TRUE \ No newline at end of file From 1b4d73d6f7d404fe1d522ef16512f66ca90156f6 Mon Sep 17 00:00:00 2001 From: Markolie Date: Thu, 9 Feb 2017 01:21:42 +0100 Subject: [PATCH 009/164] Adding an admin_check to can_admin_interact() --- code/modules/mob/dead/observer/observer.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 0afdb576e99..0e4cc50ce08 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -648,7 +648,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return 0 /mob/dead/observer/can_admin_interact() - return client && client.observer_interact + return client && client.observer_interact && check_rights(R_ADMIN, 0, src) //this is a mob verb instead of atom for performance reasons //see /mob/verb/examinate() in mob.dm for more info From 44a55cd88e27437f0a09652e533a02da32422710 Mon Sep 17 00:00:00 2001 From: Markolie Date: Thu, 9 Feb 2017 01:22:16 +0100 Subject: [PATCH 010/164] Clarify variable description --- code/modules/client/client defines.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm index 6b8acce8712..76aca64bfc0 100644 --- a/code/modules/client/client defines.dm +++ b/code/modules/client/client defines.dm @@ -94,5 +94,5 @@ // Donator stuff. var/donator_level = DONATOR_LEVEL_NONE - // If set to true, this client can interact with most machines/computers/objects while observing + // If set to true, this client can interact with most machines/computers/objects while observing (requires R_ADMIN as well) var/observer_interact = TRUE \ No newline at end of file From 2afd77a54ab10064414bedb04378ead81de18292 Mon Sep 17 00:00:00 2001 From: Markolie Date: Thu, 9 Feb 2017 19:30:36 +0100 Subject: [PATCH 011/164] Split admin interaction into regular and advanced, make more devices ghost-interactable --- code/game/machinery/ai_slipper.dm | 60 +++++++++++----------- code/game/machinery/buttons.dm | 4 +- code/game/machinery/door_control.dm | 4 +- code/game/machinery/doors/firedoor.dm | 2 +- code/game/machinery/doors/windowdoor.dm | 4 +- code/game/machinery/flasher.dm | 10 ++-- code/game/machinery/lightswitch.dm | 2 +- code/game/objects/structures/morgue.dm | 4 +- code/modules/admin/admin_verbs.dm | 14 ++--- code/modules/client/client defines.dm | 4 +- code/modules/mob/dead/observer/observer.dm | 16 +++++- 11 files changed, 69 insertions(+), 55 deletions(-) diff --git a/code/game/machinery/ai_slipper.dm b/code/game/machinery/ai_slipper.dm index a88abfc61b9..cd81d6db3cc 100644 --- a/code/game/machinery/ai_slipper.dm +++ b/code/game/machinery/ai_slipper.dm @@ -24,46 +24,49 @@ stat |= NOPOWER /obj/machinery/ai_slipper/proc/setState(var/enabled, var/uses) - src.disabled = disabled - src.uses = uses - src.power_change() + disabled = disabled + uses = uses + power_change() /obj/machinery/ai_slipper/attackby(obj/item/weapon/W, mob/user, params) if(stat & (NOPOWER|BROKEN)) return if(istype(user, /mob/living/silicon)) - return src.attack_hand(user) + return attack_hand(user) else // trying to unlock the interface - if(src.allowed(usr)) + if(allowed(usr)) locked = !locked - to_chat(user, "You [ locked ? "lock" : "unlock"] the device.") + to_chat(user, "You [locked ? "lock" : "unlock"] the device.") if(locked) - if(user.machine==src) + if(user.machine == src) user.unset_machine() user << browse(null, "window=ai_slipper") else - if(user.machine==src) - src.attack_hand(usr) + if(user.machine == src) + attack_hand(usr) else to_chat(user, "\red Access denied.") return return -/obj/machinery/ai_slipper/attack_ai(mob/user as mob) +/obj/machinery/ai_slipper/attack_ai(mob/user) + return attack_hand(user) + +/obj/machinery/ai_slipper/attack_ghost(mob/user) return attack_hand(user) -/obj/machinery/ai_slipper/attack_hand(mob/user as mob) +/obj/machinery/ai_slipper/attack_hand(mob/user) if(stat & (NOPOWER|BROKEN)) return - if( (get_dist(src, user) > 1 )) - if(!istype(user, /mob/living/silicon)) - to_chat(user, text("Too far away.")) - user.unset_machine() - user << browse(null, "window=ai_slipper") - return + + if(get_dist(src, user) > 1 && (!issilicon(user) || !user.can_admin_interact())) + to_chat(user, "Too far away.") + user.unset_machine() + user << browse(null, "window=ai_slipper") + return user.set_machine(src) - var/loc = src.loc + var/loc = loc if(istype(loc, /turf)) loc = loc:loc if(!istype(loc, /area)) @@ -72,39 +75,37 @@ var/area/area = loc var/t = "AI Liquid Dispenser ([area.name])
" - if(src.locked && (!istype(user, /mob/living/silicon))) + if(locked && (!issilicon(user) || !user.can_admin_interact())) t += "(Swipe ID card to unlock control panel.)
" else - t += text("Dispenser [] - []?
\n", src.disabled?"deactivated":"activated", src.disabled?"Enable":"Disable") + t += text("Dispenser [] - []?
\n", disabled ? "deactivated" : "activated", disabled ? "Enable" : "Disable") t += text("Uses Left: [uses]. Activate the dispenser?
\n") user << browse(t, "window=computer;size=575x450") onclose(user, "computer") - return /obj/machinery/ai_slipper/Topic(href, href_list) if(..()) return 1 - if(src.locked) + if(locked) if(!istype(usr, /mob/living/silicon)) to_chat(usr, "Control panel is locked!") return if(href_list["toggleOn"]) - src.disabled = !src.disabled - icon_state = src.disabled? "motion0":"motion3" + disabled = !disabled + icon_state = disabled? "motion0":"motion3" if(href_list["toggleUse"]) if(cooldown_on || disabled) return else - new /obj/effect/effect/foam(src.loc) - src.uses-- + new /obj/effect/effect/foam(loc) + uses-- cooldown_on = 1 cooldown_time = world.timeofday + 100 slip_process() return - src.attack_hand(usr) - return + attack_hand(usr) /obj/machinery/ai_slipper/proc/slip_process() while(cooldown_time - world.timeofday > 0) @@ -120,5 +121,4 @@ return if(uses >= 0) cooldown_on = 0 - src.power_change() - return \ No newline at end of file + power_change() \ No newline at end of file diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index e28bf145b74..b2d934dc9a2 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -56,7 +56,7 @@ return attack_hand(user) /obj/machinery/driver_button/attack_ghost(mob/user) - if(user.can_admin_interact()) + if(user.can_advanced_admin_interact()) return attack_hand(user) /obj/machinery/driver_button/attackby(obj/item/weapon/W, mob/user as mob, params) @@ -169,7 +169,7 @@ return attack_hand(user) /obj/machinery/ignition_switch/attack_ghost(mob/user) - if(user.can_admin_interact()) + if(user.can_advanced_admin_interact()) return attack_hand(user) /obj/machinery/ignition_switch/attackby(obj/item/weapon/W, mob/user, params) diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm index e9e4a40e465..a3eeccb94a8 100644 --- a/code/game/machinery/door_control.dm +++ b/code/game/machinery/door_control.dm @@ -64,7 +64,7 @@ playsound(loc, "sparks", 100, 1) /obj/machinery/door_control/attack_ghost(mob/user) - if(user.can_admin_interact()) + if(user.can_advanced_admin_interact()) return attack_hand(user) /obj/machinery/door_control/attack_hand(mob/user as mob) @@ -72,7 +72,7 @@ if(stat & (NOPOWER|BROKEN)) return - if(!allowed(user) && (wires & 1) && !user.can_admin_interact()) + if(!allowed(user) && (wires & 1) && !user.can_advanced_admin_interact()) to_chat(user, "Access Denied.") flick("doorctrl-denied",src) return diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index f95612e6b89..79a9d02e9ea 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -189,7 +189,7 @@ var/alarmed = A.air_doors_activated || A.fire var/access_granted = 0 - if(isAI(user) || isrobot(user) || user.can_admin_interact()) + if(isAI(user) || isrobot(user) || user.can_advanced_admin_interact()) access_granted = 1 if(access_granted == 1) diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 7b6752f892b..d802192a107 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -194,7 +194,7 @@ return attack_hand(user) /obj/machinery/door/window/attack_ghost(mob/user) - if(user.can_admin_interact()) + if(user.can_advanced_admin_interact()) return attack_hand(user) /obj/machinery/door/window/proc/attack_generic(mob/user as mob, damage = 0) @@ -347,7 +347,7 @@ //don't care who they are or what they have, act as if they're NOTHING user = null - if(allowed(user) || user.can_admin_interact()) + if(allowed(user) || user.can_advanced_admin_interact()) if(density) open() else diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index bbc22aa8b2a..2cf45577183 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -48,11 +48,13 @@ user.visible_message("\red [user] has connected the [src]'s flashbulb!", "\red You connect the [src]'s flashbulb!") //Let the AI trigger them directly. -/obj/machinery/flasher/attack_ai() +/obj/machinery/flasher/attack_ai(mob/user) if(anchored) return flash() - else - return + +/obj/machinery/flasher/attack_ghost(mob/user) + if(anchored && user.can_advanced_admin_interact()) + return flash() /obj/machinery/flasher/proc/flash() if(!(powered())) @@ -123,7 +125,7 @@ return attack_hand(user) /obj/machinery/flasher_button/attack_ghost(mob/user) - if(user.can_admin_interact()) + if(user.can_advanced_admin_interact()) return attack_hand(user) /obj/machinery/flasher_button/attackby(obj/item/weapon/W, mob/user as mob, params) diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index 8876bc83514..330fc5e1104 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -73,7 +73,7 @@ to_chat(user, "A light switch. It is [on? "on" : "off"].") /obj/machinery/light_switch/attack_ghost(mob/user) - if(user.can_admin_interact()) + if(user.can_advanced_admin_interact()) return attack_hand(user) /obj/machinery/light_switch/attack_hand(mob/user) diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index 9d9dffba39e..be81c338c08 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -484,11 +484,11 @@ var/id = 1 /obj/machinery/crema_switch/attack_ghost(mob/user) - if(user.can_admin_interact()) + if(user.can_advanced_admin_interact()) return attack_hand(user) /obj/machinery/crema_switch/attack_hand(mob/user) - if(allowed(usr) || user.can_admin_interact()) + if(allowed(usr) || user.can_advanced_admin_interact()) for(var/obj/structure/crematorium/C in world) if(C.id == id) if(!C.cremating) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 878e17407c7..ab2b6beb9e7 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -77,7 +77,7 @@ var/list/admin_verbs_admin = list( /client/proc/reset_all_tcs, /*resets all telecomms scripts*/ /client/proc/cmd_admin_check_player_exp, /* shows players by playtime */ /client/proc/toggle_mentor_chat, - /client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/ + /client/proc/toggle_advanced_interaction, /*toggle admin ability to interact with not only machines, but also atoms such as buttons and doors*/ ) var/list/admin_verbs_ban = list( /client/proc/unban_panel, @@ -984,15 +984,15 @@ var/list/admin_verbs_snpc = list( verbs += /client/proc/show_snpc_verbs to_chat(src, "SNPC verbs have been toggled off.") -/client/proc/toggle_AI_interact() - set name = "Toggle Admin Observer Interaction" +/client/proc/toggle_advanced_interaction() + set name = "Toggle Advanced Admin Interaction" set category = "Admin" - set desc = "Allows you to interact with most machines, computers and other objects while observing." + set desc = "Allows you to interact with atoms such as buttons and doors, on top of regular machinery interaction." if(!check_rights(R_ADMIN)) return - observer_interact = !observer_interact + advanced_admin_interaction = !advanced_admin_interaction - log_admin("[key_name(usr)] has [observer_interact ? "activated" : "deactivated"] their admin observer interaction.") - message_admins("[key_name_admin(usr)] has [observer_interact ? "activated" : "deactivated"] their admin observer interaction.") + log_admin("[key_name(usr)] has [advanced_admin_interaction ? "activated" : "deactivated"] their advanced admin interaction.") + message_admins("[key_name_admin(usr)] has [advanced_admin_interaction ? "activated" : "deactivated"] their advanced admin interaction.") diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm index 76aca64bfc0..bc4a9d83641 100644 --- a/code/modules/client/client defines.dm +++ b/code/modules/client/client defines.dm @@ -94,5 +94,5 @@ // Donator stuff. var/donator_level = DONATOR_LEVEL_NONE - // If set to true, this client can interact with most machines/computers/objects while observing (requires R_ADMIN as well) - var/observer_interact = TRUE \ No newline at end of file + // If set to true, this client can interact with atoms such as buttons and doors on top of regular machinery interaction + var/advanced_admin_interaction = FALSE \ No newline at end of file diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 0e4cc50ce08..56c5e33ee1c 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -645,10 +645,22 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp client.images -= ghostimage //remove ourself /mob/proc/can_admin_interact() - return 0 + return FALSE + +/mob/proc/can_advanced_admin_interact() + return FALSE /mob/dead/observer/can_admin_interact() - return client && client.observer_interact && check_rights(R_ADMIN, 0, src) + return check_rights(R_ADMIN, 0, src) + +/mob/dead/observer/can_advanced_admin_interact() + if(!can_admin_interact()) + return FALSE + + if(client && client.advanced_admin_interaction) + return TRUE + + return FALSE //this is a mob verb instead of atom for performance reasons //see /mob/verb/examinate() in mob.dm for more info From 93391c8dc96965cbc0c36f67dab4dc8f6612a0a2 Mon Sep 17 00:00:00 2001 From: Markolie Date: Thu, 9 Feb 2017 19:37:56 +0100 Subject: [PATCH 012/164] Fix shitcode --- code/game/machinery/ai_slipper.dm | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/code/game/machinery/ai_slipper.dm b/code/game/machinery/ai_slipper.dm index cd81d6db3cc..2b5eef23a12 100644 --- a/code/game/machinery/ai_slipper.dm +++ b/code/game/machinery/ai_slipper.dm @@ -66,14 +66,8 @@ return user.set_machine(src) - var/loc = loc - if(istype(loc, /turf)) - loc = loc:loc - if(!istype(loc, /area)) - to_chat(user, text("Turret badly positioned - loc.loc is [].", loc)) - return - var/area/area = loc - var/t = "AI Liquid Dispenser ([area.name])
" + var/area/myarea = get_area(src) + var/t = "AI Liquid Dispenser ([myarea.name])
" if(locked && (!issilicon(user) || !user.can_admin_interact())) t += "(Swipe ID card to unlock control panel.)
" From b751704ef4438fea1d012a853363f528852ba550 Mon Sep 17 00:00:00 2001 From: Markolie Date: Thu, 9 Feb 2017 19:54:52 +0100 Subject: [PATCH 013/164] Admin interaction fixes --- code/game/machinery/doors/door.dm | 6 +++--- code/game/machinery/doors/windowdoor.dm | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 27877c22c72..0d1488acad6 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -115,7 +115,7 @@ return attack_hand(user) /obj/machinery/door/attack_ghost(mob/user) - if(user.can_admin_interact()) + if(user.can_advanced_admin_interact()) return attack_hand(user) /obj/machinery/door/attack_hand(mob/user) @@ -135,11 +135,11 @@ add_fingerprint(user) - if(density && istype(I, /obj/item/weapon/melee/energy/blade)) + if(density && (istype(I, /obj/item/weapon/card/emag) || istype(I, /obj/item/weapon/melee/energy/blade))) emag_act(user) return 1 - if(allowed(user) || emergency == 1 || user.can_admin_interact()) + if(allowed(user) || emergency == 1 || user.can_advanced_admin_interact()) if(density) open() else diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index d802192a107..74a65f1a93d 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -256,7 +256,7 @@ add_fingerprint(user) //Ninja swords? You may pass. - if(density && (istype(I, /obj/item/weapon/card/emag)||istype(I, /obj/item/weapon/melee/energy/blade))) + if(density && (istype(I, /obj/item/weapon/card/emag) || istype(I, /obj/item/weapon/melee/energy/blade))) emag_act(user,I) return 1 From 1e97a262b84abbdb3daa7935389c9f8cfca0258c Mon Sep 17 00:00:00 2001 From: Markolie Date: Fri, 10 Feb 2017 01:20:01 +0100 Subject: [PATCH 014/164] Admin interaction fixes --- code/game/machinery/ai_slipper.dm | 13 ++++++------ code/game/machinery/doors/firedoor.dm | 3 ++- .../mob/living/simple_animal/bot/bot.dm | 2 +- .../mob/living/simple_animal/bot/cleanbot.dm | 2 +- .../mob/living/simple_animal/bot/ed209bot.dm | 2 +- .../mob/living/simple_animal/bot/floorbot.dm | 2 +- .../mob/living/simple_animal/bot/medbot.dm | 2 +- .../mob/living/simple_animal/bot/mulebot.dm | 2 +- .../mob/living/simple_animal/bot/secbot.dm | 2 +- code/modules/paperwork/faxmachine.dm | 21 +++++++++++++------ 10 files changed, 31 insertions(+), 20 deletions(-) diff --git a/code/game/machinery/ai_slipper.dm b/code/game/machinery/ai_slipper.dm index 2b5eef23a12..6ad0d3f3ecf 100644 --- a/code/game/machinery/ai_slipper.dm +++ b/code/game/machinery/ai_slipper.dm @@ -59,7 +59,7 @@ if(stat & (NOPOWER|BROKEN)) return - if(get_dist(src, user) > 1 && (!issilicon(user) || !user.can_admin_interact())) + if(get_dist(src, user) > 1 && (!issilicon(user) && !user.can_admin_interact())) to_chat(user, "Too far away.") user.unset_machine() user << browse(null, "window=ai_slipper") @@ -69,7 +69,7 @@ var/area/myarea = get_area(src) var/t = "AI Liquid Dispenser ([myarea.name])
" - if(locked && (!issilicon(user) || !user.can_admin_interact())) + if(locked && (!issilicon(user) && !user.can_admin_interact())) t += "(Swipe ID card to unlock control panel.)
" else t += text("Dispenser [] - []?
\n", disabled ? "deactivated" : "activated", disabled ? "Enable" : "Disable") @@ -81,10 +81,11 @@ /obj/machinery/ai_slipper/Topic(href, href_list) if(..()) return 1 - if(locked) - if(!istype(usr, /mob/living/silicon)) - to_chat(usr, "Control panel is locked!") - return + + if(locked && (!issilicon(usr) && !usr.can_admin_interact())) + to_chat(usr, "Control panel is locked!") + return 1 + if(href_list["toggleOn"]) disabled = !disabled icon_state = disabled? "motion0":"motion3" diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 79a9d02e9ea..f738cdb4d7f 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -174,7 +174,8 @@ nextstate = CLOSED /obj/machinery/door/firedoor/attack_ghost(mob/user as mob) - return attack_ai(user) + if(user.can_advanced_admin_interact()) + return attack_ai(user) /obj/machinery/door/firedoor/attack_ai(mob/user) if(operating || stat & NOPOWER) diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 5bafceffcfc..50a7afc64b5 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -821,7 +821,7 @@ Pass a positive integer as an argument to override a bot's default speed. return 1 add_fingerprint(usr) - if((href_list["power"]) && (bot_core.allowed(usr) || !locked)) + if((href_list["power"]) && (bot_core.allowed(usr) || !locked || usr.can_admin_interact())) if(on) turn_off() else diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index 3f60793de02..2aebeb5d04a 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -204,7 +204,7 @@ Status: []
Behaviour controls are [locked ? "locked" : "unlocked"]
Maintenance panel panel is [open ? "opened" : "closed"]"}, text("[on ? "On" : "Off"]")) - if(!locked || issilicon(user) || check_rights(R_ADMIN, 0, user)) + if(!locked || issilicon(user) || user.can_admin_interact()) dat += text({"
Cleans Blood: []
"}, text("[blood ? "Yes" : "No"]")) dat += text({"
Patrol station: []
"}, text("[auto_patrol ? "Yes" : "No"]")) return dat diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 65ee91d6897..8a160d25c4f 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -106,7 +106,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]
"}, "[on ? "On" : "Off"]" ) - if(!locked || issilicon(user) || check_rights(R_ADMIN, 0, user)) + if(!locked || issilicon(user) || user.can_admin_interact()) if(!lasercolor) dat += text({"
Arrest Unidentifiable Persons: []
diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm index 62d5c5f5823..a02447cd4ea 100644 --- a/code/modules/mob/living/simple_animal/bot/floorbot.dm +++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm @@ -69,7 +69,7 @@ dat += "Maintenance panel panel is [open ? "opened" : "closed"]
" dat += "Tiles left: [amount]
" dat += "Behvaiour controls are [locked ? "locked" : "unlocked"]
" - if(!locked || issilicon(user) || check_rights(R_ADMIN, 0, user)) + if(!locked || issilicon(user) || user.can_admin_interact()) dat += "Add tiles to new hull plating: [autotile ? "Yes" : "No"]
" dat += "Replace floor tiles: [replacetiles ? "Yes" : "No"]
" dat += "Finds tiles: [eattiles ? "Yes" : "No"]
" diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index 4eafbf50065..50475fe45db 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -149,7 +149,7 @@ else dat += "None Loaded" dat += "
Behaviour controls are [locked ? "locked" : "unlocked"]
" - if(!locked || issilicon(user) || check_rights(R_ADMIN, 0, user)) + if(!locked || issilicon(user) || user.can_admin_interact()) dat += "Healing Threshold: " dat += "-- " dat += "- " diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 17adfa19c54..14f7030243e 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -284,7 +284,7 @@ dat += "Destination: [!destination ? "none" : destination]
" dat += "Power level: [cell ? cell.percent() : 0]%" - if(locked && !ai && !check_rights(R_ADMIN, 0, user)) + if(locked && !ai && !user.can_admin_interact()) dat += " 
Controls are locked
Unlock Controls" else dat += " 
Controls are unlocked
Lock Controls

" diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm index 9d9e86125b2..a439d793eb3 100644 --- a/code/modules/mob/living/simple_animal/bot/secbot.dm +++ b/code/modules/mob/living/simple_animal/bot/secbot.dm @@ -119,7 +119,7 @@ Maintenance panel panel is [open ? "opened" : "closed"]"}, "[on ? "On" : "Off"]" ) - if(!locked || issilicon(user) || check_rights(R_ADMIN, 0, user)) + if(!locked || issilicon(user) || user.can_admin_interact()) dat += text({"
Arrest Unidentifiable Persons: []
Arrest for Unauthorized Weapons: []
diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm index a3a40d7d3f6..fd10ebbbaf0 100644 --- a/code/modules/paperwork/faxmachine.dm +++ b/code/modules/paperwork/faxmachine.dm @@ -67,13 +67,14 @@ var/list/alldepartments = list() /obj/machinery/photocopier/faxmachine/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) var/data[0] + var/is_authenticated = is_authenticated(user) if(scan) data["scan_name"] = scan.name else data["scan_name"] = "-----" - data["authenticated"] = authenticated - if(!authenticated) + data["authenticated"] = is_authenticated + if(!is_authenticated) data["network"] = "Disconnected" else if(!emagged) data["network"] = fax_network @@ -94,12 +95,20 @@ var/list/alldepartments = list() return data +/obj/machinery/photocopier/faxmachine/proc/is_authenticated(mob/user) + if(authenticated) + return TRUE + else if(user.can_admin_interact()) + return TRUE + return FALSE + /obj/machinery/photocopier/faxmachine/Topic(href, href_list) if(..()) return 1 - + + var/is_authenticated = is_authenticated(usr) if(href_list["send"]) - if(copyitem && authenticated) + if(copyitem && is_authenticated) if((destination in admin_departments) || (destination in hidden_admin_departments)) send_admin_fax(usr, destination) else @@ -131,7 +140,7 @@ var/list/alldepartments = list() scan() if(href_list["dept"]) - if(authenticated) + if(is_authenticated) var/lastdestination = destination var/list/combineddepartments = alldepartments if(long_range_enabled) @@ -148,7 +157,7 @@ var/list/alldepartments = list() if((!authenticated) && scan) if(check_access(scan)) authenticated = 1 - else if(authenticated) + else if(!authenticated) authenticated = 0 if(href_list["rename"]) From 4e0989ee0bd613a010e56f1d61b34172bfce2c45 Mon Sep 17 00:00:00 2001 From: Markolie Date: Fri, 10 Feb 2017 21:51:08 +0100 Subject: [PATCH 015/164] Ghost interaction with atmos machinery --- .../components/binary_devices/passive_gate.dm | 29 ++++++++------ .../components/binary_devices/pump.dm | 27 +++++++------ .../components/binary_devices/valve.dm | 22 ++++++----- .../components/binary_devices/volume_pump.dm | 27 +++++++------ .../components/omni_devices/omni_base.dm | 11 ++++-- .../components/trinary_devices/filter.dm | 39 ++++++++++--------- .../components/trinary_devices/mixer.dm | 34 ++++++++++------ .../components/trinary_devices/tvalve.dm | 22 ++++++----- 8 files changed, 123 insertions(+), 88 deletions(-) diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm index 4f3c3d65635..c96a1b0b325 100644 --- a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm +++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm @@ -88,7 +88,7 @@ return 1 -/obj/machinery/atmospherics/binary/passive_gate/interact(mob/user as mob) +/obj/machinery/atmospherics/binary/passive_gate/interact(mob/user) var/dat = {"Power: [on?"On":"Off"]
Desirable output pressure: [round(target_pressure,0.1)]kPa | Change @@ -131,32 +131,37 @@ update_icon() return -/obj/machinery/atmospherics/binary/passive_gate/attack_hand(user as mob) +/obj/machinery/atmospherics/binary/passive_gate/attack_hand(mob/user) if(..()) return - src.add_fingerprint(usr) - if(!src.allowed(user)) + add_fingerprint(user) + if(!allowed(user)) to_chat(user, "Access denied.") return - usr.set_machine(src) + user.set_machine(src) + interact(user) + +/obj/machinery/atmospherics/binary/passive_gate/attack_ghost(mob/user) + add_fingerprint(user) + user.set_machine(src) interact(user) - return /obj/machinery/atmospherics/binary/passive_gate/Topic(href,href_list) - if(..()) return + if(..()) + return 1 if(href_list["power"]) on = !on investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos") if(href_list["set_press"]) - var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",src.target_pressure) as num - src.target_pressure = max(0, min(4500, new_pressure)) + var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",target_pressure) as num + target_pressure = max(0, min(4500, new_pressure)) investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos") usr.set_machine(src) - src.update_icon() - src.updateUsrDialog() + update_icon() + updateUsrDialog() return -/obj/machinery/atmospherics/binary/passive_gate/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob, params) +/obj/machinery/atmospherics/binary/passive_gate/attackby(var/obj/item/weapon/W, var/mob/user, params) if(!istype(W, /obj/item/weapon/wrench)) return ..() if(on) diff --git a/code/ATMOSPHERICS/components/binary_devices/pump.dm b/code/ATMOSPHERICS/components/binary_devices/pump.dm index 3b1ca109a81..40faf440cfd 100644 --- a/code/ATMOSPHERICS/components/binary_devices/pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/pump.dm @@ -103,7 +103,7 @@ Thus, the two variables affect pump operation are set in New(): radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) return 1 -/obj/machinery/atmospherics/binary/pump/interact(mob/user as mob) +/obj/machinery/atmospherics/binary/pump/interact(mob/user) var/dat = {"Power: [on?"On":"Off"]
Desirable output pressure: [round(target_pressure,0.1)]kPa | Change @@ -151,16 +151,20 @@ Thus, the two variables affect pump operation are set in New(): update_icon() return -/obj/machinery/atmospherics/binary/pump/attack_hand(user as mob) +/obj/machinery/atmospherics/binary/pump/attack_hand(mob/user) if(..()) return - src.add_fingerprint(usr) - if(!src.allowed(user)) + add_fingerprint(user) + if(!allowed(user)) to_chat(user, "Access denied.") return - usr.set_machine(src) + user.set_machine(src) + interact(user) + +/obj/machinery/atmospherics/binary/pump/attack_ghost(mob/user) + add_fingerprint(user) + user.set_machine(src) interact(user) - return /obj/machinery/atmospherics/binary/pump/Topic(href,href_list) if(..()) @@ -169,13 +173,12 @@ Thus, the two variables affect pump operation are set in New(): on = !on investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos") if(href_list["set_press"]) - var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",src.target_pressure) as num - src.target_pressure = max(0, min(4500, new_pressure)) + var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",target_pressure) as num + target_pressure = max(0, min(4500, new_pressure)) investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos") usr.set_machine(src) - src.update_icon() - src.updateUsrDialog() - return + update_icon() + updateUsrDialog() /obj/machinery/atmospherics/binary/pump/power_change() var/old_stat = stat @@ -183,7 +186,7 @@ Thus, the two variables affect pump operation are set in New(): if(old_stat != stat) update_icon() -/obj/machinery/atmospherics/binary/pump/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob, params) +/obj/machinery/atmospherics/binary/pump/attackby(var/obj/item/weapon/W, var/mob/user, params) if(!istype(W, /obj/item/weapon/wrench)) return ..() if(!(stat & NOPOWER) && on) diff --git a/code/ATMOSPHERICS/components/binary_devices/valve.dm b/code/ATMOSPHERICS/components/binary_devices/valve.dm index 1a2a4ea541f..2737b7abfbd 100644 --- a/code/ATMOSPHERICS/components/binary_devices/valve.dm +++ b/code/ATMOSPHERICS/components/binary_devices/valve.dm @@ -45,17 +45,21 @@ investigate_log("was closed by [usr ? key_name(usr) : "a remote signal"]", "atmos") return -/obj/machinery/atmospherics/binary/valve/attack_ai(mob/user as mob) +/obj/machinery/atmospherics/binary/valve/attack_ai(mob/user) return + +/obj/machinery/atmospherics/binary/valve/attack_ghost(mob/user) + if(user.can_advanced_admin_interact()) + return attack_hand(user) -/obj/machinery/atmospherics/binary/valve/attack_hand(mob/user as mob) +/obj/machinery/atmospherics/binary/valve/attack_hand(mob/user) add_fingerprint(usr) update_icon(1) sleep(10) if(open) close() - return - open() + else + open() /obj/machinery/atmospherics/binary/valve/digital // can be controlled by AI name = "digital valve" @@ -67,13 +71,13 @@ var/datum/radio_frequency/radio_connection settagwhitelist = list("id_tag") -/obj/machinery/atmospherics/binary/valve/digital/attack_ai(mob/user as mob) - return src.attack_hand(user) +/obj/machinery/atmospherics/binary/valve/digital/attack_ai(mob/user) + return attack_hand(user) -/obj/machinery/atmospherics/binary/valve/digital/attack_hand(mob/user as mob) +/obj/machinery/atmospherics/binary/valve/digital/attack_hand(mob/user) if(!powered()) return - if(!src.allowed(user)) + if(!allowed(user) && !user.can_advanced_admin_interact()) to_chat(user, "Access denied.") return ..() @@ -130,7 +134,7 @@ if(open) close() -/obj/machinery/atmospherics/binary/valve/digital/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) +/obj/machinery/atmospherics/binary/valve/digital/attackby(var/obj/item/weapon/W as obj, var/mob/user) if(istype(W, /obj/item/device/multitool)) update_multitool_menu(user) return 1 diff --git a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm index 80e1ad2e8b9..4f2cbb56117 100644 --- a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm @@ -99,7 +99,7 @@ Thus, the two variables affect pump operation are set in New(): return 1 -/obj/machinery/atmospherics/binary/volume_pump/interact(mob/user as mob) +/obj/machinery/atmospherics/binary/volume_pump/interact(mob/user) var/dat = {"Power: [on?"On":"Off"]
Desirable output flow: [round(transfer_rate,1)]l/s | Change @@ -142,16 +142,20 @@ Thus, the two variables affect pump operation are set in New(): broadcast_status() update_icon() -/obj/machinery/atmospherics/binary/volume_pump/attack_hand(user as mob) +/obj/machinery/atmospherics/binary/volume_pump/attack_hand(mob/user) if(..()) return - src.add_fingerprint(usr) - if(!src.allowed(user)) + add_fingerprint(user) + if(!allowed(user) && !user.can_admin_interact()) to_chat(user, "Access denied.") return - usr.set_machine(src) + user.set_machine(src) + interact(user) + +/obj/machinery/atmospherics/binary/volume_pump/attack_ghost(mob/user) + add_fingerprint(user) + user.set_machine(src) interact(user) - return /obj/machinery/atmospherics/binary/volume_pump/Topic(href,href_list) if(..()) @@ -160,13 +164,12 @@ Thus, the two variables affect pump operation are set in New(): on = !on investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos") if(href_list["set_transfer_rate"]) - var/new_transfer_rate = input(usr,"Enter new output volume (0-200l/s)","Flow control",src.transfer_rate) as num - src.transfer_rate = max(0, min(200, new_transfer_rate)) + var/new_transfer_rate = input(usr,"Enter new output volume (0-200l/s)","Flow control",transfer_rate) as num + transfer_rate = max(0, min(200, new_transfer_rate)) investigate_log("was set to [transfer_rate] L/s by [key_name(usr)]", "atmos") usr.set_machine(src) - src.update_icon() - src.updateUsrDialog() - return + update_icon() + updateUsrDialog() /obj/machinery/atmospherics/binary/volume_pump/power_change() var/old_stat = stat @@ -174,7 +177,7 @@ Thus, the two variables affect pump operation are set in New(): if(old_stat != stat) update_icon() -/obj/machinery/atmospherics/binary/volume_pump/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob, params) +/obj/machinery/atmospherics/binary/volume_pump/attackby(var/obj/item/weapon/W, var/mob/user, params) if(!istype(W, /obj/item/weapon/wrench)) return ..() if(!(stat & NOPOWER) && on) diff --git a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm index beae30e55db..cacc1e8b9a0 100644 --- a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm +++ b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm @@ -107,7 +107,7 @@ to_chat(user, "You cannot unwrench [src], it is too exerted due to internal pressure.") add_fingerprint(user) return 1 - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) to_chat(user, "You begin to unfasten \the [src]...") if(do_after(user, 40, target = src)) user.visible_message( \ @@ -119,14 +119,17 @@ else return ..() -/obj/machinery/atmospherics/omni/attack_hand(user as mob) +/obj/machinery/atmospherics/omni/attack_hand(mob/user) if(..()) return - src.add_fingerprint(usr) + add_fingerprint(usr) ui_interact(user) - return +/obj/machinery/atmospherics/omni/attack_ghost(mob/user) + add_fingerprint(usr) + ui_interact(user) + /obj/machinery/atmospherics/omni/proc/build_icons() if(!check_icon_cache()) return diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm index 021bec1cd24..732013765d2 100755 --- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm @@ -146,15 +146,25 @@ Filter types: /obj/machinery/atmospherics/trinary/filter/initialize() set_frequency(frequency) ..() + +/obj/machinery/atmospherics/trinary/filter/attack_ghost(mob/user) + add_fingerprint(user) + user.set_machine(src) + interact(user) -/obj/machinery/atmospherics/trinary/filter/attack_hand(user as mob) // -- TLE +/obj/machinery/atmospherics/trinary/filter/attack_hand(mob/user) if(..()) return - if(!src.allowed(user)) + add_fingerprint(user) + if(!allowed(user) && !user.can_admin_interact()) to_chat(user, "Access denied.") return - + + user.set_machine(src) + interact(user) + +/obj/machinery/atmospherics/trinary/filter/interact(mob/user) var/dat var/current_filter_type switch(filter_type) @@ -184,34 +194,27 @@ Filter types: Nitrous Oxide
Nothing

Desirable output pressure: - [src.target_pressure]kPa | Change + [target_pressure]kPa | Change "} var/datum/browser/popup = new(user, "atmo_filter", name, 400, 400) popup.set_content(dat) popup.open(0) onclose(user, "atmo_filter") - return /obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE if(..()) return 1 usr.set_machine(src) - src.add_fingerprint(usr) + add_fingerprint(usr) if(href_list["filterset"]) - src.filter_type = text2num(href_list["filterset"]) + filter_type = text2num(href_list["filterset"]) if(href_list["temp"]) - src.temp = null + temp = null if(href_list["set_press"]) - var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",src.target_pressure) as num - src.target_pressure = max(0, min(4500, new_pressure)) + var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",target_pressure) as num + target_pressure = max(0, min(4500, new_pressure)) if(href_list["power"]) on=!on - src.update_icon() - src.updateUsrDialog() -/* - for(var/mob/M in viewers(1, src)) - if((M.client && M.machine == src)) - src.attack_hand(M) -*/ - return + update_icon() + updateUsrDialog() \ No newline at end of file diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm index bef88fe6f3b..54ec88c63a7 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm @@ -107,14 +107,25 @@ parent3.update = 1 return 1 + +/obj/machinery/atmospherics/trinary/mixer/attack_ghost(mob/user) + add_fingerprint(user) + user.set_machine(src) + interact(user) -/obj/machinery/atmospherics/trinary/mixer/attack_hand(user as mob) +/obj/machinery/atmospherics/trinary/mixer/attack_hand(mob/user) if(..()) return - src.add_fingerprint(usr) - if(!src.allowed(user)) + + add_fingerprint(user) + if(!allowed(user) && !user.can_admin_interact()) to_chat(user, "Access denied.") return + + user.set_machine(src) + interact(user) + +/obj/machinery/atmospherics/trinary/mixer/interact(mob/user) usr.set_machine(src) var/dat = {"Power: [on?"On":"Off"]
Desirable output pressure: @@ -139,7 +150,6 @@ popup.set_content(dat) popup.open(0) onclose(user, "atmo_mixer") - return /obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list) if(..()) @@ -147,16 +157,16 @@ if(href_list["power"]) on = !on if(href_list["set_press"]) - var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",src.target_pressure) as num - src.target_pressure = max(0, min(4500, new_pressure)) + var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",target_pressure) as num + target_pressure = max(0, min(4500, new_pressure)) if(href_list["node1_c"]) var/value = text2num(href_list["node1_c"]) - src.node1_concentration = max(0, min(1, src.node1_concentration + value)) - src.node2_concentration = max(0, min(1, src.node2_concentration - value)) + node1_concentration = max(0, min(1, node1_concentration + value)) + node2_concentration = max(0, min(1, node2_concentration - value)) if(href_list["node2_c"]) var/value = text2num(href_list["node2_c"]) - src.node2_concentration = max(0, min(1, src.node2_concentration + value)) - src.node1_concentration = max(0, min(1, src.node1_concentration - value)) - src.update_icon() - src.updateUsrDialog() + node2_concentration = max(0, min(1, node2_concentration + value)) + node1_concentration = max(0, min(1, node1_concentration - value)) + update_icon() + updateUsrDialog() return diff --git a/code/ATMOSPHERICS/components/trinary_devices/tvalve.dm b/code/ATMOSPHERICS/components/trinary_devices/tvalve.dm index 2195bab16d8..ece9a5de27d 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/tvalve.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/tvalve.dm @@ -30,7 +30,7 @@ if(flipped) flipstate = "m" if(animation) - flick("tvalve[flipstate][src.state][!src.state]",src) + flick("tvalve[flipstate][state][!state]",src) else icon_state = "tvalve[flipstate][state]" @@ -52,9 +52,9 @@ /obj/machinery/atmospherics/trinary/tvalve/proc/switch_side() if(state == TVALVE_STATE_STRAIGHT) - src.go_to_side() + go_to_side() else - src.go_straight() + go_straight() /obj/machinery/atmospherics/trinary/tvalve/proc/go_to_side() if(state == TVALVE_STATE_SIDE) @@ -86,10 +86,14 @@ investigate_log("was set to straight by [usr ? key_name(usr) : "a remote signal"]", "atmos") return 1 -/obj/machinery/atmospherics/trinary/tvalve/attack_ai(mob/user as mob) +/obj/machinery/atmospherics/trinary/tvalve/attack_ai(mob/user) return + +/obj/machinery/atmospherics/trinary/tvalve/attack_ghost(mob/user) + if(user.can_advanced_admin_interact()) + return attack_hand(user) -/obj/machinery/atmospherics/trinary/tvalve/attack_hand(mob/user as mob) +/obj/machinery/atmospherics/trinary/tvalve/attack_hand(mob/usermob) add_fingerprint(usr) update_icon(1) sleep(10) @@ -128,13 +132,13 @@ if(!powered()) icon_state = "tvalvenopower" -/obj/machinery/atmospherics/trinary/tvalve/digital/attack_ai(mob/user as mob) - return src.attack_hand(user) +/obj/machinery/atmospherics/trinary/tvalve/digital/attack_ai(mob/user) + return attack_hand(user) -/obj/machinery/atmospherics/trinary/tvalve/digital/attack_hand(mob/user as mob) +/obj/machinery/atmospherics/trinary/tvalve/digital/attack_hand(mob/user) if(!powered()) return - if(!src.allowed(user)) + if(!allowed(user) && !user.can_admin_interact()) to_chat(user, "Access denied.") return ..() From 53e156388e77873425fc1cd57f88eb5eecb43dea Mon Sep 17 00:00:00 2001 From: Markolie Date: Fri, 10 Feb 2017 21:54:51 +0100 Subject: [PATCH 016/164] Cleanup interaction --- code/ATMOSPHERICS/components/binary_devices/volume_pump.dm | 2 +- code/ATMOSPHERICS/components/trinary_devices/filter.dm | 2 +- code/ATMOSPHERICS/components/trinary_devices/mixer.dm | 2 +- code/ATMOSPHERICS/components/trinary_devices/tvalve.dm | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm index 4f2cbb56117..12982820b84 100644 --- a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm @@ -146,7 +146,7 @@ Thus, the two variables affect pump operation are set in New(): if(..()) return add_fingerprint(user) - if(!allowed(user) && !user.can_admin_interact()) + if(!allowed(user)) to_chat(user, "Access denied.") return user.set_machine(src) diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm index 732013765d2..c916848797e 100755 --- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm @@ -157,7 +157,7 @@ Filter types: return add_fingerprint(user) - if(!allowed(user) && !user.can_admin_interact()) + if(!allowed(user)) to_chat(user, "Access denied.") return diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm index 54ec88c63a7..d1b304f072a 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm @@ -118,7 +118,7 @@ return add_fingerprint(user) - if(!allowed(user) && !user.can_admin_interact()) + if(!allowed(user)) to_chat(user, "Access denied.") return diff --git a/code/ATMOSPHERICS/components/trinary_devices/tvalve.dm b/code/ATMOSPHERICS/components/trinary_devices/tvalve.dm index ece9a5de27d..0987561f94c 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/tvalve.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/tvalve.dm @@ -138,7 +138,7 @@ /obj/machinery/atmospherics/trinary/tvalve/digital/attack_hand(mob/user) if(!powered()) return - if(!allowed(user) && !user.can_admin_interact()) + if(!allowed(user) && !user.can_advanced_admin_interact()) to_chat(user, "Access denied.") return ..() From 23d4d7cc593a322c5d6db488f49fdc5f9780556e Mon Sep 17 00:00:00 2001 From: Markolie Date: Fri, 10 Feb 2017 22:06:57 +0100 Subject: [PATCH 017/164] Interaction with pipe dispensers --- code/game/machinery/pipe/pipe_dispenser.dm | 157 ++++++++++----------- 1 file changed, 75 insertions(+), 82 deletions(-) diff --git a/code/game/machinery/pipe/pipe_dispenser.dm b/code/game/machinery/pipe/pipe_dispenser.dm index 34f41e2a1b5..d7ac49381b9 100644 --- a/code/game/machinery/pipe/pipe_dispenser.dm +++ b/code/game/machinery/pipe/pipe_dispenser.dm @@ -7,9 +7,16 @@ var/unwrenched = 0 var/wait = 0 -/obj/machinery/pipedispenser/attack_hand(user as mob) +/obj/machinery/pipedispenser/attack_hand(mob/user) if(..()) - return + return 1 + + interact(user) + +/obj/machinery/pipedispenser/attack_ghost(mob/user) + interact(user) + +/obj/machinery/pipedispenser/interact(mob/user) var/dat = {" Regular pipes:
Pipe
@@ -65,21 +72,19 @@ popup.set_content(dat) popup.open(0) onclose(user, "pipedispenser") - return /obj/machinery/pipedispenser/Topic(href, href_list) - if(..()) - return - if(unwrenched || !usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr << browse(null, "window=pipedispenser") - return + if(..() || unwrenched) + return 1 + usr.set_machine(src) - src.add_fingerprint(usr) + add_fingerprint(usr) + if(href_list["make"]) if(!wait) var/p_type = text2num(href_list["make"]) var/p_dir = text2num(href_list["dir"]) - var/obj/item/pipe/P = new (/*usr.loc*/ src.loc, pipe_type=p_type, dir=p_dir) + var/obj/item/pipe/P = new (loc, pipe_type=p_type, dir=p_dir) P.update() P.add_fingerprint(usr) wait = 1 @@ -87,50 +92,49 @@ wait = 0 if(href_list["makemeter"]) if(!wait) - new /obj/item/pipe_meter(/*usr.loc*/ src.loc) + new /obj/item/pipe_meter(loc) wait = 1 spawn(15) wait = 0 if(href_list["makegsensor"]) if(!wait) - new /obj/item/pipe_gsensor(/*usr.loc*/ src.loc) + new /obj/item/pipe_gsensor(loc) wait = 1 spawn(15) wait = 0 - return /obj/machinery/pipedispenser/attackby(var/obj/item/W as obj, var/mob/user as mob, params) - src.add_fingerprint(usr) + add_fingerprint(usr) if(istype(W, /obj/item/pipe) || istype(W, /obj/item/pipe_meter) || istype(W, /obj/item/pipe_gsensor)) - to_chat(usr, "\blue You put [W] back to [src].") + to_chat(usr, "You put [W] back to [src].") user.drop_item() qdel(W) return else if(istype(W, /obj/item/weapon/wrench)) if(unwrenched==0) - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - to_chat(user, "\blue You begin to unfasten \the [src] from the floor...") + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to unfasten \the [src] from the floor...") if(do_after(user, 40, target = src)) user.visible_message( \ "[user] unfastens \the [src].", \ - "\blue You have unfastened \the [src]. Now it can be pulled somewhere else.", \ + "You have unfastened \the [src]. Now it can be pulled somewhere else.", \ "You hear ratchet.") - src.anchored = 0 - src.stat |= MAINT - src.unwrenched = 1 + anchored = 0 + stat |= MAINT + unwrenched = 1 if(usr.machine==src) usr << browse(null, "window=pipedispenser") else /*if(unwrenched==1)*/ - playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) - to_chat(user, "\blue You begin to fasten \the [src] to the floor...") + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) + to_chat(user, "You begin to fasten \the [src] to the floor...") if(do_after(user, 20, target = src)) user.visible_message( \ "[user] fastens \the [src].", \ - "\blue You have fastened \the [src]. Now it can dispense pipes.", \ + "You have fastened \the [src]. Now it can dispense pipes.", \ "You hear ratchet.") - src.anchored = 1 - src.stat &= ~MAINT - src.unwrenched = 0 + anchored = 1 + stat &= ~MAINT + unwrenched = 0 power_change() else return ..() @@ -143,21 +147,12 @@ density = 1 anchored = 1.0 -/* -//Allow you to push disposal pipes into it (for those with density 1) -/obj/machinery/pipedispenser/disposal/Crossed(var/obj/structure/disposalconstruct/pipe as obj) - if(istype(pipe) && !pipe.anchored) - qdel(pipe) - -Nah -*/ - //Allow you to drag-drop disposal pipes into it -/obj/machinery/pipedispenser/disposal/MouseDrop_T(var/obj/structure/disposalconstruct/pipe as obj, mob/usr as mob) - if(!usr.canmove || usr.stat || usr.restrained()) +/obj/machinery/pipedispenser/disposal/MouseDrop_T(var/obj/structure/disposalconstruct/pipe, mob/usr) + if(usr.incapacitated()) return - if(!istype(pipe) || get_dist(usr, src) > 1 || get_dist(src,pipe) > 1 ) + if(!istype(pipe) || get_dist(usr, src) > 1 || get_dist(src, pipe) > 1 ) return if(pipe.anchored) @@ -165,10 +160,16 @@ Nah qdel(pipe) -/obj/machinery/pipedispenser/disposal/attack_hand(user as mob) +/obj/machinery/pipedispenser/disposal/attack_hand(mob/user) if(..()) return - + + interact(user) + +/obj/machinery/pipedispenser/disposal/attack_ghost(mob/user) + interact(user) + +/obj/machinery/pipedispenser/disposal/interact(mob/user) var/dat = {"Disposal Pipes

Pipe
Bent Pipe
@@ -183,47 +184,39 @@ Nah var/datum/browser/popup = new(user, "pipedispenser", name, 400, 400) popup.set_content(dat) popup.open() - return - -// 0=straight, 1=bent, 2=junction-j1, 3=junction-j2, 4=junction-y, 5=trunk - /obj/machinery/pipedispenser/disposal/Topic(href, href_list) - if(..()) - return - usr.set_machine(src) - src.add_fingerprint(usr) - if(href_list["dmake"]) - if(unwrenched || !usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) - usr << browse(null, "window=pipedispenser") - return - if(!wait) - var/p_type = text2num(href_list["dmake"]) - var/obj/structure/disposalconstruct/C = new (src.loc) - switch(p_type) - if(0) - C.ptype = 0 - if(1) - C.ptype = 1 - if(2) - C.ptype = 2 - if(3) - C.ptype = 4 - if(4) - C.ptype = 5 - if(5) - C.ptype = 6 - C.density = 1 - if(6) - C.ptype = 7 - C.density = 1 - if(7) - C.ptype = 8 - C.density = 1 - C.add_fingerprint(usr) - C.update() - wait = 1 - spawn(15) - wait = 0 - return + if(..() || unwrenched) + return 1 + usr.set_machine(src) + add_fingerprint(usr) + + if(!wait) + var/p_type = text2num(href_list["dmake"]) + var/obj/structure/disposalconstruct/C = new (loc) + switch(p_type) + if(0) + C.ptype = 0 + if(1) + C.ptype = 1 + if(2) + C.ptype = 2 + if(3) + C.ptype = 4 + if(4) + C.ptype = 5 + if(5) + C.ptype = 6 + C.density = 1 + if(6) + C.ptype = 7 + C.density = 1 + if(7) + C.ptype = 8 + C.density = 1 + C.add_fingerprint(usr) + C.update() + wait = 1 + spawn(15) + wait = 0 \ No newline at end of file From e6ce0924b8eeefb802e6162d59f2b8d4ad5f735e Mon Sep 17 00:00:00 2001 From: Markolie Date: Fri, 10 Feb 2017 23:37:03 +0100 Subject: [PATCH 018/164] Fingerprint/set_machine consistency --- .../components/binary_devices/passive_gate.dm | 9 +++++---- code/ATMOSPHERICS/components/binary_devices/pump.dm | 9 +++++---- .../components/binary_devices/volume_pump.dm | 9 +++++---- code/ATMOSPHERICS/components/omni_devices/omni_base.dm | 1 - code/ATMOSPHERICS/components/trinary_devices/filter.dm | 9 ++++----- code/ATMOSPHERICS/components/trinary_devices/mixer.dm | 7 ++----- code/modules/hydroponics/biogenerator.dm | 1 + code/modules/hydroponics/gene_modder.dm | 1 + code/modules/hydroponics/seed_extractor.dm | 1 + 9 files changed, 24 insertions(+), 23 deletions(-) diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm index c96a1b0b325..993ba4d802f 100644 --- a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm +++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm @@ -89,6 +89,9 @@ return 1 /obj/machinery/atmospherics/binary/passive_gate/interact(mob/user) + user.set_machine(src) + add_fingerprint(user) + var/dat = {"Power: [on?"On":"Off"]
Desirable output pressure: [round(target_pressure,0.1)]kPa | Change @@ -134,16 +137,14 @@ /obj/machinery/atmospherics/binary/passive_gate/attack_hand(mob/user) if(..()) return - add_fingerprint(user) + if(!allowed(user)) to_chat(user, "Access denied.") return - user.set_machine(src) + interact(user) /obj/machinery/atmospherics/binary/passive_gate/attack_ghost(mob/user) - add_fingerprint(user) - user.set_machine(src) interact(user) /obj/machinery/atmospherics/binary/passive_gate/Topic(href,href_list) diff --git a/code/ATMOSPHERICS/components/binary_devices/pump.dm b/code/ATMOSPHERICS/components/binary_devices/pump.dm index 40faf440cfd..824d3b1c5f0 100644 --- a/code/ATMOSPHERICS/components/binary_devices/pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/pump.dm @@ -104,6 +104,9 @@ Thus, the two variables affect pump operation are set in New(): return 1 /obj/machinery/atmospherics/binary/pump/interact(mob/user) + user.set_machine(src) + add_fingerprint(user) + var/dat = {"Power: [on?"On":"Off"]
Desirable output pressure: [round(target_pressure,0.1)]kPa | Change @@ -154,16 +157,14 @@ Thus, the two variables affect pump operation are set in New(): /obj/machinery/atmospherics/binary/pump/attack_hand(mob/user) if(..()) return - add_fingerprint(user) + if(!allowed(user)) to_chat(user, "Access denied.") return - user.set_machine(src) + interact(user) /obj/machinery/atmospherics/binary/pump/attack_ghost(mob/user) - add_fingerprint(user) - user.set_machine(src) interact(user) /obj/machinery/atmospherics/binary/pump/Topic(href,href_list) diff --git a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm index 12982820b84..99465e15d88 100644 --- a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm @@ -100,6 +100,9 @@ Thus, the two variables affect pump operation are set in New(): return 1 /obj/machinery/atmospherics/binary/volume_pump/interact(mob/user) + user.set_machine(src) + add_fingerprint(user) + var/dat = {"Power: [on?"On":"Off"]
Desirable output flow: [round(transfer_rate,1)]l/s | Change @@ -145,16 +148,14 @@ Thus, the two variables affect pump operation are set in New(): /obj/machinery/atmospherics/binary/volume_pump/attack_hand(mob/user) if(..()) return - add_fingerprint(user) + if(!allowed(user)) to_chat(user, "Access denied.") return - user.set_machine(src) + interact(user) /obj/machinery/atmospherics/binary/volume_pump/attack_ghost(mob/user) - add_fingerprint(user) - user.set_machine(src) interact(user) /obj/machinery/atmospherics/binary/volume_pump/Topic(href,href_list) diff --git a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm index cacc1e8b9a0..2eca090d086 100644 --- a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm +++ b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm @@ -127,7 +127,6 @@ ui_interact(user) /obj/machinery/atmospherics/omni/attack_ghost(mob/user) - add_fingerprint(usr) ui_interact(user) /obj/machinery/atmospherics/omni/proc/build_icons() diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm index c916848797e..b8ecae86b85 100755 --- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm @@ -148,23 +148,22 @@ Filter types: ..() /obj/machinery/atmospherics/trinary/filter/attack_ghost(mob/user) - add_fingerprint(user) - user.set_machine(src) interact(user) /obj/machinery/atmospherics/trinary/filter/attack_hand(mob/user) if(..()) return - add_fingerprint(user) if(!allowed(user)) to_chat(user, "Access denied.") return - user.set_machine(src) interact(user) -/obj/machinery/atmospherics/trinary/filter/interact(mob/user) +/obj/machinery/atmospherics/trinary/filter/interact(mob/user) + user.set_machine(src) + add_fingerprint(user) + var/dat var/current_filter_type switch(filter_type) diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm index d1b304f072a..f859175cdb2 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm @@ -109,24 +109,21 @@ return 1 /obj/machinery/atmospherics/trinary/mixer/attack_ghost(mob/user) - add_fingerprint(user) - user.set_machine(src) interact(user) /obj/machinery/atmospherics/trinary/mixer/attack_hand(mob/user) if(..()) return - add_fingerprint(user) if(!allowed(user)) to_chat(user, "Access denied.") return - user.set_machine(src) interact(user) /obj/machinery/atmospherics/trinary/mixer/interact(mob/user) - usr.set_machine(src) + user.set_machine(src) + add_fingerprint(user) var/dat = {"Power: [on?"On":"Off"]
Desirable output pressure: [target_pressure]kPa | Change diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm index 4a5190bac39..ce393c16e15 100644 --- a/code/modules/hydroponics/biogenerator.dm +++ b/code/modules/hydroponics/biogenerator.dm @@ -156,6 +156,7 @@ if(stat & BROKEN || panel_open) return user.set_machine(src) + add_fingerprint(user) var/dat if(processing) dat += "
Biogenerator is processing! Please wait...

" diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm index 70eec9ae078..95e195caaf7 100644 --- a/code/modules/hydroponics/gene_modder.dm +++ b/code/modules/hydroponics/gene_modder.dm @@ -95,6 +95,7 @@ interact(user) /obj/machinery/plantgenes/interact(mob/user) + add_fingerprint(user) user.set_machine(src) if(!user) return diff --git a/code/modules/hydroponics/seed_extractor.dm b/code/modules/hydroponics/seed_extractor.dm index 631e2ff7321..379a15a296a 100644 --- a/code/modules/hydroponics/seed_extractor.dm +++ b/code/modules/hydroponics/seed_extractor.dm @@ -133,6 +133,7 @@ if(stat) return 0 + add_fingerprint(user) user.set_machine(src) var/dat = "Stored seeds:
" From a602c1d8da1cddc4be61d9127540f27bb74853e0 Mon Sep 17 00:00:00 2001 From: Kyep Date: Sat, 11 Feb 2017 21:15:44 -0800 Subject: [PATCH 019/164] Adds 'take ahelp' option on ahelp Adds a 'take' option to ahelps and mentorhelps. Can be used by admins/mentors to quickly let the asker know their ahelp/mhelp is being dealt with. Other admins/mentors can see it too, so it should reduce the dogpiling effect where every online admin/mentor answers at once. Based on: https://github.com/Baystation12/Baystation12/pull/15902/files --- code/modules/admin/topic.dm | 17 +++++++++++++++++ code/modules/admin/verbs/adminhelp.dm | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 4a01b1161e8..a404fbe525e 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1533,6 +1533,23 @@ else if(href_list["check_antagonist"]) check_antagonists() + else if(href_list["take_question"]) + var/mob/M = locateUID(href_list["take_question"]) + var/is_mhelp = href_list["is_mhelp"] + if(ismob(M)) + var/helptype = "ADMINHELP" + if(is_mhelp) + helptype = "MENTORHELP" + var/take_msg = "[helptype]: [key_name(usr.client)] is attending to [key_name(M)]'s question." + for(var/client/X in admins) + if(check_rights(R_ADMIN, 0, X.mob)) + to_chat(X, take_msg) + else if(is_mhelp && check_rights(R_MOD|R_MENTOR, 0, X.mob)) + to_chat(X, take_msg) + to_chat(M, "Your question is being attended to by [key_name(usr.client)]. Thanks for your patience!") + else + to_chat(usr, "Unable to locate mob.") + else if(href_list["cult_nextobj"]) if(alert(usr, "Validate the current Cult objective and unlock the next one?", "Cult Cheat Code", "Yes", "No") != "Yes") return diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 73b481bbc6b..972406bbdb3 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -109,13 +109,13 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey"," switch(selected_type) if("Mentorhelp") - msg = "[selected_type]: [key_name(src, 1, 1, selected_type)] (?) (PP) (VV) (SM) ([admin_jump_link(mob)]) (CA) (REJT) [ai_found ? " (CL)" : ""]: [msg]" + msg = "[selected_type]: [key_name(src, 1, 1, selected_type)] (?) (PP) (VV) (SM) ([admin_jump_link(mob)]) (CA) (REJT) [ai_found ? " (CL)" : ""] (PP) (TAKE) : [msg]" for(var/client/X in mentorholders + modholders + adminholders) if(X.prefs.sound & SOUND_ADMINHELP) X << 'sound/effects/adminhelp.ogg' to_chat(X, msg) if("Adminhelp") - msg = "[selected_type]: [key_name(src, 1, 1, selected_type)] (?) (PP) (VV) (SM) ([admin_jump_link(mob)]) (CA) (REJT) [ai_found ? " (CL)" : ""]: [msg]" + msg = "[selected_type]: [key_name(src, 1, 1, selected_type)] (?) (PP) (VV) (SM) ([admin_jump_link(mob)]) (CA) (REJT) [ai_found ? " (CL)" : ""] (PP) (TAKE) : [msg]" for(var/client/X in modholders + adminholders) if(X.prefs.sound & SOUND_ADMINHELP) X << 'sound/effects/adminhelp.ogg' From 525ecaef8e5004d93962214aea075e0520524a2a Mon Sep 17 00:00:00 2001 From: FalseIncarnate Date: Sun, 12 Feb 2017 23:07:07 -0500 Subject: [PATCH 020/164] Deepfryer fixes --- code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm index d9b98c82724..7aa24bdf264 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm @@ -76,7 +76,7 @@ output = /obj/item/weapon/reagent_containers/food/snacks/fried_shrimp /datum/deepfryer_special/banana - input = "banana" + input = /obj/item/weapon/reagent_containers/food/snacks/grown/banana output = /obj/item/weapon/reagent_containers/food/snacks/friedbanana /datum/deepfryer_special/potato_chips @@ -84,7 +84,7 @@ output = /obj/item/weapon/reagent_containers/food/snacks/chips /datum/deepfryer_special/corn_chips - input = "corn" + input = /obj/item/weapon/reagent_containers/food/snacks/grown/corn output = /obj/item/weapon/reagent_containers/food/snacks/cornchips /datum/deepfryer_special/fried_tofu From 030dba205d9b493a26f6acf6750eda41b992146b Mon Sep 17 00:00:00 2001 From: FalseIncarnate Date: Sun, 12 Feb 2017 23:22:02 -0500 Subject: [PATCH 021/164] Slows Plant Aging Now with a define instead of a magic number for easy tweaking. --- code/modules/hydroponics/hydroponics.dm | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 5eae76ea446..81bbcf16110 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -1,3 +1,5 @@ +#define HYDRO_CYCLES_PER_AGE 3 //Adjust this to adjust how many hydroponics cycles it takes to increase age. Positive integers only. + /obj/machinery/hydroponics name = "hydroponics tray" icon = 'icons/obj/hydroponics/equipment.dmi' @@ -20,6 +22,7 @@ var/lastproduce = 0 //Last time it was harvested var/lastcycle = 0 //Used for timing of cycles. var/cycledelay = 200 //About 10 seconds / cycle + var/current_cycle = 0 //Used for tracking when to age var/harvest = 0 //Ready to harvest? var/obj/item/seeds/myseed = null //The currently planted seed var/rating = 1 @@ -136,7 +139,10 @@ lastcycle = world.time if(myseed && !dead) // Advance age - age++ + current_cycle++ + if(current_cycle == HYDRO_CYCLES_PER_AGE) + age++ + current_cycle = 0 if(age < myseed.maturation) lastproduce = age @@ -1013,4 +1019,6 @@ to_chat(user, "You clear up [src]!") qdel(src) else - ..() \ No newline at end of file + ..() + +#undefine HYDRO_CYCLES_PER_AGE \ No newline at end of file From b0f46a28a145486951299a5ea8ebc5fb32ff1a07 Mon Sep 17 00:00:00 2001 From: FalseIncarnate Date: Sun, 12 Feb 2017 23:32:49 -0500 Subject: [PATCH 022/164] Re-Adds Hydro Tray Covers Also fixed a derp with the define --- code/modules/hydroponics/hydroponics.dm | 25 ++++++++++++++++-- .../mob/living/simple_animal/hostile/bees.dm | 8 +++--- icons/obj/hydroponics/equipment.dmi | Bin 24802 -> 26301 bytes 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 81bbcf16110..8d08286fa8e 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -1,4 +1,4 @@ -#define HYDRO_CYCLES_PER_AGE 3 //Adjust this to adjust how many hydroponics cycles it takes to increase age. Positive integers only. +#define HYDRO_CYCLES_PER_AGE 3 //Adjust this to adjust how many hydroponics cycles it takes to increase age. Positive integers only. /obj/machinery/hydroponics name = "hydroponics tray" @@ -27,6 +27,7 @@ var/obj/item/seeds/myseed = null //The currently planted seed var/rating = 1 var/wrenchable = 1 + var/lid_state = 0 var/recent_bee_visit = FALSE //Have we been visited by a bee recently, so bees dont overpollinate one plant var/using_irrigation = FALSE //If the tray is connected to other trays via irrigation hoses var/self_sustaining = FALSE //If the tray generates nutrients and water on its own @@ -111,6 +112,20 @@ return connected +/obj/machinery/hydroponics/AltClick() + if(wrenchable && !usr.stat && !usr.lying && Adjacent(usr)) + toggle_lid(usr) + return + return ..() + +/obj/machinery/hydroponics/proc/toggle_lid(mob/living/user) + if(!user || user.stat || user.restrained()) + return + + lid_state = !lid_state + to_chat(user, "You [lid_state ? "close" : "open"] the tray's lid.") + update_icon() + /obj/machinery/hydroponics/bullet_act(obj/item/projectile/Proj) //Works with the Somatoray to modify plant variables. if(!myseed) @@ -273,6 +288,9 @@ overlays += image('icons/obj/hydroponics/equipment.dmi', icon_state = "gaia_blessing") set_light(3) + if(lid_state) + overlays += image('icons/obj/hydroponics/equipment.dmi', icon_state = "hydrocover") + update_icon_hoses() if(myseed) @@ -910,6 +928,9 @@ /obj/machinery/hydroponics/attack_hand(mob/user) if(issilicon(user)) //How does AI know what plant is? return + if(lid_state) + to_chat(user, "You can't reach the plant through the cover.") + return if(harvest) myseed.harvest(user) else if(dead) @@ -1021,4 +1042,4 @@ else ..() -#undefine HYDRO_CYCLES_PER_AGE \ No newline at end of file +#undef HYDRO_CYCLES_PER_AGE \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm index 538ce8450c7..76577327b61 100644 --- a/code/modules/mob/living/simple_animal/hostile/bees.dm +++ b/code/modules/mob/living/simple_animal/hostile/bees.dm @@ -161,8 +161,8 @@ /mob/living/simple_animal/hostile/poison/bees/worker/Found(atom/A) if(istype(A, /obj/machinery/hydroponics)) var/obj/machinery/hydroponics/Hydro = A - if(Hydro.myseed && !Hydro.dead && !Hydro.recent_bee_visit) - wanted_objects |= /obj/machinery/hydroponics //so we only hunt them while they're alive/seeded/not visisted + if(Hydro.myseed && !Hydro.dead && !Hydro.recent_bee_visit && !Hydro.lid_state) + wanted_objects |= /obj/machinery/hydroponics //so we only hunt them while they're alive/seeded/not visisted and uncovered return 1 ..() @@ -188,12 +188,12 @@ ..() /mob/living/simple_animal/hostile/poison/bees/worker/proc/pollinate(obj/machinery/hydroponics/Hydro) - if(!istype(Hydro) || !Hydro.myseed || Hydro.dead || Hydro.recent_bee_visit) + if(!istype(Hydro) || !Hydro.myseed || Hydro.dead || Hydro.recent_bee_visit || Hydro.lid_state) target = null return target = null //so we pick a new hydro tray next FindTarget(), instead of loving the same plant for eternity - wanted_objects -= /obj/machinery/hydroponics //so we only hunt them while they're alive/seeded/not visisted + wanted_objects -= /obj/machinery/hydroponics //so we only hunt them while they're alive/seeded/not visisted and uncovered Hydro.recent_bee_visit = TRUE spawn(BEE_TRAY_RECENT_VISIT) if(Hydro) diff --git a/icons/obj/hydroponics/equipment.dmi b/icons/obj/hydroponics/equipment.dmi index 189d168219470310ad8cd46ad3e35d63f2743902..3b1c4c07cfad5d944083cc203a05243d302e7024 100644 GIT binary patch delta 6138 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 Date: Mon, 13 Feb 2017 01:16:13 -0800 Subject: [PATCH 023/164] Lets mentors see playtime Mentors can already see a list of all players by account age. This includes antags with obvious names, like "Donk Co. Operative #1". This PR changes the permissions on the playtime report (the one which shows how much playtime everyone has) so mentors can see that, too. The idea being that this enables mentors to distinguish between "X has an old account" and "X has a lot of experience on paradise". Currently, mentors cannot distinguish the two. Also, consistency. If mentors can see players' account registration age, they should also be able to see players' playtime experience. --- code/game/jobs/job_exp.dm | 2 +- code/modules/admin/admin_verbs.dm | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/jobs/job_exp.dm b/code/game/jobs/job_exp.dm index 746dfcacf44..ba87db2946e 100644 --- a/code/game/jobs/job_exp.dm +++ b/code/game/jobs/job_exp.dm @@ -1,6 +1,6 @@ // Admin Verbs -/client/proc/cmd_admin_check_player_exp() //Allows admins to determine who the newer players are. +/client/proc/cmd_mentor_check_player_exp() //Allows admins to determine who the newer players are. set category = "Admin" set name = "Check Player Playtime" if(!check_rights(R_ADMIN)) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 6b2224962f5..7f38ec55bc8 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -2,7 +2,8 @@ var/list/admin_verbs_default = list( /client/proc/deadmin_self, /*destroys our own admin datum so we can play as a regular player*/ /client/proc/hide_verbs, /*hides all our adminverbs*/ - /client/proc/cmd_mentor_check_new_players + /client/proc/cmd_mentor_check_new_players, + /client/proc/cmd_mentor_check_player_exp /* shows players by playtime */ ) var/list/admin_verbs_admin = list( /client/proc/check_antagonists, /*shows all antags*/ @@ -75,7 +76,6 @@ var/list/admin_verbs_admin = list( /client/proc/debug_variables, /client/proc/show_snpc_verbs, /client/proc/reset_all_tcs, /*resets all telecomms scripts*/ - /client/proc/cmd_admin_check_player_exp, /* shows players by playtime */ /client/proc/toggle_mentor_chat ) var/list/admin_verbs_ban = list( @@ -166,7 +166,7 @@ var/list/admin_verbs_debug = list( /client/proc/admin_serialize, /client/proc/admin_deserialize, /client/proc/jump_to_ruin, - /client/proc/toggle_medal_disable + /client/proc/toggle_medal_disable ) var/list/admin_verbs_possess = list( /proc/possess, From 622f36575efbc7c2282ef30d5de69b98c1ed69ba Mon Sep 17 00:00:00 2001 From: FalseIncarnate Date: Mon, 13 Feb 2017 23:33:28 -0500 Subject: [PATCH 024/164] A little faster 3x -> 2x --- code/modules/hydroponics/hydroponics.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 8d08286fa8e..8cbca85a521 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -1,4 +1,4 @@ -#define HYDRO_CYCLES_PER_AGE 3 //Adjust this to adjust how many hydroponics cycles it takes to increase age. Positive integers only. +#define HYDRO_CYCLES_PER_AGE 2 //Adjust this to adjust how many hydroponics cycles it takes to increase age. Positive integers only. /obj/machinery/hydroponics name = "hydroponics tray" From b7855481f6de58dac3263f9a5abc9bddb51e48c6 Mon Sep 17 00:00:00 2001 From: Kyep Date: Mon, 13 Feb 2017 23:12:57 -0800 Subject: [PATCH 025/164] Fixes & Improvements - Makes new players be listed first in the Check Playtime list, so they are easy to find. - Fixes a bug with mentor playtime list not actually working for mentors. - Fixes the Check Player Age panel not having working "FLW" links, and potentially showing antag status to mentors. --- code/defines/procs/admin.dm | 6 +++++ code/game/jobs/job_exp.dm | 30 ++++++++++++++++++++----- code/modules/admin/topic.dm | 2 +- code/modules/admin/verbs/randomverbs.dm | 5 ++++- 4 files changed, 35 insertions(+), 8 deletions(-) diff --git a/code/defines/procs/admin.dm b/code/defines/procs/admin.dm index fb9bc232e12..2bc6b59e1d0 100644 --- a/code/defines/procs/admin.dm +++ b/code/defines/procs/admin.dm @@ -48,6 +48,12 @@ var/message = "[key_name(whom, 1, include_name)](?)[isAntag(whom) ? "(A)" : ""][isLivingSSD(whom) ? "(SSD!)" : ""] ([admin_jump_link(whom)])" return message +/proc/key_name_mentor(var/whom, var/include_name = 1) + // Same as key_name_admin, but does not include (?) or (A) for antags. + var/message = "[key_name(whom, 1, include_name)] [isLivingSSD(whom) ? "(SSD!)" : ""] ([admin_jump_link(whom)])" + return message + + /proc/log_and_message_admins(var/message as text) log_admin("[key_name(usr)] " + message) message_admins("[key_name_admin(usr)] " + message) diff --git a/code/game/jobs/job_exp.dm b/code/game/jobs/job_exp.dm index ba87db2946e..fc84a39bef7 100644 --- a/code/game/jobs/job_exp.dm +++ b/code/game/jobs/job_exp.dm @@ -3,20 +3,38 @@ /client/proc/cmd_mentor_check_player_exp() //Allows admins to determine who the newer players are. set category = "Admin" set name = "Check Player Playtime" - if(!check_rights(R_ADMIN)) + if(!check_rights(R_ADMIN|R_MOD|R_MENTOR)) return - var/msg = "Playtime ReportPlaytime:
    " + var/msg = "Playtime Report" + var/list/players_new = list() + var/list/players_old = list() + var/pline for(var/client/C in clients) - msg += "
  • [key_name_admin(C.mob)]: " + C.get_exp_living() + "
  • " - msg += "
" + if(check_rights(R_ADMIN)) + pline = "
  • [key_name_admin(C.mob)]: " + C.get_exp_living() + "
  • " + else + pline = "
  • [key_name_mentor(C.mob)]: " + C.get_exp_living() + "
  • " + if(C.get_exp_living_num() > 1200) + players_old += pline + else + players_new += pline + if(players_new.len) + msg += "
    Players under 20h:
      " + msg += players_new.Join() + msg += "
    " + if(players_old.len) + msg += "
    Players over 20h:
      " + msg += players_old.Join() + msg += "
    " + msg += "" src << browse(msg, "window=Player_playtime_check") -/datum/admins/proc/cmd_show_exp_panel(var/client/C) +/datum/admins/proc/cmd_mentor_show_exp_panel(var/client/C) if(!C) to_chat(usr, "ERROR: Client not found.") return - if(!check_rights(R_ADMIN)) + if(!check_rights(R_ADMIN|R_MOD|R_MENTOR)) return var/body = "Playtime for [C.key]
    Playtime:" body += C.get_exp_report() diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 4a01b1161e8..fe182889c87 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -2031,7 +2031,7 @@ if(!M) to_chat(usr, "ERROR: Mob not found.") return - cmd_show_exp_panel(M.client) + cmd_mentor_show_exp_panel(M.client) else if(href_list["jumpto"]) if(!check_rights(R_ADMIN)) return diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 79ee34fb635..4b484d58e80 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -88,7 +88,10 @@ missing_ages = 1 continue if(C.player_age < age) - msg += "[key_name_admin(C)]: account is [C.player_age] days old
    " + if(check_rights(R_ADMIN)) + msg += "[key_name_admin(C.mob)]: [C.player_age] days old
    " + else + msg += "[key_name_mentor(C.mob)]: [C.player_age] days old
    " if(missing_ages) to_chat(src, "Some accounts did not have proper ages set in their clients. This function requires database to be present") From d3444658c99bc0591a6060eee40a5e7107869d4c Mon Sep 17 00:00:00 2001 From: allfd Date: Wed, 15 Feb 2017 22:11:32 -0500 Subject: [PATCH 026/164] Fixes cough and sneeze oversight --- code/modules/mob/living/carbon/human/species/station.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm index c07a3667a02..bdceaaa27a0 100644 --- a/code/modules/mob/living/carbon/human/species/station.dm +++ b/code/modules/mob/living/carbon/human/species/station.dm @@ -298,6 +298,10 @@ scream_verb = "shrieks" male_scream_sound = 'sound/voice/shriek1.ogg' female_scream_sound = 'sound/voice/shriek1.ogg' + male_cough_sounds = 'sound/voice/shriek1.ogg' + female_cough_sounds = 'sound/voice/shriek1.ogg' + male_sneeze_sound = 'sound/voice/shriek1.ogg' + female_sneeze_sound = 'sound/voice/shriek1.ogg' icon_skin_tones = list( 1 = "Default Green", From 8a7b1ad2fcdd37da2d813159e7e8fd24318a8111 Mon Sep 17 00:00:00 2001 From: allfd Date: Wed, 15 Feb 2017 22:46:10 -0500 Subject: [PATCH 027/164] Fix list issue --- code/modules/mob/living/carbon/human/species/station.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm index bdceaaa27a0..1e86cbda7e2 100644 --- a/code/modules/mob/living/carbon/human/species/station.dm +++ b/code/modules/mob/living/carbon/human/species/station.dm @@ -298,8 +298,8 @@ scream_verb = "shrieks" male_scream_sound = 'sound/voice/shriek1.ogg' female_scream_sound = 'sound/voice/shriek1.ogg' - male_cough_sounds = 'sound/voice/shriek1.ogg' - female_cough_sounds = 'sound/voice/shriek1.ogg' + male_cough_sounds = list('sound/voice/shriek1.ogg') + female_cough_sounds = list('sound/voice/shriek1.ogg') male_sneeze_sound = 'sound/voice/shriek1.ogg' female_sneeze_sound = 'sound/voice/shriek1.ogg' From eb1f49518d0c84e57ce299ae49ffd6fa34a5a312 Mon Sep 17 00:00:00 2001 From: Kyep Date: Thu, 16 Feb 2017 02:53:31 -0800 Subject: [PATCH 028/164] Moves some blob start locations --- _maps/map_files/cyberiad/cyberiad.dmm | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index 532fcd6f9bc..a909af22e79 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -2201,7 +2201,7 @@ "aQq" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; tag = ""},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/maintenance/fpmaint) "aQr" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/disposalpipe/junction{tag = "icon-pipe-j2 (EAST)"; icon_state = "pipe-j2"; dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint) "aQs" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; tag = ""},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/fpmaint) -"aQt" = (/obj/effect/landmark{name = "blobstart"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; tag = ""},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{level = 1},/turf/simulated/floor/plating,/area/maintenance/fpmaint) +"aQt" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; tag = ""},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{level = 1},/turf/simulated/floor/plating,/area/maintenance/fpmaint) "aQu" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; tag = ""},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 1; level = 1},/turf/simulated/floor/plating,/area/maintenance/fpmaint) "aQv" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint) "aQw" = (/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating,/area/maintenance/fpmaint) @@ -2230,7 +2230,7 @@ "aQT" = (/obj/machinery/door/airlock/engineering{name = "Electrical Maintenance"; req_access_txt = "11"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plating,/area/maintenance/electrical) "aQU" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plating,/area/maintenance/electrical) "aQV" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/machinery/hologram/holopad,/turf/simulated/floor/plating,/area/maintenance/electrical) -"aQW" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/electrical) +"aQW" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/obj/effect/landmark{name = "blobstart"},/turf/simulated/floor/plating,/area/maintenance/electrical) "aQX" = (/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/electrical) "aQY" = (/obj/structure/stool,/turf/simulated/floor/plating,/area/maintenance/electrical) "aQZ" = (/obj/structure/table,/obj/item/weapon/camera_assembly,/obj/item/weapon/camera_assembly,/obj/item/device/assembly/prox_sensor{pixel_x = -5; pixel_y = 5},/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/simulated/floor/plating,/area/maintenance/electrical) @@ -2693,7 +2693,7 @@ "aZO" = (/obj/machinery/light_switch{pixel_x = 27},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/crew_quarters/toilet) "aZP" = (/obj/structure/toilet{pixel_y = 8},/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/effect/landmark/start{name = "Civilian"},/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/crew_quarters/toilet) "aZQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/effect/decal/cleanable/fungus,/turf/simulated/wall,/area/crew_quarters/toilet) -"aZR" = (/obj/structure/toilet{pixel_y = 8},/obj/machinery/light/small{dir = 8},/obj/effect/landmark{name = "blobstart"},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{level = 1},/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/crew_quarters/toilet) +"aZR" = (/obj/structure/toilet{pixel_y = 8},/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/manifold/hidden/supply{level = 1},/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/crew_quarters/toilet) "aZS" = (/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/recharge_station,/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/crew_quarters/toilet) "aZT" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/wall,/area/crew_quarters/bar) "aZU" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -22},/obj/machinery/atmospherics/unary/vent_pump{on = 1},/turf/simulated/floor/wood,/area/crew_quarters/bar) @@ -3363,7 +3363,7 @@ "bmI" = (/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/hidden/supply{level = 1},/turf/simulated/floor/wood,/area/library) "bmJ" = (/obj/machinery/light/small{dir = 4},/obj/machinery/camera{c_tag = "Library East"; dir = 8; network = list("SS13")},/turf/simulated/floor/wood,/area/library) "bmK" = (/obj/machinery/light/small,/turf/simulated/floor/plasteel{tag = "icon-cult"; icon_state = "cult"; dir = 2},/area/library) -"bmL" = (/obj/effect/landmark{name = "blobstart"},/obj/structure/stool/bed/chair/comfy/brown{dir = 1},/turf/simulated/floor/plasteel{tag = "icon-cult"; icon_state = "cult"; dir = 2},/area/library) +"bmL" = (/obj/structure/stool/bed/chair/comfy/brown{dir = 1},/turf/simulated/floor/plasteel{tag = "icon-cult"; icon_state = "cult"; dir = 2},/area/library) "bmM" = (/obj/structure/cult/tome,/obj/item/device/videocam,/obj/machinery/light_switch{pixel_y = -25},/turf/simulated/floor/plasteel{tag = "icon-cult"; icon_state = "cult"; dir = 2},/area/library) "bmN" = (/turf/simulated/floor/plasteel{dir = 8; icon_state = "chapel"},/area/chapel/main) "bmO" = (/turf/simulated/floor/plasteel{icon_state = "chapel"},/area/chapel/main) @@ -5638,7 +5638,7 @@ "cev" = (/obj/machinery/atmospherics/unary/vent_scrubber{on = 1; scrub_N2O = 1; scrub_Toxins = 1},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/genetics) "cew" = (/obj/structure/stool/bed/chair/office/dark,/obj/machinery/alarm{dir = 8; icon_state = "alarm0"; pixel_x = 24},/turf/simulated/floor/plasteel{tag = "icon-whitepurple (EAST)"; icon_state = "whitepurple"; dir = 4},/area/medical/genetics) "cex" = (/obj/machinery/alarm/server{dir = 4; pixel_x = -22; pixel_y = 0},/obj/machinery/light/small{dir = 8},/obj/machinery/atmospherics/pipe/simple/heat_exchanging,/turf/simulated/floor/bluegrid{icon_state = "dark"; name = "Server Walkway"; nitrogen = 250; oxygen = 0; temperature = 0},/area/toxins/server_coldroom) -"cey" = (/obj/effect/landmark{name = "blobstart"},/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 4},/turf/simulated/floor/bluegrid{icon_state = "dark"; name = "Server Walkway"; nitrogen = 250; oxygen = 0; temperature = 0},/area/toxins/server_coldroom) +"cey" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 4},/turf/simulated/floor/bluegrid{icon_state = "dark"; name = "Server Walkway"; nitrogen = 250; oxygen = 0; temperature = 0},/area/toxins/server_coldroom) "cez" = (/obj/machinery/atmospherics/pipe/simple/heat_exchanging{dir = 10},/turf/simulated/floor/bluegrid{icon_state = "dark"; name = "Server Walkway"; nitrogen = 250; oxygen = 0; temperature = 0},/area/toxins/server_coldroom) "ceA" = (/obj/machinery/door/firedoor,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "Biohazard"; name = "Biohazard Shutter"; opacity = 0},/obj/machinery/door/airlock/research{name = "Toxins Mixing Room"; req_access_txt = "7"},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plasteel,/area/toxins/mixing) "ceB" = (/obj/machinery/hologram/holopad,/obj/machinery/atmospherics/pipe/simple/hidden{dir = 5; icon_state = "intact"},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/toxins/server) @@ -6752,7 +6752,7 @@ "czR" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plating,/area/storage/tech) "czS" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/effect/landmark{name = "xeno_spawn"; pixel_x = -1},/turf/simulated/floor/plating,/area/storage/tech) "czT" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plating,/area/storage/tech) -"czU" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/effect/landmark{name = "blobstart"},/obj/machinery/hologram/holopad,/turf/simulated/floor/plating,/area/storage/tech) +"czU" = (/obj/machinery/atmospherics/unary/portables_connector{layer = 2},/obj/effect/landmark{name = "blobstart"},/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/mixing) "czV" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/glass_engineering{name = "Engineering"; req_access_txt = "0"; req_one_access_txt = "11;24"},/obj/machinery/atmospherics/pipe/simple/hidden/yellow{tag = "icon-intact (NORTHWEST)"; icon_state = "intact"; dir = 9},/turf/simulated/floor/plasteel,/area/engine/controlroom) "czW" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8; initialize_directions = 11; level = 1},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plasteel{dir = 8; icon_state = "cautioncorner"},/area/hallway/primary/aft) "czX" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/turf/simulated/floor/plasteel,/area/hallway/primary/aft) @@ -6812,7 +6812,7 @@ "cAZ" = (/obj/machinery/embedded_controller/radio/airlock/access_controller{frequency = 1449; id_tag = "incinerator_access_control"; name = "Incinerator Access Console"; pixel_x = -26; pixel_y = 6; req_access_txt = "12"; tag_exterior_door = "incinerator_airlock_exterior"; tag_interior_door = "incinerator_airlock_interior"},/obj/machinery/ignition_switch{id = "Incinerator"; pixel_x = -24; pixel_y = -6},/obj/machinery/meter,/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/maintenance/incinerator) "cBa" = (/obj/machinery/atmospherics/pipe/simple/visible,/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/maintenance/incinerator) "cBb" = (/obj/machinery/atmospherics/pipe/simple/visible{dir = 4},/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/maintenance/incinerator) -"cBc" = (/obj/machinery/atmospherics/pipe/manifold/visible,/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/maintenance/incinerator) +"cBc" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/machinery/hologram/holopad,/turf/simulated/floor/plating,/area/storage/tech) "cBd" = (/obj/machinery/atmospherics/pipe/simple/visible{dir = 9},/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/maintenance/incinerator) "cBe" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/light_switch{pixel_x = 27},/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/maintenance/incinerator) "cBf" = (/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plating,/area/maintenance/apmaint) @@ -7625,6 +7625,7 @@ "cQG" = (/obj/machinery/door/firedoor,/obj/machinery/door/poddoor/shutters{dir = 8; id_tag = "teledoor"; name = "AI Satellite Teleport Access"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel{dir = 5; icon_state = "dark"; tag = "icon-vault (NORTHEAST)"},/area/turret_protected/aisat_interior) "cQH" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'RADIOACTIVE AREA'"; icon_state = "radiation"; name = "RADIOACTIVE AREA"; pixel_x = 0; pixel_y = 0},/obj/effect/spawner/window/reinforced,/obj/structure/disposalpipe/segment,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "Engineering"; name = "Engineering Security Doors"; opacity = 0},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/engine/equipmentstorage) "cQI" = (/obj/effect/spawner/window/reinforced,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "Engineering"; name = "Engineering Security Doors"; opacity = 0},/turf/simulated/floor/plating,/area/engine/equipmentstorage) +"cQJ" = (/obj/machinery/atmospherics/pipe/manifold/visible,/obj/effect/landmark{name = "blobstart"},/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/maintenance/incinerator) "cQK" = (/obj/effect/spawner/window/reinforced,/obj/machinery/atmospherics/pipe/simple/hidden/supply{level = 1},/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "Engineering"; name = "Engineering Security Doors"; opacity = 0},/turf/simulated/floor/plating,/area/engine/equipmentstorage) "cQL" = (/obj/machinery/light{dir = 8},/obj/machinery/portable_atmospherics/canister/oxygen,/obj/effect/decal/warning_stripes/blue/hollow,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/atmos) "cQM" = (/obj/machinery/portable_atmospherics/canister/oxygen,/obj/effect/decal/warning_stripes/blue/hollow,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/atmos) @@ -7747,6 +7748,7 @@ "cSZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/wall/r_wall,/area/engine/chiefs_office) "cTa" = (/obj/machinery/newscaster{pixel_x = 0; pixel_y = 30},/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) "cTb" = (/obj/machinery/alarm{pixel_y = 24},/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) +"cTc" = (/obj/effect/landmark{name = "blobstart"},/turf/simulated/floor/plating,/area/maintenance/engi_shuttle) "cTd" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plasteel,/area/engine/equipmentstorage) "cTe" = (/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel,/area/engine/equipmentstorage) "cTf" = (/obj/machinery/camera{c_tag = "Engineering Equipment East"; dir = 8; network = list("SS13")},/obj/machinery/light{icon_state = "tube1"; dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply{level = 1},/obj/structure/engineeringcart,/obj/item/device/radio/intercom{pixel_x = 28},/turf/simulated/floor/plasteel,/area/engine/equipmentstorage) @@ -9210,14 +9212,14 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaebPIclCclDclEbRybRAclFbRyclGclHbRAbPIbPIbYuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaceYcincincinceYbYPclIclJclKckmcfbcfbclLclMclNclOclPclPclPclQcgQcgQcgQcizcgSclRcktclScktclTcgWckvckwclUckwclVcgWclWclXclYchcclZcmacmbcmccmdcmecmfcmgcmhcmicmjcmkcmlcmmcmnchhcfIccuccucmockPckQcmpcmqcmrcjlcmscmtcmucmvcmwcmxcmycmzcmAcmBcmCcmDcjucmEchxcmFcmGcmHcmIcmJcmKcmLclpcllcmMcjGcjGcjGcmNcmOclpcbjcmPccZclrclrcbjcmQcmRcbnbPtcmScmTcmUcgscmVcmWcmXcmYcmZcnacnbcgucnccndcnecgucgscgscgscgscgscgscgscgsaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaacnfcieclzciecieckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacaebPIbPIbPIbPIbPIbPIbPIbPIbPIbPIbYuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaabaabafOcgQcngcngcgQcngcngcgQaaaaaacgAcnhcnicnjcgAbYPbYPbYPcamcnkcnlcnmcnmcnmcamcamcgQcnncnocnpcnqcgQcnrcnscgSclRcktcktcktcntcgWckvckwckwcnucnvcnwcnxcnycnzchcchcchcchcchccnAchcchccnBcnCchhchhcnDchhchkchhchhcaAcnEcnEcaAcnFcnGcnHcnIcnJcnKcnLcnMcnNcnObQVcnPcmycmzcnQcnRcnScnTcnUcnVchxcnWcnXcnYcnZcoacobcoccodcoecodcofcofcofcodcogcodcodcohcoiclrclrcbjcojclscbncbucolcomconceAcopcoqcoqcorcoscotcoucovcowcoxcoycozcoAcoBcoCcoDcoEcoFcoGcoHaabaabaabaabaabaabaabaabaaaaaaaaaaaaaaacidciecoIcoJcoJckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabaaaaaacgQcoKcoLcgQcoKcoLcgQaaaaaacoMceXcoNceXcoOaaaaabaaacamcamcamcamcamcamcamcoPcgQcoQcoRcoScoTclPcoUcoVcgScoWcoXcoYcktcoZcpacpbcpccpdcpecpfcgWcpgcphcpicpjcpkcpkcpkcpkcplcpmcpncpocpocppcppcpqcprcpschfcaAcptcpucpvcpwcpxckQcpycnIcpzcpAcpBcpCceicpDcpEcpFcpGcpHcpHcpIcpHcpHcpHcpJchxcpKcpLcpMcpNcpOcpPcpQcpRcpScpRcpTcpUcpVcpRcpWcpXcodcpYcpZcdacbjcbjcqacqbcqccqdcqecqfcqgcqhcqicqjcqkcqlcqmcqncqocqpcqqcqrcqqcqscqrcqrcqrcgEcqucqvcqwcqxaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaacieciecqyckbckbckbckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafOaaaafOcgQcqzcoLcgQcqzcoLcgQaaaaaaaabaabaabaabaabaabaabaabaabcgQcoLcqAcqBcgQcqCcqDcgQcqEcgQcgQcqFcgQcgQcqGcgScqHcqIcqJcqKcqLcqMcqNcqOcqPcqQcqRcpacqScqTcqUcqVcqWcqWcqWcqWcqXcqYcqZcracrbcracrccrdcrecrfcrgcrhcricrjcrkcrlcrmcrncrocrpcrqcrrcrscrtcrucrvcrwcrxcrybXubXucrzcrAcrBcrtcrCcrDcrDcrEcrDcrFcrGcrHcrIcpRcrJcrKcrLcrMcrLcrNcrOcrPcodcbjcgUcbjcbjcrRcrSclsbLRbPtcgscrTcgscgscrUcrVcrWcrXcrYcqrcrZcsacsbcqkcsbcqkcsccqkcqkcgscsdcsecsfcsgaabaabaabaabaabaabaabaabaaaaaaaaaaaaaaacieckbckbckbckbckbckbcshckbcsickbckbckbckbckbciecieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaafOaaaafOcgQcqzcoLcgQcqzcoLcgQaaaaaaaabaabaabaabaabaabaabaabaabcgQcoLcqAcqBcgQcqCcqDcgQcqEcgQcgQcqFcgQcgQcqGcgScqHcqIcqJcqKcqLcqMcqNcqOcqPcqQcqRcpacqScqTcqUcqVcqWcqWcqWcqWcqXcqYcqZcracrbcracrccrdcrecrfcrgcrhcricrjcrkcrlcrmcrncrocrpcrqcrrcrscrtcrucrvcrwcrxcrybXubXucrzcrAcrBcrtcrCcrDcrDcrEcrDcrFcrGcrHcrIcpRcrJcrKcrLcrMcrLcrNcrOcrPcodcbjcgUcbjcbjcrRcrSclsbLRbPtcgscrTcgscgscrUcrVcrWcrXcrYcqrcrZcsacsbcqkcsbcqkczUcqkcqkcgscsdcsecsfcsgaabaabaabaabaabaabaabaabaaaaaaaaaaaaaaacieckbckbckbckbckbckbcshckbcsickbckbckbckbckbciecieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcsjafOaabaMraMrafOcgQcgQcqFcgQcgQcqFcgQcgQcgQcngcngcngcgQcgQcgQcgQcgQcgQcgQcoLcskcslcgQcsmcgQcgQcsncgQcsocspcoLcgQcsqcgScsrcsscstclRcsucsvcswckvcsxcsycszcsvcsAcsBcsCcsDcsDcsEcsFcsGcsHcsIcsJcsKcsLcsMchfcsNcsLcsLcsOcsPcsQcsRcsScrlcsTcsUcsVcsWcsXcsYcsZctactbcsYcsYctcctdctdctdctdctdctectfctgcthcthctictjctkctlctmctncpRctoctpctqctrctqctscttcrLctuctvctwbLRctxbLRcrSclsbLRbIictyctzctAcgscgscgscgscgsctBcqkctCctDcsccqkctEcqkclucqkctFcgsctGctHctIcgsaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaciectJctJctJctJctJctJctKckbctLctJcsickbckbckbckbcieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabafOafOcngcoLcoLcoLcoLctMctNcoLcoLcoQctOctOctPctOctOctOctOctOctOctOctOctOctOctOctOcoRcgQcskcqzctQcgQcsqctRctRctRctRctRctRcgWcgWcgWcgWcgWcgWcgWctSctTctUcgYctWctXctYctYctZcuacsJcsLcsLcubcuccudcsLcsLcsLcuecufcugcrjcuhcuicujctdcukculcumcecculcuncuocuocuocupcuqcuqcuqcuqcurcusceccutcuucuvcuwcuxcuycuzcuAcpRcuBcuCcrLcuDcrLcuEcuFcuGchUcuIcuJcuKbLRcuLcrSclscuMbIibPAcuNcuOcuPcuQbGGbGGcgscuRcuScuTcuUcuVcuWcuXcuYcuZcvacvbcgscvccvdcvecvfaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaacvgcjZcjZcjZcjZcjZcjZcjZcvhcvickbckbckbckbcvjckccieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabafOaabaabafOcngcvkcvlcvmcoLcoLcvncoLcoLcsncgQcgQcgQcgQcgQcgQcqFcgQcgQcgQcgQcvocvocvocvocvocvocvocvocvocgQcsqcvpaaaaaaaaaaaacvqcvrcvscvtcvucvvcvwcvxcvycvzcvAcvBcvCcvDcvEcvEcvFcvGcvHcvIcvIcvIcvIcvJcvIcsLcsLcaAcvKcvLcvMcvNcvOcvPcuxcvQcvRcvScvTcvUcvVcvWcuqcuocvXcvYcvYcvYcvYcvZcwacwbcwccwdcwecwfcwgbQVcwhcwicpRcwjcwkcwlcwmcwncrLcwocpRcpRbIicwpbIibIibIicwqcwrcwsbIibGGcuNcwtcwucuQcuQcuQcgscgscgscgscgscgscgscgscgscgscgscgscgscgscgscgscgsaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaaaaaaciecoJcoJcoJcoJcoJcoJcwvckbcoIcoJcwwckbckbckbckbcieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcgQcwxcwxcwxcwxcwxcwxcwycwxcsncwzcgQcoLcwAcwBcwCcoLcwCcwDcwEcwBcvocwFcwFcvocwGcvocwHcwIcvocoLcqGcngaaacwJcwKcwLcwMcwNcwOcwPcwQcwRcwScwTcwUcwVcwWchVcwYcwZcxacxbcxccxdcvHcxecxfcxfcxfcxgcvIcsLcsLcxhcxhcxhcxhcxicxhcxjcxjcxkcxhcxhcxlcxhcxmcxncxocxpcxocxqcxrcxscxtcxucxvcxwcxxcxycxzcxAcxBcxCcxDcpscpRcpRcxEcpRcxFcpRcxGcxHcxIcsMcxJcxKcxLcxMcxNcxOcxPcxQcxNbGGcuNcxRbGGbGGcxScxTcxUctybGGbGGbGGbGGbGGbGGbGGcxVcxWbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacieckbckbckbckbckbckbcshckbcwwckbckbckbckbckbciecieaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacxXcxYcxYcxYcxYcxYcxYcxZcyacybcyccydcyecyfcwycsncygcgQcoLcyhcwBcoLcoLcoLcwDcqBcwBcvocwFcyicwIcwIcyjcwIcykcvocylcqGcngaaacymcyncyocypcyqcwOcyrcyscytcyucvxcyvcsBcywcvBcyxctYcyyctYcyzcyAcyBcyCcyDcyDcyDcyEcvIcsLcsLcxhcyFcyGcyHcyIcyJcyKcyKcyLcyMcyNcyOcyPcyQcyRcyScyTcyUcyVcyWcyXcyYcyZczaczbcxBczcczdczecxxczfczgczhczicziczjczkczlczmcznczoczmczmczmczpczmczmczqczrczscztczuczvczwczxczyczyczzczyczyczyczyczAczBczyczyczyczCczDbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacieciecqyckbckbckbckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaczEczFczFczFczFczGczHczIczJczKczKczLcwxcsncoLcqFcoLcoLcoLcoLcoLcoLcoLcoLcoLcvocvocwIczMcwIcvocwIczMcvoczNcsqcngaaacymczOczPczQczRczSczTczUczRczRchWczWczXczYczZczZcAacAbctYcAccAdcyBcyDcyDcyDcyDcAecvIcsLcsLcxhcAfcAgcAhcAicAjcAkcAkcAlcAmcAncAocyKcApcxhcAqcuocArcvYcAscAtcAucAvcAwcAxcxBcAycAzcAAcxBcABcACcADcAEcAEcAEcAEcAEcAFcAGcAHcAIcAJcAJcAKcAKcAJcALcokcqtcoocAPcAPcAQcARcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAScATcAUbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacnfcieciectJctJckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacAVcAWcAXcAYcAXcAZcBacBbcBccBdcBecwxcsncgQcgQcBfcngcngcngcngcngcngcngcBgcvocwIcwIcwIcwIcBhcwIcwIcvocygcqGcngaaacymcBicBjcBkcBlcwOcBmcBncBocBpcvxcyvcsBcnycBqcsDcrQcsDcvBcvBcvBcBscBtcyDcyDcBucBvcvIcsLcBwcxhcBxcBycBzcBAcBAcBBcBCcBDcBAcBAcBEcyKcBFcxhcBGcuocBHcvYcvYcBIcvYcvYcAwcBJcxBcBKcBLcBMcxBcBNcBOcBwcBPcBPcBPcBPcBPcBQcBQcBQcBPcBPaaaaaaaaaaaacBRcBScBTcBUcAPcBVcBWcBXcBYcBZcCacCbcCccCdcCecCfcCgcChcCicAPcAScCjcCkcClcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCncCocieclzcieckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaczEczFczFczFczFczGczHczIczJczKczKczLcwxcsncoLcqFcoLcoLcoLcoLcoLcoLcoLcoLcoLcvocvocwIczMcwIcvocwIczMcvoczNcsqcngaaacymczOczPczQczRczSczTcBcczRczRchWczWczXczYczZczZcAacAbctYcAccAdcyBcyDcyDcyDcyDcAecvIcsLcsLcxhcAfcAgcAhcAicAjcAkcAkcAlcAmcAncAocyKcApcxhcAqcuocArcvYcAscAtcAucAvcAwcAxcxBcAycAzcAAcxBcABcACcADcAEcAEcAEcAEcAEcAFcAGcAHcAIcAJcAJcAKcAKcAJcALcokcqtcoocAPcAPcAQcARcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAPcAScATcAUbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacnfcieciectJctJckbckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacAVcAWcAXcAYcAXcAZcBacBbcQJcBdcBecwxcsncgQcgQcBfcngcngcngcngcngcngcngcBgcvocwIcwIcwIcwIcBhcwIcwIcvocygcqGcngaaacymcBicBjcBkcBlcwOcBmcBncBocBpcvxcyvcsBcnycBqcsDcrQcsDcvBcvBcvBcBscBtcyDcyDcBucBvcvIcsLcBwcxhcBxcBycBzcBAcBAcBBcBCcBDcBAcBAcBEcyKcBFcxhcBGcuocBHcvYcvYcBIcvYcvYcAwcBJcxBcBKcBLcBMcxBcBNcBOcBwcBPcBPcBPcBPcBPcBQcBQcBQcBPcBPaaaaaaaaaaaacBRcBScBTcBUcAPcBVcBWcBXcBYcBZcCacCbcCccCdcCecCfcCgcChcCicAPcAScCjcCkcClcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCmcCncCocieclzcieckbckbckbckbckbckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacAVcCpcCqcCrcCsczJcCtcCucCvczJcCwctVcCycskcgQcoLcngaaaaaaaaaaaaaaacngcoLcCzcwFcCAcwIcwIcwIcwIcCBcCCcCDcCEcngaaacCFcwKcCGcwMcCHcwOcwOcCIcCJcCKcCLcCMcCNcCOcBqcsDcCPcCQcCRcCScCTcvHcCUcyDcyDcyDcCVcvIcsLcsLcCWcCWcCXcCYcCZcCZcDacDbcDccDdcDdcDecDfcDgcDfcAqcuocArcDhcDicDjcDkcDlcAwcDmcxBcDncDocDpcxBcsLcBOcBPcBPaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacDqcDrcDscDtcDucDvcDwcDwcDxcDwcDwcDwcDwcDwcDycDzcDAcDBcDCbGHcDDcjUbGHbGHaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaciecDEcDFcDGciecieckbckbcDHckbckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacAVcDIcAXcDJcAXcDKcDLcDMcDNcBbcDOcwxcDPcqBcgQcqzcvpaaaaaaaaaaaaaaacvpcDQcvocDRcDRcwFcDScDTcwIcDUcvocoLcqGcvpaaaaaaaaaaaacvqcDVcDWcDXcDXcvxcDYcvxcDZcsBcnycEacEbcEccEdcEecEecEecuHcEgcyDcEhcyDcEicvIcsLcsLcCWcEjcEkcElcEmcEncEocCWcEpcEqcErcEscEtcEucDfcEvcEwcExcDhcEycEzcEAcEBcECczbcxBcEDcEEcEFcxBcsLcBOcBPaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacDqcEHcEIcEJcwXcELcEMcENcEOcDwcDwcEPcDwcDwcDycDAcDAcDAcEQbGHcERbGGbGHaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaciccEScETclAcidciecieckbckcckbciecieaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacEUcEUcEUcEUcEUcwxcEVcEWcEWcEWcEWcEWaXpcEYcEYcEYcEWcEWcEWcEWcEWcEWcEWcEYcEYcEYcvocvocvocvocvocvocvocqFcEZcFacFacFacFacFacvqcvxcvxcvxcvxcvxcvxcvxcFbcsBcnycFccFdcFecFfcFgcFhcFicFjcFkcFlcFmcFncFocvIcsLcsLcCWcFpcFqcFrcFscFscFtcCWcFucFvcFvcFwcFvcFxcFycFzcFzcFzcFAcFBcFCcFDcDlcFEczbcFFcFFcFFcBPcBPcsLcBOcBQaaaaaaaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaacDqcFHcFIcFJcFKcFLcFMcFNcFOcDwcDwcDwcDwcFPcFQcFRcFScFTcFUbGHcERbGGbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacicciccicciccidcidcieciecieciecifaabaabaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa @@ -9239,7 +9241,7 @@ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacNxcWjcNzaabcNxcWjcNzaaacNxcWjcNzaaaaaaaaaaaaaabaaaaaaaaaaaaaabaabaabaaaaaaaabaabcXucXucXucXucXucXucXucXvcXucXucSUcXwcXxcVjcWrcUicXycUicUicXzcRRcXAcXBcUrcXCcXDcRRcXEcRXcTecXFcXGcXHcWHcXIcXJcXKcXLcXMcXNcXOcXLcXPcXQcXRcXScSdcXTcXUcXVcXWaabcTocXXcXYcXZcQZcRacBQcYacYbcYbcYbcYccQkcYdcUMcYecYfcURcYgcUTcUTcURcYhcQkcBOcYichfcsLcYjcYkcBPaaaaaacBRcYlcYmcYncYocYlcYmcYpcYqcYlcYmcYrcBRaabaabaabaabaabaabaabaabaabaabbGHcERbGHbGHbGHaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacYsaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalvaabcNxcWjcNzaaacNxcWjcNzaaacNxcWjcNzaabaaaaaaaaaaaaaaaaaaaaaaaaaabaabaaaaaaaabaabaabcXucYtcYtcYucYvcYwcYwcYxcYycYycYzcYAcYBcVjcWrcVjcYCcVjcVjcVjcRRcYDcYEcYFcYGcYHcYIcYJcKmcYLcYMcYMcYMcYNcYOcYPcYQcYRcYScVCcQPcYTcYUcYVcYWcYXcSdcXTcYYcYZcZacZbcSncZccWZcWZcQZcRacBQcOYchfchfchfckJcQkcZdcZecZfcZgcURcZhcZicUTcZjcZkcQkcBOcYichfcsLcJGcsLcBPaaaaaacBRcZlcZmcZncxNcZocZpcZqcxNcZrcZscZtcBRaabaabaaaaaaaaaaaaaaaaaaaaaaaabGHcERbGGbGGbGHaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalvaabcNxcWjcNzaaacNxcWjcNzaabcNxcWjcNzaabaabaabaabaaaaabaaaaaaaabaabaaaaaaaaaaabaaaaaacXucYtcYtcYucZucZucZucZvcZwcZxcSUcZycZzcZAcZBcZCcZDcZEcZFcZFcZGcZHcZIcVjcVjcVjcZJcZKcZLcZMcZNcZOcZPcZQcZRcSUcZScZScZTcVCcQPcZUcZVcZWcZXcZYcSdcZZdaadabdacdadcQZcQZcQZcQZcQZcRacBQcOYdaecsLcsLckJcQkdafcSAcSAdagdahdaidajcUTdakdalcQkcBOcYicMfcsLcuccTBcBPaaaaaacBRcMkcJKcJKcxNcMkcJKcJKcxNcMkcJKcJKcBRaaaaabaabaaaaaaaaaaaaaaacuQcuQbGHdamcuQbGGbGHbGHbGHcTMcTMaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamhaabcNxdancNzaaacNxdancNzaaacNxdancNzaabalvaabaabaabaabaabaabaabaaaaaaaaaaaaaaaaaaaabcXudaodapcZucZucZudaqdardardardardardardardasdatdaudavdawdawdawdaxdaydazdaAdaBdawdaydaCcMjdaEcZOdaFcZQcZRdaGdaHdaIdaJdaKdaLdaMdaNcYXdaOdaPdaQdaRdaSdaTcWXdaUcSndaVdaWdaWcQZcRacBPcOYchfcBNdaXckJcQkdaYcSAdaZdbacURdbbdbccUTdbddbecQkcBOcYichfcsLchfchfcBPaabaabcBRdbfcKZcJKcxNdbfcKZcJKcxNdbfcKZcJKcBRaaaaaaaabaabaaaaaaaaaaaacuQdbgbGGcERcuQdbhcuQdbibGHaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaamhaabcNxdancNzaaacNxdancNzaaacNxdancNzaabalvaabaabaabaabaabaabaabaaaaaaaaaaaaaaaaaaaabcXudaodapcTccZucZudaqdardardardardardardardasdatdaudavdawdawdawdaxdaydazdaAdaBdawdaydaCcMjdaEcZOdaFcZQcZRdaGdaHdaIdaJdaKdaLdaMdaNcYXdaOdaPdaQdaRdaSdaTcWXdaUcSndaVdaWdaWcQZcRacBPcOYchfcBNdaXckJcQkdaYcSAdaZdbacURdbbdbccUTdbddbecQkcBOcYichfcsLchfchfcBPaabaabcBRdbfcKZcJKcxNdbfcKZcJKcxNdbfcKZcJKcBRaaaaaaaabaabaaaaaaaaaaaacuQdbgbGGcERcuQdbhcuQdbibGHaabaabaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalvaaaaabaaaaaaaaaaabaabaabaaaaaaaabaabaaaalvaabaabaabaabaabaabaaaaaaaaaaaaaaaaaaaaaaabcXudbjcZucZucZucZucZudardbkdbldbmdbndbodardbpdbqdbrcXxcVjcVjdbsdbtdbudbvdbwdbxdbydbzcSUdbAdaEcZOdbBcZQdbCcSUdbDcZSdbEbmCcSddaMdaNdbGcSddaPdaQcXTcXUdbHcXWdbIcTodbJdbKdbLcQZcRacBPcOYchfdbMdbMckJcQkcQkdbNdbOcQkdbPcQkcQkcQkcQkcQkcQkcBOcYichfcsLcsLdbQcBPaaaaaacBRdbRcJKcJKcxNdbRcJKcJKcxNdbRcJKcJKcBRaaaaaaaaaaabaabaaaaaadbScuQbGGbGGcERcuQbGGbGGbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaalwalwalvalwalwamhalvalvalvalvalwalvalvalwdbTaaaaabaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaacXudbUcZwcZucZucZudbVdardbldbWdbXdbYdbZdcadcbdccdcddcecVjdcfdcgdchdcidcjdckdcldcmdcndcodbrcXxdcpdcqcZMdcrcSUdcscZSdctdcucSddaMdaNcYXcSddcvdaQcXTdcwdcxcZadcycSndczdaWdaWcQZcRacBQcOYdcAcuccABckJdcBcQkcQkdcCcQkdcDdcEdcFchfdcGdcHcsLcBOcYichfcsLdcIcTBcBPaaaaaacBRcBRcBRcBRcBRcBRcBRcBRcBRcBRcBRcBRcBRaaaaaaaaaaaaaabaabaaaaaabGHbGHbGHcERcuQdcJdcKbGGbZZaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabcXucXucXudcLdcMdcMdcMdardcNdcOdcPdcPdcQdcRdawdcSdcTdcUdcVdcWdcXdcYdcZddaddbddcddddcYddeddfddgddhddiddjddkddldbDcZSddmddncSddaMcSdddocSddaPdaQcXTcXUddpcXWdbIcQZcQZcQZcQZcQZcRacBQddqcYccuccTBddrddsddsddsddtchfdduddvddwchfddxcYbcYbddyddzcMfcsLcsLcBPcBPaaaaaaddAaabaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaabaaaaaaaaaaaaaaaaabaabaaabGHcJQddBddCcuQddDddEbGGbZZaaaaaaaaaaaaaaaaaaabpaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa From b9772d8b3b1e7c5005fcbcec5a71e5fd3a03771c Mon Sep 17 00:00:00 2001 From: Kyep Date: Thu, 16 Feb 2017 02:58:39 -0800 Subject: [PATCH 029/164] also removes hop office blobstart --- _maps/map_files/cyberiad/cyberiad.dmm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index a909af22e79..102b2d43e84 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -4617,7 +4617,7 @@ "bKO" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/turf/simulated/floor/plasteel,/area/hallway/primary/central/west) "bKP" = (/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plating,/area/maintenance/maintcentral) "bKQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plating,/area/maintenance/maintcentral) -"bKR" = (/obj/effect/landmark{name = "blobstart"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/maintcentral) +"bKR" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/maintcentral) "bKS" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1; initialize_directions = 11; level = 1},/obj/structure/closet/wardrobe/black,/turf/simulated/floor/plating,/area/maintenance/maintcentral) "bKT" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall,/area/bridge/meeting_room) "bKU" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/device/radio/intercom{name = "station intercom (General)"; pixel_y = -28},/turf/simulated/floor/plasteel,/area/bridge/meeting_room) From a4ab111354740034a07a1fa53f83882bb34bf985 Mon Sep 17 00:00:00 2001 From: Krausus Date: Fri, 17 Feb 2017 01:33:06 -0500 Subject: [PATCH 030/164] Adds shutdown-instead-of-reboot config options These basically exist so we can set the server up to automatically kill itself instead of rebooting. --- code/_globalvars/configuration.dm | 4 ++++ code/controllers/configuration.dm | 8 ++++++++ code/world.dm | 24 +++++++++++++++++++----- config/example/config.txt | 8 +++++++- 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/code/_globalvars/configuration.dm b/code/_globalvars/configuration.dm index 3e2d7d995d6..2d9b9761523 100644 --- a/code/_globalvars/configuration.dm +++ b/code/_globalvars/configuration.dm @@ -19,6 +19,10 @@ var/shuttle_left = 0 var/tinted_weldhelh = 1 var/mouse_respawn_time = 5 //Amount of time that must pass between a player dying as a mouse and repawning as a mouse. In minutes. +// Command to run if shutting down (SHUTDOWN_ON_REBOOT) instead of rebooting +// It's defined here as a global because this is a hilariously bad thing to have on the easily-edited config datum +var/global/shutdown_shell_command + // Debug is used exactly once (in living.dm) but is commented out in a lot of places. It is not set anywhere and only checked. // Debug2 is used in conjunction with a lot of admin verbs and therefore is actually legit. var/Debug = 0 // global debug switch diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 251494d9f89..c593296c30f 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -189,6 +189,8 @@ var/disable_ooc_emoji = 0 // prevents people from using emoji in OOC + var/shutdown_on_reboot = 0 // Whether to shut down the world instead of rebooting it + /datum/configuration/New() var/list/L = subtypesof(/datum/game_mode) for(var/T in L) @@ -585,6 +587,12 @@ if("disable_ooc_emoji") config.disable_ooc_emoji = 1 + if("shutdown_on_reboot") + config.shutdown_on_reboot = 1 + + if("shutdown_shell_command") + shutdown_shell_command = value + else diary << "Unknown setting in configuration: '[name]'" diff --git a/code/world.dm b/code/world.dm index c33b41388f4..c98f2acc2e3 100644 --- a/code/world.dm +++ b/code/world.dm @@ -261,7 +261,14 @@ var/world_topic_spam_protect_time = world.timeofday log_admin("[key_name(usr)] has requested an immediate world restart via client side debugging tools") spawn(0) to_chat(world, "Rebooting world immediately due to host request") - return ..(1) + if(config && config.shutdown_on_reboot) + sleep(0) + if(shutdown_shell_command) + shell(shutdown_shell_command) + del(world) + return + else + return ..(1) var/delay if(!isnull(time)) delay = max(0,time) @@ -287,10 +294,17 @@ var/world_topic_spam_protect_time = world.timeofday processScheduler.stop() - for(var/client/C in clients) - if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite - C << link("byond://[config.server]") - ..(0) + if(config && config.shutdown_on_reboot) + sleep(0) + if(shutdown_shell_command) + shell(shutdown_shell_command) + del(world) + return + else + for(var/client/C in clients) + if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite + C << link("byond://[config.server]") + ..(0) #define INACTIVITY_KICK 6000 //10 minutes in ticks (approx.) /world/proc/KickInactiveClients() diff --git a/config/example/config.txt b/config/example/config.txt index 5bcd469be87..d2ef1cf5062 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -334,4 +334,10 @@ DISABLE_SPACE_RUINS #MEDAL_HUB_PASSWORD ## Uncomment this if you want to disable usage of emoji in OOC -#DISABLE_OOC_EMOJI \ No newline at end of file +#DISABLE_OOC_EMOJI + +## Uncomment this to shut down the world any time it would normally reboot +#SHUTDOWN_ON_REBOOT +## A command to run prior to the world shutting down, only used if the above option is enabled +## This default value will kill Dream Daemon on Windows machines +#SHUTDOWN_SHELL_COMMAND taskkill /f /im dreamdaemon.exe \ No newline at end of file From 85df72c8b43e19156b59488b1b280cf715836412 Mon Sep 17 00:00:00 2001 From: Kyep Date: Thu, 16 Feb 2017 22:42:48 -0800 Subject: [PATCH 031/164] Blob announcement 24s -> 120s. --- code/modules/events/blob.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/events/blob.dm b/code/modules/events/blob.dm index 0bb69c693bb..c6bba219cbf 100644 --- a/code/modules/events/blob.dm +++ b/code/modules/events/blob.dm @@ -1,5 +1,5 @@ /datum/event/blob - announceWhen = 12 + announceWhen = 60 endWhen = 120 var/obj/effect/blob/core/Blob From 7c0eb7a8536f9232d6a96f49a1789256861f6e1b Mon Sep 17 00:00:00 2001 From: Kyep Date: Thu, 16 Feb 2017 23:31:28 -0800 Subject: [PATCH 032/164] CPP now lists jobs, with * on jobs with p.reqs --- code/game/jobs/job_exp.dm | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/code/game/jobs/job_exp.dm b/code/game/jobs/job_exp.dm index fc84a39bef7..e0b403bfce7 100644 --- a/code/game/jobs/job_exp.dm +++ b/code/game/jobs/job_exp.dm @@ -9,11 +9,20 @@ var/list/players_new = list() var/list/players_old = list() var/pline + var/datum/job/theirjob + var/jtext for(var/client/C in clients) + jtext = "No Job" + if(C.mob.mind.assigned_role) + theirjob = job_master.GetJob(C.mob.mind.assigned_role) + if(theirjob) + jtext = theirjob.title + if(config.use_exp_restrictions && theirjob.exp_requirements && theirjob.exp_type) + jtext += "*" if(check_rights(R_ADMIN)) - pline = "
  • [key_name_admin(C.mob)]: " + C.get_exp_living() + "
  • " + pline = "
  • [key_name_admin(C.mob)]: [jtext]: " + C.get_exp_living() + "
  • " else - pline = "
  • [key_name_mentor(C.mob)]: " + C.get_exp_living() + "
  • " + pline = "
  • [key_name_mentor(C.mob)]: [jtext]: " + C.get_exp_living() + "
  • " if(C.get_exp_living_num() > 1200) players_old += pline else From e8a04e55242fd45a463df8a16f511b5fa1025ef4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mieszko=20J=C4=99drzejczak?= Date: Fri, 17 Feb 2017 14:18:49 +0100 Subject: [PATCH 033/164] Laser carbine icons! --- .../projectiles/ammunition/magazines.dm | 4 ++++ .../projectiles/guns/projectile/automatic.dm | 4 ++++ icons/obj/ammo.dmi | Bin 27953 -> 27939 bytes icons/obj/guns/projectile.dmi | Bin 36850 -> 36918 bytes 4 files changed, 8 insertions(+) diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm index 5487f8d5bc9..2de2ae1f8f8 100644 --- a/code/modules/projectiles/ammunition/magazines.dm +++ b/code/modules/projectiles/ammunition/magazines.dm @@ -446,3 +446,7 @@ origin_tech = "combat=3" caliber = "laser" max_ammo = 20 + +/obj/item/ammo_box/magazine/laser/update_icon() + ..() + icon_state = "[initial(icon_state)]-[Ceiling(ammo_count(0)/20)*20]" diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm index e8ff8969fdf..0b174c635b0 100644 --- a/code/modules/projectiles/guns/projectile/automatic.dm +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -261,3 +261,7 @@ fire_sound = 'sound/weapons/emitter2.ogg' can_suppress = 0 burst_size = 2 + +/obj/item/weapon/gun/projectile/automatic/lasercarbine/update_icon() + ..() + icon_state = "lasercarbine[magazine ? "-[Ceiling(get_ammo(0)/5)*5]" : ""]" diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi index 1fd541fbc7d2ae12b6d990c5315a6c562c3f4afe..0977e02fb0ef8824d31ee43452ede1940009bbc7 100644 GIT binary patch delta 7172 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 delta 7156 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 al2pN}xh7UpF$YBaJ-V+0FS%#^_P+qC$~YGQ diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi index 84aa0490569d43e325ebd5fd75ed4f7b3c62fa06..fdc23ad6da824a9e60dd73185905e3a4dbb83744 100644 GIT binary patch delta 17010 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 Date: Fri, 17 Feb 2017 19:52:23 +0400 Subject: [PATCH 034/164] /vg/ shuttle engines from Eris --- icons/turf/shuttle.dmi | Bin 60546 -> 73216 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/turf/shuttle.dmi b/icons/turf/shuttle.dmi index cff10b9a0181abb6ac60b9e73576a7213209037e..659ec0bcf2d707dc40ba2cbf748918769a997142 100644 GIT binary patch literal 73216 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

    $M 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

    gQ6U1f5}|BMxoVT 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 JS9}%tzW_LI3UmMf From 366361b7d7ef5aa197f2966c9022f40aab6d2dea Mon Sep 17 00:00:00 2001 From: Krausus Date: Fri, 17 Feb 2017 12:33:45 -0500 Subject: [PATCH 035/164] Makes end-of-round sounds play before reboot Based on their length, they will now start playing early enough to finish playing right as the server reboots, so long as there's time to do so. --- code/_globalvars/lists/misc.dm | 10 +++++++++- code/world.dm | 12 ++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/code/_globalvars/lists/misc.dm b/code/_globalvars/lists/misc.dm index eb5c500573b..6c6a02b265f 100644 --- a/code/_globalvars/lists/misc.dm +++ b/code/_globalvars/lists/misc.dm @@ -20,4 +20,12 @@ var/list/restricted_camera_networks = list( //Those networks can only be accesse var/list/mineral_turfs = list() -var/list/ruin_landmarks = list() \ No newline at end of file +var/list/ruin_landmarks = list() + +var/list/round_end_sounds = list( // Maps available round end sounds to their duration + 'sound/AI/newroundsexy.ogg' = 2.3 SECONDS, + 'sound/misc/apcdestroyed.ogg' = 3 SECONDS, + 'sound/misc/bangindonk.ogg' = 1.6 SECONDS, + 'sound/goonstation/misc/newround1.ogg' = 6.9 SECONDS, + 'sound/goonstation/misc/newround2.ogg' = 14.8 SECONDS + ) diff --git a/code/world.dm b/code/world.dm index c98f2acc2e3..f37fd273e86 100644 --- a/code/world.dm +++ b/code/world.dm @@ -269,6 +269,7 @@ var/world_topic_spam_protect_time = world.timeofday return else return ..(1) + var/delay if(!isnull(time)) delay = max(0,time) @@ -278,6 +279,13 @@ var/world_topic_spam_protect_time = world.timeofday to_chat(world, "An admin has delayed the round end.") return to_chat(world, "Rebooting world in [delay/10] [delay > 10 ? "seconds" : "second"]. [reason]") + + var/round_end_sound = pick(round_end_sounds) + var/sound_length = round_end_sounds[round_end_sound] + if(delay > sound_length) // If there's time, play the round-end sound before rebooting + spawn(delay - sound_length) + if(!ticker.delay_end) + world << round_end_sound sleep(delay) if(blackbox) blackbox.save_all_data_to_sql() @@ -288,10 +296,6 @@ var/world_topic_spam_protect_time = world.timeofday log_game("Rebooting world. [reason]") //kick_clients_in_lobby("The round came to an end with you in the lobby.", 1) - spawn(0) - world << sound(pick('sound/AI/newroundsexy.ogg','sound/misc/apcdestroyed.ogg','sound/misc/bangindonk.ogg', 'sound/goonstation/misc/newround1.ogg', 'sound/goonstation/misc/newround2.ogg'))// random end sounds!! - LastyBatsy - - processScheduler.stop() if(config && config.shutdown_on_reboot) From e4357015314f716a257d09b70c05d6be6e005147 Mon Sep 17 00:00:00 2001 From: allfd Date: Fri, 17 Feb 2017 18:39:24 -0500 Subject: [PATCH 036/164] Adds unique Vox coughs and sneezes --- .../mob/living/carbon/human/species/station.dm | 8 ++++---- sound/voice/shriekcough.ogg | Bin 0 -> 12101 bytes sound/voice/shrieksneeze.ogg | Bin 0 -> 11882 bytes 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 sound/voice/shriekcough.ogg create mode 100644 sound/voice/shrieksneeze.ogg diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm index 1e86cbda7e2..238d6ce0890 100644 --- a/code/modules/mob/living/carbon/human/species/station.dm +++ b/code/modules/mob/living/carbon/human/species/station.dm @@ -298,10 +298,10 @@ scream_verb = "shrieks" male_scream_sound = 'sound/voice/shriek1.ogg' female_scream_sound = 'sound/voice/shriek1.ogg' - male_cough_sounds = list('sound/voice/shriek1.ogg') - female_cough_sounds = list('sound/voice/shriek1.ogg') - male_sneeze_sound = 'sound/voice/shriek1.ogg' - female_sneeze_sound = 'sound/voice/shriek1.ogg' + male_cough_sounds = list('sound/voice/shriekcough.ogg') + female_cough_sounds = list('sound/voice/shriekcough.ogg') + male_sneeze_sound = 'sound/voice/shrieksneeze.ogg' + female_sneeze_sound = 'sound/voice/shrieksneeze.ogg' icon_skin_tones = list( 1 = "Default Green", diff --git a/sound/voice/shriekcough.ogg b/sound/voice/shriekcough.ogg new file mode 100644 index 0000000000000000000000000000000000000000..15dc2e3873cbdadab627d42d786cb1368e02c0fe GIT binary patch literal 12101 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 VD^_Q`J@L8c?$EOGm%mtp{{x!-=m-D+ literal 0 HcmV?d00001 diff --git a/sound/voice/shrieksneeze.ogg b/sound/voice/shrieksneeze.ogg new file mode 100644 index 0000000000000000000000000000000000000000..9b1a5d1cca7358bb03a4dc45298215b51881c160 GIT binary patch literal 11882 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 NSEhl$qoQ%S{{wT&d&K|% literal 0 HcmV?d00001 From 07b79280f11daa2e13b351b945f007a6b16cfd1e Mon Sep 17 00:00:00 2001 From: davipatury Date: Fri, 17 Feb 2017 22:46:10 -0200 Subject: [PATCH 037/164] EFTPOS nano-ui. --- code/modules/economy/EFTPOS.dm | 108 ++++++++++++++------------------- nano/templates/eftpos.tmpl | 55 +++++++++++++++++ 2 files changed, 100 insertions(+), 63 deletions(-) create mode 100644 nano/templates/eftpos.tmpl diff --git a/code/modules/economy/EFTPOS.dm b/code/modules/economy/EFTPOS.dm index bd7a25d12b3..babbac30b11 100644 --- a/code/modules/economy/EFTPOS.dm +++ b/code/modules/economy/EFTPOS.dm @@ -27,7 +27,7 @@ /obj/item/device/eftpos/proc/print_reference() playsound(loc, 'sound/goonstation/machines/printer_thermal.ogg', 50, 1) - var/obj/item/weapon/paper/R = new(src.loc) + var/obj/item/weapon/paper/R = new(loc) R.name = "Reference: [eftpos_name]" // AUTOFIXED BY fix_string_idiocy.py @@ -45,7 +45,7 @@ R.overlays += stampoverlay R.stamps += "


    This paper has been stamped by the EFTPOS device." var/obj/item/smallDelivery/D = new(R.loc) - R.loc = D + R.forceMove(D) D.wrapped = R D.name = "small parcel - 'EFTPOS access code'" @@ -54,70 +54,51 @@ if(!location) return - for(var/obj/machinery/computer/account_database/DB in world) //Hotfix until someone finds out why it isn't in 'machines' + for(var/obj/machinery/computer/account_database/DB in machines) if(DB.z == location.z) linked_db = DB break -/obj/item/device/eftpos/attack_self(mob/user as mob) - if(get_dist(src,user) <= 1) +/obj/item/device/eftpos/attack_self(mob/user) + ui_interact(user) - // AUTOFIXED BY fix_string_idiocy.py - // C:\Users\Rob\Documents\Projects\vgstation13\code\WorkInProgress\Cael_Aislinn\Economy\EFTPOS.dm:59: var/dat = "[eftpos_name]
    " - var/dat = {"[eftpos_name]
    -This terminal is [machine_id]. Report this code when contacting Nanotrasen IT Support
    "} - // END AUTOFIX - if(transaction_locked) - - // AUTOFIXED BY fix_string_idiocy.py - // C:\Users\Rob\Documents\Projects\vgstation13\code\WorkInProgress\Cael_Aislinn\Economy\EFTPOS.dm:59: dat += "
    Reset[transaction_paid ? "" : " (authentication required)"]

    " - dat += {"Reset[transaction_paid ? "" : " (authentication required)"]

    - Transaction purpose: [transaction_purpose]
    - Value: $[transaction_amount]
    - Linked account: [linked_account ? linked_account.owner_name : "None"]
    "} - // END AUTOFIX - if(transaction_paid) - dat += "This transaction has been processed successfully.
    " - else - - // AUTOFIXED BY fix_string_idiocy.py - // C:\Users\Rob\Documents\Projects\vgstation13\code\WorkInProgress\Cael_Aislinn\Economy\EFTPOS.dm:67: dat += "Swipe your card below the line to finish this transaction.
    " - dat += {"Swipe your card below the line to finish this transaction.
    - \[------\]"} - // END AUTOFIX - else - - // AUTOFIXED BY fix_string_idiocy.py - // C:\Users\Rob\Documents\Projects\vgstation13\code\WorkInProgress\Cael_Aislinn\Economy\EFTPOS.dm:70: dat += "Lock in new transaction

    " - dat += {"Lock in new transaction

    - Transaction purpose: [transaction_purpose]
    - Value: $[transaction_amount]
    - Linked account: [linked_account ? linked_account.owner_name : "None"]
    - Change access code
    - Change EFTPOS ID
    - Scan card to reset access code \[------\]"} - // END AUTOFIX - user << browse(dat,"window=eftpos") - else - user << browse(null,"window=eftpos") - -/obj/item/device/eftpos/attackby(O as obj, user as mob, params) +/obj/item/device/eftpos/attackby(obj/O, mob/user, params) if(istype(O, /obj/item/weapon/card)) //attempt to connect to a new db, and if that doesn't work then fail if(!linked_db) reconnect_database() if(linked_db) if(linked_account) - var/obj/item/weapon/card/I = O - scan_card(I) + scan_card(O, user) + nanomanager.update_uis(src) else - to_chat(usr, "[bicon(src)]Unable to connect to linked account.") + to_chat(user, "[bicon(src)]Unable to connect to linked account.") else - to_chat(usr, "[bicon(src)]Unable to connect to accounts database.") + to_chat(user, "[bicon(src)]Unable to connect to accounts database.") else ..() -/obj/item/device/eftpos/Topic(var/href, var/href_list) +/obj/item/device/eftpos/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "eftpos.tmpl", name, 790, 310) + ui.open() + +/obj/item/device/eftpos/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) + var/data[0] + data["eftpos_name"] = eftpos_name + data["machine_id"] = machine_id + data["transaction_locked"] = transaction_locked + data["transaction_paid"] = transaction_paid + data["transaction_purpose"] = transaction_purpose + data["transaction_amount"] = transaction_amount + data["linked_account"] = linked_account ? linked_account.owner_name : null + return data + +/obj/item/device/eftpos/Topic(href, list/href_list) + if(..()) + return 1 + if(href_list["choice"]) switch(href_list["choice"]) if("change_code") @@ -134,9 +115,9 @@ if("change_id") var/attempt_code = text2num(input("Re-enter the current EFTPOS access code", "Confirm EFTPOS code")) if(attempt_code == access_code) - var name = input("Enter a new terminal ID for this device", "Enter new EFTPOS ID") as text|null + var/name = input("Enter a new terminal ID for this device", "Enter new EFTPOS ID") as text|null if(name) - eftpos_name = name + " EFTPOS scanner" + eftpos_name = "[name] EFTPOS scanner" print_reference() else to_chat(usr, "[bicon(src)]Incorrect code entered.") @@ -150,11 +131,11 @@ else to_chat(usr, "[bicon(src)]Unable to connect to accounts database.") if("trans_purpose") - var/purpose = input("Enter reason for EFTPOS transaction", "Transaction purpose") as text|null + var/purpose = input("Enter reason for EFTPOS transaction", "Transaction purpose", transaction_purpose) as text|null if(purpose) transaction_purpose = purpose if("trans_value") - var/try_num = input("Enter amount for EFTPOS transaction", "Transaction amount") as num + var/try_num = input("Enter amount for EFTPOS transaction", "Transaction amount", transaction_amount) as num if(try_num < 0) alert("That is not a valid amount!") else @@ -168,7 +149,7 @@ else if(linked_account) transaction_locked = 1 else - to_chat(usr, "[bicon(src)] No account connected to send transactions to.") + to_chat(usr, "[bicon(src)]No account connected to send transactions to.") if("scan_card") //attempt to connect to a new db, and if that doesn't work then fail if(!linked_db) @@ -176,7 +157,7 @@ if(linked_db && linked_account) var/obj/item/I = usr.get_active_hand() if(istype(I, /obj/item/weapon/card)) - scan_card(I) + scan_card(I, usr) else to_chat(usr, "[bicon(src)]Unable to link accounts.") if("reset") @@ -191,12 +172,13 @@ access_code = 0 to_chat(usr, "[bicon(src)]Access code reset to 0.") - src.attack_self(usr) + nanomanager.update_uis(src) + return 1 -/obj/item/device/eftpos/proc/scan_card(var/obj/item/weapon/card/I) +/obj/item/device/eftpos/proc/scan_card(obj/item/weapon/card/I, mob/user) if(istype(I, /obj/item/weapon/card/id)) var/obj/item/weapon/card/id/C = I - visible_message("[usr] swipes a card through [src].") + visible_message("[user] swipes a card through [src].") if(transaction_locked && !transaction_paid) if(linked_account) var/attempt_pin = input("Enter pin code", "EFTPOS transaction") as num @@ -204,7 +186,7 @@ if(D) if(transaction_amount <= D.money) playsound(src, 'sound/machines/chime.ogg', 50, 1) - src.visible_message("[bicon(src)] The [src] chimes.") + visible_message("[bicon(src)] The [src] chimes.") transaction_paid = 1 //transfer the money @@ -233,11 +215,11 @@ T.time = worldtime2text() linked_account.transaction_log.Add(T) else - to_chat(usr, "[bicon(src)]You don't have that much money!") + to_chat(user, "[bicon(src)]You don't have that much money!") else - to_chat(usr, "[bicon(src)]Unable to access account. Check security settings and try again.") + to_chat(user, "[bicon(src)]Unable to access account. Check security settings and try again.") else - to_chat(usr, "[bicon(src)]EFTPOS is not connected to an account.") + to_chat(user, "[bicon(src)]EFTPOS is not connected to an account.") else ..() diff --git a/nano/templates/eftpos.tmpl b/nano/templates/eftpos.tmpl new file mode 100644 index 00000000000..663f665d7f9 --- /dev/null +++ b/nano/templates/eftpos.tmpl @@ -0,0 +1,55 @@ + + +

    {{:data.eftpos_name}}

    +This terminal is {{:data.machine_id}}. Report this code when contacting Nanotrasen IT Support
    +{{if data.transaction_locked == 1}} +
    {{:helper.link(data.transaction_paid ? 'Reset' : 'Reset (authentication required)', 'unlock', {'choice' : 'toggle_lock'})}}
    +
    +
    +
    Transaction purpose:
    +
    {{:data.transaction_purpose}}
    +
    + +
    +
    Value:
    +
    {{:data.transaction_amount}}
    +
    + +
    +
    Linked account:
    +
    {{:data.linked_account ? data.linked_account : 'None'}}
    +
    +
    + {{if data.transaction_paid}} + This transaction has been processed successfully. + {{else}} + Swipe your card below the line to finish this transaction. +
    {{:helper.link('------', 'eject', {'choice' : 'scan_card'})}}
    + {{/if}} +{{else}} +
    {{:helper.link('Lock in new transaction', 'lock', {'choice' : 'toggle_lock'})}}
    +
    +
    +
    Transaction purpose:
    +
    {{:helper.link(data.transaction_purpose, 'info', {'choice' : 'trans_purpose'})}}
    +
    + +
    +
    Value:
    +
    {{:helper.link(data.transaction_amount, 'usd', {'choice' : 'trans_value'})}}
    +
    + +
    +
    Linked account:
    +
    {{:helper.link(data.linked_account ? data.linked_account : 'None', data.linked_account ? 'user' : 'user-times', {'choice' : 'link_account'})}}
    +
    +
    +
    +
    {{:helper.link('Change access code', 'key', {'choice' : 'change_code'})}}
    +
    {{:helper.link('Change EFTPOS ID', 'pencil', {'choice' : 'change_id'})}}
    +
    {{:helper.link('Scan card to reset acess code', 'refresh', {'choice' : 'reset'})}}
    +
    +{{/if}} \ No newline at end of file From b2868c31e0f94dd7950b150caa698d46b5166955 Mon Sep 17 00:00:00 2001 From: Tigercat2000 Date: Fri, 17 Feb 2017 17:43:33 -0800 Subject: [PATCH 038/164] Add [OPEN] option for AI in radio messages Also mildly refactors hear_radio to kill those nasty istype(src)'s. This makes an [OPEN] link appear on all radio messages the AI hears (to the right of the follow link). When clicked, it allows the AI to open the door nearest to the speaker (or, if it is a voice changer, the door nearest to the poor sap who had his voice stolen) --- code/modules/mob/dead/observer/say.dm | 9 +++ code/modules/mob/hear_say.dm | 77 +++++--------------- code/modules/mob/living/silicon/ai/ai.dm | 87 ++++++++++------------- code/modules/mob/living/silicon/ai/say.dm | 67 +++++++++++++++++ 4 files changed, 132 insertions(+), 108 deletions(-) diff --git a/code/modules/mob/dead/observer/say.dm b/code/modules/mob/dead/observer/say.dm index fb5b7735633..b4ae61f3e82 100644 --- a/code/modules/mob/dead/observer/say.dm +++ b/code/modules/mob/dead/observer/say.dm @@ -37,3 +37,12 @@ return . = src.emote_dead(message) + +/mob/dead/observer/handle_track(var/message, var/verb = "says", var/datum/language/language, var/mob/speaker = null, var/speaker_name, var/atom/follow_target, var/hard_to_hear) + return "[speaker_name] ([ghost_follow_link(follow_target, ghost=src)])" + +/mob/dead/observer/handle_speaker_name(var/mob/speaker = null, var/vname, var/hard_to_hear) + var/speaker_name = ..() + if(speaker && (speaker_name != speaker.real_name) && !isAI(speaker)) //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs. + speaker_name = "[speaker.real_name] ([speaker_name])" + return speaker_name \ No newline at end of file diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm index f158534475e..568033f3606 100644 --- a/code/modules/mob/hear_say.dm +++ b/code/modules/mob/hear_say.dm @@ -117,65 +117,8 @@ if(hard_to_hear) message = stars(message) - var/speaker_name = "unknown" - if(speaker) - speaker_name = speaker.name - - if(vname) - speaker_name = vname - if(hard_to_hear) - speaker_name = "unknown" - - var/changed_voice - - if(isAI(src) && !hard_to_hear) - var/jobname // the mob's "job" - var/mob/living/carbon/human/impersonating //The crewmember being impersonated, if any. - - if(ishuman(speaker)) - var/mob/living/carbon/human/H = speaker - - var/obj/item/weapon/card/id/id = H.wear_id - if((istype(id) && id.is_untrackable()) && H.HasVoiceChanger()) - changed_voice = 1 - var/mob/living/carbon/human/I = locate(speaker_name) - if(I) - impersonating = I - jobname = impersonating.get_assignment() - else - jobname = "Unknown" - else - jobname = H.get_assignment() - - else if(iscarbon(speaker)) // Nonhuman carbon mob - jobname = "No ID" - else if(isAI(speaker)) - jobname = "AI" - else if(isrobot(speaker)) - jobname = "Cyborg" - else if(ispAI(speaker)) - jobname = "Personal AI" - else if(isAutoAnnouncer(speaker)) - var/mob/living/automatedannouncer/AA = speaker - jobname = AA.role - else - jobname = "Unknown" - - if(changed_voice) - if(impersonating) - track = "[speaker_name] ([jobname])" - else - track = "[speaker_name] ([jobname])" - else - if(istype(follow_target, /mob/living/simple_animal/bot)) - track = "[speaker_name] ([jobname])" - else - track = "[speaker_name] ([jobname])" - - if(isobserver(src)) - if(speaker && (speaker_name != speaker.real_name) && !isAI(speaker)) //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs. - speaker_name = "[speaker.real_name] ([speaker_name])" - track = "[speaker_name] ([ghost_follow_link(follow_target, ghost=src)])" + var/speaker_name = handle_speaker_name(speaker, vname, hard_to_hear) + track = handle_track(message, verb, language, speaker, speaker_name, follow_target, hard_to_hear) var/formatted if(language) @@ -190,6 +133,22 @@ else to_chat(src, "[part_a][speaker_name][part_b][formatted]") +/mob/proc/handle_speaker_name(var/mob/speaker = null, var/vname, var/hard_to_hear) + var/speaker_name = "unknown" + if(speaker) + speaker_name = speaker.name + + if(vname) + speaker_name = vname + + if(hard_to_hear) + speaker_name = "unknown" + + return speaker_name + +/mob/proc/handle_track(var/message, var/verb = "says", var/datum/language/language, var/mob/speaker = null, var/speaker_name, var/atom/follow_target, var/hard_to_hear) + return + /mob/proc/hear_signlang(var/message, var/verb = "gestures", var/datum/language/language, var/mob/speaker = null) if(!client) return diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 3235c6899c1..33e74cb6266 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -618,9 +618,10 @@ var/list/ai_verbs_default = list( sleep(40) continue - return - - return + else if(href_list["open"]) + var/mob/target = locate(href_list["open"]) in mob_list + if(target) + open_nearest_door(target) /mob/living/silicon/ai/bullet_act(var/obj/item/projectile/Proj) ..(Proj) @@ -1092,52 +1093,6 @@ var/list/ai_verbs_default = list( aiRadio.interact(src) -/mob/living/silicon/ai/proc/open_nearest_door(mob/living/target) - if(!istype(target)) - return - spawn(0) - if(ishuman(target)) - var/mob/living/carbon/human/H = target - var/obj/item/weapon/card/id/id = H.wear_id - if(istype(id) && id.is_untrackable()) - to_chat(src, "Unable to locate an airlock") - return - if(H.digitalcamo) - to_chat(src, "Unable to locate an airlock") - return - if(!near_camera(target)) - to_chat(src, "Target is not near any active cameras.") - return - var/obj/machinery/door/airlock/tobeopened - var/dist = -1 - for(var/obj/machinery/door/airlock/D in range(3,target)) - if(!D.density) - continue - if(dist < 0) - dist = get_dist(D, target) -// to_chat(world, dist) - tobeopened = D - else - if(dist > get_dist(D, target)) - dist = get_dist(D, target) -// to_chat(world, dist) - tobeopened = D -// to_chat(world, "found [tobeopened.name] closer") - else -// to_chat(world, "[D.name] not close enough | [get_dist(D, target)] | [dist]") - if(tobeopened) - switch(alert(src, "Do you want to open \the [tobeopened] for [target]?","Doorknob_v2a.exe","Yes","No")) - if("Yes") - var/nhref = "src=[tobeopened.UID()];aiEnable=7" - tobeopened.Topic(nhref, params2list(nhref), tobeopened, 1) - to_chat(src, "\blue You've opened \the [tobeopened] for [target].") - if("No") - to_chat(src, "\red You deny the request.") - else - to_chat(src, "\red You've failed to open an airlock for [target]") - return - - /mob/living/silicon/ai/proc/check_unable(flags = 0) if(stat == DEAD) to_chat(usr, "You are dead!") @@ -1234,3 +1189,37 @@ var/list/ai_verbs_default = list( view_core() //A BYOND bug requires you to be viewing your core before your verbs update verbs += /mob/living/silicon/ai/proc/choose_modules malf_picker = new /datum/module_picker + +/mob/living/silicon/ai/proc/open_nearest_door(mob/living/target) + if(!istype(target)) + return + + if(target && target.can_track()) + var/obj/machinery/door/airlock/A = null + + var/dist = -1 + for(var/obj/machinery/door/airlock/D in range(3, target)) + if(!D.density) + continue + + var/curr_dist = get_dist(D, target) + + if(dist < 0) + dist = curr_dist + A = D + else if(dist > curr_dist) + dist = curr_dist + A = D + + if(istype(A)) + switch(alert(src, "Do you want to open \the [A] for [target]?", "Doorknob_v2a.exe", "Yes", "No")) + if("Yes") + A.AIShiftClick() + to_chat(src, "You open \the [A] for [target].") + else + to_chat(src, "You deny the request.") + else + to_chat(src, "Unable to locate an airlock near [target].") + + else + to_chat(src, "Target is not on or near any active cameras on the station.") \ No newline at end of file diff --git a/code/modules/mob/living/silicon/ai/say.dm b/code/modules/mob/living/silicon/ai/say.dm index 2a3b39c1c9b..ccd0f652b68 100644 --- a/code/modules/mob/living/silicon/ai/say.dm +++ b/code/modules/mob/living/silicon/ai/say.dm @@ -1,3 +1,70 @@ +/* + * AI Saycode + */ + + +/mob/living/silicon/ai/handle_track(var/message, var/verb = "says", var/datum/language/language, var/mob/speaker = null, var/speaker_name, var/atom/follow_target, var/hard_to_hear) + if(hard_to_hear) + return + + var/jobname // the mob's "job" + var/mob/living/carbon/human/impersonating //The crewmember being impersonated, if any. + var/changed_voice + + if(ishuman(speaker)) + var/mob/living/carbon/human/H = speaker + + var/obj/item/weapon/card/id/id = H.wear_id + if((istype(id) && id.is_untrackable()) && H.HasVoiceChanger()) + changed_voice = 1 + var/mob/living/carbon/human/I = locate(speaker_name) + if(I) + impersonating = I + jobname = impersonating.get_assignment() + else + jobname = "Unknown" + else + jobname = H.get_assignment() + + else if(iscarbon(speaker)) // Nonhuman carbon mob + jobname = "No ID" + else if(isAI(speaker)) + jobname = "AI" + else if(isrobot(speaker)) + jobname = "Cyborg" + else if(ispAI(speaker)) + jobname = "Personal AI" + else if(isAutoAnnouncer(speaker)) + var/mob/living/automatedannouncer/AA = speaker + jobname = AA.role + else + jobname = "Unknown" + + var/track = "" + var/mob/mob_to_track = null + if(changed_voice) + if(impersonating) + mob_to_track = impersonating + else + track = "[speaker_name] ([jobname])" + else + if(istype(follow_target, /mob/living/simple_animal/bot)) + track = "[speaker_name] ([jobname])" + else + mob_to_track = speaker + + if(mob_to_track) + track = "[speaker_name] ([jobname])" + track += "\[OPEN\]" + + return track + + + +/* + * AI VOX Announcements + */ + var/announcing_vox = 0 // Stores the time of the last announcement var/const/VOX_CHANNEL = 200 var/const/VOX_DELAY = 100 From 050543432c6c6c334536a917f68ca04a6f773c55 Mon Sep 17 00:00:00 2001 From: Crazylemon64 Date: Fri, 17 Feb 2017 20:51:35 -0800 Subject: [PATCH 039/164] Centcomm's not clowning around any more --- code/__HELPERS/text.dm | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 082af09f3f1..84c8ec3656e 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -471,7 +471,21 @@ proc/checkhtml(var/t) text = replacetext(text, "\[h3\]", "

    ") text = replacetext(text, "\[/h3\]", "

    ") - if(istype(P, /obj/item/weapon/pen)) + if(istype(P, /obj/item/toy/crayon)) // If it is a crayon, and he still tries to use these, make them empty! + text = replacetext(text, "\[*\]", "") + text = replacetext(text, "\[hr\]", "") + text = replacetext(text, "\[small\]", "") + text = replacetext(text, "\[/small\]", "") + text = replacetext(text, "\[list\]", "") + text = replacetext(text, "\[/list\]", "") + text = replacetext(text, "\[table\]", "") + text = replacetext(text, "\[/table\]", "") + text = replacetext(text, "\[row\]", "") + text = replacetext(text, "\[cell\]", "") + text = replacetext(text, "\[logo\]", "") + + text = "[text]" + else // They are using "not a crayon" - formatting is OK and such text = replacetext(text, "\[*\]", "
  • ") text = replacetext(text, "\[hr\]", "
    ") text = replacetext(text, "\[small\]", "") @@ -487,20 +501,6 @@ proc/checkhtml(var/t) text = replacetext(text, "\[logo\]", "") text = "[text]" - else // If it is a crayon, and he still tries to use these, make them empty! - text = replacetext(text, "\[*\]", "") - text = replacetext(text, "\[hr\]", "") - text = replacetext(text, "\[small\]", "") - text = replacetext(text, "\[/small\]", "") - text = replacetext(text, "\[list\]", "") - text = replacetext(text, "\[/list\]", "") - text = replacetext(text, "\[table\]", "") - text = replacetext(text, "\[/table\]", "") - text = replacetext(text, "\[row\]", "") - text = replacetext(text, "\[cell\]", "") - text = replacetext(text, "\[logo\]", "") - - text = "[text]" text = copytext(text, 1, MAX_PAPER_MESSAGE_LEN) return text @@ -539,4 +539,3 @@ proc/checkhtml(var/t) text = replacetext(text, "", "\[cell\]") text = replacetext(text, "", "\[logo\]") return text - From e9ef99d68dd4973eae0aaccdb036afbd5ebf24b0 Mon Sep 17 00:00:00 2001 From: Crazylemon64 Date: Fri, 17 Feb 2017 21:54:13 -0800 Subject: [PATCH 040/164] Mind transfer works again --- code/modules/mob/living/living.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 2aff4a71d85..6f4ad8840c7 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -6,7 +6,8 @@ /mob/living/ghostize(can_reenter_corpse = 1) var/prev_client = client - if(..()) + . = ..() + if(.) if(ranged_ability && prev_client) ranged_ability.remove_mousepointer(prev_client) From f5f7383ab8efb9735f65661d18e07807ae9230ec Mon Sep 17 00:00:00 2001 From: Crazylemon64 Date: Fri, 17 Feb 2017 22:44:19 -0800 Subject: [PATCH 041/164] Fixes a speech_span runtime --- code/modules/mob/living/carbon/human/say.dm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm index 7d5e6b30a78..63982b86948 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -105,7 +105,9 @@ /mob/living/carbon/human/handle_speech_problems(var/message, var/verb) var/list/returns[3] var/speech_problem_flag = 0 - var/span = mind.speech_span + var/span = "" + if(mind) + span = mind.speech_span if(silent || (disabilities & MUTE)) message = "" @@ -228,4 +230,4 @@ if(istype(r_ear, /obj/item/device/radio/headset)) R = r_ear if(R.translate_binary) - . = TRUE \ No newline at end of file + . = TRUE From 11c9f59abd843bf4f3ba941220a80d804e7b90d3 Mon Sep 17 00:00:00 2001 From: Crazylemon64 Date: Fri, 17 Feb 2017 23:07:43 -0800 Subject: [PATCH 042/164] Lighting now states which atom is missing a `light_sources` list on runtime --- code/modules/lighting/lighting_source.dm | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm index f2aa13a82e3..01f967a0544 100644 --- a/code/modules/lighting/lighting_source.dm +++ b/code/modules/lighting/lighting_source.dm @@ -66,7 +66,10 @@ destroyed = TRUE force_update() if(source_atom) - source_atom.light_sources -= src + if(!source_atom.light_sources) + log_runtime(EXCEPTION("Atom [source_atom] was a light source, but lacked a light source list!\n"), source_atom) + else + source_atom.light_sources -= src if(top_atom) top_atom.light_sources -= src From 27e7d538c4d4f74bef067bc643e8bab40b2146ea Mon Sep 17 00:00:00 2001 From: Crazylemon64 Date: Fri, 17 Feb 2017 23:29:33 -0800 Subject: [PATCH 043/164] The BSA goal will no longer choke on the z2 BSA --- code/modules/station_goals/bsa.dm | 34 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm index 6697aa0af26..89a58d7cc9e 100644 --- a/code/modules/station_goals/bsa.dm +++ b/code/modules/station_goals/bsa.dm @@ -21,9 +21,9 @@ /datum/station_goal/bluespace_cannon/check_completion() if(..()) return TRUE - var/obj/machinery/bsa/full/B = locate() - if(B && !B.stat && is_station_contact(B.z)) - return TRUE + for(var/obj/machinery/bsa/full/B) + if(B && !B.stat && is_station_contact(B.z)) + return TRUE return FALSE /obj/machinery/bsa @@ -139,21 +139,21 @@ pixel_x = -192 bound_width = 352 bound_x = -192 - + /obj/machinery/bsa/full/Destroy() if(controller && controller.cannon == src) controller.cannon = null controller = null return ..() - + /obj/machinery/bsa/full/east icon_state = "cannon_east" cannon_direction = EAST - + /obj/machinery/bsa/full/admin power_used_per_shot = 0 reload_cooldown = 100 - + /obj/machinery/bsa/full/admin/east icon_state = "cannon_east" cannon_direction = EAST @@ -212,7 +212,7 @@ point.Beam(get_target_turf(), icon_state = "bsa_beam", time = 50, maxdistance = world.maxx, beam_type = /obj/effect/ebeam/deadly) //ZZZAP playsound(src, 'sound/machines/bsa_fire.ogg', 100, 1) - + message_admins("[key_name_admin(user)] has launched an artillery strike.") explosion(bullseye,ex_power,ex_power*2,ex_power*4) @@ -268,26 +268,26 @@ var/area_aim = FALSE //should also show areas for targeting var/target_all_areas = FALSE //allows all areas (including admin areas) to be targeted - + /obj/machinery/computer/bsa_control/admin area_aim = TRUE target_all_areas = TRUE - + /obj/machinery/computer/bsa_control/admin/initialize() ..() if(!cannon) cannon = deploy() - + /obj/machinery/computer/bsa_control/Destroy() if(cannon && cannon.controller == src) cannon.controller = null cannon = null return ..() - + /obj/machinery/computer/bsa_control/process() ..() update_icon() - + /obj/machinery/computer/bsa_control/update_icon() if(stat & BROKEN) icon_state = icon_state_broken @@ -299,7 +299,7 @@ icon_state = icon_state_active else icon_state = initial(icon_state) - + /obj/machinery/computer/bsa_control/attack_hand(mob/user) if(..()) return 1 @@ -318,7 +318,7 @@ data["notice"] = notice if(target) data["target"] = get_target_name() - + if(cannon) var/reload_cooldown = cannon.reload_cooldown var/last_fire_time = cannon.last_fire_time @@ -331,13 +331,13 @@ data["ready"] = minutes == 0 && seconds == 0 else data["ready"] = FALSE - + return data /obj/machinery/computer/bsa_control/Topic(href, href_list) if(..()) return 1 - + if(href_list["build"]) cannon = deploy() . = TRUE From e687103d7697be135459eb6c9afe360234f60639 Mon Sep 17 00:00:00 2001 From: Twinmold Date: Sat, 18 Feb 2017 05:47:22 -0600 Subject: [PATCH 044/164] Changes Biogenerator Belt Holster to Accessory Holster This simply adjusts the currently available holster from the biogenerator from being the belt item (which can only hold sketckins (pistols) and the detective's revolver) to the accessory holster, which is the same one Blueshields get. :cl:Twinmold Adjust: Biogenerator holster from belt object to accessory holster. /:cl: --- code/modules/research/designs/biogenerator_designs.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/research/designs/biogenerator_designs.dm b/code/modules/research/designs/biogenerator_designs.dm index fb6201eaf31..14b8ad1dc6b 100644 --- a/code/modules/research/designs/biogenerator_designs.dm +++ b/code/modules/research/designs/biogenerator_designs.dm @@ -184,7 +184,7 @@ id = "s_holster" build_type = BIOGENERATOR materials = list(MAT_BIOMASS = 400) - build_path = /obj/item/weapon/storage/belt/holster + build_path = /obj/item/clothing/accessory/holster category = list("initial","Leather and Cloth") /datum/design/leather_satchel From ae1a76a5c41af38208d5fcc86dc23f8b13b9874c Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 18 Feb 2017 07:46:04 -0500 Subject: [PATCH 045/164] Automatic changelog generation for PR #6490 [ci skip] --- html/changelogs/AutoChangeLog-pr-6490.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-6490.yml diff --git a/html/changelogs/AutoChangeLog-pr-6490.yml b/html/changelogs/AutoChangeLog-pr-6490.yml new file mode 100644 index 00000000000..a528a15851b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6490.yml @@ -0,0 +1,4 @@ +author: "Crazylemon64" +delete-after: True +changes: + - bugfix: "Centcomm is no longer obnoxiously pedantic, regarding BSA deployment" From 41087e53444ee38d6245103f9f5a0fb6feb5ebfc Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 18 Feb 2017 07:52:07 -0500 Subject: [PATCH 046/164] Automatic changelog generation for PR #6487 [ci skip] --- html/changelogs/AutoChangeLog-pr-6487.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-6487.yml diff --git a/html/changelogs/AutoChangeLog-pr-6487.yml b/html/changelogs/AutoChangeLog-pr-6487.yml new file mode 100644 index 00000000000..0ebf70b5781 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6487.yml @@ -0,0 +1,4 @@ +author: "Crazylemon64" +delete-after: True +changes: + - bugfix: "Mind transfer abilities work again" From 945e45309745113225cc317e61b5f0e03fd25d55 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 18 Feb 2017 07:53:41 -0500 Subject: [PATCH 047/164] Automatic changelog generation for PR #6486 [ci skip] --- html/changelogs/AutoChangeLog-pr-6486.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-6486.yml diff --git a/html/changelogs/AutoChangeLog-pr-6486.yml b/html/changelogs/AutoChangeLog-pr-6486.yml new file mode 100644 index 00000000000..14ca54dc06b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6486.yml @@ -0,0 +1,4 @@ +author: "Crazylemon64" +delete-after: True +changes: + - bugfix: "Centcomm has begun enforcing stricter security protocols after a recent influx of fax responses from Clown impersonators" From b2604cc2619d785a8555becc4da719fc21846032 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 18 Feb 2017 07:58:33 -0500 Subject: [PATCH 048/164] Automatic changelog generation for PR #6465 [ci skip] --- html/changelogs/AutoChangeLog-pr-6465.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-6465.yml diff --git a/html/changelogs/AutoChangeLog-pr-6465.yml b/html/changelogs/AutoChangeLog-pr-6465.yml new file mode 100644 index 00000000000..f8d27d99f44 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6465.yml @@ -0,0 +1,4 @@ +author: "Alffd" +delete-after: True +changes: + - bugfix: "Fixes missing entries in species/station for Vox cough and sneeze." From 23b18b4a329b947d5a9c438a4dbf5792ddea9ce9 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 18 Feb 2017 08:00:18 -0500 Subject: [PATCH 049/164] Automatic changelog compile, [ci skip] --- html/changelog.html | 12 ++++++++++++ html/changelogs/.all_changelog.yml | 8 ++++++++ html/changelogs/AutoChangeLog-pr-6465.yml | 4 ---- html/changelogs/AutoChangeLog-pr-6486.yml | 4 ---- html/changelogs/AutoChangeLog-pr-6487.yml | 4 ---- html/changelogs/AutoChangeLog-pr-6490.yml | 4 ---- 6 files changed, 20 insertions(+), 16 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-6465.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-6486.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-6487.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-6490.yml diff --git a/html/changelog.html b/html/changelog.html index 3b59884b2eb..12830048819 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,6 +55,18 @@ -->
    +

    18 February 2017

    +

    Alffd updated:

    +
      +
    • Fixes missing entries in species/station for Vox cough and sneeze.
    • +
    +

    Crazylemon64 updated:

    +
      +
    • Centcomm has begun enforcing stricter security protocols after a recent influx of fax responses from Clown impersonators
    • +
    • Mind transfer abilities work again
    • +
    • Centcomm is no longer obnoxiously pedantic, regarding BSA deployment
    • +
    +

    17 February 2017

    Crazylemon64 updated:

      diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index cc93f5f21d9..2088bedab95 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -3756,3 +3756,11 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. - rscadd: 'Three station goals have been added: bluespace artillery construction, meteor shield satellite network and DNA vault.' - bugfix: Fixes the "Messages" tab of the communications computer. +2017-02-18: + Alffd: + - bugfix: Fixes missing entries in species/station for Vox cough and sneeze. + Crazylemon64: + - bugfix: Centcomm has begun enforcing stricter security protocols after a recent + influx of fax responses from Clown impersonators + - bugfix: Mind transfer abilities work again + - bugfix: Centcomm is no longer obnoxiously pedantic, regarding BSA deployment diff --git a/html/changelogs/AutoChangeLog-pr-6465.yml b/html/changelogs/AutoChangeLog-pr-6465.yml deleted file mode 100644 index f8d27d99f44..00000000000 --- a/html/changelogs/AutoChangeLog-pr-6465.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Alffd" -delete-after: True -changes: - - bugfix: "Fixes missing entries in species/station for Vox cough and sneeze." diff --git a/html/changelogs/AutoChangeLog-pr-6486.yml b/html/changelogs/AutoChangeLog-pr-6486.yml deleted file mode 100644 index 14ca54dc06b..00000000000 --- a/html/changelogs/AutoChangeLog-pr-6486.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Crazylemon64" -delete-after: True -changes: - - bugfix: "Centcomm has begun enforcing stricter security protocols after a recent influx of fax responses from Clown impersonators" diff --git a/html/changelogs/AutoChangeLog-pr-6487.yml b/html/changelogs/AutoChangeLog-pr-6487.yml deleted file mode 100644 index 0ebf70b5781..00000000000 --- a/html/changelogs/AutoChangeLog-pr-6487.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Crazylemon64" -delete-after: True -changes: - - bugfix: "Mind transfer abilities work again" diff --git a/html/changelogs/AutoChangeLog-pr-6490.yml b/html/changelogs/AutoChangeLog-pr-6490.yml deleted file mode 100644 index a528a15851b..00000000000 --- a/html/changelogs/AutoChangeLog-pr-6490.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Crazylemon64" -delete-after: True -changes: - - bugfix: "Centcomm is no longer obnoxiously pedantic, regarding BSA deployment" From 97416138aeb234a26918056b52fdead3b2f05582 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 18 Feb 2017 08:30:16 -0500 Subject: [PATCH 050/164] Automatic changelog generation for PR #6410 [ci skip] --- html/changelogs/AutoChangeLog-pr-6410.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-6410.yml diff --git a/html/changelogs/AutoChangeLog-pr-6410.yml b/html/changelogs/AutoChangeLog-pr-6410.yml new file mode 100644 index 00000000000..398f2a23866 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6410.yml @@ -0,0 +1,4 @@ +author: "Kyep" +delete-after: True +changes: + - rscadd: "Added a 'take' option to ahelps/mhelps, so admins/mentors can quickly let the asker know their question is being looked at." From 9a69922a86b21432e0d7dae64515dca98c2bd4df Mon Sep 17 00:00:00 2001 From: Markolie Date: Sat, 18 Feb 2017 15:58:38 +0100 Subject: [PATCH 051/164] Fix slicing disposal pipes not showing a progress bar --- code/modules/recycling/disposal.dm | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index 622fe780031..b9cb76b31b0 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -872,29 +872,22 @@ //weldingtool: unfasten and convert to obj/disposalconstruct /obj/structure/disposalpipe/attackby(var/obj/item/I, var/mob/user, params) - - var/turf/T = src.loc + var/turf/T = get_turf(src) if(T.intact) return // prevent interaction with T-scanner revealed pipes - src.add_fingerprint(user) + + add_fingerprint(user) + if(istype(I, /obj/item/weapon/weldingtool)) var/obj/item/weapon/weldingtool/W = I - - if(W.remove_fuel(0,user)) - playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) - // check if anything changed over 2 seconds - var/turf/uloc = user.loc - var/atom/wloc = W.loc - to_chat(user, "Slicing the disposal pipe.") - sleep(30) - if(!W.isOn()) return - if(user.loc == uloc && wloc == W.loc) + if(W.remove_fuel(0, user)) + to_chat(user, "You begin slicing \the [src].") + playsound(loc, 'sound/items/Welder2.ogg', 100, 1) + if(do_after(user, 30, target = src)) + to_chat(user, "You finish slicing \the [src].") welded() - else - to_chat(user, "You must stay still while welding the pipe.") else - to_chat(user, "You need more welding fuel to cut the pipe.") - return + to_chat(user, "You need more welding fuel to cut the pipe.") // called when pipe is cut with welder /obj/structure/disposalpipe/proc/welded() From 67c114c6e1e29e4eb3774cfa311e751ee9d0e03e Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 18 Feb 2017 10:00:33 -0500 Subject: [PATCH 052/164] Automatic changelog compile, [ci skip] --- html/changelog.html | 4 ++++ html/changelogs/.all_changelog.yml | 3 +++ html/changelogs/AutoChangeLog-pr-6410.yml | 4 ---- 3 files changed, 7 insertions(+), 4 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-6410.yml diff --git a/html/changelog.html b/html/changelog.html index 12830048819..7e7bda4afb2 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -66,6 +66,10 @@
    • Mind transfer abilities work again
    • Centcomm is no longer obnoxiously pedantic, regarding BSA deployment
    +

    Kyep updated:

    +
      +
    • Added a 'take' option to ahelps/mhelps, so admins/mentors can quickly let the asker know their question is being looked at.
    • +

    17 February 2017

    Crazylemon64 updated:

    diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 2088bedab95..9464e5a3672 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -3764,3 +3764,6 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. influx of fax responses from Clown impersonators - bugfix: Mind transfer abilities work again - bugfix: Centcomm is no longer obnoxiously pedantic, regarding BSA deployment + Kyep: + - rscadd: Added a 'take' option to ahelps/mhelps, so admins/mentors can quickly + let the asker know their question is being looked at. diff --git a/html/changelogs/AutoChangeLog-pr-6410.yml b/html/changelogs/AutoChangeLog-pr-6410.yml deleted file mode 100644 index 398f2a23866..00000000000 --- a/html/changelogs/AutoChangeLog-pr-6410.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Kyep" -delete-after: True -changes: - - rscadd: "Added a 'take' option to ahelps/mhelps, so admins/mentors can quickly let the asker know their question is being looked at." From df15e35012a448521943d7a1992038aeb38d0e15 Mon Sep 17 00:00:00 2001 From: Markolie Date: Sat, 18 Feb 2017 17:00:50 +0100 Subject: [PATCH 053/164] Make firelocks more lethal (autoclose, takes time to open with hand). Also fixes atmospherics remote control. --- code/__DEFINES/atmospherics.dm | 7 +++- code/game/area/Space Station 13 areas.dm | 2 +- code/game/area/areas.dm | 6 ++-- code/game/machinery/alarm.dm | 42 +++++++++------------- code/game/machinery/doors/door.dm | 4 ++- code/game/machinery/doors/firedoor.dm | 26 ++++++++++---- code/modules/nano/modules/atmos_control.dm | 4 +-- 7 files changed, 51 insertions(+), 40 deletions(-) diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm index d2988a6474f..fe7e2b0067c 100644 --- a/code/__DEFINES/atmospherics.dm +++ b/code/__DEFINES/atmospherics.dm @@ -114,4 +114,9 @@ // Atmos pipe limits #define MAX_OUTPUT_PRESSURE 4500 // (kPa) What pressure pumps and powered equipment max out at. -#define MAX_TRANSFER_RATE 200 // (L/s) Maximum speed powered equipment can work at. \ No newline at end of file +#define MAX_TRANSFER_RATE 200 // (L/s) Maximum speed powered equipment can work at. + +// Atmos alarm defines +#define ATMOS_ALARM_NONE 0 +#define ATMOS_ALARM_WARNING 1 +#define ATMOS_ALARM_DANGER 2 \ No newline at end of file diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 8ec413450b0..fd6b0938108 100644 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -17,7 +17,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station /area var/fire = null - var/atmosalm = 0 + var/atmosalm = ATMOS_ALARM_NONE var/poweralm = 1 var/party = null var/radalert = 0 diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index ec70d50c504..96ffc936a7b 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -53,7 +53,7 @@ /area/proc/atmosalert(danger_level, var/alarm_source) - if(danger_level == 0) + if(danger_level == ATMOS_ALARM_NONE) atmosphere_alarm.clearAlarm(src, alarm_source) else atmosphere_alarm.triggerAlarm(src, alarm_source, severity = danger_level) @@ -64,10 +64,10 @@ danger_level = max(danger_level, AA.danger_level) if(danger_level != atmosalm) - if(danger_level < 1 && atmosalm >= 1) + if(danger_level < ATMOS_ALARM_WARNING && atmosalm >= ATMOS_ALARM_WARNING) //closing the doors on red and opening on green provides a bit of hysteresis that will hopefully prevent fire doors from opening and closing repeatedly due to noise air_doors_open() - else if(danger_level >= 2 && atmosalm < 2) + else if(danger_level >= ATMOS_ALARM_DANGER && atmosalm < ATMOS_ALARM_DANGER) air_doors_close() atmosalm = danger_level diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index efa6a1ded81..632177d7358 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -14,14 +14,14 @@ /datum/tlv/proc/get_danger_level(curval as num) if(max2 >=0 && curval>max2) - return 2 + return ATMOS_ALARM_DANGER if(min2 >=0 && curval=0 && curval>max1) - return 1 + return ATMOS_ALARM_WARNING if(min1 >=0 && curval[user] begins forcing \the [src].", \ + "You begin forcing \the [src].") + if(do_after(user, force_open_time, target = src)) + user.visible_message("[user] forces \the [src].", \ + "You force \the [src].") + autoclose = TRUE open() - else - close() - + /obj/machinery/door/firedoor/attack_ai(mob/user) attack_hand(user) @@ -133,7 +141,13 @@ /obj/machinery/door/firedoor/close() . = ..() + crush() latetoggle() + +/obj/machinery/door/firedoor/autoclose() + var/area/A = get_area(src) + if(A && A.atmosalm >= ATMOS_ALARM_DANGER) + ..() /obj/machinery/door/firedoor/proc/latetoggle() if(operating || stat & NOPOWER || !nextstate) diff --git a/code/modules/nano/modules/atmos_control.dm b/code/modules/nano/modules/atmos_control.dm index 0670193e498..9dbb508f16e 100644 --- a/code/modules/nano/modules/atmos_control.dm +++ b/code/modules/nano/modules/atmos_control.dm @@ -25,7 +25,7 @@ if(ui_ref) var/obj/machinery/alarm/alarm = locate(href_list["alarm"]) in (monitored_alarms ? monitored_alarms : machines) if(alarm) - var/datum/topic_state/TS = generate_state(alarm) + var/datum/topic_state/air_alarm/TS = generate_state(alarm) alarm.ui_interact(usr, master_ui = ui_ref, state = TS) /datum/nano_module/atmos_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/master_ui = null, var/datum/topic_state/state = default_state) @@ -63,7 +63,7 @@ /datum/topic_state/air_alarm/href_list(var/mob/user) var/list/extra_href = list() - extra_href["remote_connection"] = 1 + extra_href["remote_connection"] = TRUE extra_href["remote_access"] = has_access(user) return extra_href From b19be1b93a8a54b40e868e58e9078a1a4d96dd60 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 18 Feb 2017 11:03:51 -0500 Subject: [PATCH 054/164] Automatic changelog generation for PR #6496 [ci skip] --- html/changelogs/AutoChangeLog-pr-6496.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-6496.yml diff --git a/html/changelogs/AutoChangeLog-pr-6496.yml b/html/changelogs/AutoChangeLog-pr-6496.yml new file mode 100644 index 00000000000..be3aa93ccd4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6496.yml @@ -0,0 +1,4 @@ +author: "Markolie" +delete-after: True +changes: + - bugfix: "Slicing disposal pipes now shows a progress bar." From 70087cde3d07e24110b48836354c0d5da57868c3 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 18 Feb 2017 11:07:47 -0500 Subject: [PATCH 055/164] Automatic changelog generation for PR #6480 [ci skip] --- html/changelogs/AutoChangeLog-pr-6480.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-6480.yml diff --git a/html/changelogs/AutoChangeLog-pr-6480.yml b/html/changelogs/AutoChangeLog-pr-6480.yml new file mode 100644 index 00000000000..e9f42bed2ee --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6480.yml @@ -0,0 +1,4 @@ +author: "uraniummeltdown" +delete-after: True +changes: + - rscadd: "Shuttle engines have new sprites." From 5a07c4140a37699f3dc9daf723816a599fb69c6f Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 18 Feb 2017 11:11:03 -0500 Subject: [PATCH 056/164] Automatic changelog generation for PR #6369 [ci skip] --- html/changelogs/AutoChangeLog-pr-6369.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-6369.yml diff --git a/html/changelogs/AutoChangeLog-pr-6369.yml b/html/changelogs/AutoChangeLog-pr-6369.yml new file mode 100644 index 00000000000..cd5c824a8c6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6369.yml @@ -0,0 +1,5 @@ +author: "Markolie" +delete-after: True +changes: + - rscadd: "Vending machines, newscasters, biogenerators, plant DNA manipulators, seed extractors, bots, fax machines, photocopiers, AI slippers, cell door timers, airlocks, pipe dispensers and atmospherics machinery that open a window can now be viewed by ghosts." + - rscadd: "Admins can now interact with mass driver, crematorium, ignition, light, flashers and flasher switches and door switches, as well as airlocks, windoors, firedoors and atmospherics machinery that do not open a window if they have advanced admin interaction enabled (under the \"Admin\" tab)." From 71744db9e13140460fba7270f75adefb0998f914 Mon Sep 17 00:00:00 2001 From: Markolie Date: Sat, 18 Feb 2017 17:23:09 +0100 Subject: [PATCH 057/164] Prevent heavy firelocks from being forced --- code/game/machinery/doors/firedoor.dm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 201f7763eb8..29270a54c99 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -20,6 +20,7 @@ closed_layer = 3.11 auto_close_time = 50 + var/can_force = TRUE var/force_open_time = 300 var/assembly_type = /obj/structure/firelock_frame var/nextstate = null @@ -95,7 +96,7 @@ close() /obj/machinery/door/firedoor/attack_hand(mob/user) - if(operating || !density) + if(operating || !density || !can_force) return add_fingerprint(user) @@ -199,9 +200,10 @@ /obj/machinery/door/firedoor/heavy name = "heavy firelock" icon = 'icons/obj/doors/Doorfire.dmi' - glass = 0 + glass = FALSE opacity = 1 assembly_type = /obj/structure/firelock_frame/heavy + can_force = FALSE /obj/machinery/door/firedoor/heavy/ex_act(severity) switch(severity) From ba193fdd105c35e1f8ffc61c18f0972587ec6ad1 Mon Sep 17 00:00:00 2001 From: davipatury Date: Sat, 18 Feb 2017 14:36:37 -0200 Subject: [PATCH 058/164] Medical Records nano-ui. --- code/game/machinery/computer/medical.dm | 940 +++++++++--------- code/modules/mob/living/carbon/human/human.dm | 26 +- code/modules/paperwork/filingcabinet.dm | 8 +- nano/templates/med_data.tmpl | 171 ++++ 4 files changed, 676 insertions(+), 469 deletions(-) create mode 100644 nano/templates/med_data.tmpl diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index ddbee4c06a9..da42cc740ca 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -1,4 +1,9 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 +#define MED_DATA_MAIN 1 // Main menu +#define MED_DATA_R_LIST 2 // Record list +#define MED_DATA_MAINT 3 // Records maintenance +#define MED_DATA_RECORD 4 // Record +#define MED_DATA_V_DATA 5 // Virus database +#define MED_DATA_MEDBOT 6 // Medbot monitor /obj/machinery/computer/med_data//TODO:SANITY name = "medical records console" @@ -13,486 +18,516 @@ var/screen = null var/datum/data/record/active1 = null var/datum/data/record/active2 = null - var/a_id = null var/temp = null var/printing = null light_color = LIGHT_COLOR_DARKBLUE -/obj/machinery/computer/med_data/attack_ai(user as mob) - return src.attack_hand(user) +/obj/machinery/computer/med_data/attackby(obj/item/O, mob/user, params) + if(istype(O, /obj/item/weapon/card/id) && !scan) + usr.drop_item() + O.forceMove(src) + scan = O + ui_interact(user) + ..() - -/obj/machinery/computer/med_data/attack_hand(mob/user as mob) +/obj/machinery/computer/med_data/attack_hand(mob/user) if(..()) return - var/dat - if(src.temp) - dat = text("[src.temp]

    Clear Screen") - else - dat = text("Confirm Identity: []
    ", (src.scan ? text("[]", src.scan.name) : "----------")) - if(src.authenticated) - switch(src.screen) - if(1.0) - dat += {" -Search Records -
    List Records -
    -
    Virus Database -
    Medbot Tracking -
    -
    Record Maintenance -
    {Log Out}
    -"} - if(2.0) - dat += "Record List:
    " - if(!isnull(data_core.general)) - for(var/datum/data/record/R in sortRecord(data_core.general)) - dat += text("[]: []
    ", R, R.fields["id"], R.fields["name"]) - //Foreach goto(132) - dat += "
    Back" - if(3.0) - dat += "Records Maintenance
    \nBackup To Disk
    \nUpload From disk
    \nDelete All Records
    \n
    \nBack" - if(4.0) - dat += "
    Medical Record

    " - if((istype(src.active1, /datum/data/record) && data_core.general.Find(src.active1))) - dat += "
    Name: [active1.fields["name"]] \ - ID: [active1.fields["id"]]
    \n \ - Sex: [active1.fields["sex"]]
    \n \ - Age: [active1.fields["age"]]
    \n \ - Fingerprint: [active1.fields["fingerprint"]]
    \n \ - Physical Status: [active1.fields["p_stat"]]
    \n \ - Mental Status: [active1.fields["m_stat"]]
    \ - Photo:
    \ -
    " - else - dat += "General Record Lost!
    " - if((istype(src.active2, /datum/data/record) && data_core.medical.Find(src.active2))) - dat += text("
    \n
    Medical Data

    \nBlood Type: []
    \nDNA: []
    \n
    \nMinor Disabilities: []
    \nDetails: []
    \n
    \nMajor Disabilities: []
    \nDetails: []
    \n
    \nAllergies: []
    \nDetails: []
    \n
    \nCurrent Diseases: [] (per disease info placed in log/comment section)
    \nDetails: []
    \n
    \nImportant Notes:
    \n\t[]
    \n
    \n
    Comments/Log

    ", src.active2.fields["b_type"], src.active2.fields["b_dna"], src.active2.fields["mi_dis"], src.active2.fields["mi_dis_d"], src.active2.fields["ma_dis"], src.active2.fields["ma_dis_d"], src.active2.fields["alg"], src.active2.fields["alg_d"], src.active2.fields["cdi"], src.active2.fields["cdi_d"], src.active2.fields["notes"]) - var/counter = 1 - while(src.active2.fields[text("com_[]", counter)]) - dat += text("[]
    Delete Entry

    ", src.active2.fields[text("com_[]", counter)], counter) - counter++ - dat += "Add Entry

    " - dat += "Delete Record (Medical Only)

    " - else - dat += "Medical Record Lost!
    " - dat += text("New Record

    ") - dat += "\nPrint Record
    \nBack
    " - if(5.0) - dat += "
    Virus Database
    " - for(var/Dt in typesof(/datum/disease/)) - var/datum/disease/Dis = new Dt(0) - if(istype(Dis, /datum/disease/advance)) - continue // TODO (tm): Add advance diseases to the virus database which no one uses. - if(!Dis.desc) - continue - dat += "
    [Dis.name]" - dat += "
    Back" - if(6.0) - dat += "
    Medical Robot Monitor
    " - dat += "Back" - dat += "
    Medical Robots:" - var/bdat = null - for(var/mob/living/simple_animal/bot/medbot/M in world) + if(is_away_level(z)) + to_chat(user, "Unable to establish a connection: You're too far away from the station!") + return + add_fingerprint(user) + ui_interact(user) - if(M.z != src.z) continue //only find medibots on the same z-level as the computer - var/turf/bl = get_turf(M) - if(bl) //if it can't find a turf for the medibot, then it probably shouldn't be showing up - bdat += "[M.name] - \[[bl.x],[bl.y]\] - [M.on ? "Online" : "Offline"]
    " - if((!isnull(M.reagent_glass)) && M.use_beaker) - bdat += "Reservoir: \[[M.reagent_glass.reagents.total_volume]/[M.reagent_glass.reagents.maximum_volume]\]
    " - else - bdat += "Using Internal Synthesizer.
    " - if(!bdat) - dat += "
    None detected
    " - else - dat += "
    [bdat]" +/obj/machinery/computer/med_data/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "med_data.tmpl", name, 800, 380) + ui.open() +/obj/machinery/computer/med_data/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) + var/data[0] + data["temp"] = temp + data["scan"] = scan ? scan.name : null + data["authenticated"] = authenticated + data["screen"] = screen + if(authenticated) + switch(screen) + if(MED_DATA_R_LIST) + if(!isnull(data_core.general)) + var/list/records = list() + data["records"] = records + for(var/datum/data/record/R in sortRecord(data_core.general)) + records[++records.len] = list("ref" = "\ref[R]", "id" = R.fields["id"], "name" = R.fields["name"]) + if(MED_DATA_RECORD) + var/list/general = list() + data["general"] = general + if(istype(active1, /datum/data/record) && data_core.general.Find(active1)) + var/list/fields = list() + general["fields"] = fields + fields[++fields.len] = list("field" = "Name:", "value" = active1.fields["name"], "edit" = null) + fields[++fields.len] = list("field" = "ID:", "value" = active1.fields["id"], "edit" = null) + fields[++fields.len] = list("field" = "Sex:", "value" = active1.fields["sex"], "edit" = "sex") + fields[++fields.len] = list("field" = "Age:", "value" = active1.fields["age"], "edit" = "age") + fields[++fields.len] = list("field" = "Fingerprint:", "value" = active1.fields["fingerprint"], "edit" = "fingerprint") + fields[++fields.len] = list("field" = "Physical Status:", "value" = active1.fields["p_stat"], "edit" = "p_stat") + fields[++fields.len] = list("field" = "Mental Status:", "value" = active1.fields["m_stat"], "edit" = "m_stat") + var/list/photos = list() + general["photos"] = photos + photos[++photos.len] = list("photo" = active1.fields["photo-south"]) + photos[++photos.len] = list("photo" = active1.fields["photo-west"]) + general["has_photos"] = (active1.fields["photo-south"] || active1.fields["photo-west"] ? 1 : 0) + general["empty"] = 0 else - else - dat += "{Log In}" - var/datum/browser/popup = new(user, "med_rec", name, 400, 400) - popup.set_content(dat) - popup.open(0) - onclose(user, "med_rec") - return + general["empty"] = 1 + + var/list/medical = list() + data["medical"] = medical + if(istype(active2, /datum/data/record) && data_core.medical.Find(active2)) + var/list/fields = list() + medical["fields"] = fields + fields[++fields.len] = list("field" = "Blood Type:", "value" = active2.fields["b_type"], "edit" = "b_type", "line_break" = 0) + fields[++fields.len] = list("field" = "DNA:", "value" = active2.fields["b_dna"], "edit" = "b_dna", "line_break" = 1) + fields[++fields.len] = list("field" = "Minor Disabilities:", "value" = active2.fields["mi_dis"], "edit" = "mi_dis", "line_break" = 0) + fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["mi_dis_d"], "edit" = "mi_dis_d", "line_break" = 1) + fields[++fields.len] = list("field" = "Major Disabilities:", "value" = active2.fields["ma_dis"], "edit" = "ma_dis", "line_break" = 0) + fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["ma_dis_d"], "edit" = "ma_dis_d", "line_break" = 1) + fields[++fields.len] = list("field" = "Allergies:", "value" = active2.fields["alg"], "edit" = "alg", "line_break" = 0) + fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["alg_d"], "edit" = "alg_d", "line_break" = 1) + fields[++fields.len] = list("field" = "Current Diseases:", "value" = active2.fields["cdi"], "edit" = "cdi", "line_break" = 0) + fields[++fields.len] = list("field" = "Details:", "value" = active2.fields["cdi_d"], "edit" = "cdi_d", "line_break" = 1) + fields[++fields.len] = list("field" = "Important Notes:", "value" = active2.fields["notes"], "edit" = "notes", "line_break" = 0) + if(!active2.fields["comments"] || !islist(active2.fields["comments"])) + active2.fields["comments"] = list() + medical["comments"] = active2.fields["comments"] + medical["empty"] = 0 + else + medical["empty"] = 1 + if(MED_DATA_V_DATA) + data["virus"] = list() + for(var/D in typesof(/datum/disease)) + var/datum/disease/DS = new D(0) + if(istype(DS, /datum/disease/advance)) + continue + if(!DS.desc) + continue + data["virus"] += list(list("name" = DS.name, "D" = D)) + if(MED_DATA_MEDBOT) + data["medbots"] = list() + for(var/mob/living/simple_animal/bot/medbot/M in world) + if(M.z != z) + continue + var/turf/T = get_turf(M) + if(T) + var/medbot = list() + medbot["name"] = M.name + medbot["x"] = T.x + medbot["y"] = T.y + medbot["on"] = M.on + if(!isnull(M.reagent_glass) && M.use_beaker) + medbot["use_beaker"] = 1 + medbot["total_volume"] = M.reagent_glass.reagents.total_volume + medbot["maximum_volume"] = M.reagent_glass.reagents.maximum_volume + else + medbot["use_beaker"] = 0 + data["medbots"] += list(medbot) + return data /obj/machinery/computer/med_data/Topic(href, href_list) if(..()) return 1 - if(!( data_core.general.Find(src.active1) )) - src.active1 = null + if(!data_core.general.Find(active1)) + active1 = null + if(!data_core.medical.Find(active2)) + active2 = null - if(!( data_core.medical.Find(src.active2) )) - src.active2 = null + if(href_list["temp"]) + temp = null - if((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) + if(href_list["temp_action"]) + if(href_list["temp_action"]) + var/temp_href = splittext(href_list["temp_action"], "=") + switch(temp_href[1]) + if("del_all2") + for(var/datum/data/record/R in data_core.medical) + qdel(R) + temp = list("text" = "All records deleted.", "buttons" = list()) + if("p_stat") + if(active1) + switch(temp_href[2]) + if("deceased") + active1.fields["p_stat"] = "*Deceased*" + if("ssd") + active1.fields["p_stat"] = "*SSD*" + if("active") + active1.fields["p_stat"] = "Active" + if("unfit") + active1.fields["p_stat"] = "Physically Unfit" + if("disabled") + active1.fields["p_stat"] = "Disabled" + if("m_stat") + if(active1) + switch(temp_href[2]) + if("insane") + active1.fields["m_stat"] = "*Insane*" + if("unstable") + active1.fields["m_stat"] = "*Unstable*" + if("watch") + active1.fields["m_stat"] = "*Watch*" + if("stable") + active1.fields["m_stat"] = "Stable" + if("b_type") + if(active2) + switch(temp_href[2]) + if("an") + active2.fields["b_type"] = "A-" + if("bn") + active2.fields["b_type"] = "B-" + if("abn") + active2.fields["b_type"] = "AB-" + if("on") + active2.fields["b_type"] = "O-" + if("ap") + active2.fields["b_type"] = "A+" + if("bp") + active2.fields["b_type"] = "B+" + if("abp") + active2.fields["b_type"] = "AB+" + if("op") + active2.fields["b_type"] = "O+" + if("del_r2") + if(active2) + qdel(active2) + active2 = null - if(href_list["temp"]) - src.temp = null + if(href_list["scan"]) + if(scan) + scan.forceMove(loc) + if(ishuman(usr) && !usr.get_active_hand()) + usr.put_in_hands(scan) + scan = null + else + var/obj/item/I = usr.get_active_hand() + if(istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.forceMove(src) + scan = I - if(href_list["scan"]) - if(src.scan) + if(href_list["login"]) + if(isAI(usr)) + authenticated = usr.name + rank = "AI" + else if(isrobot(usr)) + authenticated = usr.name + var/mob/living/silicon/robot/R = usr + rank = "[R.modtype] [R.braintype]" + else if(istype(scan, /obj/item/weapon/card/id)) + if(check_access(scan)) + authenticated = scan.registered_name + rank = scan.assignment - if(ishuman(usr)) - scan.loc = usr.loc + if(authenticated) + active1 = null + active2 = null + screen = MED_DATA_MAIN - if(!usr.get_active_hand()) - usr.put_in_hands(scan) + if(authenticated) + var/incapable = (usr.stat || usr.restrained() || (!in_range(src, usr) && !issilicon(usr))) + if(href_list["logout"]) + authenticated = null + screen = null + active1 = null + active2 = null - scan = null + if(href_list["screen"]) + screen = text2num(href_list["screen"]) + if(screen < 1) + screen = MED_DATA_MAIN - else - src.scan.loc = src.loc - src.scan = null + active1 = null + active2 = null - else - var/obj/item/I = usr.get_active_hand() - if(istype(I, /obj/item/weapon/card/id)) - usr.drop_item() - I.loc = src - src.scan = I + if(href_list["vir"]) + var/type = href_list["vir"] + var/datum/disease/D = new type(0) + var/afs = "" + for(var/mob/M in D.viable_mobtypes) + afs += "[initial(M.name)];" + var/severity = D.severity + switch(severity) + if("Harmful", "Minor") + severity = "[severity]" + if("Medium") + severity = "[severity]" + if("Dangerous!") + severity = "[severity]" + if("BIOHAZARD THREAT!") + severity = "

    [severity]

    " + setTemp({"Name: [D.name] +
    Number of stages: [D.max_stages] +
    Spread: [D.spread_text] Transmission +
    Possible Cure: [(D.cure_text||"none")] +
    Affected Lifeforms:[afs]
    +
    Notes: [D.desc]
    +
    Severity: [severity]"}) + qdel(D) - else if(href_list["logout"]) - src.authenticated = null - src.screen = null - src.active1 = null - src.active2 = null + if(href_list["del_all"]) + var/list/buttons = list() + buttons[++buttons.len] = list("name" = "Yes", "icon" = "check", "href" = "del_all2=1") + buttons[++buttons.len] = list("name" = "No", "icon" = "times", "href" = null) + setTemp("

    Are you sure you wish to delete all records?

    ", buttons) - else if(href_list["login"]) - - if(istype(usr, /mob/living/silicon/ai)) - src.active1 = null - src.active2 = null - src.authenticated = usr.name - src.rank = "AI" - src.screen = 1 - - else if(istype(usr, /mob/living/silicon/robot)) - src.active1 = null - src.active2 = null - src.authenticated = usr.name - var/mob/living/silicon/robot/R = usr - src.rank = "[R.modtype] [R.braintype]" - src.screen = 1 - - else if(istype(src.scan, /obj/item/weapon/card/id)) - src.active1 = null - src.active2 = null - - if(src.check_access(src.scan)) - src.authenticated = src.scan.registered_name - src.rank = src.scan.assignment - src.screen = 1 - - if(src.authenticated) - - if(href_list["screen"]) - src.screen = text2num(href_list["screen"]) - if(src.screen < 1) - src.screen = 1 - - src.active1 = null - src.active2 = null - - if(href_list["vir"]) - var/type = href_list["vir"] - var/datum/disease/Dis = new type(0) - var/AfS = "" - for(var/mob/M in Dis.viable_mobtypes) - AfS += " [initial(M.name)];" - src.temp = {"Name: [Dis.name] -
    Number of stages: [Dis.max_stages] -
    Spread: [Dis.spread_text] Transmission -
    Possible Cure: [(Dis.cure_text||"none")] -
    Affected Lifeforms:[AfS] -
    -
    Notes: [Dis.desc] -
    -
    Severity: [Dis.severity]"} - - if(href_list["del_all"]) - src.temp = "Are you sure you wish to delete all records?
    \n\tYes
    \n\tNo
    " - - if(href_list["del_all2"]) - for(var/datum/data/record/R in data_core.medical) - //R = null - qdel(R) - //Foreach goto(494) - src.temp = "All records deleted." - - if(href_list["field"]) - var/a1 = src.active1 - var/a2 = src.active2 - switch(href_list["field"]) - if("fingerprint") - if(istype(src.active1, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please input fingerprint hash:", "Med. records", src.active1.fields["fingerprint"], null) as text)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1)) - return - src.active1.fields["fingerprint"] = t1 - if("sex") - if(istype(src.active1, /datum/data/record)) - if(src.active1.fields["sex"] == "Male") - src.active1.fields["sex"] = "Female" - else - src.active1.fields["sex"] = "Male" - if("age") - if(istype(src.active1, /datum/data/record)) - var/t1 = input("Please input age:", "Med. records", src.active1.fields["age"], null) as num - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1)) - return - src.active1.fields["age"] = t1 - if("mi_dis") - if(istype(src.active2, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please input minor disabilities list:", "Med. records", src.active2.fields["mi_dis"], null) as text)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) - return - src.active2.fields["mi_dis"] = t1 - if("mi_dis_d") - if(istype(src.active2, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please summarize minor dis.:", "Med. records", src.active2.fields["mi_dis_d"], null) as message)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) - return - src.active2.fields["mi_dis_d"] = t1 - if("ma_dis") - if(istype(src.active2, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please input major diabilities list:", "Med. records", src.active2.fields["ma_dis"], null) as text)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) - return - src.active2.fields["ma_dis"] = t1 - if("ma_dis_d") - if(istype(src.active2, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please summarize major dis.:", "Med. records", src.active2.fields["ma_dis_d"], null) as message)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) - return - src.active2.fields["ma_dis_d"] = t1 - if("alg") - if(istype(src.active2, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please state allergies:", "Med. records", src.active2.fields["alg"], null) as text)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) - return - src.active2.fields["alg"] = t1 - if("alg_d") - if(istype(src.active2, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please summarize allergies:", "Med. records", src.active2.fields["alg_d"], null) as message)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) - return - src.active2.fields["alg_d"] = t1 - if("cdi") - if(istype(src.active2, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please state diseases:", "Med. records", src.active2.fields["cdi"], null) as text)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) - return - src.active2.fields["cdi"] = t1 - if("cdi_d") - if(istype(src.active2, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please summarize diseases:", "Med. records", src.active2.fields["cdi_d"], null) as message)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) - return - src.active2.fields["cdi_d"] = t1 - if("notes") - if(istype(src.active2, /datum/data/record)) - var/t1 = copytext(html_encode(trim(input("Please summarize notes:", "Med. records", html_decode(src.active2.fields["notes"]), null) as message)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) - return - src.active2.fields["notes"] = t1 - if("p_stat") - if(istype(src.active1, /datum/data/record)) - src.temp = "Physical Condition:
    \n\t*Deceased*
    \n\t*SSD*
    \n\tActive
    \n\tPhysically Unfit
    \n\tDisabled
    " - if("m_stat") - if(istype(src.active1, /datum/data/record)) - src.temp = "Mental Condition:
    \n\t*Insane*
    \n\t*Unstable*
    \n\t*Watch*
    \n\tStable
    " - if("b_type") - if(istype(src.active2, /datum/data/record)) - src.temp = "Blood Type:
    \n\tA- A+
    \n\tB- B+
    \n\tAB- AB+
    \n\tO- O+
    " - if("b_dna") - if(istype(src.active1, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please input DNA hash:", "Med. records", src.active1.fields["dna"], null) as text)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1)) - return - src.active1.fields["dna"] = t1 - if("vir_name") - var/datum/data/record/v = locate(href_list["edit_vir"]) - if(v) - var/t1 = copytext(trim(sanitize(input("Please input pathogen name:", "VirusDB", v.fields["name"], null) as text)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1)) - return - v.fields["name"] = t1 - if("vir_desc") - var/datum/data/record/v = locate(href_list["edit_vir"]) - if(v) - var/t1 = copytext(trim(sanitize(input("Please input information about pathogen:", "VirusDB", v.fields["description"], null) as message)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active1 != a1)) - return - v.fields["description"] = t1 - else - - if(href_list["p_stat"]) - if(src.active1) - switch(href_list["p_stat"]) - if("deceased") - src.active1.fields["p_stat"] = "*Deceased*" - if("ssd") - src.active1.fields["p_stat"] = "*SSD*" - if("active") - src.active1.fields["p_stat"] = "Active" - if("unfit") - src.active1.fields["p_stat"] = "Physically Unfit" - if("disabled") - src.active1.fields["p_stat"] = "Disabled" - - if(href_list["m_stat"]) - if(src.active1) - switch(href_list["m_stat"]) - if("insane") - src.active1.fields["m_stat"] = "*Insane*" - if("unstable") - src.active1.fields["m_stat"] = "*Unstable*" - if("watch") - src.active1.fields["m_stat"] = "*Watch*" - if("stable") - src.active1.fields["m_stat"] = "Stable" - - - if(href_list["b_type"]) - if(src.active2) - switch(href_list["b_type"]) - if("an") - src.active2.fields["b_type"] = "A-" - if("bn") - src.active2.fields["b_type"] = "B-" - if("abn") - src.active2.fields["b_type"] = "AB-" - if("on") - src.active2.fields["b_type"] = "O-" - if("ap") - src.active2.fields["b_type"] = "A+" - if("bp") - src.active2.fields["b_type"] = "B+" - if("abp") - src.active2.fields["b_type"] = "AB+" - if("op") - src.active2.fields["b_type"] = "O+" - - - if(href_list["del_r"]) - if(src.active2) - src.temp = "Are you sure you wish to delete the record (Medical Portion Only)?
    \n\tYes
    \n\tNo
    " - - if(href_list["del_r2"]) - if(src.active2) - //src.active2 = null - qdel(src.active2) - - if(href_list["d_rec"]) - var/datum/data/record/R = locate(href_list["d_rec"]) - var/datum/data/record/M = locate(href_list["d_rec"]) - if(!( data_core.general.Find(R) )) - src.temp = "Record Not Found!" - return - for(var/datum/data/record/E in data_core.medical) - if((E.fields["name"] == R.fields["name"] || E.fields["id"] == R.fields["id"])) - M = E - else - //Foreach continue //goto(2540) - src.active1 = R - src.active2 = M - src.screen = 4 - - if(href_list["new"]) - if((istype(src.active1, /datum/data/record) && !( istype(src.active2, /datum/data/record) ))) - var/datum/data/record/R = new /datum/data/record( ) - R.fields["name"] = src.active1.fields["name"] - R.fields["id"] = src.active1.fields["id"] - R.name = text("Medical Record #[]", R.fields["id"]) - R.fields["b_type"] = "Unknown" - R.fields["b_dna"] = "Unknown" - R.fields["mi_dis"] = "None" - R.fields["mi_dis_d"] = "No minor disabilities have been declared." - R.fields["ma_dis"] = "None" - R.fields["ma_dis_d"] = "No major disabilities have been diagnosed." - R.fields["alg"] = "None" - R.fields["alg_d"] = "No allergies have been detected in this patient." - R.fields["cdi"] = "None" - R.fields["cdi_d"] = "No diseases have been diagnosed at the moment." - R.fields["notes"] = "No notes." - data_core.medical += R - src.active2 = R - src.screen = 4 - - if(href_list["add_c"]) - if(!( istype(src.active2, /datum/data/record) )) - return - var/a2 = src.active2 - var/t1 = copytext(trim(sanitize(input("Add Comment:", "Med. records", null, null) as message)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( src.authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || src.active2 != a2)) - return - var/counter = 1 - while(src.active2.fields[text("com_[]", counter)]) - counter++ - src.active2.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [time2text(world.realtime, "DDD MMM DD hh:mm:ss")]
    [t1]") - - if(href_list["del_c"]) - if((istype(src.active2, /datum/data/record) && src.active2.fields[text("com_[]", href_list["del_c"])])) - src.active2.fields[text("com_[]", href_list["del_c"])] = "Deleted" - - if(href_list["search"]) - var/t1 = input("Search String: (Name, DNA, or ID)", "Med. records", null, null) as text - if((!( t1 ) || usr.stat || !( src.authenticated ) || usr.restrained() || ((!in_range(src, usr)) && (!istype(usr, /mob/living/silicon))))) - return - src.active1 = null - src.active2 = null - t1 = lowertext(t1) - for(var/datum/data/record/R in data_core.medical) - if((lowertext(R.fields["name"]) == t1 || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["b_dna"]))) - src.active2 = R - else - //Foreach continue //goto(3229) - if(!( src.active2 )) - src.temp = text("Could not locate record [].", t1) - else - for(var/datum/data/record/E in data_core.general) - if((E.fields["name"] == src.active2.fields["name"] || E.fields["id"] == src.active2.fields["id"])) - src.active1 = E + if(href_list["field"]) + if(incapable) + return 1 + var/a1 = active1 + var/a2 = active2 + switch(href_list["field"]) + if("fingerprint") + if(istype(active1, /datum/data/record)) + var/t1 = copytext(trim(sanitize(input("Please input fingerprint hash:", "Med. records", active1.fields["fingerprint"], null) as text)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active1 != a1) + return 1 + active1.fields["fingerprint"] = t1 + if("sex") + if(istype(active1, /datum/data/record)) + if(active1.fields["sex"] == "Male") + active1.fields["sex"] = "Female" else - //Foreach continue //goto(3334) - src.screen = 4 + active1.fields["sex"] = "Male" + if("age") + if(istype(active1, /datum/data/record)) + var/t1 = input("Please input age:", "Med. records", active1.fields["age"], null) as num + if(!t1 || incapable || active1 != a1) + return 1 + active1.fields["age"] = t1 + if("mi_dis") + if(istype(active2, /datum/data/record)) + var/t1 = copytext(trim(sanitize(input("Please input minor disabilities list:", "Med. records", active2.fields["mi_dis"], null) as text)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active2 != a2) + return 1 + active2.fields["mi_dis"] = t1 + if("mi_dis_d") + if(istype(active2, /datum/data/record)) + var/t1 = copytext(trim(sanitize(input("Please summarize minor dis.:", "Med. records", active2.fields["mi_dis_d"], null) as message)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active2 != a2) + return 1 + active2.fields["mi_dis_d"] = t1 + if("ma_dis") + if(istype(active2, /datum/data/record)) + var/t1 = copytext(trim(sanitize(input("Please input major diabilities list:", "Med. records", active2.fields["ma_dis"], null) as text)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active2 != a2) + return 1 + active2.fields["ma_dis"] = t1 + if("ma_dis_d") + if(istype(active2, /datum/data/record)) + var/t1 = copytext(trim(sanitize(input("Please summarize major dis.:", "Med. records", active2.fields["ma_dis_d"], null) as message)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active2 != a2) + return 1 + active2.fields["ma_dis_d"] = t1 + if("alg") + if(istype(active2, /datum/data/record)) + var/t1 = copytext(trim(sanitize(input("Please state allergies:", "Med. records", active2.fields["alg"], null) as text)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active2 != a2) + return 1 + active2.fields["alg"] = t1 + if("alg_d") + if(istype(active2, /datum/data/record)) + var/t1 = copytext(trim(sanitize(input("Please summarize allergies:", "Med. records", active2.fields["alg_d"], null) as message)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active2 != a2) + return 1 + active2.fields["alg_d"] = t1 + if("cdi") + if(istype(active2, /datum/data/record)) + var/t1 = copytext(trim(sanitize(input("Please state diseases:", "Med. records", active2.fields["cdi"], null) as text)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active2 != a2) + return 1 + active2.fields["cdi"] = t1 + if("cdi_d") + if(istype(active2, /datum/data/record)) + var/t1 = copytext(trim(sanitize(input("Please summarize diseases:", "Med. records", active2.fields["cdi_d"], null) as message)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active2 != a2) + return 1 + active2.fields["cdi_d"] = t1 + if("notes") + if(istype(active2, /datum/data/record)) + var/t1 = copytext(html_encode(trim(input("Please summarize notes:", "Med. records", html_decode(active2.fields["notes"]), null) as message)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active2 != a2) + return 1 + active2.fields["notes"] = t1 + if("p_stat") + if(istype(active1, /datum/data/record)) + var/list/buttons = list() + buttons[++buttons.len] = list("name" = "*Deceased*", "icon" = "stethoscope", "href" = "p_stat=deceased", "status" = (active1.fields["p_stat"] == "*Deceased*" ? "selected" : null)) + buttons[++buttons.len] = list("name" = "*SSD*", "icon" = "stethoscope", "href" = "p_stat=ssd", "status" = (active1.fields["p_stat"] == "*SSD*" ? "selected" : null)) + buttons[++buttons.len] = list("name" = "Active", "icon" = "stethoscope", "href" = "p_stat=active", "status" = (active1.fields["p_stat"] == "Active" ? "selected" : null)) + buttons[++buttons.len] = list("name" = "Physically Unfit", "icon" = "stethoscope", "href" = "p_stat=unfit", "status" = (active1.fields["p_stat"] == "Physically Unfit" ? "selected" : null)) + buttons[++buttons.len] = list("name" = "Disabled", "icon" = "stethoscope", "href" = "p_stat=disabled", "status" = (active1.fields["p_stat"] == "Disabled" ? "selected" : null)) + setTemp("

    Physical Condition

    ", buttons) + if("m_stat") + if(istype(active1, /datum/data/record)) + var/list/buttons = list() + buttons[++buttons.len] = list("name" = "*Insane*", "icon" = "stethoscope", "href" = "m_stat=insane", "status" = (active1.fields["m_stat"] == "*Insane*" ? "selected" : null)) + buttons[++buttons.len] = list("name" = "*Unstable*", "icon" = "stethoscope", "href" = "m_stat=unstable", "status" = (active1.fields["m_stat"] == "*Unstable*" ? "selected" : null)) + buttons[++buttons.len] = list("name" = "*Watch*", "icon" = "stethoscope", "href" = "m_stat=watch", "status" = (active1.fields["m_stat"] == "*Watch*" ? "selected" : null)) + buttons[++buttons.len] = list("name" = "Stable", "icon" = "stethoscope", "href" = "m_stat=stable", "status" = (active1.fields["m_stat"] == "Stable" ? "selected" : null)) + setTemp("

    Mental Condition

    ", buttons) + if("b_type") + if(istype(active2, /datum/data/record)) + var/list/buttons = list() + buttons[++buttons.len] = list("name" = "A-", "icon" = "tint", "href" = "b_type=an", "status" = (active2.fields["b_type"] == "A-" ? "selected" : null)) + buttons[++buttons.len] = list("name" = "A+", "icon" = "tint", "href" = "b_type=ap", "status" = (active2.fields["b_type"] == "A+" ? "selected" : null)) + buttons[++buttons.len] = list("name" = "B-", "icon" = "tint", "href" = "b_type=bn", "status" = (active2.fields["b_type"] == "B-" ? "selected" : null)) + buttons[++buttons.len] = list("name" = "B+", "icon" = "tint", "href" = "b_type=bp", "status" = (active2.fields["b_type"] == "B+" ? "selected" : null)) + buttons[++buttons.len] = list("name" = "AB-", "icon" = "tint", "href" = "b_type=abn", "status" = (active2.fields["b_type"] == "AB-" ? "selected" : null)) + buttons[++buttons.len] = list("name" = "AB+", "icon" = "tint", "href" = "b_type=abp", "status" = (active2.fields["b_type"] == "AB+" ? "selected" : null)) + buttons[++buttons.len] = list("name" = "O-", "icon" = "tint", "href" = "b_type=on", "status" = (active2.fields["b_type"] == "O-" ? "selected" : null)) + buttons[++buttons.len] = list("name" = "O+", "icon" = "tint", "href" = "b_type=op", "status" = (active2.fields["b_type"] == "O+" ? "selected" : null)) + setTemp("

    Blood Type

    ", buttons) + if("b_dna") + if(istype(active2, /datum/data/record)) + var/t1 = copytext(trim(sanitize(input("Please input DNA hash:", "Med. records", active2.fields["b_dna"], null) as text)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active2 != a2) + return 1 + active2.fields["b_dna"] = t1 + if("vir_name") + var/datum/data/record/v = locate(href_list["edit_vir"]) + if(v) + var/t1 = copytext(trim(sanitize(input("Please input pathogen name:", "VirusDB", v.fields["name"], null) as text)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active1 != a1) + return 1 + v.fields["name"] = t1 + if("vir_desc") + var/datum/data/record/v = locate(href_list["edit_vir"]) + if(v) + var/t1 = copytext(trim(sanitize(input("Please input information about pathogen:", "VirusDB", v.fields["description"], null) as message)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active1 != a1) + return 1 + v.fields["description"] = t1 - if(href_list["print_p"]) - if(!( src.printing )) - src.printing = 1 - playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1) - sleep(50) - var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( src.loc ) - P.info = "
    Medical Record

    " - if((istype(src.active1, /datum/data/record) && data_core.general.Find(src.active1))) - P.info += text("Name: [] ID: []
    \nSex: []
    \nAge: []
    \nFingerprint: []
    \nPhysical Status: []
    \nMental Status: []
    ", src.active1.fields["name"], src.active1.fields["id"], src.active1.fields["sex"], src.active1.fields["age"], src.active1.fields["fingerprint"], src.active1.fields["p_stat"], src.active1.fields["m_stat"]) - else - P.info += "General Record Lost!
    " - if((istype(src.active2, /datum/data/record) && data_core.medical.Find(src.active2))) - P.info += text("
    \n
    Medical Data

    \nBlood Type: []
    \nDNA: []
    \n
    \nMinor Disabilities: []
    \nDetails: []
    \n
    \nMajor Disabilities: []
    \nDetails: []
    \n
    \nAllergies: []
    \nDetails: []
    \n
    \nCurrent Diseases: [] (per disease info placed in log/comment section)
    \nDetails: []
    \n
    \nImportant Notes:
    \n\t[]
    \n
    \n
    Comments/Log

    ", src.active2.fields["b_type"], src.active2.fields["b_dna"], src.active2.fields["mi_dis"], src.active2.fields["mi_dis_d"], src.active2.fields["ma_dis"], src.active2.fields["ma_dis_d"], src.active2.fields["alg"], src.active2.fields["alg_d"], src.active2.fields["cdi"], src.active2.fields["cdi_d"], src.active2.fields["notes"]) - var/counter = 1 - while(src.active2.fields[text("com_[]", counter)]) - P.info += text("[]
    ", src.active2.fields[text("com_[]", counter)]) - counter++ - else - P.info += "Medical Record Lost!
    " - P.info += "
    " - P.name = "paper- 'Medical Record'" - src.printing = null + if(href_list["del_r"]) + if(active2) + var/list/buttons = list() + buttons[++buttons.len] = list("name" = "Yes", "icon" = "check", "href" = "del_r2=1", "status" = null) + buttons[++buttons.len] = list("name" = "No", "icon" = "times", "href" = null, "status" = null) + setTemp("

    Are you sure you wish to delete the record (Medical Portion Only)?

    ", buttons) - src.add_fingerprint(usr) - src.updateUsrDialog() - return + if(href_list["d_rec"]) + var/datum/data/record/R = locate(href_list["d_rec"]) + var/datum/data/record/M = locate(href_list["d_rec"]) + if(!data_core.general.Find(R)) + temp = list("text" = "

    Record not found!

    ", "buttons" = list()) + return 1 + for(var/datum/data/record/E in data_core.medical) + if(E.fields["name"] == R.fields["name"] && E.fields["id"] == R.fields["id"]) + M = E + active1 = R + active2 = M + screen = MED_DATA_RECORD + + if(href_list["new"]) + if(istype(active1, /datum/data/record) && !istype(active2, /datum/data/record)) + var/datum/data/record/R = new /datum/data/record() + R.fields["name"] = active1.fields["name"] + R.fields["id"] = active1.fields["id"] + R.name = "Medical Record #[R.fields["id"]]" + R.fields["b_type"] = "Unknown" + R.fields["b_dna"] = "Unknown" + R.fields["mi_dis"] = "None" + R.fields["mi_dis_d"] = "No minor disabilities have been declared." + R.fields["ma_dis"] = "None" + R.fields["ma_dis_d"] = "No major disabilities have been diagnosed." + R.fields["alg"] = "None" + R.fields["alg_d"] = "No allergies have been detected in this patient." + R.fields["cdi"] = "None" + R.fields["cdi_d"] = "No diseases have been diagnosed at the moment." + R.fields["notes"] = "No notes." + data_core.medical += R + active2 = R + screen = MED_DATA_RECORD + + if(href_list["add_c"]) + if(!istype(active2, /datum/data/record)) + return 1 + var/a2 = active2 + var/t1 = copytext(trim(sanitize(input("Add Comment:", "Med. records", null, null) as message)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active2 != a2) + return 1 + active2.fields["comments"] += "Made by [authenticated] ([rank]) on [current_date_string] [worldtime2text()]
    [t1]" + + if(href_list["del_c"]) + var/index = min(max(text2num(href_list["del_c"]) + 1, 1), length(active2.fields["comments"])) + if(istype(active2, /datum/data/record) && active2.fields["comments"][index]) + active2.fields["comments"] -= active2.fields["comments"][index] + + if(href_list["search"]) + var/t1 = input("Search String: (Name, DNA, or ID)", "Med. records", null, null) as text + if(!t1 || incapable) + return 1 + active1 = null + active2 = null + t1 = lowertext(t1) + for(var/datum/data/record/R in data_core.medical) + if(t1 == lowertext(R.fields["name"]) || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["b_dna"])) + active2 = R + if(!active2) + temp = list("text" = "

    Could not locate record [t1].

    ") + else + for(var/datum/data/record/E in data_core.general) + if(E.fields["name"] == active2.fields["name"] && E.fields["id"] == active2.fields["id"]) + active1 = E + screen = MED_DATA_RECORD + + if(href_list["print_p"]) + if(!printing) + printing = 1 + playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1) + sleep(50) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(loc) + P.info = "
    Medical Record

    " + if(istype(active1, /datum/data/record) && data_core.general.Find(active1)) + P.info += {"Name: [active1.fields["name"]] ID: [active1.fields["id"]] +
    \nSex: [active1.fields["sex"]] +
    \nAge: [active1.fields["age"]] +
    \nFingerprint: [active1.fields["fingerprint"]] +
    \nPhysical Status: [active1.fields["p_stat"]] +
    \nMental Status: [active1.fields["m_stat"]]
    "} + else + P.info += "General Record Lost!
    " + if(istype(active2, /datum/data/record) && data_core.medical.Find(active2)) + P.info += {"
    \n
    Medical Data
    +
    \nBlood Type: [active2.fields["b_type"]] +
    \nDNA: [active2.fields["b_dna"]]
    \n +
    \nMinor Disabilities: [active2.fields["mi_dis"]] +
    \nDetails: [active2.fields["mi_dis_d"]]
    \n +
    \nMajor Disabilities: [active2.fields["ma_dis"]] +
    \nDetails: [active2.fields["ma_dis_d"]]
    \n +
    \nAllergies: [active2.fields["alg"]] +
    \nDetails: [active2.fields["alg_d"]]
    \n +
    \nCurrent Diseases: [active2.fields["cdi"]] (per disease info placed in log/comment section) +
    \nDetails: [active2.fields["cdi_d"]]
    \n +
    \nImportant Notes: +
    \n\t[active2.fields["notes"]]
    \n +
    \n +
    Comments/Log

    "} + for(var/c in active2.fields["comments"]) + P.info += "[c]
    " + else + P.info += "Medical Record Lost!
    " + P.info += "
    " + P.name = "paper- 'Medical Record'" + printing = 0 + return 1 + +/obj/machinery/computer/med_data/proc/setTemp(text, list/buttons = list()) + temp = list("text" = text, "buttons" = buttons, "has_buttons" = buttons.len > 0) /obj/machinery/computer/med_data/emp_act(severity) if(stat & (BROKEN|NOPOWER)) - ..(severity) - return + return ..(severity) for(var/datum/data/record/R in data_core.medical) if(prob(10/severity)) @@ -500,7 +535,7 @@ if(1) R.fields["name"] = "[pick(pick(first_names_male), pick(first_names_female))] [pick(last_names)]" if(2) - R.fields["sex"] = pick("Male", "Female") + R.fields["sex"] = pick("Male", "Female") if(3) R.fields["age"] = rand(5, 85) if(4) @@ -525,3 +560,10 @@ icon_keyboard = "laptop_key" icon_screen = "medlaptop" density = 0 + +#undef MED_DATA_MAIN +#undef MED_DATA_R_LIST +#undef MED_DATA_MAINT +#undef MED_DATA_RECORD +#undef MED_DATA_V_DATA +#undef MED_DATA_MEDBOT \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 7e54aebf396..c3cec37da1a 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1049,12 +1049,11 @@ if(R.fields["id"] == E.fields["id"]) if(hasHUD(usr,"medical")) read = 1 - var/counter = 1 - while(R.fields[text("com_[]", counter)]) - to_chat(usr, text("[]", R.fields[text("com_[]", counter)])) - counter++ - if(counter == 1) - to_chat(usr, "No comment found") + if(length(R.fields["comments"])) + for(var/c in R.fields["comments"]) + to_chat(usr, c) + else + to_chat(usr, "No comment found") to_chat(usr, "\[Add comment\]") if(!read) @@ -1076,18 +1075,15 @@ for(var/datum/data/record/R in data_core.medical) if(R.fields["id"] == E.fields["id"]) if(hasHUD(usr,"medical")) - var/t1 = sanitize(copytext(input("Add Comment:", "Med. records", null, null) as message,1,MAX_MESSAGE_LEN)) - if( !(t1) || usr.stat || usr.restrained() || !(hasHUD(usr,"medical")) ) + var/t1 = copytext(trim(sanitize(input("Add Comment:", "Med. records", null, null) as message)), 1, MAX_MESSAGE_LEN) + if(!t1 || usr.stat || usr.restrained() || !hasHUD(usr, "medical")) return - var/counter = 1 - while(R.fields[text("com_[]", counter)]) - counter++ - if(istype(usr,/mob/living/carbon/human)) + if(ishuman(usr)) var/mob/living/carbon/human/U = usr - R.fields[text("com_[counter]")] = text("Made by [U.get_authentification_name()] ([U.get_assignment()]) on [time2text(world.realtime, "DDD MMM DD hh:mm:ss")], [game_year]
    [t1]") - if(istype(usr,/mob/living/silicon/robot)) + R.fields["comments"] += "Made by [U.get_authentification_name()] ([U.get_assignment()]) on [current_date_string] [worldtime2text()]
    [t1]" + if(isrobot(usr)) var/mob/living/silicon/robot/U = usr - R.fields[text("com_[counter]")] = text("Made by [U.name] ([U.modtype] [U.braintype]) on [time2text(world.realtime, "DDD MMM DD hh:mm:ss")], [game_year]
    [t1]") + R.fields["comments"] += "Made by [U.name] ([U.modtype] [U.braintype]) on [current_date_string] [worldtime2text()]
    [t1]" if(href_list["lookitem"]) var/obj/item/I = locate(href_list["lookitem"]) diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index 0fe3a6e75a4..7f821f3779e 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -146,17 +146,15 @@ for(var/datum/data/record/G in data_core.general) var/datum/data/record/M for(var/datum/data/record/R in data_core.medical) - if((R.fields["name"] == G.fields["name"] || R.fields["id"] == G.fields["id"])) + if(R.fields["name"] == G.fields["name"] || R.fields["id"] == G.fields["id"]) M = R break var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(src) P.info = "
    Medical Record

    " P.info += "Name: [G.fields["name"]] ID: [G.fields["id"]]
    \nSex: [G.fields["sex"]]
    \nAge: [G.fields["age"]]
    \nFingerprint: [G.fields["fingerprint"]]
    \nPhysical Status: [G.fields["p_stat"]]
    \nMental Status: [G.fields["m_stat"]]
    " P.info += "
    \n
    Medical Data

    \nBlood Type: [M.fields["b_type"]]
    \nDNA: [M.fields["b_dna"]]
    \n
    \nMinor Disabilities: [M.fields["mi_dis"]]
    \nDetails: [M.fields["mi_dis_d"]]
    \n
    \nMajor Disabilities: [M.fields["ma_dis"]]
    \nDetails: [M.fields["ma_dis_d"]]
    \n
    \nAllergies: [M.fields["alg"]]
    \nDetails: [M.fields["alg_d"]]
    \n
    \nCurrent Diseases: [M.fields["cdi"]] (per disease info placed in log/comment section)
    \nDetails: [M.fields["cdi_d"]]
    \n
    \nImportant Notes:
    \n\t[M.fields["notes"]]
    \n
    \n
    Comments/Log

    " - var/counter = 1 - while(M.fields["com_[counter]"]) - P.info += "[M.fields["com_[counter]"]]
    " - counter++ + for(var/c in M.fields["comments"]) + P.info += "[c]
    " P.info += "
    " P.name = "paper - '[G.fields["name"]]'" virgin = 0 //tabbing here is correct- it's possible for people to try and use it diff --git a/nano/templates/med_data.tmpl b/nano/templates/med_data.tmpl new file mode 100644 index 00000000000..f47e13c6885 --- /dev/null +++ b/nano/templates/med_data.tmpl @@ -0,0 +1,171 @@ + + + + +
    +
    + Confirm Identity: +
    +
    + {{:helper.link(data.scan ? data.scan : "----------", 'eject', {'scan' : 1}, null, data.scan ? 'itemContentWide' : 'fixedLeft')}} +
    +
    +
    +{{if data.authenticated}} + {{if data.screen == 1}} +

    Menu

    +
    +
    {{:helper.link('Search Records', 'search', {'search' : 1})}}
    +
    {{:helper.link('List Records', 'list', {'screen' : 2})}}
    +
    {{:helper.link('Virus Database', 'database', {'screen' : 5})}}
    +
    {{:helper.link('Medbot Tracking', 'plus-square', {'screen' : 6})}}
    +
    {{:helper.link('Record Maintenance', 'wrench', {'screen' : 3})}}
    +
    {{:helper.link('Logout', 'lock', {'logout' : 1})}}
    +
    + {{else data.screen == 2}} +

    Record List

    + {{for data.records}} +
    {{:helper.link(value.id + ': ' + value.name, 'user', {'d_rec' : value.ref})}}
    + {{/for}} +

    +
    {{:helper.link('Back', 'arrow-left', {'screen' : 1})}}
    + {{else data.screen == 3}} +

    Records Maintenance

    +
    {{:helper.link('Backup To Disk', 'download', {'back' : 1}, 'disabled')}}
    +
    {{:helper.link('Upload From disk', 'upload', {'u_load' : 1}, 'disabled')}}
    +
    {{:helper.link('Delete All Records', 'trash', {'del_all' : 1})}}
    +
    {{:helper.link('Back', 'arrow-left', {'screen' : 1})}}
    + {{else data.screen == 4}} +

    Medical Record

    +

    General Data

    + {{if data.general.empty}} +
    General Record Lost!
    + {{else}} +
    + + + +
    + {{for data.general.fields}} +
    +
    {{:value.field}}
    +
    {{:helper.link(value.value, value.edit ? 'pencil' : 'user-times', {'field' : value.edit}, value.edit ? null : 'disabled')}}
    +
    + {{/for}} +
    + {{if data.general.has_photos}} + {{for data.general.photos}} + {{if value.photo}} + + {{/if}} + {{/for}} + {{/if}} +
    +
    + {{/if}} + +

    Medical Data

    + {{if data.medical.empty}} +
    Medical Record Lost!
    +
    +
    {{:helper.link('New Record', 'plus', {'new' : 1})}}
    +
    +

    Menu

    + {{else}} + {{for data.medical.fields}} +
    +
    {{:value.field}}
    +
    {{:helper.link(value.value, 'pencil', {'field' : value.edit})}}
    +
    + {{if value.line_break}} +
    + {{/if}} + {{/for}} + +

    Comments/Log

    + {{for data.medical.comments}} +
    {{:value}}
    +
    {{:helper.link('Remove entry', 'trash', {'del_c' : index})}}
    +

    + {{/for}} + +
    +
    {{:helper.link('Add Entry', 'plus', {'add_c' : 1})}}
    +
    + +

    Menu

    +
    {{:helper.link('Delete Record (Medical Only)', 'trash', {'del_r' : 1})}}
    + {{/if}} + +
    {{:helper.link('Print Record', 'print', {'print_p' : 1})}}
    +
    {{:helper.link('Back', 'arrow-left', {'screen' : 2})}}
    + {{else data.screen == 5}} +

    Virus Database

    + {{for data.virus}} +
    {{:helper.link(value.name, 'arrow-right', {'vir' : value.D})}}
    + {{/for}} +

    + {{:helper.link('Back', 'arrow-left', {'screen' : 1})}} + {{else data.screen == 6}} +

    Medical Robot Monitor

    + {{for data.medbots}} +

    {{:value.name}}

    +
    +
    Location:
    +
    {{:value.x}}, {{:value.y}}
    +
    +
    +
    Status:
    +
    + {{:value.on ? "Online" : "Offline"}}. {{if value.use_beaker}}Reservoir: [{{:value.total_volume}}/{{:value.maximum_volume}}]{{else}}Using internal synthesizer.{{/if}} +
    +
    +
    + {{empty}} +

    None detected!

    + {{/for}} +
    {{:helper.link('Back', 'arrow-left', {'screen' : 1})}}
    + {{/if}} +{{else}} +

    Menu

    + {{:helper.link('Login', 'unlock', {'login' : 1})}} +{{/if}} + +{{if data.temp}} +
    +
    + {{if data.temp.notice}} +
    {{:data.temp.text}}
    + {{else}} +
    {{:data.temp.text}}
    + {{/if}} + + + {{if data.temp.has_buttons}} +
    +
    +
    + {{for data.temp.buttons}} + {{:helper.link(value.name, value.icon, {'temp' : 1, 'temp_action' : value.href}, value.status)}} + {{/for}} +
    +
    +
    + {{/if}} + +
    +
    {{:helper.link('Clear screen', 'home', {'temp' : 1})}}
    +
    +
    +
    +{{/if}} \ No newline at end of file From 4615c94bcd667501b29b569895de22583bde6322 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 18 Feb 2017 11:55:58 -0500 Subject: [PATCH 059/164] Automatic changelog compile, [ci skip] --- html/changelog.html | 10 ++++++++++ html/changelogs/.all_changelog.yml | 12 ++++++++++++ html/changelogs/AutoChangeLog-pr-6369.yml | 5 ----- html/changelogs/AutoChangeLog-pr-6480.yml | 4 ---- html/changelogs/AutoChangeLog-pr-6496.yml | 4 ---- 5 files changed, 22 insertions(+), 13 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-6369.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-6480.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-6496.yml diff --git a/html/changelog.html b/html/changelog.html index 7e7bda4afb2..a0c2cfa1aa4 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -70,6 +70,16 @@
    • Added a 'take' option to ahelps/mhelps, so admins/mentors can quickly let the asker know their question is being looked at.
    +

    Markolie updated:

    +
      +
    • Vending machines, newscasters, biogenerators, plant DNA manipulators, seed extractors, bots, fax machines, photocopiers, AI slippers, cell door timers, airlocks, pipe dispensers and atmospherics machinery that open a window can now be viewed by ghosts.
    • +
    • Admins can now interact with mass driver, crematorium, ignition, light, flashers and flasher switches and door switches, as well as airlocks, windoors, firedoors and atmospherics machinery that do not open a window if they have advanced admin interaction enabled (under the "Admin" tab).
    • +
    • Slicing disposal pipes now shows a progress bar.
    • +
    +

    uraniummeltdown updated:

    +
      +
    • Shuttle engines have new sprites.
    • +

    17 February 2017

    Crazylemon64 updated:

    diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 9464e5a3672..7e0cb591f66 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -3767,3 +3767,15 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. Kyep: - rscadd: Added a 'take' option to ahelps/mhelps, so admins/mentors can quickly let the asker know their question is being looked at. + Markolie: + - rscadd: Vending machines, newscasters, biogenerators, plant DNA manipulators, + seed extractors, bots, fax machines, photocopiers, AI slippers, cell door timers, + airlocks, pipe dispensers and atmospherics machinery that open a window can + now be viewed by ghosts. + - rscadd: Admins can now interact with mass driver, crematorium, ignition, light, + flashers and flasher switches and door switches, as well as airlocks, windoors, + firedoors and atmospherics machinery that do not open a window if they have + advanced admin interaction enabled (under the "Admin" tab). + - bugfix: Slicing disposal pipes now shows a progress bar. + uraniummeltdown: + - rscadd: Shuttle engines have new sprites. diff --git a/html/changelogs/AutoChangeLog-pr-6369.yml b/html/changelogs/AutoChangeLog-pr-6369.yml deleted file mode 100644 index cd5c824a8c6..00000000000 --- a/html/changelogs/AutoChangeLog-pr-6369.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Markolie" -delete-after: True -changes: - - rscadd: "Vending machines, newscasters, biogenerators, plant DNA manipulators, seed extractors, bots, fax machines, photocopiers, AI slippers, cell door timers, airlocks, pipe dispensers and atmospherics machinery that open a window can now be viewed by ghosts." - - rscadd: "Admins can now interact with mass driver, crematorium, ignition, light, flashers and flasher switches and door switches, as well as airlocks, windoors, firedoors and atmospherics machinery that do not open a window if they have advanced admin interaction enabled (under the \"Admin\" tab)." diff --git a/html/changelogs/AutoChangeLog-pr-6480.yml b/html/changelogs/AutoChangeLog-pr-6480.yml deleted file mode 100644 index e9f42bed2ee..00000000000 --- a/html/changelogs/AutoChangeLog-pr-6480.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "uraniummeltdown" -delete-after: True -changes: - - rscadd: "Shuttle engines have new sprites." diff --git a/html/changelogs/AutoChangeLog-pr-6496.yml b/html/changelogs/AutoChangeLog-pr-6496.yml deleted file mode 100644 index be3aa93ccd4..00000000000 --- a/html/changelogs/AutoChangeLog-pr-6496.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Markolie" -delete-after: True -changes: - - bugfix: "Slicing disposal pipes now shows a progress bar." From 7b7d5673a3714000797fc2d4561ba590685bba3c Mon Sep 17 00:00:00 2001 From: davipatury Date: Sat, 18 Feb 2017 15:01:09 -0200 Subject: [PATCH 060/164] Oops. --- code/game/machinery/computer/medical.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index da42cc740ca..79696fe1c9d 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -153,7 +153,7 @@ if("del_all2") for(var/datum/data/record/R in data_core.medical) qdel(R) - temp = list("text" = "All records deleted.", "buttons" = list()) + setTemp("

    All records deleted.

    ") if("p_stat") if(active1) switch(temp_href[2]) @@ -419,7 +419,7 @@ var/datum/data/record/R = locate(href_list["d_rec"]) var/datum/data/record/M = locate(href_list["d_rec"]) if(!data_core.general.Find(R)) - temp = list("text" = "

    Record not found!

    ", "buttons" = list()) + setTemp("

    Record not found!

    ") return 1 for(var/datum/data/record/E in data_core.medical) if(E.fields["name"] == R.fields["name"] && E.fields["id"] == R.fields["id"]) @@ -474,7 +474,7 @@ if(t1 == lowertext(R.fields["name"]) || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["b_dna"])) active2 = R if(!active2) - temp = list("text" = "

    Could not locate record [t1].

    ") + setTemp("

    Could not locate record [t1].

    ") else for(var/datum/data/record/E in data_core.general) if(E.fields["name"] == active2.fields["name"] && E.fields["id"] == active2.fields["id"]) From 98140635f0e7e43d8c2e84058faa47a38d5a2683 Mon Sep 17 00:00:00 2001 From: Markolie Date: Sat, 18 Feb 2017 19:09:24 +0100 Subject: [PATCH 061/164] Fix secure vending machine and newscaster interaction --- code/game/machinery/newscaster.dm | 14 +++++++------- code/game/machinery/vending.dm | 5 +++-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm index 7f2c1706cbc..4c14df16ec3 100644 --- a/code/game/machinery/newscaster.dm +++ b/code/game/machinery/newscaster.dm @@ -938,19 +938,19 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co ////////////////////////////////////helper procs -/obj/machinery/newscaster/proc/scan_user(mob/user as mob) +/obj/machinery/newscaster/proc/scan_user(mob/user) if(ishuman(user)) //User is a human var/mob/living/carbon/human/human_user = user if(human_user.wear_id) //Newscaster scans you - if(istype(human_user.wear_id, /obj/item/device/pda) ) //autorecognition, woo! + if(istype(human_user.wear_id, /obj/item/device/pda)) //autorecognition, woo! var/obj/item/device/pda/P = human_user.wear_id if(P.id) scanned_user = "[P.id.registered_name] ([P.id.assignment])" else scanned_user = "Unknown" - else if(istype(human_user.wear_id, /obj/item/weapon/card/id) ) + else if(istype(human_user.wear_id, /obj/item/weapon/card/id)) var/obj/item/weapon/card/id/ID = human_user.wear_id - scanned_user ="[ID.registered_name] ([ID.assignment])" + scanned_user = "[ID.registered_name] ([ID.assignment])" else scanned_user = "Unknown" else @@ -961,10 +961,10 @@ var/list/obj/machinery/newscaster/allCasters = list() //Global list that will co else scanned_user = "Unknown" -/obj/machinery/newscaster/proc/can_scan(mob/user as mob) +/obj/machinery/newscaster/proc/can_scan(mob/user) if(ishuman(user) || issilicon(user)) - . = TRUE - . = FALSE + return TRUE + return FALSE /obj/machinery/newscaster/proc/print_paper() feedback_inc("newscaster_newspapers_printed",1) diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 474eb44bcda..f45daee2af5 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -498,7 +498,7 @@ to_chat(usr, "The vending machine refuses to interface with you, as you are not in its target demographic!") return - if((!allowed(usr) && !usr.can_admin_interact()) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH + if(!allowed(usr) && !usr.can_admin_interact() && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH to_chat(usr, "Access denied.") //Unless emagged of course flick(icon_deny,src) return @@ -531,7 +531,7 @@ nanomanager.update_uis(src) /obj/machinery/vending/proc/vend(datum/data/vending_product/R, mob/user) - if((!allowed(usr) || !usr.can_admin_interact()) && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH + if(!allowed(usr) && !usr.can_admin_interact() && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH to_chat(usr, "Access denied.")//Unless emagged of course flick(icon_deny,src) return @@ -539,6 +539,7 @@ if(!R.amount) to_chat(user, "The vending machine has ran out of that product.") return + vend_ready = 0 //One thing at a time!! status_message = "Vending..." status_error = 0 From f9d55844fb1a5bcffa9a9875ebac410eaa634ca8 Mon Sep 17 00:00:00 2001 From: davipatury Date: Sat, 18 Feb 2017 16:34:28 -0200 Subject: [PATCH 062/164] Employment Records nano-ui. --- code/game/machinery/computer/skills.dm | 589 +++++++++++-------------- nano/templates/skills_data.tmpl | 199 +++++++++ 2 files changed, 451 insertions(+), 337 deletions(-) create mode 100644 nano/templates/skills_data.tmpl diff --git a/code/game/machinery/computer/skills.dm b/code/game/machinery/computer/skills.dm index 384e9e80179..da754bf9937 100644 --- a/code/game/machinery/computer/skills.dm +++ b/code/game/machinery/computer/skills.dm @@ -1,4 +1,6 @@ -//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 +#define SKILL_DATA_R_LIST 1 // Record list +#define SKILL_DATA_MAINT 2 // Records maintenance +#define SKILL_DATA_RECORD 3 // Record /obj/machinery/computer/skills//TODO:SANITY name = "employment records console" @@ -15,372 +17,281 @@ var/rank = null var/screen = null var/datum/data/record/active1 = null - var/a_id = null var/temp = null var/printing = null - var/can_change_id = 0 - var/list/Perp - var/tempname = null //Sorting Variables var/sortBy = "name" var/order = 1 // -1 = Descending - 1 = Ascending -/obj/machinery/computer/skills/attackby(obj/item/O as obj, user as mob, params) +/obj/machinery/computer/skills/attackby(obj/item/O, mob/user, params) if(istype(O, /obj/item/weapon/card/id) && !scan) - usr.drop_item() - O.loc = src + user.drop_item() + O.forceMove(src) scan = O - to_chat(user, "You insert [O].") + ui_interact(user) ..() -/obj/machinery/computer/skills/attack_ai(mob/user as mob) - return attack_hand(user) - //Someone needs to break down the dat += into chunks instead of long ass lines. -/obj/machinery/computer/skills/attack_hand(mob/user as mob) +/obj/machinery/computer/skills/attack_hand(mob/user) if(..()) return - - if(is_away_level(src.z)) + if(is_away_level(z)) to_chat(user, "Unable to establish a connection: You're too far away from the station!") return - var/dat + add_fingerprint(user) + ui_interact(user) - if(temp) - dat = "[temp]

    Clear Screen" - else - dat = text("Confirm Identity: []
    ", (scan ? text("[]", scan.name) : "----------")) - if(authenticated) - switch(screen) - if(1.0) - dat += {" -

    "} - dat += "Search Records
    " - dat += "New Record
    " - dat += {" -

    - - - - -
    Records:
    - - - - - - -"} - if(!isnull(data_core.general)) - for(var/datum/data/record/R in sortRecord(data_core.general, sortBy, order)) - for(var/datum/data/record/E in data_core.security) - var/background - dat += text("", background, R, R.fields["name"]) - dat += text("", R.fields["id"]) - dat += text("", R.fields["rank"]) - dat += text("", R.fields["fingerprint"]) - dat += "
    NameIDRankFingerprints
    [][][][]

    " - dat += "Record Maintenance

    " - dat += "{Log Out}" - if(2.0) - dat += "Records Maintenance
    " - dat += "
    Delete All Records

    Back" - if(3.0) - dat += "
    Employment Record

    " - if((istype(active1, /datum/data/record) && data_core.general.Find(active1))) - dat += text(" \ -
    \ - Name: [active1.fields["name"]]
    \ - ID: [active1.fields["id"]]
    \n \ - Sex: [active1.fields["sex"]]
    \n \ - Age: [active1.fields["age"]]
    \n \ - Rank: [active1.fields["rank"]]
    \n \ - Fingerprint: [active1.fields["fingerprint"]]
    \n \ - Physical Status: [active1.fields["p_stat"]]
    \n \ - Mental Status: [active1.fields["m_stat"]]

    \n \ - Employment/skills summary:
    [active1.fields["notes"]]
    Photo:
    \ -
    ") - else - dat += "General Record Lost!
    " - dat += "\nDelete Record (ALL)

    \nPrint Record
    \nBack
    " - if(4.0) - if(!Perp.len) - dat += "ERROR. String could not be located.

    Back" - else - dat += {" - - "} - dat += text("", tempname) - dat += {" - -
    Search Results for '[]':
    - - - - - - - "} - for(var/i=1, i<=Perp.len, i += 2) - var/crimstat = "" - var/datum/data/record/R = Perp[i] - if(istype(Perp[i+1],/datum/data/record/)) - var/datum/data/record/E = Perp[i+1] - crimstat = E.fields["criminal"] - var/background - background = "'background-color:#00FF7F;'" - dat += text("", background, R, R.fields["name"]) - dat += text("", R.fields["id"]) - dat += text("", R.fields["rank"]) - dat += text("", R.fields["fingerprint"]) - dat += text("", crimstat) - dat += "
    NameIDRankFingerprints
    [][][][][]

    " - dat += "
    Return to index." +/obj/machinery/computer/skills/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "skills_data.tmpl", name, 800, 380) + ui.open() + +/obj/machinery/computer/skills/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) + var/data[0] + data["temp"] = temp + data["scan"] = scan ? scan.name : null + data["authenticated"] = authenticated + data["screen"] = screen + if(authenticated) + switch(screen) + if(SKILL_DATA_R_LIST) + if(!isnull(data_core.general)) + for(var/datum/data/record/R in sortRecord(data_core.general, sortBy, order)) + data["records"] += list(list("ref" = "\ref[R]", "id" = R.fields["id"], "name" = R.fields["name"], "rank" = R.fields["rank"], "fingerprint" = R.fields["fingerprint"])) + if(SKILL_DATA_RECORD) + var/list/general = list() + data["general"] = general + if(istype(active1, /datum/data/record) && data_core.general.Find(active1)) + var/list/fields = list() + general["fields"] = fields + fields[++fields.len] = list("field" = "Name:", "value" = active1.fields["name"], "name" = "name") + fields[++fields.len] = list("field" = "ID:", "value" = active1.fields["id"], "name" = "id") + fields[++fields.len] = list("field" = "Sex:", "value" = active1.fields["sex"], "name" = "sex") + fields[++fields.len] = list("field" = "Age:", "value" = active1.fields["age"], "name" = "age") + fields[++fields.len] = list("field" = "Rank:", "value" = active1.fields["rank"], "name" = "rank") + fields[++fields.len] = list("field" = "Fingerprint:", "value" = active1.fields["fingerprint"], "name" = "fingerprint") + fields[++fields.len] = list("field" = "Physical Status:", "value" = active1.fields["p_stat"]) + fields[++fields.len] = list("field" = "Mental Status:", "value" = active1.fields["m_stat"]) + general["notes"] = active1.fields["notes"] + var/list/photos = list() + general["photos"] = photos + photos[++photos.len] = list("photo" = active1.fields["photo-south"]) + photos[++photos.len] = list("photo" = active1.fields["photo-west"]) + general["has_photos"] += (active1.fields["photo-south"] || active1.fields["photo-west"] ? 1 : 0) + general["empty"] = 0 else - else - dat += "{Log In}" - user << browse(text("Employment Records[]", dat), "window=secure_rec;size=600x400") - onclose(user, "secure_rec") - return + general["empty"] = 1 + return data -/*Revised /N -I can't be bothered to look more of the actual code outside of switch but that probably needs revising too. -What a mess.*/ /obj/machinery/computer/skills/Topic(href, href_list) if(..()) return 1 - if(!( data_core.general.Find(active1) )) + + if(!data_core.general.Find(active1)) active1 = null - if((usr.contents.Find(src) || (in_range(src, usr) && istype(loc, /turf))) || (istype(usr, /mob/living/silicon))) - usr.set_machine(src) - switch(href_list["choice"]) -// SORTING! - if("Sorting") - // Reverse the order if clicked twice - if(sortBy == href_list["sort"]) - if(order == 1) - order = -1 - else - order = 1 + + if(href_list["temp"]) + temp = null + + if(href_list["temp_action"]) + if(href_list["temp_action"]) + var/prm = splittext(href_list["temp_action"], "=") + switch(prm[1]) + if("del_all2") + if(PDA_Manifest && PDA_Manifest.len) + PDA_Manifest.Cut() + for(var/datum/data/record/R in data_core.security) + qdel(R) + setTemp("

    All employment records deleted.

    ") + if("del_rg2") + if(active1) + if(PDA_Manifest && PDA_Manifest.len) + PDA_Manifest.Cut() + for(var/datum/data/record/R in data_core.medical) + if(R.fields["name"] == active1.fields["name"] && R.fields["id"] == active1.fields["id"]) + qdel(R) + qdel(active1) + active1 = null + screen = SKILL_DATA_R_LIST + if("rank") + if(active1) + if(PDA_Manifest && PDA_Manifest.len) + PDA_Manifest.Cut() + active1.fields["rank"] = prm[2] + if(prm[2] in joblist) + active1.fields["real_rank"] = prm[2] + + if(href_list["scan"]) + if(scan) + scan.forceMove(loc) + if(ishuman(usr) && !usr.get_active_hand()) + usr.put_in_hands(scan) + scan = null + else + var/obj/item/I = usr.get_active_hand() + if(istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.forceMove(src) + scan = I + + if(href_list["login"]) + if(isAI(usr)) + authenticated = usr.name + rank = "AI" + else if(isrobot(usr)) + authenticated = usr.name + var/mob/living/silicon/robot/R = usr + rank = "[R.modtype] [R.braintype]" + else if(istype(scan, /obj/item/weapon/card/id)) + if(check_access(scan)) + authenticated = scan.registered_name + rank = scan.assignment + + if(authenticated) + active1 = null + screen = SKILL_DATA_R_LIST + + if(authenticated) + var/incapable = (usr.stat || usr.restrained() || (!in_range(src, usr) && !issilicon(usr))) + if(href_list["logout"]) + authenticated = null + screen = null + active1 = null + + else if(href_list["sort"]) + // Reverse the order if clicked twice + if(sortBy == href_list["sort"]) + if(order == 1) + order = -1 else - // New sorting order! - sortBy = href_list["sort"] - order = initial(order) -//BASIC FUNCTIONS - if("Clear Screen") - temp = null + order = 1 + else + sortBy = href_list["sort"] + order = initial(order) - if("Return") - screen = 1 - active1 = null + else if(href_list["screen"]) + screen = text2num(href_list["screen"]) + if(screen < 1) + screen = SKILL_DATA_R_LIST - if("Confirm Identity") - if(scan) - if(istype(usr,/mob/living/carbon/human) && !usr.get_active_hand()) - usr.put_in_hands(scan) - else - scan.loc = get_turf(src) - scan = null + active1 = null + + else if(href_list["d_rec"]) + var/datum/data/record/R = locate(href_list["d_rec"]) + if(!data_core.general.Find(R)) + setTemp("

    Record not found!

    ") + return 1 + active1 = R + screen = SKILL_DATA_RECORD + + else if(href_list["del_all"]) + var/list/buttons = list() + buttons[++buttons.len] = list("name" = "Yes", "icon" = "check", "val" = "del_all2=1", "status" = null) + buttons[++buttons.len] = list("name" = "No", "icon" = "times", "val" = null, "status" = null) + setTemp("

    Are you sure you wish to delete all employment records?

    ", buttons) + + else if(href_list["del_rg"]) + if(active1) + var/list/buttons = list() + buttons[++buttons.len] = list("name" = "Yes", "icon" = "check", "val" = "del_rg2=1", "status" = null) + buttons[++buttons.len] = list("name" = "No", "icon" = "times", "val" = null, "status" = null) + setTemp("

    Are you sure you wish to delete the record (ALL)?

    ", buttons) + + else if(href_list["new_g"]) + if(PDA_Manifest.len) + PDA_Manifest.Cut() + var/datum/data/record/G = new /datum/data/record() + G.fields["name"] = "New Record" + G.fields["id"] = "[add_zero(num2hex(rand(1, 1.6777215E7)), 6)]" + G.fields["rank"] = "Unassigned" + G.fields["real_rank"] = "Unassigned" + G.fields["sex"] = "Male" + G.fields["age"] = "Unknown" + G.fields["fingerprint"] = "Unknown" + G.fields["p_stat"] = "Active" + G.fields["m_stat"] = "Stable" + G.fields["species"] = "Human" + data_core.general += G + active1 = G + + else if(href_list["print_r"]) + if(!printing) + printing = 1 + playsound(loc, "sound/goonstation/machines/printer_dotmatrix.ogg", 50, 1) + sleep(50) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(loc) + P.info = "
    Employment Record

    " + if(istype(active1, /datum/data/record) && data_core.general.Find(active1)) + P.info += {"Name: [active1.fields["name"]] ID: [active1.fields["id"]] +
    \nSex: [active1.fields["sex"]] +
    \nAge: [active1.fields["age"]] +
    \nFingerprint: [active1.fields["fingerprint"]] +
    \nPhysical Status: [active1.fields["p_stat"]] +
    \nMental Status: [active1.fields["m_stat"]] +
    \nEmployment/Skills Summary:[active1.fields["notes"]]
    "} else - var/obj/item/I = usr.get_active_hand() - if(istype(I, /obj/item/weapon/card/id)) - usr.drop_item() - I.loc = src - scan = I + P.info += "General Record Lost!
    " + P.info += "" + P.name = "paper - 'Employment Record'" + printing = 0 - if("Log Out") - authenticated = null - screen = null - active1 = null - - if("Log In") - if(istype(usr, /mob/living/silicon/ai)) - src.active1 = null - src.authenticated = usr.name - src.rank = "AI" - src.screen = 1 - else if(istype(usr, /mob/living/silicon/robot)) - src.active1 = null - src.authenticated = usr.name - var/mob/living/silicon/robot/R = usr - src.rank = R.braintype - src.screen = 1 - else if(istype(scan, /obj/item/weapon/card/id)) - active1 = null - if(check_access(scan)) - authenticated = scan.registered_name - rank = scan.assignment - screen = 1 -//RECORD FUNCTIONS - if("Search Records") - var/t1 = input("Search String: (Partial Name or ID or Fingerprints or Rank)", "Secure. records", null, null) as text - if((!( t1 ) || usr.stat || !( authenticated ) || usr.restrained() || !in_range(src, usr))) - return - Perp = new/list() - t1 = lowertext(t1) - var/list/components = splittext(t1, " ") - if(components.len > 5) - return //Lets not let them search too greedily. - for(var/datum/data/record/R in data_core.general) - var/temptext = R.fields["name"] + " " + R.fields["id"] + " " + R.fields["fingerprint"] + " " + R.fields["rank"] - for(var/i = 1, i<=components.len, i++) - if(findtext(temptext,components[i])) - var/prelist = new/list(2) - prelist[1] = R - Perp += prelist - for(var/i = 1, i<=Perp.len, i+=2) - for(var/datum/data/record/E in data_core.security) - var/datum/data/record/R = Perp[i] - if((E.fields["name"] == R.fields["name"] && E.fields["id"] == R.fields["id"])) - Perp[i+1] = E - tempname = t1 - screen = 4 - - if("Record Maintenance") - screen = 2 - active1 = null - - if("Browse Record") - var/datum/data/record/R = locate(href_list["d_rec"]) - if(!( data_core.general.Find(R) )) - temp = "Record Not Found!" - else - for(var/datum/data/record/E in data_core.security) - active1 = R - screen = 3 - - if("Print Record") - if(!( printing )) - printing = 1 - playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1) - sleep(50) - var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( loc ) - P.info = "
    Employment Record

    " - if((istype(active1, /datum/data/record) && data_core.general.Find(active1))) - P.info += text("Name: [] ID: []
    \nSex: []
    \nAge: []
    \nFingerprint: []
    \nPhysical Status: []
    \nMental Status: []
    \nEmployment/Skills Summary:[]
    ", active1.fields["name"], active1.fields["id"], active1.fields["sex"], active1.fields["age"], active1.fields["fingerprint"], active1.fields["p_stat"], active1.fields["m_stat"], active1.fields["notes"]) - else - P.info += "General Record Lost!
    " - P.info += "" - P.name = "paper - 'Employment Record'" - printing = null -//RECORD DELETE - if("Delete All Records") - temp = "" - temp += "Are you sure you wish to delete all Employment records?
    " - temp += "Yes
    " - temp += "No" - - if("Purge All Records") - if(PDA_Manifest.len) - PDA_Manifest.Cut() - for(var/datum/data/record/R in data_core.security) - qdel(R) - temp = "All Employment records deleted." - - if("Delete Record (ALL)") - if(active1) - temp = "
    Are you sure you wish to delete the record (ALL)?
    " - temp += "Yes
    " - temp += "No" -//RECORD CREATE - if("New Record (General)") - - if(PDA_Manifest.len) - PDA_Manifest.Cut() - var/datum/data/record/G = new /datum/data/record() - G.fields["name"] = "New Record" - G.fields["id"] = text("[]", add_zero(num2hex(rand(1, 1.6777215E7)), 6)) - G.fields["rank"] = "Unassigned" - G.fields["real_rank"] = "Unassigned" - G.fields["sex"] = "Male" - G.fields["age"] = "Unknown" - G.fields["fingerprint"] = "Unknown" - G.fields["p_stat"] = "Active" - G.fields["m_stat"] = "Stable" - G.fields["species"] = "Human" - data_core.general += G - active1 = G - -//FIELD FUNCTIONS - if("Edit Field") - var/a1 = active1 - switch(href_list["field"]) - if("name") - if(istype(active1, /datum/data/record)) - var/t1 = reject_bad_name(input("Please input name:", "Secure. records", active1.fields["name"], null) as text) - if((!( t1 ) || !length(trim(t1)) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon)))) || active1 != a1) - return - active1.fields["name"] = t1 - if("id") - if(istype(active1, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please input id:", "Secure. records", active1.fields["id"], null) as text)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || active1 != a1)) - return - active1.fields["id"] = t1 - if("fingerprint") - if(istype(active1, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please input fingerprint hash:", "Secure. records", active1.fields["fingerprint"], null) as text)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || active1 != a1)) - return - active1.fields["fingerprint"] = t1 - if("sex") - if(istype(active1, /datum/data/record)) - if(active1.fields["sex"] == "Male") - active1.fields["sex"] = "Female" - else - active1.fields["sex"] = "Male" - if("age") - if(istype(active1, /datum/data/record)) - var/t1 = input("Please input age:", "Secure. records", active1.fields["age"], null) as num - if((!( t1 ) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || active1 != a1)) - return - active1.fields["age"] = t1 - if("rank") - var/list/L = list( "Head of Personnel", "Captain", "AI" ) - //This was so silly before the change. Now it actually works without beating your head against the keyboard. /N - if((istype(active1, /datum/data/record) && L.Find(rank))) - temp = "
    Rank:
    " - temp += "
      " - for(var/rank in joblist) - temp += "
    • [rank]
    • " - temp += "
    " + if(href_list["field"]) + if(incapable) + return 1 + var/a1 = active1 + switch(href_list["field"]) + if("name") + if(istype(active1, /datum/data/record)) + var/t1 = reject_bad_name(input("Please input name:", "Secure. records", active1.fields["name"], null) as text) + if(!t1 || !length(trim(t1)) || incapable || active1 != a1) + return 1 + active1.fields["name"] = t1 + if("id") + if(istype(active1, /datum/data/record)) + var/t1 = copytext(trim(sanitize(input("Please input id:", "Secure. records", active1.fields["id"], null) as text)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active1 != a1) + return 1 + active1.fields["id"] = t1 + if("fingerprint") + if(istype(active1, /datum/data/record)) + var/t1 = copytext(trim(sanitize(input("Please input fingerprint hash:", "Secure. records", active1.fields["fingerprint"], null) as text)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active1 != a1) + return 1 + active1.fields["fingerprint"] = t1 + if("sex") + if(istype(active1, /datum/data/record)) + if(active1.fields["sex"] == "Male") + active1.fields["sex"] = "Female" else - alert(usr, "You do not have the required rank to do this!") - if("species") - if(istype(active1, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please enter race:", "General records", active1.fields["species"], null) as message)),1,MAX_MESSAGE_LEN) - if((!( t1 ) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || active1 != a1)) - return - active1.fields["species"] = t1 - -//TEMPORARY MENU FUNCTIONS - else//To properly clear as per clear screen. - temp=null - switch(href_list["choice"]) - if("Change Rank") - if(active1) - if(PDA_Manifest.len) - PDA_Manifest.Cut() - active1.fields["rank"] = href_list["rank"] - if(href_list["rank"] in joblist) - active1.fields["real_rank"] = href_list["real_rank"] - - if("Delete Record (ALL) Execute") - if(active1) - if(PDA_Manifest.len) - PDA_Manifest.Cut() - for(var/datum/data/record/R in data_core.medical) - if((R.fields["name"] == active1.fields["name"] || R.fields["id"] == active1.fields["id"])) - qdel(R) - else - qdel(active1) + active1.fields["sex"] = "Male" + if("age") + if(istype(active1, /datum/data/record)) + var/t1 = input("Please input age:", "Secure. records", active1.fields["age"], null) as num + if(!t1 || incapable || active1 != a1) + return 1 + active1.fields["age"] = t1 + if("rank") + var/list/L = list("Head of Personnel", "Captain", "AI") + //This was so silly before the change. Now it actually works without beating your head against the keyboard. /N + if(istype(active1, /datum/data/record) && L.Find(rank)) + var/list/buttons = list() + for(var/rank in joblist) + buttons[++buttons.len] = list("name" = rank, "icon" = null, "val" = "rank=[rank]", "status" = (active1.fields["rank"] == rank ? "selected" : null)) + setTemp("

    Rank

    ", buttons) else - temp = "This function does not appear to be working at the moment. Our apologies." + setTemp("You do not have the required rank to do this!") + if("species") + if(istype(active1, /datum/data/record)) + var/t1 = copytext(trim(sanitize(input("Please enter race:", "General records", active1.fields["species"], null) as message)), 1, MAX_MESSAGE_LEN) + if(!t1 || incapable || active1 != a1) + return 1 + active1.fields["species"] = t1 + return 1 - add_fingerprint(usr) - updateUsrDialog() - return +/obj/machinery/computer/skills/proc/setTemp(text, list/buttons = list()) + temp = list("text" = text, "buttons" = buttons, "has_buttons" = buttons.len > 0) /obj/machinery/computer/skills/emp_act(severity) if(stat & (BROKEN|NOPOWER)) @@ -393,7 +304,7 @@ What a mess.*/ if(1) R.fields["name"] = "[pick(pick(first_names_male), pick(first_names_female))] [pick(last_names)]" if(2) - R.fields["sex"] = pick("Male", "Female") + R.fields["sex"] = pick("Male", "Female") if(3) R.fields["age"] = rand(5, 85) if(4) @@ -409,3 +320,7 @@ What a mess.*/ continue ..(severity) + +#undef SKILL_DATA_R_LIST +#undef SKILL_DATA_MAINT +#undef SKILL_DATA_RECORD \ No newline at end of file diff --git a/nano/templates/skills_data.tmpl b/nano/templates/skills_data.tmpl new file mode 100644 index 00000000000..6f8fb1d6a0d --- /dev/null +++ b/nano/templates/skills_data.tmpl @@ -0,0 +1,199 @@ + + + + +{{if !data.temp && data.screen == 1}} + +{{/if}} + + +
    +
    + Confirm Identity: +
    +
    + {{:helper.link(data.scan ? data.scan : "----------", 'eject', {'scan' : 1}, null, data.scan ? 'itemContentWide' : 'fixedLeft')}} +
    +
    +
    +{{if data.authenticated}} + {{if data.screen == 1}} +
    +
    {{:helper.link('New Record', 'plus', {'new_g' : 1})}}
    +
    +

    Record List

    + + + + +
    + Search: +
    +
    + + + + + + + + + + + + {{for data.records}} + + + + + + + {{/for}} + +
    {{:helper.link('Name', null, {'sort' : 'name'}, null, 'infoButton')}}{{:helper.link('ID', null, {'sort' : 'id'}, null, 'infoButton')}}{{:helper.link('Rank', null, {'sort' : 'rank'}, null, 'infoButton')}}{{:helper.link('Fingerprints', null, {'sort' : 'fingerprint'}, null, 'infoButton')}}
    {{:helper.link(value.name, 'user', {'d_rec' : value.ref}, null, 'infoButton')}}{{:value.id}}{{:value.rank}}{{:value.fingerprint}}
    +
    +
    +

    Menu

    +
    {{:helper.link('Record Maintenance', 'wrench', {'screen' : 2})}}
    +
    {{:helper.link('Logout', 'lock', {'logout' : 1})}}
    + {{else data.screen == 2}} +

    Records Maintenance

    +
    {{:helper.link('Backup To Disk', 'download', {'back' : 1}, 'disabled')}}
    +
    {{:helper.link('Upload From disk', 'upload', {'u_load' : 1}, 'disabled')}}
    +
    {{:helper.link('Delete All Records', 'trash', {'del_all' : 1})}}
    +
    {{:helper.link('Back', 'arrow-left', {'screen' : 1})}}
    + {{else data.screen == 3}} +

    Employment Record

    +

    General Data

    + {{if data.general.empty}} +
    General Record Lost!
    + {{else}} +
    + + + +
    + {{for data.general.fields}} +
    +
    + {{:value.field}} +
    +
    + {{:helper.link(value.value, value.name ? 'pencil' : 'user-times', {'field' : value.name}, value.name ? null : 'disabled')}} +
    +
    + {{/for}} +
    + {{if data.general.has_photos}} + {{for data.general.photos}} + {{if value.photo}} + + {{/if}} + {{/for}} + {{/if}} +
    +
    + +

    Employment Data

    +
    +
    + Employment/skills summary: +
    +
    + {{:data.general.notes ? data.general.notes : 'None'}} +
    +
    + {{/if}} +

    Menu

    +
    {{:helper.link('Delete Record (All)', 'trash', {'del_rg' : 1})}}
    +
    {{:helper.link('Print Record', 'print', {'print_r' : 1})}}
    +
    {{:helper.link('Back', 'arrow-left', {'screen' : 1})}}
    + {{/if}} +{{else}} +

    Menu

    + {{:helper.link('Login', 'unlock', {'login' : 1})}} +{{/if}} + +{{if data.temp}} +
    +
    + {{if data.temp.notice}} +
    {{:data.temp.text}}
    + {{else}} +
    {{:data.temp.text}}
    + {{/if}} + + + {{if data.temp.has_buttons}} +
    +
    +
    + {{for data.temp.buttons}} + {{:helper.link(value.name, value.icon, {'temp' : 1, 'temp_action' : value.val}, value.status)}} + {{/for}} +
    +
    +
    + {{/if}} + +
    +
    {{:helper.link('Clear screen', 'home', {'temp' : 1})}}
    +
    +
    +
    +{{/if}} \ No newline at end of file From c7eda9d78dcdeaa0ef1badb8e1cef43202ea5806 Mon Sep 17 00:00:00 2001 From: Twinmold Date: Sat, 18 Feb 2017 13:11:51 -0600 Subject: [PATCH 063/164] BloodPack Tagging/Pen Labeling With this, you can now use a pen on a bloodpack and add a label to it, giving the ability to tag a bloodpack with the type of blood from donations. Bloodpacks will now switch between "empty" and notso in naming, depending on if there is reagent/blood inside or not. :cl:Twinmold Add: Ability to label bloodpacks with a pen, so you can now label a bloodpack from donations without a handlabeler. Add: Bloodpacks will now change name to say if they are empty or not. /:cl: --- .../reagents/reagent_containers/blood_pack.dm | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index a04087603ad..c0e85013ccd 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -1,11 +1,13 @@ /obj/item/weapon/reagent_containers/blood name = "BloodPack" + var/base_name = "BloodPack" desc = "Contains blood used for transfusion." icon = 'icons/obj/bloodpack.dmi' icon_state = "empty" volume = 200 var/blood_type = null + var/label_text = "" /obj/item/weapon/reagent_containers/blood/New() ..() @@ -16,6 +18,7 @@ /obj/item/weapon/reagent_containers/blood/on_reagent_change() update_icon() + update_name_label() /obj/item/weapon/reagent_containers/blood/update_icon() var/percent = round((reagents.total_volume / volume) * 100) @@ -27,27 +30,55 @@ if(51 to INFINITY) icon_state = "full" +/obj/item/weapon/reagent_containers/blood/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/weapon/pen) || istype(I, /obj/item/device/flashlight/pen)) + var/tmp_label = sanitize(input(user, "Enter a label for [name]","Label",label_text)) + if(length(tmp_label) > MAX_NAME_LEN) + to_chat(user, "The label can be at most [MAX_NAME_LEN] characters long.") + else + to_chat(user, "You set the label to \"[tmp_label]\".") + label_text = tmp_label + update_name_label() + +/obj/item/weapon/reagent_containers/blood/proc/update_name_label() + if(reagents.total_volume == 0) + base_name = "Empty BloodPack" + desc = "Seems pretty useless... Maybe if there were a way to fill it?" + else + base_name = "BloodPack" + desc = "Contains blood used for transfusion." + if(label_text == "") + name = base_name + else + name = "[base_name] ([label_text])" + /obj/item/weapon/reagent_containers/blood/random/New() blood_type = pick("A+", "A-", "B+", "B-", "O+", "O-") ..() /obj/item/weapon/reagent_containers/blood/APlus blood_type = "A+" + label_text = "A+" /obj/item/weapon/reagent_containers/blood/AMinus blood_type = "A-" + label_text = "A-" /obj/item/weapon/reagent_containers/blood/BPlus blood_type = "B+" + label_text = "B+" /obj/item/weapon/reagent_containers/blood/BMinus blood_type = "B-" + label_text = "B-" /obj/item/weapon/reagent_containers/blood/OPlus blood_type = "O+" + label_text = "O+" /obj/item/weapon/reagent_containers/blood/OMinus blood_type = "O-" + label_text = "O-" /obj/item/weapon/reagent_containers/blood/empty name = "Empty BloodPack" From 337a3462842d5f17c90d7f08b6102ed1ef21ab76 Mon Sep 17 00:00:00 2001 From: davipatury Date: Sat, 18 Feb 2017 19:11:52 -0200 Subject: [PATCH 064/164] Autolathe nano-ui. --- code/game/machinery/autolathe.dm | 336 ++++++++++++------------------- nano/templates/autolathe.tmpl | 150 ++++++++++++++ 2 files changed, 280 insertions(+), 206 deletions(-) create mode 100644 nano/templates/autolathe.tmpl diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 9ed23ae44cd..5ffaa3331ff 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -1,6 +1,6 @@ -#define AUTOLATHE_MAIN_MENU 1 -#define AUTOLATHE_CATEGORY_MENU 2 -#define AUTOLATHE_SEARCH_MENU 3 +#define AUTOLATHE_MAIN_MENU 1 +#define AUTOLATHE_CATEGORY_MENU 2 +#define AUTOLATHE_SEARCH_MENU 3 /obj/machinery/autolathe name = "autolathe" @@ -31,21 +31,13 @@ var/list/being_built = list() var/datum/research/files var/list/datum/design/matching_designs + var/temp_search var/selected_category var/screen = 1 var/datum/material_container/materials - var/list/categories = list( - "Communication", - "Construction", - "Electronics", - "Medical", - "Miscellaneous", - "Security", - "Tools", - "Imported" - ) + var/list/categories = list("Communication", "Construction", "Electronics", "Imported", "Medical", "Miscellaneous", "Security", "Tools") /obj/machinery/autolathe/New() ..() @@ -56,7 +48,7 @@ component_parts += new /obj/item/weapon/stock_parts/matter_bin(null) component_parts += new /obj/item/weapon/stock_parts/manipulator(null) component_parts += new /obj/item/weapon/stock_parts/console_screen(null) - materials = new /datum/material_container(src, list(MAT_METAL=1, MAT_GLASS=1)) + materials = new /datum/material_container(src, list(MAT_METAL = 1, MAT_GLASS = 1)) RefreshParts() wires = new(src) @@ -83,36 +75,109 @@ /obj/machinery/autolathe/interact(mob/user) if(shocked && !(stat & NOPOWER)) - shock(user,50) - - user.set_machine(src) - var/dat + shock(user, 50) + return if(panel_open) - dat = wires.GetInteractWindow() - + wires.Interact() else - switch(screen) - if(AUTOLATHE_MAIN_MENU) - dat = main_win(user) - if(AUTOLATHE_CATEGORY_MENU) - dat = category_win(user,selected_category) - if(AUTOLATHE_SEARCH_MENU) - dat = search_win(user) + ui_interact(user) - var/datum/browser/popup = new(user, "autolathe", name, 800, 500) - popup.set_content(dat) - popup.open() +/obj/machinery/autolathe/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "autolathe.tmpl", name, 800, 550) + ui.open() - return +/obj/machinery/autolathe/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) + var/data[0] + data["screen"] = screen + data["total_amount"] = materials.total_amount + data["max_amount"] = materials.max_amount + data["metal_amount"] = materials.amount(MAT_METAL) + data["glass_amount"] = materials.amount(MAT_GLASS) + switch(screen) + if(AUTOLATHE_MAIN_MENU) + data["uid"] = UID() + data["categories"] = categories + if(AUTOLATHE_CATEGORY_MENU) + data["selected_category"] = selected_category + var/list/designs = list() + data["designs"] = designs + for(var/v in files.known_designs) + var/datum/design/D = files.known_designs[v] + if(!(selected_category in D.category)) + continue + var/list/design = list() + designs[++designs.len] = design + design["name"] = D.name + design["id"] = D.id + design["disabled"] = disabled || !can_build(D) ? "disabled" : null + if(ispath(D.build_path, /obj/item/stack)) + design["max_multiplier"] = min(D.maxstack, D.materials[MAT_METAL] ? round(materials.amount(MAT_METAL) / D.materials[MAT_METAL]) : INFINITY, D.materials[MAT_GLASS] ? round(materials.amount(MAT_GLASS) / D.materials[MAT_GLASS]) : INFINITY) + else + design["max_multiplier"] = null + design["materials"] = design_cost_data(D) + if(AUTOLATHE_SEARCH_MENU) + data["search"] = temp_search + var/list/designs = list() + data["designs"] = designs + for(var/datum/design/D in matching_designs) + var/list/design = list() + designs[++designs.len] = design + design["name"] = D.name + design["id"] = D.id + design["disabled"] = disabled || !can_build(D) ? "disabled" : null + if(ispath(D.build_path, /obj/item/stack)) + design["max_multiplier"] = min(D.maxstack, D.materials[MAT_METAL] ? round(materials.amount(MAT_METAL) / D.materials[MAT_METAL]) : INFINITY, D.materials[MAT_GLASS] ? round(materials.amount(MAT_GLASS) / D.materials[MAT_GLASS]) : INFINITY) + else + design["max_multiplier"] = null + design["materials"] = design_cost_data(D) + + data = queue_data(data) + return data + +/obj/machinery/autolathe/proc/design_cost_data(datum/design/D) + var/list/data = list() + var/coeff = get_coeff(D) + + var/has_metal = 1 + if(D.materials[MAT_METAL] && (materials.amount(MAT_METAL) < (D.materials[MAT_METAL] / coeff))) + has_metal = 0 + var/has_glass = 1 + if(D.materials[MAT_GLASS] && (materials.amount(MAT_GLASS) < (D.materials[MAT_GLASS] / coeff))) + has_glass = 0 + + data[++data.len] = list("name" = "metal", "amount" = D.materials[MAT_METAL] / coeff, "is_red" = !has_metal) + data[++data.len] = list("name" = "glass", "amount" = D.materials[MAT_GLASS] / coeff, "is_red" = !has_glass) + + return data + +/obj/machinery/autolathe/proc/queue_data(list/data) + var/temp_metal = materials.amount(MAT_METAL) + var/temp_glass = materials.amount(MAT_GLASS) + data["processing"] = being_built.len ? get_processing_line() : null + if(istype(queue) && queue.len) + var/list/data_queue = list() + for(var/list/L in queue) + var/datum/design/D = L[1] + var/list/LL = get_design_cost_as_list(D, L[2]) + data_queue[++data_queue.len] = list("name" = initial(D.name), "can_build" = can_build(D, L[2], temp_metal, temp_glass), "multiplier" = L[2]) + temp_metal = max(temp_metal - LL[1], 1) + temp_glass = max(temp_glass - LL[2], 1) + data["queue"] = data_queue + data["queue_len"] = data_queue.len + else + data["queue"] = null + return data /obj/machinery/autolathe/attackby(obj/item/O, mob/user, params) if(busy) - to_chat(user, "The autolathe is busy. Please wait for completion of previous operation.") + to_chat(user, "The autolathe is busy. Please wait for completion of previous operation.") return 1 if(default_deconstruction_screwdriver(user, "autolathe_t", "autolathe", O)) - updateUsrDialog() + nanomanager.update_uis(src) return if(exchange_parts(user, O)) @@ -137,7 +202,7 @@ user.visible_message("[user] begins to load \the [O] in \the [src]...", "You begin to load a design from \the [O]...", "You hear the chatter of a floppy drive.") - playsound(get_turf(src), 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1) + playsound(get_turf(src), "sound/goonstation/machines/printer_dotmatrix.ogg", 50, 1) busy = 1 if(do_after(user, 14.4, target = src)) files.AddDesign2Known(D.blueprint) @@ -168,15 +233,15 @@ if(O.materials[MAT_METAL]) flick("autolathe_o",src)//plays metal insertion animation if(O.materials[MAT_GLASS]) - flick("autolathe_r",src)//plays glass insertion animation + flick("autolathe_r", src)//plays glass insertion animation to_chat(user, "You insert [inserted] sheet[inserted>1 ? "s" : ""] to the autolathe.") - use_power(inserted*100) + use_power(inserted * 100) else to_chat(user, "You insert a material total of [inserted] to the autolathe.") - use_power(max(500,inserted/10)) + use_power(max(500, inserted / 10)) qdel(O) busy = 0 - src.updateUsrDialog() + nanomanager.update_uis(src) /obj/machinery/autolathe/attack_ghost(mob/user) interact(user) @@ -195,6 +260,7 @@ if(href_list["category"]) selected_category = href_list["category"] + screen = AUTOLATHE_CATEGORY_MENU if(href_list["make"]) BuildTurf = loc @@ -215,14 +281,14 @@ if(!is_stack && (multiplier > 1)) return - if(!(multiplier in list(1,10,25,max_multiplier))) //"enough materials ?" is checked in the build proc + if(!(multiplier in list(1, 10, 25, max_multiplier))) //"enough materials ?" is checked in the build proc return ///////////////// - if((queue.len+1)The autolathe queue is full!") if(!busy) busy = 1 process_queue() @@ -230,28 +296,32 @@ if(href_list["remove_from_queue"]) var/index = text2num(href_list["remove_from_queue"]) - if(isnum(index) && IsInRange(index,1,queue.len)) + if(isnum(index) && IsInRange(index, 1, queue.len)) remove_from_queue(index) if(href_list["queue_move"] && href_list["index"]) var/index = text2num(href_list["index"]) var/new_index = index + text2num(href_list["queue_move"]) if(isnum(index) && isnum(new_index)) - if(IsInRange(new_index,1,queue.len)) + if(IsInRange(new_index, 1, queue.len)) queue.Swap(index,new_index) if(href_list["clear_queue"]) queue = list() if(href_list["search"]) + if(href_list["to_search"]) + temp_search = href_list["to_search"] + if(!temp_search) + return matching_designs.Cut() for(var/v in files.known_designs) var/datum/design/D = files.known_designs[v] - if(findtext(D.name,href_list["to_search"])) + if(findtext(D.name, temp_search)) matching_designs.Add(D) + screen = AUTOLATHE_SEARCH_MENU - src.updateUsrDialog() - - return + nanomanager.update_uis(src) + return 1 /obj/machinery/autolathe/RefreshParts() var/tot_rating = 0 @@ -263,19 +333,19 @@ for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts) prod_coeff += M.rating - 1 -/obj/machinery/autolathe/proc/get_coeff(var/datum/design/D) +/obj/machinery/autolathe/proc/get_coeff(datum/design/D) var/coeff = (ispath(D.build_path,/obj/item/stack) ? 1 : 2 ** prod_coeff)//stacks are unaffected by production coefficient return coeff -/obj/machinery/autolathe/proc/build_item(var/datum/design/D, var/multiplier) +/obj/machinery/autolathe/proc/build_item(datum/design/D, multiplier) desc = initial(desc)+"\nIt's building \a [initial(D.name)]." var/is_stack = ispath(D.build_path, /obj/item/stack) var/coeff = get_coeff(D) var/metal_cost = D.materials[MAT_METAL] var/glass_cost = D.materials[MAT_GLASS] var/power = max(2000, (metal_cost+glass_cost)*multiplier/5) - if(can_build(D,multiplier)) - being_built = list(D,multiplier) + if(can_build(D, multiplier)) + being_built = list(D, multiplier) use_power(power) icon_state = "autolathe" flick("autolathe_n",src) @@ -285,7 +355,7 @@ else var/list/materials_used = list(MAT_METAL=metal_cost/coeff, MAT_GLASS=glass_cost/coeff) materials.use_amount(materials_used) - updateUsrDialog() + nanomanager.update_uis(src) sleep(32/coeff) if(is_stack) var/obj/item/stack/S = new D.build_path(BuildTurf) @@ -294,10 +364,10 @@ var/obj/item/new_item = new D.build_path(BuildTurf) new_item.materials[MAT_METAL] /= coeff new_item.materials[MAT_GLASS] /= coeff - updateUsrDialog() + nanomanager.update_uis(src) desc = initial(desc) -/obj/machinery/autolathe/proc/can_build(var/datum/design/D,var/multiplier=1,var/custom_metal,var/custom_glass) +/obj/machinery/autolathe/proc/can_build(datum/design/D, multiplier = 1, custom_metal, custom_glass) if(D.make_reagents.len) return 0 @@ -316,7 +386,7 @@ return 0 return 1 -/obj/machinery/autolathe/proc/get_design_cost_as_list(var/datum/design/D,var/multiplier=1) +/obj/machinery/autolathe/proc/get_design_cost_as_list(datum/design/D, multiplier = 1) var/list/OutputList = list(0,0) var/coeff = get_coeff(D) if(D.materials[MAT_METAL]) @@ -332,43 +402,7 @@ var/output = "PROCESSING: [initial(D.name)][is_stack?" (x[multiplier])":null]" return output -/obj/machinery/autolathe/proc/get_queue() - var/temp_metal = materials.amount(MAT_METAL) - var/temp_glass = materials.amount(MAT_GLASS) - var/output = "" - output += "
    " - output += "Queue contains:" - if(!istype(queue) || !queue.len) - if(being_built.len) - output += "
    1. " - output += get_processing_line() - output += "
    " - else - output += "
    Nothing" - else - output += "
      " - if(being_built.len) - output += "
    1. " - output += get_processing_line() - output += "
    2. " - var/i = 0 - var/datum/design/D - for(var/list/L in queue) - i++ - D = L[1] - var/multiplier = L[2] - var/list/LL = get_design_cost_as_list(D,multiplier) - var/is_stack = (multiplier>1) - output += "[initial(D.name)][is_stack?" (x[multiplier])":null] - [i>1?"":null] [i↓":null] Remove" - temp_metal = max(temp_metal-LL[1],1) - temp_glass = max(temp_glass-LL[2],1) - - output += "
    " - output += "Clear queue" - output += "
    " - return output - -/obj/machinery/autolathe/proc/add_to_queue(D,var/multiplier) +/obj/machinery/autolathe/proc/add_to_queue(D, multiplier) if(!istype(queue)) queue = list() if(D) @@ -391,10 +425,10 @@ else return while(D) - if(stat&(NOPOWER|BROKEN)) + if(stat & (NOPOWER|BROKEN)) being_built = new /list() return 0 - if(!can_build(D,multiplier)) + if(!can_build(D, multiplier)) visible_message("[bicon(src)] \The [src] beeps, \"Not enough resources. Queue processing terminated.\"") queue = list() being_built = new /list() @@ -407,117 +441,7 @@ being_built = new /list() //visible_message("[bicon(src)] \The [src] beeps, \"Queue processing finished successfully.\"") -/obj/machinery/autolathe/proc/main_win(mob/user) - var/dat = "" - dat += "" - dat += get_queue() - dat += "
    " - dat += "

    Autolathe Menu:


    " - dat += "Total amount: [materials.total_amount] / [materials.max_amount] cm3
    " - dat += "Metal amount: [materials.amount(MAT_METAL)] cm3
    " - dat += "Glass amount: [materials.amount(MAT_GLASS)] cm3
    " - - dat += "
    \ - \ - \ - \ - \ - \ -

    " - - var/line_length = 1 - dat += "" - - for(var/C in categories) - if(line_length > 2) - dat += "" - line_length = 1 - - dat += "" - line_length++ - - dat += "
    [C]
    " - dat += "
    " - return dat - -/obj/machinery/autolathe/proc/category_win(mob/user,var/selected_category) - var/dat = "" - dat += get_queue() - dat += "
    " - dat += "
    " - dat += "Return to main menu" - dat += "

    Browsing [selected_category]:


    " - dat += "Total amount: [materials.total_amount] / [materials.max_amount] cm3
    " - dat += "Metal amount: [materials.amount(MAT_METAL)] cm3
    " - dat += "Glass amount: [materials.amount(MAT_GLASS)] cm3
    " - - for(var/v in files.known_designs) - var/datum/design/D = files.known_designs[v] - if(!(selected_category in D.category)) - continue - - if(disabled || !can_build(D)) - dat += "[D.name]" - else - dat += "[D.name]" - - if(ispath(D.build_path, /obj/item/stack)) - var/max_multiplier = min(D.maxstack, D.materials[MAT_METAL] ?round(materials.amount(MAT_METAL)/D.materials[MAT_METAL]):INFINITY,D.materials[MAT_GLASS]?round(materials.amount(MAT_GLASS)/D.materials[MAT_GLASS]):INFINITY) - if(max_multiplier>10 && !disabled) - dat += " x10" - if(max_multiplier>25 && !disabled) - dat += " x25" - if(max_multiplier > 0 && !disabled) - dat += " x[max_multiplier]" - - dat += "[get_design_cost(D)]
    " - - dat += "
    " - dat += "
    " - return dat - -/obj/machinery/autolathe/proc/search_win(mob/user) - var/dat = "" - dat += get_queue() - dat += "
    " - dat += "
    " - dat += "Return to main menu" - dat += "

    Search results:


    " - dat += "Total amount: [materials.total_amount] / [materials.max_amount] cm3
    " - dat += "Metal amount: [materials.amount(MAT_METAL)] cm3
    " - dat += "Glass amount: [materials.amount(MAT_GLASS)] cm3
    " - - for(var/datum/design/D in matching_designs) - if(disabled || !can_build(D)) - dat += "[D.name]" - else - dat += "[D.name]" - - if(ispath(D.build_path, /obj/item/stack)) - var/max_multiplier = min(D.maxstack, D.materials[MAT_METAL] ?round(materials.amount(MAT_METAL)/D.materials[MAT_METAL]):INFINITY,D.materials[MAT_GLASS]?round(materials.amount(MAT_GLASS)/D.materials[MAT_GLASS]):INFINITY) - if(max_multiplier>10 && !disabled) - dat += " x10" - if(max_multiplier>25 && !disabled) - dat += " x25" - if(max_multiplier > 0 && !disabled) - dat += " x[max_multiplier]" - - dat += "[get_design_cost(D)]
    " - - dat += "
    " - dat += "
    " - return dat - -/obj/machinery/autolathe/proc/get_design_cost(var/datum/design/D) - var/coeff = get_coeff(D) - var/dat - if(D.materials[MAT_METAL]) - dat += "[D.materials[MAT_METAL] / coeff] metal " - if(D.materials[MAT_GLASS]) - dat += "[D.materials[MAT_GLASS] / coeff] glass" - return dat - -/obj/machinery/autolathe/proc/adjust_hacked(var/hack) +/obj/machinery/autolathe/proc/adjust_hacked(hack) hacked = hack if(hack) @@ -527,4 +451,4 @@ else for(var/datum/design/D in files.known_designs) if("hacked" in D.category) - files.known_designs -= D.id + files.known_designs -= D.id \ No newline at end of file diff --git a/nano/templates/autolathe.tmpl b/nano/templates/autolathe.tmpl new file mode 100644 index 00000000000..55e017ca95c --- /dev/null +++ b/nano/templates/autolathe.tmpl @@ -0,0 +1,150 @@ + + + + + + +{{if data.screen == 2 || data.screen == 3}} +
    + {{:helper.link('Main Menu', 'reply', {'menu' : 1})}} +
    +{{/if}} + + + + +
    +
    + {{if data.screen == 1}} +

    Autolathe Menu

    +
    + + + + + + + + + +
    Total amount:{{:data.total_amount}} / {{:data.max_amount}} cm3
    Metal amount:{{:data.metal_amount}} cm3
    Glass amount:{{:data.glass_amount}} cm3
    +
    + + + +
    + +
    + + {{for data.categories}} + {{if (index & 1) == 0 && index != 0}} + + {{/if}} + + {{/for}} +
    {{:helper.link(value, 'arrow-right', {'category': value})}}
    + {{else data.screen == 2 || data.screen == 3}} + {{if data.screen == 2}} +

    Viewing Category {{:data.selected_category}}:

    + {{else data.screen == 3}} +

    Search Results for '{{:data.search}}':

    + {{/if}} +
    + + + + + + + + + +
    Total amount:{{:data.total_amount}} / {{:data.max_amount}} cm3
    Metal amount:{{:data.metal_amount}} cm3
    Glass amount:{{:data.glass_amount}} cm3
    + + {{for data.designs}} + + + + + + + + {{/for}} +
    {{:helper.link(value.name, 'print', {'make' : value.id, 'multiplier' : 1}, value.disabled)}}{{if value.max_multiplier > 10}} + {{:helper.link('x10', null, {'make' : value.id, 'multiplier' : 10}, value.disabled)}} + {{/if}}{{if value.max_multiplier > 25}} + {{:helper.link('x25', null, {'make' : value.id, 'multiplier' : 25}, value.disabled)}} + {{/if}}{{if value.max_multiplier}} + {{:helper.link('x' + value.max_multiplier, null, {'make' : value.id, 'multiplier' : value.max_multiplier}, value.disabled)}} + {{/if}} + {{for value.materials : material : i}} + {{if material.amount}} + | + {{if material.is_red}} + + {{/if}} + {{:material.amount}} {{:material.name}} + {{if material.is_red}} + + {{/if}} + {{/if}} + {{/for}} +
    + {{/if}} +
    +
    +
    +

    Queue contains:

    + {{if data.queue}} + {{if data.processing}} +
      {{:data.processing}}
    + {{/if}} +
      + {{for data.queue}} +
    1. + {{if !value.can_build}} + + {{/if}} + {{:value.name}} {{:value.multiplier > 1 ? '(xvalue.multiplier)' : ''}} + {{if !value.can_build}} + + {{/if}} +
      + {{if index + 1 > 1}} + {{:helper.link('', 'arrow-up', {'queue_move' : -1, 'index' : index + 1})}} + {{/if}} + {{if index + 1 < data.queue_len}} + {{:helper.link('', 'arrow-down', {'queue_move' : +1, 'index' : index + 1})}} + {{/if}} + {{:helper.link('Remove', 'times', {'remove_from_queue' : index + 1})}} +
      +
    2. + {{/for}} +
    + {{:helper.link('Clear queue', 'trash', {'clear_queue' : 1})}} + {{else}} + {{if data.processing}} +
      {{:data.processing}}
    + {{else}} +
      Nothing
    + {{/if}} + {{/if}} +
    +
    \ No newline at end of file From 7af8959bdaf7d210814e2d6b3f64f40844516dbc Mon Sep 17 00:00:00 2001 From: davipatury Date: Sat, 18 Feb 2017 19:39:41 -0200 Subject: [PATCH 065/164] oops --- code/game/machinery/autolathe.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 5ffaa3331ff..a5011905f79 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -202,7 +202,7 @@ user.visible_message("[user] begins to load \the [O] in \the [src]...", "You begin to load a design from \the [O]...", "You hear the chatter of a floppy drive.") - playsound(get_turf(src), "sound/goonstation/machines/printer_dotmatrix.ogg", 50, 1) + playsound(get_turf(src), 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1) busy = 1 if(do_after(user, 14.4, target = src)) files.AddDesign2Known(D.blueprint) From 6c37baa16f57cf6ad0fdcb6a7070effe9a511457 Mon Sep 17 00:00:00 2001 From: allfd Date: Sat, 18 Feb 2017 17:33:54 -0500 Subject: [PATCH 066/164] Updates configs from server --- config/example/admin_ranks.txt | 62 +++++++++++++++++----------------- config/example/config.txt | 32 +++++++++--------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/config/example/admin_ranks.txt b/config/example/admin_ranks.txt index db2118ee8b7..c7d1cccef98 100644 --- a/config/example/admin_ranks.txt +++ b/config/example/admin_ranks.txt @@ -8,36 +8,36 @@ # Ranks with no keywords will just be given the most basic verbs and abilities # ######################################################################################## # KEYWORDS: -# +ADMIN = General admin tools and verbs. -# +FUN = Events and other event-orientated actions. -# +BAN = The ability to ban and jobban. -# +STEALTH = The ability to stealthmin (make yourself appear with a fake name to everyone but other admins). -# +POSSESS = The ability to possess objects. -# +REJUV (or +REJUVINATE) = The ability to heal, respawn, modify damage and use godmode. -# +BUILD (or +BUILDMODE) = The ability to use buildmode. -# +SERVER = Higher-risk admin verbs and abilities, such as those which affect the server configuration. -# +DEBUG = Debug tools used for diagnosing and fixing problems. It's useful to give this to coders so they can investigate problems on a live server. -# +VAREDIT = Allows you to actually modify variables in the view variables window. -# +RIGHTS (or +PERMISSIONS) = Allows you to promote and demote people. -# +SOUND (or +SOUNDS) = Allows you to upload and play sounds. -# +SPAWN (or +CREATE) = Mob transformations, spawning of most atoms including mobs (high-risk atoms will require the +FUN flag too). -# +PROCCALL = The ability to call any proc on any entity. -# +MOD = Low level admin abilities. -# +MENTOR = The ability to answer questions. -# +EVERYTHING (or +HOST or +ALL) = Simply gives you everything without having to type every flag. - +# +MENTOR = Access only to the Question's Ahelp and has little way of metagaming the game. +# +ADMIN = general admin tools, verbs etc +# +FUN = events, other event-orientated actions. Access to the fun secrets in the secrets panel. +# +BAN = the ability to ban, jobban and fullban +# +STEALTH = the ability to stealthmin (make yourself appear with a fake name to everyone but other admins +# +POSSESS = the ability to possess objects +# +REJUV (or +REJUVINATE) = the ability to heal, respawn, modify damage and use godmode +# +BUILD (or +BUILDMODE) = the ability to use buildmode +# +SERVER = higher-risk admin verbs and abilities, such as those which affect the server configuration. +# +DEBUG = debug tools used for diagnosing and fixing problems. It's useful to give this to coders so they can investigate problems on a live server. +# +VAREDIT = everyone may view viewvars/debugvars/whatever you call it. This keyword allows you to actually EDIT those variables. +# +RIGHTS (or +PERMISSIONS) = allows you to promote and/or demote people. +# +SOUND (or +SOUNDS) = allows you to upload and play sounds +# +SPAWN (or +CREATE) = mob transformations, spawning of most atoms including mobs (high-risk atoms, e.g. blackholes, will require the +FUN flag too) +# +EVERYTHING (or +HOST or +ALL) = Simply gives you everything without having to type every flag + +# Admin Ranks Admin Observer -Mentor +MENTOR -Moderator +MOD +Mentor +MENTOR +Moderator +MOD +Trial Admin +ADMIN +BAN +DEBUG +REJUVINATE +Game Admin +ADMIN +BAN +DEBUG +REJUVINATE +BUILDMODE +EVENT +SERVER +POSSESS +STEALTH +VAREDIT +SOUND +SPAWN +Senior Admin +ADMIN +BAN +DEBUG +REJUVINATE +BUILDMODE +EVENT +SERVER +POSSESS +STEALTH +VAREDIT +SOUND +SPAWN +Retired Admin +ADMIN +BAN +STEALTH +VAREDIT +SPAWN +Head of Staff +EVERYTHING -Admin Candidate +ADMIN -Trial Admin +@ +SPAWN +REJUV +VAREDIT +BAN -Badmin +@ +POSSESS +BUILDMODE +SERVER +FUN -Game Admin +@ +STEALTH +SOUNDS +DEBUG +PERMISSIONS -Game Master +EVERYTHING -Head Admin +EVERYTHING -Retired Admin +ADMIN +STEALTH - -Host +EVERYTHING - -Developer +DEBUG +VAREDIT +SERVER +SPAWN +REJUV +POSSESS +BUILDMODE \ No newline at end of file +Hosting Provider +EVERYTHING + +# Coder Ranks +Trial Coder +ADMIN +VAREDIT +REJUVINATE +DEBUG +Coders +ADMIN +VAREDIT +REJUVINATE +DEBUG +BUILDMODE +EVENT +SERVER +POSSESS +STEALTH +SOUND +SPAWN +Retired Coder +ADMIN +VAREDIT +REJUVINATE +DEBUG +BUILDMODE +EVENT +SERVER +POSSESS +STEALTH +SOUND +SPAWN +BAN +Maintainers +EVERYTHING \ No newline at end of file diff --git a/config/example/config.txt b/config/example/config.txt index 5bcd469be87..4f1a9102c20 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -77,24 +77,23 @@ KICK_INACTIVE ## ## default probablity is 1, increase to make that mode more likely to be picked ## set to 0 to disable that mode +PROBABILITY EXTEND-A-TRAITORMONGOUS 3 +PROBABILITY TRAITORCHAN 3 +PROBABILITY TRAITORVAMP 3 +PROBABILITY REVOLUTION 0 +PROBABILITY SHADOWLING 2 +PROBABILITY CULT 4 +PROBABILITY CHANGELING 3 +PROBABILITY WIZARD 2 +PROBABILITY BLOB 1 +PROBABILITY RAGINMAGES 0 +PROBABILITY METEOR 0 +PROBABILITY HEIST 0 +PROBABILITY VAMPIRE 3 +PROBABILITY NATIONS 0 PROBABILITY EXTENDED 2 PROBABILITY NUCLEAR 3 PROBABILITY ABDUCTION 0 -PROBABILITY CHANGELING 3 -PROBABILITY CULT 4 -PROBABILITY EXTEND-A-TRAITORMONGOUS 5 -PROBABILITY TRAITORCHAN 4 -PROBABILITY TRAITORVAMP 4 -PROBABILITY BLOB 2 -PROBABILITY REVOLUTION 0 -PROBABILITY HEIST 1 -PROBABILITY WIZARD 2 -PROBABILITY VAMPIRE 3 -PROBABILITY RAGINMAGES 0 -PROBABILITY METEOR 0 -PROBABILITY TRAITOR 0 -PROBABILITY SHADOWLING 2 -PROBABILITY NATIONS 0 ## Hash out to disable random events during the round. ALLOW_RANDOM_EVENTS @@ -203,6 +202,7 @@ LOAD_JOBS_FROM_TXT ## Remove the # to allow special 'Easter-egg' events on special holidays such as seasonal holidays and stuff like 'Talk Like a Pirate Day' :3 YAARRR ALLOW_HOLIDAYS + ##Defines the ticklag for the world. 0.9 is the normal one, 0.5 is smoother. TICKLAG 0.5 @@ -286,7 +286,7 @@ EVENT_DELAY_UPPER 15;45;70 EVENT_CUSTOM_START_MAJOR 80;100 ## Strength of ambient star light. Set to 0 or less to turn off. -STARLIGHT 0 +STARLIGHT 2 ## Player rerouting stuff ## If not 0, players can be rerouted to an overflow server after a certain cap is reached From f1ae2e3f3a99c9c51deb43f459a0efcaafe1798f Mon Sep 17 00:00:00 2001 From: davipatury Date: Sat, 18 Feb 2017 20:49:38 -0200 Subject: [PATCH 067/164] Shuttle Console nano-ui. --- code/modules/shuttle/shuttle.dm | 48 +++++++++++++++-------------- nano/templates/shuttle_console.tmpl | 28 +++++++++++++++++ 2 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 nano/templates/shuttle_console.tmpl diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index d48d892a86f..72f83153687 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -676,41 +676,41 @@ return if(!shuttleId) return - src.add_fingerprint(usr) - connect() + add_fingerprint(user) + ui_interact(user) - var/list/options = params2list(possible_destinations) +/obj/machinery/computer/shuttle/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) var/obj/docking_port/mobile/M = shuttle_master.getShuttle(shuttleId) - var/dat = "Status: [M ? M.getStatusText() : "*Missing*"]

    " + ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "shuttle_console.tmpl", M ? M.name : "shuttle", 300, 200) + ui.open() + +/obj/machinery/computer/shuttle/ui_data(mob/user, ui_key = "main", datum/topic_state/state = default_state) + var/data[0] + var/obj/docking_port/mobile/M = shuttle_master.getShuttle(shuttleId) + data["status"] = M ? M.getStatusText() : null if(M) - var/destination_found + data["shuttle"] = 1 + var/list/docking_ports = list() + data["docking_ports"] = docking_ports + var/list/options = params2list(possible_destinations) for(var/obj/docking_port/stationary/S in shuttle_master.stationary) if(!options.Find(S.id)) continue if(!M.check_dock(S)) continue - destination_found = 1 - dat += "Send to [S.name]
    " - if(!destination_found) - dat += "Shuttle Locked
    " - if(admin_controlled) - dat += "Authorized personnel only
    " - dat += "Request Authorization
    " - if(docking_request) - dat += "Request docking at NSS Cyberiad
    " - dat += "Close" + docking_ports[++docking_ports.len] = list("name" = S.name, "id" = S.id) + data["admin_controlled"] = admin_controlled + data["docking_request"] = docking_request - var/datum/browser/popup = new(user, "computer", M ? M.name : "shuttle", 300, 200) - popup.set_content("
    [dat]
    ") - popup.set_title_image(usr.browse_rsc_icon(src.icon, src.icon_state)) - popup.open() + return data /obj/machinery/computer/shuttle/Topic(href, href_list) if(..()) return 1 - usr.set_machine(src) - src.add_fingerprint(usr) + if(!allowed(usr)) to_chat(usr, "Access denied.") return @@ -728,7 +728,7 @@ to_chat(usr, "Invalid shuttle requested.") else to_chat(usr, "Unable to comply.") - updateUsrDialog() + return 1 /obj/machinery/computer/shuttle/emag_act(mob/user) if(!emagged) @@ -760,10 +760,11 @@ to_chat(usr, "Your request has been recieved by Centcom.") log_admin("[key_name(usr)] requested to move the transport ferry to Centcom.") message_admins("FERRY: [key_name_admin(usr)] (Move Ferry) is requesting to move the transport ferry to Centcom.") + . = 1 + nanomanager.update_uis(src) spawn(600) //One minute cooldown cooldown = 0 - /obj/machinery/computer/shuttle/ert name = "specops shuttle console" //circuit = /obj/item/weapon/circuitboard/ert @@ -846,6 +847,7 @@ var/global/trade_dockrequest_timelimit = 0 to_chat(usr, "Request sent.") event_announcement.Announce(docking_request_message, "Docking Request") trade_dockrequest_timelimit = world.time + 1200 // They have 2 minutes to approve the request. + return 1 /obj/machinery/computer/shuttle/trade/sol req_access = list(access_trade_sol) diff --git a/nano/templates/shuttle_console.tmpl b/nano/templates/shuttle_console.tmpl new file mode 100644 index 00000000000..2b16495d522 --- /dev/null +++ b/nano/templates/shuttle_console.tmpl @@ -0,0 +1,28 @@ + + +
    +
    Status: {{:data.status ? data.status : '*Missing*'}}
    + {{if data.shuttle}} + {{for data.docking_ports}} +
    +
    {{:helper.link('Send to ' + value.name, 'sign-out', {'move' : value.id})}}
    +
    + {{empty}} +

    Shuttle Locked

    + {{if data.admin_controlled}} +
    Authorized personnel only
    +
    +
    {{:helper.link('Request Authorization', 'share-square-o', {'request' : 1})}}
    +
    + {{/if}} + {{/for}} + {{if data.docking_request}} +
    +
    {{:helper.link('Request docking at NSS Cyberiad', 'share-square-o', {'request' : 1})}}
    +
    + {{/if}} + {{/if}} +
    \ No newline at end of file From fc710e71d48f128956305aadaa69dc7fe783375f Mon Sep 17 00:00:00 2001 From: Crazylemon64 Date: Sat, 18 Feb 2017 15:21:39 -0800 Subject: [PATCH 068/164] Telecomms monitor is speedier now --- code/game/machinery/telecomms/logbrowser.dm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/game/machinery/telecomms/logbrowser.dm b/code/game/machinery/telecomms/logbrowser.dm index ae0b2738d1b..a77edd5cadc 100644 --- a/code/game/machinery/telecomms/logbrowser.dm +++ b/code/game/machinery/telecomms/logbrowser.dm @@ -24,7 +24,8 @@ if(stat & (BROKEN|NOPOWER)) return user.set_machine(src) - var/dat = "Telecommunication Server Monitor
    Telecommunications Server Monitor
    " + var/list/dat = list() + dat += "Telecommunication Server Monitor
    Telecommunications Server Monitor
    " switch(screen) @@ -136,7 +137,7 @@ - user << browse(dat, "window=comm_monitor;size=575x400") + user << browse(dat.Join(""), "window=comm_monitor;size=575x400") onclose(user, "server_control") temp = "" From d4338bed12b0b98edb6b559dd7b976f663d7a5df Mon Sep 17 00:00:00 2001 From: davipatury Date: Sat, 18 Feb 2017 22:18:01 -0200 Subject: [PATCH 069/164] Some changes! --- code/modules/shuttle/shuttle.dm | 5 +-- nano/templates/shuttle_console.tmpl | 47 +++++++++++++++++------------ 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 72f83153687..6f019350217 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -174,7 +174,7 @@ */ /obj/docking_port/stationary/transit - name = "In Transit" + name = "In transit" turf_type = /turf/space/transit lock_shuttle_doors = 1 @@ -183,7 +183,7 @@ if(!..()) return 0 - name = "In Transit" //This looks weird, but- it means that the on-map instances can be named something actually usable to search for, but still appear correctly in terminals. + name = "In transit" //This looks weird, but- it means that the on-map instances can be named something actually usable to search for, but still appear correctly in terminals. shuttle_master.transit += src return 1 @@ -702,6 +702,7 @@ if(!M.check_dock(S)) continue docking_ports[++docking_ports.len] = list("name" = S.name, "id" = S.id) + data["docking_ports_len"] = docking_ports.len data["admin_controlled"] = admin_controlled data["docking_request"] = docking_request diff --git a/nano/templates/shuttle_console.tmpl b/nano/templates/shuttle_console.tmpl index 2b16495d522..d16f39a8b20 100644 --- a/nano/templates/shuttle_console.tmpl +++ b/nano/templates/shuttle_console.tmpl @@ -3,26 +3,35 @@ Title: Shuttle Console Used In File(s): /code/modules/shuttle/shuttle.dm --> -
    -
    Status: {{:data.status ? data.status : '*Missing*'}}
    - {{if data.shuttle}} - {{for data.docking_ports}} -
    -
    {{:helper.link('Send to ' + value.name, 'sign-out', {'move' : value.id})}}
    -
    - {{empty}} -

    Shuttle Locked

    - {{if data.admin_controlled}} -
    Authorized personnel only
    -
    -
    {{:helper.link('Request Authorization', 'share-square-o', {'request' : 1})}}
    +
    +
    Location:
    +
    {{:data.status ? data.status : '*Missing*'}}
    +
    +{{if data.shuttle}} + {{if data.docking_ports_len}} +
    +
    + {{for data.docking_ports}} +
    {{:helper.link('Send to ' + value.name, 'sign-out', {'move' : value.id})}}
    + {{/for}} +
    + {{else}} +
    +
    Status:
    +
    Shuttle locked + {{if data.admin_controlled}} + , authorized personnel only +
    +
    +
    {{:helper.link('Request authorization', 'share-square-o', {'request' : 1})}}
    + {{else}}
    - {{/if}} - {{/for}} - {{if data.docking_request}} -
    -
    {{:helper.link('Request docking at NSS Cyberiad', 'share-square-o', {'request' : 1})}}
    +
    {{/if}} {{/if}} -
    \ No newline at end of file + + {{if data.docking_request}} +
    {{:helper.link('Request docking at NSS Cyberiad', 'share-square-o', {'request' : 1})}}
    + {{/if}} +{{/if}} \ No newline at end of file From c8ec2347e6a95f20ebd17af968bb7d94338bc849 Mon Sep 17 00:00:00 2001 From: Crazylemon64 Date: Sat, 18 Feb 2017 17:38:19 -0800 Subject: [PATCH 070/164] Fixes the obvious optimization --- code/__DEFINES/mob.dm | 10 ++++++++++ code/game/machinery/telecomms/logbrowser.dm | 19 ++++++++----------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/code/__DEFINES/mob.dm b/code/__DEFINES/mob.dm index 7ab8a19f86d..0e4a9f40ef1 100644 --- a/code/__DEFINES/mob.dm +++ b/code/__DEFINES/mob.dm @@ -129,11 +129,21 @@ #define isswarmer(A) (istype((A), /mob/living/simple_animal/hostile/swarmer)) #define isguardian(A) (istype((A), /mob/living/simple_animal/hostile/guardian)) + + #define issilicon(A) (istype((A), /mob/living/silicon)) #define isAI(A) (istype((A), /mob/living/silicon/ai)) #define isrobot(A) (istype((A), /mob/living/silicon/robot)) #define ispAI(A) (istype((A), /mob/living/silicon/pai)) +// For the tcomms monitor +#define ispathhuman(A) (ispath(A, /mob/living/carbon/human)) +#define ispathbrain(A) (ispath(A, /mob/living/carbon/brain)) +#define ispathslime(A) (ispath(A, /mob/living/carbon/slime)) +#define ispathbot(A) (ispath(A, /mob/living/simple_animal/bot)) +#define ispathsilicon(A) (ispath(A, /mob/living/silicon)) +#define ispathanimal(A) (ispath(A, /mob/living/simple_animal)) + #define isAutoAnnouncer(A) (istype((A), /mob/living/automatedannouncer)) #define isAIEye(A) (istype((A), /mob/camera/aiEye)) diff --git a/code/game/machinery/telecomms/logbrowser.dm b/code/game/machinery/telecomms/logbrowser.dm index a77edd5cadc..49133b1cd43 100644 --- a/code/game/machinery/telecomms/logbrowser.dm +++ b/code/game/machinery/telecomms/logbrowser.dm @@ -76,28 +76,27 @@ var/race // The actual race of the mob var/language = "Human" // MMIs, pAIs, Cyborgs and humans all speak Human var/mobtype = C.parameters["mobtype"] - var/mob/M = new mobtype - if(ishuman(M) || isbrain(M)) - var/mob/living/carbon/human/H = M - race = "[H.species.name]" + if(ispathhuman(mobtype) || ispathbrain(mobtype)) + race = "Human" // The initializing thing wouldn't work anyways since it just kept the path, and kept no species data - else if(issmall(M)) + else if(ispath(mobtype, /mob/living/carbon/human/monkey)) // I am aware this will only work for always-monkeys, and not + // those made a monkey after first being a human. race = "Monkey" language = race - else if(issilicon(M) || C.parameters["job"] == "AI") // sometimes M gets deleted prematurely for AIs... just check the job + else if(ispathsilicon(mobtype) || C.parameters["job"] == "AI") // sometimes M gets deleted prematurely for AIs... just check the job race = "Artificial Life" - else if(isslime(M)) // NT knows a lot about slimes, but not aliens. Can identify slimes + else if(ispathslime(mobtype)) // NT knows a lot about slimes, but not aliens. Can identify slimes race = "Slime" language = race - else if(isbot(M)) + else if(ispathbot(mobtype)) race = "Bot" - else if(isanimal(M)) + else if(ispathanimal(mobtype)) race = "Domestic Animal" language = race @@ -105,8 +104,6 @@ race = "Unidentifiable" language = race - qdel(M) - // -- If the orator is a human, or universal translate is active, OR mob has universal speech on -- if(language == "Human" || universal_translate || C.parameters["uspeech"]) From 9cb39cf07d36abac4cc27772411e670549335bf3 Mon Sep 17 00:00:00 2001 From: Markolie Date: Sun, 19 Feb 2017 03:37:05 +0100 Subject: [PATCH 071/164] Add initial version of door alarms --- code/game/area/areas.dm | 6 ++++-- code/game/machinery/doors/firedoor.dm | 23 +++++++++++++++++------ icons/obj/doors/Doorfire.dmi | Bin 3783 -> 8021 bytes 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 96ffc936a7b..eb743afad62 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -81,9 +81,10 @@ /area/proc/air_doors_close() if(!air_doors_activated) - air_doors_activated = 1 + air_doors_activated = TRUE for(var/obj/machinery/door/firedoor/D in src) if(!D.welded) + D.activate_alarm() if(D.operating) D.nextstate = CLOSED else if(!D.density) @@ -92,9 +93,10 @@ /area/proc/air_doors_open() if(air_doors_activated) - air_doors_activated = 0 + air_doors_activated = FALSE for(var/obj/machinery/door/firedoor/D in src) if(!D.welded) + D.deactivate_alarm() if(D.operating) D.nextstate = OPEN else if(D.density) diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 29270a54c99..25aaa6d810b 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -13,9 +13,9 @@ icon = 'icons/obj/doors/Doorfireglass.dmi' icon_state = "door_open" opacity = 0 - density = 0 - heat_proof = 1 - glass = 1 + density = FALSE + heat_proof = TRUE + glass = TRUE power_channel = ENVIRON closed_layer = 3.11 auto_close_time = 50 @@ -24,9 +24,10 @@ var/force_open_time = 300 var/assembly_type = /obj/structure/firelock_frame var/nextstate = null - var/welded = 0 - var/boltslocked = 1 - var/can_deconstruct = 1 + var/welded = FALSE + var/boltslocked = TRUE + var/can_deconstruct = TRUE + var/active_alarm = TRUE /obj/machinery/door/firedoor/Bumped(atom/AM) if(p_open || operating) @@ -127,6 +128,8 @@ /obj/machinery/door/firedoor/update_icon() overlays.Cut() + if(active_alarm && !(stat & NOPOWER)) + overlays += image('icons/obj/doors/Doorfire.dmi', "alarmlights") if(density) icon_state = "door_closed" if(welded) @@ -135,6 +138,14 @@ icon_state = "door_open" if(welded) overlays += "welded_open" + +/obj/machinery/door/firedoor/proc/activate_alarm() + active_alarm = TRUE + update_icon() + +/obj/machinery/door/firedoor/proc/deactivate_alarm() + active_alarm = FALSE + update_icon() /obj/machinery/door/firedoor/open() . = ..() diff --git a/icons/obj/doors/Doorfire.dmi b/icons/obj/doors/Doorfire.dmi index 1f3999b774e08340d7fc4bbdb39d94d9ad7fdb0c..94ec8b967fbf9fdc7bf301a121716d30fd313bf3 100644 GIT binary patch literal 8021 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 From b7f0ca71f70ff3575d6fdd6cfd4c88e718f79481 Mon Sep 17 00:00:00 2001 From: Markolie Date: Sun, 19 Feb 2017 03:43:20 +0100 Subject: [PATCH 072/164] Give chaplain soulstone on Cyberiad, modify soulstone path on MetaStation --- _maps/map_files/MetaStation/MetaStation.v41A.II.dmm | 2 +- _maps/map_files/cyberiad/cyberiad.dmm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm index 77c0a8f0fa3..de72bb217e9 100644 --- a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm +++ b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm @@ -7701,7 +7701,7 @@ "cSe" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8; initialize_directions = 11},/obj/structure/disposalpipe/segment{dir = 8; icon_state = "pipe-c"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/chapel/office) "cSf" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 8; on = 1; scrub_N2O = 0; scrub_Toxins = 0},/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/chapel/office) "cSg" = (/obj/machinery/door/morgue{name = "Relic Closet"; req_access_txt = "22"},/turf/simulated/floor/plasteel{tag = "icon-cult"; icon_state = "cult"; dir = 2},/area/chapel/office) -"cSh" = (/obj/structure/table/woodentable,/obj/item/weapon/spellbook/oneuse/smoke{name = "mysterious old book of "},/obj/item/weapon/reagent_containers/food/drinks/bottle/holywater{name = "flask of holy water"; pixel_x = -2; pixel_y = 2},/obj/item/weapon/nullrod{pixel_x = 4},/obj/item/organ/internal/heart,/obj/item/device/soulstone,/turf/simulated/floor/plasteel{tag = "icon-cult"; icon_state = "cult"; dir = 2},/area/chapel/office) +"cSh" = (/obj/structure/table/woodentable,/obj/item/weapon/spellbook/oneuse/smoke{name = "mysterious old book of "},/obj/item/weapon/reagent_containers/food/drinks/bottle/holywater{name = "flask of holy water"; pixel_x = -2; pixel_y = 2},/obj/item/weapon/nullrod{pixel_x = 4},/obj/item/organ/internal/heart,/obj/item/device/soulstone/anybody/chaplain,/turf/simulated/floor/plasteel{tag = "icon-cult"; icon_state = "cult"; dir = 2},/area/chapel/office) "cSi" = (/obj/machinery/door/airlock/maintenance{name = "Chapel Maintenance Access "; req_access_txt = "0"; req_one_access_txt = "12;27"},/obj/structure/cable/yellow{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plating,/area/maintenance/aft{name = "Aft Maintenance"}) "cSj" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/obj/machinery/camera{c_tag = "Departure Lounge - Port Fore"; dir = 4; network = list("SS13")},/obj/item/weapon/twohanded/required/kirbyplants{icon_state = "plant-24"; layer = 4.1; tag = "icon-plant-24"},/turf/simulated/floor/plasteel{dir = 8; icon_state = "warning"},/area/hallway/secondary/exit{name = "\improper Departure Lounge"}) "cSk" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel,/area/hallway/secondary/exit{name = "\improper Departure Lounge"}) diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index 532fcd6f9bc..4169a96922f 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -2931,7 +2931,7 @@ "bes" = (/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/crema_switch{pixel_x = 25},/obj/machinery/light/small{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/office) "bet" = (/obj/structure/table/woodentable,/obj/item/device/flashlight/lamp{pixel_y = 10},/obj/structure/disposalpipe/segment,/obj/item/device/eftpos,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/chapel/office) "beu" = (/obj/structure/table/woodentable,/obj/item/weapon/pen,/obj/item/weapon/reagent_containers/food/drinks/bottle/holywater,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/chapel/office) -"bev" = (/obj/structure/table/woodentable,/obj/item/weapon/nullrod,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/chapel/office) +"bev" = (/obj/structure/table/woodentable,/obj/item/device/soulstone/anybody/chaplain,/obj/item/weapon/nullrod,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/chapel/office) "bew" = (/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/chapel/office) "bex" = (/obj/structure/closet/coffin,/obj/machinery/door/window/eastleft{dir = 8; name = "Coffin Storage"; req_access_txt = "22"},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/office) "bey" = (/obj/item/weapon/storage/bible,/obj/structure/table/glass,/turf/simulated/floor/plasteel{dir = 4; icon_state = "chapel"},/area/chapel/main) From 850da229c65c7ce1409fc8df5fc3fed01a558c79 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 18 Feb 2017 23:45:34 -0500 Subject: [PATCH 073/164] Automatic changelog generation for PR #6475 [ci skip] --- html/changelogs/AutoChangeLog-pr-6475.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-6475.yml diff --git a/html/changelogs/AutoChangeLog-pr-6475.yml b/html/changelogs/AutoChangeLog-pr-6475.yml new file mode 100644 index 00000000000..9e6845f1570 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-6475.yml @@ -0,0 +1,4 @@ +author: "Krausus" +delete-after: True +changes: + - tweak: "End-of-round sounds will now play just in time for them to end as the server reboots, rather than starting the moment it reboots." From a26a4543d96308cf3d24d1b30dea94c24e5a61ec Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sat, 18 Feb 2017 23:48:12 -0500 Subject: [PATCH 074/164] Automatic changelog compile, [ci skip] --- html/changelog.html | 4 ++++ html/changelogs/.all_changelog.yml | 3 +++ html/changelogs/AutoChangeLog-pr-6475.yml | 4 ---- 3 files changed, 7 insertions(+), 4 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-6475.yml diff --git a/html/changelog.html b/html/changelog.html index a0c2cfa1aa4..58333c2ca13 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -66,6 +66,10 @@
  • Mind transfer abilities work again
  • Centcomm is no longer obnoxiously pedantic, regarding BSA deployment
  • +

    Krausus updated:

    +
      +
    • End-of-round sounds will now play just in time for them to end as the server reboots, rather than starting the moment it reboots.
    • +

    Kyep updated: