diff --git a/.github/AUTODOC_GUIDE.md b/.github/AUTODOC_GUIDE.md new file mode 100644 index 00000000000..6a7d521a04d --- /dev/null +++ b/.github/AUTODOC_GUIDE.md @@ -0,0 +1,108 @@ +# dmdoc +[DOCUMENTATION]: https://codedocs.paradisestation.org/ + +[BYOND]: https://secure.byond.com/ + +[DMDOC]: https://github.com/AffectedArc07/ParaSpacemanDMM/tree/master/src/dmdoc + +[DMDOC] is a documentation generator for DreamMaker, the scripting language +of the [BYOND] game engine. It produces simple static HTML files based on +documented files, macros, types, procs, and vars. + +We use **dmdoc** to generate [DOCUMENTATION] for our code, and that documentation +is automatically generated and built on every new commit to the master branch + +This gives new developers a clickable reference [DOCUMENTATION] they can browse to better help +gain understanding of the Paradise codebase structure and api reference. + +## Documenting code on Paradise +We use block comments to document procs and classes, and we use `///` line comments +when documenting individual variables. + +Documentation is not required at Paradise, but it is highly recommended that all new code be covered with DMdoc code, according to the [Specifications](#Specification) + +We also recommend that when you touch older code, you document the functions that you +have touched in the process of updating that code + +### Specification +A class *should* always be autodocumented, and all public functions *should* be documented + +All class level defined variables *should* be documented + +Internal functions *can* be documented, but may not be + +A public function is any function that a developer might reasonably call while using +or interacting with your object. Internal functions are helper functions that your +public functions rely on to implement logic + + +### Documenting a proc +When documenting a proc, we give a short one line description (as this is shown +next to the proc definition in the list of all procs for a type or global +namespace), then a longer paragraph which will be shown when the user clicks on +the proc to jump to it's definition +``` +/** + * Short description of the proc + * + * Longer detailed paragraph about the proc + * including any relevant detail + * Arguments: + * * arg1 - Relevance of this argument + * * arg2 - Relevance of this argument + */ +``` + +### Documenting a class +We first give the name of the class as a header, this can be omitted if the name is +just going to be the typepath of the class, as dmdoc uses that by default + +Then we give a short oneline description of the class + +Finally we give a longer multi paragraph description of the class and it's details +``` +/** + * # Classname (Can be omitted if it's just going to be the typepath) + * + * The short overview + * + * A longer + * paragraph of functionality about the class + * including any assumptions/special cases + * + */ +``` + +### Documenting a variable/define +Give a short explanation of what the variable, in the context of the class, or define is. +``` +/// Type path of item to go in suit slot +var/suit = null +``` + +## Module level description of code +Modules are the best way to describe the structure/intent of a package of code +where you don't want to be tied to the formal layout of the class structure. + +On Paradise we do this by adding markdown files inside the `code` directory +that will also be rendered and added to the modules tree. The structure for +these is deliberately not defined, so you can be as freeform and as wheeling as +you would like. + +[Here is a representative example of what you might write](https://codedocs.paradisestation.org/code/modules/keybindings/readme.html) + +## Special variables +You can use certain special template variables in DM DOC comments and they will be expanded +``` + [DEFINE_NAME] - Expands to a link to the define definition if documented + [/mob] - Expands to a link to the docs for the /mob class + [/mob/proc/Dizzy] - Expands to a link that will take you to the /mob class and anchor you to the dizzy proc docs + [/mob/var/stat] - Expands to a link that will take you to the /mob class and anchor you to the stat var docs +``` + +You can customise the link name by using `[link name][link shorthand].` + +eg. `[see more about dizzy here] [/mob/proc/Dizzy]` + +This is very useful to quickly link to other parts of the autodoc code to expand +upon a comment made, or reasoning about code diff --git a/.github/workflows/generate_autodoc.yml b/.github/workflows/generate_autodoc.yml new file mode 100644 index 00000000000..44eb69eb570 --- /dev/null +++ b/.github/workflows/generate_autodoc.yml @@ -0,0 +1,32 @@ +name: Generate Documentation + +on: + schedule: + - cron: "0 0 * * *" # Every day at the very start of the day + +jobs: + generate_docs: + name: 'Generate Documentation' + runs-on: ubuntu-18.04 + steps: + - name: 'Update Branch' + uses: actions/checkout@v2 + with: + fetch-depth: 1 + ref: master + + - name: 'Generate Documentation' + run: | + ./tools/github-actions/doc-generator + touch dmdoc/.nojekyll + # Nojekyll is important to disable jeykll syntax, which can mess with files that start with underscores + + - name: 'Deploy Documentation' + uses: crazy-max/ghaction-github-pages@v2 + with: + keep_history: false + build_dir: dmdoc + jekyll: false + fqdn: codedocs.paradisestation.org + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/SpacemanDMM.toml b/SpacemanDMM.toml new file mode 100644 index 00000000000..9b658dce0fa --- /dev/null +++ b/SpacemanDMM.toml @@ -0,0 +1,6 @@ +[langserver] +dreamchecker = true + +[code_standards] +disallow_relative_type_definitions = true +disallow_relative_proc_definitions = true diff --git a/_maps/map_files/RandomRuins/LavaRuins/lavaland_biodome_winter.dmm b/_maps/map_files/RandomRuins/LavaRuins/lavaland_biodome_winter.dmm index 3d8d22218f6..671822abfeb 100644 --- a/_maps/map_files/RandomRuins/LavaRuins/lavaland_biodome_winter.dmm +++ b/_maps/map_files/RandomRuins/LavaRuins/lavaland_biodome_winter.dmm @@ -167,7 +167,7 @@ /turf/simulated/floor/wood, /area/ruin/powered/snow_cabin) "aL" = ( -/obj/structure/displaycase/captain, +/obj/mecha/working/ripley/mining, /turf/simulated/floor/wood, /area/ruin/powered/snow_cabin) "aM" = ( @@ -392,12 +392,6 @@ /obj/structure/filingcabinet, /turf/simulated/floor/pod/dark, /area/ruin/powered/snow_biodome) -"UM" = ( -/obj/machinery/computer/monitor/secret{ - dir = 1 - }, -/turf/simulated/floor/pod/dark, -/area/ruin/powered/snow_biodome) "Wg" = ( /turf/simulated/wall/r_wall, /area/ruin/powered/snow_biodome) @@ -484,7 +478,7 @@ HP tl PK gz -UM +HP Wg ak ak diff --git a/_maps/map_files/RandomRuins/SpaceRuins/syndiedepot.dmm b/_maps/map_files/RandomRuins/SpaceRuins/syndiedepot.dmm index 1dc60364d99..ceb8067f7ac 100644 --- a/_maps/map_files/RandomRuins/SpaceRuins/syndiedepot.dmm +++ b/_maps/map_files/RandomRuins/SpaceRuins/syndiedepot.dmm @@ -68,7 +68,6 @@ "an" = ( /obj/machinery/navbeacon/invisible{ codes_txt = "patrol;next_patrol=SDNW"; - invisibility = 100; location = "SDNE" }, /turf/simulated/floor/plating/asteroid/airless, @@ -292,15 +291,13 @@ "aU" = ( /obj/machinery/navbeacon/invisible{ codes_txt = "patrol;next_patrol=SDSW"; - invisibility = 100; location = "SDNW" }, /turf/simulated/floor/plating/asteroid/airless, /area/syndicate_depot/outer) "aV" = ( /obj/machinery/light{ - dir = 4; - icon_state = "tube1" + dir = 4 }, /turf/simulated/floor/plating/asteroid/airless, /area/syndicate_depot/outer) @@ -429,8 +426,7 @@ /area/syndicate_depot/core) "bo" = ( /obj/machinery/light{ - dir = 4; - icon_state = "tube1" + dir = 4 }, /obj/effect/spawner/random_spawners/syndicate/loot, /turf/simulated/floor/plasteel{ @@ -512,7 +508,6 @@ id = "syndi_depot_rear"; idle_power_usage = 0; name = "mysterious button"; - normaldoorcontrol = 0; pixel_x = 24; use_power = 0 }, @@ -663,8 +658,8 @@ /obj/machinery/turretid/syndicate{ name = "external turret controls"; pixel_x = -32; - pixel_y = 0; - req_access = list(150) + req_access = null; + req_access_txt = "150" }, /turf/simulated/floor/plasteel{ icon_state = "dark" @@ -745,9 +740,8 @@ /area/syndicate_depot/core) "ce" = ( /obj/machinery/light/small{ - tag = "icon-bulb1 (EAST)"; - icon_state = "bulb1"; - dir = 4 + dir = 4; + tag = "icon-bulb1 (EAST)" }, /turf/simulated/floor/mineral/silver, /area/syndicate_depot/core) @@ -757,7 +751,6 @@ id = "syndi_depot_rear"; idle_power_usage = 0; name = "mysterious button"; - normaldoorcontrol = 0; use_power = 0 }, /obj/structure/sign/poster/contraband/syndicate_recruitment, @@ -774,8 +767,8 @@ /area/syndicate_depot/core) "ci" = ( /obj/structure/cable{ - icon_state = "0-2"; - d2 = 2 + d2 = 2; + icon_state = "0-2" }, /obj/machinery/power/smes/upgraded{ charge = 5e+006; @@ -845,7 +838,6 @@ "cr" = ( /obj/structure/sink{ dir = 4; - icon_state = "sink"; pixel_x = 12 }, /turf/simulated/floor/mineral/silver, @@ -1154,7 +1146,6 @@ "dc" = ( /obj/machinery/navbeacon/invisible{ codes_txt = "patrol;next_patrol=SDSE"; - invisibility = 100; location = "SDSW" }, /turf/simulated/floor/plating/asteroid/airless, @@ -1179,7 +1170,6 @@ "df" = ( /obj/machinery/navbeacon/invisible{ codes_txt = "patrol;next_patrol=SDNE"; - invisibility = 100; location = "SDSE" }, /turf/simulated/floor/plating/asteroid/airless, diff --git a/_maps/map_files/cyberiad/z2.dmm b/_maps/map_files/cyberiad/z2.dmm index 4c916fe365c..66f2f61abee 100644 --- a/_maps/map_files/cyberiad/z2.dmm +++ b/_maps/map_files/cyberiad/z2.dmm @@ -4296,55 +4296,20 @@ dir = 2 }, /area/centcom/control) -"mE" = ( -/obj/structure/flora/ausbushes/lavendergrass, -/turf/unsimulated/floor{ - icon_state = "grass1"; - name = "grass" - }, -/area/centcom/specops) -"mF" = ( -/obj/structure/flora/ausbushes/stalkybush, -/turf/unsimulated/floor{ - icon_state = "grass1"; - name = "grass" - }, -/area/centcom/specops) -"mG" = ( -/obj/structure/flora/ausbushes/pointybush, -/turf/unsimulated/floor{ - icon_state = "grass1"; - name = "grass" - }, -/area/centcom/specops) -"mH" = ( -/obj/structure/flora/ausbushes/ywflowers, -/turf/unsimulated/floor{ - icon_state = "grass1"; - name = "grass" - }, -/area/centcom/specops) "mI" = ( /obj/structure/flora/ausbushes/brflowers, /turf/unsimulated/floor{ icon_state = "grass1"; name = "grass" }, -/area/centcom/specops) -"mJ" = ( -/obj/structure/flora/ausbushes/sparsegrass, -/turf/unsimulated/floor{ - icon_state = "grass1"; - name = "grass" - }, -/area/centcom/specops) +/area/centcom/control) "mK" = ( /obj/structure/flora/ausbushes/reedbush, /turf/unsimulated/floor{ icon_state = "grass1"; name = "grass" }, -/area/centcom/specops) +/area/centcom/control) "mL" = ( /turf/unsimulated/floor{ dir = 1; @@ -36255,7 +36220,7 @@ lH lH mu su -mF +mZ mY su nD @@ -36512,7 +36477,7 @@ mc lH lH su -mE +nd mX su nD @@ -36769,7 +36734,7 @@ mc lH lH su -mH +mY na su nD @@ -37026,7 +36991,7 @@ lH lH lH su -mG +WW mZ su nD @@ -37283,7 +37248,7 @@ lH mk mw su -mJ +na ne su nD diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm index 7e7a6e9eb49..ae099bf6d36 100644 --- a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm +++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm @@ -137,51 +137,56 @@ return add_fingerprint(user) - ui_interact(user) + tgui_interact(user) /obj/machinery/atmospherics/binary/passive_gate/attack_ghost(mob/user) - ui_interact(user) + tgui_interact(user) -/obj/machinery/atmospherics/binary/passive_gate/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/atmospherics/binary/passive_gate/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) user.set_machine(src) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "atmos_pump.tmpl", name, 385, 115, state = state) + ui = new(user, src, ui_key, "AtmosPump", name, 310, 110, master_ui, state) ui.open() -/obj/machinery/atmospherics/binary/passive_gate/ui_data(mob/user) - var/list/data = list() - data["on"] = on - data["pressure"] = round(target_pressure) - data["max_pressure"] = round(MAX_OUTPUT_PRESSURE) +/obj/machinery/atmospherics/binary/passive_gate/tgui_data(mob/user) + var/list/data = list( + "on" = on, + "rate" = round(target_pressure), + "max_rate" = MAX_OUTPUT_PRESSURE, + "gas_unit" = "kPa", + "step" = 10 // This is for the TGUI step. It's here since multiple pumps share the same UI, but need different values. + ) return data -/obj/machinery/atmospherics/binary/passive_gate/Topic(href,href_list) +/obj/machinery/atmospherics/binary/passive_gate/tgui_act(action, list/params) if(..()) - return 1 + return - if(href_list["power"]) + switch(action) + if("power") + toggle() + investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos") + return TRUE + + if("max_rate") + target_pressure = MAX_OUTPUT_PRESSURE + . = TRUE + + if("min_rate") + target_pressure = 0 + . = TRUE + + if("custom_rate") + target_pressure = clamp(text2num(params["rate"]), 0 , MAX_OUTPUT_PRESSURE) + . = TRUE + if(.) + investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos") + +/obj/machinery/atmospherics/binary/passive_gate/proc/toggle() + if(powered()) on = !on - investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos") - . = TRUE - if(href_list["pressure"]) - var/pressure = href_list["pressure"] - if(pressure == "max") - pressure = MAX_OUTPUT_PRESSURE - . = TRUE - else if(pressure == "input") - pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null - if(!isnull(pressure)) - . = TRUE - else if(text2num(pressure) != null) - pressure = text2num(pressure) - . = TRUE - if(.) - target_pressure = clamp(pressure, 0, MAX_OUTPUT_PRESSURE) - investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos") - - update_icon() - SSnanoui.update_uis(src) + update_icon() /obj/machinery/atmospherics/binary/passive_gate/attackby(obj/item/W, mob/user, params) if(!istype(W, /obj/item/wrench)) diff --git a/code/ATMOSPHERICS/components/binary_devices/pump.dm b/code/ATMOSPHERICS/components/binary_devices/pump.dm index 550fd140d1d..5178507bbc4 100644 --- a/code/ATMOSPHERICS/components/binary_devices/pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/pump.dm @@ -192,51 +192,51 @@ Thus, the two variables affect pump operation are set in New(): return add_fingerprint(user) - ui_interact(user) + tgui_interact(user) /obj/machinery/atmospherics/binary/pump/attack_ghost(mob/user) - ui_interact(user) + tgui_interact(user) -/obj/machinery/atmospherics/binary/pump/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/atmospherics/binary/pump/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) user.set_machine(src) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "atmos_pump.tmpl", name, 385, 115, state = state) + ui = new(user, src, ui_key, "AtmosPump", name, 310, 110, master_ui, state) ui.open() -/obj/machinery/atmospherics/binary/pump/ui_data(mob/user) - var/list/data = list() - data["on"] = on - data["pressure"] = round(target_pressure) - data["max_pressure"] = round(MAX_OUTPUT_PRESSURE) +/obj/machinery/atmospherics/binary/pump/tgui_data(mob/user) + var/list/data = list( + "on" = on, + "rate" = round(target_pressure), + "max_rate" = MAX_OUTPUT_PRESSURE, + "gas_unit" = "kPa", + "step" = 10 // This is for the TGUI step. It's here since multiple pumps share the same UI, but need different values. + ) return data -/obj/machinery/atmospherics/binary/pump/Topic(href,href_list) +/obj/machinery/atmospherics/binary/pump/tgui_act(action, list/params) if(..()) - return 1 + return - if(href_list["power"]) - on = !on - investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos") - . = TRUE - if(href_list["pressure"]) - var/pressure = href_list["pressure"] - if(pressure == "max") - pressure = MAX_OUTPUT_PRESSURE - . = TRUE - else if(pressure == "input") - pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null - if(!isnull(pressure)) - . = TRUE - else if(text2num(pressure) != null) - pressure = text2num(pressure) - . = TRUE - if(.) - target_pressure = clamp(pressure, 0, MAX_OUTPUT_PRESSURE) - investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos") + switch(action) + if("power") + toggle() + investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos") + return TRUE - update_icon() - SSnanoui.update_uis(src) + if("max_rate") + target_pressure = MAX_OUTPUT_PRESSURE + . = TRUE + + if("min_rate") + target_pressure = 0 + . = TRUE + + if("custom_rate") + target_pressure = clamp(text2num(params["rate"]), 0 , MAX_OUTPUT_PRESSURE) + . = TRUE + if(.) + investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos") /obj/machinery/atmospherics/binary/pump/power_change() var/old_stat = stat diff --git a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm index 804d25cfa1b..12079341143 100644 --- a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm @@ -188,51 +188,51 @@ Thus, the two variables affect pump operation are set in New(): return add_fingerprint(user) - ui_interact(user) + tgui_interact(user) /obj/machinery/atmospherics/binary/volume_pump/attack_ghost(mob/user) - ui_interact(user) + tgui_interact(user) -/obj/machinery/atmospherics/binary/volume_pump/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/atmospherics/binary/volume_pump/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) user.set_machine(src) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "atmos_pump.tmpl", name, 310, 115, state = state) + ui = new(user, src, ui_key, "AtmosPump", name, 310, 110, master_ui, state) ui.open() -/obj/machinery/atmospherics/binary/volume_pump/ui_data(mob/user) - var/list/data = list() - data["on"] = on - data["rate"] = round(transfer_rate) - data["max_rate"] = round(MAX_TRANSFER_RATE) +/obj/machinery/atmospherics/binary/volume_pump/tgui_data(mob/user) + var/list/data = list( + "on" = on, + "rate" = round(transfer_rate), + "max_rate" = round(MAX_TRANSFER_RATE), + "gas_unit" = "L/s", + "step" = 1 // This is for the TGUI step. It's here since multiple pumps share the same UI, but need different values. + ) return data -/obj/machinery/atmospherics/binary/volume_pump/Topic(href,href_list) +/obj/machinery/atmospherics/binary/volume_pump/tgui_act(action, list/params) if(..()) - return 1 + return - if(href_list["power"]) - on = !on - investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos") - . = TRUE - if(href_list["rate"]) - var/rate = href_list["rate"] - if(rate == "max") - rate = MAX_TRANSFER_RATE - . = TRUE - else if(rate == "input") - rate = input("New transfer rate (0-[MAX_TRANSFER_RATE] L/s):", name, transfer_rate) as num|null - if(!isnull(rate)) - . = TRUE - else if(text2num(rate) != null) - rate = text2num(rate) - . = TRUE - if(.) - transfer_rate = clamp(rate, 0, MAX_TRANSFER_RATE) - investigate_log("was set to [transfer_rate] L/s by [key_name(usr)]", "atmos") + switch(action) + if("power") + toggle() + investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos") + return TRUE - update_icon() - SSnanoui.update_uis(src) + if("max_rate") + transfer_rate = MAX_TRANSFER_RATE + . = TRUE + + if("min_rate") + transfer_rate = 0 + . = TRUE + + if("custom_rate") + transfer_rate = clamp(text2num(params["rate"]), 0 , MAX_TRANSFER_RATE) + . = TRUE + if(.) + investigate_log("was set to [transfer_rate] L/s by [key_name(usr)]", "atmos") /obj/machinery/atmospherics/binary/volume_pump/power_change() var/old_stat = stat diff --git a/code/ATMOSPHERICS/components/omni_devices/_omni_extras.dm b/code/ATMOSPHERICS/components/omni_devices/_omni_extras.dm deleted file mode 100644 index d03329e24fc..00000000000 --- a/code/ATMOSPHERICS/components/omni_devices/_omni_extras.dm +++ /dev/null @@ -1,94 +0,0 @@ -//-------------------------------------------- -// Omni device port types -//-------------------------------------------- -#define ATM_NONE 0 -#define ATM_INPUT 1 -#define ATM_OUTPUT 2 - -#define ATM_O2 3 -#define ATM_N2 4 -#define ATM_CO2 5 -#define ATM_P 6 //Plasma -#define ATM_N2O 7 - -//-------------------------------------------- -// Omni port datum -// -// Used by omni devices to manage connections -// to other atmospheric objects. -//-------------------------------------------- -/datum/omni_port - var/obj/machinery/atmospherics/omni/master - var/dir - var/update = 1 - var/mode = 0 - var/concentration = 0 - var/con_lock = 0 - var/transfer_moles = 0 - var/datum/gas_mixture/air - var/obj/machinery/atmospherics/node - var/datum/pipeline/parent - -/datum/omni_port/New(var/obj/machinery/atmospherics/omni/M, var/direction = NORTH) - ..() - dir = direction - if(istype(M)) - master = M - air = new - air.volume = 200 - -/datum/omni_port/proc/connect() - if(node) - return - master.atmos_init() - if(node) - node.atmos_init() - node.addMember(master) - master.build_network() - -/datum/omni_port/proc/disconnect() - if(node) - node.disconnect(master) - node = null - master.nullifyPipenet(parent) - -//-------------------------------------------- -// Need to find somewhere else for these -//-------------------------------------------- - -//returns a text string based on the direction flag input -// if capitalize is true, it will return the string capitalized -// otherwise it will return the direction string in lower case -/proc/dir_name(var/dir, var/capitalize = 0) - var/string = null - switch(dir) - if(NORTH) - string = "North" - if(SOUTH) - string = "South" - if(EAST) - string = "East" - if(WEST) - string = "West" - - if(!capitalize && string) - string = lowertext(string) - - return string - -//returns a direction flag based on the string passed to it -// case insensitive -/proc/dir_flag(var/dir) - dir = lowertext(dir) - switch(dir) - if("north") - return NORTH - if("south") - return SOUTH - if("east") - return EAST - if("west") - return WEST - else - return 0 - diff --git a/code/ATMOSPHERICS/components/omni_devices/filter.dm b/code/ATMOSPHERICS/components/omni_devices/filter.dm deleted file mode 100644 index 0803d34e522..00000000000 --- a/code/ATMOSPHERICS/components/omni_devices/filter.dm +++ /dev/null @@ -1,273 +0,0 @@ -//-------------------------------------------- -// Gas filter - omni variant -//-------------------------------------------- -/obj/machinery/atmospherics/omni/filter - name = "omni gas filter" - icon_state = "map_filter" - - var/list/o_filters = new() - var/datum/omni_port/input - var/datum/omni_port/output - -/obj/machinery/atmospherics/omni/filter/Destroy() - input = null - output = null - o_filters.Cut() - return ..() - -/obj/machinery/atmospherics/omni/filter/sort_ports() - for(var/datum/omni_port/P in ports) - if(P.update) - if(output == P) - output = null - if(input == P) - input = null - if(o_filters.Find(P)) - o_filters -= P - - P.air.volume = 200 - switch(P.mode) - if(ATM_INPUT) - input = P - if(ATM_OUTPUT) - output = P - if(ATM_O2 to ATM_N2O) - o_filters += P - -/obj/machinery/atmospherics/omni/filter/error_check() - if(!input || !output || !o_filters) - return 1 - if(o_filters.len < 1 || o_filters.len > 2) //requires 1 or 2 o_filters ~otherwise why are you using a filter? - return 1 - - return 0 - -/obj/machinery/atmospherics/omni/filter/process_atmos() - ..() - if(!on) - return 0 - - if(!input || !output) - return 0 - - var/datum/gas_mixture/output_air = output.air //BYOND doesn't like referencing "output.air.return_pressure()" so we need to make a direct reference - var/datum/gas_mixture/input_air = input.air // it's completely happy with them if they're in a loop though i.e. "P.air.return_pressure()"... *shrug* - - var/output_pressure = output_air.return_pressure() - - if(output_pressure >= target_pressure) - return 1 - for(var/datum/omni_port/P in o_filters) - if(P.air.return_pressure() >= target_pressure) - return 1 - - var/pressure_delta = target_pressure - output_pressure - - if(input_air.return_temperature() > 0) - input.transfer_moles = pressure_delta * output_air.volume / (input_air.return_temperature() * R_IDEAL_GAS_EQUATION) - - if(input.transfer_moles > 0) - var/datum/gas_mixture/removed = input_air.remove(input.transfer_moles) - - if(!removed) - return 1 - - for(var/datum/omni_port/P in o_filters) - var/datum/gas_mixture/filtered_out = new - filtered_out.temperature = removed.return_temperature() - - switch(P.mode) - if(ATM_O2) - filtered_out.oxygen = removed.oxygen - removed.oxygen = 0 - if(ATM_N2) - filtered_out.nitrogen = removed.nitrogen - removed.nitrogen = 0 - if(ATM_CO2) - filtered_out.carbon_dioxide = removed.carbon_dioxide - removed.carbon_dioxide = 0 - if(ATM_P) - filtered_out.toxins = removed.toxins - removed.toxins = 0 - - filtered_out.agent_b = removed.agent_b - removed.agent_b = 0 - if(ATM_N2O) - filtered_out.sleeping_agent = removed.sleeping_agent - removed.sleeping_agent = 0 - else - filtered_out = null - - P.air.merge(filtered_out) - P.parent.update = 1 - - output_air.merge(removed) - output.parent.update = 1 - - input.transfer_moles = 0 - input.parent.update = 1 - - return 1 - -/obj/machinery/atmospherics/omni/filter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, force_open = 0) - usr.set_machine(src) - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "omni_filter.tmpl", "Omni Filter Control", 330, 330) - ui.open() - -/obj/machinery/atmospherics/omni/filter/ui_data(mob/user, datum/topic_state/state) - var/data[0] - - data["power"] = on - data["config"] = configuring - - var/portData[0] - for(var/datum/omni_port/P in ports) - if(!configuring && P.mode == 0) - continue - - var/input = 0 - var/output = 0 - var/filter = 1 - var/f_type = null - switch(P.mode) - if(ATM_INPUT) - input = 1 - filter = 0 - if(ATM_OUTPUT) - output = 1 - filter = 0 - if(ATM_O2 to ATM_N2O) - f_type = mode_send_switch(P.mode) - - portData[++portData.len] = list("dir" = dir_name(P.dir, capitalize = 1), \ - "input" = input, \ - "output" = output, \ - "filter" = filter, \ - "f_type" = f_type) - - if(portData.len) - data["ports"] = portData - if(output) - data["pressure"] = target_pressure - - return data - -/obj/machinery/atmospherics/omni/filter/proc/mode_send_switch(var/mode = ATM_NONE) - switch(mode) - if(ATM_O2) - return "Oxygen" - if(ATM_N2) - return "Nitrogen" - if(ATM_CO2) - return "Carbon Dioxide" - if(ATM_P) - return "Plasma" //*cough* Plasma *cough* - if(ATM_N2O) - return "Nitrous Oxide" - else - return null - -/obj/machinery/atmospherics/omni/filter/Topic(href, href_list) - if(..()) - return 1 - switch(href_list["command"]) - if("power") - if(!configuring) - on = !on - else - on = 0 - if("configure") - configuring = !configuring - if(configuring) - on = 0 - - //only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on - if(configuring && !on) - switch(href_list["command"]) - if("set_pressure") - var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",target_pressure) as num - target_pressure = between(0, new_pressure, 4500) - if("switch_mode") - switch_mode(dir_flag(href_list["dir"]), mode_return_switch(href_list["mode"])) - if("switch_filter") - var/new_filter = input(usr,"Select filter mode:","Change filter",href_list["mode"]) in list("None", "Oxygen", "Nitrogen", "Carbon Dioxide", "Plasma", "Nitrous Oxide") - switch_filter(dir_flag(href_list["dir"]), mode_return_switch(new_filter)) - - update_icon() - SSnanoui.update_uis(src) - return - -/obj/machinery/atmospherics/omni/filter/proc/mode_return_switch(var/mode) - switch(mode) - if("Oxygen") - return ATM_O2 - if("Nitrogen") - return ATM_N2 - if("Carbon Dioxide") - return ATM_CO2 - if("Plasma") - return ATM_P - if("Nitrous Oxide") - return ATM_N2O - if("in") - return ATM_INPUT - if("out") - return ATM_OUTPUT - if("None") - return ATM_NONE - else - return null - -/obj/machinery/atmospherics/omni/filter/proc/switch_filter(var/dir, var/mode) - //check they aren't trying to disable the input or output ~this can only happen if they hack the cached tmpl file - for(var/datum/omni_port/P in ports) - if(P.dir == dir) - if(P.mode == ATM_INPUT || P.mode == ATM_OUTPUT) - return - - switch_mode(dir, mode) - -/obj/machinery/atmospherics/omni/filter/proc/switch_mode(var/port, var/mode) - if(mode == null || !port) - return - var/datum/omni_port/target_port = null - var/list/other_ports = new() - - for(var/datum/omni_port/P in ports) - if(P.dir == port) - target_port = P - else - other_ports += P - - var/previous_mode = null - if(target_port) - previous_mode = target_port.mode - target_port.mode = mode - if(target_port.mode != previous_mode) - handle_port_change(target_port) - else - return - else - return - - for(var/datum/omni_port/P in other_ports) - if(P.mode == mode) - var/old_mode = P.mode - P.mode = previous_mode - if(P.mode != old_mode) - handle_port_change(P) - - update_ports() - -/obj/machinery/atmospherics/omni/filter/proc/handle_port_change(var/datum/omni_port/P) - switch(P.mode) - if(ATM_NONE) - initialize_directions &= ~P.dir - P.disconnect() - else - initialize_directions |= P.dir - P.connect() - P.update = 1 diff --git a/code/ATMOSPHERICS/components/omni_devices/mixer.dm b/code/ATMOSPHERICS/components/omni_devices/mixer.dm deleted file mode 100644 index 5586bdc3a98..00000000000 --- a/code/ATMOSPHERICS/components/omni_devices/mixer.dm +++ /dev/null @@ -1,291 +0,0 @@ -//-------------------------------------------- -// Gas mixer - omni variant -//-------------------------------------------- -/obj/machinery/atmospherics/omni/mixer - name = "omni gas mixer" - icon_state = "map_mixer" - - var/list/inputs = new() - var/datum/omni_port/output - - //setup tags for initial concentration values (must be decimal) - var/tag_north_con - var/tag_south_con - var/tag_east_con - var/tag_west_con - -/obj/machinery/atmospherics/omni/mixer/New() - ..() - if(mapper_set()) - var/con = 0 - for(var/datum/omni_port/P in ports) - switch(P.dir) - if(NORTH) - if(tag_north_con && tag_north == 1) - P.concentration = tag_north_con - con += max(0, tag_north_con) - if(SOUTH) - if(tag_south_con && tag_south == 1) - P.concentration = tag_south_con - con += max(0, tag_south_con) - if(EAST) - if(tag_east_con && tag_east == 1) - P.concentration = tag_east_con - con += max(0, tag_east_con) - if(WEST) - if(tag_west_con && tag_west == 1) - P.concentration = tag_west_con - con += max(0, tag_west_con) - - //mappers who are bad at maths will be punished (total concentration must be 100%) - if(con != 1) - tag_north_con = null - tag_south_con = null - tag_east_con = null - tag_west_con = null - -/obj/machinery/atmospherics/omni/mixer/Destroy() - inputs.Cut() - output = null - return ..() - -/obj/machinery/atmospherics/omni/mixer/sort_ports() - for(var/datum/omni_port/P in ports) - if(P.update) - if(output == P) - output = null - if(inputs.Find(P)) - inputs -= P - - P.air.volume = 200 - switch(P.mode) - if(ATM_INPUT) - inputs += P - if(ATM_OUTPUT) - output = P - - if(!mapper_set()) - for(var/datum/omni_port/P in inputs) - P.concentration = 1 / max(1, inputs.len) - - if(output) - output.air.volume *= 0.75 * inputs.len - output.concentration = 1 - -/obj/machinery/atmospherics/omni/mixer/proc/mapper_set() - return (tag_north_con || tag_south_con || tag_east_con || tag_west_con) - -/obj/machinery/atmospherics/omni/mixer/error_check() - if(!output || !inputs) - return 1 - if(inputs.len < 2 || inputs.len > 3) //requires 2 or 3 inputs ~otherwise why are you using a mixer? - return 1 - - return 0 - -/obj/machinery/atmospherics/omni/mixer/process_atmos() - ..() - if(!on) - return 0 - - var/datum/gas_mixture/output_air = output.air - var/output_pressure = output_air.return_pressure() - - - if(output_pressure >= target_pressure * 0.999) - //No need to mix if target is already full! - 0.1% margin of error so we minimize processing minor gas volumes - return 1 - - //Calculate necessary moles to transfer using PV=nRT - - var/pressure_delta = target_pressure - output_pressure - - for(var/datum/omni_port/P in inputs) - if(P.air.return_temperature() > 0) - P.transfer_moles = (P.concentration * pressure_delta) * output_air.return_volume() / (P.air.return_temperature() * R_IDEAL_GAS_EQUATION) - - var/ratio_check = null - - for(var/datum/omni_port/P in inputs) - if(!P.transfer_moles) - return 1 - if(P.air.total_moles() < P.transfer_moles) - ratio_check = 1 - continue - - if(ratio_check) - var/list/ratio_list = new() - for(var/datum/omni_port/P in inputs) - ratio_list.Add(P.air.total_moles() / P.transfer_moles) - - var/ratio = min(ratio_list) - - for(var/datum/omni_port/P in inputs) - P.transfer_moles *= ratio - - for(var/datum/omni_port/P in inputs) - if(P.transfer_moles > 0) - output_air.merge(P.air.remove(P.transfer_moles)) - P.parent.update = 1 - P.transfer_moles = 0 - - output.parent.update = 1 - - return 1 - -/obj/machinery/atmospherics/omni/mixer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, force_open = 0) - usr.set_machine(src) - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "omni_mixer.tmpl", "Omni Mixer Control", 360, 330) - ui.open() - -/obj/machinery/atmospherics/omni/mixer/ui_data(mob/user, datum/topic_state/state) - var/data[0] - - data["power"] = on - data["config"] = configuring - - var/portData[0] - for(var/datum/omni_port/P in ports) - if(!configuring && P.mode == 0) - continue - - var/input = 0 - var/output = 0 - switch(P.mode) - if(ATM_INPUT) - input = 1 - if(ATM_OUTPUT) - output = 1 - - portData[++portData.len] = list("dir" = dir_name(P.dir, capitalize = 1), \ - "concentration" = P.concentration, \ - "input" = input, \ - "output" = output, \ - "con_lock" = P.con_lock) - - if(portData.len) - data["ports"] = portData - if(output) - data["pressure"] = target_pressure - - return data - -/obj/machinery/atmospherics/omni/mixer/Topic(href, href_list) - if(..()) - return 1 - - switch(href_list["command"]) - if("power") - if(!configuring) - on = !on - else - on = 0 - if("configure") - configuring = !configuring - if(configuring) - on = 0 - - //only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on - if(configuring && !on) - switch(href_list["command"]) - if("set_pressure") - var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",target_pressure) as num - target_pressure = between(0, new_pressure, 4500) - if("switch_mode") - switch_mode(dir_flag(href_list["dir"]), href_list["mode"]) - if("switch_con") - change_concentration(dir_flag(href_list["dir"])) - if("switch_conlock") - con_lock(dir_flag(href_list["dir"])) - - update_icon() - SSnanoui.update_uis(src) - return - -/obj/machinery/atmospherics/omni/mixer/proc/switch_mode(var/port = NORTH, var/mode = ATM_NONE) - if(mode != ATM_INPUT && mode != ATM_OUTPUT) - switch(mode) - if("in") - mode = ATM_INPUT - if("out") - mode = ATM_OUTPUT - else - mode = ATM_NONE - - for(var/datum/omni_port/P in ports) - var/old_mode = P.mode - if(P.dir == port) - switch(mode) - if(ATM_INPUT) - if(P.mode == ATM_OUTPUT) - return - P.mode = mode - if(ATM_OUTPUT) - P.mode = mode - if(ATM_NONE) - if(P.mode == ATM_OUTPUT) - return - if(P.mode == ATM_INPUT && inputs.len > 2) - P.mode = mode - else if(P.mode == ATM_OUTPUT && mode == ATM_OUTPUT) - P.mode = ATM_INPUT - if(P.mode != old_mode) - switch(P.mode) - if(ATM_NONE) - initialize_directions &= ~P.dir - P.disconnect() - else - initialize_directions |= P.dir - P.connect() - P.update = 1 - - update_ports() - -/obj/machinery/atmospherics/omni/mixer/proc/change_concentration(var/port = NORTH) - tag_north_con = null - tag_south_con = null - tag_east_con = null - tag_west_con = null - - var/old_con = 0 - var/non_locked = 0 - var/remain_con = 1 - - for(var/datum/omni_port/P in inputs) - if(P.dir == port) - old_con = P.concentration - else if(!P.con_lock) - non_locked++ - else - remain_con -= P.concentration - - //return if no adjustable ports - if(non_locked < 1) - return - - var/new_con = (input(usr,"Enter a new concentration (0-[round(remain_con * 100, 0.5)])%","Concentration control", min(remain_con, old_con)*100) as num) / 100 - - //cap it between 0 and the max remaining concentration - new_con = between(0, new_con, remain_con) - - //new_con = min(remain_con, new_con) - - //clamp remaining concentration so we don't go into negatives - remain_con = max(0, remain_con - new_con) - - //distribute remaining concentration between unlocked ports evenly - remain_con /= max(1, non_locked) - - for(var/datum/omni_port/P in inputs) - if(P.dir == port) - P.concentration = new_con - else if(!P.con_lock) - P.concentration = remain_con - -/obj/machinery/atmospherics/omni/mixer/proc/con_lock(var/port = NORTH) - for(var/datum/omni_port/P in inputs) - if(P.dir == port) - P.con_lock = !P.con_lock diff --git a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm deleted file mode 100644 index d75e2e683c1..00000000000 --- a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm +++ /dev/null @@ -1,302 +0,0 @@ -//-------------------------------------------- -// Base omni device -//-------------------------------------------- -/obj/machinery/atmospherics/omni - name = "omni device" - icon = 'icons/atmos/omni_devices.dmi' - icon_state = "base" - use_power = IDLE_POWER_USE - initialize_directions = 0 - - can_unwrench = 1 - - var/on = 0 - var/configuring = 0 - var/target_pressure = ONE_ATMOSPHERE - - var/tag_north = ATM_NONE - var/tag_south = ATM_NONE - var/tag_east = ATM_NONE - var/tag_west = ATM_NONE - - var/overlays_on[5] - var/overlays_off[5] - var/overlays_error[2] - var/underlays_current[4] - - var/list/ports = new() - -/obj/machinery/atmospherics/omni/New() - ..() - icon_state = "base" - - ports = new() - for(var/d in GLOB.cardinal) - var/datum/omni_port/new_port = new(src, d) - switch(d) - if(NORTH) - new_port.mode = tag_north - if(SOUTH) - new_port.mode = tag_south - if(EAST) - new_port.mode = tag_east - if(WEST) - new_port.mode = tag_west - if(new_port.mode > 0) - initialize_directions |= d - ports += new_port - - build_icons() - -/obj/machinery/atmospherics/omni/Destroy() - for(var/datum/omni_port/P in ports) - if(P.node) - P.node.disconnect(src) - P.node = null - nullifyPipenet(P.parent) - return ..() - -/obj/machinery/atmospherics/omni/atmos_init() - ..() - for(var/datum/omni_port/P in ports) - if(P.node || P.mode == 0) - continue - for(var/obj/machinery/atmospherics/target in get_step(src, P.dir)) - if(target.initialize_directions & get_dir(target,src)) - P.node = target - break - - for(var/datum/omni_port/P in ports) - P.update = 1 - - update_ports() - -/obj/machinery/atmospherics/omni/update_icon() - ..() - - if(stat & NOPOWER) - overlays = overlays_off - on = 0 - else if(error_check()) - overlays = overlays_error - on = 0 - else - overlays = on ? (overlays_on) : (overlays_off) - - underlays = underlays_current - -/obj/machinery/atmospherics/omni/proc/error_check() - return - -/obj/machinery/atmospherics/omni/power_change() - var/old_stat = stat - ..() - if(old_stat != stat) - update_icon() - -/obj/machinery/atmospherics/omni/attackby(var/obj/item/W as obj, var/mob/user as mob, params) - if(!istype(W, /obj/item/wrench)) - return ..() - - if(can_unwrench) - var/int_pressure = 0 - for(var/datum/omni_port/P in ports) - int_pressure += P.air.return_pressure() - var/datum/gas_mixture/env_air = loc.return_air() - if((int_pressure - env_air.return_pressure()) > 2*ONE_ATMOSPHERE) - to_chat(user, "You cannot unwrench [src], it is too exerted due to internal pressure.") - add_fingerprint(user) - return 1 - playsound(loc, W.usesound, 50, 1) - to_chat(user, "You begin to unfasten \the [src]...") - if(do_after(user, 40 * W.toolspeed, target = src)) - user.visible_message( \ - "[user] unfastens \the [src].", \ - "You have unfastened \the [src].", \ - "You hear a ratchet.") - new /obj/item/pipe(loc, make_from=src) - qdel(src) - else - return ..() - -/obj/machinery/atmospherics/omni/attack_hand(mob/user) - if(..()) - return - - add_fingerprint(usr) - ui_interact(user) - -/obj/machinery/atmospherics/omni/attack_ghost(mob/user) - ui_interact(user) - -/obj/machinery/atmospherics/omni/proc/build_icons() - if(!check_icon_cache()) - return - - var/core_icon = null - if(istype(src, /obj/machinery/atmospherics/omni/mixer)) - core_icon = "mixer" - else if(istype(src, /obj/machinery/atmospherics/omni/filter)) - core_icon = "filter" - else - return - - //directional icons are layers 1-4, with the core icon on layer 5 - if(core_icon) - overlays_off[5] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon) - overlays_on[5] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon + "_glow") - - overlays_error[1] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , core_icon) - overlays_error[2] = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , "error") - -/obj/machinery/atmospherics/omni/proc/update_port_icons() - if(!check_icon_cache()) - return - - for(var/datum/omni_port/P in ports) - if(P.update) - var/ref_layer = 0 - switch(P.dir) - if(NORTH) - ref_layer = 1 - if(SOUTH) - ref_layer = 2 - if(EAST) - ref_layer = 3 - if(WEST) - ref_layer = 4 - - if(!ref_layer) - continue - - var/list/port_icons = select_port_icons(P) - if(port_icons) - if(P.node) - underlays_current[ref_layer] = port_icons["pipe_icon"] - else - underlays_current[ref_layer] = null - overlays_off[ref_layer] = port_icons["off_icon"] - overlays_on[ref_layer] = port_icons["on_icon"] - else - underlays_current[ref_layer] = null - overlays_off[ref_layer] = null - overlays_on[ref_layer] = null - - update_icon() - -/obj/machinery/atmospherics/omni/proc/select_port_icons(var/datum/omni_port/P) - if(!istype(P)) - return - - if(P.mode > 0) - var/ic_dir = dir_name(P.dir) - var/ic_on = ic_dir - var/ic_off = ic_dir - switch(P.mode) - if(ATM_INPUT) - ic_on += "_in_glow" - ic_off += "_in" - if(ATM_OUTPUT) - ic_on += "_out_glow" - ic_off += "_out" - if(ATM_O2 to ATM_N2O) - ic_on += "_filter" - ic_off += "_out" - - ic_on = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , ic_on) - ic_off = GLOB.pipe_icon_manager.get_atmos_icon("omni", , , ic_off) - - var/pipe_state - var/turf/T = get_turf(src) - if(!istype(T)) - return - if(T.intact && istype(P.node, /obj/machinery/atmospherics/pipe) && P.node.level == 1 ) - //pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay_down", P.dir, color_cache_name(P.node)) - pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "down") - else - //pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay_intact", P.dir, color_cache_name(P.node)) - pipe_state = GLOB.pipe_icon_manager.get_atmos_icon("underlay", P.dir, color_cache_name(P.node), "intact") - - return list("on_icon" = ic_on, "off_icon" = ic_off, "pipe_icon" = pipe_state) - -/obj/machinery/atmospherics/omni/update_underlays() - for(var/datum/omni_port/P in ports) - P.update = 1 - update_ports() - -/obj/machinery/atmospherics/omni/hide(var/i) - update_underlays() - -/obj/machinery/atmospherics/omni/proc/update_ports() - sort_ports() - update_port_icons() - for(var/datum/omni_port/P in ports) - P.update = 0 - -/obj/machinery/atmospherics/omni/proc/sort_ports() - return - -// Pipenet procs -/obj/machinery/atmospherics/omni/build_network(remove_deferral = FALSE) - for(var/datum/omni_port/P in ports) - if(!P.parent) - P.parent = new /datum/pipeline() - P.parent.build_pipeline(src) - ..() - -/obj/machinery/atmospherics/omni/disconnect(obj/machinery/atmospherics/reference) - for(var/datum/omni_port/P in ports) - if(reference == P.node) - if(istype(P.node, /obj/machinery/atmospherics/pipe)) - qdel(P.parent) - P.node = null - update_ports() - -/obj/machinery/atmospherics/omni/nullifyPipenet(datum/pipeline/P) - ..() - if(!P) - return - for(var/datum/omni_port/PO in ports) - if(P == PO.parent) - PO.parent.other_airs -= PO.air - PO.parent = null - -/obj/machinery/atmospherics/omni/returnPipenetAir(datum/pipeline/P) - for(var/datum/omni_port/PO in ports) - if(P == PO.parent) - return PO.air - -/obj/machinery/atmospherics/omni/pipeline_expansion(datum/pipeline/P) - if(P) - for(var/datum/omni_port/PO in ports) - if(PO.parent == P) - return list(PO.node) - else - var/list/nodes = list() - for(var/datum/omni_port/PO in ports) - nodes += PO.node - - return nodes - -/obj/machinery/atmospherics/omni/setPipenet(datum/pipeline/P, obj/machinery/atmospherics/A) - for(var/datum/omni_port/PO in ports) - if(A == PO.node) - PO.parent = P - -/obj/machinery/atmospherics/omni/returnPipenet(obj/machinery/atmospherics/A) - for(var/datum/omni_port/P in ports) - if(A == P.node) - return P.parent - -/obj/machinery/atmospherics/omni/replacePipenet(datum/pipeline/Old, datum/pipeline/New) - for(var/datum/omni_port/P in ports) - if(Old == P.parent) - P.parent = New - - -/obj/machinery/atmospherics/omni/process_atmos() - ..() - for(var/datum/omni_port/port in ports) - if(!port.parent) - return 0 - return 1 diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm index 64fb308c2db..c06e863406d 100755 --- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm @@ -1,26 +1,39 @@ + +/// Nothing will be filtered. +#define FILTER_NOTHING -1 +/// Plasma, and Oxygen Agent B. +#define FILTER_TOXINS 0 +/// Oxygen only. +#define FILTER_OXYGEN 1 +/// Nitrogen only. +#define FILTER_NITROGEN 2 +/// Carbon dioxide only. +#define FILTER_CO2 3 +/// Nitrous oxide only. +#define FILTER_N2O 4 + /obj/machinery/atmospherics/trinary/filter + name = "gas filter" icon = 'icons/atmos/filter.dmi' icon_state = "map" - - can_unwrench = 1 - - name = "gas filter" - + can_unwrench = TRUE + /// The amount of pressure the filter wants to operate at. var/target_pressure = ONE_ATMOSPHERE - - var/filter_type = 0 -/* -Filter types: --1: Nothing - 0: Toxins: Toxins, Oxygen Agent B - 1: Oxygen: Oxygen ONLY - 2: Nitrogen: Nitrogen ONLY - 3: Carbon Dioxide: Carbon Dioxide ONLY - 4: Sleeping Agent (N2O) -*/ - - var/frequency = 0 + /// The type of gas we want to filter. Valid values that go here are from the `FILTER` defines at the top of the file. + var/filter_type = FILTER_NOTHING + /// The frequency of the filter. Used with `radio_connection`. + var/frequency = NONE + /// A reference to the filter's `datum/radio_frequency`. var/datum/radio_frequency/radio_connection + /// A list of available filter options. Used with `tgui_data`. + var/list/filter_list = list( + "Nothing" = FILTER_NOTHING, + "Plasma" = FILTER_TOXINS, + "O2" = FILTER_OXYGEN, + "N2" = FILTER_NITROGEN, + "CO2" = FILTER_CO2, + "N2O" = FILTER_N2O + ) /obj/machinery/atmospherics/trinary/filter/CtrlClick(mob/living/user) if(!istype(user) || user.incapacitated()) @@ -146,26 +159,26 @@ Filter types: filtered_out.temperature = removed.temperature switch(filter_type) - if(0) //removing hydrocarbons + if(FILTER_TOXINS) filtered_out.toxins = removed.toxins removed.toxins = 0 filtered_out.agent_b = removed.agent_b removed.agent_b = 0 - if(1) //removing O2 + if(FILTER_OXYGEN) filtered_out.oxygen = removed.oxygen removed.oxygen = 0 - if(2) //removing N2 + if(FILTER_NITROGEN) filtered_out.nitrogen = removed.nitrogen removed.nitrogen = 0 - if(3) //removing CO2 + if(FILTER_CO2) filtered_out.carbon_dioxide = removed.carbon_dioxide removed.carbon_dioxide = 0 - if(4)//removing N2O + if(FILTER_N2O) filtered_out.sleeping_agent = removed.sleeping_agent removed.sleeping_agent = 0 else @@ -188,7 +201,7 @@ Filter types: ..() /obj/machinery/atmospherics/trinary/filter/attack_ghost(mob/user) - ui_interact(user) + tgui_interact(user) /obj/machinery/atmospherics/trinary/filter/attack_hand(mob/user) if(..()) @@ -199,53 +212,56 @@ Filter types: return add_fingerprint(user) - ui_interact(user) + tgui_interact(user) -/obj/machinery/atmospherics/trinary/filter/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/atmospherics/trinary/filter/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) user.set_machine(src) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "atmos_filter.tmpl", name, 475, 155, state = state) + ui = new(user, src, ui_key, "AtmosFilter", name, 380, 140, master_ui, state) ui.open() -/obj/machinery/atmospherics/trinary/filter/ui_data(mob/user) - var/list/data = list() - data["on"] = on - data["pressure"] = round(target_pressure) - data["max_pressure"] = round(MAX_OUTPUT_PRESSURE) - data["filter_type"] = filter_type +/obj/machinery/atmospherics/trinary/filter/tgui_data(mob/user) + var/list/data = list( + "on" = on, + "pressure" = round(target_pressure), + "max_pressure" = round(MAX_OUTPUT_PRESSURE), + "filter_type" = filter_type + ) + data["filter_type_list"] = list() + for(var/label in filter_list) + data["filter_type_list"] += list(list("label" = label, "gas_type" = filter_list[label])) + return data -/obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE +/obj/machinery/atmospherics/trinary/filter/tgui_act(action, list/params) if(..()) - return 1 + return - if(href_list["power"]) - on = !on - investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos") - . = TRUE - if(href_list["pressure"]) - var/pressure = href_list["pressure"] - if(pressure == "max") - pressure = MAX_OUTPUT_PRESSURE - . = TRUE - else if(pressure == "input") - pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null - if(!isnull(pressure) && !..()) - . = TRUE - else if(text2num(pressure) != null) - pressure = text2num(pressure) - . = TRUE - if(.) - target_pressure = clamp(pressure, 0, MAX_OUTPUT_PRESSURE) - investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos") - if(href_list["filter"]) - filter_type = text2num(href_list["filter"]) - investigate_log("was set to filter [filter_type] by [key_name(usr)]", "atmos") - . = TRUE + switch(action) + if("power") + toggle() + investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos") + return TRUE - update_icon() - SSnanoui.update_uis(src) + if("set_filter") + filter_type = text2num(params["filter"]) + investigate_log("was set to filter [filter_type] by [key_name(usr)]", "atmos") + return TRUE + + if("max_pressure") + target_pressure = MAX_OUTPUT_PRESSURE + . = TRUE + + if("min_pressure") + target_pressure = 0 + . = TRUE + + if("custom_pressure") + target_pressure = clamp(text2num(params["pressure"]), 0, MAX_OUTPUT_PRESSURE) + . = TRUE + if(.) + investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos") /obj/machinery/atmospherics/trinary/filter/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/pen)) diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm index be4bf969009..52845f1154d 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm @@ -152,7 +152,7 @@ return 1 /obj/machinery/atmospherics/trinary/mixer/attack_ghost(mob/user) - ui_interact(user) + tgui_interact(user) /obj/machinery/atmospherics/trinary/mixer/attack_hand(mob/user) if(..()) @@ -163,62 +163,62 @@ return add_fingerprint(user) - ui_interact(user) + tgui_interact(user) -/obj/machinery/atmospherics/trinary/mixer/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, var/master_ui = null, var/datum/topic_state/state = GLOB.default_state) +/obj/machinery/atmospherics/trinary/mixer/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) user.set_machine(src) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "atmos_mixer.tmpl", name, 370, 165, state = state) + ui = new(user, src, ui_key, "AtmosMixer", name, 330, 165, master_ui, state) ui.open() -/obj/machinery/atmospherics/trinary/mixer/ui_data(mob/user) - var/list/data = list() - data["on"] = on - data["pressure"] = round(target_pressure) - data["max_pressure"] = round(MAX_OUTPUT_PRESSURE) - data["node1_concentration"] = round(node1_concentration*100) - data["node2_concentration"] = round(node2_concentration*100) +/obj/machinery/atmospherics/trinary/mixer/tgui_data(mob/user) + var/list/data = list( + "on" = on, + "pressure" = round(target_pressure, 0.01), + "max_pressure" = MAX_OUTPUT_PRESSURE, + "node1_concentration" = round(node1_concentration * 100), + "node2_concentration" = round(node2_concentration * 100) + ) return data -/obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list) + + +/obj/machinery/atmospherics/trinary/mixer/tgui_act(action, list/params) if(..()) - return 1 + return - if(href_list["power"]) - on = !on - investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos") - . = TRUE - if(href_list["pressure"]) - var/pressure = href_list["pressure"] - if(pressure == "max") - pressure = MAX_OUTPUT_PRESSURE - . = TRUE - else if(pressure == "input") - pressure = input("New output pressure (0-[MAX_OUTPUT_PRESSURE] kPa):", name, target_pressure) as num|null - if(!isnull(pressure) && !..()) - . = TRUE - else if(text2num(pressure) != null) - pressure = text2num(pressure) - . = TRUE - if(.) - target_pressure = clamp(pressure, 0, MAX_OUTPUT_PRESSURE) - investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos") - if(href_list["node1"]) - var/value = text2num(href_list["node1"]) - node1_concentration = max(0, min(1, node1_concentration + value)) - node2_concentration = max(0, min(1, node2_concentration - value)) - investigate_log("was set to [node1_concentration] % on node 1 by [key_name(usr)]", "atmos") - . = TRUE - if(href_list["node2"]) - var/value = text2num(href_list["node2"]) - node2_concentration = max(0, min(1, node2_concentration + value)) - node1_concentration = max(0, min(1, node1_concentration - value)) - investigate_log("was set to [node2_concentration] % on node 2 by [key_name(usr)]", "atmos") - . = TRUE + switch(action) + if("power") + toggle() + investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", "atmos") + return TRUE - update_icon() - SSnanoui.update_uis(src) + if("set_node") + if(params["node_name"] == "Node 1") + node1_concentration = clamp(round(text2num(params["concentration"]), 0.01), 0, 1) + node2_concentration = round(1 - node1_concentration, 0.01) + investigate_log("was set to [node1_concentration] % on node 1 by [key_name(usr)]", "atmos") + return TRUE + else + node2_concentration = clamp(round(text2num(params["concentration"]), 0.01), 0, 1) + node1_concentration = round(1 - node2_concentration, 0.01) + investigate_log("was set to [node2_concentration] % on node 2 by [key_name(usr)]", "atmos") + return TRUE + + if("max_pressure") + target_pressure = MAX_OUTPUT_PRESSURE + . = TRUE + + if("min_pressure") + target_pressure = 0 + . = TRUE + + if("custom_pressure") + target_pressure = clamp(text2num(params["pressure"]), 0, MAX_OUTPUT_PRESSURE) + . = TRUE + if(.) + investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", "atmos") /obj/machinery/atmospherics/trinary/mixer/attackby(obj/item/W, mob/user, params) if(istype(W, /obj/item/pen)) diff --git a/code/ATMOSPHERICS/datum_icon_manager.dm b/code/ATMOSPHERICS/datum_icon_manager.dm index 2286b3523a0..014fafc5c18 100644 --- a/code/ATMOSPHERICS/datum_icon_manager.dm +++ b/code/ATMOSPHERICS/datum_icon_manager.dm @@ -33,7 +33,6 @@ //var/list/underlays_intact[] //var/list/pipe_underlays_exposed[] //var/list/pipe_underlays_intact[] - var/list/omni_icons[] /datum/pipe_icon_manager/New() check_icons() @@ -53,8 +52,6 @@ return manifold_icons[state + color] if("device") return device_icons[state] - if("omni") - return omni_icons[state] if("underlay") return underlays[state + dir + color] //if("underlay_intact") @@ -75,8 +72,6 @@ gen_manifold_icons() if(!device_icons) gen_device_icons() - if(!omni_icons) - gen_omni_icons() //if(!underlays_intact || !underlays_down || !underlays_exposed || !pipe_underlays_exposed || !pipe_underlays_intact) if(!underlays) gen_underlay_icons() @@ -150,18 +145,6 @@ continue device_icons["scrubber" + state] = image('icons/atmos/vent_scrubber.dmi', icon_state = state) -/datum/pipe_icon_manager/proc/gen_omni_icons() - if(!omni_icons) - omni_icons = new() - - var/icon/omni = new('icons/atmos/omni_devices.dmi') - - for(var/state in omni.IconStates()) - if(!state || findtext(state, "map")) - continue - omni_icons[state] = image('icons/atmos/omni_devices.dmi', icon_state = state) - - /datum/pipe_icon_manager/proc/gen_underlay_icons() if(!underlays) diff --git a/code/LINDA/LINDA_system.dm b/code/LINDA/LINDA_system.dm index 3c8633c2b91..8d1ff95d3e9 100644 --- a/code/LINDA/LINDA_system.dm +++ b/code/LINDA/LINDA_system.dm @@ -32,13 +32,13 @@ if(!R) return 1 -atom/movable/proc/CanAtmosPass() +/atom/movable/proc/CanAtmosPass() return 1 -atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5) +/atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5) return (!density || !height) -turf/CanPass(atom/movable/mover, turf/target, height=1.5) +/turf/CanPass(atom/movable/mover, turf/target, height=1.5) if(!target) return 0 if(istype(mover)) // turf/Enter(...) will perform more advanced checks diff --git a/code/LINDA/LINDA_turf_tile.dm b/code/LINDA/LINDA_turf_tile.dm index acfa1983f72..8d71323cfb8 100644 --- a/code/LINDA/LINDA_turf_tile.dm +++ b/code/LINDA/LINDA_turf_tile.dm @@ -473,7 +473,7 @@ SSair.active_super_conductivity -= src return 0 -turf/simulated/proc/consider_superconductivity(starting) +/turf/simulated/proc/consider_superconductivity(starting) if(!thermal_conductivity) return 0 @@ -489,7 +489,7 @@ turf/simulated/proc/consider_superconductivity(starting) SSair.active_super_conductivity |= src return 1 -turf/simulated/proc/radiate_to_spess() //Radiate excess tile heat to space +/turf/simulated/proc/radiate_to_spess() //Radiate excess tile heat to space if(temperature > T0C) //Considering 0 degC as te break even point for radiation in and out var/delta_temperature = (temperature_archived - TCMB) //hardcoded space temperature if((heat_capacity > 0) && (abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)) diff --git a/code/__DEFINES/js.dm b/code/__DEFINES/js.dm index e1a86e664d4..eeca4da55dd 100644 --- a/code/__DEFINES/js.dm +++ b/code/__DEFINES/js.dm @@ -36,7 +36,7 @@ Be sure to include required js functions in your page, or it'll raise an excepti And yes I know this is a proc in a defines file, but its highly relevant so it can be here */ -proc/send_byjax(receiver, control_id, target_element, new_content=null, callback=null, list/callback_args=null) +/proc/send_byjax(receiver, control_id, target_element, new_content=null, callback=null, list/callback_args=null) if(receiver && target_element && control_id) // && winexists(receiver, control_id)) var/list/argums = list(target_element, new_content) if(callback) diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 719274857ec..7cd4cc7a918 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -208,6 +208,7 @@ #define isguardian(A) (istype((A), /mob/living/simple_animal/hostile/guardian)) #define isnymph(A) (istype((A), /mob/living/simple_animal/diona)) #define ishostile(A) (istype(A, /mob/living/simple_animal/hostile)) +#define isterrorspider(A) (istype((A), /mob/living/simple_animal/hostile/poison/terror_spider)) #define issilicon(A) (istype((A), /mob/living/silicon)) #define isAI(A) (istype((A), /mob/living/silicon/ai)) diff --git a/code/__DEFINES/pipes.dm b/code/__DEFINES/pipes.dm index c855a5e4260..d56d446ca1d 100644 --- a/code/__DEFINES/pipes.dm +++ b/code/__DEFINES/pipes.dm @@ -21,8 +21,6 @@ #define PIPE_TVALVE 18 #define PIPE_MANIFOLD4W 19 #define PIPE_CAP 20 -#define PIPE_OMNI_MIXER 21 -#define PIPE_OMNI_FILTER 22 #define PIPE_UNIVERSAL 23 #define PIPE_SUPPLY_STRAIGHT 24 #define PIPE_SUPPLY_BENT 25 diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 6e3603f83a3..11732a22375 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -48,7 +48,7 @@ #define INIT_ORDER_GARBAGE 21 #define INIT_ORDER_DBCORE 20 #define INIT_ORDER_BLACKBOX 19 -#define INIT_ORDER_SERVER_MAINT 18 +#define INIT_ORDER_CLEANUP 18 #define INIT_ORDER_INPUT 17 #define INIT_ORDER_SOUNDS 16 #define INIT_ORDER_INSTRUMENTS 15 @@ -90,7 +90,7 @@ #define FIRE_PRIORITY_NANOMOB 10 #define FIRE_PRIORITY_NIGHTSHIFT 10 #define FIRE_PRIORITY_IDLE_NPC 10 -#define FIRE_PRIORITY_SERVER_MAINT 10 +#define FIRE_PRIORITY_CLEANUP 10 #define FIRE_PRIORITY_TICKETS 10 #define FIRE_PRIORITY_RESEARCH 10 #define FIRE_PRIORITY_GARBAGE 15 diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 0d3b26d0340..49c77ca0a4a 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -1,4 +1,4 @@ -proc/GetOppositeDir(var/dir) +/proc/GetOppositeDir(var/dir) switch(dir) if(NORTH) return SOUTH if(SOUTH) return NORTH @@ -10,7 +10,7 @@ proc/GetOppositeDir(var/dir) if(SOUTHEAST) return NORTHWEST return 0 -proc/random_underwear(gender, species = "Human") +/proc/random_underwear(gender, species = "Human") var/list/pick_list = list() switch(gender) if(MALE) pick_list = GLOB.underwear_m @@ -18,7 +18,7 @@ proc/random_underwear(gender, species = "Human") else pick_list = GLOB.underwear_list return pick_species_allowed_underwear(pick_list, species) -proc/random_undershirt(gender, species = "Human") +/proc/random_undershirt(gender, species = "Human") var/list/pick_list = list() switch(gender) if(MALE) pick_list = GLOB.undershirt_m @@ -26,7 +26,7 @@ proc/random_undershirt(gender, species = "Human") else pick_list = GLOB.undershirt_list return pick_species_allowed_underwear(pick_list, species) -proc/random_socks(gender, species = "Human") +/proc/random_socks(gender, species = "Human") var/list/pick_list = list() switch(gender) if(MALE) pick_list = GLOB.socks_m @@ -34,7 +34,7 @@ proc/random_socks(gender, species = "Human") else pick_list = GLOB.socks_list return pick_species_allowed_underwear(pick_list, species) -proc/pick_species_allowed_underwear(list/all_picks, species) +/proc/pick_species_allowed_underwear(list/all_picks, species) var/list/valid_picks = list() for(var/test in all_picks) var/datum/sprite_accessory/S = all_picks[test] @@ -46,7 +46,7 @@ proc/pick_species_allowed_underwear(list/all_picks, species) return pick(valid_picks) -proc/random_hair_style(var/gender, species = "Human", var/datum/robolimb/robohead) +/proc/random_hair_style(var/gender, species = "Human", var/datum/robolimb/robohead) var/h_style = "Bald" var/list/valid_hairstyles = list() for(var/hairstyle in GLOB.hair_styles_public_list) @@ -75,7 +75,7 @@ proc/random_hair_style(var/gender, species = "Human", var/datum/robolimb/robohea return h_style -proc/random_facial_hair_style(var/gender, species = "Human", var/datum/robolimb/robohead) +/proc/random_facial_hair_style(var/gender, species = "Human", var/datum/robolimb/robohead) var/f_style = "Shaved" var/list/valid_facial_hairstyles = list() for(var/facialhairstyle in GLOB.facial_hair_styles_list) @@ -104,7 +104,7 @@ proc/random_facial_hair_style(var/gender, species = "Human", var/datum/robolimb/ return f_style -proc/random_head_accessory(species = "Human") +/proc/random_head_accessory(species = "Human") var/ha_style = "None" var/list/valid_head_accessories = list() for(var/head_accessory in GLOB.head_accessory_styles_list) @@ -119,7 +119,7 @@ proc/random_head_accessory(species = "Human") return ha_style -proc/random_marking_style(var/location = "body", species = "Human", var/datum/robolimb/robohead, var/body_accessory, var/alt_head) +/proc/random_marking_style(var/location = "body", species = "Human", var/datum/robolimb/robohead, var/body_accessory, var/alt_head) var/m_style = "None" var/list/valid_markings = list() for(var/marking in GLOB.marking_styles_list) @@ -158,7 +158,7 @@ proc/random_marking_style(var/location = "body", species = "Human", var/datum/ro return m_style -proc/random_body_accessory(species = "Vulpkanin") +/proc/random_body_accessory(species = "Vulpkanin") var/body_accessory = null var/list/valid_body_accessories = list() for(var/B in GLOB.body_accessory_by_name) @@ -174,7 +174,7 @@ proc/random_body_accessory(species = "Vulpkanin") return body_accessory -proc/random_name(gender, species = "Human") +/proc/random_name(gender, species = "Human") var/datum/species/current_species if(species) @@ -188,7 +188,7 @@ proc/random_name(gender, species = "Human") else return current_species.get_random_name(gender) -proc/random_skin_tone(species = "Human") +/proc/random_skin_tone(species = "Human") if(species == "Human" || species == "Drask") switch(pick(60;"caucasian", 15;"afroamerican", 10;"african", 10;"latino", 5;"albino")) if("caucasian") . = -10 @@ -202,7 +202,7 @@ proc/random_skin_tone(species = "Human") . = rand(1, 6) return . -proc/skintone2racedescription(tone, species = "Human") +/proc/skintone2racedescription(tone, species = "Human") if(species == "Human") switch(tone) if(30 to INFINITY) return "albino" @@ -225,7 +225,7 @@ proc/skintone2racedescription(tone, species = "Human") else return "unknown" -proc/age2agedescription(age) +/proc/age2agedescription(age) switch(age) if(0 to 1) return "infant" if(1 to 3) return "toddler" diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index 034e8851c18..7019ee8b2c4 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -196,7 +196,7 @@ //checks text for html tags //if tag is not in whitelist (var/list/paper_tag_whitelist in global.dm) //relpaces < with < -proc/checkhtml(var/t) +/proc/checkhtml(var/t) t = sanitize_simple(t, list("&#"=".")) var/p = findtext(t,"<",1) while(p) //going through all the tags diff --git a/code/__HELPERS/time.dm b/code/__HELPERS/time.dm index 83347c20d3b..a1da66b1373 100644 --- a/code/__HELPERS/time.dm +++ b/code/__HELPERS/time.dm @@ -60,7 +60,7 @@ return time2text(station_time(time, TRUE), format) /* Returns 1 if it is the selected month and day */ -proc/isDay(var/month, var/day) +/proc/isDay(var/month, var/day) if(isnum(month) && isnum(day)) var/MM = text2num(time2text(world.timeofday, "MM")) // get the current month var/DD = text2num(time2text(world.timeofday, "DD")) // get the current day @@ -95,7 +95,7 @@ proc/isDay(var/month, var/day) /proc/seconds_to_time(var/seconds as num) var/numSeconds = seconds % 60 var/numMinutes = (seconds - numSeconds) / 60 - return "[numMinutes] [numMinutes > 1 ? "minutes" : "minute"] and [numSeconds] seconds." + return "[numMinutes] [numMinutes > 1 ? "minutes" : "minute"] and [numSeconds] seconds" //Take a value in seconds and makes it display like a clock /proc/seconds_to_clock(var/seconds as num) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index fc0f7520e0e..3fb8c2400ab 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -529,7 +529,7 @@ Returns 1 if the chain up to the area contains the given typepath return max(min(middle, high), low) //returns random gauss number -proc/GaussRand(var/sigma) +/proc/GaussRand(var/sigma) var/x,y,rsq do x=2*rand()-1 @@ -539,7 +539,7 @@ proc/GaussRand(var/sigma) return sigma*y*sqrt(-2*log(rsq)/rsq) //returns random gauss number, rounded to 'roundto' -proc/GaussRandRound(var/sigma,var/roundto) +/proc/GaussRandRound(var/sigma,var/roundto) return round(GaussRand(sigma),roundto) //Will return the contents of an atom recursivly to a depth of 'searchDepth' @@ -583,7 +583,7 @@ proc/GaussRandRound(var/sigma,var/roundto) return 1 -proc/is_blocked_turf(turf/T, exclude_mobs) +/proc/is_blocked_turf(turf/T, exclude_mobs) if(T.density) return 1 for(var/i in T) @@ -984,16 +984,16 @@ proc/is_blocked_turf(turf/T, exclude_mobs) -proc/get_cardinal_dir(atom/A, atom/B) +/proc/get_cardinal_dir(atom/A, atom/B) var/dx = abs(B.x - A.x) var/dy = abs(B.y - A.y) return get_dir(A, B) & (rand() * (dx+dy) < dy ? 3 : 12) //chances are 1:value. anyprob(1) will always return true -proc/anyprob(value) +/proc/anyprob(value) return (rand(1,value)==value) -proc/view_or_range(distance = world.view , center = usr , type) +/proc/view_or_range(distance = world.view , center = usr , type) switch(type) if("view") . = view(distance,center) @@ -1001,7 +1001,7 @@ proc/view_or_range(distance = world.view , center = usr , type) . = range(distance,center) return -proc/oview_or_orange(distance = world.view , center = usr , type) +/proc/oview_or_orange(distance = world.view , center = usr , type) switch(type) if("view") . = oview(distance,center) @@ -1009,7 +1009,7 @@ proc/oview_or_orange(distance = world.view , center = usr , type) . = orange(distance,center) return -proc/get_mob_with_client_list() +/proc/get_mob_with_client_list() var/list/mobs = list() for(var/mob/M in GLOB.mob_list) if(M.client) @@ -1233,10 +1233,10 @@ GLOBAL_LIST_INIT(wall_items, typecacheof(list(/obj/machinery/power/apc, /obj/mac return 0 -proc/get_angle(atom/a, atom/b) +/proc/get_angle(atom/a, atom/b) return atan2(b.y - a.y, b.x - a.x) -proc/atan2(x, y) +/proc/atan2(x, y) if(!x && !y) return 0 return y >= 0 ? arccos(x / sqrt(x * x + y * y)) : -arccos(x / sqrt(x * x + y * y)) @@ -1329,7 +1329,7 @@ Standard way to write links -Sayu return FACING_INIT_FACING_TARGET_TARGET_FACING_PERPENDICULAR -atom/proc/GetTypeInAllContents(typepath) +/atom/proc/GetTypeInAllContents(typepath) var/list/processing_list = list(src) var/list/processed = list() diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm index 283d92a954f..9c6fa81c1a2 100644 --- a/code/_globalvars/misc.dm +++ b/code/_globalvars/misc.dm @@ -10,12 +10,12 @@ GLOBAL_DATUM_INIT(command_announcer, /obj/item/radio/intercom/command, create_co // Load order issues means this can't be new'd until other code runs // This is probably not the way I should be doing this, but I don't know how to do it right! -proc/create_global_announcer() +/proc/create_global_announcer() spawn(0) GLOB.global_announcer = new(null) return -proc/create_command_announcer() +/proc/create_command_announcer() spawn(0) GLOB.command_announcer = new(null) return @@ -92,6 +92,7 @@ GLOBAL_VAR(map_name) // Self explanatory GLOBAL_DATUM_INIT(data_core, /datum/datacore, new) // Station datacore, manifest, etc GLOBAL_VAR_INIT(panic_bunker_enabled, FALSE) // Is the panic bunker enabled +GLOBAL_VAR_INIT(pending_server_update, FALSE) //Database connections //A connection is established on world creation. Ideally, the connection dies when the server restarts (After feedback logging.). diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index b0676eabdc7..777a7625fe7 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -231,6 +231,13 @@ to_chat(user, "The door bolt lights have been enabled.") update_icon() +// FIRE ALARMS + +/obj/machinery/firealarm/AICtrlClick() + if(enabled) + reset() + else + alarm() // AI-CONTROLLED SLIP GENERATOR IN AI CORE diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index f9e5cbf3e5a..e61b9bdc8b6 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -170,6 +170,9 @@ /obj/machinery/ai_slipper/BorgAltClick() //Dispenses liquid if on Activate() +/obj/machinery/firealarm/BorgCtrlClick() + AICtrlClick() + /* As with AI, these are not used in click code, because the code for robots is specific, not generic. diff --git a/code/controllers/subsystem/cleanup.dm b/code/controllers/subsystem/cleanup.dm new file mode 100644 index 00000000000..f5962c45547 --- /dev/null +++ b/code/controllers/subsystem/cleanup.dm @@ -0,0 +1,44 @@ +/** + * # Cleanup Subsystem + * + * For now, all it does is periodically clean the supplied global lists of any null values they may contain. + * + * Why is this important? + * + * Sometimes, these lists can gain nulls due to errors. + * For example, when a dead player trasitions from the `dead_mob_list` to the `alive_mob_list`, a null value may get stuck in the dead mob list. + * This can cause issues when other code tries to do things with the values in the list, but are instead met with null values. + * These problems are incredibly hard to track down and fix, so this subsystem is a solution to that. + */ +SUBSYSTEM_DEF(cleanup) + name = "Null cleanup" + wait = 30 SECONDS + flags = SS_POST_FIRE_TIMING + priority = FIRE_PRIORITY_CLEANUP + init_order = INIT_ORDER_CLEANUP + runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT + offline_implications = "Certain global lists will no longer be cleared of nulls, which may result in runtimes. No immediate action is needed." + /// A list of global lists we want the subsystem to clean. + var/list/lists_to_clean + +/datum/controller/subsystem/cleanup/Initialize(start_timeofday) + // If you want this subsystem to clean out nulls from a specific list, add it here. + lists_to_clean = list( + GLOB.clients = "clients", + GLOB.player_list = "player_list", + GLOB.mob_list = "mob_list", + GLOB.alive_mob_list = "alive_mob_list", + GLOB.dead_mob_list = "dead_mob_list", + GLOB.human_list = "human_list", + GLOB.carbon_list = "carbon_list" + ) + return ..() + +/datum/controller/subsystem/cleanup/fire(resumed) + for(var/L in lists_to_clean) + var/list/_list = L + var/prev_length = length(_list) + listclearnulls(_list) + + if(length(_list) < prev_length) + stack_trace("Found a null value in GLOB.[lists_to_clean[_list]]!") diff --git a/code/controllers/subsystem/jobs.dm b/code/controllers/subsystem/jobs.dm index 3adfdf3972f..729c4dbe67b 100644 --- a/code/controllers/subsystem/jobs.dm +++ b/code/controllers/subsystem/jobs.dm @@ -620,20 +620,32 @@ SUBSYSTEM_DEF(jobs) var/mob/M = tgtcard.getPlayer() for(var/datum/job/job in occupations) if(tgtcard.assignment && tgtcard.assignment == job.title) - jobs_to_formats[job.title] = "disabled" // the job they already have is pre-selected + jobs_to_formats[job.title] = "green" // the job they already have is pre-selected + else if(tgtcard.assignment == "Demoted" || tgtcard.assignment == "Terminated") + jobs_to_formats[job.title] = "grey" else if(!job.would_accept_job_transfer_from_player(M)) - jobs_to_formats[job.title] = "linkDiscourage" // jobs which are karma-locked and not unlocked for this player are discouraged + jobs_to_formats[job.title] = "grey" // jobs which are karma-locked and not unlocked for this player are discouraged else if((job.title in GLOB.command_positions) && istype(M) && M.client && job.available_in_playtime(M.client)) - jobs_to_formats[job.title] = "linkDiscourage" // command jobs which are playtime-locked and not unlocked for this player are discouraged + jobs_to_formats[job.title] = "grey" // command jobs which are playtime-locked and not unlocked for this player are discouraged else if(job.total_positions && !job.current_positions && job.title != "Civilian") - jobs_to_formats[job.title] = "linkEncourage" // jobs with nobody doing them at all are encouraged + jobs_to_formats[job.title] = "teal" // jobs with nobody doing them at all are encouraged else if(job.total_positions >= 0 && job.current_positions >= job.total_positions) - jobs_to_formats[job.title] = "linkDiscourage" // jobs that are full (no free positions) are discouraged + jobs_to_formats[job.title] = "grey" // jobs that are full (no free positions) are discouraged + if(tgtcard.assignment == "Demoted" || tgtcard.assignment == "Terminated") + jobs_to_formats["Custom"] = "grey" return jobs_to_formats -/datum/controller/subsystem/jobs/proc/log_job_transfer(transferee, oldvalue, newvalue, whodidit) - id_change_records["[id_change_counter]"] = list("transferee" = transferee, "oldvalue" = oldvalue, "newvalue" = newvalue, "whodidit" = whodidit, "timestamp" = station_time_timestamp()) + +/datum/controller/subsystem/jobs/proc/log_job_transfer(transferee, oldvalue, newvalue, whodidit, reason) + id_change_records["[id_change_counter]"] = list( + "transferee" = transferee, + "oldvalue" = oldvalue, + "newvalue" = newvalue, + "whodidit" = whodidit, + "timestamp" = station_time_timestamp(), + "reason" = reason + ) id_change_counter++ /datum/controller/subsystem/jobs/proc/slot_job_transfer(oldtitle, newtitle) @@ -663,45 +675,35 @@ SUBSYSTEM_DEF(jobs) return var/datum/data/pda/app/messenger/PM = target_pda.find_program(/datum/data/pda/app/messenger) if(PM && PM.can_receive()) - PM.notify("Automated Notification: \"[antext]\" (Unable to Reply)") + PM.notify("Automated Notification: \"[antext]\" (Unable to Reply)", 0) // the 0 means don't make the PDA flash +/datum/controller/subsystem/jobs/proc/notify_by_name(target_name, antext) + // Used to notify a specific crew member based on their real_name + if(!target_name || !antext) + return + var/obj/item/pda/target_pda + for(var/obj/item/pda/check_pda in GLOB.PDAs) + if(check_pda.owner == target_name) + target_pda = check_pda + break + if(!target_pda) + return + var/datum/data/pda/app/messenger/PM = target_pda.find_program(/datum/data/pda/app/messenger) + if(PM && PM.can_receive()) + PM.notify("Automated Notification: \"[antext]\" (Unable to Reply)", 0) // the 0 means don't make the PDA flash -/datum/controller/subsystem/jobs/proc/fetch_transfer_record_html(var/centcom) - var/record_html = "" - - var/table_headers = list("Crewman", "Old Rank", "New Rank", "Authorized By", "Time") - var/hidden_fields = list("deletedby") - if(centcom) - table_headers += "Deleted By" - record_html += "" - for(var/thisheader in table_headers) - record_html += "" - record_html += "" - - var/visible_record_count = 0 +/datum/controller/subsystem/jobs/proc/format_job_change_records(centcom) + var/list/formatted = list() for(var/thisid in id_change_records) var/thisrecord = id_change_records[thisid] - if(thisrecord["deletedby"] && !centcom) continue - - record_html += "" + var/list/newlist = list() for(var/lkey in thisrecord) - if(lkey in hidden_fields) - if(centcom) - record_html += "" - else - continue - else - record_html += "" - record_html += "" - visible_record_count++ + newlist[lkey] = thisrecord[lkey] + formatted.Add(list(newlist)) + return formatted - record_html += "
[thisheader]
[thisrecord[lkey]][thisrecord[lkey]]
" - - if(!visible_record_count) - return "No records on file yet." - return record_html /datum/controller/subsystem/jobs/proc/delete_log_records(sourceuser, delete_all) . = 0 diff --git a/code/controllers/subsystem/parallax.dm b/code/controllers/subsystem/parallax.dm index 9135f62b03f..1e3c8aca0d9 100644 --- a/code/controllers/subsystem/parallax.dm +++ b/code/controllers/subsystem/parallax.dm @@ -34,7 +34,7 @@ SUBSYSTEM_DEF(parallax) for (A; isloc(A.loc) && !isturf(A.loc); A = A.loc); if(A != C.movingmob) - if(C.movingmob != null) + if(C.movingmob != null && C.movingmob.client_mobs_in_contents) C.movingmob.client_mobs_in_contents -= C.mob UNSETEMPTY(C.movingmob.client_mobs_in_contents) LAZYINITLIST(A.client_mobs_in_contents) diff --git a/code/controllers/subsystem/shuttles.dm b/code/controllers/subsystem/shuttles.dm index 08fa7709320..67b6a1b8dd7 100644 --- a/code/controllers/subsystem/shuttles.dm +++ b/code/controllers/subsystem/shuttles.dm @@ -93,6 +93,11 @@ SUBSYSTEM_DEF(shuttle) return S WARNING("couldn't find dock with id: [id]") +/datum/controller/subsystem/shuttle/proc/secondsToRefuel() + var/elapsed = world.time - SSticker.round_start_time + var/remaining = round((config.shuttle_refuel_delay - elapsed) / 10) + return remaining > 0 ? remaining : 0 + /datum/controller/subsystem/shuttle/proc/requestEvac(mob/user, call_reason) if(!emergency) WARNING("requestEvac(): There is no emergency shuttle, but the shuttle was called. Using the backup shuttle instead.") @@ -107,7 +112,7 @@ SUBSYSTEM_DEF(shuttle) return emergency = backup_shuttle - if(world.time - SSticker.round_start_time < config.shuttle_refuel_delay) + if(secondsToRefuel()) to_chat(user, "The emergency shuttle is refueling. Please wait another [abs(round(((world.time - SSticker.round_start_time) - config.shuttle_refuel_delay)/600))] minutes before trying again.") return @@ -131,7 +136,7 @@ SUBSYSTEM_DEF(shuttle) call_reason = trim(html_encode(call_reason)) if(length(call_reason) < CALL_SHUTTLE_REASON_LENGTH) - to_chat(user, "You must provide a reason.") + to_chat(user, "Reason is too short. [CALL_SHUTTLE_REASON_LENGTH] character minimum.") return var/area/signal_origin = get_area(user) @@ -192,7 +197,7 @@ SUBSYSTEM_DEF(shuttle) var/obj/machinery/computer/communications/C = thing if(C.stat & BROKEN) continue - else if(istype(thing, /datum/computer_file/program/comm) || istype(thing, /obj/item/circuitboard/communications)) + else if(istype(thing, /obj/item/circuitboard/communications)) continue var/turf/T = get_turf(thing) diff --git a/code/datums/action.dm b/code/datums/action.dm index 11ab496d386..1a146467b5a 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -450,6 +450,7 @@ /datum/action/spell_action check_flags = 0 background_icon_state = "bg_spell" + var/recharge_text_color = "#FFFFFF" /datum/action/spell_action/New(Target) ..() @@ -487,6 +488,18 @@ return spell.can_cast(owner) return 0 +/datum/action/spell_action/UpdateButtonIcon() + if(button && !(. = ..())) + var/obj/effect/proc_holder/spell/S = target + if(!istype(S)) + return + var/progress = S.get_availability_percentage() + var/col_val_high = 72 * progress + 128 + var/col_val_low = 200 * progress + button.maptext = "
[round_down(progress * 100)]%
" + button.color = rgb(col_val_high, col_val_low, col_val_low, col_val_high) + else + button.maptext = null /* /datum/action/spell_action/alien diff --git a/code/datums/cache/air_alarm.dm b/code/datums/cache/air_alarm.dm index 2edc0792a34..fd9e529d70a 100644 --- a/code/datums/cache/air_alarm.dm +++ b/code/datums/cache/air_alarm.dm @@ -1,3 +1,5 @@ +#define AIR_ALARM_DATA_CACHE_DURATION 10 SECONDS + GLOBAL_DATUM_INIT(air_alarm_repository, /datum/repository/air_alarm, new()) /datum/repository/air_alarm/proc/air_alarm_data(var/list/monitored_alarms, var/refresh = 0, var/obj/machinery/alarm/passed_alarm) @@ -8,7 +10,7 @@ GLOBAL_DATUM_INIT(air_alarm_repository, /datum/repository/air_alarm, new()) cache_entry = new/datum/cache_entry cache_data = cache_entry - if(!refresh) + if(!refresh && cache_entry.timestamp + AIR_ALARM_DATA_CACHE_DURATION > world.time) return cache_entry.data if(SSticker && SSticker.current_state < GAME_STATE_PLAYING && istype(passed_alarm)) // Generating the list for the first time as the game hasn't started - no need to run through the machines list everything every time @@ -29,3 +31,5 @@ GLOBAL_DATUM_INIT(air_alarm_repository, /datum/repository/air_alarm, new()) /datum/repository/air_alarm/proc/update_cache(var/obj/machinery/alarm/alarm) return air_alarm_data(refresh = 1, passed_alarm = alarm) + +#undef AIR_ALARM_DATA_CACHE_DURATION diff --git a/code/datums/components/ducttape.dm b/code/datums/components/ducttape.dm index 49931db8edc..b41066d375d 100644 --- a/code/datums/components/ducttape.dm +++ b/code/datums/components/ducttape.dm @@ -47,23 +47,30 @@ return if(!isturf(target)) return - if(!user.unEquip(I)) - return var/turf/source_turf = get_turf(I) var/turf/target_turf = target - var/list/clickparams = params2list(params) - var/x_offset = text2num(clickparams["icon-x"]) - 16 - var/y_offset = text2num(clickparams["icon-y"]) - 16 + var/x_offset + var/y_offset if(target_turf != get_turf(I)) //Trying to stick it on a wall, don't move it to the actual wall or you can move the item through it. Instead set the pixels as appropriate var/target_direction = get_dir(source_turf, target_turf)//The direction we clicked + // Snowflake diagonal handling + if(target_direction in GLOB.diagonals) + to_chat(user, "You cant reach [target_turf].") + return if(target_direction & EAST) - x_offset += 32 + x_offset = 16 + y_offset = rand(-12, 12) else if(target_direction & WEST) - x_offset -= 32 - if(target_direction & NORTH) - y_offset += 32 + x_offset = -16 + y_offset = rand(-12, 12) + else if(target_direction & NORTH) + x_offset = rand(-12, 12) + y_offset = 16 else if(target_direction & SOUTH) - y_offset -= 32 + x_offset = rand(-12, 12) + y_offset = -16 + if(!user.unEquip(I)) + return to_chat(user, "You stick [I] to [target_turf].") I.pixel_x = x_offset I.pixel_y = y_offset diff --git a/code/datums/dog_fashion.dm b/code/datums/dog_fashion.dm index 3bf109eabd9..14705ae7375 100644 --- a/code/datums/dog_fashion.dm +++ b/code/datums/dog_fashion.dm @@ -191,6 +191,10 @@ ..() desc = "That's Definitely Not [M.real_name]." +/datum/dog_fashion/head/cone + name = "REAL_NAME" + desc = "Omnicone's Chosen Champion" + /datum/dog_fashion/back/hardsuit name = "Space Explorer REAL_NAME" desc = "That's one small step for a corgi. One giant yap for corgikind." @@ -200,3 +204,7 @@ D.mutations.Add(BREATHLESS) D.atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) D.minbodytemp = 0 + +/datum/dog_fashion/head/fried_vox_empty + name = "Colonel REAL_NAME" + desc = "Keep away from live vox." diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm index 4e20d2a675e..4609075ddd7 100644 --- a/code/datums/helper_datums/teleport.dm +++ b/code/datums/helper_datums/teleport.dm @@ -152,13 +152,11 @@ return doTeleport() return 0 -/datum/teleport/instant //teleports when datum is created - - start(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null) - if(..()) - if(teleport()) - return 1 - return 0 +/datum/teleport/instant/start(ateleatom, adestination, aprecision=0, afteleport=1, aeffectin=null, aeffectout=null, asoundin=null, asoundout=null) + if(..()) + if(teleport()) + return 1 + return 0 /datum/teleport/instant/science diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 0c992bbb32c..8fa5b909cda 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -914,7 +914,7 @@ log_admin("[key_name(usr)] has equipped [key_name(current)] as a wizard") message_admins("[key_name_admin(usr)] has equipped [key_name_admin(current)] as a wizard") if("name") - SSticker.mode.name_wizard(current) + INVOKE_ASYNC(SSticker.mode, /datum/game_mode/wizard.proc/name_wizard, current) log_admin("[key_name(usr)] has allowed wizard [key_name(current)] to name themselves") message_admins("[key_name_admin(usr)] has allowed wizard [key_name_admin(current)] to name themselves") if("autoobjectives") @@ -1501,7 +1501,7 @@ SSticker.mode.equip_wizard(current) for(var/obj/item/spellbook/S in current.contents) S.op = 0 - SSticker.mode.name_wizard(current) + INVOKE_ASYNC(SSticker.mode, /datum/game_mode/wizard.proc/name_wizard, current) SSticker.mode.forge_wizard_objectives(src) SSticker.mode.greet_wizard(src) SSticker.mode.update_wiz_icons_added(src) diff --git a/code/datums/pipe_datums.dm b/code/datums/pipe_datums.dm index 83b77425447..8d3b0807f9c 100644 --- a/code/datums/pipe_datums.dm +++ b/code/datums/pipe_datums.dm @@ -351,16 +351,6 @@ GLOBAL_LIST_EMPTY(rpd_pipe_list) //Some pipes we don't want to be dispensable pipe_id = PIPE_CIRCULATOR pipe_icon = "circ" -/datum/pipes/atmospheric/omni_filter - pipe_name = "omni filter" - pipe_id = PIPE_OMNI_FILTER - pipe_icon = "omni_filter" - -/datum/pipes/atmospheric/omni_mixer - pipe_name = "omni mixer" - pipe_id = PIPE_OMNI_MIXER - pipe_icon = "omni_mixer" - /datum/pipes/atmospheric/insulated pipe_name = "insulated pipe" pipe_id = PIPE_INSULATED_STRAIGHT diff --git a/code/datums/ruins/lavaland.dm b/code/datums/ruins/lavaland.dm index f826b6ff0d2..2143fb5ad5c 100644 --- a/code/datums/ruins/lavaland.dm +++ b/code/datums/ruins/lavaland.dm @@ -16,7 +16,7 @@ name = "Biodome Winter" id = "biodome-winter" description = "For those getaways where you want to get back to nature, but you don't want to leave the fortified military compound where you spend your days. \ - Includes a unique(*) laser pistol display case, and the recently introduced I.C.E(tm)." + Includes the recently introduced I.C.E(tm)." suffix = "lavaland_biodome_winter.dmm" /datum/map_template/ruin/lavaland/biodome/clown @@ -42,7 +42,7 @@ cost = 10 allow_duplicates = FALSE -datum/map_template/ruin/lavaland/ash_walker +/datum/map_template/ruin/lavaland/ash_walker name = "Ash Walker Nest" id = "ash-walker" description = "A race of unbreathing lizards live here, that run faster than a human can, worship a broken dead city, and are capable of reproducing by something involving tentacles? \ diff --git a/code/datums/spawners_menu.dm b/code/datums/spawners_menu.dm index a651edbc79c..a196a60fcc5 100644 --- a/code/datums/spawners_menu.dm +++ b/code/datums/spawners_menu.dm @@ -6,44 +6,47 @@ qdel(src) owner = new_owner -/datum/spawners_menu/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = FALSE, datum/topic_state/state = GLOB.ghost_state, datum/nanoui/master_ui = null) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/datum/spawners_menu/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui_state/state = GLOB.tgui_observer_state, datum/tgui/master_ui = null) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "spawners_menu.tmpl", "Spawners Menu", 700, 600, master_ui, state = state) + ui = new(user, src, ui_key, "SpawnersMenu", "Spawners Menu", 700, 600, master_ui, state = state) ui.open() -/datum/spawners_menu/ui_data(mob/user) +/datum/spawners_menu/tgui_data(mob/user) var/list/data = list() data["spawners"] = list() for(var/spawner in GLOB.mob_spawners) var/list/this = list() this["name"] = spawner this["desc"] = "" + this["important_info"] = "" + this["fluff"] = "" this["uids"] = list() - for(var/spawner_obj in GLOB.mob_spawners[spawner]) + for(var/spawner_obj in GLOB.mob_spawners[spawner])//each spawner can contain multiple actual spawners, we use only one desc/info this["uids"] += "\ref[spawner_obj]" - if(!this["desc"]) + if(!this["desc"]) //haven't set descriptions yet if(istype(spawner_obj, /obj/effect/mob_spawn)) var/obj/effect/mob_spawn/MS = spawner_obj - this["desc"] = MS.flavour_text + this["desc"] = MS.description + this["important_info"] = MS.important_info + this["fluff"] = MS.flavour_text else var/obj/O = spawner_obj this["desc"] = O.desc this["amount_left"] = LAZYLEN(GLOB.mob_spawners[spawner]) data["spawners"] += list(this) - return data -/datum/spawners_menu/Topic(href, href_list) +/datum/spawners_menu/tgui_act(action, params) if(..()) - return 1 - var/spawners = replacetext(href_list["uid"], ",", ";") + return + var/spawners = replacetext(params["ID"], ",", ";") var/list/possible_spawners = params2list(spawners) var/obj/effect/mob_spawn/MS = locate(pick(possible_spawners)) if(!MS || !istype(MS)) log_runtime(EXCEPTION("A ghost tried to interact with an invalid spawner, or the spawner didn't exist.")) return - switch(href_list["action"]) + switch(action) if("jump") owner.forceMove(get_turf(MS)) . = TRUE diff --git a/code/datums/spell.dm b/code/datums/spell.dm index cb10700e5c6..94779ed67fb 100644 --- a/code/datums/spell.dm +++ b/code/datums/spell.dm @@ -230,12 +230,12 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) /obj/effect/proc_holder/spell/process() charge_counter += 2 + if(action) + action.UpdateButtonIcon() if(charge_counter < charge_max) return STOP_PROCESSING(SSfastprocess, src) charge_counter = charge_max - if(action) - action.UpdateButtonIcon() /obj/effect/proc_holder/spell/proc/perform(list/targets, recharge = 1, mob/user = usr, make_attack_logs = TRUE) //if recharge is started is important for the trigger spells before_cast(targets) @@ -339,6 +339,19 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) target.vars[type] += amount //I bear no responsibility for the runtimes that'll happen if you try to adjust non-numeric or even non-existant vars return +/obj/effect/proc_holder/spell/proc/get_availability_percentage() + switch(charge_type) + if("recharge") + if(charge_counter == 0) + return 0 + return charge_counter / charge_max + if("charges") + if(charge_counter) + return 1 + return 0 + if("holdervar") + return 1 + /obj/effect/proc_holder/spell/targeted //can mean aoe for mobs (limited/unlimited number) or one target mob var/max_targets = 1 //leave 0 for unlimited targets in range, 1 for one selectable target in range, more for limited number of casts (can all target one guy, depends on target_ignore_prev) in range var/target_ignore_prev = 1 //only important if max_targets > 1, affects if the spell can be cast multiple times at one person from one cast diff --git a/code/datums/spells/devil.dm b/code/datums/spells/devil.dm index 27b2fcb8851..1a1069481cf 100644 --- a/code/datums/spells/devil.dm +++ b/code/datums/spells/devil.dm @@ -75,7 +75,7 @@ action_background_icon_state = "bg_demon" /obj/effect/proc_holder/spell/fireball/hellish/cast(list/targets, mob/living/user = usr) - msg_admin_attack("[key_name_admin(usr)] has fired a fireball.", ATKLOG_FEW) + add_attack_logs(user, targets, "has fired a Hellfire ball", ATKLOG_FEW) .=..() diff --git a/code/datums/spells/lightning.dm b/code/datums/spells/lightning.dm index e7821aed6c2..ed6b7cd543e 100644 --- a/code/datums/spells/lightning.dm +++ b/code/datums/spells/lightning.dm @@ -44,7 +44,7 @@ if(ready) Discharge() -obj/effect/proc_holder/spell/targeted/lightning/proc/Reset(mob/user = usr) +/obj/effect/proc_holder/spell/targeted/lightning/proc/Reset(mob/user = usr) ready = 0 start_time = 0 if(halo) diff --git a/code/datums/spells/magnet.dm b/code/datums/spells/magnet.dm index fea6780085c..dfdac6f1b9c 100644 --- a/code/datums/spells/magnet.dm +++ b/code/datums/spells/magnet.dm @@ -39,7 +39,7 @@ if(ready) Discharge() -obj/effect/proc_holder/spell/targeted/magnet/proc/Reset(mob/user = usr) +/obj/effect/proc_holder/spell/targeted/magnet/proc/Reset(mob/user = usr) ready = 0 energy = 0 start_time = 0 diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index 3562cfd9d80..8a29d2cb0d0 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -412,9 +412,9 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) /datum/uplink_item/jobspecific/energizedfireaxe name = "Energized Fire Axe" - desc = "A fire axe with a massive electrical charge built into it. It can release this charge on its first victim and will be rather plain after that." + desc = "A fire axe with a massive energy charge built into it. Upon striking someone while charged it will throw them backwards while stunning them briefly, but will take some time to charge up again. It is also much sharper than a regular axe and can pierce light armor." reference = "EFA" - item = /obj/item/twohanded/energizedfireaxe + item = /obj/item/twohanded/fireaxe/energized cost = 10 job = list("Life Support Specialist") diff --git a/code/datums/wires/suitstorage.dm b/code/datums/wires/suitstorage.dm index 828e56884bf..ec651002747 100644 --- a/code/datums/wires/suitstorage.dm +++ b/code/datums/wires/suitstorage.dm @@ -17,7 +17,7 @@ . += "The green light is [A.shocked ? "on" : "off"]." . += "The UV display shows [A.uv_super ? "15 nm" : "185 nm"]." -datum/wires/suitstorage/interactable(mob/user) +/datum/wires/suitstorage/interactable(mob/user) var/obj/machinery/suit_storage_unit/A = holder if(iscarbon(user) && A.Adjacent(user) && A.shocked) return A.shock(user, 100) @@ -42,7 +42,7 @@ datum/wires/suitstorage/interactable(mob/user) A.uv_super = !mend ..() -datum/wires/suitstorage/on_pulse(wire) +/datum/wires/suitstorage/on_pulse(wire) var/obj/machinery/suit_storage_unit/A = holder if(is_cut(wire)) return diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm index 27d1448ac77..d2c092211ec 100644 --- a/code/datums/wires/wires.dm +++ b/code/datums/wires/wires.dm @@ -62,7 +62,7 @@ * In the `colors` list, the name of the color is the key, and the wire is the value. * For example: `colors["red"] = WIRE_ELECTRIFY`. This will look like `list("red" = WIRE_ELECTRIFY)` internally. */ -datum/wires/proc/randomize() +/datum/wires/proc/randomize() var/static/list/possible_colors = list("red", "blue", "green", "silver", "orange", "brown", "gold", "white", "cyan", "magenta", "purple", "pink") var/list/my_possible_colors = possible_colors.Copy() diff --git a/code/defines/procs/dbcore.dm b/code/defines/procs/dbcore.dm index 90a5b0db40c..945ab8af23a 100644 --- a/code/defines/procs/dbcore.dm +++ b/code/defines/procs/dbcore.dm @@ -29,7 +29,7 @@ #define BLOB 14 // TODO: Investigate more recent type additions and see if I can handle them. - Nadrew -DBConnection +/DBConnection var/_db_con // This variable contains a reference to the actual database connection. var/dbi // This variable is a string containing the DBI MySQL requires. var/user // This variable contains the username data. @@ -39,14 +39,14 @@ DBConnection var/server = "" var/port = 3306 -DBConnection/New(dbi_handler,username,password_handler,cursor_handler) +/DBConnection/New(dbi_handler,username,password_handler,cursor_handler) src.dbi = dbi_handler src.user = username src.password = password_handler src.default_cursor = cursor_handler _db_con = _dm_db_new_con() -DBConnection/proc/Connect(dbi_handler=src.dbi,user_handler=src.user,password_handler=src.password,cursor_handler) +/DBConnection/proc/Connect(dbi_handler=src.dbi,user_handler=src.user,password_handler=src.password,cursor_handler) if(!config.sql_enabled) return 0 if(!src) return 0 @@ -54,24 +54,24 @@ DBConnection/proc/Connect(dbi_handler=src.dbi,user_handler=src.user,password_han if(!cursor_handler) cursor_handler = Default_Cursor return _dm_db_connect(_db_con,dbi_handler,user_handler,password_handler,cursor_handler,null) -DBConnection/proc/Disconnect() return _dm_db_close(_db_con) +/DBConnection/proc/Disconnect() return _dm_db_close(_db_con) -DBConnection/proc/IsConnected() +/DBConnection/proc/IsConnected() if(!config.sql_enabled) return 0 var/success = _dm_db_is_connected(_db_con) return success -DBConnection/proc/Quote(str) return _dm_db_quote(_db_con,str) +/DBConnection/proc/Quote(str) return _dm_db_quote(_db_con,str) -DBConnection/proc/ErrorMsg() return _dm_db_error_msg(_db_con) -DBConnection/proc/SelectDB(database_name,dbi) +/DBConnection/proc/ErrorMsg() return _dm_db_error_msg(_db_con) +/DBConnection/proc/SelectDB(database_name,dbi) if(IsConnected()) Disconnect() //return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[DB_SERVER]:[DB_PORT]"]",user,password) return Connect("[dbi?"[dbi]":"dbi:mysql:[database_name]:[sqladdress]:[sqlport]"]",user,password) -DBConnection/proc/NewQuery(sql_query,cursor_handler=src.default_cursor) return new/DBQuery(sql_query,src,cursor_handler) +/DBConnection/proc/NewQuery(sql_query,cursor_handler=src.default_cursor) return new/DBQuery(sql_query,src,cursor_handler) -DBQuery/New(sql_query,DBConnection/connection_handler,cursor_handler) +/DBQuery/New(sql_query,DBConnection/connection_handler,cursor_handler) if(IsAdminAdvancedProcCall()) to_chat(usr, "DB query blocked: Advanced ProcCall detected.") message_admins("[key_name(usr)] attempted to create a DB query via advanced proc-call") @@ -83,12 +83,12 @@ DBQuery/New(sql_query,DBConnection/connection_handler,cursor_handler) _db_query = _dm_db_new_query() return ..() -DBQuery/CanProcCall() +/DBQuery/CanProcCall() // dont even try it return FALSE -DBQuery +/DBQuery var/sql // The sql query being executed. var/default_cursor var/list/columns //list of DB Columns populated by Columns() @@ -98,26 +98,26 @@ DBQuery var/DBConnection/db_connection var/_db_query -DBQuery/proc/Connect(DBConnection/connection_handler) src.db_connection = connection_handler +/DBQuery/proc/Connect(DBConnection/connection_handler) src.db_connection = connection_handler -DBQuery/proc/Execute(sql_query=src.sql,cursor_handler=default_cursor) +/DBQuery/proc/Execute(sql_query=src.sql,cursor_handler=default_cursor) Close() return _dm_db_execute(_db_query,sql_query,db_connection._db_con,cursor_handler,null) -DBQuery/proc/NextRow() return _dm_db_next_row(_db_query,item,conversions) +/DBQuery/proc/NextRow() return _dm_db_next_row(_db_query,item,conversions) -DBQuery/proc/RowsAffected() return _dm_db_rows_affected(_db_query) +/DBQuery/proc/RowsAffected() return _dm_db_rows_affected(_db_query) -DBQuery/proc/RowCount() return _dm_db_row_count(_db_query) +/DBQuery/proc/RowCount() return _dm_db_row_count(_db_query) -DBQuery/proc/ErrorMsg() return _dm_db_error_msg(_db_query) +/DBQuery/proc/ErrorMsg() return _dm_db_error_msg(_db_query) -DBQuery/proc/Columns() +/DBQuery/proc/Columns() if(!columns) columns = _dm_db_columns(_db_query,/DBColumn) return columns -DBQuery/proc/GetRowData() +/DBQuery/proc/GetRowData() var/list/columns = Columns() var/list/results if(columns.len) @@ -128,23 +128,23 @@ DBQuery/proc/GetRowData() results[C] = src.item[(cur_col.position+1)] return results -DBQuery/proc/Close() +/DBQuery/proc/Close() item.len = 0 columns = null conversions = null return _dm_db_close(_db_query) -DBQuery/proc/Quote(str) +/DBQuery/proc/Quote(str) return db_connection.Quote(str) -DBQuery/proc/SetConversion(column,conversion) +/DBQuery/proc/SetConversion(column,conversion) if(istext(column)) column = columns.Find(column) if(!conversions) conversions = new/list(column) else if(conversions.len < column) conversions.len = column conversions[column] = conversion -DBColumn +/DBColumn var/name var/table var/position //1-based index into item data @@ -153,7 +153,7 @@ DBColumn var/length var/max_length -DBColumn/New(name_handler,table_handler,position_handler,type_handler,flag_handler,length_handler,max_length_handler) +/DBColumn/New(name_handler,table_handler,position_handler,type_handler,flag_handler,length_handler,max_length_handler) src.name = name_handler src.table = table_handler src.position = position_handler @@ -164,7 +164,7 @@ DBColumn/New(name_handler,table_handler,position_handler,type_handler,flag_handl return ..() -DBColumn/proc/SqlTypeName(type_handler=src.sql_type) +/DBColumn/proc/SqlTypeName(type_handler=src.sql_type) switch(type_handler) if(TINYINT) return "TINYINT" if(SMALLINT) return "SMALLINT" diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index de913ac9f91..990e2f1694d 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -570,7 +570,7 @@ /area/proc/prison_break() for(var/obj/machinery/power/apc/temp_apc in src) - temp_apc.overload_lighting(70) + INVOKE_ASYNC(temp_apc, /obj/machinery/power/apc.proc/overload_lighting, 70) for(var/obj/machinery/door/airlock/temp_airlock in src) temp_airlock.prison_open() for(var/obj/machinery/door/window/temp_windoor in src) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 776a2bccd12..73dcd14c7c8 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -231,7 +231,7 @@ /atom/proc/on_reagent_change() return -/atom/proc/Bumped(AM as mob|obj) +/atom/proc/Bumped(atom/movable/AM) return /// Convenience proc to see if a container is open for chemistry handling @@ -257,7 +257,7 @@ /atom/proc/CheckExit() return TRUE -/atom/proc/HasProximity(atom/movable/AM as mob|obj) +/atom/proc/HasProximity(atom/movable/AM) return /atom/proc/emp_act(severity) diff --git a/code/game/dna/genes/vg_powers.dm b/code/game/dna/genes/vg_powers.dm index 9092448e398..e08d35b681d 100644 --- a/code/game/dna/genes/vg_powers.dm +++ b/code/game/dna/genes/vg_powers.dm @@ -214,25 +214,21 @@ /obj/effect/proc_holder/spell/targeted/remotetalk/choose_targets(mob/user = usr) var/list/targets = new /list() - var/list/validtargets = new /list() - var/turf/T = get_turf(user) - for(var/mob/living/M in range(14, T)) - if(M && M.mind) - if(M == user) - continue - validtargets += M + var/list/validtargets = user.get_telepathic_targets() - if(!validtargets.len) + if(!length(validtargets)) to_chat(user, "There are no valid targets!") start_recharge() return - targets += input("Choose the target to talk to.", "Targeting") as null|mob in validtargets + var/target_name = input("Choose the target to talk to.", "Targeting") as null|anything in validtargets - if(!targets.len || !targets[1]) //doesn't waste the spell + var/mob/living/target + if(!target_name || !(target = validtargets[target_name])) revert_cast(user) return + targets += target perform(targets, user = user) /obj/effect/proc_holder/spell/targeted/remotetalk/cast(list/targets, mob/user = usr) @@ -249,7 +245,7 @@ target.show_message("You hear [user.real_name]'s voice: [say]") else target.show_message("You hear a voice that seems to echo around the room: [say]") - user.show_message("You project your mind into [target.name]: [say]") + user.show_message("You project your mind into [(target in user.get_visible_mobs()) ? target.name : "the unknown entity"]: [say]") for(var/mob/dead/observer/G in GLOB.player_list) G.show_message("Telepathic message from [user] ([ghost_follow_link(user, ghost=G)]) to [target] ([ghost_follow_link(target, ghost=G)]): [say]") @@ -266,26 +262,22 @@ var/list/available_targets = list() /obj/effect/proc_holder/spell/targeted/mindscan/choose_targets(mob/user = usr) - var/list/targets = new /list() - var/list/validtargets = new /list() - var/turf/T = get_turf(user) - for(var/mob/living/M in range(14, T)) - if(M && M.mind) - if(M == user) - continue - validtargets += M + var/list/targets = list() + var/list/validtargets = user.get_telepathic_targets() - if(!validtargets.len) + if(!length(validtargets)) to_chat(user, "There are no valid targets!") start_recharge() return - targets += input("Choose the target to listen to.", "Targeting") as null|mob in validtargets + var/target_name = input("Choose the target to listen to.", "Targeting") as null|anything in validtargets - if(!targets.len || !targets[1]) //doesn't waste the spell + var/mob/living/target + if(!target_name || !(target = validtargets[target_name])) revert_cast(user) return + targets += target perform(targets, user = user) /obj/effect/proc_holder/spell/targeted/mindscan/cast(list/targets, mob/user = usr) @@ -295,7 +287,7 @@ var/message = "You feel your mind expand briefly... (Click to send a message.)" if(REMOTE_TALK in target.mutations) message = "You feel [user.real_name] request a response from you... (Click here to project mind.)" - user.show_message("You offer your mind to [target.name].") + user.show_message("You offer your mind to [(target in user.get_visible_mobs()) ? target.name : "the unknown entity"].") target.show_message("[message]") available_targets += target addtimer(CALLBACK(src, .proc/removeAvailability, target), 100) diff --git a/code/game/gamemodes/blob/blob_report.dm b/code/game/gamemodes/blob/blob_report.dm index 8f6ba965222..93b84dbb54d 100644 --- a/code/game/gamemodes/blob/blob_report.dm +++ b/code/game/gamemodes/blob/blob_report.dm @@ -18,7 +18,7 @@ intercepttext += "
Note in the event of a quarantine breach or uncontrolled spread of the biohazard, the directive 7-10 may be upgraded to a directive 7-12.
" intercepttext += "Message ends." if(2) - var/nukecode = "[rand(10000, 99999)]" + var/nukecode = rand(10000, 99999) for(var/obj/machinery/nuclearbomb/bomb in GLOB.machines) if(bomb && bomb.r_code) if(is_station_level(bomb.z)) @@ -40,7 +40,7 @@ aiPlayer.set_zeroth_law(law) to_chat(aiPlayer, "Laws Updated: [law]") - print_command_report(intercepttext, interceptname) + print_command_report(intercepttext, interceptname, FALSE) GLOB.event_announcement.Announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", 'sound/AI/commandreport.ogg', from = "[command_name()] Update") /datum/station_state diff --git a/code/game/gamemodes/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm index fbfb75b8b6a..9bc9fc7b511 100644 --- a/code/game/gamemodes/changeling/powers/tiny_prick.dm +++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm @@ -112,7 +112,7 @@ feedback_add_details("changeling_powers","TS") return TRUE -datum/action/changeling/sting/extract_dna +/datum/action/changeling/sting/extract_dna name = "Extract DNA Sting" desc = "We stealthily sting a target and extract their DNA. Costs 25 chemicals." helptext = "Will give you the DNA of your target, allowing you to transform into them." @@ -132,7 +132,7 @@ datum/action/changeling/sting/extract_dna feedback_add_details("changeling_powers","ED") return 1 -datum/action/changeling/sting/mute +/datum/action/changeling/sting/mute name = "Mute Sting" desc = "We silently sting a human, completely silencing them for a short time. Costs 20 chemicals." helptext = "Does not provide a warning to the victim that they have been stung, until they try to speak and cannot." @@ -147,7 +147,7 @@ datum/action/changeling/sting/mute feedback_add_details("changeling_powers","MS") return 1 -datum/action/changeling/sting/blind +/datum/action/changeling/sting/blind name = "Blind Sting" desc = "We temporarily blind our victim. Costs 25 chemicals." helptext = "This sting completely blinds a target for a short time, and leaves them with blurred vision for a long time." @@ -165,7 +165,7 @@ datum/action/changeling/sting/blind feedback_add_details("changeling_powers","BS") return 1 -datum/action/changeling/sting/LSD +/datum/action/changeling/sting/LSD name = "Hallucination Sting" desc = "We cause mass terror to our victim. Costs 10 chemicals." helptext = "We evolve the ability to sting a target with a powerful hallucinogenic chemical. The target does not notice they have been stung, and the effect occurs after 30 to 60 seconds." @@ -182,7 +182,7 @@ datum/action/changeling/sting/LSD feedback_add_details("changeling_powers","HS") return 1 -datum/action/changeling/sting/cryo //Enable when mob cooling is fixed so that frostoil actually makes you cold, instead of mostly just hungry. +/datum/action/changeling/sting/cryo //Enable when mob cooling is fixed so that frostoil actually makes you cold, instead of mostly just hungry. name = "Cryogenic Sting" desc = "We silently sting our victim with a cocktail of chemicals that freezes them from the inside. Costs 15 chemicals." helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing." diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm index c06913c1abe..17ae54591aa 100644 --- a/code/game/gamemodes/cult/cult_structures.dm +++ b/code/game/gamemodes/cult/cult_structures.dm @@ -270,14 +270,10 @@ GLOBAL_LIST_INIT(blacklisted_pylon_turfs, typecacheof(list( /obj/effect/gateway/singularity_pull() return -/obj/effect/gateway/Bumped(mob/M as mob|obj) - spawn(0) - return +/obj/effect/gateway/Bumped(atom/movable/AM) return -/obj/effect/gateway/Crossed(AM as mob|obj, oldloc) - spawn(0) - return +/obj/effect/gateway/Crossed(atom/movable/AM, oldloc) return diff --git a/code/game/gamemodes/devil/contracts/friend.dm b/code/game/gamemodes/devil/contracts/friend.dm index 7760ee10ee7..8838dc8a371 100644 --- a/code/game/gamemodes/devil/contracts/friend.dm +++ b/code/game/gamemodes/devil/contracts/friend.dm @@ -17,7 +17,8 @@ /obj/effect/mob_spawn/human/demonic_friend/Initialize(mapload, datum/mind/owner_mind, obj/effect/proc_holder/spell/targeted/summon_friend/summoning_spell) . = ..() owner = owner_mind - flavour_text = "You have been given a reprieve from your eternity of torment, to be [owner.name]'s friend for [owner.p_their()] short mortal coil. Be aware that if you do not live up to [owner.name]'s expectations, [owner.p_they()] can send you back to hell with a single thought. [owner.name]'s death will also return you to hell." + description = "Be someone's loyal friend/slave. If they die, you die as well." //best I could think of in the moment, not sure how this role plays in practise, have never seen it. + flavour_text = "You have been given a reprieve from your eternity of torment, to be [owner.name]'s friend for [owner.p_their()] short mortal coil. Be aware that if you do not live up to [owner.name]'s expectations, [owner.p_they()] can send you back to hell with a single thought. [owner.name]'s death will also return you to hell." var/area/A = get_area(src) if(!mapload && A) notify_ghosts("\A friendship shell has been completed in \the [A.name].", source = src, action=NOTIFY_ATTACK, flashwindow = TRUE) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 1e2dd3d554b..8757fa00d4f 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -337,7 +337,7 @@ ////////////////////////// //Reports player logouts// ////////////////////////// -proc/display_roundstart_logout_report() +/proc/display_roundstart_logout_report() var/msg = "Roundstart logout report\n\n" for(var/mob/living/L in GLOB.mob_list) @@ -507,7 +507,7 @@ proc/display_roundstart_logout_report() message_text += G.get_report() message_text += "
" - print_command_report(message_text, "[command_name()] Orders") + print_command_report(message_text, "[command_name()] Orders", FALSE) /datum/game_mode/proc/declare_station_goal_completion() for(var/V in station_goals) diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm index 142ae33c078..f95702e7f28 100644 --- a/code/game/gamemodes/heist/heist.dm +++ b/code/game/gamemodes/heist/heist.dm @@ -250,7 +250,7 @@ GLOBAL_LIST_EMPTY(cortical_stacks) //Stacks for 'leave nobody behind' objective. ..() -datum/game_mode/proc/auto_declare_completion_heist() +/datum/game_mode/proc/auto_declare_completion_heist() if(raiders.len) var/check_return = 0 if(GAMEMODE_IS_HEIST) diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm index 9f5db8d5dae..9ed2adf3332 100644 --- a/code/game/gamemodes/malfunction/Malf_Modules.dm +++ b/code/game/gamemodes/malfunction/Malf_Modules.dm @@ -679,7 +679,7 @@ for(var/thing in GLOB.apcs) var/obj/machinery/power/apc/apc if(prob(30 * apc.overload)) - apc.overload_lighting() + INVOKE_ASYNC(apc, /obj/machinery/power/apc.proc/overload_lighting) else apc.overload++ to_chat(owner, "Overcurrent applied to the powernet.") diff --git a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm index 8da5b4468d7..7fe146d3e47 100644 --- a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm +++ b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm @@ -19,15 +19,13 @@ mob_name = "a swarmer" death = FALSE roundstart = FALSE - flavour_text = {" - You are a swarmer, a weapon of a long dead civilization. Until further orders from your original masters are received, you must continue to consume and replicate. - Clicking on any object will try to consume it, either deconstructing it into its components, destroying it, or integrating any materials it has into you if successful. - Ctrl-Clicking on a mob will attempt to remove it from the area and place it in a safe environment for storage. - Objectives: + important_info = "Follow your objectives, do not make the station inhospitable or try and kill crew." + flavour_text = "You are a swarmer, a weapon of a long dead civilization. Until further orders from your original masters are received, you must continue to consume and replicate." + description = {" Your goal is to create more of yourself by consuming the station. Clicking on any object will try to consume it, either deconstructing it into its components, destroying it, or integrating any materials it has into you if successful. Ctrl-Clicking on a mob will attempt to remove it from the area and place it in a safe environment for storage. + Objectives: 1. Consume resources and replicate until there are no more resources left. 2. Ensure that this location is fit for invasion at a later date; do not perform actions that would render it dangerous or inhospitable. - 3. Biological resources will be harvested at a later date; do not harm them. - "} + 3. Biological resources will be harvested at a later date; do not harm them."} /obj/effect/mob_spawn/swarmer/Initialize(mapload) . = ..() diff --git a/code/game/gamemodes/miniantags/bot_swarm/swarmer_event.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer_event.dm index fbceda6bd94..5c4b83e965c 100644 --- a/code/game/gamemodes/miniantags/bot_swarm/swarmer_event.dm +++ b/code/game/gamemodes/miniantags/bot_swarm/swarmer_event.dm @@ -7,7 +7,7 @@ var/swarmer_report = "[command_name()] High-Priority Update" swarmer_report += "

Our long-range sensors have detected an odd signal emanating from your station's gateway. We recommend immediate investigation of your gateway, as something may have come \ through." - print_command_report(swarmer_report, "Classified [command_name()] Update") + print_command_report(swarmer_report, "Classified [command_name()] Update", FALSE) GLOB.event_announcement.Announce("A report has been downloaded and printed out at all communications consoles.", "Incoming Classified Message", 'sound/AI/commandreport.ogg') /datum/event/spawn_swarmer/start() diff --git a/code/game/gamemodes/miniantags/guardian/guardian.dm b/code/game/gamemodes/miniantags/guardian/guardian.dm index fdf17f6ddda..d063b742047 100644 --- a/code/game/gamemodes/miniantags/guardian/guardian.dm +++ b/code/game/gamemodes/miniantags/guardian/guardian.dm @@ -363,7 +363,7 @@ if("Protector") pickedtype = /mob/living/simple_animal/hostile/guardian/protector - var/mob/living/simple_animal/hostile/guardian/G = new pickedtype(user) + var/mob/living/simple_animal/hostile/guardian/G = new pickedtype(user, user) G.summoner = user G.summoned = TRUE G.key = key diff --git a/code/game/gamemodes/miniantags/guardian/types/lightning.dm b/code/game/gamemodes/miniantags/guardian/types/lightning.dm index bf84e199bab..2c716d5d4a4 100644 --- a/code/game/gamemodes/miniantags/guardian/types/lightning.dm +++ b/code/game/gamemodes/miniantags/guardian/types/lightning.dm @@ -3,12 +3,12 @@ layer = LYING_MOB_LAYER /mob/living/simple_animal/hostile/guardian/beam - melee_damage_lower = 7 - melee_damage_upper = 7 + melee_damage_lower = 12 + melee_damage_upper = 12 attacktext = "shocks" melee_damage_type = BURN attack_sound = 'sound/machines/defib_zap.ogg' - damage_transfer = 0.7 + damage_transfer = 0.6 range = 7 playstyle_string = "As a Lightning type, you will apply lightning chains to targets on attack and have a lightning chain to your summoner. Lightning chains will shock anyone near them." magic_fluff_string = "..And draw the Tesla, a shocking, lethal source of power." @@ -18,6 +18,17 @@ var/list/enemychains = list() var/successfulshocks = 0 +/mob/living/simple_animal/hostile/guardian/beam/New(loc, mob/living/user) + . = ..() + if(!user) + return + summoner = user + if(!(NO_SHOCK in summoner.mutations)) + summoner.mutations.Add(NO_SHOCK) + +/mob/living/simple_animal/hostile/guardian/beam/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = FALSE, override = FALSE, tesla_shock = FALSE, illusion = FALSE, stun = TRUE) + return FALSE //You are lightning, you should not be hurt by such things. + /mob/living/simple_animal/hostile/guardian/beam/AttackingTarget() . = ..() if(. && isliving(target) && target != src && target != summoner) @@ -106,3 +117,8 @@ ) L.adjustFireLoss(1.2) //adds up very rapidly . = 1 + +/mob/living/simple_animal/hostile/guardian/beam/death(gibbed) + if(summoner && (NO_SHOCK in summoner.mutations)) + summoner.mutations.Remove(NO_SHOCK) + return ..() diff --git a/code/game/gamemodes/miniantags/guardian/types/protector.dm b/code/game/gamemodes/miniantags/guardian/types/protector.dm index 534b7e16934..fda005a58ed 100644 --- a/code/game/gamemodes/miniantags/guardian/types/protector.dm +++ b/code/game/gamemodes/miniantags/guardian/types/protector.dm @@ -25,6 +25,7 @@ overlays.Cut() melee_damage_lower = initial(melee_damage_lower) melee_damage_upper = initial(melee_damage_upper) + obj_damage = initial(obj_damage) speed = initial(speed) damage_transfer = 0.4 to_chat(src, "You switch to combat mode.") @@ -35,6 +36,7 @@ overlays.Add(shield_overlay) melee_damage_lower = 2 melee_damage_upper = 2 + obj_damage = 6 //40/7.5 rounded up, we don't want a protector guardian 2 shotting blob tiles while taking 5% damage, thats just silly. speed = 1 damage_transfer = 0.05 //damage? what's damage? to_chat(src, "You switch to protection mode.") diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 8316364781b..7c87083dfe5 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -3,7 +3,7 @@ /datum/game_mode var/list/datum/mind/syndicates = list() -proc/issyndicate(mob/living/M as mob) +/proc/issyndicate(mob/living/M as mob) return istype(M) && M.mind && SSticker && SSticker.mode && (M.mind in SSticker.mode.syndicates) /datum/game_mode/nuclear @@ -103,7 +103,7 @@ proc/issyndicate(mob/living/M as mob) var/obj/effect/landmark/nuke_spawn = locate("landmark*Nuclear-Bomb") - var/nuke_code = "[rand(10000, 99999)]" + var/nuke_code = rand(10000, 99999) var/leader_selected = 0 var/agent_number = 1 var/spawnpos = 1 diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index c73293da519..209f9689de1 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -14,29 +14,29 @@ GLOBAL_VAR(bomb_set) icon_state = "nuclearbomb0" density = 1 resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF - var/deployable = 0 - var/extended = 0 - var/lighthack = 0 + var/extended = FALSE + var/lighthack = FALSE var/timeleft = 120 - var/timing = 0 + var/timing = FALSE + var/exploded = FALSE var/r_code = "ADMIN" - var/code = "" - var/yes_code = 0 - var/safety = 1 + var/code + var/yes_code = FALSE + var/safety = TRUE var/obj/item/disk/nuclear/auth = null var/removal_stage = NUKE_INTACT var/lastentered - var/is_syndicate = 0 + var/is_syndicate = FALSE use_power = NO_POWER_USE var/previous_level = "" var/datum/wires/nuclearbomb/wires = null /obj/machinery/nuclearbomb/syndicate - is_syndicate = 1 + is_syndicate = TRUE /obj/machinery/nuclearbomb/New() ..() - r_code = "[rand(10000, 99999.0)]"//Creates a random code upon object spawn. + r_code = rand(10000, 99999.0) // Creates a random code upon object spawn. wires = new/datum/wires/nuclearbomb(src) previous_level = get_security_level() GLOB.poi_list |= src @@ -49,25 +49,24 @@ GLOBAL_VAR(bomb_set) /obj/machinery/nuclearbomb/process() if(timing) - GLOB.bomb_set = 1 //So long as there is one nuke timing, it means one nuke is armed. + GLOB.bomb_set = TRUE // So long as there is one nuke timing, it means one nuke is armed. timeleft = max(timeleft - 2, 0) // 2 seconds per process() if(timeleft <= 0) INVOKE_ASYNC(src, .proc/explode) - SSnanoui.update_uis(src) return /obj/machinery/nuclearbomb/attackby(obj/item/O as obj, mob/user as mob, params) if(istype(O, /obj/item/disk/nuclear)) if(extended) if(!user.drop_item()) - to_chat(user, "\The [O] is stuck to your hand!") + to_chat(user, "[O] is stuck to your hand!") return O.forceMove(src) auth = O add_fingerprint(user) return attack_hand(user) else - to_chat(user, "You need to deploy \the [src] first. Right click on the sprite, select 'Make Deployable' then click on \the [src] with an empty hand.") + to_chat(user, "You need to deploy [src] first.") return return ..() @@ -171,181 +170,157 @@ GLOBAL_VAR(bomb_set) removal_stage = NUKE_SEALANT_OPEN /obj/machinery/nuclearbomb/attack_ghost(mob/user as mob) - if(extended) - attack_hand(user) + attack_hand(user) /obj/machinery/nuclearbomb/attack_hand(mob/user as mob) - if(extended) - if(panel_open) - wires.Interact(user) - else - ui_interact(user) - else if(deployable) - if(removal_stage != NUKE_MOBILE) - anchored = 1 - visible_message("With a steely snap, bolts slide out of [src] and anchor it to the flooring!") - else - visible_message("\The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") - if(!lighthack) - flick("nuclearbombc", src) - icon_state = "nuclearbomb1" - extended = 1 - return - -/obj/machinery/nuclearbomb/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "nuclear_bomb.tmpl", "Nuke Control Panel", 450, 550, state = GLOB.physical_state) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/nuclearbomb/ui_data(mob/user, datum/topic_state/state) - var/data[0] - data["is_syndicate"] = is_syndicate - data["hacking"] = 0 - data["auth"] = is_auth(user) - if(is_auth(user)) - if(yes_code) - data["authstatus"] = timing ? "Functional/Set" : "Functional" - else - data["authstatus"] = "Auth. S2" + if(panel_open) + wires.Interact(user) else - if(timing) - data["authstatus"] = "Set" - else - data["authstatus"] = "Auth. S1" + tgui_interact(user) + +/obj/machinery/nuclearbomb/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_physical_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "NuclearBomb", name, 450, 300, master_ui, state) + ui.open() + +/obj/machinery/nuclearbomb/tgui_data(mob/user) + var/list/data = list() + data["extended"] = extended + data["authdisk"] = is_auth(user) + data["diskname"] = auth ? auth.name : FALSE + data["authcode"] = yes_code + data["authfull"] = data["authdisk"] && data["authcode"] data["safe"] = safety ? "Safe" : "Engaged" data["time"] = timeleft data["timer"] = timing data["safety"] = safety data["anchored"] = anchored - data["yescode"] = yes_code - data["message"] = "AUTH" if(is_auth(user)) - data["message"] = code if(yes_code) - data["message"] = "*****" - - return data - -/obj/machinery/nuclearbomb/verb/make_deployable() - set category = "Object" - set name = "Make Deployable" - set src in oview(1) - - if(usr.stat || !usr.canmove || usr.restrained()) - return - - if(deployable) - to_chat(usr, "You close several panels to make [src] undeployable.") - deployable = 0 + data["codemsg"] = "CLEAR CODE" + else if(code) + data["codemsg"] = "RE-ENTER CODE" + else + data["codemsg"] = "ENTER CODE" else - to_chat(usr, "You adjust some panels to make [src] deployable.") - deployable = 1 - return + data["codemsg"] = "-----" + return data /obj/machinery/nuclearbomb/proc/is_auth(var/mob/user) if(auth) - return 1 + return TRUE else if(user.can_admin_interact()) - return 1 + return TRUE else - return 0 + return FALSE -/obj/machinery/nuclearbomb/Topic(href, href_list) +/obj/machinery/nuclearbomb/tgui_act(action, params) if(..()) - return 1 - - if(href_list["auth"]) - if(auth) - auth.loc = loc - yes_code = 0 - auth = null - else - var/obj/item/I = usr.get_active_hand() - if(istype(I, /obj/item/disk/nuclear)) - usr.drop_item() - I.loc = src - auth = I - if(is_auth(usr)) - if(href_list["type"]) - if(href_list["type"] == "E") + return + . = TRUE + if(exploded) + return + switch(action) + if("deploy") + if(removal_stage != NUKE_MOBILE) + anchored = TRUE + visible_message("With a steely snap, bolts slide out of [src] and anchor it to the flooring!") + else + visible_message("[src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") + if(!lighthack) + flick("nuclearbombc", src) + icon_state = "nuclearbomb1" + extended = TRUE + return + if("auth") + if(auth) + if(!usr.get_active_hand() && Adjacent(usr)) + usr.put_in_hands(auth) + else + auth.forceMove(get_turf(src)) + yes_code = FALSE + auth = null + else + var/obj/item/I = usr.get_active_hand() + if(istype(I, /obj/item/disk/nuclear)) + usr.drop_item() + I.forceMove(src) + auth = I + return + if(!is_auth(usr)) // All requests below here require NAD inserted. + return FALSE + switch(action) + if("code") + if(yes_code) // Clear code + code = null + yes_code = FALSE + return + // If no code set, enter new one + var/tempcode = input(usr, "Code", "Input Code", null) as num|null + if(tempcode) + code = min(max(round(tempcode), 0), 999999) if(code == r_code) - yes_code = 1 + yes_code = TRUE code = null else code = "ERROR" + return + + if(!yes_code) // All requests below here require both NAD inserted AND code correct + return + + switch(action) + if("toggle_anchor") + if(removal_stage == NUKE_MOBILE) + anchored = FALSE + visible_message("[src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") + else if(isinspace()) + to_chat(usr, "There is nothing to anchor to!") + return FALSE else - if(href_list["type"] == "R") - yes_code = 0 - code = null - else - lastentered = text("[]", href_list["type"]) - if(text2num(lastentered) == null) - var/turf/LOC = get_turf(usr) - message_admins("[key_name_admin(usr)] tried to exploit a nuclear bomb by entering non-numerical codes: [lastentered]! ([LOC ? "JMP" : "null"])", 0) - log_admin("EXPLOIT: [key_name(usr)] tried to exploit a nuclear bomb by entering non-numerical codes: [lastentered]!") - else - code += lastentered - if(length(code) > 5) - code = "ERROR" - if(yes_code) - if(href_list["time"]) - var/time = text2num(href_list["time"]) - timeleft += time - timeleft = min(max(round(src.timeleft), 120), 600) - if(href_list["timer"]) - if(timing == -1.0) - SSnanoui.update_uis(src) - return - if(safety) - to_chat(usr, "The safety is still on.") - SSnanoui.update_uis(src) - return - timing = !(timing) - if(timing) - if(!lighthack) - icon_state = "nuclearbomb2" - if(!safety) - message_admins("[key_name_admin(usr)] engaged a nuclear bomb (JMP)") - if(!is_syndicate) - set_security_level("delta") - GLOB.bomb_set = 1 //There can still be issues with this resetting when there are multiple bombs. Not a big deal though for Nuke/N - else - GLOB.bomb_set = 0 + anchored = !(anchored) + if(anchored) + visible_message("With a steely snap, bolts slide out of [src] and anchor it to the flooring.") else + visible_message("The anchoring bolts slide back into the depths of [src].") + return + if("set_time") + var/time = input(usr, "Detonation time (seconds, min 120, max 600)", "Input Time", 120) as num|null + if(time) + timeleft = min(max(round(time), 120), 600) + if("toggle_safety") + safety = !(safety) + if(safety) + if(!is_syndicate) + set_security_level(previous_level) + timing = FALSE + GLOB.bomb_set = FALSE + if("toggle_armed") + if(safety) + to_chat(usr, "The safety is still on.") + return + timing = !(timing) + if(timing) + if(!lighthack) + icon_state = "nuclearbomb2" + if(!safety) + message_admins("[key_name_admin(usr)] engaged a nuclear bomb [ADMIN_JMP(src)]") if(!is_syndicate) - set_security_level(previous_level) - GLOB.bomb_set = 0 - if(!lighthack) - icon_state = "nuclearbomb1" - if(href_list["safety"]) - safety = !(safety) - if(safety) - if(!is_syndicate) - set_security_level(previous_level) - timing = 0 - GLOB.bomb_set = 0 - if(href_list["anchor"]) - if(removal_stage == NUKE_MOBILE) - anchored = 0 - visible_message("\The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") - SSnanoui.update_uis(src) - return - - if(!isinspace()) - anchored = !(anchored) - if(anchored) - visible_message("With a steely snap, bolts slide out of [src] and anchor it to the flooring.") - else - visible_message("The anchoring bolts slide back into the depths of [src].") + set_security_level("delta") + GLOB.bomb_set = TRUE // There can still be issues with this resetting when there are multiple bombs. Not a big deal though for Nuke else - to_chat(usr, "There is nothing to anchor to!") + GLOB.bomb_set = TRUE + else + if(!is_syndicate) + set_security_level(previous_level) + GLOB.bomb_set = FALSE + if(!lighthack) + icon_state = "nuclearbomb1" - SSnanoui.update_uis(src) /obj/machinery/nuclearbomb/blob_act(obj/structure/blob/B) - if(timing == -1.0) + if(exploded) return if(timing) //boom INVOKE_ASYNC(src, .proc/explode) @@ -360,11 +335,11 @@ GLOBAL_VAR(bomb_set) #define NUKERANGE 80 /obj/machinery/nuclearbomb/proc/explode() if(safety) - timing = 0 + timing = FALSE return - timing = -1.0 - yes_code = 0 - safety = 1 + exploded = TRUE + yes_code = FALSE + safety = TRUE if(!lighthack) icon_state = "nuclearbomb3" playsound(src,'sound/machines/alarm.ogg',100,0,5) diff --git a/code/game/gamemodes/shadowling/shadowling_abilities.dm b/code/game/gamemodes/shadowling/shadowling_abilities.dm index 27267d2ec02..7692aa202b2 100644 --- a/code/game/gamemodes/shadowling/shadowling_abilities.dm +++ b/code/game/gamemodes/shadowling/shadowling_abilities.dm @@ -109,9 +109,10 @@ return to_chat(user, "You silently disable all nearby lights.") for(var/obj/structure/glowshroom/G in orange(2, user)) //Why the fuck was this in the loop below? - G.visible_message("\The [G] withers away!") + G.visible_message("[G] withers away!") qdel(G) for(var/turf/T in targets) + T.extinguish_light() for(var/atom/A in T.contents) A.extinguish_light() diff --git a/code/game/gamemodes/shadowling/special_shadowling_abilities.dm b/code/game/gamemodes/shadowling/special_shadowling_abilities.dm index 5fc5e1e78cc..83ca06fe4b7 100644 --- a/code/game/gamemodes/shadowling/special_shadowling_abilities.dm +++ b/code/game/gamemodes/shadowling/special_shadowling_abilities.dm @@ -163,7 +163,7 @@ GLOBAL_LIST_INIT(possibleShadowlingNames, list("U'ruan", "Y`shej", "Nex", "Hel-u to_chat(M, "An immense pressure slams you onto the ground!") for(var/thing in GLOB.apcs) var/obj/machinery/power/apc/A = thing - A.overload_lighting() + INVOKE_ASYNC(A, /obj/machinery/power/apc.proc/overload_lighting) var/mob/living/simple_animal/ascendant_shadowling/A = new /mob/living/simple_animal/ascendant_shadowling(H.loc) A.announce("VYSHA NERADA YEKHEZET U'RUU!!", 5, 'sound/hallucinations/veryfar_noise.ogg') for(var/obj/effect/proc_holder/spell/S in H.mind.spell_list) diff --git a/code/game/gamemodes/steal_items.dm b/code/game/gamemodes/steal_items.dm index 4175883fc1a..a20b0e1654b 100644 --- a/code/game/gamemodes/steal_items.dm +++ b/code/game/gamemodes/steal_items.dm @@ -57,7 +57,7 @@ typepath = /obj/item/aicard location_override = "AI Satellite. An intellicard for transportation can be found in Tech Storage, Science Department or manufactured" -datum/theft_objective/ai/check_special_completion(var/obj/item/aicard/C) +/datum/theft_objective/ai/check_special_completion(var/obj/item/aicard/C) if(..()) for(var/mob/living/silicon/ai/A in C) if(istype(A, /mob/living/silicon/ai) && A.stat != 2) //See if any AI's are alive inside that card. diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index c7ab4490f48..e7c5b4541a8 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -82,22 +82,10 @@ /datum/game_mode/proc/auto_declare_completion_traitor() if(traitors.len) - var/text = "The traitors were:" + var/text = "The traitors were:
" for(var/datum/mind/traitor in traitors) var/traitorwin = 1 - - text += "
[traitor.key] was [traitor.name] (" - if(traitor.current) - if(traitor.current.stat == DEAD) - text += "died" - else - text += "survived" - if(traitor.current.real_name != traitor.name) - text += " as [traitor.current.real_name]" - else - text += "body destroyed" - text += ")" - + text += printplayer(traitor) var/TC_uses = 0 var/uplink_true = 0 @@ -131,12 +119,20 @@ if(traitorwin) - text += "
The [special_role_text] was successful!" + text += "
The [special_role_text] was successful!
" feedback_add_details("traitor_success","SUCCESS") else - text += "
The [special_role_text] has failed!" + text += "
The [special_role_text] has failed!
" feedback_add_details("traitor_success","FAIL") + if(length(SSticker.mode.implanted)) + text += "

The mindslaves were:
" + for(var/datum/mind/mindslave in SSticker.mode.implanted) + text += printplayer(mindslave) + var/datum/mind/master_mind = SSticker.mode.implanted[mindslave] + var/mob/living/carbon/human/master = master_mind.current + text += " (slaved by: [master])
" + var/phrases = jointext(GLOB.syndicate_code_phrase, ", ") var/responses = jointext(GLOB.syndicate_code_response, ", ") diff --git a/code/game/gamemodes/vampire/vampire.dm b/code/game/gamemodes/vampire/vampire.dm index 3caf860383d..75748448527 100644 --- a/code/game/gamemodes/vampire/vampire.dm +++ b/code/game/gamemodes/vampire/vampire.dm @@ -279,6 +279,7 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha var/blood = 0 var/old_bloodtotal = 0 //used to see if we increased our blood total var/old_bloodusable = 0 //used to see if we increased our blood usable + var/blood_volume_warning = 9999 //Blood volume threshold for warnings if(owner.is_muzzled()) to_chat(owner, "[owner.wear_mask] prevents you from biting [H]!") draining = null @@ -291,13 +292,10 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha H.LAssailant = owner while(do_mob(owner, H, 50)) if(!(owner.mind in SSticker.mode.vampires)) - to_chat(owner, "Your fangs have disappeared!") + to_chat(owner, "Your fangs have disappeared!") return old_bloodtotal = bloodtotal old_bloodusable = bloodusable - if(!H.blood_volume) - to_chat(owner, "They've got no blood left to give.") - break if(H.stat < DEAD) if(H.ckey || H.player_ghosted) //Requires ckey regardless if monkey or humanoid, or the body has been ghosted before it died blood = min(20, H.blood_volume) // if they have less than 20 blood, give them the remnant else they get 20 blood @@ -312,6 +310,17 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha to_chat(owner, "You have accumulated [bloodtotal] [bloodtotal > 1 ? "units" : "unit"] of blood[bloodusable != old_bloodusable ? ", and have [bloodusable] left to use" : ""].") check_vampire_upgrade() H.blood_volume = max(H.blood_volume - 25, 0) + //Blood level warnings (Code 'borrowed' from Fulp) + if(H.blood_volume) + if(H.blood_volume <= BLOOD_VOLUME_BAD && blood_volume_warning > BLOOD_VOLUME_BAD) + to_chat(owner, "Your victim's blood volume is dangerously low.") + else if(H.blood_volume <= BLOOD_VOLUME_OKAY && blood_volume_warning > BLOOD_VOLUME_OKAY) + to_chat(owner, "Your victim's blood is at an unsafe level.") + blood_volume_warning = H.blood_volume //Set to blood volume, so that you only get the message once + else + to_chat(owner, "You have bled your victim dry!") + break + if(ishuman(owner)) var/mob/living/carbon/human/V = owner if(!H.ckey && !H.player_ghosted)//Only runs if there is no ckey and the body has not being ghosted while alive diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm index 44dec855f82..442e9958fc7 100644 --- a/code/game/gamemodes/wizard/artefact.dm +++ b/code/game/gamemodes/wizard/artefact.dm @@ -836,6 +836,10 @@ GLOBAL_LIST_EMPTY(multiverse) var/wgw = sanitize(input(user, "What would you like the victim to say", "Voodoo", null) as text) target.say(wgw) log_game("[user][user.key] made [target][target.key] say [wgw] with a voodoo doll.") + log_say("Wicker doll say to [target][target.key]: [wgw]", user) + log_admin("[user][user.key] made [target][target.key] say [wgw] with a voodoo doll.") + user.create_log(SAY_LOG, "forced [target] to say [wgw] through [src].", target) + target.create_log(SAY_LOG, "was forced to say [wgw] through [src] by [user].", user) if("eyes") user.set_machine(src) user.reset_perspective(target) diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm index a0bb4c349af..77972b00880 100644 --- a/code/game/gamemodes/wizard/wizard.dm +++ b/code/game/gamemodes/wizard/wizard.dm @@ -45,9 +45,8 @@ for(var/datum/mind/wizard in wizards) log_game("[key_name(wizard)] has been selected as a Wizard") forge_wizard_objectives(wizard) - //learn_basic_spells(wizard.current) equip_wizard(wizard.current) - name_wizard(wizard.current) + INVOKE_ASYNC(src, .proc/name_wizard, wizard.current) greet_wizard(wizard) if(use_huds) update_wiz_icons_added(wizard) @@ -89,17 +88,15 @@ var/wizard_name_first = pick(GLOB.wizard_first) var/wizard_name_second = pick(GLOB.wizard_second) var/randomname = "[wizard_name_first] [wizard_name_second]" - spawn(0) - var/newname = sanitize(copytext(input(wizard_mob, "You are the Space Wizard. Would you like to change your name to something else?", "Name change", randomname) as null|text,1,MAX_NAME_LEN)) + var/newname = sanitize(copytext(input(wizard_mob, "You are the Space Wizard. Would you like to change your name to something else?", "Name change", randomname) as null|text,1,MAX_NAME_LEN)) - if(!newname) - newname = randomname + if(!newname) + newname = randomname - wizard_mob.real_name = newname - wizard_mob.name = newname - if(wizard_mob.mind) - wizard_mob.mind.name = newname - return + wizard_mob.real_name = newname + wizard_mob.name = newname + if(wizard_mob.mind) + wizard_mob.mind.name = newname /datum/game_mode/proc/greet_wizard(var/datum/mind/wizard, var/you_are=1) addtimer(CALLBACK(wizard.current, /mob/.proc/playsound_local, null, 'sound/ambience/antag/ragesmages.ogg', 100, 0), 30) diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm index 48ac91c72fa..ac533f0b7ef 100644 --- a/code/game/jobs/access.dm +++ b/code/game/jobs/access.dm @@ -426,6 +426,7 @@ //gets the alt title, failing that the actual job rank //this is unused +// THEN WHY IS IT STILL HERE?? -AA07, 2020-07-31 /obj/proc/sdsdsd() //GetJobDisplayName if(!istype(src, /obj/item/pda) && !istype(src,/obj/item/card/id)) return @@ -442,7 +443,7 @@ return "Unknown" -proc/GetIdCard(var/mob/living/carbon/human/H) +/proc/GetIdCard(var/mob/living/carbon/human/H) if(H.wear_id) var/id = H.wear_id.GetID() if(id) @@ -451,7 +452,7 @@ proc/GetIdCard(var/mob/living/carbon/human/H) var/obj/item/I = H.get_active_hand() return I.GetID() -proc/FindNameFromID(var/mob/living/carbon/human/H) +/proc/FindNameFromID(var/mob/living/carbon/human/H) ASSERT(istype(H)) var/obj/item/card/id/C = H.get_active_hand() if( istype(C) || istype(C, /obj/item/pda) ) @@ -480,7 +481,7 @@ proc/FindNameFromID(var/mob/living/carbon/human/H) if(ID) return ID.registered_name -proc/get_all_job_icons() //For all existing HUD icons +/proc/get_all_job_icons() //For all existing HUD icons return GLOB.joblist + list("Prisoner") /obj/proc/GetJobName() //Used in secHUD icon generation @@ -511,7 +512,7 @@ proc/get_all_job_icons() //For all existing HUD icons return "Unknown" //Return unknown if none of the above apply -proc/get_accesslist_static_data(num_min_region = REGION_GENERAL, num_max_region = REGION_COMMAND) +/proc/get_accesslist_static_data(num_min_region = REGION_GENERAL, num_max_region = REGION_COMMAND) var/list/retval for(var/i in num_min_region to num_max_region) var/list/accesses = list() diff --git a/code/game/jobs/job/engineering.dm b/code/game/jobs/job/engineering.dm index 84f903dd2b1..a3333e1dc82 100644 --- a/code/game/jobs/job/engineering.dm +++ b/code/game/jobs/job/engineering.dm @@ -18,7 +18,7 @@ ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS, ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINISAT, ACCESS_MECHANIC, ACCESS_MINERAL_STOREROOM) minimal_player_age = 21 - exp_requirements = 300 + exp_requirements = 1200 exp_type = EXP_TYPE_ENGINEERING outfit = /datum/outfit/job/chief_engineer diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm index 2d1b091a10d..b1b81e0b849 100644 --- a/code/game/jobs/job/medical.dm +++ b/code/game/jobs/job/medical.dm @@ -16,7 +16,7 @@ ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_PSYCHIATRIST, ACCESS_MAINT_TUNNELS, ACCESS_PARAMEDIC, ACCESS_MINERAL_STOREROOM) minimal_player_age = 21 - exp_requirements = 300 + exp_requirements = 1200 exp_type = EXP_TYPE_MEDICAL outfit = /datum/outfit/job/cmo diff --git a/code/game/jobs/job/science.dm b/code/game/jobs/job/science.dm index 684de933832..f6fdb02477b 100644 --- a/code/game/jobs/job/science.dm +++ b/code/game/jobs/job/science.dm @@ -18,7 +18,7 @@ ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_GATEWAY, ACCESS_XENOARCH, ACCESS_MINISAT, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM, ACCESS_NETWORK) minimal_player_age = 21 - exp_requirements = 300 + exp_requirements = 1200 exp_type = EXP_TYPE_SCIENCE // All science-y guys get bonuses for maxing out their tech. required_objectives = list( diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm index a32656598df..6f4eb3759de 100644 --- a/code/game/jobs/job/security.dm +++ b/code/game/jobs/job/security.dm @@ -18,7 +18,7 @@ ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING, ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_GATEWAY, ACCESS_PILOT, ACCESS_WEAPONS) minimal_player_age = 21 - exp_requirements = 300 + exp_requirements = 1200 exp_type = EXP_TYPE_SECURITY disabilities_allowed = 0 outfit = /datum/outfit/job/hos @@ -64,7 +64,7 @@ minimal_access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_WEAPONS) minimal_player_age = 21 exp_requirements = 600 - exp_type = EXP_TYPE_CREW + exp_type = EXP_TYPE_SECURITY outfit = /datum/outfit/job/warden /datum/outfit/job/warden diff --git a/code/game/jobs/job/supervisor.dm b/code/game/jobs/job/supervisor.dm index 1d627f131b2..55ae7f4b3ae 100644 --- a/code/game/jobs/job/supervisor.dm +++ b/code/game/jobs/job/supervisor.dm @@ -13,7 +13,7 @@ GLOBAL_DATUM_INIT(captain_announcement, /datum/announcement/minor, new(do_newsca access = list() //See get_access() minimal_access = list() //See get_access() minimal_player_age = 30 - exp_requirements = 300 + exp_requirements = 1200 exp_type = EXP_TYPE_COMMAND disabilities_allowed = 0 outfit = /datum/outfit/job/captain @@ -67,7 +67,7 @@ GLOBAL_DATUM_INIT(captain_announcement, /datum/announcement/minor, new(do_newsca req_admin_notify = 1 is_command = 1 minimal_player_age = 21 - exp_requirements = 300 + exp_requirements = 1200 exp_type = EXP_TYPE_COMMAND access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_FORENSICS_LOCKERS, ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS, diff --git a/code/game/jobs/job/support.dm b/code/game/jobs/job/support.dm index 09328865b59..fda831242f9 100644 --- a/code/game/jobs/job/support.dm +++ b/code/game/jobs/job/support.dm @@ -458,6 +458,7 @@ total_positions = 0 spawn_positions = 0 supervisors = "the head of personnel" + department_head = list("Head of Personnel") selection_color = "#dddddd" access = list(ACCESS_MAINT_TUNNELS, ACCESS_GATEWAY, ACCESS_EVA, ACCESS_EXTERNAL_AIRLOCKS) minimal_access = list(ACCESS_MAINT_TUNNELS, ACCESS_GATEWAY, ACCESS_EVA, ACCESS_EXTERNAL_AIRLOCKS) diff --git a/code/game/jobs/jobs.dm b/code/game/jobs/jobs.dm index 81cc54aa3c3..2f8e426e030 100644 --- a/code/game/jobs/jobs.dm +++ b/code/game/jobs/jobs.dm @@ -69,7 +69,7 @@ GLOBAL_LIST_INIT(supply_positions, list( "Shaft Miner" )) -GLOBAL_LIST_INIT(service_positions, (support_positions - supply_positions + list("Head of Personnel"))) +GLOBAL_LIST_INIT(service_positions, (list("Head of Personnel") + (support_positions - supply_positions))) GLOBAL_LIST_INIT(security_positions, list( diff --git a/code/game/machinery/Freezer.dm b/code/game/machinery/Freezer.dm index d9243005ead..a2a69fad357 100644 --- a/code/game/machinery/Freezer.dm +++ b/code/game/machinery/Freezer.dm @@ -104,59 +104,46 @@ to_chat(user, "Close the maintenance panel first.") return - src.ui_interact(user) + tgui_interact(user) -/obj/machinery/atmospherics/unary/cold_sink/freezer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/atmospherics/unary/cold_sink/freezer/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "freezer.tmpl", "Gas Cooling System", 540, 300) - // open the new ui window + ui = new(user, src, ui_key, "GasFreezer", "Gas Cooling System", 540, 200) ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) -/obj/machinery/atmospherics/unary/cold_sink/freezer/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - data["on"] = on ? 1 : 0 - data["gasPressure"] = round(air_contents.return_pressure()) - data["gasTemperature"] = round(air_contents.temperature) - data["gasTemperatureCelsius"] = round(air_contents.temperature - T0C,1) +/obj/machinery/atmospherics/unary/cold_sink/freezer/tgui_data(mob/user) + var/list/data = list() + data["on"] = on + data["pressure"] = round(air_contents.return_pressure()) + data["temperature"] = round(air_contents.temperature) + data["temperatureCelsius"] = round(air_contents.temperature - T0C, 1) if(air_contents.total_moles() == 0 && air_contents.temperature == 0) - data["gasTemperatureCelsius"] = 0 - data["minGasTemperature"] = round(min_temperature) - data["maxGasTemperature"] = round(T20C) - data["targetGasTemperature"] = round(current_temperature) - data["targetGasTemperatureCelsius"] = round(current_temperature - T0C,1) - - var/temp_class = "good" - if(air_contents.temperature > (T0C - 20)) - temp_class = "bad" - else if(air_contents.temperature < (T0C - 20) && air_contents.temperature > (T0C - 100)) - temp_class = "average" - data["gasTemperatureClass"] = temp_class + data["temperatureCelsius"] = 0 + data["min"] = round(min_temperature) + data["max"] = round(T20C) + data["target"] = round(current_temperature) + data["targetCelsius"] = round(current_temperature - T0C, 1) return data -/obj/machinery/atmospherics/unary/cold_sink/freezer/Topic(href, href_list) +/obj/machinery/atmospherics/unary/cold_sink/freezer/tgui_act(action, params) if(..()) - return 1 - if(href_list["toggleStatus"]) - src.on = !src.on - update_icon() - else if(href_list["minimum"]) - current_temperature = min_temperature - else if(href_list["maximum"]) - current_temperature = T20C - else if(href_list["temp"]) - var/amount = text2num(href_list["temp"]) - if(amount > 0) - src.current_temperature = min(T20C, src.current_temperature+amount) - else - src.current_temperature = max(min_temperature, src.current_temperature+amount) - src.add_fingerprint(usr) - return 1 + return + add_fingerprint(usr) + . = TRUE + + switch(action) + if("power") + on = !on + update_icon() + if("minimum") + current_temperature = min_temperature + if("maximum") + current_temperature = T20C + if("temp") + var/amount = params["temp"] + amount = text2num(amount) + current_temperature = clamp(amount, T20C, min_temperature) /obj/machinery/atmospherics/unary/cold_sink/freezer/power_change() ..() @@ -273,57 +260,46 @@ if(panel_open) to_chat(user, "Close the maintenance panel first.") return - src.ui_interact(user) + tgui_interact(user) -/obj/machinery/atmospherics/unary/heat_reservoir/heater/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/atmospherics/unary/heat_reservoir/heater/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "freezer.tmpl", "Gas Heating System", 540, 300) - // open the new ui window + ui = new(user, src, ui_key, "GasFreezer", "Gas Heating System", 540, 200) ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) -/obj/machinery/atmospherics/unary/heat_reservoir/heater/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - data["on"] = on ? 1 : 0 - data["gasPressure"] = round(air_contents.return_pressure()) - data["gasTemperature"] = round(air_contents.temperature) - data["gasTemperatureCelsius"] = round(air_contents.temperature - T0C,1) +/obj/machinery/atmospherics/unary/heat_reservoir/heater/tgui_data(mob/user) + var/list/data = list() + data["on"] = on + data["pressure"] = round(air_contents.return_pressure()) + data["temperature"] = round(air_contents.temperature) + data["temperatureCelsius"] = round(air_contents.temperature - T0C, 1) if(air_contents.total_moles() == 0 && air_contents.temperature == 0) - data["gasTemperatureCelsius"] = 0 - data["minGasTemperature"] = round(T20C) - data["maxGasTemperature"] = round(T20C+max_temperature) - data["targetGasTemperature"] = round(current_temperature) - data["targetGasTemperatureCelsius"] = round(current_temperature - T0C,1) - - var/temp_class = "normal" - if(air_contents.temperature > (T20C+40)) - temp_class = "bad" - data["gasTemperatureClass"] = temp_class + data["temperatureCelsius"] = 0 + data["min"] = round(T20C) + data["max"] = round(T20C + max_temperature) + data["target"] = round(current_temperature) + data["targetCelsius"] = round(current_temperature - T0C, 1) return data -/obj/machinery/atmospherics/unary/heat_reservoir/heater/Topic(href, href_list) +/obj/machinery/atmospherics/unary/heat_reservoir/heater/tgui_act(action, params) if(..()) - return 1 - if(href_list["toggleStatus"]) - src.on = !src.on - update_icon() - else if(href_list["minimum"]) - current_temperature = T20C - else if(href_list["maximum"]) - current_temperature = max_temperature + T20C - else if(href_list["temp"]) - var/amount = text2num(href_list["temp"]) - if(amount > 0) - src.current_temperature = min((T20C+max_temperature), src.current_temperature+amount) - else - src.current_temperature = max(T20C, src.current_temperature+amount) - src.add_fingerprint(usr) - return 1 + return + add_fingerprint(usr) + . = TRUE + + switch(action) + if("power") + on = !on + update_icon() + if("minimum") + current_temperature = T20C + if("maximum") + current_temperature = max_temperature + T20C + if("temp") + var/amount = params["temp"] + amount = text2num(amount) + current_temperature = clamp(amount, T20C, T20C + max_temperature) /obj/machinery/atmospherics/unary/heat_reservoir/heater/power_change() ..() diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm index 3c09da548f5..ea273850d90 100644 --- a/code/game/machinery/atmoalter/canister.dm +++ b/code/game/machinery/atmoalter/canister.dm @@ -353,7 +353,7 @@ update_flag if(valve_open) logmsg = "Valve was opened by [key_name(usr)], starting a transfer into the [holding || "air"].
" if(!holding) - logmsg = "Valve was opened by [key_name(usr)], starting a transfer into the [holding || "air"].
" + logmsg = "Valve was opened by [key_name(usr)], starting a transfer into the air.
" if(air_contents.toxins > 0) message_admins("[key_name_admin(usr)] opened a canister that contains plasma in [get_area(src)]! (JMP)") log_admin("[key_name(usr)] opened a canister that contains plasma at [get_area(src)]: [x], [y], [z]") @@ -367,8 +367,9 @@ update_flag if("eject") if(holding) if(valve_open) + if(air_contents && (air_contents.toxins > 0 || air_contents.sleeping_agent > 0)) + message_admins("[ADMIN_LOOKUPFLW(usr)] removed [holding] from [src] with valve still open at [ADMIN_VERBOSEJMP(src)] releasing contents into the air.") release_log += "[key_name(usr)] removed the [holding], leaving the valve open and transferring into the air
" - message_admins("[ADMIN_LOOKUPFLW(usr)] removed [holding] from [src] with valve still open at [ADMIN_VERBOSEJMP(src)] releasing contents into the air.") investigate_log("[key_name(usr)] removed the [holding], leaving the valve open and transferring into the air.", "atmos") replace_tank(usr, FALSE) if("recolor") diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 5c1b84d8cba..3fffc598334 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -24,7 +24,7 @@ use_power = IDLE_POWER_USE idle_power_usage = 10 active_power_usage = 100 - var/busy = 0 + var/busy = FALSE var/prod_coeff var/datum/wires/autolathe/wires = null @@ -33,7 +33,7 @@ var/list/datum/design/matching_designs var/temp_search var/selected_category - var/screen = 1 + var/list/recipiecache = list() var/list/categories = list("Tools", "Electronics", "Construction", "Communication", "Security", "Machinery", "Medical", "Miscellaneous", "Dinnerware", "Imported") @@ -79,63 +79,121 @@ if(panel_open) wires.Interact(user) else - ui_interact(user) + tgui_interact(user) -/obj/machinery/autolathe/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/autolathe/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "autolathe.tmpl", name, 800, 550) + ui = new(user, src, ui_key, "Autolathe", name, 750, 700, master_ui, state) ui.open() -/obj/machinery/autolathe/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) + +/obj/machinery/autolathe/tgui_static_data(mob/user) + var/list/data = list() + data["categories"] = categories + if(!recipiecache.len) + var/list/recipes = list() + for(var/v in files.known_designs) + var/datum/design/D = files.known_designs[v] + var/list/cost_list = design_cost_data(D) + var/list/matreq = list() + for(var/list/x in cost_list) + if(!x["amount"]) + continue + if(x["name"] == "metal") // Do not use MAT_METAL or MAT_GLASS here. + matreq["metal"] = x["amount"] + if(x["name"] == "glass") + matreq["glass"] = x["amount"] + var/obj/item/I = D.build_path + var/maxmult = 1 + if(ispath(D.build_path, /obj/item/stack)) + maxmult = D.maxstack + recipes.Add(list(list( + "name" = D.name, + "category" = D.category, + "uid" = D.UID(), + "requirements" = matreq, + "hacked" = ("hacked" in D.category) ? TRUE : FALSE, + "max_multiplier" = maxmult, + "image" = "[icon2base64(icon(initial(I.icon), initial(I.icon_state), SOUTH, 1))]" + ))) + recipiecache = recipes + data["recipes"] = recipiecache + return data + +/obj/machinery/autolathe/tgui_data(mob/user) + var/list/data = list() //..() var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - var/data[0] - data["screen"] = screen data["total_amount"] = materials.total_amount data["max_amount"] = materials.max_amount + data["fill_percent"] = round((materials.total_amount / materials.max_amount) * 100) 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) + data["busyname"] = FALSE + data["busyamt"] = 1 + if(length(being_built) > 0) + var/datum/design/D = being_built[1] + data["busyname"] = istype(D) && D.name ? D.name : FALSE + data["busyamt"] = length(being_built) > 1 ? being_built[2] : 1 + data["showhacked"] = hacked ? TRUE : FALSE + data["buildQueue"] = queue + data["buildQueueLen"] = queue.len return data +/obj/machinery/autolathe/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state) + if(..()) + return FALSE + + add_fingerprint(usr) + + . = TRUE + switch(action) + if("clear_queue") + queue = list() + if("remove_from_queue") + var/index = text2num(params["remove_from_queue"]) + if(isnum(index) && ISINRANGE(index, 1, queue.len)) + remove_from_queue(index) + to_chat(usr, "Removed item from queue.") + if("make") + BuildTurf = loc + var/datum/design/design_last_ordered + design_last_ordered = locateUID(params["make"]) + if(!istype(design_last_ordered)) + to_chat(usr, "Invalid design") + return + if(!(design_last_ordered.build_type & AUTOLATHE)) + to_chat(usr, "Invalid design (not buildable in autolathe, report this error.)") + return + var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) + if(design_last_ordered.materials["$metal"] > materials.amount(MAT_METAL)) + to_chat(usr, "Invalid design (not enough metal)") + return + if(design_last_ordered.materials["$glass"] > materials.amount(MAT_GLASS)) + to_chat(usr, "Invalid design (not enough glass)") + return + if(!hacked && ("hacked" in design_last_ordered.category)) + to_chat(usr, "Invalid design (lathe requires hacking)") + return + //multiplier checks : only stacks can have one and its value is 1, 10 ,25 or max_multiplier + var/multiplier = text2num(params["multiplier"]) + var/max_multiplier = min(design_last_ordered.maxstack, design_last_ordered.materials[MAT_METAL] ?round(materials.amount(MAT_METAL)/design_last_ordered.materials[MAT_METAL]):INFINITY,design_last_ordered.materials[MAT_GLASS]?round(materials.amount(MAT_GLASS)/design_last_ordered.materials[MAT_GLASS]):INFINITY) + var/is_stack = ispath(design_last_ordered.build_path, /obj/item/stack) + + if(!is_stack && (multiplier > 1)) + return + if(!(multiplier in list(1, 10, 25, max_multiplier))) //"enough materials ?" is checked in the build proc + message_admins("Player [key_name_admin(usr)] attempted to pass invalid multiplier [multiplier] to an autolathe in tgui_act. Possible href exploit.") + return + if((queue.len + 1) < queue_max_len) + add_to_queue(design_last_ordered, multiplier) + else + to_chat(usr, "The autolathe queue is full!") + if(!busy) + busy = TRUE + process_queue() + busy = FALSE + /obj/machinery/autolathe/proc/design_cost_data(datum/design/D) var/list/data = list() var/coeff = get_coeff(D) @@ -185,14 +243,21 @@ if(istype(O, /obj/item/disk/design_disk)) var/obj/item/disk/design_disk/D = O if(D.blueprint) + if(!(D.blueprint.build_type & AUTOLATHE)) // otherwise, would silently fail in AddDesign2Known + to_chat(user, "This design is not compatible with the autolathe.") + return 1 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) - busy = 1 + busy = TRUE if(do_after(user, 14.4, target = src)) + if(!("Imported" in D.blueprint.category)) // R&D should always ensure this is set on design disks, but it doesn't. + D.blueprint.category += "Imported" // now it will actually show up in the list. files.AddDesign2Known(D.blueprint) - busy = 0 + recipiecache = list() + SStgui.close_uis(src) // forces all connected users to re-open the TGUI. Imported entries won't show otherwise due to static_data + busy = FALSE else to_chat(user, "That disk does not have a design on it!") return 1 @@ -222,7 +287,6 @@ to_chat(user, "The autolathe is busy. Please wait for completion of previous operation.") return if(default_deconstruction_screwdriver(user, "autolathe_t", "autolathe", I)) - SSnanoui.update_uis(src) I.play_tool_sound(user, I.tool_volume) /obj/machinery/autolathe/wirecutter_act(mob/user, obj/item/I) @@ -254,7 +318,7 @@ if(MAT_GLASS) flick("autolathe_r", src)//plays glass insertion animation use_power(min(1000, amount_inserted / 100)) - SSnanoui.update_uis(src) + SStgui.update_uis(src) /obj/machinery/autolathe/attack_ghost(mob/user) interact(user) @@ -264,79 +328,6 @@ return interact(user) -/obj/machinery/autolathe/Topic(href, href_list) - if(..()) - return 1 - - if(href_list["menu"]) - screen = text2num(href_list["menu"]) - - if(href_list["category"]) - selected_category = href_list["category"] - screen = AUTOLATHE_CATEGORY_MENU - - if(href_list["make"]) - BuildTurf = loc - - ///////////////// - //href protection - var/datum/design/design_last_ordered - design_last_ordered = files.FindDesignByID(href_list["make"]) //check if it's a valid design - if(!design_last_ordered) - return - if(!(design_last_ordered.build_type & AUTOLATHE)) - return - - //multiplier checks : only stacks can have one and its value is 1, 10 ,25 or max_multiplier - var/multiplier = text2num(href_list["multiplier"]) - var/datum/component/material_container/materials = GetComponent(/datum/component/material_container) - var/max_multiplier = min(design_last_ordered.maxstack, design_last_ordered.materials[MAT_METAL] ?round(materials.amount(MAT_METAL)/design_last_ordered.materials[MAT_METAL]):INFINITY,design_last_ordered.materials[MAT_GLASS]?round(materials.amount(MAT_GLASS)/design_last_ordered.materials[MAT_GLASS]):INFINITY) - var/is_stack = ispath(design_last_ordered.build_path, /obj/item/stack) - - if(!is_stack && (multiplier > 1)) - return - if(!(multiplier in list(1, 10, 25, max_multiplier))) //"enough materials ?" is checked in the build proc - return - ///////////////// - - if((queue.len + 1) < queue_max_len) - add_to_queue(design_last_ordered,multiplier) - else - to_chat(usr, "The autolathe queue is full!") - if(!busy) - busy = 1 - process_queue() - busy = 0 - - if(href_list["remove_from_queue"]) - var/index = text2num(href_list["remove_from_queue"]) - 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)) - 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, temp_search)) - matching_designs.Add(D) - - screen = AUTOLATHE_SEARCH_MENU - - SSnanoui.update_uis(src) - return 1 - /obj/machinery/autolathe/RefreshParts() var/tot_rating = 0 prod_coeff = 0 @@ -371,7 +362,7 @@ else var/list/materials_used = list(MAT_METAL=metal_cost/coeff, MAT_GLASS=glass_cost/coeff) materials.use_amount(materials_used) - SSnanoui.update_uis(src) + SStgui.update_uis(src) sleep(32/coeff) if(is_stack) var/obj/item/stack/S = new D.build_path(BuildTurf) @@ -380,7 +371,7 @@ var/obj/item/new_item = new D.build_path(BuildTurf) new_item.materials[MAT_METAL] /= coeff new_item.materials[MAT_GLASS] /= coeff - SSnanoui.update_uis(src) + SStgui.update_uis(src) desc = initial(desc) /obj/machinery/autolathe/proc/can_build(datum/design/D, multiplier = 1, custom_metal, custom_glass) @@ -455,7 +446,6 @@ D = listgetindex(listgetindex(queue, 1),1) multiplier = listgetindex(listgetindex(queue,1),2) being_built = new /list() - //visible_message("[bicon(src)] \The [src] beeps, \"Queue processing finished successfully.\"") /obj/machinery/autolathe/proc/adjust_hacked(hack) hacked = hack @@ -468,6 +458,8 @@ for(var/datum/design/D in files.known_designs) if("hacked" in D.category) files.known_designs -= D.id + SStgui.close_uis(src) // forces all connected users to re-open the TGUI, thus adding/removing hacked entries from lists + recipiecache = list() /obj/machinery/autolathe/proc/check_hacked_callback() if(!wires.is_cut(WIRE_AUTOLATHE_HACK)) diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm index 44b55ed1d2c..57554d92867 100644 --- a/code/game/machinery/computer/ai_core.dm +++ b/code/game/machinery/computer/ai_core.dm @@ -288,7 +288,7 @@ That prevents a few funky behaviors. //The type of interaction, the player performing the operation, the AI itself, and the card object, if any. -atom/proc/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card) +/atom/proc/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card) if(istype(card)) if(card.flush) to_chat(user, "ERROR: AI flush is in progress, cannot execute transfer protocol.") diff --git a/code/game/machinery/computer/aifixer.dm b/code/game/machinery/computer/aifixer.dm index 0d715fe5759..38ec50abc6e 100644 --- a/code/game/machinery/computer/aifixer.dm +++ b/code/game/machinery/computer/aifixer.dm @@ -22,23 +22,22 @@ return ..() /obj/machinery/computer/aifixer/attack_ai(var/mob/user as mob) - ui_interact(user) + tgui_interact(user) /obj/machinery/computer/aifixer/attack_hand(var/mob/user as mob) - ui_interact(user) + tgui_interact(user) -/obj/machinery/computer/aifixer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/aifixer/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "ai_fixer.tmpl", "AI System Integrity Restorer", 550, 500) + ui = new(user, src, ui_key, "AIFixer", name, 550, 500, master_ui, state) ui.open() - ui.set_auto_update(1) -/obj/machinery/computer/aifixer/ui_data(mob/user, datum/topic_state/state) +/obj/machinery/computer/aifixer/tgui_data(mob/user, datum/topic_state/state) var/data[0] + data["occupant"] = (occupant ? occupant.name : null) // a null occupant isn't passed on if this is below the if. if(occupant) - data["occupant"] = occupant.name data["reference"] = "\ref[occupant]" data["integrity"] = (occupant.health+100)/2 data["stat"] = occupant.stat @@ -48,45 +47,49 @@ var/laws[0] for(var/datum/ai_law/law in occupant.laws.all_laws()) - laws.Add(list(list("law" = law.law, "number" = law.get_index()))) - + if(law in occupant.laws.ion_laws) // If we're an ion law, give it an ion index code + laws.Add(ionnum() + ". " + law.law) + else + laws.Add(num2text(law.get_index()) + ". " + law.law) data["laws"] = laws + data["has_laws"] = length(laws) return data -/obj/machinery/computer/aifixer/Topic(href, href_list) +/obj/machinery/computer/aifixer/tgui_act(action, params) if(..()) - return 1 + return + switch(action) + if("fix") + if(active) // Prevent from starting a fix while fixing. + to_chat(usr, "You are already fixing this AI!") + return + active = TRUE + INVOKE_ASYNC(src, .proc/fix_ai) + add_fingerprint(usr) - if(href_list["fix"]) - active = 1 - while(occupant.health < 100) - occupant.adjustOxyLoss(-1, FALSE) - occupant.adjustFireLoss(-1, FALSE) - occupant.adjustToxLoss(-1, FALSE) - occupant.adjustBruteLoss(-1, FALSE) - occupant.updatehealth() - if(occupant.health >= 0 && occupant.stat == DEAD) - occupant.update_revive() - occupant.lying = 0 - update_icon() - sleep(10) - active = 0 - add_fingerprint(usr) + if("wireless") + occupant.control_disabled = !occupant.control_disabled - if(href_list["wireless"]) - var/wireless = text2num(href_list["wireless"]) - if(wireless == 0 || wireless == 1) - occupant.control_disabled = wireless + if("radio") + occupant.aiRadio.disabledAi = !occupant.aiRadio.disabledAi - if(href_list["radio"]) - var/radio = text2num(href_list["radio"]) - if(radio == 0 || radio == 1) - occupant.aiRadio.disabledAi = radio - - SSnanoui.update_uis(src) update_icon() - return + return TRUE + +/obj/machinery/computer/aifixer/proc/fix_ai() // Can we fix it? Probrably. + while(occupant.health < 100) + occupant.adjustOxyLoss(-1, FALSE) + occupant.adjustFireLoss(-1, FALSE) + occupant.adjustToxLoss(-1, FALSE) + occupant.adjustBruteLoss(-1, FALSE) + occupant.updatehealth() + if(occupant.health >= 0 && occupant.stat == DEAD) + occupant.update_revive() + occupant.lying = FALSE + update_icon() + sleep(10) + active = FALSE /obj/machinery/computer/aifixer/update_icon() ..() diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index 98f56feeb6a..7211970fd14 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -2,6 +2,12 @@ //increase the slots of many jobs. GLOBAL_VAR_INIT(time_last_changed_position, 0) +#define IDCOMPUTER_SCREEN_TRANSFER 0 +#define IDCOMPUTER_SCREEN_SLOTS 1 +#define IDCOMPUTER_SCREEN_ACCESS 2 +#define IDCOMPUTER_SCREEN_RECORDS 3 +#define IDCOMPUTER_SCREEN_DEPT 4 + /obj/machinery/computer/card name = "identification computer" desc = "Terminal for programming Nanotrasen employee ID cards to access parts of the station." @@ -12,9 +18,9 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) light_color = LIGHT_COLOR_LIGHTBLUE var/obj/item/card/id/scan = null var/obj/item/card/id/modify = null - var/mode = 0.0 - var/printing = null + var/mode = 0 var/target_dept = 0 //Which department this computer has access to. 0=all departments + var/obj/item/radio/Radio //Cooldown for closing positions in seconds //if set to -1: No cooldown... probably a bad idea @@ -54,15 +60,27 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) //Assoc array: "JobName" = (int) var/list/opened_positions = list() + +/obj/machinery/computer/card/Initialize() + ..() + Radio = new /obj/item/radio(src) + Radio.listening = 0 + Radio.config(list("Command" = 0)) + Radio.follow_target = src + +/obj/machinery/computer/card/Destroy() + QDEL_NULL(Radio) + return ..() + /obj/machinery/computer/card/proc/is_centcom() - return istype(src, /obj/machinery/computer/card/centcom) + return FALSE /obj/machinery/computer/card/proc/is_authenticated(var/mob/user) if(user.can_admin_interact()) - return 1 + return TRUE if(scan) return check_access(scan) - return 0 + return FALSE /obj/machinery/computer/card/proc/get_target_rank() return modify && modify.assignment ? modify.assignment : "Unassigned" @@ -134,18 +152,18 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) if(!istype(id_card)) return ..() - if(!scan && (ACCESS_CHANGE_IDS in id_card.access)) + if(!scan && check_access(id_card)) user.drop_item() - id_card.loc = src + id_card.forceMove(src) scan = id_card playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) else if(!modify) user.drop_item() - id_card.loc = src + id_card.forceMove(src) modify = id_card playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) - SSnanoui.update_uis(src) + SStgui.update_uis(src) attack_hand(user) //Check if you can't touch a job in any way whatsoever @@ -156,68 +174,123 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) /obj/machinery/computer/card/proc/job_blacklisted_partial(datum/job/job) return (job.type in blacklisted_partial) -//Logic check for Topic() if you can open the job +// Logic check for if you can open the job /obj/machinery/computer/card/proc/can_open_job(datum/job/job) if(job) - if(!job_blacklisted_full(job) && !job_blacklisted_partial(job) && job_in_department(job, FALSE)) - if((job.total_positions <= GLOB.player_list.len * (max_relative_positions / 100))) - var/delta = (world.time / 10) - GLOB.time_last_changed_position - if((change_position_cooldown < delta) || (opened_positions[job.title] < 0)) - return 1 - return -2 - return -1 - return 0 + if(job_blacklisted_full(job)) + return FALSE + if(job_blacklisted_partial(job)) + return FALSE + if(!job_in_department(job, FALSE)) + return FALSE + if((job.total_positions > GLOB.player_list.len * (max_relative_positions / 100))) + return FALSE + if(opened_positions[job.title] < 0) + return TRUE + var/delta = (world.time / 10) - GLOB.time_last_changed_position + if(change_position_cooldown < delta) + return TRUE + return FALSE -//Logic check for Topic() if you can close the job +// Logic check for if you can close the job /obj/machinery/computer/card/proc/can_close_job(datum/job/job) if(job) - if(!job_blacklisted_full(job) && !job_blacklisted_partial(job) && job_in_department(job, FALSE)) - if(job.total_positions > job.current_positions && !(job in SSjobs.prioritized_jobs)) - var/delta = (world.time / 10) - GLOB.time_last_changed_position - if((change_position_cooldown < delta) || (opened_positions[job.title] > 0)) - return 1 - return -2 - return -1 - return 0 + if(job_blacklisted_full(job)) + return FALSE + if(job_blacklisted_partial(job)) + return FALSE + if(!job_in_department(job, FALSE)) + return FALSE + if(job in SSjobs.prioritized_jobs) // different to above + return FALSE + if(job.total_positions <= job.current_positions) // different to above + return FALSE + if(opened_positions[job.title] > 0) // different to above + return TRUE + var/delta = (world.time / 10) - GLOB.time_last_changed_position + if(change_position_cooldown < delta) + return TRUE + return FALSE /obj/machinery/computer/card/proc/can_prioritize_job(datum/job/job) if(job) - if(!job_blacklisted_full(job) && job_in_department(job, FALSE)) - if(job in SSjobs.prioritized_jobs) - return 2 - else - if(SSjobs.prioritized_jobs.len >= 3) - return 0 - if(job.total_positions <= job.current_positions) - return 0 - return 1 - return -1 + if(job_blacklisted_full(job)) + return FALSE + if(!job_in_department(job, FALSE)) + return FALSE + if(job in SSjobs.prioritized_jobs) + return TRUE // because this also lets us un-prioritize the job + if(SSjobs.prioritized_jobs.len >= 3) + return FALSE + if(job.total_positions <= job.current_positions) + return FALSE + return TRUE + return FALSE +/obj/machinery/computer/card/proc/has_idchange_access() + return scan && scan.access && (ACCESS_CHANGE_IDS in scan.access) ? TRUE : FALSE -/obj/machinery/computer/card/proc/job_in_department(datum/job/targetjob, includecivs = 1) +/obj/machinery/computer/card/proc/job_in_department(datum/job/targetjob, includecivs = TRUE) if(!scan || !scan.access) - return 0 + return FALSE if(!target_dept) - return 1 + return TRUE if(!scan.assignment) - return 0 - if(ACCESS_CAPTAIN in scan.access) - return 1 + return FALSE + if(has_idchange_access()) + return TRUE if(!targetjob || !targetjob.title) - return 0 + return FALSE if(targetjob.title in get_subordinates(scan.assignment, includecivs)) - return 1 - return 0 + return TRUE + return FALSE /obj/machinery/computer/card/proc/get_subordinates(rank, addcivs) var/list/jobs_returned = list() for(var/datum/job/thisjob in SSjobs.occupations) + if(thisjob.title in GLOB.nonhuman_positions) // hides AI from list when Captain ID is inserted into dept console + continue if(rank in thisjob.department_head) jobs_returned += thisjob.title if(addcivs) jobs_returned += "Civilian" return jobs_returned +/obj/machinery/computer/card/proc/get_employees(list/selectedranks) + var/list/names_returned = list() + if(isnull(GLOB.data_core.general) || isnull(GLOB.data_core.security)) + return names_returned + for(var/datum/data/record/R in GLOB.data_core.general) + if(!R.fields || !R.fields["name"] || !R.fields["real_rank"]) + continue + if(!(R.fields["real_rank"] in selectedranks)) + continue + for(var/datum/data/record/E in GLOB.data_core.security) + if(E.fields["name"] == R.fields["name"] && E.fields["id"] == R.fields["id"]) + var/buttontext + var/isdemotable = FALSE + if(status_valid_for_demotion(E.fields["criminal"])) + buttontext = "Demote" + isdemotable = TRUE + else if(E.fields["criminal"] == SEC_RECORD_STATUS_DEMOTE) + buttontext = "Pending Demotion" + else + buttontext = "Ineligible" + names_returned.Add(list(list( + "name" = E.fields["name"], + "crimstat" = E.fields["criminal"], + "title" = R.fields["real_rank"], + "buttontext" = buttontext, + "demotable" = isdemotable + ))) + break + return names_returned + +/obj/machinery/computer/card/proc/status_valid_for_demotion(crimstat) + if(crimstat in list(SEC_RECORD_STATUS_NONE, SEC_RECORD_STATUS_MONITOR, SEC_RECORD_STATUS_RELEASED, SEC_RECORD_STATUS_SEARCH)) + return TRUE + return FALSE + /obj/machinery/computer/card/attack_ai(var/mob/user as mob) return attack_hand(user) @@ -227,103 +300,119 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) if(stat & (NOPOWER|BROKEN)) return - ui_interact(user) + tgui_interact(user) -/obj/machinery/computer/card/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/card/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "identification_computer.tmpl", src.name, 775, 700) + ui = new(user, src, ui_key, "CardComputer", name, 800, 800, master_ui, state) ui.open() -/obj/machinery/computer/card/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - data["src"] = UID() - data["station_name"] = station_name() +/obj/machinery/computer/card/tgui_data(mob/user) + var/list/data = list() data["mode"] = mode - data["printing"] = printing - data["manifest"] = GLOB.data_core ? GLOB.data_core.get_manifest(0) : null - data["target_name"] = modify ? modify.name : "-----" - data["target_owner"] = modify && modify.registered_name ? modify.registered_name : "-----" - data["target_rank"] = get_target_rank() - data["scan_name"] = scan ? scan.name : "-----" - data["scan_owner"] = scan && scan.registered_name ? scan.registered_name : null - data["authenticated"] = is_authenticated(user) - data["has_modify"] = !!modify - data["account_number"] = modify ? modify.associated_account_number : null - data["centcom_access"] = is_centcom() - data["all_centcom_access"] = null - data["regions"] = null + data["modify_name"] = modify ? modify.name : FALSE + data["modify_owner"] = modify && modify.registered_name ? modify.registered_name : "-----" + data["modify_rank"] = get_target_rank() + data["modify_lastlog"] = modify && modify.lastlog ? modify.lastlog : FALSE + data["scan_name"] = scan ? scan.name : FALSE + data["scan_rank"] = scan ? scan.rank : FALSE + + data["authenticated"] = is_authenticated(user) ? TRUE : FALSE data["target_dept"] = target_dept - data["card_is_owned"] = modify && modify.owner_ckey + data["iscentcom"] = is_centcom() ? TRUE : FALSE - var/list/job_formats = SSjobs.format_jobs_for_id_computer(modify) - - data["top_jobs"] = format_jobs(list("Captain", "Custom"), data["target_rank"], job_formats) - data["engineering_jobs"] = format_jobs(GLOB.engineering_positions, data["target_rank"], job_formats) - data["medical_jobs"] = format_jobs(GLOB.medical_positions, data["target_rank"], job_formats) - data["science_jobs"] = format_jobs(GLOB.science_positions, data["target_rank"], job_formats) - data["security_jobs"] = format_jobs(GLOB.security_positions, data["target_rank"], job_formats) - data["support_jobs"] = format_jobs(GLOB.support_positions, data["target_rank"], job_formats) - data["civilian_jobs"] = format_jobs(GLOB.civilian_positions, data["target_rank"], job_formats) - data["special_jobs"] = format_jobs(GLOB.whitelisted_positions, data["target_rank"], job_formats) - data["centcom_jobs"] = format_jobs(get_all_centcom_jobs(), data["target_rank"], job_formats) - data["card_skins"] = format_card_skins(get_station_card_skins()) - - data["job_slots"] = format_job_slots() - - var/time_to_wait = round(change_position_cooldown - ((world.time / 10) - GLOB.time_last_changed_position), 1) - var/mins = round(time_to_wait / 60) - var/seconds = time_to_wait - (60*mins) - data["cooldown_mins"] = mins - data["cooldown_secs"] = (seconds < 10) ? "0[seconds]" : seconds - - if(mode == 3 && is_authenticated(user)) - data["id_change_html"] = SSjobs.fetch_transfer_record_html(is_centcom()) - - if(modify) - data["current_skin"] = modify.icon_state - - if(modify && is_centcom()) - var/list/all_centcom_access = list() - for(var/access in get_all_centcom_access()) - all_centcom_access.Add(list(list( - "desc" = replacetext(get_centcom_access_desc(access), " ", " "), - "ref" = access, - "allowed" = (access in modify.access) ? 1 : 0))) - - data["all_centcom_access"] = all_centcom_access - data["all_centcom_skins"] = format_card_skins(get_centcom_card_skins()) - - else if(modify) - var/list/regions = list() - for(var/i = 1; i <= 7; i++) - var/list/accesses = list() - for(var/access in get_region_accesses(i)) - if(get_access_desc(access)) - accesses.Add(list(list( - "desc" = replacetext(get_access_desc(access), " ", " "), - "ref" = access, - "allowed" = (access in modify.access) ? 1 : 0))) - - regions.Add(list(list( - "name" = get_region_accesses_name(i), - "accesses" = accesses))) - - data["regions"] = regions + switch(mode) + if(IDCOMPUTER_SCREEN_TRANSFER) // JOB TRANSFER + if(modify) + if(!scan) + return data + else if(target_dept) + data["jobs_dept"] = get_subordinates(scan.assignment, FALSE) + data["canterminate"] = has_idchange_access() + else + data["account_number"] = modify ? modify.associated_account_number : null + data["jobs_top"] = list("Captain", "Custom") + data["jobs_engineering"] = GLOB.engineering_positions + data["jobs_medical"] = GLOB.medical_positions + data["jobs_science"] = GLOB.science_positions + data["jobs_security"] = GLOB.security_positions + data["jobs_service"] = GLOB.service_positions + data["jobs_supply"] = GLOB.supply_positions - "Head of Personnel" + data["jobs_civilian"] = GLOB.civilian_positions + data["jobs_karma"] = GLOB.whitelisted_positions + data["jobs_centcom"] = get_all_centcom_jobs() + data["jobFormats"] = SSjobs.format_jobs_for_id_computer(modify) + data["current_skin"] = modify.icon_state + data["card_skins"] = format_card_skins(get_station_card_skins()) + data["all_centcom_skins"] = is_centcom() ? format_card_skins(get_centcom_card_skins()) : FALSE + if(IDCOMPUTER_SCREEN_SLOTS) // JOB SLOTS + data["job_slots"] = format_job_slots() + data["priority_jobs"] = list() + for(var/datum/job/a in SSjobs.prioritized_jobs) + data["priority_jobs"] += a.title + var/time_to_wait = round(change_position_cooldown - ((world.time / 10) - GLOB.time_last_changed_position), 1) + if(time_to_wait > 0) + var/mins = round(time_to_wait / 60) + var/seconds = time_to_wait - (60*mins) + seconds = (seconds < 10) ? "0[seconds]" : seconds + data["cooldown_time"] = "[mins]:[seconds]" + else + data["cooldown_time"] = FALSE + if(IDCOMPUTER_SCREEN_ACCESS) // ACCESS CHANGES + if(modify) + data["selectedAccess"] = modify.access + data["regions"] = get_accesslist_static_data(REGION_GENERAL, is_centcom() ? REGION_CENTCOMM : REGION_COMMAND) + if(IDCOMPUTER_SCREEN_RECORDS) // RECORDS + if(is_authenticated(user)) + data["records"] = SSjobs.format_job_change_records(data["iscentcom"]) + if(IDCOMPUTER_SCREEN_DEPT) // DEPARTMENT EMPLOYEE LIST + if(is_authenticated(user) && scan) // .requires both (aghosts don't count) + data["jobs_dept"] = get_subordinates(scan.assignment, FALSE) + data["people_dept"] = get_employees(data["jobs_dept"]) return data -/obj/machinery/computer/card/Topic(href, href_list) - if(..()) - return 1 +/obj/machinery/computer/card/proc/regenerate_id_name() + if(modify) + modify.name = text("[modify.registered_name]'s ID Card ([modify.assignment])") - switch(href_list["choice"]) - if("modify") +/obj/machinery/computer/card/tgui_act(action, params) + if(..()) + return + . = TRUE + + // 1st, handle the functions that require no authorization at all + + switch(action) + if("scan") // inserting or removing your authorizing ID + if(scan) + if(ishuman(usr)) + scan.forceMove(get_turf(src)) + if(!usr.get_active_hand() && Adjacent(usr)) + usr.put_in_hands(scan) + scan = null + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) + else + scan.forceMove(get_turf(src)) + scan = null + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) + else if(Adjacent(usr)) + var/obj/item/I = usr.get_active_hand() + if(istype(I, /obj/item/card/id)) + if(!check_access(I)) + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0) + to_chat(usr, "This card does not have access.") + return FALSE + usr.drop_item() + I.forceMove(src) + scan = I + playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) + return + if("modify") // inserting or removing the ID you plan to modify if(modify) GLOB.data_core.manifest_modify(modify.registered_name, modify.assignment) - modify.name = text("[modify.registered_name]'s ID Card ([modify.assignment])") + regenerate_id_name() if(ishuman(usr)) modify.forceMove(get_turf(src)) if(!usr.get_active_hand() && Adjacent(usr)) @@ -341,274 +430,299 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) I.forceMove(src) modify = I playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) + return + if("mode") // changing mode in the menu + mode = text2num(params["mode"]) + return - if("scan") - if(scan) - if(ishuman(usr)) - scan.forceMove(get_turf(src)) - if(!usr.get_active_hand() && Adjacent(usr)) - usr.put_in_hands(scan) - scan = null - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) - else - scan.forceMove(get_turf(src)) - scan = null - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) - else if(Adjacent(usr)) - var/obj/item/I = usr.get_active_hand() - if(istype(I, /obj/item/card/id)) - usr.drop_item() - I.forceMove(src) - scan = I - playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, 0) + // Everything below HERE requires auth + if(!is_authenticated(usr)) + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0) + to_chat(usr, "This function is not available unless you are logged in.") + return FALSE - if("access") - if(href_list["allowed"] && !target_dept) - if(is_authenticated(usr)) - var/access_type = text2num(href_list["access_target"]) - var/access_allowed = text2num(href_list["allowed"]) - if(access_type in (is_centcom() ? get_all_centcom_access() : get_all_accesses())) - modify.access -= access_type - if(!access_allowed) - modify.access += access_type - - if("skin") - if(!target_dept) - var/skin = href_list["skin_target"] - if(is_authenticated(usr) && modify && ((skin in get_station_card_skins()) || ((skin in get_centcom_card_skins()) && is_centcom()))) - modify.icon_state = href_list["skin_target"] - - if("assign") - if(is_authenticated(usr) && modify) - var/t1 = href_list["assign_target"] - if(target_dept && modify.assignment == "Demoted") - visible_message("[src]: Demoted individuals must see the HoP for a new job.") - return 0 + // 2nd, handle the functions that are available to head-level consoles (department consoles) + switch(action) + if("assign") // transfer to a new job + if(!modify) + return + var/t1 = params["assign_target"] + if(target_dept) + if(modify.assignment == "Demoted") + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0) + visible_message("[src]: Reassigning a demoted individual requires a full ID computer.") + return FALSE if(!job_in_department(SSjobs.GetJob(modify.rank), FALSE)) - visible_message("[src]: Cross-department job transfers must be done by the HoP.") - return 0 + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0) + visible_message("[src]: Reassigning someone outside your department requires a full ID computer.") + return FALSE if(!job_in_department(SSjobs.GetJob(t1))) - return 0 - if(t1 == "Custom") - var/temp_t = sanitize(reject_bad_name(copytext(input("Enter a custom job assignment.", "Assignment"), 1, MAX_MESSAGE_LEN), TRUE)) - //let custom jobs function as an impromptu alt title, mainly for sechuds - if(temp_t && modify) - SSjobs.log_job_transfer(modify.registered_name, modify.getRankAndAssignment(), temp_t, scan.registered_name) - modify.assignment = temp_t - log_game("[key_name(usr)] has given \"[modify.registered_name]\" the custom job title \"[temp_t]\".") + return FALSE + if(t1 == "Custom") + var/temp_t = sanitize(reject_bad_name(copytext(input("Enter a custom job assignment.", "Assignment"), 1, MAX_MESSAGE_LEN), TRUE)) + //let custom jobs function as an impromptu alt title, mainly for sechuds + if(temp_t && scan && modify) + var/oldrank = modify.getRankAndAssignment() + SSjobs.log_job_transfer(modify.registered_name, oldrank, temp_t, scan.registered_name, null) + modify.lastlog = "[station_time_timestamp()]: Reassigned by \"[scan.registered_name]\" from \"[oldrank]\" to \"[temp_t]\"." + modify.assignment = temp_t + log_game("[key_name(usr)] ([scan.assignment]) has reassigned \"[modify.registered_name]\" from \"[oldrank]\" to \"[temp_t]\".") + SSjobs.notify_dept_head(modify.rank, "[scan.registered_name] has transferred \"[modify.registered_name]\" the \"[oldrank]\" to \"[temp_t]\".") + else + var/list/access = list() + if(is_centcom() && islist(get_centcom_access(t1))) + access = get_centcom_access(t1) else - var/list/access = list() - if(is_centcom() && islist(get_centcom_access(t1))) - access = get_centcom_access(t1) - else - var/datum/job/jobdatum - for(var/jobtype in typesof(/datum/job)) - var/datum/job/J = new jobtype - if(ckey(J.title) == ckey(t1)) - jobdatum = J - break - if(!jobdatum) - to_chat(usr, "No log exists for this job: [t1]") + var/datum/job/jobdatum + for(var/jobtype in typesof(/datum/job)) + var/datum/job/J = new jobtype + if(ckey(J.title) == ckey(t1)) + jobdatum = J + break + if(!jobdatum) + to_chat(usr, "No log exists for this job: [t1]") + return + + access = jobdatum.get_access() + + var/jobnamedata = modify.getRankAndAssignment() + log_game("[key_name(usr)] ([scan.assignment]) has reassigned \"[modify.registered_name]\" from \"[jobnamedata]\" to \"[t1]\".") + if(t1 == "Civilian") + message_admins("[key_name_admin(usr)] has reassigned \"[modify.registered_name]\" from \"[jobnamedata]\" to \"[t1]\".") + + SSjobs.log_job_transfer(modify.registered_name, jobnamedata, t1, scan.registered_name, null) + modify.lastlog = "[station_time_timestamp()]: Reassigned by \"[scan.registered_name]\" from \"[jobnamedata]\" to \"[t1]\"." + SSjobs.notify_dept_head(t1, "[scan.registered_name] has transferred \"[modify.registered_name]\" the \"[jobnamedata]\" to \"[t1]\".") + if(modify.owner_uid) + SSjobs.slot_job_transfer(modify.rank, t1) + + var/mob/living/carbon/human/H = modify.getPlayer() + if(istype(H)) + if(jobban_isbanned(H, t1)) + message_admins("[ADMIN_FULLMONTY(H)] has been assigned the job [t1], in possible violation of their job ban.") + if(H.mind) + H.mind.playtime_role = t1 + + modify.access = access + modify.rank = t1 + modify.assignment = t1 + regenerate_id_name() + return + if("demote") + if(modify.assignment == "Demoted") + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0) + visible_message("[src]: Demoted crew cannot be demoted any further. If further action is warranted, ask the Captain about Termination.") + return FALSE + if(!job_in_department(SSjobs.GetJob(modify.rank), FALSE)) + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0) + visible_message("[src]: Heads may only demote members of their own department.") + return FALSE + var/reason = sanitize(copytext(input("Enter legal reason for demotion. Enter nothing to cancel.","Legal Demotion"), 1, MAX_MESSAGE_LEN)) + if(!reason || !is_authenticated(usr) || !modify) + return FALSE + var/list/access = list() + var/datum/job/jobdatum = new /datum/job/civilian + access = jobdatum.get_access() + var/jobnamedata = modify.getRankAndAssignment() + var/m_ckey = modify.getPlayerCkey() + var/m_ckey_text = m_ckey ? "([m_ckey])" : "(no ckey)" + log_game("[key_name(usr)] ([scan.assignment]) has demoted \"[modify.registered_name]\" [m_ckey_text] the \"[jobnamedata]\" for: \"[reason]\".") + message_admins("[key_name_admin(usr)] has demoted \"[modify.registered_name]\" [m_ckey_text] the \"[jobnamedata]\" for: \"[reason]\".") + usr.create_log(MISC_LOG, "demoted \"[modify.registered_name]\" [m_ckey_text] the \"[jobnamedata]\"") + SSjobs.log_job_transfer(modify.registered_name, jobnamedata, "Demoted", scan.registered_name, reason) + modify.lastlog = "[station_time_timestamp()]: DEMOTED by \"[scan.registered_name]\" ([scan.assignment]) from \"[jobnamedata]\" for: \"[reason]\"." + SSjobs.notify_dept_head(modify.rank, "[scan.registered_name] ([scan.assignment]) has demoted \"[modify.registered_name]\" ([jobnamedata]) for \"[reason]\".") + modify.access = access + modify.rank = "Civilian" + modify.assignment = "Demoted" + modify.icon_state = "id" + regenerate_id_name() + return + if("terminate") + if(!has_idchange_access()) // because captain/HOP can use this even on dept consoles + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0) + visible_message("[src]: Only the Captain or HOP may completely terminate the employment of a crew member.") + return FALSE + var/jobnamedata = modify.getRankAndAssignment() + var/reason = sanitize(copytext(input("Enter legal reason for termination. Enter nothing to cancel.", "Employment Termination"), 1, MAX_MESSAGE_LEN)) + if(!reason || !has_idchange_access() || !modify) + return FALSE + var/m_ckey = modify.getPlayerCkey() + var/m_ckey_text = m_ckey ? "([m_ckey])" : "(no ckey)" + log_game("[key_name(usr)] ([scan.assignment]) has terminated \"[modify.registered_name]\" [m_ckey_text] the \"[jobnamedata]\" for: \"[reason]\".") + message_admins("[key_name_admin(usr)] has terminated \"[modify.registered_name]\" [m_ckey_text] the \"[jobnamedata]\" for: \"[reason]\".") + usr.create_log(MISC_LOG, "terminated the employment of \"[modify.registered_name]\" [m_ckey_text] the \"[jobnamedata]\"") + SSjobs.log_job_transfer(modify.registered_name, jobnamedata, "Terminated", scan.registered_name, reason) + modify.lastlog = "[station_time_timestamp()]: TERMINATED by \"[scan.registered_name]\" ([scan.assignment]) from \"[jobnamedata]\" for: \"[reason]\"." + SSjobs.notify_dept_head(modify.rank, "[scan.registered_name] ([scan.assignment]) has terminated the employment of \"[modify.registered_name]\" the \"[jobnamedata]\" for \"[reason]\".") + modify.assignment = "Terminated" + modify.access = list() + regenerate_id_name() + return + if("make_job_available") // MAKE ANOTHER JOB POSITION AVAILABLE FOR LATE JOINERS + var/edit_job_target = params["job"] + var/datum/job/j = SSjobs.GetJob(edit_job_target) + if(!job_in_department(j, FALSE)) + return FALSE + if(!j) + return FALSE + if(!can_open_job(j)) + return FALSE + if(opened_positions[edit_job_target] >= 0) + GLOB.time_last_changed_position = world.time / 10 + j.total_positions++ + opened_positions[edit_job_target]++ + log_game("[key_name(usr)] ([scan.assignment]) has opened a job slot for job \"[j.title]\".") + message_admins("[key_name_admin(usr)] has opened a job slot for job \"[j.title]\".") + return + if("make_job_unavailable") // MAKE JOB POSITION UNAVAILABLE FOR LATE JOINERS + var/edit_job_target = params["job"] + var/datum/job/j = SSjobs.GetJob(edit_job_target) + if(!job_in_department(j, FALSE)) + return FALSE + if(!j) + return FALSE + if(!can_close_job(j)) + return FALSE + //Allow instant closing without cooldown if a position has been opened before + if(opened_positions[edit_job_target] <= 0) + GLOB.time_last_changed_position = world.time / 10 + j.total_positions-- + opened_positions[edit_job_target]-- + log_game("[key_name(usr)] ([scan.assignment]) has closed a job slot for job \"[j.title]\".") + message_admins("[key_name_admin(usr)] has closed a job slot for job \"[j.title]\".") + return + if("remote_demote") + var/reason = sanitize(copytext(input("Enter legal reason for demotion. Enter nothing to cancel.","Legal Demotion"), 1, MAX_MESSAGE_LEN)) + if(!reason || !is_authenticated(usr) || !scan) + return FALSE + for(var/datum/data/record/E in GLOB.data_core.general) + if(E.fields["name"] == params["remote_demote"]) + var/datum/job/j = SSjobs.GetJob(E.fields["real_rank"]) + var/tempname = params["remote_demote"] + var/temprank = E.fields["real_rank"] + if(!j) + visible_message("[src]: This employee has either no job, or a customized job ([temprank]).") + return FALSE + if(!job_in_department(j, FALSE)) + visible_message("[src]: Only the head of this employee may demote them.") + return FALSE + for(var/datum/data/record/R in GLOB.data_core.security) + if(R.fields["id"] == E.fields["id"]) + if(status_valid_for_demotion(R.fields["criminal"])) + set_criminal_status(usr, R, SEC_RECORD_STATUS_DEMOTE, reason, scan.assignment) + Radio.autosay("[scan.registered_name] ([scan.assignment]) has set [tempname] ([temprank]) to demote for: [reason]", name, "Command", list(z)) + message_admins("[key_name_admin(usr)] ([scan.assignment]) has set [tempname] ([temprank]) to demote for: \"[reason]\"") + log_game("[key_name(usr)] ([scan.assignment]) has set \"[tempname]\" ([temprank]) to demote for: \"[reason]\".") + SSjobs.notify_by_name(tempname, "[scan.registered_name] ([scan.assignment]) has ordered your demotion. Report to their office, or the HOP. Reason given: \"[reason]\"") + else + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0) + to_chat(usr, "[src]: Cannot demote, due to their current security status.") + return FALSE return + return - access = jobdatum.get_access() + // Everything below here requires a full ID computer (dept consoles do not qualify) + if(target_dept) + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0) + to_chat(usr, "This function is not available on department-level consoles.") + return - var/jobnamedata = modify.getRankAndAssignment() - log_game("[key_name(usr)] has reassigned \"[modify.registered_name]\" from \"[jobnamedata]\" to \"[t1]\".") - if(t1 == "Civilian") - message_admins("[key_name_admin(usr)] has reassigned \"[modify.registered_name]\" from \"[jobnamedata]\" to \"[t1]\".") + // 3rd, handle the functions that require a full ID computer + switch(action) + // Changing basic card info + if("reg") // registered name on card + var/temp_name = reject_bad_name(input(usr, "Who is this ID for?", "ID Card Renaming", modify.registered_name), TRUE) + if(!modify || !temp_name) + playsound(get_turf(src), 'sound/machines/buzz-sigh.ogg', 50, 0) + visible_message("[src] buzzes rudely.") + return FALSE + modify.registered_name = temp_name + regenerate_id_name() + return + if("account") // card account number + var/account_num = input(usr, "Account Number", "Input Number", null) as num|null + if(!scan || !modify) + return FALSE + modify.associated_account_number = clamp(round(account_num), 0, 999999) + return + if("skin") + if(!modify) + return FALSE + var/skin = params["skin_target"] + var/skin_list = is_centcom() ? get_centcom_card_skins() : get_station_card_skins() + if(skin in skin_list) + modify.icon_state = skin + return + // Changing card access + if("set") // add/remove a single access number + var/access = text2num(params["access"]) + var/list/changable = is_centcom() ? get_all_centcom_access() + get_all_accesses() : get_all_accesses() + if(access in changable) + if(access in modify.access) + modify.access -= access + else + modify.access += access + return + if("grant_region") + var/region = text2num(params["region"]) + if(isnull(region) || region < REGION_GENERAL || region > (is_centcom() ? REGION_CENTCOMM : REGION_COMMAND)) + return + modify.access |= get_region_accesses(region) + return + if("deny_region") + var/region = text2num(params["region"]) + if(isnull(region) || region < REGION_GENERAL || region > (is_centcom() ? REGION_CENTCOMM : REGION_COMMAND)) + return + modify.access -= get_region_accesses(region) + return + if("clear_all") + modify.access = list() + return + if("grant_all") + modify.access = get_all_accesses() + return - SSjobs.log_job_transfer(modify.registered_name, jobnamedata, t1, scan.registered_name) - if(modify.owner_uid) - SSjobs.slot_job_transfer(modify.rank, t1) + // JOB SLOT MANAGEMENT functions - var/mob/living/carbon/human/H = modify.getPlayer() - if(istype(H)) - if(jobban_isbanned(H, t1)) - message_admins("[ADMIN_FULLMONTY(H)] has been assigned the job [t1], in possible violation of their job ban.") - if(H.mind) - H.mind.playtime_role = t1 + if("prioritize_job") // TOGGLE WHETHER JOB APPEARS AS PRIORITIZED IN THE LOBBY + var/priority_target = params["job"] + var/datum/job/j = SSjobs.GetJob(priority_target) + if(!j) + return FALSE + if(!job_in_department(j)) + return FALSE + var/priority = TRUE + if(j in SSjobs.prioritized_jobs) + SSjobs.prioritized_jobs -= j + priority = FALSE + else if(SSjobs.prioritized_jobs.len < 3) + SSjobs.prioritized_jobs += j + else + return FALSE + log_game("[key_name(usr)] ([scan.assignment]) [priority ? "prioritized" : "unprioritized"] the job \"[j.title]\".") + playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) + return - modify.access = access - modify.rank = t1 - modify.assignment = t1 - - if("reg") - if(is_authenticated(usr) && !target_dept) - var/t2 = modify - if((modify == t2 && (in_range(src, usr) || (istype(usr, /mob/living/silicon))) && istype(loc, /turf))) - var/temp_name = reject_bad_name(href_list["reg"], TRUE) - if(temp_name) - modify.registered_name = temp_name - else - visible_message("[src] buzzes rudely.") - SSnanoui.update_uis(src) - - if("account") - if(is_authenticated(usr) && !target_dept) - var/t2 = modify - if((modify == t2 && (in_range(src, usr) || (istype(usr, /mob/living/silicon))) && istype(loc, /turf))) - var/account_num = text2num(href_list["account"]) - modify.associated_account_number = account_num - SSnanoui.update_uis(src) - - if("mode") - mode = text2num(href_list["mode_target"]) - - if("wipe_my_logs") - if(is_authenticated(usr) && is_centcom()) - var/delcount = SSjobs.delete_log_records(scan.registered_name, FALSE) - if(delcount) - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) - SSnanoui.update_uis(src) - - if("wipe_all_logs") + if("wipe_all_logs") // Delete all records from 'records' section if(is_authenticated(usr) && !target_dept) var/delcount = SSjobs.delete_log_records(scan.registered_name, TRUE) if(delcount) message_admins("[key_name_admin(usr)] has wiped all ID computer logs.") usr.create_log(MISC_LOG, "wiped all ID computer logs.") playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) - SSnanoui.update_uis(src) + return - if("print") - if(!printing && !target_dept) - printing = 1 - playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1) - spawn(50) - printing = null - SSnanoui.update_uis(src) + // Everything below here is exclusive to the CC card computer. + if(!is_centcom()) + return - var/obj/item/paper/P = new(loc) - if(mode == 2) - P.name = "crew manifest ([station_time_timestamp()])" - P.info = {"

Crew Manifest

-
- [GLOB.data_core ? GLOB.data_core.get_manifest(0) : ""] - "} - else if(modify && !mode) - P.name = "access report" - P.info = {"

Access Report

- Prepared By: [scan && scan.registered_name ? scan.registered_name : "Unknown"]
- For: [modify.registered_name ? modify.registered_name : "Unregistered"]
-
- Assignment: [modify.assignment]
- Account Number: #[modify.associated_account_number]
- Blood Type: [modify.blood_type]

- Access:
- "} - - var/first = 1 - for(var/A in modify.access) - P.info += "[first ? "" : ", "][get_access_desc(A)]" - first = 0 - P.info += "
" - - if("terminate") - if(is_authenticated(usr) && !target_dept) - var/jobnamedata = modify.getRankAndAssignment() - var/reason = sanitize(copytext(input("Enter legal reason for termination. Enter nothing to cancel.", "Employment Termination"), 1, MAX_MESSAGE_LEN)) - if(!reason || !is_authenticated(usr) || !modify) - return FALSE - var/m_ckey = modify.getPlayerCkey() - var/m_ckey_text = m_ckey ? "([m_ckey])" : "(no ckey)" - log_game("[key_name(usr)] has terminated the employment of \"[modify.registered_name]\" [m_ckey_text] the \"[jobnamedata]\" for: \"[reason]\".") - message_admins("[key_name_admin(usr)] has terminated the employment of \"[modify.registered_name]\" [m_ckey_text] the \"[jobnamedata]\" for: \"[reason]\".") - usr.create_log(MISC_LOG, "terminated the employment of \"[modify.registered_name]\" [m_ckey_text] the \"[jobnamedata]\"") - SSjobs.log_job_transfer(modify.registered_name, jobnamedata, "Terminated", scan.registered_name) - SSjobs.notify_dept_head(modify.rank, "[scan.registered_name] has terminated the employment of \"[modify.registered_name]\" the \"[jobnamedata]\" for \"[reason]\".") - modify.assignment = "Terminated" - modify.access = list() - - if("demote") - if(is_authenticated(usr)) - if(modify.assignment == "Demoted") - visible_message("[src]: Demoted crew cannot be demoted any further. If further action is warranted, ask the Captain about Termination.") - return 0 - if(!job_in_department(SSjobs.GetJob(modify.rank), FALSE)) - visible_message("[src]: Heads may only demote members of their own department.") - return 0 - var/reason = sanitize(copytext(input("Enter legal reason for demotion. Enter nothing to cancel.","Legal Demotion"),1,MAX_MESSAGE_LEN)) - if(!reason || !is_authenticated(usr) || !modify) - return 0 - var/list/access = list() - var/datum/job/jobdatum = new /datum/job/civilian - access = jobdatum.get_access() - var/jobnamedata = modify.getRankAndAssignment() - var/m_ckey = modify.getPlayerCkey() - var/m_ckey_text = m_ckey ? "([m_ckey])" : "(no ckey)" - log_game("[key_name(usr)] has demoted \"[modify.registered_name]\" the \"[jobnamedata]\" [m_ckey_text] to \"Civilian (Demoted)\" for: \"[reason]\".") - message_admins("[key_name_admin(usr)] has demoted \"[modify.registered_name]\" the \"[jobnamedata]\" [m_ckey_text] to \"Civilian (Demoted)\" for: \"[reason]\".") - usr.create_log(MISC_LOG, "demoted \"[modify.registered_name]\" [m_ckey_text] the \"[jobnamedata]\"") - SSjobs.log_job_transfer(modify.registered_name, jobnamedata, "Demoted", scan.registered_name) - SSjobs.notify_dept_head(modify.rank, "[scan.registered_name] has demoted \"[modify.registered_name]\" the \"[jobnamedata]\" for \"[reason]\".") - modify.access = access - modify.rank = "Civilian" - modify.assignment = "Demoted" - modify.icon_state = "id" - - if("make_job_available") - // MAKE ANOTHER JOB POSITION AVAILABLE FOR LATE JOINERS - if(is_authenticated(usr)) - var/edit_job_target = href_list["job"] - var/datum/job/j = SSjobs.GetJob(edit_job_target) - if(!job_in_department(j, FALSE)) - return 0 - if(!j) - return 0 - if(can_open_job(j) != 1) - return 0 - if(opened_positions[edit_job_target] >= 0) - GLOB.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]\".") - message_admins("[key_name_admin(usr)] has opened a job slot for job \"[j.title]\".") - SSnanoui.update_uis(src) - - if("make_job_unavailable") - // MAKE JOB POSITION UNAVAILABLE FOR LATE JOINERS - if(is_authenticated(usr)) - var/edit_job_target = href_list["job"] - var/datum/job/j = SSjobs.GetJob(edit_job_target) - if(!job_in_department(j, FALSE)) - return 0 - if(!j) - return 0 - if(can_close_job(j) != 1) - return 0 - //Allow instant closing without cooldown if a position has been opened before - if(opened_positions[edit_job_target] <= 0) - GLOB.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]\".") - message_admins("[key_name_admin(usr)] has closed a job slot for job \"[j.title]\".") - SSnanoui.update_uis(src) - - if("prioritize_job") - // TOGGLE WHETHER JOB APPEARS AS PRIORITIZED IN THE LOBBY - if(is_authenticated(usr) && !target_dept) - var/priority_target = href_list["job"] - var/datum/job/j = SSjobs.GetJob(priority_target) - if(!j) - return 0 - if(!job_in_department(j)) - return 0 - var/priority = TRUE - if(j in SSjobs.prioritized_jobs) - SSjobs.prioritized_jobs -= j - priority = FALSE - else if(SSjobs.prioritized_jobs.len < 3) - SSjobs.prioritized_jobs += j - else - return 0 - log_game("[key_name(usr)] [priority ? "prioritized" : "unprioritized"] the job \"[j.title]\".") + switch(action) + if("wipe_my_logs") + var/delcount = SSjobs.delete_log_records(scan.registered_name, FALSE) + if(delcount) playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) - if(modify) - modify.name = text("[modify.registered_name]'s ID Card ([modify.assignment])") - return 1 /obj/machinery/computer/card/centcom name = "\improper CentComm identification computer" @@ -618,6 +732,9 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) blacklisted_full = list() blacklisted_partial = list() +/obj/machinery/computer/card/centcom/is_centcom() + return TRUE + /obj/machinery/computer/card/minor name = "department management console" target_dept = TARGET_DEPT_GENERIC diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 366946254ea..60563e692b3 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -1,35 +1,39 @@ #define COMM_SCREEN_MAIN 1 #define COMM_SCREEN_STAT 2 #define COMM_SCREEN_MESSAGES 3 -#define COMM_SCREEN_SECLEVEL 4 #define COMM_AUTHENTICATION_NONE 0 #define COMM_AUTHENTICATION_MIN 1 #define COMM_AUTHENTICATION_MAX 2 +#define COMM_MSGLEN_MINIMUM 6 +#define COMM_CCMSGLEN_MINIMUM 20 + // The communications computer /obj/machinery/computer/communications name = "communications console" - desc = "This can be used for various important functions. Still under developement." + desc = "This allows the Captain to contact Central Command, or change the alert level. It also allows the command staff to call the Escape Shuttle." icon_keyboard = "tech_key" icon_screen = "comm" req_access = list(ACCESS_HEADS) circuit = /obj/item/circuitboard/communications - var/prints_intercept = 1 - var/authenticated = COMM_AUTHENTICATION_NONE var/list/messagetitle = list() var/list/messagetext = list() - var/currmsg = 0 - var/aicurrmsg = 0 + var/currmsg + + var/authenticated = COMM_AUTHENTICATION_NONE var/menu_state = COMM_SCREEN_MAIN var/ai_menu_state = COMM_SCREEN_MAIN - var/message_cooldown = 0 - var/centcomm_message_cooldown = 0 + var/aicurrmsg + + var/message_cooldown + var/centcomm_message_cooldown var/tmp_alertlevel = 0 var/stat_msg1 var/stat_msg2 - var/display_type="blank" + var/display_type = "blank" + var/display_icon var/datum/announcement/priority/crew_announcement = new @@ -70,123 +74,113 @@ feedback_inc("alert_comms_blue",1) tmp_alertlevel = 0 -/obj/machinery/computer/communications/Topic(href, href_list) - if(..(href, href_list)) - return 1 - - if(!is_secure_level(src.z)) +/obj/machinery/computer/communications/tgui_act(action, params) + if(..()) + return + if(!is_secure_level(z)) to_chat(usr, "Unable to establish a connection: You're too far away from the station!") - return 1 + return - if(href_list["login"]) + . = TRUE + + if(action == "auth") if(!ishuman(usr)) to_chat(usr, "Access denied.") + return FALSE + // Logout function. + if(authenticated != COMM_AUTHENTICATION_NONE) + authenticated = COMM_AUTHENTICATION_NONE + crew_announcement.announcer = null + setMenuState(usr, COMM_SCREEN_MAIN) return - + // Login function. var/list/access = usr.get_access() if(allowed(usr)) authenticated = COMM_AUTHENTICATION_MIN - if(ACCESS_CAPTAIN in access) authenticated = COMM_AUTHENTICATION_MAX var/mob/living/carbon/human/H = usr var/obj/item/card/id = H.get_idcard(TRUE) if(istype(id)) crew_announcement.announcer = GetNameAndAssignmentFromId(id) - - SSnanoui.update_uis(src) - return - - if(href_list["logout"]) - authenticated = COMM_AUTHENTICATION_NONE - crew_announcement.announcer = "" - setMenuState(usr,COMM_SCREEN_MAIN) - SSnanoui.update_uis(src) + if(authenticated == COMM_AUTHENTICATION_NONE) + to_chat(usr, "You need to wear your ID.") return + // All functions below this point require authentication. if(!is_authenticated(usr)) - return 1 + return FALSE - switch(href_list["operation"]) + switch(action) if("main") - setMenuState(usr,COMM_SCREEN_MAIN) - - if("changeseclevel") - setMenuState(usr,COMM_SCREEN_SECLEVEL) + setMenuState(usr, COMM_SCREEN_MAIN) if("newalertlevel") if(isAI(usr) || isrobot(usr)) to_chat(usr, "Firewalls prevent you from changing the alert level.") - return 1 + return else if(usr.can_admin_interact()) - change_security_level(text2num(href_list["level"])) - return 1 + change_security_level(text2num(params["level"])) + return else if(!ishuman(usr)) to_chat(usr, "Security measures prevent you from changing the alert level.") - return 1 + return - var/mob/living/carbon/human/L = usr - var/obj/item/card = L.get_active_hand() - var/obj/item/card/id/I = (card && card.GetID()) || L.wear_id || L.wear_pda - if(istype(I, /obj/item/pda)) - var/obj/item/pda/pda = I - I = pda.id - if(I && istype(I)) + var/mob/living/carbon/human/H = usr + var/obj/item/card/id/I = H.get_idcard(TRUE) + if(istype(I)) if(ACCESS_CAPTAIN in I.access) - change_security_level(text2num(href_list["level"])) + change_security_level(text2num(params["level"])) else to_chat(usr, "You are not authorized to do this.") - setMenuState(usr,COMM_SCREEN_MAIN) + setMenuState(usr, COMM_SCREEN_MAIN) else - to_chat(usr, "You need to swipe your ID.") + to_chat(usr, "You need to wear your ID.") if("announce") if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX) - if(message_cooldown) + if(message_cooldown > world.time) to_chat(usr, "Please allow at least one minute to pass between announcements.") - SSnanoui.update_uis(src) return var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement") - if(!input || message_cooldown || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)) - SSnanoui.update_uis(src) + if(!input || message_cooldown > world.time || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)) + return + if(length(input) < COMM_MSGLEN_MINIMUM) + to_chat(usr, "Message '[input]' is too short. [COMM_MSGLEN_MINIMUM] character minimum.") return crew_announcement.Announce(input) - message_cooldown = 1 - spawn(600)//One minute cooldown - message_cooldown = 0 + message_cooldown = world.time + 600 //One minute if("callshuttle") var/input = clean_input("Please enter the reason for calling the shuttle.", "Shuttle Call Reason.","") if(!input || ..() || !is_authenticated(usr)) - SSnanoui.update_uis(src) return - call_shuttle_proc(usr, input) if(SSshuttle.emergency.timer) post_status("shuttle") - setMenuState(usr,COMM_SCREEN_MAIN) + setMenuState(usr, COMM_SCREEN_MAIN) if("cancelshuttle") if(isAI(usr) || isrobot(usr)) to_chat(usr, "Firewalls prevent you from recalling the shuttle.") - SSnanoui.update_uis(src) - return 1 + return var/response = alert("Are you sure you wish to recall the shuttle?", "Confirm", "Yes", "No") if(response == "Yes") cancel_call_proc(usr) if(SSshuttle.emergency.timer) post_status("shuttle") - setMenuState(usr,COMM_SCREEN_MAIN) + setMenuState(usr, COMM_SCREEN_MAIN) if("messagelist") - currmsg = 0 - if(href_list["msgid"]) - setCurrentMessage(usr, text2num(href_list["msgid"])) - setMenuState(usr,COMM_SCREEN_MESSAGES) + currmsg = null + aicurrmsg = null + if(params["msgid"]) + setCurrentMessage(usr, text2num(params["msgid"])) + setMenuState(usr, COMM_SCREEN_MESSAGES) if("delmessage") - if(href_list["msgid"]) - currmsg = text2num(href_list["msgid"]) + if(params["msgid"]) + currmsg = text2num(params["msgid"]) var/response = alert("Are you sure you wish to delete this message?", "Confirm", "Yes", "No") if(response == "Yes") if(currmsg) @@ -196,95 +190,95 @@ messagetitle.Remove(title) messagetext.Remove(text) if(currmsg == id) - currmsg = 0 + currmsg = null if(aicurrmsg == id) - aicurrmsg = 0 - setMenuState(usr,COMM_SCREEN_MESSAGES) + aicurrmsg = null + setMenuState(usr, COMM_SCREEN_MESSAGES) if("status") - setMenuState(usr,COMM_SCREEN_STAT) + setMenuState(usr, COMM_SCREEN_STAT) // Status display stuff if("setstat") - display_type=href_list["statdisp"] + display_type = params["statdisp"] switch(display_type) if("message") + display_icon = null post_status("message", stat_msg1, stat_msg2, usr) if("alert") - post_status("alert", href_list["alert"], user = usr) + display_icon = params["alert"] + post_status("alert", params["alert"], user = usr) else - post_status(href_list["statdisp"], user = usr) - setMenuState(usr,COMM_SCREEN_STAT) + display_icon = null + post_status(params["statdisp"], user = usr) + setMenuState(usr, COMM_SCREEN_STAT) if("setmsg1") stat_msg1 = clean_input("Line 1", "Enter Message Text", stat_msg1) - setMenuState(usr,COMM_SCREEN_STAT) + setMenuState(usr, COMM_SCREEN_STAT) if("setmsg2") stat_msg2 = clean_input("Line 2", "Enter Message Text", stat_msg2) - setMenuState(usr,COMM_SCREEN_STAT) + setMenuState(usr, COMM_SCREEN_STAT) if("nukerequest") if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX) - if(centcomm_message_cooldown) + if(centcomm_message_cooldown > world.time) to_chat(usr, "Arrays recycling. Please stand by.") - SSnanoui.update_uis(src) return var/input = stripped_input(usr, "Please enter the reason for requesting the nuclear self-destruct codes. Misuse of the nuclear request system will not be tolerated under any circumstances. Transmission does not guarantee a response.", "Self Destruct Code Request.","") if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)) - SSnanoui.update_uis(src) + return + if(length(input) < COMM_CCMSGLEN_MINIMUM) + to_chat(usr, "Message '[input]' is too short. [COMM_CCMSGLEN_MINIMUM] character minimum.") return Nuke_request(input, usr) to_chat(usr, "Request sent.") log_game("[key_name(usr)] has requested the nuclear codes from Centcomm") GLOB.priority_announcement.Announce("The codes for the on-station nuclear self-destruct have been requested by [usr]. Confirmation or denial of this request will be sent shortly.", "Nuclear Self Destruct Codes Requested",'sound/AI/commandreport.ogg') - centcomm_message_cooldown = 1 - spawn(6000)//10 minute cooldown - centcomm_message_cooldown = 0 - setMenuState(usr,COMM_SCREEN_MAIN) + centcomm_message_cooldown = world.time + 6000 // 10 minutes + setMenuState(usr, COMM_SCREEN_MAIN) if("MessageCentcomm") if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX) - if(centcomm_message_cooldown) + if(centcomm_message_cooldown > world.time) to_chat(usr, "Arrays recycling. Please stand by.") - SSnanoui.update_uis(src) return var/input = stripped_input(usr, "Please choose a message to transmit to Centcomm via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "To abort, send an empty message.", "") if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)) - SSnanoui.update_uis(src) + return + if(length(input) < COMM_CCMSGLEN_MINIMUM) + to_chat(usr, "Message '[input]' is too short. [COMM_CCMSGLEN_MINIMUM] character minimum.") return Centcomm_announce(input, usr) print_centcom_report(input, station_time_timestamp() + " Captain's Message") to_chat(usr, "Message transmitted.") log_game("[key_name(usr)] has made a Centcomm announcement: [input]") - centcomm_message_cooldown = 1 - spawn(6000)//10 minute cooldown - centcomm_message_cooldown = 0 - setMenuState(usr,COMM_SCREEN_MAIN) + centcomm_message_cooldown = world.time + 6000 // 10 minutes + setMenuState(usr, COMM_SCREEN_MAIN) // OMG SYNDICATE ...LETTERHEAD if("MessageSyndicate") if((is_authenticated(usr) == COMM_AUTHENTICATION_MAX) && (src.emagged)) - if(centcomm_message_cooldown) + if(centcomm_message_cooldown > world.time) to_chat(usr, "Arrays recycling. Please stand by.") - SSnanoui.update_uis(src) return var/input = stripped_input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "To abort, send an empty message.", "") if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)) - SSnanoui.update_uis(src) + return + if(length(input) < COMM_CCMSGLEN_MINIMUM) + to_chat(usr, "Message '[input]' is too short. [COMM_CCMSGLEN_MINIMUM] character minimum.") return Syndicate_announce(input, usr) to_chat(usr, "Message transmitted.") log_game("[key_name(usr)] has made a Syndicate announcement: [input]") - centcomm_message_cooldown = 1 - spawn(6000)//10 minute cooldown - centcomm_message_cooldown = 0 - setMenuState(usr,COMM_SCREEN_MAIN) + centcomm_message_cooldown = world.time + 6000 // 10 minutes + setMenuState(usr, COMM_SCREEN_MAIN) if("RestoreBackup") to_chat(usr, "Backup routing data restored!") src.emagged = 0 - setMenuState(usr,COMM_SCREEN_MAIN) + setMenuState(usr, COMM_SCREEN_MAIN) if("RestartNanoMob") if(SSmob_hunt) @@ -298,14 +292,13 @@ else to_chat(usr, "Nano-Mob Hunter GO! game server is offline for extended maintenance. Contact your Central Command administrators for more info if desired.") - SSnanoui.update_uis(src) - return 1 + /obj/machinery/computer/communications/emag_act(user as mob) if(!emagged) src.emagged = 1 to_chat(user, "You scramble the communication routing circuits!") - SSnanoui.update_uis(src) + SStgui.update_uis(src) /obj/machinery/computer/communications/attack_ai(var/mob/user as mob) return src.attack_hand(user) @@ -321,28 +314,25 @@ to_chat(user, "Unable to establish a connection: You're too far away from the station!") return - ui_interact(user) + tgui_interact(user) -/obj/machinery/computer/communications/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null) - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui) +/obj/machinery/computer/communications/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "comm_console.tmpl", "Communications Console", 400, 500) - // open the new ui window + ui = new(user, src, ui_key, "CommunicationsComputer", name, 500, 600, master_ui, state) ui.open() -/obj/machinery/computer/communications/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] +/obj/machinery/computer/communications/tgui_data(mob/user) + var/list/data = list() data["is_ai"] = isAI(user) || isrobot(user) data["menu_state"] = data["is_ai"] ? ai_menu_state : menu_state data["emagged"] = emagged data["authenticated"] = is_authenticated(user, 0) - data["screen"] = getMenuState(usr) + data["authmax"] = data["authenticated"] == COMM_AUTHENTICATION_MAX ? TRUE : FALSE data["stat_display"] = list( "type" = display_type, + "icon" = display_icon, "line_1" = (stat_msg1 ? stat_msg1 : "-----"), "line_2" = (stat_msg2 ? stat_msg2 : "-----"), @@ -360,12 +350,20 @@ ) ) - data["security_level"] = GLOB.security_level + data["security_level"] = GLOB.security_level + switch(GLOB.security_level) + if(SEC_LEVEL_GREEN) + data["security_level_color"] = "green"; + if(SEC_LEVEL_BLUE) + data["security_level_color"] = "blue"; + if(SEC_LEVEL_RED) + data["security_level_color"] = "red"; + else + data["security_level_color"] = "purple"; data["str_security_level"] = capitalize(get_security_level()) data["levels"] = list( - list("id" = SEC_LEVEL_GREEN, "name" = "Green"), - list("id" = SEC_LEVEL_BLUE, "name" = "Blue"), - //SEC_LEVEL_RED = list("name"="Red"), + list("id" = SEC_LEVEL_GREEN, "name" = "Green", "icon" = "dove"), + list("id" = SEC_LEVEL_BLUE, "name" = "Blue", "icon" = "eye"), ) var/list/msg_data = list() @@ -373,27 +371,30 @@ msg_data.Add(list(list("title" = messagetitle[i], "body" = messagetext[i], "id" = i))) data["messages"] = msg_data + + data["current_message"] = null + data["current_message_title"] = null if((data["is_ai"] && aicurrmsg) || (!data["is_ai"] && currmsg)) data["current_message"] = data["is_ai"] ? messagetext[aicurrmsg] : messagetext[currmsg] data["current_message_title"] = data["is_ai"] ? messagetitle[aicurrmsg] : messagetitle[currmsg] data["lastCallLoc"] = SSshuttle.emergencyLastCallLoc ? format_text(SSshuttle.emergencyLastCallLoc.name) : null + data["msg_cooldown"] = message_cooldown ? (round((message_cooldown - world.time) / 10)) : 0 + data["cc_cooldown"] = centcomm_message_cooldown ? (round((centcomm_message_cooldown - world.time) / 10)) : 0 - var/shuttle[0] - switch(SSshuttle.emergency.mode) - if(SHUTTLE_IDLE, SHUTTLE_RECALL) - shuttle["callStatus"] = 2 //#define - else - shuttle["callStatus"] = 1 - if(SSshuttle.emergency.mode == SHUTTLE_CALL) + var/secondsToRefuel = SSshuttle.secondsToRefuel() + data["esc_callable"] = SSshuttle.emergency.mode == SHUTTLE_IDLE && !secondsToRefuel ? TRUE : FALSE + data["esc_recallable"] = SSshuttle.emergency.mode == SHUTTLE_CALL ? TRUE : FALSE + data["esc_status"] = FALSE + if(SSshuttle.emergency.mode == SHUTTLE_CALL || SSshuttle.emergency.mode == SHUTTLE_RECALL) var/timeleft = SSshuttle.emergency.timeLeft() - shuttle["eta"] = "[timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]" - - data["shuttle"] = shuttle - + data["esc_status"] = SSshuttle.emergency.mode == SHUTTLE_CALL ? "ETA:" : "RECALLING:" + data["esc_status"] += " [timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]" + else if(secondsToRefuel) + data["esc_status"] = "Refueling: [secondsToRefuel / 60 % 60]:[add_zero(num2text(secondsToRefuel % 60), 2)]" + data["esc_section"] = data["esc_status"] || data["esc_callable"] || data["esc_recallable"] || data["lastCallLoc"] return data - /obj/machinery/computer/communications/proc/setCurrentMessage(var/mob/user,var/value) if(isAI(user) || isrobot(user)) aicurrmsg = value @@ -412,12 +413,6 @@ else menu_state=value -/obj/machinery/computer/communications/proc/getMenuState(var/mob/user) - if(isAI(user) || isrobot(user)) - return ai_menu_state - else - return menu_state - /proc/call_shuttle_proc(var/mob/user, var/reason) if(GLOB.sent_strike_team == 1) to_chat(user, "Central Command will not allow the shuttle to be called. Consider all contracts terminated.") @@ -521,24 +516,16 @@ SSshuttle.autoEvac() return ..() -/proc/print_command_report(text = "", title = "Central Command Update") +/proc/print_command_report(text = "", title = "Central Command Update", add_to_records = TRUE) for(var/obj/machinery/computer/communications/C in GLOB.shuttle_caller_list) if(!(C.stat & (BROKEN|NOPOWER)) && is_station_contact(C.z)) var/obj/item/paper/P = new /obj/item/paper(C.loc) P.name = "paper- '[title]'" P.info = text P.update_icon() - C.messagetitle.Add("[title]") - C.messagetext.Add(text) - for(var/datum/computer_file/program/comm/P in GLOB.shuttle_caller_list) - var/turf/T = get_turf(P.computer) - if(T && P.program_state != PROGRAM_STATE_KILLED && is_station_contact(T.z)) - if(P.computer) - var/obj/item/computer_hardware/printer/printer = P.computer.all_components[MC_PRINT] - if(printer) - printer.print_text(text, "paper- '[title]'") - P.messagetitle.Add("[title]") - P.messagetext.Add(text) + if(add_to_records) + C.messagetitle.Add("[title]") + C.messagetext.Add(text) /proc/print_centcom_report(text = "", title = "Incoming Message") for(var/obj/machinery/computer/communications/C in GLOB.shuttle_caller_list) @@ -549,12 +536,5 @@ P.update_icon() C.messagetitle.Add("[title]") C.messagetext.Add(text) - for(var/datum/computer_file/program/comm/P in GLOB.shuttle_caller_list) - var/turf/T = get_turf(P.computer) - if(T && P.program_state != PROGRAM_STATE_KILLED && is_admin_level(T.z)) - if(P.computer) - var/obj/item/computer_hardware/printer/printer = P.computer.all_components[MC_PRINT] - if(printer) - printer.print_text(text, "paper- '[title]'") - P.messagetitle.Add("[title]") - P.messagetext.Add(text) + + diff --git a/code/game/machinery/computer/law.dm b/code/game/machinery/computer/law.dm index 74cc417e7ce..d7987477a65 100644 --- a/code/game/machinery/computer/law.dm +++ b/code/game/machinery/computer/law.dm @@ -11,55 +11,57 @@ light_range_on = 2 - verb/AccessInternals() - set category = "Object" - set name = "Access Computer's Internals" - set src in oview(1) - if(get_dist(src, usr) > 1 || usr.restrained() || usr.lying || usr.stat || istype(usr, /mob/living/silicon)) - return - - opened = !opened - if(opened) - to_chat(usr, "The access panel is now open.") - else - to_chat(usr, "The access panel is now closed.") +// What the fuck even is this +/obj/machinery/computer/aiupload/verb/AccessInternals() + set category = "Object" + set name = "Access Computer's Internals" + set src in oview(1) + if(get_dist(src, usr) > 1 || usr.restrained() || usr.lying || usr.stat || istype(usr, /mob/living/silicon)) return + opened = !opened + if(opened) + to_chat(usr, "The access panel is now open.") + else + to_chat(usr, "The access panel is now closed.") + return - attackby(obj/item/O as obj, mob/user as mob, params) - if(istype(O, /obj/item/aiModule)) - if(!current)//no AI selected - to_chat(user, "No AI selected. Please chose a target before proceeding with upload.") - return - var/turf/T = get_turf(current) - if(!atoms_share_level(T, src)) - to_chat(user, "Unable to establish a connection: You're too far away from the target silicon!") - return - var/obj/item/aiModule/M = O - M.install(src) + +/obj/machinery/computer/aiupload/attackby(obj/item/O as obj, mob/user as mob, params) + if(istype(O, /obj/item/aiModule)) + if(!current)//no AI selected + to_chat(user, "No AI selected. Please chose a target before proceeding with upload.") return - return ..() - - - attack_hand(var/mob/user as mob) - if(src.stat & NOPOWER) - to_chat(usr, "The upload computer has no power!") - return - if(src.stat & BROKEN) - to_chat(usr, "The upload computer is broken!") + var/turf/T = get_turf(current) + if(!atoms_share_level(T, src)) + to_chat(user, "Unable to establish a connection: You're too far away from the target silicon!") return + var/obj/item/aiModule/M = O + M.install(src) + return + return ..() - src.current = select_active_ai(user) - if(!src.current) - to_chat(usr, "No active AIs detected.") - else - to_chat(usr, "[src.current.name] selected for law changes.") +/obj/machinery/computer/aiupload/attack_hand(var/mob/user as mob) + if(src.stat & NOPOWER) + to_chat(usr, "The upload computer has no power!") + return + if(src.stat & BROKEN) + to_chat(usr, "The upload computer is broken!") return - attack_ghost(user as mob) - return 1 + src.current = select_active_ai(user) + if(!src.current) + to_chat(usr, "No active AIs detected.") + else + to_chat(usr, "[src.current.name] selected for law changes.") + return + +/obj/machinery/computer/aiupload/attack_ghost(user as mob) + return 1 + +// Why is this not a subtype /obj/machinery/computer/borgupload name = "cyborg upload console" desc = "Used to upload laws to Cyborgs." @@ -69,35 +71,35 @@ var/mob/living/silicon/robot/current = null - attackby(obj/item/aiModule/module as obj, mob/user as mob, params) - if(istype(module, /obj/item/aiModule)) - if(!current)//no borg selected - to_chat(user, "No borg selected. Please chose a target before proceeding with upload.") - return - var/turf/T = get_turf(current) - if(!atoms_share_level(T, src)) - to_chat(user, "Unable to establish a connection: You're too far away from the target silicon!") - return - module.install(src) +/obj/machinery/computer/borgupload/attackby(obj/item/aiModule/module as obj, mob/user as mob, params) + if(istype(module, /obj/item/aiModule)) + if(!current)//no borg selected + to_chat(user, "No borg selected. Please chose a target before proceeding with upload.") return - return ..() - - - attack_hand(var/mob/user as mob) - if(src.stat & NOPOWER) - to_chat(usr, "The upload computer has no power!") - return - if(src.stat & BROKEN) - to_chat(usr, "The upload computer is broken!") + var/turf/T = get_turf(current) + if(!atoms_share_level(T, src)) + to_chat(user, "Unable to establish a connection: You're too far away from the target silicon!") return + module.install(src) + return + return ..() - src.current = freeborg() - if(!src.current) - to_chat(usr, "No free cyborgs detected.") - else - to_chat(usr, "[src.current.name] selected for law changes.") +/obj/machinery/computer/borgupload/attack_hand(var/mob/user as mob) + if(src.stat & NOPOWER) + to_chat(usr, "The upload computer has no power!") + return + if(src.stat & BROKEN) + to_chat(usr, "The upload computer is broken!") return - attack_ghost(user as mob) + src.current = freeborg() + + if(!src.current) + to_chat(usr, "No free cyborgs detected.") + else + to_chat(usr, "[src.current.name] selected for law changes.") + return + +/obj/machinery/computer/borgupload/attack_ghost(user as mob) return 1 diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index 6134860733a..f676d861f96 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -20,221 +20,210 @@ return if(stat & (NOPOWER|BROKEN)) return - ui_interact(user) + tgui_interact(user) -/obj/machinery/computer/robotics/proc/is_authenticated(var/mob/user as mob) +/obj/machinery/computer/robotics/proc/is_authenticated(mob/user) + if(!istype(user)) + return FALSE if(user.can_admin_interact()) - return 1 - else if(allowed(user)) - return 1 - return 0 + return TRUE + if(allowed(user)) + return TRUE + return FALSE -/obj/machinery/computer/robotics/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/** + * Does this borg show up in the console + * + * Returns TRUE if a robot will show up in the console + * Returns FALSE if a robot will not show up in the console + * Arguments: + * * R - The [mob/living/silicon/robot] to be checked + */ +/obj/machinery/computer/robotics/proc/console_shows(mob/living/silicon/robot/R) + if(!istype(R)) + return FALSE + if(istype(R, /mob/living/silicon/robot/drone)) + return FALSE + if(R.scrambledcodes) + return FALSE + if(!atoms_share_level(get_turf(src), get_turf(R))) + return FALSE + return TRUE + +/** + * Check if a user can send a lockdown/detonate command to a specific borg + * + * Returns TRUE if a user can send the command (does not guarantee it will work) + * Returns FALSE if a user cannot + * Arguments: + * * user - The [mob/user] to be checked + * * R - The [mob/living/silicon/robot] to be checked + * * telluserwhy - Bool of whether the user should be sent a to_chat message if they don't have access + */ +/obj/machinery/computer/robotics/proc/can_control(mob/user, mob/living/silicon/robot/R, telluserwhy = FALSE) + if(!istype(user)) + return FALSE + if(!console_shows(R)) + return FALSE + if(isAI(user)) + if(R.connected_ai != user) + if(telluserwhy) + to_chat(user, "AIs can only control cyborgs which are linked to them.") + return FALSE + if(isrobot(user)) + if(R != user) + if(telluserwhy) + to_chat(user, "Cyborgs cannot control other cyborgs.") + return FALSE + return TRUE + +/** + * Check if the user is the right kind of entity to be able to hack borgs + * + * Returns TRUE if a user is a traitor AI, or aghost + * Returns FALSE otherwise + * Arguments: + * * user - The [mob/user] to be checked + */ +/obj/machinery/computer/robotics/proc/can_hack_any(mob/user) + if(!istype(user)) + return FALSE + if(user.can_admin_interact()) + return TRUE + if(!isAI(user)) + return FALSE + return (user.mind.special_role && user.mind.original == user) + +/** + * Check if the user is allowed to hack a specific borg + * + * Returns TRUE if a user can hack the specific cyborg + * Returns FALSE if a user cannot + * Arguments: + * * user - The [mob/user] to be checked + * * R - The [mob/living/silicon/robot] to be checked + */ +/obj/machinery/computer/robotics/proc/can_hack(mob/user, mob/living/silicon/robot/R) + if(!can_hack_any(user)) + return FALSE + if(!istype(R)) + return FALSE + if(R.emagged) + return FALSE + if(R.connected_ai != user) + return FALSE + return TRUE + +/obj/machinery/computer/robotics/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "robot_control.tmpl", "Robotic Control Console", 400, 500) + ui = new(user, src, ui_key, "RoboticsControlConsole", name, 500, 460, master_ui, state) ui.open() - ui.set_auto_update(1) -/obj/machinery/computer/robotics/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - var/list/robots = get_cyborgs(user) - if(robots.len) - data["robots"] = robots +/obj/machinery/computer/robotics/tgui_data(mob/user) + var/list/data = list() + data["auth"] = is_authenticated(user) + data["can_hack"] = can_hack_any(user) + data["cyborgs"] = list() data["safety"] = safety - // Also applies for cyborgs. Hides the manual self-destruct button. - data["is_ai"] = issilicon(user) - data["allowed"] = is_authenticated(user) + for(var/mob/living/silicon/robot/R in GLOB.mob_list) + if(!console_shows(R)) + continue + var/area/A = get_area(R) + var/turf/T = get_turf(R) + var/list/cyborg_data = list( + name = R.name, + uid = R.UID(), + locked_down = R.lockcharge, + locstring = "[A.name] ([T.x], [T.y])", + status = R.stat, + health = round(R.health * 100 / R.maxHealth, 0.1), + charge = R.cell ? round(R.cell.percent()) : null, + cell_capacity = R.cell ? R.cell.maxcharge : null, + module = R.module ? R.module.name : "No Module Detected", + synchronization = R.connected_ai, + is_hacked = R.connected_ai && R.emagged, + hackable = can_hack(user, R), + ) + data["cyborgs"] += list(cyborg_data) + data["show_detonate_all"] = (data["auth"] && length(data["cyborgs"]) > 0 && ishuman(user)) return data -/obj/machinery/computer/robotics/Topic(href, href_list) +/obj/machinery/computer/robotics/tgui_act(action, params) if(..()) - return 1 - - var/mob/user = usr - if(!is_authenticated(user)) - to_chat(user, "Access denied.") return - - // Destroys the cyborg - if(href_list["detonate"]) - var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["detonate"]) - if(!target || !istype(target)) - return - if(isAI(user) && (target.connected_ai != user)) - to_chat(user, "Access Denied. This robot is not linked to you.") - return - // Cyborgs may blow up themselves via the console - if((isrobot(user) && user != target) || !is_authenticated(user)) - to_chat(user, "Access Denied.") - return - var/choice = input("Really detonate [target.name]?") in list ("Yes", "No") - if(choice != "Yes") - return - if(!target || !istype(target)) - return - - // Antagonistic cyborgs? Left here for downstream - if(target.mind && target.mind.special_role && target.emagged) - to_chat(target, "Extreme danger. Termination codes detected. Scrambling security codes and automatic AI unlink triggered.") - target.ResetSecurityCodes() - else - message_admins("[key_name_admin(usr)] detonated [key_name_admin(target)] (JMP)!") - log_game("\[key_name(usr)] detonated [key_name(target)]!") - to_chat(target, "Self-destruct command received.") - if(target.connected_ai) - to_chat(target.connected_ai, "

ALERT - Cyborg detonation detected: [target.name]
") - spawn(10) - target.self_destruct() - - // Locks or unlocks the cyborg - else if(href_list["lockdown"]) - var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["lockdown"]) - if(!target || !istype(target)) - return - - if(isAI(user) && (target.connected_ai != user)) - to_chat(user, "Access Denied. This robot is not linked to you.") - return - - if(isrobot(user)) - to_chat(user, "Access Denied.") - return - - var/choice = input("Really [target.lockcharge ? "unlock" : "lockdown"] [target.name] ?") in list ("Yes", "No") - if(choice != "Yes") - return - - if(!target || !istype(target)) - return - - message_admins("[key_name_admin(usr)] [target.canmove ? "locked down" : "released"] [key_name_admin(target)]!") - log_game("[key_name(usr)] [target.canmove ? "locked down" : "released"] [key_name(target)]!") - target.SetLockdown(!target.lockcharge) - to_chat(target, "[!target.lockcharge ? "Your lockdown has been lifted!" : "You have been locked down!"]") - if(target.connected_ai) - to_chat(target.connected_ai, "[!target.lockcharge ? "NOTICE - Cyborg lockdown lifted" : "ALERT - Cyborg lockdown detected"]: [target.name]

") - - // Remotely hacks the cyborg. Only antag AIs can do this and only to linked cyborgs. - else if(href_list["hack"]) - var/mob/living/silicon/robot/target = get_cyborg_by_name(href_list["hack"]) - if(!target || !istype(target)) - return - - // Antag AI checks - if(!istype(user, /mob/living/silicon/ai) || !(user.mind.special_role && user.mind.original == user)) - to_chat(user, "Access Denied.") - return - - if(target.connected_ai != user) - to_chat(user, "Access Denied. This robot is not linked to you.") - return - - if(target.emagged) - to_chat(user, "Robot is already hacked.") - return - - var/choice = input("Really hack [target.name]? This cannot be undone.") in list("Yes", "No") - if(choice != "Yes") - return - - if(!target || !istype(target)) - return - - message_admins("[key_name_admin(usr)] emagged [key_name_admin(target)] using robotic console!") - log_game("[key_name(usr)] emagged [key_name(target)] using robotic console!") - target.emagged = 1 - to_chat(target, "Failsafe protocols overriden. New tools available.") - - // Arms the emergency self-destruct system - else if(href_list["arm"]) - if(istype(user, /mob/living/silicon)) - to_chat(user, "Access Denied.") - return - - safety = !safety - to_chat(user, "You [safety ? "disarm" : "arm"] the emergency self destruct.") - - // Destroys all accessible cyborgs if safety is disabled - else if(href_list["nuke"]) - if(istype(user, /mob/living/silicon)) - to_chat(user, "Access Denied") - return - if(safety) - to_chat(user, "Self-destruct aborted - safety active") - return - - message_admins("[key_name_admin(usr)] detonated all cyborgs!") - log_game("\[key_name(usr)] detonated all cyborgs!") - - for(var/mob/living/silicon/robot/R in GLOB.mob_list) - if(istype(R, /mob/living/silicon/robot/drone)) - continue - // Ignore antagonistic cyborgs - if(R.scrambledcodes) - continue + . = FALSE + if(!is_authenticated(usr)) + to_chat(usr, "Access denied.") + return + switch(action) + if("arm") // Arms the emergency self-destruct system + if(issilicon(usr)) + to_chat(usr, "Access Denied (silicon detected)") + return + safety = !safety + to_chat(usr, "You [safety ? "disarm" : "arm"] the emergency self destruct.") + . = TRUE + if("nuke") // Destroys all accessible cyborgs if safety is disabled + if(issilicon(usr)) + to_chat(usr, "Access Denied (silicon detected)") + return + if(safety) + to_chat(usr, "Self-destruct aborted - safety active") + return + message_admins("[key_name_admin(usr)] detonated all cyborgs!") + log_game("\[key_name(usr)] detonated all cyborgs!") + for(var/mob/living/silicon/robot/R in GLOB.mob_list) + if(istype(R, /mob/living/silicon/robot/drone)) + continue + // Ignore antagonistic cyborgs + if(R.scrambledcodes) + continue + to_chat(R, "Self-destruct command received.") + if(R.connected_ai) + to_chat(R.connected_ai, "

ALERT - Cyborg detonation detected: [R.name]
") + R.self_destruct() + . = TRUE + if("killbot") // destroys one specific cyborg + var/mob/living/silicon/robot/R = locateUID(params["uid"]) + if(!can_control(usr, R, TRUE)) + return + if(R.mind && R.mind.special_role && R.emagged) + to_chat(R, "Extreme danger! Termination codes detected. Scrambling security codes and automatic AI unlink triggered.") + R.ResetSecurityCodes() + . = TRUE + return + var/turf/T = get_turf(R) + message_admins("[key_name_admin(usr)] detonated [key_name_admin(R)] ([ADMIN_COORDJMP(T)])!") + log_game("\[key_name(usr)] detonated [key_name(R)]!") to_chat(R, "Self-destruct command received.") if(R.connected_ai) to_chat(R.connected_ai, "

ALERT - Cyborg detonation detected: [R.name]
") - spawn(10) - R.self_destruct() - -// Proc: get_cyborgs() -// Parameters: 1 (operator - mob which is operating the console.) -// Description: Returns NanoUI-friendly list of accessible cyborgs. -/obj/machinery/computer/robotics/proc/get_cyborgs(var/mob/operator) - var/list/robots = list() - - for(var/mob/living/silicon/robot/R in GLOB.mob_list) - // Ignore drones - if(istype(R, /mob/living/silicon/robot/drone)) - continue - // Ignore antagonistic cyborgs - if(R.scrambledcodes) - continue - - var/list/robot = list() - robot["name"] = R.name - if(R.stat) - robot["status"] = "Not Responding" - else if(!R.canmove) - robot["status"] = "Lockdown" - else - robot["status"] = "Operational" - - if(R.cell) - robot["cell"] = 1 - robot["cell_capacity"] = R.cell.maxcharge - robot["cell_current"] = R.cell.charge - robot["cell_percentage"] = round(R.cell.percent()) - else - robot["cell"] = 0 - - var/turf/pos = get_turf(R) - var/area/bot_area = get_area(R) - robot["xpos"] = pos.x - robot["ypos"] = pos.y - robot["zpos"] = pos.z - robot["area"] = format_text(bot_area.name) - - robot["health"] = round(R.health * 100 / R.maxHealth,0.1) - - robot["module"] = R.module ? R.module.name : "None" - robot["master_ai"] = R.connected_ai ? R.connected_ai.name : "None" - robot["hackable"] = 0 - // Antag AIs know whether linked cyborgs are hacked or not. - if(operator && istype(operator, /mob/living/silicon/ai) && (R.connected_ai == operator) && (operator.mind.special_role && operator.mind.original == operator)) - robot["hacked"] = R.emagged ? 1 : 0 - robot["hackable"] = R.emagged? 0 : 1 - robots.Add(list(robot)) - return robots - -// Proc: get_cyborg_by_name() -// Parameters: 1 (name - Cyborg we are trying to find) -// Description: Helper proc for finding cyborg by name -/obj/machinery/computer/robotics/proc/get_cyborg_by_name(var/name) - if(!name) - return - for(var/mob/living/silicon/robot/R in GLOB.mob_list) - if(R.name == name) - return R + R.self_destruct() + . = TRUE + if("stopbot") // lock or unlock the borg + if(isrobot(usr)) + to_chat(usr, "Access Denied.") + return + var/mob/living/silicon/robot/R = locateUID(params["uid"]) + if(!can_control(usr, R, TRUE)) + return + message_admins("[ADMIN_LOOKUPFLW(usr)] [!R.lockcharge ? "locked down" : "released"] [ADMIN_LOOKUPFLW(R)]!") + log_game("[key_name(usr)] [!R.lockcharge ? "locked down" : "released"] [key_name(R)]!") + R.SetLockdown(!R.lockcharge) + to_chat(R, "[!R.lockcharge ? "Your lockdown has been lifted!" : "You have been locked down!"]") + if(R.connected_ai) + to_chat(R.connected_ai, "[!R.lockcharge ? "NOTICE - Cyborg lockdown lifted" : "ALERT - Cyborg lockdown detected"]: [R.name]
") + . = TRUE + if("hackbot") // AIs hacking/emagging a borg + var/mob/living/silicon/robot/R = locateUID(params["uid"]) + if(!can_hack(usr, R)) + return + var/choice = input("Really hack [R.name]? This cannot be undone.") in list("Yes", "No") + if(choice != "Yes") + return + log_game("[key_name(usr)] emagged [key_name(R)] using robotic console!") + message_admins("[key_name_admin(usr)] emagged [key_name_admin(R)] using robotic console!") + R.emagged = TRUE + to_chat(R, "Failsafe protocols overriden. New tools available.") + . = TRUE diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm index ba8f430937c..70798c0b92e 100644 --- a/code/game/machinery/cryo.dm +++ b/code/game/machinery/cryo.dm @@ -27,12 +27,13 @@ var/running_bob_animation = 0 // This is used to prevent threads from building up if update_icons is called multiple times light_color = LIGHT_COLOR_WHITE - power_change() - ..() - if(!(stat & (BROKEN|NOPOWER))) - set_light(2) - else - set_light(0) + +/obj/machinery/atmospherics/unary/cryo_cell/power_change() + ..() + if(!(stat & (BROKEN|NOPOWER))) + set_light(2) + else + set_light(0) /obj/machinery/atmospherics/unary/cryo_cell/New() ..() diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index fecd006886e..a13f87845ff 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -784,6 +784,9 @@ if(free_cryopods.len) target_cryopod = safepick(free_cryopods) if(target_cryopod.check_occupant_allowed(person_to_cryo)) + var/turf/T = get_turf(person_to_cryo) + var/obj/effect/portal/SP = new /obj/effect/portal(T, null, null, 40) + SP.name = "NT SSD Teleportation Portal" target_cryopod.take_occupant(person_to_cryo, 1) return 1 return 0 diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 3f074c9051d..27c37f19c1a 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1261,8 +1261,10 @@ About the new airlock wires panel: return 1 /obj/machinery/door/airlock/emp_act(severity) - ..() - if(prob(40/severity)) + . = ..() + if(prob(20 / severity)) + open() + if(prob(40 / severity)) var/duration = world.time + (30 / severity) SECONDS if(duration > electrified_until) electrify(duration) diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index 36eba1a6ee5..a4cacc19abd 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -36,9 +36,10 @@ var/crimes = CELL_NONE var/time = 0 var/officer = CELL_NONE - var/prisoner_name = "" - var/prisoner_charge = "" - var/prisoner_time = "" + var/prisoner_name + var/prisoner_charge + var/prisoner_time + var/prisoner_hasrecord = FALSE /obj/machinery/door_timer/New() GLOB.celltimers_list += src @@ -82,10 +83,15 @@ var/datum/data/record/R = find_security_record("name", occupant) - var/announcetext = "Detainee [occupant] ([prisoner_drank]) has been incarcerated for [seconds_to_time(timetoset / 10)] for the charges of: '[crimes]'. \ + var/timetext = seconds_to_time(timetoset / 10) + var/announcetext = "Detainee [occupant] ([prisoner_drank]) has been incarcerated for [timetext] for the crime of: '[crimes]'. \ Arresting Officer: [usr.name].[R ? "" : " Detainee record not found, manual record update required."]" Radio.autosay(announcetext, name, "Security", list(z)) + // Notify the actual criminal being brigged. This is a QOL thing to ensure they always know the charges against them. + // Announcing it on radio isn't enough, as they're unlikely to have sec radio. + notify_prisoner("You have been incarcerated for [timetext] for the crime of: '[crimes]'.") + if(prisoner_trank != "unknown" && prisoner_trank != "Civilian") SSjobs.notify_dept_head(prisoner_trank, announcetext) @@ -104,6 +110,13 @@ update_all_mob_security_hud() return 1 +/obj/machinery/door_timer/proc/notify_prisoner(notifytext) + for(var/mob/living/carbon/human/H in range(4, get_turf(src))) + if(occupant == H.name) + to_chat(H, "[src] beeps, \"[notifytext]\"") + return + atom_say("[src] beeps, \"[occupant]: [notifytext]\"") + /obj/machinery/door_timer/Initialize() ..() @@ -224,8 +237,7 @@ for(var/obj/machinery/door/window/brigdoor/door in targets) if(!door.density) continue - spawn(0) - door.open() + INVOKE_ASYNC(door, /obj/machinery/door/window/brigdoor.proc/open) for(var/obj/structure/closet/secure_closet/brig/C in targets) if(C.broken) @@ -261,13 +273,11 @@ return -//Allows AIs to use door_timer, see human attack_hand function below /obj/machinery/door_timer/attack_ai(mob/user) - attack_hand(user) - ui_interact(user) + tgui_interact(user) /obj/machinery/door_timer/attack_ghost(mob/user) - ui_interact(user) + tgui_interact(user) //Allows humans to use door_timer //Opens dialog window when someone clicks on door timer @@ -276,71 +286,109 @@ /obj/machinery/door_timer/attack_hand(mob/user) if(..()) return - ui_interact(user) + tgui_interact(user) -/obj/machinery/door_timer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/door_timer/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "brig_timer.tmpl", "Brig Timer", 500, 400) + ui = new(user, src, ui_key, "BrigTimer", name, 500, 450, master_ui, state) ui.open() - ui.set_auto_update(TRUE) -/obj/machinery/door_timer/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] +/obj/machinery/door_timer/tgui_static_data(mob/user) + var/list/data = list() + data["spns"] = list() + for(var/mob/living/carbon/human/H in range(4, get_turf(src))) + if(H.handcuffed) + data["spns"] += H.name + return data + +/obj/machinery/door_timer/tgui_data(mob/user) + var/list/data = list() data["cell_id"] = name data["occupant"] = occupant data["crimes"] = crimes data["brigged_by"] = officer - data["time_set"] = seconds_to_clock(time / 10) + data["time_set"] = seconds_to_clock(timetoset / 10) data["time_left"] = seconds_to_clock(timeleft()) data["timing"] = timing data["isAllowed"] = allowed(user) data["prisoner_name"] = prisoner_name data["prisoner_charge"] = prisoner_charge data["prisoner_time"] = prisoner_time - + data["prisoner_hasrec"] = prisoner_hasrecord return data -/obj/machinery/door_timer/Topic(href, href_list) - if(!allowed(usr) && !usr.can_admin_interact()) - return 1 +/obj/machinery/door_timer/allowed(mob/user) + if(user.can_admin_interact()) + return TRUE + return ..() - if(href_list["flash"]) - for(var/obj/machinery/flasher/F in targets) - if(F.last_flash && (F.last_flash + 150) > world.time) - to_chat(usr, "Flash still charging.") +/obj/machinery/door_timer/tgui_act(action, params) + if(..()) + return + if(!allowed(usr)) + to_chat(usr, "Access denied.") + return + . = TRUE + switch(action) + if("prisoner_name") + if(params["prisoner_name"]) + prisoner_name = params["prisoner_name"] else - F.flash() - - if(href_list["release"]) - if(timing) - timer_end() - Radio.autosay("Timer stopped manually from cell control.", name, "Security", list(z)) - ui_interact(usr) - - if(href_list["prisoner_name"]) - prisoner_name = input("Prisoner Name:", name, prisoner_name) as text|null - - if(href_list["prisoner_charge"]) - prisoner_charge = input("Prisoner Charge:", name, prisoner_charge) as text|null - - if(href_list["prisoner_time"]) - prisoner_time = input("Prisoner Time (in minutes):", name, prisoner_time) as num|null - prisoner_time = min(max(round(prisoner_time), 0), 60) - - if(href_list["set_timer"]) - if(!prisoner_name || !prisoner_charge || !prisoner_time) - return - timeset(prisoner_time * 60) - occupant = prisoner_name - crimes = prisoner_charge - prisoner_name = "" - prisoner_charge = "" - prisoner_time = "" - timing = TRUE - timer_start() - ui_interact(usr) - update_icon() + prisoner_name = input("Prisoner Name:", name, prisoner_name) as text|null + if(prisoner_name) + var/datum/data/record/R = find_security_record("name", prisoner_name) + if(istype(R)) + prisoner_hasrecord = TRUE + else + prisoner_hasrecord = FALSE + if("prisoner_charge") + prisoner_charge = input("Prisoner Charge:", name, prisoner_charge) as text|null + if("prisoner_time") + prisoner_time = input("Prisoner Time (in minutes):", name, prisoner_time) as num|null + prisoner_time = min(max(round(prisoner_time), 0), 60) + if("start") + if(!prisoner_name || !prisoner_charge || !prisoner_time) + return FALSE + timeset(prisoner_time * 60) + occupant = prisoner_name + crimes = prisoner_charge + prisoner_name = null + prisoner_charge = null + prisoner_time = null + timing = TRUE + timer_start() + update_icon() + if("restart_timer") + if(timing) + var/reset_reason = sanitize(copytext(input(usr, "Reason for resetting timer:", name, "") as text|null, 1, MAX_MESSAGE_LEN)) + if(!reset_reason) + to_chat(usr, "Cancelled reset: reason field is required.") + return FALSE + releasetime = world.timeofday + timetoset + var/resettext = isobserver(usr) ? "for: [reset_reason]." : "by [usr.name] for: [reset_reason]." + Radio.autosay("Prisoner [occupant] had their timer reset [resettext]", name, "Security", list(z)) + notify_prisoner("Your brig timer has been reset for: '[reset_reason]'.") + var/datum/data/record/R = find_security_record("name", occupant) + if(istype(R)) + R.fields["comments"] += "Autogenerated by [name] on [GLOB.current_date_string] [station_time_timestamp()]
Timer reset [resettext]" + else + . = FALSE + if("stop") + if(timing) + timer_end() + var/stoptext = isobserver(usr) ? "from cell control." : "by [usr.name]." + Radio.autosay("Timer stopped manually [stoptext]", name, "Security", list(z)) + else + . = FALSE + if("flash") + for(var/obj/machinery/flasher/F in targets) + if(F.last_flash && (F.last_flash + 150) > world.time) + to_chat(usr, "Flash still charging.") + else + F.flash() + else + . = FALSE //icon update function diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 2d6fac3bb81..4ed92910c5a 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -234,12 +234,6 @@ emagged = 1 return 1 -/obj/machinery/door/emp_act(severity) - if(prob(20/severity) && (istype(src,/obj/machinery/door/airlock) || istype(src,/obj/machinery/door/window)) ) - spawn(0) - open() - ..() - /obj/machinery/door/update_icon() if(density) icon_state = "door1" diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index e423f92683c..f27d4bf34a8 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -57,6 +57,11 @@ if(emagged) . += "Its access panel is smoking slightly." +/obj/machinery/door/window/emp_act(severity) + . = ..() + if(prob(20 / severity)) + open() + /obj/machinery/door/window/proc/open_and_close() open() if(check_access(null)) diff --git a/code/game/machinery/embedded_controller/airlock_program.dm b/code/game/machinery/embedded_controller/airlock_program.dm index 8ad85a608f0..d9500e30808 100644 --- a/code/game/machinery/embedded_controller/airlock_program.dm +++ b/code/game/machinery/embedded_controller/airlock_program.dm @@ -305,7 +305,7 @@ signalDoor(tag_exterior_door, command) signalDoor(tag_interior_door, command) -datum/computer/file/embedded_program/airlock/proc/signal_mech_sensor(var/command, var/sensor) +/datum/computer/file/embedded_program/airlock/proc/signal_mech_sensor(var/command, var/sensor) var/datum/signal/signal = new signal.data["tag"] = sensor signal.data["command"] = command diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index b387f404d8c..911f85be753 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -33,6 +33,7 @@ FIRE ALARM var/last_process = 0 var/wiresexposed = 0 var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone + var/enabled = FALSE var/report_fire_alarms = TRUE // Should triggered fire alarms also trigger an actual alarm? var/show_alert_level = TRUE // Should fire alarms display the current alert level? diff --git a/code/game/machinery/floodlight.dm b/code/game/machinery/floodlight.dm index 0cc6dda7098..b4babfbabfd 100644 --- a/code/game/machinery/floodlight.dm +++ b/code/game/machinery/floodlight.dm @@ -146,3 +146,4 @@ /obj/machinery/floodlight/extinguish_light() on = 0 set_light(0) + update_icon() diff --git a/code/game/machinery/overview.dm b/code/game/machinery/overview.dm index 7165cceb1ff..7d8910d6ef5 100644 --- a/code/game/machinery/overview.dm +++ b/code/game/machinery/overview.dm @@ -342,13 +342,13 @@ return -proc/getr(col) +/proc/getr(col) return hex2num( copytext(col, 2,4)) -proc/getg(col) +/proc/getg(col) return hex2num( copytext(col, 4,6)) -proc/getb(col) +/proc/getb(col) return hex2num( copytext(col, 6)) diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm index 42452a9f8e2..a8c9710ff6c 100644 --- a/code/game/machinery/pipe/construction.dm +++ b/code/game/machinery/pipe/construction.dm @@ -106,10 +106,6 @@ else if(istype(make_from, /obj/machinery/atmospherics/unary/passive_vent)) src.pipe_type = PIPE_PASV_VENT - else if(istype(make_from, /obj/machinery/atmospherics/omni/mixer)) - src.pipe_type = PIPE_OMNI_MIXER - else if(istype(make_from, /obj/machinery/atmospherics/omni/filter)) - src.pipe_type = PIPE_OMNI_FILTER else if(istype(make_from, /obj/machinery/atmospherics/binary/circulator)) src.pipe_type = PIPE_CIRCULATOR @@ -259,7 +255,7 @@ return dir //dir|acw if(PIPE_CONNECTOR, PIPE_UVENT, PIPE_PASV_VENT, PIPE_SCRUBBER, PIPE_HEAT_EXCHANGE, PIPE_INJECTOR) return dir|flip - if(PIPE_MANIFOLD4W, PIPE_SUPPLY_MANIFOLD4W, PIPE_SCRUBBERS_MANIFOLD4W, PIPE_OMNI_MIXER, PIPE_OMNI_FILTER) + if(PIPE_MANIFOLD4W, PIPE_SUPPLY_MANIFOLD4W, PIPE_SCRUBBERS_MANIFOLD4W) return dir|flip|cw|acw if(PIPE_MANIFOLD, PIPE_SUPPLY_MANIFOLD, PIPE_SCRUBBERS_MANIFOLD) return flip|cw|acw @@ -317,7 +313,7 @@ dir = 1 else if(dir==8) dir = 4 - else if(pipe_type in list(PIPE_MANIFOLD4W, PIPE_SUPPLY_MANIFOLD4W, PIPE_SCRUBBERS_MANIFOLD4W, PIPE_OMNI_MIXER, PIPE_OMNI_FILTER)) + else if(pipe_type in list(PIPE_MANIFOLD4W, PIPE_SUPPLY_MANIFOLD4W, PIPE_SCRUBBERS_MANIFOLD4W)) dir = 2 /obj/item/pipe/attack_self(mob/user as mob) @@ -499,14 +495,6 @@ P.name = pipename P.on_construction(dir, pipe_dir, color) - if(PIPE_OMNI_MIXER) - var/obj/machinery/atmospherics/omni/mixer/P = new(loc) - P.on_construction(dir, pipe_dir, color) - - if(PIPE_OMNI_FILTER) - var/obj/machinery/atmospherics/omni/filter/P = new(loc) - P.on_construction(dir, pipe_dir, color) - user.visible_message( \ "[user] fastens the [src].", \ "You have fastened the [src].", \ diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index 2a476c215ef..37dd2c6d439 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -260,9 +260,9 @@ var/turf/bombturf = get_turf(src) var/area/A = get_area(bombturf) if(payload && !istype(payload, /obj/item/bombcore/training)) - msg_admin_attack("[key_name_admin(user)] has primed a [name] ([payload]) for detonation at [A.name] (JMP).", ATKLOG_FEW) log_game("[key_name(user)] has primed a [name] ([payload]) for detonation at [A.name] [COORD(bombturf)]") investigate_log("[key_name(user)] has has primed a [name] ([payload]) for detonation at [A.name] [COORD(bombturf)]", INVESTIGATE_BOMB) + add_attack_logs(user, src, "has primed a [name] ([payload]) for detonation", ATKLOG_FEW) payload.adminlog = "\The [src] that [key_name(user)] had primed detonated!" ///Bomb Subtypes/// @@ -652,8 +652,8 @@ var/turf/T = get_turf(src) var/area/A = get_area(T) detonated-- - message_admins("[key_name_admin(user)] has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using a [name] at [A.name] (JMP).") investigate_log("[key_name(user)] has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using a [name] at [A.name] ([T.x],[T.y],[T.z])", INVESTIGATE_BOMB) + add_attack_logs(user, src, "has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using", ATKLOG_FEW) log_game("[key_name(user)] has remotely detonated [detonated ? "syndicate bombs" : "a syndicate bomb"] using a [name] at [A.name] ([T.x],[T.y],[T.z])") detonated = 0 existant = 0 diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 59bae3174c4..005e6720b8b 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -1,16 +1,24 @@ +#define REGIME_TELEPORT 0 +#define REGIME_GATE 1 +#define REGIME_GPS 2 + /obj/machinery/computer/teleporter name = "teleporter control console" desc = "Used to control a linked teleportation Hub and Station." icon_screen = "teleport" icon_keyboard = "teleport_key" circuit = /obj/item/circuitboard/teleporter - var/obj/item/gps/locked = null - var/regime_set = "Teleporter" + var/obj/item/gps/locked = null /// A GPS with a locked destination + var/regime = REGIME_TELEPORT /// Switches mode between teleporter, gate and gps var/id = null - var/obj/machinery/teleport/station/power_station - var/calibrating - var/turf/target //Used for one-time-use teleport cards (such as clown planet coordinates.) - //Setting this to 1 will set src.locked to null after a player enters the portal and will not allow hand-teles to open portals to that location. + var/obj/machinery/teleport/station/power_station /// The power station that's connected to the console + var/calibrating = FALSE /// Whether calibration is in progress or not. Calibration prevents changes. + var/turf/target ///The target turf of the teleporter + var/target_list ///lists of suitable teleport targets, dependent on regime. Used in the UI + + /* var/area_bypass is for one-time-use teleport cards (such as clown planet coordinates.) + Setting this to TRUE will set var/obj/item/gps/locked to null after a player enters the portal and will not allow hand-teles to open portals to that location. + */ var/area_bypass = FALSE var/cc_beacon = FALSE @@ -24,6 +32,7 @@ ..() link_power_station() update_icon() + target_list = targets_teleport() /obj/machinery/computer/teleporter/Destroy() if(power_station) @@ -55,202 +64,238 @@ /obj/machinery/computer/teleporter/emag_act(mob/user) if(!emagged) - emagged = 1 + emagged = TRUE to_chat(user, "The teleporter can now lock on to Syndicate beacons!") else - ui_interact(user) + tgui_interact(user) /obj/machinery/computer/teleporter/attack_ai(mob/user) - src.attack_hand(user) + attack_hand(user) /obj/machinery/computer/teleporter/attack_hand(mob/user) - ui_interact(user) + tgui_interact(user) -/obj/machinery/computer/teleporter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) + +/obj/machinery/computer/teleporter/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) if(stat & (NOPOWER|BROKEN)) return - - // Set up the Nano UI - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "teleporter_console.tmpl", "Teleporter Console UI", 400, 400) + ui = new(user, src, ui_key, "Teleporter", "Teleporter Console", 380, 260) ui.open() -/obj/machinery/computer/teleporter/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] +/obj/machinery/computer/teleporter/tgui_data(mob/user) + var/list/data = list() data["powerstation"] = power_station if(power_station?.teleporter_hub) data["teleporterhub"] = power_station.teleporter_hub data["calibrated"] = power_station.teleporter_hub.calibrated - data["accurate"] = power_station.teleporter_hub.accurate else data["teleporterhub"] = null data["calibrated"] = null - data["accurate"] = null - data["regime"] = regime_set + data["regime"] = regime var/area/targetarea = get_area(target) data["target"] = (!target || !targetarea) ? "None" : sanitize(targetarea.name) data["calibrating"] = calibrating - data["locked"] = locked + data["locked"] = locked ? TRUE : FALSE + data["targetsTeleport"] = target_list return data -/obj/machinery/computer/teleporter/Topic(href, href_list) +/obj/machinery/computer/teleporter/tgui_act(action, params) if(..()) - return 1 - - if(href_list["eject"]) - eject() - SSnanoui.update_uis(src) return if(!check_hub_connection()) - to_chat(usr, "Error: Unable to detect hub.") - SSnanoui.update_uis(src) + atom_say("Error: Unable to detect hub.") return if(calibrating) - to_chat(usr, "Error: Calibration in progress. Stand by.") - SSnanoui.update_uis(src) + atom_say("Error: Calibration in progress. Stand by.") return - if(href_list["regimeset"]) - power_station.engaged = 0 - power_station.teleporter_hub.update_icon() - power_station.teleporter_hub.calibrated = 0 - reset_regime() - SSnanoui.update_uis(src) - if(href_list["settarget"]) - power_station.engaged = 0 - power_station.teleporter_hub.update_icon() - power_station.teleporter_hub.calibrated = 0 - set_target(usr) - SSnanoui.update_uis(src) - if(href_list["lock"]) - power_station.engaged = 0 - power_station.teleporter_hub.update_icon() - power_station.teleporter_hub.calibrated = 0 - target = get_turf(locked.locked_location) - SSnanoui.update_uis(src) - if(href_list["calibrate"]) - if(!target) - to_chat(usr, "Error: No target set to calibrate to.") - SSnanoui.update_uis(src) - return - if(power_station.teleporter_hub.calibrated || power_station.teleporter_hub.accurate >= 3) - to_chat(usr, "Hub is already calibrated.") - SSnanoui.update_uis(src) - return - src.visible_message("Processing hub calibration to target...") + . = TRUE - calibrating = 1 - SSnanoui.update_uis(src) - spawn(50 * (3 - power_station.teleporter_hub.accurate)) //Better parts mean faster calibration - calibrating = 0 - if(check_hub_connection()) - power_station.teleporter_hub.calibrated = 1 - src.visible_message("Calibration complete.") - else - src.visible_message("Error: Unable to detect hub.") - SSnanoui.update_uis(src) + switch(action) + if("eject") //eject gps device + eject() + if("load") //load gps coordinates + target = locate(locked.locked_location.x,locked.locked_location.y,locked.locked_location.z) + if("setregime") + regime = text2num(params["regime"]) + if(regime == REGIME_TELEPORT) + target_list = targets_teleport() + if(regime == REGIME_GATE) + target_list = targets_gate() + if(regime == REGIME_GPS) + target_list = null //clears existing entries, target is added by load action + resetPowerstation() + target = null + if("settarget") + resetPowerstation() + var/turf/tmpTarget = locate(text2num(params["x"]),text2num(params["y"]),text2num(params["z"])) + if(!istype(tmpTarget, /turf)) + atom_say("No valid targets available.") + return + target = tmpTarget + if(regime == REGIME_TELEPORT) + teleport_helper() + if(regime == REGIME_GATE) + gate_helper() + if("calibrate") + if(!target) + atom_say("Error: No target set to calibrate to.") + return + if(power_station.teleporter_hub.calibrated || power_station.teleporter_hub.accurate >= 3) + atom_say("Hub is already calibrated.") + return - SSnanoui.update_uis(src) + atom_say("Processing hub calibration to target...") + calibrating = TRUE + addtimer(CALLBACK(src, .proc/calibrateCallback), 50 * (3 - power_station.teleporter_hub.accurate)) //Better parts mean faster calibration + +/** +* Resets the connected powerstation to initial values. Helper function of tgui_act +*/ +/obj/machinery/computer/teleporter/proc/resetPowerstation() + power_station.engaged = FALSE + power_station.teleporter_hub.calibrated = FALSE + power_station.teleporter_hub.update_icon() + +/** +* Calibrates the hub. Helper function of tgui_act +*/ +/obj/machinery/computer/teleporter/proc/calibrateCallback() + calibrating = FALSE + if(check_hub_connection()) + power_station.teleporter_hub.calibrated = TRUE + atom_say("Calibration complete.") + else + atom_say("Error: Unable to detect hub.") /obj/machinery/computer/teleporter/proc/check_hub_connection() if(!power_station) return if(!power_station.teleporter_hub) return - return 1 - -/obj/machinery/computer/teleporter/proc/reset_regime() - target = null - if(regime_set == "Teleporter") - regime_set = "Gate" - else - regime_set = "Teleporter" + return TRUE +/** +* Helper function of tgui_act +* +* Triggered when ejecting a gps device. Sets the gps to the ground and resets the console +*/ /obj/machinery/computer/teleporter/proc/eject() if(locked) locked.loc = loc locked = null + regime = REGIME_TELEPORT + target_list = targets_teleport() -/obj/machinery/computer/teleporter/proc/set_target(mob/user) - area_bypass = FALSE - if(regime_set == "Teleporter") - var/list/L = list() - var/list/areaindex = list() +/** +* Creates a list of viable targets for the teleport. Helper function of tgui_data +*/ +/obj/machinery/computer/teleporter/proc/targets_teleport() + var/list/L = list() + var/list/areaindex = list() - for(var/obj/item/radio/beacon/R in GLOB.beacons) - var/turf/T = get_turf(R) - if(!T) - continue - if(!is_teleport_allowed(T.z) && !R.cc_beacon) - continue - if(R.syndicate == 1 && emagged == 0) - continue - var/tmpname = T.loc.name + for(var/obj/item/radio/beacon/R in GLOB.beacons) + var/turf/T = get_turf(R) + if(!T) + continue + if(!is_teleport_allowed(T.z) && !R.cc_beacon) + continue + if(R.syndicate && !emagged) + continue + var/tmpname = T.loc.name + if(areaindex[tmpname]) + tmpname = "[tmpname] ([++areaindex[tmpname]])" + else + areaindex[tmpname] = 1 + L[tmpname] = list( + "name" = tmpname, + "x" = T.x, + "y" = T.y, + "z" = T.z) + + for(var/obj/item/implant/tracking/I in GLOB.tracked_implants) + if(!I.implanted || !ismob(I.loc)) + continue + else + var/mob/M = I.loc + if(M.stat == DEAD) + if(M.timeofdeath + 6000 < world.time) + continue + var/turf/T = get_turf(M) + if(!T) continue + if(!is_teleport_allowed(T.z)) continue + var/tmpname = M.real_name if(areaindex[tmpname]) tmpname = "[tmpname] ([++areaindex[tmpname]])" else areaindex[tmpname] = 1 - L[tmpname] = R + L[tmpname] = list( + "name" = tmpname, + "x" = T.x, + "y" = T.y, + "z" = T.z) + return L - for(var/obj/item/implant/tracking/I in GLOB.tracked_implants) - if(!I.implanted || !ismob(I.loc)) - continue - else - var/mob/M = I.loc - if(M.stat == DEAD) - if(M.timeofdeath + 6000 < world.time) - continue - var/turf/T = get_turf(M) - if(!T) continue - if(!is_teleport_allowed(T.z)) continue - var/tmpname = M.real_name - if(areaindex[tmpname]) - tmpname = "[tmpname] ([++areaindex[tmpname]])" - else - areaindex[tmpname] = 1 - L[tmpname] = I +/** +* Creates a list of viable targets for the gate. Helper function of tgui_data +*/ +/obj/machinery/computer/teleporter/proc/targets_gate(mob/users) + var/list/L = list() + var/list/areaindex = list() + var/list/S = power_station.linked_stations + if(!S.len) + return L + for(var/obj/machinery/teleport/station/R in S) + var/turf/T = get_turf(R) + if(!T || !R.teleporter_hub || !R.teleporter_console) + continue + if(!is_teleport_allowed(T.z)) + continue + var/tmpname = T.loc.name + if(areaindex[tmpname]) + tmpname = "[tmpname] ([++areaindex[tmpname]])" + else + areaindex[tmpname] = 1 + L[tmpname] = list( + "name" = tmpname, + "x" = T.x, + "y" = T.y, + "z" = T.z) + return L - var/desc = input("Please select a location to lock in.", "Locking Computer") in L - target = L[desc] - if(istype(target, /obj/item/radio/beacon)) - var/obj/item/radio/beacon/B = target +/** +* Helper function of tgui_act. +* +* Called after selecting a target for the gate in the UI. Sets area_bypass and cc_beacon. +*/ +/obj/machinery/computer/teleporter/proc/teleport_helper() + area_bypass = FALSE + for(var/item in target.contents) + if(istype(item, /obj/item/radio/beacon)) + var/obj/item/radio/beacon/B = item if(B.area_bypass) area_bypass = TRUE cc_beacon = B.cc_beacon - else - var/list/L = list() - var/list/areaindex = list() - var/list/S = power_station.linked_stations - if(!S.len) - to_chat(user, "No connected stations located.") - return - for(var/obj/machinery/teleport/station/R in S) - var/turf/T = get_turf(R) - if(!T || !R.teleporter_hub || !R.teleporter_console) - continue - if(!is_teleport_allowed(T.z)) - continue - var/tmpname = T.loc.name - if(areaindex[tmpname]) - tmpname = "[tmpname] ([++areaindex[tmpname]])" - else - areaindex[tmpname] = 1 - L[tmpname] = R - var/desc = input("Please select a station to lock in.", "Locking Computer") in L - target = L[desc] - if(target) - var/obj/machinery/teleport/station/trg = target - trg.linked_stations |= power_station - trg.stat &= ~NOPOWER - if(trg.teleporter_hub) - trg.teleporter_hub.stat &= ~NOPOWER - trg.teleporter_hub.update_icon() - if(trg.teleporter_console) - trg.teleporter_console.stat &= ~NOPOWER - trg.teleporter_console.update_icon() - return + +/** +* Helper function of tgui_act. +* +* Called after selecting a target for the teleporter in the UI. +*/ +/obj/machinery/computer/teleporter/proc/gate_helper() + area_bypass = FALSE + var/obj/machinery/teleport/station/trg = target + trg.linked_stations |= power_station + trg.stat &= ~NOPOWER + if(trg.teleporter_hub) + trg.teleporter_hub.stat &= ~NOPOWER + trg.teleporter_hub.update_icon() + if(trg.teleporter_console) + trg.teleporter_console.stat &= ~NOPOWER + trg.teleporter_console.update_icon() /proc/find_loc(obj/R as obj) if(!R) return null @@ -263,20 +308,20 @@ /obj/machinery/teleport name = "teleport" icon = 'icons/obj/stationobjs.dmi' - density = 1 - anchored = 1.0 + density = TRUE + anchored = TRUE /obj/machinery/teleport/hub name = "teleporter hub" desc = "It's the hub of a teleporting machine." icon_state = "tele0" - var/accurate = 0 + var/accurate = FALSE use_power = IDLE_POWER_USE idle_power_usage = 10 active_power_usage = 2000 var/obj/machinery/teleport/station/power_station var/calibrated //Calibration prevents mutation - var/admin_usage = 0 // if 1, works on z2. If 0, doesn't. Used for admin room teleport. + var/admin_usage = FALSE // if 1, works on z2. If 0, doesn't. Used for admin room teleport. /obj/machinery/teleport/hub/New() ..() @@ -317,6 +362,7 @@ for(dir in list(NORTH,EAST,SOUTH,WEST)) power_station = locate(/obj/machinery/teleport/station, get_step(src, dir)) if(power_station) + power_station.link_console_and_hub() break return power_station @@ -324,27 +370,12 @@ if(!is_teleport_allowed(z) && !admin_usage) to_chat(M, "You can't use this here.") return - if(power_station && power_station.engaged && !panel_open) - //--FalseIncarnate - //Prevents AI cores from using the teleporter, prints out failure messages for clarity - if(istype(M, /mob/living/silicon/ai) || istype(M, /obj/structure/AIcore)) - visible_message("The teleporter rejects the AI unit.") - if(istype(M, /mob/living/silicon/ai)) - var/mob/living/silicon/ai/T = M - var/list/TPError = list("Firmware instructions dictate you must remain on your assigned station!", - "You cannot interface with this technology and get rejected!", - "External firewalls prevent you from utilizing this machine!", - "Your AI core's anti-bluespace failsafes trigger and prevent teleportation!") - to_chat(T, "[pick(TPError)]") - return - else - if(!teleport(M) && isliving(M)) // the isliving(M) is needed to avoid triggering errors if a spark bumps the telehub - visible_message("[src] emits a loud buzz, as its teleport portal flickers and fails!") - playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) - power_station.toggle() // turn off the portal. - - use_power(5000) - //--FalseIncarnate + if(power_station && power_station.engaged && !panel_open && !blockAI(M) && !istype(M, /obj/spacepod)) + if(!teleport(M) && isliving(M)) // the isliving(M) is needed to avoid triggering errors if a spark bumps the telehub + visible_message("[src] emits a loud buzz, as its teleport portal flickers and fails!") + playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, FALSE) + power_station.toggle() // turn off the portal. + use_power(5000) return /obj/machinery/teleport/hub/attackby(obj/item/I, mob/user, params) @@ -375,7 +406,7 @@ . = do_teleport(M, locate(rand((2*TRANSITIONEDGE), world.maxx - (2*TRANSITIONEDGE)), rand((2*TRANSITIONEDGE), world.maxy - (2*TRANSITIONEDGE)), 3), 2, bypass_area_flag = com.area_bypass) else . = do_teleport(M, com.target, bypass_area_flag = com.area_bypass) - calibrated = 0 + calibrated = FALSE /obj/machinery/teleport/hub/update_icon() if(panel_open) @@ -389,7 +420,7 @@ name = "permanent teleporter" desc = "A teleporter with the target pre-set on the circuit board." icon_state = "tele0" - var/recalibrating = 0 + var/recalibrating = FALSE use_power = IDLE_POWER_USE idle_power_usage = 10 active_power_usage = 2000 @@ -406,37 +437,42 @@ tele_delay = max(A, 0) update_icon() -/obj/machinery/teleport/perma/Bumped(M as mob|obj) +/** + Internal helper function + + Prevents AI from using the teleporter, prints out failure messages for clarity +*/ +/obj/machinery/teleport/proc/blockAI(atom/A) + if(istype(A, /mob/living/silicon/ai) || istype(A, /obj/structure/AIcore)) + visible_message("The teleporter rejects the AI unit.") + if(istype(A, /mob/living/silicon/ai)) + var/mob/living/silicon/ai/T = A + var/list/TPError = list("Firmware instructions dictate you must remain on your assigned station!", + "You cannot interface with this technology and get rejected!", + "External firewalls prevent you from utilizing this machine!", + "Your AI core's anti-bluespace failsafes trigger and prevent teleportation!") + to_chat(T, "[pick(TPError)]") + return TRUE + return FALSE + +/obj/machinery/teleport/perma/Bumped(atom/A) if(stat & (BROKEN|NOPOWER)) return if(!is_teleport_allowed(z)) - to_chat(M, "You can't use this here.") + to_chat(A, "You can't use this here.") return - if(target && !recalibrating && !panel_open) - //--FalseIncarnate - //Prevents AI cores from using the teleporter, prints out failure messages for clarity - if(istype(M, /mob/living/silicon/ai) || istype(M, /obj/structure/AIcore)) - visible_message("The teleporter rejects the AI unit.") - if(istype(M, /mob/living/silicon/ai)) - var/mob/living/silicon/ai/T = M - var/list/TPError = list("Firmware instructions dictate you must remain on your assigned station!", - "You cannot interface with this technology and get rejected!", - "External firewalls prevent you from utilizing this machine!", - "Your AI core's anti-bluespace failsafes trigger and prevent teleportation!") - to_chat(T, "[pick(TPError)]") - return - else - do_teleport(M, target) - use_power(5000) - if(tele_delay) - recalibrating = 1 - update_icon() - spawn(tele_delay) - recalibrating = 0 - update_icon() - //--FalseIncarnate - return + if(target && !recalibrating && !panel_open && !blockAI(A)) + do_teleport(A, target) + use_power(5000) + if(tele_delay) + recalibrating = TRUE + update_icon() + addtimer(CALLBACK(src, .proc/BumpedCallback), tele_delay) + +/obj/machinery/teleport/perma/proc/BumpedCallback() + recalibrating = FALSE + update_icon() /obj/machinery/teleport/perma/power_change() ..() @@ -467,7 +503,7 @@ name = "station" desc = "The power control station for a bluespace teleporter." icon_state = "controller" - var/engaged = 0 + var/engaged = FALSE use_power = IDLE_POWER_USE idle_power_usage = 10 active_power_usage = 2000 @@ -568,7 +604,7 @@ /obj/machinery/teleport/station/attack_ai() - src.attack_hand() + attack_hand() /obj/machinery/teleport/station/attack_hand(mob/user) if(!panel_open) @@ -583,12 +619,12 @@ to_chat(user, "Close the hub's maintenance panel first.") return if(teleporter_console.target) - src.engaged = !src.engaged + engaged = !engaged use_power(5000) visible_message("Teleporter [engaged ? "" : "dis"]engaged!") else visible_message("No target detected.") - src.engaged = 0 + engaged = FALSE teleporter_hub.update_icon() if(istype(user)) add_fingerprint(user) diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index fdca5c56194..1ac341db260 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -11,9 +11,6 @@ var/max_amount = 0 var/price = 0 // Price to buy one -/** - * A vending machine - */ /obj/machinery/vending name = "\improper Vendomat" desc = "A generic vending machine." @@ -25,8 +22,10 @@ max_integrity = 300 integrity_failure = 100 armor = list(melee = 20, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 50, acid = 70) - var/icon_vend //Icon_state when vending - var/icon_deny //Icon_state when denying access + /// Icon_state when vending + var/icon_vend + /// Icon_state when denying access + var/icon_deny // Power use_power = IDLE_POWER_USE @@ -34,12 +33,14 @@ var/vend_power_usage = 150 // Vending-related - var/active = 1 //No sales pitches if off! - var/vend_ready = 1 //Are we ready to vend?? Is it time?? - var/vend_delay = 10 //How long does it take to vend? - var/datum/data/vending_product/currently_vending = null // What we're requesting payment for right now - var/status_message = "" // Status screen messages like "insufficient funds", displayed in NanoUI - var/status_error = 0 // Set to 1 if status_message is an error + /// No sales pitches if off + var/active = 1 + /// If off, vendor is busy and unusable until current action finishes + var/vend_ready = TRUE + /// How long vendor takes to vend one item. + var/vend_delay = 10 + /// Item currently being bought + var/datum/data/vending_product/currently_vending = null // To be filled out at compile time var/list/products = list() // For each, use the following pattern: @@ -51,16 +52,19 @@ var/list/product_records = list() var/list/hidden_records = list() var/list/coin_records = list() + var/list/imagelist = list() - - var/list/ads_list = list() //Small ad messages in the vending screen - random chance, TODO: implementation + /// Unimplemented list of ads that are meant to show up somewhere, but don't. + var/list/ads_list = list() // Stuff relating vocalizations - var/list/slogan_list = list() //List of slogans the vendor will say, optional + /// List of slogans the vendor will say, optional + var/list/slogan_list = list() var/vend_reply //Thank you for shopping! - var/shut_up = 0 //Stop spouting those godawful pitches! + /// If true, prevent saying sales pitches + var/shut_up = FALSE ///can we access the hidden inventory? - var/extended_inventory = 0 + var/extended_inventory = FALSE var/last_reply = 0 var/last_slogan = 0 //When did we last pitch? var/slogan_delay = 6000 //How long until we can pitch again? @@ -69,17 +73,26 @@ var/obj/item/vending_refill/refill_canister = null // Things that can go wrong - emagged = 0 //Ignores if somebody doesn't have card access to that machine. - var/seconds_electrified = 0 //Shock customers like an airlock. - var/shoot_inventory = 0 //Fire items at customers! We're broken! - var/shoot_speed = 3 //How hard are we firing the items? - var/shoot_chance = 2 //How often are we firing the items? + /// Allows people to access a vendor that's normally access restricted. + emagged = 0 + /// Shocks people like an airlock + var/seconds_electrified = 0 + /// Fire items at customers! We're broken! + var/shoot_inventory = FALSE + /// How hard are we firing the items? + var/shoot_speed = 3 + /// How often are we firing the items? (prob(...)) + var/shoot_chance = 2 - var/scan_id = 1 + /// If true, enforce access checks on customers. Disabled by messing with wires. + var/scan_id = TRUE + /// Holder for a coin inserted into the vendor var/obj/item/coin/coin var/datum/wires/vending/wires = null + /// boolean, whether this vending machine can accept people inserting items into it, used for coffee vendors var/item_slot = FALSE + /// the actual item inserted var/obj/item/inserted_item = null /obj/machinery/vending/Initialize(mapload) @@ -92,6 +105,10 @@ build_inventory(products, product_records) build_inventory(contraband, hidden_records) build_inventory(premium, coin_records) + for (var/datum/data/vending_product/R in (product_records + coin_records + hidden_records)) + var/obj/item/I = R.product_path + var/pp = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-") + imagelist[pp] = "[icon2base64(icon(initial(I.icon), initial(I.icon_state)))]" if(LAZYLEN(slogan_list)) // So not all machines speak at the exact same time. // The first time this machine says something will be at slogantime + this random value, @@ -214,37 +231,16 @@ ..() /obj/machinery/vending/attackby(obj/item/I, mob/user, params) - if(currently_vending && GLOB.vendor_account && !GLOB.vendor_account.suspended) - var/paid = 0 - var/handled = 0 - if(istype(I, /obj/item/card/id)) - var/obj/item/card/id/C = I - paid = pay_with_card(C) - handled = 1 - if(istype(I, /obj/item/pda)) - var/obj/item/pda/PDA = I - if(PDA.id) - paid = pay_with_card(PDA.id) - handled = 1 - else if(istype(I, /obj/item/stack/spacecash)) - var/obj/item/stack/spacecash/C = I - paid = pay_with_cash(C, user) - handled = 1 - - if(paid) - vend(currently_vending, usr) + if(istype(I, /obj/item/coin)) + if(!premium.len) + to_chat(user, "[src] does not accept coins.") return - else if(handled) - SSnanoui.update_uis(src) - return // don't smack that machine with your 2 thalers - - if(istype(I, /obj/item/coin) && premium.len) if(!user.drop_item()) return I.forceMove(src) coin = I to_chat(user, "You insert the [I] into the [src]") - SSnanoui.update_uis(src) + SStgui.update_uis(src) return if(refill_canister && istype(I, refill_canister)) if(!panel_open) @@ -295,7 +291,7 @@ else SCREWDRIVER_CLOSE_PANEL_MESSAGE overlays.Cut() - SSnanoui.update_uis(src) // Speaker switch is on the main UI, not wires UI + SStgui.update_uis(src) /obj/machinery/vending/wirecutter_act(mob/user, obj/item/I) . = TRUE @@ -359,12 +355,10 @@ if(!user.drop_item()) to_chat(user, "[I] is stuck to your hand, you can't seem to put it down!") return - inserted_item = I I.forceMove(src) - to_chat(user, "You insert [I] into [src].") - SSnanoui.update_uis(src) + SStgui.update_uis(src) /obj/machinery/vending/proc/eject_item(mob/user) if(!item_slot || !inserted_item) @@ -377,23 +371,19 @@ var/turf/T = get_turf(src) inserted_item.forceMove(T) inserted_item = null - SSnanoui.update_uis(src) + SStgui.update_uis(src) /obj/machinery/vending/emag_act(user as mob) emagged = TRUE to_chat(user, "You short out the product lock on [src]") -/** - * Receive payment with cashmoney. - * - * usr is the mob who gets the change. - */ + /obj/machinery/vending/proc/pay_with_cash(obj/item/stack/spacecash/cashmoney, mob/user) if(currently_vending.price > cashmoney.amount) // This is not a status display message, since it's something the character // themselves is meant to see BEFORE putting the money in to_chat(usr, "[bicon(cashmoney)] That is not enough money.") - return 0 + return FALSE // Bills (banknotes) cannot really have worth different than face value, // so we have to eat the bill and spit out change in a bundle @@ -405,50 +395,36 @@ // Vending machines have no idea who paid with cash GLOB.vendor_account.credit(currently_vending.price, "Sale of [currently_vending.name]", name, "(cash)") - return 1 + return TRUE -/** - * Scan a card and attempt to transfer payment from associated account. - * - * Takes payment for whatever is the currently_vending item. Returns 1 if - * successful, 0 if failed - */ -/obj/machinery/vending/proc/pay_with_card(var/obj/item/card/id/I) - visible_message("[usr] swipes a card through [src].") - return pay_with_account(get_card_account(I)) -/obj/machinery/vending/proc/pay_with_account(var/datum/money_account/customer_account) +/obj/machinery/vending/proc/pay_with_card(obj/item/card/id/I, mob/M) + visible_message("[M] swipes a card through [src].") + return pay_with_account(get_card_account(I), M) + +/obj/machinery/vending/proc/pay_with_account(datum/money_account/customer_account, mob/M) if(!customer_account) - src.status_message = "Error: Unable to access account. Please contact technical support if problem persists." - src.status_error = 1 - return 0 - + to_chat(M, "Error: Unable to access account. Please contact technical support if problem persists.") + return FALSE if(customer_account.suspended) - src.status_message = "Unable to access account: account suspended." - src.status_error = 1 - return 0 - - // Have the customer punch in the PIN before checking if there's enough money. Prevents people from figuring out acct is - // empty at high security levels - if(customer_account.security_level != 0) //If card requires pin authentication (ie seclevel 1 or 2) + to_chat(M, "Unable to access account: account suspended.") + return FALSE + // Have the customer punch in the PIN before checking if there's enough money. + // Prevents people from figuring out acct is empty at high security levels + if(customer_account.security_level != 0) + // If card requires pin authentication (ie seclevel 1 or 2) var/attempt_pin = input("Enter pin code", "Vendor transaction") as num - if(!attempt_account_access(customer_account.account_number, attempt_pin, 2)) - src.status_message = "Unable to access account: incorrect credentials." - src.status_error = 1 - return 0 - + to_chat(M, "Unable to access account: incorrect credentials.") + return FALSE if(currently_vending.price > customer_account.money) - src.status_message = "Insufficient funds in account." - src.status_error = 1 - return 0 - else - // Okay to move the money at this point - customer_account.charge(currently_vending.price, GLOB.vendor_account, - "Purchase of [currently_vending.name]", name, GLOB.vendor_account.owner_name, - "Sale of [currently_vending.name]", customer_account.owner_name) - - return TRUE + to_chat(M, "Your bank account has insufficient money to purchase this.") + return FALSE + // Okay to move the money at this point + customer_account.charge(currently_vending.price, GLOB.vendor_account, + "Purchase of [currently_vending.name]", name, GLOB.vendor_account.owner_name, + "Sale of [currently_vending.name]", customer_account.owner_name) + return TRUE /obj/machinery/vending/attack_ai(mob/user) @@ -465,174 +441,238 @@ if(src.shock(user, 100)) return - ui_interact(user) + tgui_interact(user) wires.Interact(user) -/** - * Display the NanoUI window for the vending machine. - * - * See NanoUI documentation for details. - */ -/obj/machinery/vending/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - user.set_machine(src) - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/vending/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "vending_machine.tmpl", src.name, 440, 600) + var/estimated_height = 100 + (length(product_records) * 34) + if(length(prices) > 0) + estimated_height += 100 // to account for the "current user" interface + ui = new(user, src, ui_key, "Vending", name, 470, estimated_height, master_ui, state) ui.open() -/obj/machinery/vending/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) +/obj/machinery/vending/tgui_data(mob/user) var/list/data = list() - if(currently_vending) - data["mode"] = 1 - data["product"] = sanitize(currently_vending.name) - data["price"] = currently_vending.price - data["message_err"] = 0 - data["message"] = src.status_message - data["message_err"] = src.status_error - else - data["mode"] = 0 - var/list/listed_products = list() - - var/list/display_records = product_records + coin_records - if(extended_inventory) - display_records = product_records + coin_records + hidden_records - - for(var/key = 1 to display_records.len) - var/datum/data/vending_product/I = display_records[key] - - if(coin_records.Find(I) && !coin) - continue - - if(hidden_records.Find(I) && !extended_inventory) - continue - - listed_products.Add(list(list( - "key" = key, - "name" = sanitize(I.name), - "price" = I.price, - "amount" = I.amount))) - - data["products"] = listed_products - - if(coin) - data["coin"] = coin.name - - if(item_slot) - data["item_slot"] = 1 - if(inserted_item) - data["inserted_item"] = inserted_item - else - data["inserted_item"] = null - else - data["item_slot"] = 0 - - if(panel_open) - data["panel"] = 1 - data["speaker"] = shut_up ? 0 : 1 - else - data["panel"] = 0 + var/mob/living/carbon/human/H + var/obj/item/card/id/C + data["guestNotice"] = "No valid ID card detected. Wear your ID, or present cash."; + data["userMoney"] = 0 + data["user"] = null + if(ishuman(user)) + H = user + C = H.get_idcard(TRUE) + var/obj/item/stack/spacecash/S = H.get_active_hand() + if(istype(S)) + data["userMoney"] = S.amount + data["guestNotice"] = "Accepting Cash. You have: [S.amount] credits." + else if(istype(C)) + var/datum/money_account/A = get_card_account(C) + if(istype(A)) + data["user"] = list() + data["user"]["name"] = A.owner_name + data["userMoney"] = A.money + data["user"]["job"] = (istype(C) && C.rank) ? C.rank : "No Job" + else + data["guestNotice"] = "Unlinked ID detected. Present cash to pay."; + data["stock"] = list() + for (var/datum/data/vending_product/R in product_records + coin_records + hidden_records) + data["stock"][R.name] = R.amount + data["extended_inventory"] = extended_inventory + data["vend_ready"] = vend_ready + data["coin_name"] = coin ? coin.name : FALSE + data["panel_open"] = panel_open ? TRUE : FALSE + data["speaker"] = shut_up ? FALSE : TRUE + data["item_slot"] = item_slot // boolean + data["inserted_item_name"] = inserted_item ? inserted_item.name : FALSE return data -/obj/machinery/vending/Topic(href, href_list) - if(..()) - return 1 - if(href_list["remove_coin"] && !istype(usr,/mob/living/silicon)) - if(!coin) - to_chat(usr, "There is no coin in this machine.") - return +/obj/machinery/vending/tgui_static_data(mob/user) + var/list/data = list() + data["chargesMoney"] = length(prices) > 0 ? TRUE : FALSE + data["product_records"] = list() + var/i = 1 + for (var/datum/data/vending_product/R in product_records) + var/list/data_pr = list( + path = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-"), + name = R.name, + price = (R.product_path in prices) ? prices[R.product_path] : 0, + max_amount = R.max_amount, + req_coin = FALSE, + is_hidden = FALSE, + inum = i + ) + data["product_records"] += list(data_pr) + i++ + data["coin_records"] = list() + for (var/datum/data/vending_product/R in coin_records) + var/list/data_cr = list( + path = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-"), + name = R.name, + price = (R.product_path in prices) ? prices[R.product_path] : 0, + max_amount = R.max_amount, + req_coin = TRUE, + is_hidden = FALSE, + inum = i, + premium = TRUE + ) + data["coin_records"] += list(data_cr) + i++ + data["hidden_records"] = list() + for (var/datum/data/vending_product/R in hidden_records) + var/list/data_hr = list( + path = replacetext(replacetext("[R.product_path]", "/obj/item/", ""), "/", "-"), + name = R.name, + price = (R.product_path in prices) ? prices[R.product_path] : 0, + max_amount = R.max_amount, + req_coin = FALSE, + is_hidden = TRUE, + inum = i, + premium = TRUE + ) + data["hidden_records"] += list(data_hr) + i++ + data["imagelist"] = imagelist + return data - usr.put_in_hands(coin) - coin = null - to_chat(usr, "You remove [coin] from [src].") +/obj/machinery/vending/tgui_act(action, params) + . = ..() + if(.) + 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 + switch(action) + if("toggle_voice") + if(panel_open) + shut_up = !shut_up + . = TRUE + if("eject_item") + eject_item(usr) + . = TRUE + if("remove_coin") + if(!coin) + to_chat(usr, "There is no coin in this machine.") + return + if(istype(usr, /mob/living/silicon)) + to_chat(usr, "You lack hands.") + return + to_chat(usr, "You remove [coin] from [src].") + usr.put_in_hands(coin) + coin = null + . = TRUE + if("vend") + if(!vend_ready) + to_chat(usr, "The vending machine is busy!") + return + if(panel_open) + to_chat(usr, "The vending machine cannot dispense products while its service panel is open!") + return + var/key = text2num(params["inum"]) + var/list/display_records = product_records + coin_records + if(extended_inventory) + display_records = product_records + coin_records + hidden_records + if(key < 1 || key > length(display_records)) + to_chat(usr, "ERROR: invalid inum passed to vendor. Report this bug.") + return + var/datum/data/vending_product/R = display_records[key] + if(!istype(R)) + to_chat(usr, "ERROR: unknown vending_product record. Report this bug.") + return + var/list/record_to_check = product_records + coin_records + if(extended_inventory) + record_to_check = product_records + coin_records + hidden_records + if(!R || !istype(R) || !R.product_path) + to_chat(usr, "ERROR: unknown product record. Report this bug.") + return + if(R in hidden_records) + if(!extended_inventory) + // Exploit prevention, stop the user purchasing hidden stuff if they haven't hacked the machine. + to_chat(usr, "ERROR: machine does not allow extended_inventory in current state. Report this bug.") + return + else if (!(R in record_to_check)) + // Exploit prevention, stop the user + message_admins("Vending machine exploit attempted by [ADMIN_LOOKUPFLW(usr)]!") + return + if (R.amount <= 0) + to_chat(usr, "Sold out of [R.name].") + flick(icon_deny, src) + return - if(href_list["remove_item"]) - eject_item(usr) + vend_ready = FALSE // From this point onwards, vendor is locked to performing this transaction only, until it is resolved. - if(href_list["pay"]) - if(currently_vending && GLOB.vendor_account && !GLOB.vendor_account.suspended) - var/paid = 0 - var/handled = 0 - var/datum/money_account/A = usr.get_worn_id_account() - if(A) - paid = pay_with_account(A) - handled = 1 - else if(istype(usr.get_active_hand(), /obj/item/card)) - paid = pay_with_card(usr.get_active_hand()) - handled = 1 - else if(usr.can_admin_interact()) - paid = 1 - handled = 1 + if(!ishuman(usr) || R.price <= 0) + // Either the purchaser is not human, or the item is free. + // Skip all payment logic. + vend(R, usr) + add_fingerprint(usr) + vend_ready = TRUE + . = TRUE + return + + // --- THE REST OF THIS PROC IS JUST PAYMENT LOGIC --- + + var/mob/living/carbon/human/H = usr + var/obj/item/card/id/C = H.get_idcard(TRUE) + + if(!GLOB.vendor_account || GLOB.vendor_account.suspended) + to_chat(usr, "Vendor account offline. Unable to process transaction.") + flick(icon_deny, src) + vend_ready = TRUE + return + + currently_vending = R + var/paid = FALSE + + if(istype(usr.get_active_hand(), /obj/item/stack/spacecash)) + var/obj/item/stack/spacecash/S = usr.get_active_hand() + paid = pay_with_cash(S) + else if(istype(C, /obj/item/card)) + // Because this uses H.get_idcard(TRUE), it will attempt to use: + // active hand, inactive hand, pda.id, and then wear_id ID in that order + // this is important because it lets people buy stuff with someone else's ID by holding it while using the vendor + paid = pay_with_card(C, usr) + else if(usr.can_advanced_admin_interact()) + to_chat(usr, "Vending object due to admin interaction.") + paid = TRUE + else + to_chat(usr, "Payment failure: you have no ID or other method of payment.") + vend_ready = TRUE + flick(icon_deny, src) + . = TRUE // we set this because they shouldn't even be able to get this far, and we want the UI to update. + return if(paid) vend(currently_vending, usr) - return - else if(handled) - SSnanoui.update_uis(src) - return // don't smack that machine with your 2 credits - - 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(!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 - - var/key = text2num(href_list["vend"]) - var/list/display_records = product_records + coin_records - if(extended_inventory) - display_records = product_records + coin_records + hidden_records - var/datum/data/vending_product/R = display_records[key] - - // This should not happen unless the request from NanoUI was bad - if(coin_records.Find(R) && !coin) - return - - if(hidden_records.Find(R) && !extended_inventory) - return - - if(R.price <= 0) - vend(R, usr) - else - currently_vending = R - if(!GLOB.vendor_account || GLOB.vendor_account.suspended) - status_message = "This machine is currently unable to process payments due to problems with the associated account." - status_error = 1 + . = TRUE else - status_message = "Please swipe a card or insert cash to pay for the item." - status_error = 0 + to_chat(usr, "Payment failure: unable to process payment.") + vend_ready = TRUE + if(.) + add_fingerprint(usr) - else if(href_list["cancelpurchase"]) - currently_vending = null - else if(href_list["togglevoice"] && panel_open) - shut_up = !src.shut_up - add_fingerprint(usr) - SSnanoui.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 - to_chat(usr, "Access denied.")//Unless emagged of course - flick(icon_deny,src) + if(!allowed(user) && !user.can_admin_interact() && !emagged && scan_id) //For SECURE VENDING MACHINES YEAH + to_chat(user, "Access denied.")//Unless emagged of course + flick(icon_deny, src) + vend_ready = TRUE return if(!R.amount) to_chat(user, "The vending machine has ran out of that product.") + vend_ready = TRUE return - vend_ready = 0 //One thing at a time!! - status_message = "Vending..." - status_error = 0 - SSnanoui.update_uis(src) + vend_ready = FALSE //One thing at a time!! if(coin_records.Find(R)) if(!coin) to_chat(user, "You need to insert a coin to get this item.") + vend_ready = TRUE return if(coin.string_attached) if(prob(50)) @@ -652,15 +692,13 @@ use_power(vend_power_usage) //actuators and stuff if(icon_vend) //Show the vending animation if needed flick(icon_vend, src) + playsound(get_turf(src), 'sound/machines/machine_vend.ogg', 50, TRUE) addtimer(CALLBACK(src, .proc/delayed_vend, R, user), vend_delay) /obj/machinery/vending/proc/delayed_vend(datum/data/vending_product/R, mob/user) do_vend(R, user) - status_message = "" - status_error = 0 - vend_ready = 1 + vend_ready = TRUE currently_vending = null - SSnanoui.update_uis(src) //override this proc to add handling for what to do with the vended product when you have a inserted item and remember to include a parent call for this generic handling /obj/machinery/vending/proc/do_vend(datum/data/vending_product/R, mob/user) @@ -796,17 +834,6 @@ */ -/* -/obj/machinery/vending/atmospherics //Commenting this out until someone ponies up some actual working, broken, and unpowered sprites - Quarxink - name = "\improper Tank Vendor" - desc = "A vendor with a wide variety of masks and gas tanks." - icon = 'icons/obj/objects.dmi' - icon_state = "dispenser" - product_paths = "/obj/item/tank/oxygen;/obj/item/tank/plasma;/obj/item/tank/emergency_oxygen;/obj/item/tank/emergency_oxygen/engi;/obj/item/clothing/mask/breath" - product_amounts = "10;10;10;5;25" - vend_delay = 0 -*/ - /obj/machinery/vending/assist products = list( /obj/item/assembly/prox_sensor = 5,/obj/item/assembly/igniter = 3,/obj/item/assembly/signaler = 4, /obj/item/wirecutters = 1, /obj/item/cartridge/signal = 4) @@ -1245,7 +1272,7 @@ ads_list = list("We like plants!","Don't you want some?","The greenest thumbs ever.","We like big plants.","Soft soil...") icon_state = "nutri" icon_deny = "nutri-deny" - products = list(/obj/item/reagent_containers/glass/bottle/nutrient/ez = 30,/obj/item/reagent_containers/glass/bottle/nutrient/l4z = 20,/obj/item/reagent_containers/glass/bottle/nutrient/rh = 10,/obj/item/reagent_containers/spray/pestspray = 20, + products = list(/obj/item/reagent_containers/glass/bottle/nutrient/ez = 20,/obj/item/reagent_containers/glass/bottle/nutrient/l4z = 13,/obj/item/reagent_containers/glass/bottle/nutrient/rh = 6,/obj/item/reagent_containers/spray/pestspray = 20, /obj/item/reagent_containers/syringe = 5,/obj/item/storage/bag/plants = 5,/obj/item/cultivator = 3,/obj/item/shovel/spade = 3,/obj/item/plant_analyzer = 4) contraband = list(/obj/item/reagent_containers/glass/bottle/ammonia = 10,/obj/item/reagent_containers/glass/bottle/diethylamine = 5) refill_canister = /obj/item/vending_refill/hydronutrients @@ -1553,7 +1580,6 @@ desc = "Tools for tools." icon_state = "tool" icon_deny = "tool-deny" - //req_access_txt = "12" //Maintenance access products = list(/obj/item/stack/cable_coil/random = 10,/obj/item/crowbar = 5,/obj/item/weldingtool = 3,/obj/item/wirecutters = 5, /obj/item/wrench = 5,/obj/item/analyzer = 5,/obj/item/t_scanner = 5,/obj/item/screwdriver = 5) contraband = list(/obj/item/weldingtool/hugetank = 2,/obj/item/clothing/gloves/color/fyellow = 2) diff --git a/code/game/mecha/combat/honker.dm b/code/game/mecha/combat/honker.dm index 1bb73856f1b..eb7bfad8942 100644 --- a/code/game/mecha/combat/honker.dm +++ b/code/game/mecha/combat/honker.dm @@ -137,7 +137,7 @@ squeak = 0 return result -obj/mecha/combat/honker/Topic(href, href_list) +/obj/mecha/combat/honker/Topic(href, href_list) ..() if(href_list["play_sound"]) switch(href_list["play_sound"]) diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index e05fef18e5a..d1e63deaf0c 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -60,7 +60,7 @@ set_ready_state(0) log_message("Fired from [name], targeting [target].") var/turf/T = get_turf(src) - msg_admin_attack("[key_name_admin(chassis.occupant)] fired a [src] in ([T.x], [T.y], [T.z] - [ADMIN_JMP(T)])") + add_attack_logs(chassis.occupant, target, "fired a [src]", ATKLOG_FEW) log_game("[key_name(chassis.occupant)] fired a [src] in [T.x], [T.y], [T.z]") do_after_cooldown() return @@ -238,7 +238,7 @@ chassis.use_power(energy_drain) log_message("Honked from [name]. HONK!") var/turf/T = get_turf(src) - msg_admin_attack("[key_name_admin(chassis.occupant)] used a Mecha Honker in ([T.x], [T.y], [T.z] - [ADMIN_JMP(T)])") + add_attack_logs(chassis.occupant, target, "used a Mecha Honker", ATKLOG_MOST) log_game("[key_name(chassis.occupant)] used a Mecha Honker in [T.x], [T.y], [T.z]") do_after_cooldown() return @@ -357,7 +357,7 @@ projectiles-- log_message("Fired from [name], targeting [target].") var/turf/T = get_turf(src) - msg_admin_attack("[key_name_admin(chassis.occupant)] fired a [src] in ([T.x], [T.y], [T.z] - [ADMIN_JMP(T)])") + add_attack_logs(chassis.occupant, target, "fired a [src]", ATKLOG_FEW) log_game("[key_name(chassis.occupant)] fired a [src] in [T.x], [T.y], [T.z]") do_after_cooldown() return diff --git a/code/game/mecha/mech_bay.dm b/code/game/mecha/mech_bay.dm index 896ce886887..34e8648c59e 100644 --- a/code/game/mecha/mech_bay.dm +++ b/code/game/mecha/mech_bay.dm @@ -158,36 +158,36 @@ /obj/machinery/computer/mech_bay_power_console/attack_hand(mob/user as mob) if(..()) return - ui_interact(user) + tgui_interact(user) -/obj/machinery/computer/mech_bay_power_console/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/mech_bay_power_console/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "mech_bay_console.tmpl", "Mech Bay Control Console", 500, 325) - // open the new ui window + ui = new(user, src, ui_key, "MechBayConsole", name, 400, 150, master_ui, state) ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) -/obj/machinery/computer/mech_bay_power_console/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] +/obj/machinery/computer/mech_bay_power_console/tgui_act(action, params) + if(..()) + return + switch(action) + if("reconnect") + reconnect() + . = TRUE + update_icon() + +/obj/machinery/computer/mech_bay_power_console/tgui_data(mob/user) + var/data = list() if(!recharge_port) reconnect() if(recharge_port && !QDELETED(recharge_port)) data["recharge_port"] = list("mech" = null) if(recharge_port.recharging_mecha && !QDELETED(recharge_port.recharging_mecha)) - data["recharge_port"]["mech"] = list("health" = recharge_port.recharging_mecha.obj_integrity, "maxhealth" = initial(recharge_port.recharging_mecha.max_integrity), "cell" = null) + data["recharge_port"]["mech"] = list("health" = recharge_port.recharging_mecha.obj_integrity, "maxhealth" = recharge_port.recharging_mecha.max_integrity, "cell" = null, "name" = recharge_port.recharging_mecha.name) if(recharge_port.recharging_mecha.cell && !QDELETED(recharge_port.recharging_mecha.cell)) - data["has_mech"] = 1 - data["mecha_name"] = recharge_port.recharging_mecha || "None" - data["mecha_charge"] = isnull(recharge_port.recharging_mecha) ? 0 : recharge_port.recharging_mecha.cell.charge - data["mecha_maxcharge"] = isnull(recharge_port.recharging_mecha) ? 0 : recharge_port.recharging_mecha.cell.maxcharge - data["mecha_charge_percentage"] = isnull(recharge_port.recharging_mecha) ? 0 : round(recharge_port.recharging_mecha.cell.percent()) - else - data["has_mech"] = 0 - + data["recharge_port"]["mech"]["cell"] = list( + "charge" = recharge_port.recharging_mecha.cell.charge, + "maxcharge" = recharge_port.recharging_mecha.cell.maxcharge + ) return data /obj/machinery/computer/mech_bay_power_console/Initialize() diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 9a24edb4da3..54a431c92db 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -159,7 +159,6 @@ radio.name = "[src] radio" radio.icon = icon radio.icon_state = icon_state - radio.subspace_transmission = 1 /obj/mecha/examine(mob/user) . = ..() @@ -425,12 +424,7 @@ return if(isobj(obstacle)) var/obj/O = obstacle - if(istype(O, /obj/effect/portal)) //derpfix - anchored = 0 - O.Bumped(src) - spawn(0) //countering portal teleport spawn(0), hurr - anchored = 1 - else if(!O.anchored) + if(!O.anchored) step(obstacle, dir) else if(ismob(obstacle)) step(obstacle, dir) diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index a55c2a731eb..3f8eb81c6b9 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -481,7 +481,7 @@ would spawn and follow the beaker, even if it is carried or thrown. var/more = "" if(M) more = " " - msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", 0, 1) + add_attack_logs(M, location, "Caused a chemical smoke reaction containing [contained]. Last associated key is [carry.my_atom.fingerprintslast][more]", ATKLOG_FEW) log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") else msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", 0, 1) diff --git a/code/game/objects/effects/effect_system/effects_chem_smoke.dm b/code/game/objects/effects/effect_system/effects_chem_smoke.dm index 8c28c7f11c5..2ebad516beb 100644 --- a/code/game/objects/effects/effect_system/effects_chem_smoke.dm +++ b/code/game/objects/effects/effect_system/effects_chem_smoke.dm @@ -83,13 +83,13 @@ var/more = "" if(M) more = " " - msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. Last associated key is [carry.my_atom.fingerprintslast][more].", ATKLOG_FEW) + add_attack_logs(M, location, "Caused a chemical smoke reaction containing [contained]. Last associated key is [carry.my_atom.fingerprintslast][more]", ATKLOG_FEW) log_game("A chemical smoke reaction has taken place in ([where])[contained]. Last associated key is [carry.my_atom.fingerprintslast].") else - msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key.", ATKLOG_FEW) + msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. No associated key.", ATKLOG_FEW) log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key.") else - msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink]). No associated key. CODERS: carry.my_atom may be null.", ATKLOG_FEW) + msg_admin_attack("A chemical smoke reaction has taken place in ([whereLink])[contained]. No associated key. CODERS: carry.my_atom may be null.", ATKLOG_FEW) log_game("A chemical smoke reaction has taken place in ([where])[contained]. No associated key. CODERS: carry.my_atom may be null.") diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm index aa756631768..a2b084463a4 100644 --- a/code/game/objects/effects/portals.dm +++ b/code/game/objects/effects/portals.dm @@ -88,9 +88,6 @@ if(!M.simulated || iseffect(M)) . = FALSE - if(M.anchored && ismecha(M)) - . = FALSE - /obj/effect/portal/proc/teleport(atom/movable/M) if(!can_teleport(M)) return FALSE diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm index 2e81ecb235d..9b62faa5252 100644 --- a/code/game/objects/effects/spawners/bombspawner.dm +++ b/code/game/objects/effects/spawners/bombspawner.dm @@ -6,18 +6,18 @@ var/btemp1 = 1500 var/btemp2 = 1000 // tank temperatures - timer - btype = 2 +/obj/effect/spawner/newbomb/timer + btype = 2 - syndicate - btemp1 = 150 - btemp2 = 20 +/obj/effect/spawner/newbomb/timer/syndicate + btemp1 = 150 + btemp2 = 20 - proximity - btype = 1 +/obj/effect/spawner/newbomb/proximity + btype = 1 - radio - btype = 0 +/obj/effect/spawner/newbomb/radio + btype = 0 /obj/effect/spawner/newbomb/New() diff --git a/code/game/objects/effects/spawners/random_spawners.dm b/code/game/objects/effects/spawners/random_spawners.dm index 9eb8e9de1a2..acd1e54eef7 100644 --- a/code/game/objects/effects/spawners/random_spawners.dm +++ b/code/game/objects/effects/spawners/random_spawners.dm @@ -285,7 +285,7 @@ /obj/item/clothing/gloves/color/yellow/power = 1, /obj/item/twohanded/chainsaw = 1, /obj/item/bee_briefcase = 1, - /obj/item/twohanded/energizedfireaxe = 1, + /obj/item/twohanded/fireaxe/energized = 1, /obj/item/clothing/glasses/thermal = 1, /obj/item/chameleon = 1, /obj/item/reagent_containers/hypospray/autoinjector/stimulants = 1, diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm index 639687a45e9..a1538b5fe92 100644 --- a/code/game/objects/effects/spiders.dm +++ b/code/game/objects/effects/spiders.dm @@ -42,7 +42,7 @@ /obj/structure/spider/stickyweb/CanPass(atom/movable/mover, turf/target, height=0) if(height == 0) return TRUE - if(istype(mover, /mob/living/simple_animal/hostile/poison/giant_spider)) + if(istype(mover, /mob/living/simple_animal/hostile/poison/giant_spider) || isterrorspider(mover)) return TRUE else if(istype(mover, /mob/living)) if(prob(50)) diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm index 1b31891e537..f35b877bc17 100644 --- a/code/game/objects/explosion.dm +++ b/code/game/objects/explosion.dm @@ -137,19 +137,7 @@ T.ex_act(3) CHECK_TICK - //--- THROW ITEMS AROUND --- -/* - if(throw_dist > 0) - var/throw_dir = get_dir(epicenter,T) - for(var/obj/item/I in T) - spawn(0) //Simultaneously not one at a time - if(I && !I.anchored) - var/throw_mult = 0.5 + (0.5 * rand()) // Between 0.5 and 1.0 - var/throw_range = round((throw_dist + 1) * throw_mult) // Roughly 50% to 100% of throw_dist - if(throw_range > 0) - var/turf/throw_at = get_ranged_target_turf(I, throw_dir, throw_range) - I.throw_at(throw_at, throw_range, 2, no_spin = 1) //Throw it at 2 speed, this is purely visual anyway; don't spin the thrown items, it's very costly. -*/ + var/took = stop_watch(watch) //You need to press the DebugGame verb to see these now....they were getting annoying and we've collected a fair bit of data. Just -test- changes to explosion code using this please so we can compare if(GLOB.debug2) diff --git a/code/game/objects/items/bodybag.dm b/code/game/objects/items/bodybag.dm index 5c63dbc709c..58a4ab63d34 100644 --- a/code/game/objects/items/bodybag.dm +++ b/code/game/objects/items/bodybag.dm @@ -7,10 +7,10 @@ icon_state = "bodybag_folded" w_class = WEIGHT_CLASS_SMALL - attack_self(mob/user) - var/obj/structure/closet/body_bag/R = new /obj/structure/closet/body_bag(user.loc) - R.add_fingerprint(user) - qdel(src) +/obj/item/bodybag/attack_self(mob/user) + var/obj/structure/closet/body_bag/R = new /obj/structure/closet/body_bag(user.loc) + R.add_fingerprint(user) + qdel(src) /obj/structure/closet/body_bag name = "body bag" @@ -56,16 +56,13 @@ /obj/structure/closet/body_bag/MouseDrop(over_object, src_location, over_location) - ..() + . = ..() if((over_object == usr && (in_range(src, usr) || usr.contents.Find(src)))) - if(!ishuman(usr)) return - if(opened) return 0 - if(contents.len) return 0 - visible_message("[usr] folds up the [src.name]") + if(!ishuman(usr) || opened || length(contents)) + return FALSE + visible_message("[usr] folds up the [name]") new item_path(get_turf(src)) - spawn(0) - qdel(src) - return + qdel(src) /obj/structure/closet/body_bag/relaymove(mob/user as mob) if(user.stat) diff --git a/code/game/objects/items/changestone.dm b/code/game/objects/items/changestone.dm index 62d56614a07..ec7ad232857 100644 --- a/code/game/objects/items/changestone.dm +++ b/code/game/objects/items/changestone.dm @@ -4,7 +4,7 @@ icon = 'icons/obj/artifacts.dmi' icon_state = "changerock" -obj/item/changestone/attack_hand(var/mob/user as mob) +/obj/item/changestone/attack_hand(var/mob/user as mob) if(istype(user,/mob/living/carbon/human)) var/mob/living/carbon/human/H = user if(!H.gloves) diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index 093f28692ec..7eb1dc9fd56 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -37,71 +37,83 @@ overlays.Cut() /obj/item/aicard/attack_self(mob/user) - ui_interact(user) + tgui_interact(user) -/obj/item/aicard/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.inventory_state) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/aicard/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_inventory_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "aicard.tmpl", "[name]", 600, 400, state = state) + ui = new(user, src, ui_key, "AICard", "[name]", 600, 394, master_ui, state) ui.open() - ui.set_auto_update(1) -/obj/item/aicard/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.inventory_state) +/obj/item/aicard/tgui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.inventory_state) var/data[0] var/mob/living/silicon/ai/AI = locate() in src if(istype(AI)) - data["has_ai"] = 1 + data["has_ai"] = TRUE data["name"] = AI.name - data["hardware_integrity"] = ((AI.health + 100) / 2) + data["integrity"] = ((AI.health + 100) / 2) data["radio"] = !AI.aiRadio.disabledAi data["wireless"] = !AI.control_disabled data["operational"] = AI.stat != DEAD data["flushing"] = flush var/laws[0] - for(var/datum/ai_law/AL in AI.laws.all_laws()) - laws[++laws.len] = list("index" = AL.get_index(), "law" = sanitize(AL.law)) + for(var/datum/ai_law/law in AI.laws.all_laws()) + if(law in AI.laws.ion_laws) // If we're an ion law, give it an ion index code + laws.Add(ionnum() + ". " + law.law) + else + laws.Add(num2text(law.get_index()) + ". " + law.law) data["laws"] = laws - data["has_laws"] = laws.len + data["has_laws"] = length(AI.laws.all_laws()) + + else + data["has_ai"] = FALSE // If this isn't passed to tgui, it won't show there isn't a AI in the card. return data -/obj/item/aicard/Topic(href, href_list, nowindow, state) +/obj/item/aicard/tgui_act(action, params) if(..()) - return 1 + return var/mob/living/silicon/ai/AI = locate() in src if(!istype(AI)) - return 1 + return var/user = usr + switch(action) + if("wipe") + if(flush) // Don't doublewipe. + to_chat(user, "You are already wiping this AI!") + return + var/confirm = alert("Are you sure you want to wipe this card's memory? This cannot be undone once started.", "Confirm Wipe", "Yes", "No") + if(confirm == "Yes" && (tgui_status(user, GLOB.tgui_inventory_state) == STATUS_INTERACTIVE)) // And make doubly sure they want to wipe (three total clicks) + msg_admin_attack("[key_name_admin(user)] wiped [key_name_admin(AI)] with \the [src].", ATKLOG_FEW) + add_attack_logs(user, AI, "Wiped with [src].") + INVOKE_ASYNC(src, .proc/wipe_ai) - if(href_list["wipe"]) - var/confirm = alert("Are you sure you want to wipe this card's memory? This cannot be undone once started.", "Confirm Wipe", "Yes", "No") - if(confirm == "Yes" && (CanUseTopic(user, state) == STATUS_INTERACTIVE)) - msg_admin_attack("[key_name_admin(user)] wiped [key_name_admin(AI)] with \the [src].", ATKLOG_FEW) - add_attack_logs(user, AI, "Wiped with [src].") - flush = 1 - AI.suiciding = 1 - to_chat(AI, "Your core files are being wiped!") - while(AI && AI.stat != DEAD) - AI.adjustOxyLoss(2) - sleep(10) - flush = 0 + if("radio") + AI.aiRadio.disabledAi = !AI.aiRadio.disabledAi + to_chat(AI, "Your Subspace Transceiver has been [AI.aiRadio.disabledAi ? "disabled" : "enabled"]!") + to_chat(user, "You [AI.aiRadio.disabledAi ? "disable" : "enable"] the AI's Subspace Transceiver.") - if(href_list["radio"]) - AI.aiRadio.disabledAi = text2num(href_list["radio"]) - to_chat(AI, "Your Subspace Transceiver has been [AI.aiRadio.disabledAi ? "disabled" : "enabled"]!") - to_chat(user, "You [AI.aiRadio.disabledAi ? "disable" : "enable"] the AI's Subspace Transceiver.") + if("wireless") + AI.control_disabled = !AI.control_disabled + to_chat(AI, "Your wireless interface has been [AI.control_disabled ? "disabled" : "enabled"]!") + to_chat(user, "You [AI.control_disabled ? "disable" : "enable"] the AI's wireless interface.") + update_icon() - if(href_list["wireless"]) - AI.control_disabled = text2num(href_list["wireless"]) - to_chat(AI, "Your wireless interface has been [AI.control_disabled ? "disabled" : "enabled"]!") - to_chat(user, "You [AI.control_disabled ? "disable" : "enable"] the AI's wireless interface.") - update_icon() + return TRUE - return 1 +/obj/item/aicard/proc/wipe_ai() + var/mob/living/silicon/ai/AI = locate() in src + flush = TRUE + AI.suiciding = TRUE + to_chat(AI, "Your core files are being wiped!") + while(AI && AI.stat != DEAD) + AI.adjustOxyLoss(2) + sleep(10) + flush = FALSE diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm index 284ce8d5598..c9d95dd8a99 100644 --- a/code/game/objects/items/devices/radio/electropack.dm +++ b/code/game/objects/items/devices/radio/electropack.dm @@ -10,8 +10,6 @@ materials = list(MAT_METAL=10000, MAT_GLASS=2500) var/code = 2 - is_special = 1 - /obj/item/radio/electropack/attack_hand(mob/user as mob) if(src == user.back) to_chat(user, "You need help taking this off!") @@ -54,23 +52,6 @@ if(src.flags & NODROP) A.flags |= NODROP -/obj/item/radio/electropack/Topic(href, href_list) - if(..()) - return 1 - - if(href_list["freq"]) - var/new_frequency = sanitize_frequency(frequency + text2num(href_list["freq"])) - set_frequency(new_frequency) - - else if(href_list["code"]) - code += text2num(href_list["code"]) - code = round(code) - code = clamp(code, 1, 100) - - else if(href_list["power"]) - on = !on - - add_fingerprint(usr) /obj/item/radio/electropack/receive_signal(datum/signal/signal) if(!signal || signal.encryption != code) @@ -96,18 +77,48 @@ return -/obj/item/radio/electropack/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/radio/electropack/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_inventory_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "radio_electro.tmpl", "[name]", 400, 500) + ui = new(user, src, ui_key, "Electropack", name, 360, 150, master_ui, state) ui.open() - ui.set_auto_update(1) - -/obj/item/radio/electropack/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] +/obj/item/radio/electropack/tgui_data(mob/user) + var/list/data = list() data["power"] = on - data["freq"] = format_frequency(frequency) + data["frequency"] = frequency data["code"] = code - + data["minFrequency"] = PUBLIC_LOW_FREQ + data["maxFrequency"] = PUBLIC_HIGH_FREQ return data + +/obj/item/radio/electropack/tgui_act(action, params) + if(..()) + return + . = TRUE + switch(action) + if("power") + on = !on + if("freq") + var/value = params["freq"] + if(value) + frequency = sanitize_frequency(value) + set_frequency(frequency) + else + . = FALSE + if("code") + var/value = text2num(params["code"]) + if(value) + value = round(value) + code = clamp(value, 1, 100) + else + . = FALSE + if("reset") + if(params["reset"] == "freq") + frequency = initial(frequency) + else if(params["reset"] == "code") + code = initial(code) + else + . = FALSE + if(.) + add_fingerprint(usr) diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 691c12e1347..2142dc9e50b 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -9,7 +9,6 @@ "Vox Armalis" = 'icons/mob/species/armalis/ears.dmi' ) //We read you loud and skree-er. materials = list(MAT_METAL=75) - subspace_transmission = TRUE canhear_range = 0 // can't hear headsets from very far away slot_flags = SLOT_EARS @@ -46,9 +45,6 @@ QDEL_NULL(keyslot2) return ..() -/obj/item/radio/headset/list_channels(var/mob/user) - return list_secure_channels() - /obj/item/radio/headset/examine(mob/user) . = ..() if(in_range(src, user) && radio_desc) @@ -91,6 +87,7 @@ ks1type = /obj/item/encryptionkey/syndicate/nukeops requires_tcomms = FALSE instant = TRUE // Work instantly if there are no comms + freqlock = TRUE /obj/item/radio/headset/syndicate/alt //undisguised bowman with flash protection name = "syndicate headset" @@ -289,6 +286,7 @@ icon_state = "com_headset" item_state = "headset" ks2type = /obj/item/encryptionkey/ert + freqlock = TRUE /obj/item/radio/headset/ert/alt name = "\proper emergency response team's bowman headset" @@ -367,7 +365,7 @@ else to_chat(user, "This headset doesn't have any encryption keys! How useless...") -/obj/item/radio/headset/proc/recalculateChannels(var/setDescription = FALSE) +/obj/item/radio/headset/recalculateChannels(setDescription = FALSE) channels = list() translate_binary = FALSE translate_hive = FALSE diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index c8122fc34d6..f9ba60ab380 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -75,7 +75,6 @@ name = "illicit intercom" desc = "Talk through this. Evilly" frequency = SYND_FREQ - subspace_transmission = TRUE syndiekey = new /obj/item/encryptionkey/syndicate/nukeops /obj/item/radio/intercom/syndicate/New() @@ -85,7 +84,6 @@ /obj/item/radio/intercom/pirate name = "pirate radio intercom" desc = "You wouldn't steal a space shuttle. Piracy. It's a crime!" - subspace_transmission = 1 /obj/item/radio/intercom/pirate/New() ..() @@ -109,13 +107,13 @@ GLOB.global_intercoms.Remove(src) return ..() -/obj/item/radio/intercom/attack_ai(mob/user as mob) +/obj/item/radio/intercom/attack_ai(mob/user) add_hiddenprint(user) add_fingerprint(user) spawn(0) attack_self(user) -/obj/item/radio/intercom/attack_hand(mob/user as mob) +/obj/item/radio/intercom/attack_hand(mob/user) add_fingerprint(user) spawn(0) attack_self(user) @@ -247,14 +245,7 @@ usesound = 'sound/items/deconstruct.ogg' /obj/item/radio/intercom/locked - var/locked_frequency - -/obj/item/radio/intercom/locked/set_frequency(var/frequency) - if(frequency == locked_frequency) - ..(locked_frequency) - -/obj/item/radio/intercom/locked/list_channels() - return "" + freqlock = TRUE /obj/item/radio/intercom/locked/ai_private name = "\improper AI intercom" diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 528be3c5f87..ed6b0190502 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -26,21 +26,37 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( suffix = "\[3\]" icon_state = "walkietalkie" item_state = "walkietalkie" - var/on = 1 // 0 for off + /// boolean for radio enabled or not + var/on = TRUE var/last_transmission - var/frequency = PUB_FREQ //common chat - var/traitor_frequency = 0 //tune to frequency to unlock traitor supplies - var/canhear_range = 3 // the range which mobs can hear this radio from + var/frequency = PUB_FREQ + /// tune to frequency to unlock traitor supplies + var/traitor_frequency = 0 + /// the range which mobs can hear this radio from + var/canhear_range = 3 var/datum/wires/radio/wires = null var/b_stat = 0 - var/broadcasting = 0 - var/listening = 1 - var/list/channels = list() //see communications.dm for full list. First channes is a "default" for :h - var/subspace_transmission = 0 - var/obj/item/encryptionkey/syndicate/syndiekey = null //Holder for the syndicate encryption key if present - var/disable_timer = 0 //How many times this is disabled by EMPs - var/is_special = 0 //For electropacks mostly, skips Topic() checks + /// Whether the radio will broadcast stuff it hears, out over the radio + var/broadcasting = FALSE + /// Whether the radio is currently receiving + var/listening = TRUE + /// Whether the radio can be re-tuned to restricted channels it has no key for + var/freerange = FALSE + /// Whether the radio is able to have its primary frequency changed. Used for radios with weird primary frequencies, like DS, syndi, etc + var/freqlock = FALSE + + /// Whether the radio broadcasts to everyone within a few tiles, or not + var/loudspeaker = FALSE + /// Whether loudspeaker can be toggled by the user + var/has_loudspeaker = FALSE + + /// see communications.dm for full list. First channes is a "default" for :h + var/list/channels = list() + /// Holder for the syndicate encryption key if present + var/obj/item/encryptionkey/syndicate/syndiekey = null + /// How many times this is disabled by EMPs + var/disable_timer = 0 flags = CONDUCT slot_flags = SLOT_BELT @@ -100,76 +116,122 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( /obj/item/radio/attack_ghost(mob/user) return interact(user) -/obj/item/radio/attack_self(mob/user as mob) - user.set_machine(src) - interact(user) +/obj/item/radio/attack_self(mob/user) + tgui_interact(user) /obj/item/radio/interact(mob/user) if(!user) return 0 - if(b_stat) wires.Interact(user) + tgui_interact(user) - return ui_interact(user) - -/obj/item/radio/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/radio/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 400, 550) + var/list/schannels = list_secure_channels(user) + var/list/ichannels = list_internal_channels(user) + var/calc_height = 150 + (schannels.len * 20) + (ichannels.len * 10) + ui = new(user, src, ui_key, "Radio", name, 400, calc_height, master_ui, state) ui.open() - ui.set_auto_update(1) -/obj/item/radio/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] +/obj/item/radio/tgui_data(mob/user) + var/list/data = list() - data["mic_status"] = broadcasting - data["speaker"] = listening - data["freq"] = format_frequency(frequency) - data["rawfreq"] = num2text(frequency) - - data["mic_cut"] = (wires.is_cut(WIRE_RADIO_TRANSMIT) || wires.is_cut(WIRE_RADIO_SIGNAL)) - data["spk_cut"] = (wires.is_cut(WIRE_RADIO_RECEIVER) || wires.is_cut(WIRE_RADIO_SIGNAL)) - - var/list/chanlist = list_channels(user) - if(islist(chanlist) && chanlist.len) - data["chan_list"] = chanlist - data["chan_list_len"] = chanlist.len - - if(syndiekey) - data["useSyndMode"] = 1 + data["broadcasting"] = broadcasting + data["listening"] = listening + data["frequency"] = frequency + data["minFrequency"] = freerange ? RADIO_LOW_FREQ : PUBLIC_LOW_FREQ + data["maxFrequency"] = freerange ? RADIO_HIGH_FREQ : PUBLIC_HIGH_FREQ + data["canReset"] = frequency == initial(frequency) ? FALSE : TRUE + data["freqlock"] = freqlock + data["schannels"] = list_secure_channels(user) + data["ichannels"] = list_internal_channels(user) + data["has_loudspeaker"] = has_loudspeaker + data["loudspeaker"] = loudspeaker return data +/obj/item/radio/tgui_act(action, params, datum/tgui/ui) + if(..()) + return + . = TRUE + switch(action) + if("frequency") + if(freqlock) + return + var/tune = params["tune"] + var/adjust = text2num(params["adjust"]) + if(tune == "reset") + tune = initial(frequency) + else if(adjust) + tune = frequency + adjust * 10 + else if(text2num(tune) != null) + tune = tune * 10 + else + . = FALSE + if(hidden_uplink) + if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency)) + usr << browse(null, "window=radio") + if(.) + set_frequency(sanitize_frequency(tune, freerange)) + if("ichannel") // change primary frequency to an internal channel authorized by access + if(freqlock) + return + var/freq = params["ichannel"] + if(has_channel_access(usr, freq)) + set_frequency(text2num(freq)) + if("listen") + listening = !listening + if("broadcast") + broadcasting = !broadcasting + if("channel") + var/channel = params["channel"] + if(!(channel in channels)) + return + if(channels[channel] & FREQ_LISTENING) + channels[channel] &= ~FREQ_LISTENING + else + channels[channel] |= FREQ_LISTENING + if("loudspeaker") + // Toggle loudspeaker mode, AKA everyone around you hearing your radio. + if(has_loudspeaker) + loudspeaker = !loudspeaker + if(loudspeaker) + canhear_range = 3 + else + canhear_range = 0 + else + . = FALSE + if(.) + add_fingerprint(usr) -/obj/item/radio/proc/list_channels(var/mob/user) - return list_internal_channels(user) - -/obj/item/radio/proc/list_secure_channels(var/mob/user) - var/dat[0] - - for(var/ch_name in channels) - var/chan_stat = channels[ch_name] - var/listening = !!(chan_stat & FREQ_LISTENING) != 0 - - dat.Add(list(list("chan" = ch_name, "display_name" = ch_name, "secure_channel" = 1, "sec_channel_listen" = !listening, "chan_span" = SSradio.frequency_span_class(SSradio.radiochannels[ch_name])))) - +/obj/item/radio/proc/list_secure_channels(mob/user) + var/list/dat = list() + for(var/channel in channels) + dat[channel] = channels[channel] & FREQ_LISTENING return dat -/obj/item/radio/proc/list_internal_channels(var/mob/user) - var/dat[0] +/obj/item/radio/proc/list_internal_channels(mob/user) + var/list/dat = list() + if(freqlock) + return dat for(var/internal_chan in internal_channels) + var/freqnum = text2num(internal_chan) + var/freqname = get_frequency_name(freqnum) if(has_channel_access(user, internal_chan)) - dat.Add(list(list("chan" = internal_chan, "display_name" = get_frequency_name(text2num(internal_chan)), "chan_span" = SSradio.frequency_span_class(text2num(internal_chan))))) - + dat[freqname] = freqnum // unlike secure_channels, this is set to the freq number so Radio.js can use it as an arg return dat -/obj/item/radio/proc/has_channel_access(var/mob/user, var/freq) +/obj/item/radio/proc/has_channel_access(mob/user, freq) if(!user) - return 0 + return FALSE if(!(freq in internal_channels)) - return 0 + return FALSE + + if(isrobot(user)) + return FALSE // cyborgs and drones are not allowed to remotely re-tune intercomms, etc return user.has_internal_radio_channel_access(user, internal_channels[freq]) @@ -190,53 +252,6 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( /obj/item/radio/proc/ToggleReception() listening = !listening && !(wires.is_cut(WIRE_RADIO_RECEIVER) || wires.is_cut(WIRE_RADIO_SIGNAL)) -/obj/item/radio/Topic(href, href_list) - if(..()) - return 1 - - if(is_special) - return 0 - - if(href_list["track"]) - var/mob/target = locate(href_list["track"]) - var/mob/living/silicon/ai/A = locate(href_list["track2"]) - if(A && target) - A.ai_actual_track(target) - . = 1 - - else if(href_list["freq"]) - var/new_frequency = (frequency + text2num(href_list["freq"])) - if((new_frequency < PUBLIC_LOW_FREQ || new_frequency > PUBLIC_HIGH_FREQ)) - new_frequency = sanitize_frequency(new_frequency) - set_frequency(new_frequency) - if(hidden_uplink) - if(hidden_uplink.check_trigger(usr, frequency, traitor_frequency)) - usr << browse(null, "window=radio") - . = 1 - else if(href_list["talk"]) - ToggleBroadcast() - . = 1 - else if(href_list["listen"]) - var/chan_name = href_list["ch_name"] - if(!chan_name) - ToggleReception() - else - if(channels[chan_name] & FREQ_LISTENING) - channels[chan_name] &= ~FREQ_LISTENING - else - channels[chan_name] |= FREQ_LISTENING - . = 1 - else if(href_list["spec_freq"]) - var/freq = href_list["spec_freq"] - if(has_channel_access(usr, freq)) - set_frequency(text2num(freq)) - . = 1 - - if(href_list["nowindow"]) // here for pAIs, maybe others will want it, idk - return 1 - - add_fingerprint(usr) - /obj/item/radio/proc/autosay(message, from, channel, role = "Unknown") //BS12 EDIT var/datum/radio_frequency/connection = null if(channel && channels && channels.len > 0) @@ -582,20 +597,26 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( if(!disable_timer) on = 1 +/obj/item/radio/proc/recalculateChannels() + /// Exists so that borg radios and headsets can override it. + stack_trace("recalculateChannels() called on a radio which does not implement the proc.") + /////////////////////////////// //////////Borg Radios////////// /////////////////////////////// //Giving borgs their own radio to have some more room to work with -Sieve /obj/item/radio/borg + name = "Cyborg Radio" var/mob/living/silicon/robot/myborg = null // Cyborg which owns this radio. Used for power checks - var/obj/item/encryptionkey/keyslot = null//Borg radios can handle a single encryption key - var/shut_up = 1 + var/obj/item/encryptionkey/keyslot // Borg radios can handle a single encryption key icon = 'icons/obj/robot_component.dmi' // Cyborgs radio icons should look like the component. icon_state = "radio" + has_loudspeaker = TRUE + loudspeaker = FALSE canhear_range = 0 - subspace_transmission = 1 dog_fashion = null + freqlock = TRUE // don't let cyborgs change the default channel of their internal radio away from common /obj/item/radio/borg/syndicate keyslot = new /obj/item/encryptionkey/syndicate/nukeops @@ -609,19 +630,18 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( myborg = null return ..() -/obj/item/radio/borg/list_channels(var/mob/user) - return list_secure_channels(user) - /obj/item/radio/borg/syndicate/New() ..() syndiekey = keyslot set_frequency(SYND_FREQ) + freqlock = TRUE /obj/item/radio/borg/deathsquad /obj/item/radio/borg/deathsquad/New() ..() set_frequency(DTH_FREQ) + freqlock = TRUE /obj/item/radio/borg/ert keyslot = new /obj/item/encryptionkey/ert @@ -629,6 +649,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( /obj/item/radio/borg/ert/New() ..() set_frequency(ERT_FREQ) + freqlock = TRUE /obj/item/radio/borg/ert/specops keyslot = new /obj/item/encryptionkey/centcom @@ -673,7 +694,7 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( else to_chat(user, "This radio doesn't have any encryption keys!") -/obj/item/radio/borg/proc/recalculateChannels() +/obj/item/radio/borg/recalculateChannels() channels = list() syndiekey = null @@ -706,72 +727,12 @@ GLOBAL_LIST_INIT(default_medbay_channels, list( return -/obj/item/radio/borg/Topic(href, href_list) - if(..()) - return 1 - if(href_list["mode"]) - var/enable_subspace_transmission = text2num(href_list["mode"]) - if(enable_subspace_transmission != subspace_transmission) - subspace_transmission = !subspace_transmission - if(subspace_transmission) - to_chat(usr, "Subspace Transmission is enabled.") - else - to_chat(usr, "Subspace Transmission is disabled.") - if(subspace_transmission == 0)//Simple as fuck, clears the channel list to prevent talking/listening over them if subspace transmission is disabled - channels = list() - else - recalculateChannels() - . = 1 - if(href_list["shutup"]) // Toggle loudspeaker mode, AKA everyone around you hearing your radio. - var/do_shut_up = text2num(href_list["shutup"]) - if(do_shut_up != shut_up) - shut_up = !shut_up - if(shut_up) - canhear_range = 0 - to_chat(usr, "Loudspeaker disabled.") - else - canhear_range = 3 - to_chat(usr, "Loudspeaker enabled.") - . = 1 - - -/obj/item/radio/borg/interact(mob/user as mob) +/obj/item/radio/borg/interact(mob/user) if(!on) return - . = ..() -/obj/item/radio/borg/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "radio_basic.tmpl", "[name]", 430, 500) - ui.open() - ui.set_auto_update(1) - -/obj/item/radio/borg/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - - data["mic_status"] = broadcasting - data["speaker"] = listening - data["freq"] = format_frequency(frequency) - data["rawfreq"] = num2text(frequency) - - var/list/chanlist = list_channels(user) - if(islist(chanlist) && chanlist.len) - data["chan_list"] = chanlist - data["chan_list_len"] = chanlist.len - - if(syndiekey) - data["useSyndMode"] = 1 - - data["has_loudspeaker"] = 1 - data["loudspeaker"] = !shut_up - data["has_subspace"] = 1 - data["subspace"] = subspace_transmission - - return data - /obj/item/radio/proc/config(op) if(SSradio) for(var/ch_name in channels) diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index acba0087caf..1eba4e54056 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -64,7 +64,7 @@ A.toggle_secure() //this calls update_icon(), which calls update_icon() on the holder (i.e. the bomb). investigate_log("[key_name(user)] attached a [A] to a transfer valve.", INVESTIGATE_BOMB) - msg_admin_attack("[key_name_admin(user)]attached [A] to a transfer valve.", ATKLOG_FEW) + add_attack_logs(user, src, "attached [A] to a transfer valve", ATKLOG_FEW) log_game("[key_name_admin(user)] attached [A] to a transfer valve.") attacher = user SSnanoui.update_uis(src) // update all UIs attached to src @@ -86,64 +86,64 @@ O.hear_message(M, msg) /obj/item/transfer_valve/attack_self(mob/user) - ui_interact(user) + tgui_interact(user) -/obj/item/transfer_valve/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1) - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/item/transfer_valve/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_inventory_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "transfer_valve.tmpl", "Tank Transfer Valve", 460, 280) - // open the new ui window + ui = new(user, src, ui_key, "TransferValve", name, 460, 320, master_ui, state) ui.open() - // auto update every Master Controller tick - //ui.set_auto_update(1) - -/obj/item/transfer_valve/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - - data["attachmentOne"] = tank_one ? tank_one.name : null - data["attachmentTwo"] = tank_two ? tank_two.name : null - data["valveAttachment"] = attached_device ? attached_device.name : null - data["valveOpen"] = valve_open ? 1 : 0 +/obj/item/transfer_valve/tgui_data(mob/user) + var/list/data = list() + data["tank_one"] = tank_one ? tank_one.name : null + data["tank_two"] = tank_two ? tank_two.name : null + data["attached_device"] = attached_device ? attached_device.name : null + data["valve"] = valve_open return data -/obj/item/transfer_valve/Topic(href, href_list) - ..() - if(usr.incapacitated()) - return 0 - if(loc != usr) - return 0 - if(tank_one && href_list["tankone"]) - split_gases() - valve_open = 0 - tank_one.forceMove(get_turf(src)) - tank_one = null + + +/obj/item/transfer_valve/tgui_act(action, params) + if(..()) + return + . = TRUE + switch(action) + if("tankone") + if(tank_one) + split_gases() + valve_open = FALSE + tank_one.forceMove(get_turf(src)) + tank_one = null + update_icon() + if((!tank_two || tank_two.w_class < WEIGHT_CLASS_BULKY) && (w_class > WEIGHT_CLASS_NORMAL)) + w_class = WEIGHT_CLASS_NORMAL + if("tanktwo") + if(tank_two) + split_gases() + valve_open = FALSE + tank_two.forceMove(get_turf(src)) + tank_two = null + update_icon() + if((!tank_one || tank_one.w_class < WEIGHT_CLASS_BULKY) && (w_class > WEIGHT_CLASS_NORMAL)) + w_class = WEIGHT_CLASS_NORMAL + if("toggle") + toggle_valve(usr) + if("device") + if(attached_device) + attached_device.attack_self(usr) + if("remove_device") + if(attached_device) + attached_device.forceMove(get_turf(src)) + attached_device.holder = null + attached_device = null + update_icon() + else + . = FALSE + if(.) update_icon() - if((!tank_two || tank_two.w_class < WEIGHT_CLASS_BULKY) && (w_class > WEIGHT_CLASS_NORMAL)) - w_class = WEIGHT_CLASS_NORMAL - else if(tank_two && href_list["tanktwo"]) - split_gases() - valve_open = 0 - tank_two.forceMove(get_turf(src)) - tank_two = null - update_icon() - if((!tank_one || tank_one.w_class < WEIGHT_CLASS_BULKY) && (w_class > WEIGHT_CLASS_NORMAL)) - w_class = WEIGHT_CLASS_NORMAL - else if(href_list["open"]) - toggle_valve() - else if(attached_device) - if(href_list["rem_device"]) - attached_device.forceMove(get_turf(src)) - attached_device.holder = null - attached_device = null - update_icon() - if(href_list["device"]) - attached_device.attack_self(usr) - add_fingerprint(usr) - return 1 // Returning 1 sends an update to attached UIs + add_fingerprint(usr) + /obj/item/transfer_valve/proc/process_activation(obj/item/D) if(toggle) @@ -190,7 +190,7 @@ it explodes properly when it gets a signal (and it does). */ -/obj/item/transfer_valve/proc/toggle_valve() +/obj/item/transfer_valve/proc/toggle_valve(mob/user) if(!valve_open && tank_one && tank_two) valve_open = 1 var/turf/bombturf = get_turf(src) @@ -207,6 +207,8 @@ investigate_log("Bomb valve opened at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name(mob)]", INVESTIGATE_BOMB) message_admins("Bomb valve opened at [A.name] (JMP) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name_admin(mob)]") log_game("Bomb valve opened at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name(mob)]") + if(user) + add_attack_logs(user, src, "Bomb valve opened with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name(mob)]", ATKLOG_FEW) merge_gases() spawn(20) // In case one tank bursts for(var/i in 1 to 5) diff --git a/code/game/objects/items/flag.dm b/code/game/objects/items/flag.dm index f33e504a3e6..0dda06d3e5c 100644 --- a/code/game/objects/items/flag.dm +++ b/code/game/objects/items/flag.dm @@ -242,15 +242,15 @@ to_chat(user, "You hide [I] in the [src]. It will detonate some time after the flag is lit on fire.") var/turf/bombturf = get_turf(src) var/area/A = get_area(bombturf) - message_admins("[key_name_admin(user)] has hidden [I] in the [src] ready for detonation at [A.name] (JMP).") log_game("[key_name(user)] has hidden [I] in the [src] ready for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).") investigate_log("[key_name(user)] has hidden [I] in the [src] ready for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).", INVESTIGATE_BOMB) + add_attack_logs(user, src, "has hidden [I] ready for detonation in", ATKLOG_MOST) else if(is_hot(I) && !(resistance_flags & ON_FIRE) && boobytrap && trapper) var/turf/bombturf = get_turf(src) var/area/A = get_area(bombturf) - message_admins("[key_name_admin(user)] has lit the [src] trapped with [boobytrap] by [key_name_admin(trapper)] at [A.name] (JMP).") log_game("[key_name_admin(user)] has lit the [src] trapped with [boobytrap] by [key_name_admin(trapper)] at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).") investigate_log("[key_name_admin(user)] has lit the [src] trapped with [boobytrap] by [key_name_admin(trapper)] at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]).", INVESTIGATE_BOMB) + add_attack_logs(user, src, "has lit (booby trapped with [boobytrap]", ATKLOG_FEW) burn() else return ..() diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 2d2b110fa06..067411ed647 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -185,20 +185,18 @@ /obj/item/borg/upgrade/syndicate name = "safety override module" - desc = "Unlocks the hidden, deadlier functions of a cyborg. Also prevents emag subversion." + desc = "Unlocks the hidden, deadlier functions of a cyborg." icon_state = "cyborg_upgrade3" - origin_tech = "combat=4;syndicate=1" + origin_tech = "combat=6;materials=6" require_module = TRUE /obj/item/borg/upgrade/syndicate/action(mob/living/silicon/robot/R) if(..()) return - if(R.emagged) - return if(R.weapons_unlock) - to_chat(R, "Internal diagnostic error: incompatible upgrade module detected.") + to_chat(R, "Warning: Safety Overide Protocols have be disabled.") return - R.emagged = 1 + R.weapons_unlock = 1 return TRUE /obj/item/borg/upgrade/lavaproof diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index cd1b91388d7..5eddfae9bbb 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -214,8 +214,9 @@ /obj/item/twohanded/dualsaber/toy/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) return 0 -/obj/item/twohanded/dualsaber/toy/IsReflect()//Stops Toy Dualsabers from reflecting energy projectiles - return 0 +/obj/item/twohanded/dualsaber/toy/IsReflect() + if(wielded) + return 2 /obj/item/toy/katana name = "replica katana" @@ -404,7 +405,7 @@ -obj/item/toy/cards +/obj/item/toy/cards resistance_flags = FLAMMABLE max_integrity = 50 var/parentdeck = null @@ -416,14 +417,14 @@ obj/item/toy/cards var/card_throw_range = 20 var/list/card_attack_verb = list("attacked") -obj/item/toy/cards/New() +/obj/item/toy/cards/New() ..() -obj/item/toy/cards/proc/apply_card_vars(obj/item/toy/cards/newobj, obj/item/toy/cards/sourceobj) // Applies variables for supporting multiple types of card deck +/obj/item/toy/cards/proc/apply_card_vars(obj/item/toy/cards/newobj, obj/item/toy/cards/sourceobj) // Applies variables for supporting multiple types of card deck if(!istype(sourceobj)) return -obj/item/toy/cards/deck +/obj/item/toy/cards/deck name = "deck of cards" desc = "A deck of space-grade playing cards." icon = 'icons/obj/toy.dmi' @@ -433,7 +434,7 @@ obj/item/toy/cards/deck var/cooldown = 0 var/list/cards = list() -obj/item/toy/cards/deck/New() +/obj/item/toy/cards/deck/New() ..() icon_state = "deck_[deckstyle]_full" for(var/i in 2 to 10) @@ -458,7 +459,7 @@ obj/item/toy/cards/deck/New() cards += "Ace of Clubs" cards += "Ace of Diamonds" -obj/item/toy/cards/deck/attack_hand(mob/user as mob) +/obj/item/toy/cards/deck/attack_hand(mob/user as mob) var/choice = null if(cards.len == 0) icon_state = "deck_[deckstyle]_empty" @@ -476,14 +477,14 @@ obj/item/toy/cards/deck/attack_hand(mob/user as mob) visible_message("[user] draws a card from the deck.", "You draw a card from the deck.") update_icon() -obj/item/toy/cards/deck/attack_self(mob/user as mob) +/obj/item/toy/cards/deck/attack_self(mob/user as mob) if(cooldown < world.time - 50) cards = shuffle(cards) playsound(user, 'sound/items/cardshuffle.ogg', 50, 1) user.visible_message("[user] shuffles the deck.", "You shuffle the deck.") cooldown = world.time -obj/item/toy/cards/deck/attackby(obj/item/toy/cards/singlecard/C, mob/living/user, params) +/obj/item/toy/cards/deck/attackby(obj/item/toy/cards/singlecard/C, mob/living/user, params) ..() if(istype(C)) if(C.parentdeck == src) @@ -498,7 +499,7 @@ obj/item/toy/cards/deck/attackby(obj/item/toy/cards/singlecard/C, mob/living/use update_icon() -obj/item/toy/cards/deck/attackby(obj/item/toy/cards/cardhand/C, mob/living/user, params) +/obj/item/toy/cards/deck/attackby(obj/item/toy/cards/cardhand/C, mob/living/user, params) ..() if(istype(C)) if(C.parentdeck == src) @@ -512,7 +513,7 @@ obj/item/toy/cards/deck/attackby(obj/item/toy/cards/cardhand/C, mob/living/user, to_chat(user, "You can't mix cards from other decks.") update_icon() -obj/item/toy/cards/deck/MouseDrop(atom/over_object) +/obj/item/toy/cards/deck/MouseDrop(atom/over_object) var/mob/M = usr if(usr.stat || !ishuman(usr) || !usr.canmove || usr.restrained()) return @@ -536,7 +537,7 @@ obj/item/toy/cards/deck/MouseDrop(atom/over_object) else to_chat(usr, "You can't reach it from here.") -obj/item/toy/cards/deck/update_icon() +/obj/item/toy/cards/deck/update_icon() switch(cards.len) if(0) icon_state = "deck_[deckstyle]_empty" @@ -547,7 +548,7 @@ obj/item/toy/cards/deck/update_icon() else icon_state = "deck_[deckstyle]_full" -obj/item/toy/cards/cardhand +/obj/item/toy/cards/cardhand name = "hand of cards" desc = "A number of cards not in a deck, customarily held in ones hand." icon = 'icons/obj/toy.dmi' @@ -557,11 +558,11 @@ obj/item/toy/cards/cardhand var/choice = null -obj/item/toy/cards/cardhand/attack_self(mob/user as mob) +/obj/item/toy/cards/cardhand/attack_self(mob/user as mob) user.set_machine(src) interact(user) -obj/item/toy/cards/cardhand/interact(mob/user) +/obj/item/toy/cards/cardhand/interact(mob/user) var/dat = "You have:
" for(var/t in currenthand) dat += "A [t].
" @@ -572,7 +573,7 @@ obj/item/toy/cards/cardhand/interact(mob/user) popup.open() -obj/item/toy/cards/cardhand/Topic(href, href_list) +/obj/item/toy/cards/cardhand/Topic(href, href_list) if(..()) return if(usr.stat || !ishuman(usr) || !usr.canmove) @@ -606,7 +607,7 @@ obj/item/toy/cards/cardhand/Topic(href, href_list) qdel(src) return -obj/item/toy/cards/cardhand/attackby(obj/item/toy/cards/singlecard/C, mob/living/user, params) +/obj/item/toy/cards/cardhand/attackby(obj/item/toy/cards/singlecard/C, mob/living/user, params) if(istype(C)) if(C.parentdeck == parentdeck) currenthand += C.cardname @@ -618,7 +619,7 @@ obj/item/toy/cards/cardhand/attackby(obj/item/toy/cards/singlecard/C, mob/living else to_chat(user, "You can't mix cards from other decks.") -obj/item/toy/cards/cardhand/apply_card_vars(obj/item/toy/cards/newobj,obj/item/toy/cards/sourceobj) +/obj/item/toy/cards/cardhand/apply_card_vars(obj/item/toy/cards/newobj,obj/item/toy/cards/sourceobj) ..() newobj.deckstyle = sourceobj.deckstyle newobj.icon_state = "[deckstyle]_hand2" // Another dumb hack, without this the hand is invisible (or has the default deckstyle) until another card is added. @@ -631,7 +632,7 @@ obj/item/toy/cards/cardhand/apply_card_vars(obj/item/toy/cards/newobj,obj/item/t newobj.resistance_flags = sourceobj.resistance_flags -obj/item/toy/cards/singlecard +/obj/item/toy/cards/singlecard name = "card" desc = "a card" icon = 'icons/obj/toy.dmi' @@ -642,7 +643,7 @@ obj/item/toy/cards/singlecard pixel_x = -5 -obj/item/toy/cards/singlecard/examine(mob/user) +/obj/item/toy/cards/singlecard/examine(mob/user) . = ..() if(get_dist(user, src) <= 0) if(ishuman(user)) @@ -653,7 +654,7 @@ obj/item/toy/cards/singlecard/examine(mob/user) . += "You need to have the card in your hand to check it." -obj/item/toy/cards/singlecard/verb/Flip() +/obj/item/toy/cards/singlecard/verb/Flip() set name = "Flip Card" set category = "Object" set src in range(1) @@ -674,7 +675,7 @@ obj/item/toy/cards/singlecard/verb/Flip() name = "card" pixel_x = -5 -obj/item/toy/cards/singlecard/attackby(obj/item/I, mob/living/user, params) +/obj/item/toy/cards/singlecard/attackby(obj/item/I, mob/living/user, params) if(istype(I, /obj/item/toy/cards/singlecard/)) var/obj/item/toy/cards/singlecard/C = I if(C.parentdeck == parentdeck) @@ -704,7 +705,7 @@ obj/item/toy/cards/singlecard/attackby(obj/item/I, mob/living/user, params) else to_chat(user, "You can't mix cards from other decks.") -obj/item/toy/cards/cardhand/update_icon() +/obj/item/toy/cards/cardhand/update_icon() switch(currenthand.len) if(0 to 1) return @@ -718,12 +719,12 @@ obj/item/toy/cards/cardhand/update_icon() icon_state = "[deckstyle]_hand5" -obj/item/toy/cards/singlecard/attack_self(mob/user) +/obj/item/toy/cards/singlecard/attack_self(mob/user) if(usr.stat || !ishuman(usr) || !usr.canmove || usr.restrained()) return Flip() -obj/item/toy/cards/singlecard/apply_card_vars(obj/item/toy/cards/singlecard/newobj,obj/item/toy/cards/sourceobj) +/obj/item/toy/cards/singlecard/apply_card_vars(obj/item/toy/cards/singlecard/newobj,obj/item/toy/cards/sourceobj) ..() newobj.deckstyle = sourceobj.deckstyle newobj.icon_state = "singlecard_down_[deckstyle]" // Without this the card is invisible until flipped. It's an ugly hack, but it works. @@ -745,7 +746,7 @@ obj/item/toy/cards/singlecard/apply_card_vars(obj/item/toy/cards/singlecard/newo || Syndicate playing cards, for pretending you're Gambit and playing poker for the nuke disk. || */ -obj/item/toy/cards/deck/syndicate +/obj/item/toy/cards/deck/syndicate name = "suspicious looking deck of cards" desc = "A deck of space-grade playing cards. They seem unusually rigid." deckstyle = "syndicate" @@ -760,10 +761,10 @@ obj/item/toy/cards/deck/syndicate /* || Custom card decks || */ -obj/item/toy/cards/deck/black +/obj/item/toy/cards/deck/black deckstyle = "black" -obj/item/toy/cards/deck/syndicate/black +/obj/item/toy/cards/deck/syndicate/black deckstyle = "black" /obj/item/toy/nuke diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm index 8508c741524..d369161127f 100644 --- a/code/game/objects/items/trash.dm +++ b/code/game/objects/items/trash.dm @@ -59,6 +59,14 @@ /obj/item/trash/fried_vox name = "Kentucky Fried Vox" icon_state = "fried_vox_empty" + item_state = "fried_vox_empty" + slot_flags = SLOT_HEAD + dog_fashion = /datum/dog_fashion/head/fried_vox_empty + sprite_sheets = list( + "Skrell" = 'icons/mob/species/skrell/head.dmi', + "Drask" = 'icons/mob/species/drask/head.dmi', + "Kidan" = 'icons/mob/species/kidan/head.dmi' + ) /obj/item/trash/pistachios name = "Pistachios pack" diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index b780a837559..2b30ae5851f 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -102,6 +102,7 @@ var/rank = null //actual job var/owner_uid var/owner_ckey + var/lastlog var/dorm = 0 // determines if this ID has claimed a dorm already var/sex diff --git a/code/game/objects/items/weapons/cigs.dm b/code/game/objects/items/weapons/cigs.dm index 30ad91beffa..bd80e43140f 100644 --- a/code/game/objects/items/weapons/cigs.dm +++ b/code/game/objects/items/weapons/cigs.dm @@ -66,6 +66,10 @@ LIGHTERS ARE IN LIGHTERS.DM ..() light() +/obj/item/clothing/mask/cigarette/catch_fire() + if(!lit) + light("The [name] is lit by the flames!") + /obj/item/clothing/mask/cigarette/welder_act(mob/user, obj/item/I) . = TRUE if(I.tool_use_check(user, 0)) //Don't need to flash eyes because you are a badass diff --git a/code/game/objects/items/weapons/dice.dm b/code/game/objects/items/weapons/dice.dm index 629942860be..ae49512853a 100644 --- a/code/game/objects/items/weapons/dice.dm +++ b/code/game/objects/items/weapons/dice.dm @@ -189,8 +189,8 @@ var/turf/bombturf = get_turf(src) var/area/A = get_area(bombturf) investigate_log("E20 detonated at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with a roll of [result]. Triggered by: [key_name(user)]", INVESTIGATE_BOMB) - message_admins("E20 detonated at [A.name] (JMP) with a roll of [result]. Triggered by: [key_name_admin(user)]") log_game("E20 detonated at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with a roll of [result]. Triggered by: [key_name(user)]") + add_attack_logs(user, src, "detonated with a roll of [result]", ATKLOG_FEW) /obj/item/dice/update_icon() diff --git a/code/game/objects/items/weapons/fireworks.dm b/code/game/objects/items/weapons/fireworks.dm index a2a0d6df552..906c4f3fef7 100644 --- a/code/game/objects/items/weapons/fireworks.dm +++ b/code/game/objects/items/weapons/fireworks.dm @@ -1,10 +1,11 @@ -obj/item/firework +/obj/item/firework name = "fireworks" icon = 'icons/obj/fireworks.dmi' icon_state = "rocket_0" var/litzor = 0 var/datum/effect_system/sparkle_spread/S -obj/item/firework/attackby(obj/item/W,mob/user, params) + +/obj/item/firework/attackby(obj/item/W,mob/user, params) if(litzor) return if(is_hot(W)) @@ -20,13 +21,13 @@ obj/item/firework/attackby(obj/item/W,mob/user, params) S.start() qdel(src) -obj/item/sparkler +/obj/item/sparkler name = "sparkler" icon = 'icons/obj/fireworks.dmi' icon_state = "sparkler_0" var/litzor = 0 -obj/item/sparkler/attackby(obj/item/W,mob/user, params) +/obj/item/sparkler/attackby(obj/item/W,mob/user, params) if(litzor) return if(is_hot(W)) @@ -39,8 +40,12 @@ obj/item/sparkler/attackby(obj/item/W,mob/user, params) do_sparks(1, 0, loc) sleep(10) qdel(src) + +// TODO: Refactor this into a proper locker or something +// Or just axe the system. This code is 7 years old /obj/crate/fireworks name = "Fireworks!" + /obj/crate/fireworks/New() new /obj/item/sparkler(src) new /obj/item/sparkler(src) diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm index 79612afd1f3..3aa658b0812 100644 --- a/code/game/objects/items/weapons/grenades/chem_grenade.dm +++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm @@ -101,9 +101,9 @@ update_icon() else if(clown_check(user)) // This used to go before the assembly check, but that has absolutely zero to do with priming the damn thing. You could spam the admins with it. - message_admins("[key_name_admin(usr)] has primed a [name] for detonation at [A.name] (JMP) [contained].") log_game("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) [contained].") investigate_log("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])[contained].", INVESTIGATE_BOMB) + add_attack_logs(user, src, "has primed (contained [contained])", ATKLOG_FEW) to_chat(user, "You prime the [name]! [det_time / 10] second\s!") playsound(user.loc, 'sound/weapons/armbomb.ogg', 60, 1) active = 1 @@ -120,7 +120,7 @@ owner.visible_message("[attack_text] hits [owner]'s [src], setting it off! What a shot!") var/turf/T = get_turf(src) log_game("A projectile ([hitby]) detonated a grenade held by [key_name(owner)] at [COORD(T)]") - message_admins("A projectile ([hitby]) detonated a grenade held by [key_name_admin(owner)] at [ADMIN_COORDJMP(T)]") + add_attack_logs(P.firer, owner, "A projectile ([hitby]) detonated a grenade held", ATKLOG_FEW) prime() return 1 //It hit the grenade, not them @@ -149,16 +149,16 @@ if(!O.reagents) continue if(istype(O,/obj/item/slime_extract)) cores += " [O]" - for(var/reagent in O.reagents.reagent_list) - contained += " [reagent] " + for(var/R in O.reagents.reagent_list) + var/datum/reagent/reagent = R + contained += "[reagent.volume] [reagent], " if(contained) if(cores) - contained = "\[[cores];[contained]\]" + contained = "\[[cores]; [contained]\]" else - contained = "\[[contained]\]" + contained = "\[ [contained]\]" var/turf/bombturf = get_turf(loc) - var/area/A = bombturf.loc - message_admins("[key_name_admin(usr)] has completed [name] at [A.name] (JMP) [contained].") + add_attack_logs(user, src, "has completed with [contained]", ATKLOG_MOST) log_game("[key_name(usr)] has completed [name] at [bombturf.x], [bombturf.y], [bombturf.z]. [contained]") else to_chat(user, "You need to add at least one beaker before locking the assembly.") diff --git a/code/game/objects/items/weapons/grenades/ghettobomb.dm b/code/game/objects/items/weapons/grenades/ghettobomb.dm index b58330a248b..c2303dd2937 100644 --- a/code/game/objects/items/weapons/grenades/ghettobomb.dm +++ b/code/game/objects/items/weapons/grenades/ghettobomb.dm @@ -48,9 +48,9 @@ var/turf/bombturf = get_turf(src) var/area/A = get_area(bombturf) - message_admins("[ADMIN_LOOKUPFLW(user)] has primed a [name] for detonation at [ADMIN_COORDJMP(bombturf)].") log_game("[key_name(user)] has primed a [name] for detonation at [A.name] [COORD(bombturf)].") investigate_log("[key_name(user)] has primed a [name] for detonation at [A.name] [COORD(bombturf)])", INVESTIGATE_BOMB) + add_attack_logs(user, src, "has primed for detonation", ATKLOG_FEW) if(iscarbon(user)) var/mob/living/carbon/C = user C.throw_mode_on() diff --git a/code/game/objects/items/weapons/grenades/grenade.dm b/code/game/objects/items/weapons/grenades/grenade.dm index 8cbc041c146..da546836dc6 100644 --- a/code/game/objects/items/weapons/grenades/grenade.dm +++ b/code/game/objects/items/weapons/grenades/grenade.dm @@ -73,6 +73,7 @@ message_admins("[key_name_admin(usr)] has primed a [name] for detonation at [A.name] (JMP)") log_game("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])") investigate_log("[key_name(usr)] has primed a [name] for detonation at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z])", INVESTIGATE_BOMB) + add_attack_logs(user, src, "has primed for detonation", ATKLOG_FEW) if(iscarbon(user)) var/mob/living/carbon/C = user C.throw_mode_on() diff --git a/code/game/objects/items/weapons/grenades/spawnergrenade.dm b/code/game/objects/items/weapons/grenades/spawnergrenade.dm index b4df7b0d16b..efb93a520a5 100644 --- a/code/game/objects/items/weapons/grenades/spawnergrenade.dm +++ b/code/game/objects/items/weapons/grenades/spawnergrenade.dm @@ -9,27 +9,27 @@ var/deliveryamt = 1 // amount of type to deliver spawner_type = /mob/living/simple_animal/hostile/viscerator - prime() // Prime now just handles the two loops that query for people in lockers and people who can see it. +/obj/item/grenade/spawnergrenade/prime() // Prime now just handles the two loops that query for people in lockers and people who can see it. - if(spawner_type && deliveryamt) - // Make a quick flash - var/turf/T = get_turf(src) - playsound(T, 'sound/effects/phasein.ogg', 100, 1) - for(var/mob/living/carbon/C in viewers(T, null)) - C.flash_eyes() + if(spawner_type && deliveryamt) + // Make a quick flash + var/turf/T = get_turf(src) + playsound(T, 'sound/effects/phasein.ogg', 100, 1) + for(var/mob/living/carbon/C in viewers(T, null)) + C.flash_eyes() - for(var/i=1, i<=deliveryamt, i++) - var/atom/movable/x = new spawner_type - x.admin_spawned = admin_spawned - x.loc = T - if(prob(50)) - for(var/j = 1, j <= rand(1, 3), j++) - step(x, pick(NORTH,SOUTH,EAST,WEST)) + for(var/i=1, i<=deliveryamt, i++) + var/atom/movable/x = new spawner_type + x.admin_spawned = admin_spawned + x.loc = T + if(prob(50)) + for(var/j = 1, j <= rand(1, 3), j++) + step(x, pick(NORTH,SOUTH,EAST,WEST)) - // Spawn some hostile syndicate critters + // Spawn some hostile syndicate critters - qdel(src) - return + qdel(src) + return /obj/item/grenade/spawnergrenade/manhacks name = "manhack delivery grenade" diff --git a/code/game/objects/items/weapons/implants/implantchair.dm b/code/game/objects/items/weapons/implants/implantchair.dm index d74ab31a6c3..00a72f3401b 100644 --- a/code/game/objects/items/weapons/implants/implantchair.dm +++ b/code/game/objects/items/weapons/implants/implantchair.dm @@ -17,13 +17,6 @@ var/mob/living/carbon/occupant = null var/injecting = 0 -/obj/machinery/implantchair/proc - go_out() - put_mob(mob/living/carbon/M) - implant(var/mob/M) - add_implants() - - /obj/machinery/implantchair/New() ..() add_implants() @@ -87,7 +80,7 @@ return -/obj/machinery/implantchair/go_out(mob/M) +/obj/machinery/implantchair/proc/go_out(mob/M) if(!( src.occupant )) return if(M == occupant) // so that the guy inside can't eject himself -Agouri @@ -101,7 +94,7 @@ return -/obj/machinery/implantchair/put_mob(mob/living/carbon/M) +/obj/machinery/implantchair/proc/put_mob(mob/living/carbon/M) if(!iscarbon(M)) to_chat(usr, "The [src.name] cannot hold this!") return @@ -116,7 +109,7 @@ return 1 -/obj/machinery/implantchair/implant(mob/M) +/obj/machinery/implantchair/proc/implant(mob/M) if(!istype(M, /mob/living/carbon)) return if(!implant_list.len) return @@ -131,7 +124,7 @@ return -/obj/machinery/implantchair/add_implants() +/obj/machinery/implantchair/proc/add_implants() for(var/i=0, i[user] slams the charged axe into [M.name] with all [user.p_their()] might!
") + do_sparks(1, 1, src) + M.Weaken(4) + var/atom/throw_target = get_edge_target_turf(M, get_dir(src, get_step_away(M, src))) + M.throw_at(throw_target, 5, 1) + /* * Double-Bladed Energy Swords - Cheridan */ @@ -755,57 +791,6 @@ charged = 3 playsound(user, 'sound/weapons/marauder.ogg', 50, 1) -// Energized Fire axe -/obj/item/twohanded/energizedfireaxe - name = "energized fire axe" - desc = "Someone with a love for fire axes decided to turn one into a single-charge energy weapon. Seems excessive." - icon_state = "fireaxe0" - force = 5 - throwforce = 15 - sharp = TRUE - w_class = WEIGHT_CLASS_HUGE - armour_penetration = 20 - slot_flags = SLOT_BACK - force_unwielded = 5 - force_wielded = 30 - attack_verb = list("attacked", "chopped", "cleaved", "torn", "cut") - hitsound = 'sound/weapons/bladeslice.ogg' - armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 30) - var/charged = 1 - -/obj/item/twohanded/energizedfireaxe/update_icon() - if(wielded) - icon_state = "fireaxe2" - else - icon_state = "fireaxe0" - ..() - -/obj/item/twohanded/energizedfireaxe/afterattack(atom/A, mob/user, proximity) - if(!proximity) - return - if(wielded) - if(isliving(A)) - var/mob/living/Z = A - if(charged) - charged-- - Z.take_organ_damage(0, 30) - user.visible_message("[user] slams the charged axe into [Z.name] with all [user.p_their()] might!") - playsound(loc, 'sound/magic/lightningbolt.ogg', 5, 1) - do_sparks(1, 1, src) - - if(A && wielded && (istype(A, /obj/structure/window) || istype(A, /obj/structure/grille))) - if(istype(A, /obj/structure/window)) - var/obj/structure/window/W = A - W.deconstruct(FALSE) - if(prob(4)) - charged++ - user.visible_message("The axe starts to emit an electric buzz!") - else - qdel(A) - if(prob(4)) - charged++ - user.visible_message("The axe starts to emit an electric buzz!") - /obj/item/twohanded/pitchfork icon_state = "pitchfork0" name = "pitchfork" diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index e5f903a1853..28e213c7826 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -185,6 +185,7 @@ throwforce = 12 attack_verb = list("beat", "smacked") w_class = WEIGHT_CLASS_HUGE + var/next_throw_time = 0 var/homerun_ready = 0 var/homerun_able = 0 @@ -253,16 +254,38 @@ to_chat(user, "You cannot attack in deflect mode!") return . = ..() - var/atom/throw_target = get_edge_target_turf(target, user.dir) if(homerun_ready) + var/atom/throw_target = get_edge_target_turf(target, user.dir) user.visible_message("It's a home run!") target.throw_at(throw_target, rand(8,10), 14, user) target.ex_act(2) playsound(get_turf(src), 'sound/weapons/homerun.ogg', 100, 1) homerun_ready = 0 return - else if(!target.anchored) - target.throw_at(throw_target, rand(1,2), 7, user) + if(world.time < next_throw_time) + // Limit the rate of throwing, so you can't spam it. + return + if(!istype(target)) + // Should already be /mob/living, but check anyway. + return + if(target.anchored) + // No throwing mobs that are anchored to the floor. + return + if(target.mob_size > MOB_SIZE_HUMAN) + // No throwing things that are physically bigger than you are. + // Covers: blobbernaut, alien empress, ai core, juggernaut, ed209, mulebot, alien/queen/large, carp/megacarp, deathsquid, hostile/tree, megafauna, hostile/asteroid, terror_spider/queen/empress + return + if(!(target.status_flags & CANPUSH)) + // No throwing mobs specifically flagged as immune to being pushed. + // Covers: revenant, hostile/blob/*, most borgs, juggernauts, hivebot/tele, spaceworms, shades, bots, alien queens, hostile/syndicate/melee, hostile/asteroid + return + if(target.move_resist > MOVE_RESIST_DEFAULT) + // No throwing mobs that have higher than normal move_resist. + // Covers: revenant, bot/mulebot, hostile/statue, hostile/megafauna, goliath + return + var/atom/throw_target = get_edge_target_turf(target, user.dir) + target.throw_at(throw_target, rand(1, 2), 7, user) + next_throw_time = world.time + 10 SECONDS /obj/item/melee/baseball_bat/ablative name = "metal baseball bat" diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index bbd43db7c1e..e41d2173c23 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -51,6 +51,8 @@ take_damage(AM.throwforce, BRUTE, "melee", 1, get_dir(src, AM)) /obj/ex_act(severity) + if(QDELETED(src)) + return if(resistance_flags & INDESTRUCTIBLE) return switch(severity) diff --git a/code/game/objects/random/random.dm b/code/game/objects/random/random.dm index 59cc3898088..52b70590ee4 100644 --- a/code/game/objects/random/random.dm +++ b/code/game/objects/random/random.dm @@ -30,13 +30,14 @@ desc = "This is a random tool" icon = 'icons/obj/items.dmi' icon_state = "welder" - item_to_spawn() - return pick(/obj/item/screwdriver,\ - /obj/item/wirecutters,\ - /obj/item/weldingtool,\ - /obj/item/crowbar,\ - /obj/item/wrench,\ - /obj/item/flashlight) + +/obj/random/tool/item_to_spawn() + return pick(/obj/item/screwdriver,\ + /obj/item/wirecutters,\ + /obj/item/weldingtool,\ + /obj/item/crowbar,\ + /obj/item/wrench,\ + /obj/item/flashlight) /obj/random/technology_scanner @@ -44,10 +45,11 @@ desc = "This is a random technology scanner." icon = 'icons/obj/device.dmi' icon_state = "atmos" - item_to_spawn() - return pick(prob(5);/obj/item/t_scanner,\ - prob(2);/obj/item/radio/intercom,\ - prob(5);/obj/item/analyzer) + +/obj/random/technology_scanner/item_to_spawn() + return pick(prob(5);/obj/item/t_scanner,\ + prob(2);/obj/item/radio/intercom,\ + prob(5);/obj/item/analyzer) /obj/random/powercell @@ -55,23 +57,24 @@ desc = "This is a random powercell." icon = 'icons/obj/power.dmi' icon_state = "cell" - item_to_spawn() - return pick(prob(10);/obj/item/stock_parts/cell/crap,\ - prob(40);/obj/item/stock_parts/cell,\ - prob(40);/obj/item/stock_parts/cell/high,\ - prob(9);/obj/item/stock_parts/cell/super,\ - prob(1);/obj/item/stock_parts/cell/hyper) +/obj/random/powercell/item_to_spawn() + return pick(prob(10);/obj/item/stock_parts/cell/crap,\ + prob(40);/obj/item/stock_parts/cell,\ + prob(40);/obj/item/stock_parts/cell/high,\ + prob(9);/obj/item/stock_parts/cell/super,\ + prob(1);/obj/item/stock_parts/cell/hyper) /obj/random/bomb_supply name = "Bomb Supply" desc = "This is a random bomb supply." icon = 'icons/obj/assemblies/new_assemblies.dmi' icon_state = "signaller" - item_to_spawn() - return pick(/obj/item/assembly/igniter,\ - /obj/item/assembly/prox_sensor,\ - /obj/item/assembly/signaler) + +/obj/random/bomb_supply/item_to_spawn() + return pick(/obj/item/assembly/igniter,\ + /obj/item/assembly/prox_sensor,\ + /obj/item/assembly/signaler) /obj/random/toolbox @@ -79,11 +82,11 @@ desc = "This is a random toolbox." icon = 'icons/obj/storage.dmi' icon_state = "red" - item_to_spawn() - return pick(prob(3);/obj/item/storage/toolbox/mechanical,\ - prob(2);/obj/item/storage/toolbox/electrical,\ - prob(1);/obj/item/storage/toolbox/emergency) +/obj/random/toolbox/item_to_spawn() + return pick(prob(3);/obj/item/storage/toolbox/mechanical,\ + prob(2);/obj/item/storage/toolbox/electrical,\ + prob(1);/obj/item/storage/toolbox/emergency) /obj/random/tech_supply name = "Random Tech Supply" @@ -91,15 +94,16 @@ icon = 'icons/obj/power.dmi' icon_state = "cell" spawn_nothing_percentage = 50 - item_to_spawn() - return pick(prob(3);/obj/random/powercell,\ - prob(2);/obj/random/technology_scanner,\ - prob(1);/obj/item/stack/packageWrap,\ - prob(2);/obj/random/bomb_supply,\ - prob(1);/obj/item/extinguisher,\ - prob(1);/obj/item/clothing/gloves/color/fyellow,\ - prob(3);/obj/item/stack/cable_coil,\ - prob(2);/obj/random/toolbox,\ - prob(2);/obj/item/storage/belt/utility,\ - prob(5);/obj/random/tool,\ - prob(3);/obj/item/stack/tape_roll) + +/obj/random/tech_supply/item_to_spawn() + return pick(prob(3);/obj/random/powercell,\ + prob(2);/obj/random/technology_scanner,\ + prob(1);/obj/item/stack/packageWrap,\ + prob(2);/obj/random/bomb_supply,\ + prob(1);/obj/item/extinguisher,\ + prob(1);/obj/item/clothing/gloves/color/fyellow,\ + prob(3);/obj/item/stack/cable_coil,\ + prob(2);/obj/random/toolbox,\ + prob(2);/obj/item/storage/belt/utility,\ + prob(5);/obj/random/tool,\ + prob(3);/obj/item/stack/tape_roll) diff --git a/code/game/objects/structures/crates_lockers/closets/syndicate.dm b/code/game/objects/structures/crates_lockers/closets/syndicate.dm index d95eac2a0ac..8f812397ef9 100644 --- a/code/game/objects/structures/crates_lockers/closets/syndicate.dm +++ b/code/game/objects/structures/crates_lockers/closets/syndicate.dm @@ -61,89 +61,89 @@ new /obj/item/clothing/mask/gas/syndicate(src) new /obj/item/clothing/suit/space/hardsuit/syndi/elite/sst(src) -/obj/structure/closet/syndicate/resources/ +/obj/structure/closet/syndicate/resources desc = "An old, dusty locker." - New() - ..() - var/common_min = 30 //Minimum amount of minerals in the stack for common minerals - var/common_max = 50 //Maximum amount of HONK in the stack for HONK common minerals - var/rare_min = 5 //Minimum HONK of HONK in the stack HONK HONK rare minerals - var/rare_max = 20 //Maximum HONK HONK HONK in the HONK for HONK rare HONK +/obj/structure/closet/syndicate/resources/New() + ..() + var/common_min = 30 //Minimum amount of minerals in the stack for common minerals + var/common_max = 50 //Maximum amount of HONK in the stack for HONK common minerals + var/rare_min = 5 //Minimum HONK of HONK in the stack HONK HONK rare minerals + var/rare_max = 20 //Maximum HONK HONK HONK in the HONK for HONK rare HONK - var/pickednum = rand(1, 50) + var/pickednum = rand(1, 50) - //Sad trombone - if(pickednum == 1) - var/obj/item/paper/P = new /obj/item/paper(src) - P.name = "IOU" - P.info = "Sorry man, we needed the money so we sold your stash. It's ok, we'll double our money for sure this time!" + //Sad trombone + if(pickednum == 1) + var/obj/item/paper/P = new /obj/item/paper(src) + P.name = "IOU" + P.info = "Sorry man, we needed the money so we sold your stash. It's ok, we'll double our money for sure this time!" - //Metal (common ore) - if(pickednum >= 2) - new /obj/item/stack/sheet/metal(src, rand(common_min, common_max)) + //Metal (common ore) + if(pickednum >= 2) + new /obj/item/stack/sheet/metal(src, rand(common_min, common_max)) - //Glass (common ore) - if(pickednum >= 5) - new /obj/item/stack/sheet/glass(src, rand(common_min, common_max)) + //Glass (common ore) + if(pickednum >= 5) + new /obj/item/stack/sheet/glass(src, rand(common_min, common_max)) - //Plasteel (common ore) Because it has a million more uses then plasma - if(pickednum >= 10) - new /obj/item/stack/sheet/plasteel(src, rand(common_min, common_max)) + //Plasteel (common ore) Because it has a million more uses then plasma + if(pickednum >= 10) + new /obj/item/stack/sheet/plasteel(src, rand(common_min, common_max)) - //Plasma (rare ore) - if(pickednum >= 15) - new /obj/item/stack/sheet/mineral/plasma(src, rand(rare_min, rare_max)) + //Plasma (rare ore) + if(pickednum >= 15) + new /obj/item/stack/sheet/mineral/plasma(src, rand(rare_min, rare_max)) - //Silver (rare ore) - if(pickednum >= 20) - new /obj/item/stack/sheet/mineral/silver(src, rand(rare_min, rare_max)) + //Silver (rare ore) + if(pickednum >= 20) + new /obj/item/stack/sheet/mineral/silver(src, rand(rare_min, rare_max)) - //Gold (rare ore) - if(pickednum >= 30) - new /obj/item/stack/sheet/mineral/gold(src, rand(rare_min, rare_max)) + //Gold (rare ore) + if(pickednum >= 30) + new /obj/item/stack/sheet/mineral/gold(src, rand(rare_min, rare_max)) - //Uranium (rare ore) - if(pickednum >= 40) - new /obj/item/stack/sheet/mineral/uranium(src, rand(rare_min, rare_max)) + //Uranium (rare ore) + if(pickednum >= 40) + new /obj/item/stack/sheet/mineral/uranium(src, rand(rare_min, rare_max)) - //Titanium (rare ore) - if(pickednum >= 40) - new /obj/item/stack/sheet/mineral/titanium(src, rand(rare_min, rare_max)) + //Titanium (rare ore) + if(pickednum >= 40) + new /obj/item/stack/sheet/mineral/titanium(src, rand(rare_min, rare_max)) - //Plastitanium (rare ore) - if(pickednum >= 40) - new /obj/item/stack/sheet/mineral/plastitanium(src, rand(rare_min, rare_max)) + //Plastitanium (rare ore) + if(pickednum >= 40) + new /obj/item/stack/sheet/mineral/plastitanium(src, rand(rare_min, rare_max)) - //Diamond (rare HONK) - if(pickednum >= 45) - new /obj/item/stack/sheet/mineral/diamond(src, rand(rare_min, rare_max)) + //Diamond (rare HONK) + if(pickednum >= 45) + new /obj/item/stack/sheet/mineral/diamond(src, rand(rare_min, rare_max)) - //Jetpack (You hit the jackpot!) - if(pickednum == 50) - new /obj/item/tank/jetpack/carbondioxide(src) + //Jetpack (You hit the jackpot!) + if(pickednum == 50) + new /obj/item/tank/jetpack/carbondioxide(src) /obj/structure/closet/syndicate/resources/everything desc = "It's an emergency storage closet for repairs." - New() - ..() - var/list/resources = list( - /obj/item/stack/sheet/metal, - /obj/item/stack/sheet/glass, - /obj/item/stack/sheet/mineral/gold, - /obj/item/stack/sheet/mineral/silver, - /obj/item/stack/sheet/mineral/plasma, - /obj/item/stack/sheet/mineral/uranium, - /obj/item/stack/sheet/mineral/diamond, - /obj/item/stack/sheet/mineral/bananium, - /obj/item/stack/sheet/mineral/titanium, - /obj/item/stack/sheet/mineral/plastitanium, - /obj/item/stack/sheet/plasteel, - /obj/item/stack/rods - ) +/obj/structure/closet/syndicate/resources/everything/New() + ..() + var/list/resources = list( + /obj/item/stack/sheet/metal, + /obj/item/stack/sheet/glass, + /obj/item/stack/sheet/mineral/gold, + /obj/item/stack/sheet/mineral/silver, + /obj/item/stack/sheet/mineral/plasma, + /obj/item/stack/sheet/mineral/uranium, + /obj/item/stack/sheet/mineral/diamond, + /obj/item/stack/sheet/mineral/bananium, + /obj/item/stack/sheet/mineral/titanium, + /obj/item/stack/sheet/mineral/plastitanium, + /obj/item/stack/sheet/plasteel, + /obj/item/stack/rods + ) - for(var/i in 1 to 2) - for(var/res in resources) - var/obj/item/stack/R = new res(src) - R.amount = R.max_amount + for(var/i in 1 to 2) + for(var/res in resources) + var/obj/item/stack/R = new res(src) + R.amount = R.max_amount diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 2441a2d57d6..61db52bf8a0 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -187,6 +187,7 @@ if(user) to_chat(user, "The crate's anti-tamper system activates!") investigate_log("[key_name(user)] has detonated a [src]", INVESTIGATE_BOMB) + add_attack_logs(user, src, "has detonated", ATKLOG_MOST) for(var/atom/movable/AM in src) qdel(AM) explosion(get_turf(src), 0, 1, 5, 5) @@ -338,24 +339,23 @@ var/target_temp = T0C - 40 var/cooling_power = 40 - return_air() - var/datum/gas_mixture/gas = (..()) - if(!gas) return null - var/datum/gas_mixture/newgas = new/datum/gas_mixture() - newgas.oxygen = gas.oxygen - newgas.carbon_dioxide = gas.carbon_dioxide - newgas.nitrogen = gas.nitrogen - newgas.toxins = gas.toxins - newgas.volume = gas.volume - newgas.temperature = gas.temperature - if(newgas.temperature <= target_temp) return - - if((newgas.temperature - cooling_power) > target_temp) - newgas.temperature -= cooling_power - else - newgas.temperature = target_temp - return newgas +/obj/structure/closet/crate/freezer/return_air() + var/datum/gas_mixture/gas = (..()) + if(!gas) return null + var/datum/gas_mixture/newgas = new/datum/gas_mixture() + newgas.oxygen = gas.oxygen + newgas.carbon_dioxide = gas.carbon_dioxide + newgas.nitrogen = gas.nitrogen + newgas.toxins = gas.toxins + newgas.volume = gas.volume + newgas.temperature = gas.temperature + if(newgas.temperature <= target_temp) return + if((newgas.temperature - cooling_power) > target_temp) + newgas.temperature -= cooling_power + else + newgas.temperature = target_temp + return newgas /obj/structure/closet/crate/can desc = "A large can, looks like a bin to me." @@ -496,22 +496,23 @@ /obj/structure/closet/crate/hydroponics/prespawned //This exists so the prespawned hydro crates spawn with their contents. - New() - ..() - new /obj/item/reagent_containers/glass/bucket(src) - new /obj/item/reagent_containers/glass/bucket(src) - new /obj/item/screwdriver(src) - new /obj/item/screwdriver(src) - new /obj/item/wrench(src) - new /obj/item/wrench(src) - new /obj/item/wirecutters(src) - new /obj/item/wirecutters(src) - new /obj/item/shovel/spade(src) - new /obj/item/shovel/spade(src) - new /obj/item/storage/box/beakers(src) - new /obj/item/storage/box/beakers(src) - new /obj/item/hand_labeler(src) - new /obj/item/hand_labeler(src) +// Do I need the definition above? Who knows! +/obj/structure/closet/crate/hydroponics/prespawned/New() + ..() + new /obj/item/reagent_containers/glass/bucket(src) + new /obj/item/reagent_containers/glass/bucket(src) + new /obj/item/screwdriver(src) + new /obj/item/screwdriver(src) + new /obj/item/wrench(src) + new /obj/item/wrench(src) + new /obj/item/wirecutters(src) + new /obj/item/wirecutters(src) + new /obj/item/shovel/spade(src) + new /obj/item/shovel/spade(src) + new /obj/item/storage/box/beakers(src) + new /obj/item/storage/box/beakers(src) + new /obj/item/hand_labeler(src) + new /obj/item/hand_labeler(src) /obj/structure/closet/crate/sci name = "science crate" diff --git a/code/game/objects/structures/displaycase.dm b/code/game/objects/structures/displaycase.dm index 36a20aa0239..0ad8a73c9ba 100644 --- a/code/game/objects/structures/displaycase.dm +++ b/code/game/objects/structures/displaycase.dm @@ -144,7 +144,7 @@ to_chat(user, "You [open ? "close":"open"] [src].") toggle_lock(user) -obj/structure/displaycase/welder_act(mob/user, obj/item/I) +/obj/structure/displaycase/welder_act(mob/user, obj/item/I) . = TRUE if(default_welder_repair(user, I)) broken = FALSE diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm index 0c0a7f5e4dd..73f8bbfff41 100644 --- a/code/game/objects/structures/dresser.dm +++ b/code/game/objects/structures/dresser.dm @@ -67,7 +67,7 @@ . = TRUE default_unfasten_wrench(user, I, time = 20) -obj/structure/dresser/deconstruct(disassembled = FALSE) +/obj/structure/dresser/deconstruct(disassembled = FALSE) var/mat_drop = 15 if(disassembled) mat_drop = 30 diff --git a/code/game/objects/structures/lavaland/necropolis_tendril.dm b/code/game/objects/structures/lavaland/necropolis_tendril.dm index f9717956bb0..13c0ce77c0f 100644 --- a/code/game/objects/structures/lavaland/necropolis_tendril.dm +++ b/code/game/objects/structures/lavaland/necropolis_tendril.dm @@ -15,7 +15,6 @@ anchored = TRUE resistance_flags = FIRE_PROOF | LAVA_PROOF - var/gps = null var/obj/effect/light_emitter/tendril/emitted_light /obj/structure/spawner/lavaland/goliath @@ -29,7 +28,6 @@ GLOBAL_LIST_INIT(tendrils, list()) /obj/structure/spawner/lavaland/Initialize(mapload) . = ..() emitted_light = new(loc) - gps = new /obj/item/gps/internal(src) GLOB.tendrils += src return INITIALIZE_HINT_LATELOAD @@ -59,7 +57,6 @@ GLOBAL_LIST_INIT(tendrils, list()) SSmedals.SetScore(TENDRIL_CLEAR_SCORE, L.client, 1) GLOB.tendrils -= src QDEL_NULL(emitted_light) - QDEL_NULL(gps) return ..() /obj/effect/light_emitter/tendril diff --git a/code/game/objects/structures/misc.dm b/code/game/objects/structures/misc.dm index 44cbf6c52c9..5118a7fe0da 100644 --- a/code/game/objects/structures/misc.dm +++ b/code/game/objects/structures/misc.dm @@ -11,8 +11,8 @@ anchored = 1 density = 1 - attack_hand(mob/user as mob) - to_chat(user, "Civilians: NT is recruiting! Please head SOUTH to the NT Recruitment office to join the station's crew!") +/obj/structure/signpost/attack_hand(mob/user as mob) + to_chat(user, "Civilians: NT is recruiting! Please head SOUTH to the NT Recruitment office to join the station's crew!") /obj/structure/ninjatele @@ -23,31 +23,28 @@ anchored = 1 density = 0 - attack_hand(mob/user as mob) - - - if(user.mind.special_role=="Ninja") - switch(alert("Phase Jaunt relay primed, target locked as [station_name()], initiate VOID-shift translocation? (Warning! Internals required!)",,"Yes","No")) - - if("Yes") - if(user.z != src.z) return - - user.loc.loc.Exited(user) - user.loc = pick(GLOB.carplist) // In the future, possibly make specific NinjaTele landmarks, and give him an option to teleport to North/South/East/West of SS13 instead of just hijacking a carpspawn. - - - playsound(user.loc, 'sound/effects/phasein.ogg', 25, 1) - playsound(user.loc, 'sound/effects/sparks2.ogg', 50, 1) - new /obj/effect/temp_visual/dir_setting/ninja/phase(get_turf(user), user.dir) - to_chat(user, "VOID-Shift translocation successful") - - if("No") - - to_chat(user, "Process aborted!") +/obj/structure/ninjatele/attack_hand(mob/user as mob) + if(user.mind.special_role=="Ninja") + switch(alert("Phase Jaunt relay primed, target locked as [station_name()], initiate VOID-shift translocation? (Warning! Internals required!)",,"Yes","No")) + if("Yes") + if(user.z != src.z) return - else - to_chat(user, "FĆAL �Rr�R: ŧer nt recgnized, c-cntr-r䣧-ç äcked.") + + user.loc.loc.Exited(user) + user.loc = pick(GLOB.carplist) // In the future, possibly make specific NinjaTele landmarks, and give him an option to teleport to North/South/East/West of SS13 instead of just hijacking a carpspawn. + + playsound(user.loc, 'sound/effects/phasein.ogg', 25, 1) + playsound(user.loc, 'sound/effects/sparks2.ogg', 50, 1) + new /obj/effect/temp_visual/dir_setting/ninja/phase(get_turf(user), user.dir) + to_chat(user, "VOID-Shift translocation successful") + + if("No") + to_chat(user, "Process aborted!") + return + + else + to_chat(user, "FĆAL �Rr�R: ŧer nt recgnized, c-cntr-r䣧-ç äcked.") /obj/structure/respawner name = "\improper Long-Distance Cloning Machine" diff --git a/code/game/objects/structures/transit_tubes/transit_tube.dm b/code/game/objects/structures/transit_tubes/transit_tube.dm index c7926870ccf..650df02c59b 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube.dm @@ -26,7 +26,7 @@ return !density // When destroyed by explosions, properly handle contents. -obj/structure/transit_tube/ex_act(severity) +/obj/structure/transit_tube/ex_act(severity) switch(severity) if(1.0) for(var/atom/movable/AM in contents) diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index 3a1546bdd2b..0a059198d2a 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -31,14 +31,14 @@ . = ..() . += "Alt-click to rotate it clockwise." -obj/structure/windoor_assembly/New(loc, set_dir) +/obj/structure/windoor_assembly/New(loc, set_dir) ..() if(set_dir) dir = set_dir ini_dir = dir air_update_turf(1) -obj/structure/windoor_assembly/Destroy() +/obj/structure/windoor_assembly/Destroy() density = FALSE QDEL_NULL(electronics) air_update_turf(1) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 9faab45cf97..cfe8a20cce7 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -666,7 +666,7 @@ GLOBAL_LIST_INIT(wcCommon, pick(list("#379963", "#0d8395", "#58b5c3", "#49e46e", icon_state = "tinted_window" opacity = 1 -obj/structure/window/full/reinforced/ice +/obj/structure/window/full/reinforced/ice icon = 'icons/obj/smooth_structures/rice_window.dmi' icon_state = "ice_window" max_integrity = 150 diff --git a/code/game/shuttle_engines.dm b/code/game/shuttle_engines.dm index 3c1ba0b8fbc..415df5d9dde 100644 --- a/code/game/shuttle_engines.dm +++ b/code/game/shuttle_engines.dm @@ -19,11 +19,13 @@ opacity = 0 anchored = 1 - CanPass(atom/movable/mover, turf/target, height) - if(!height) return 0 - else return ..() +/obj/structure/shuttle/window/CanPass(atom/movable/mover, turf/target, height) + if(!height) + return 0 + else + return ..() - CanAtmosPass(turf/T) +/obj/structure/shuttle/window/CanAtmosPass(turf/T) return !density /obj/structure/shuttle/engine diff --git a/code/game/turfs/simulated/floor/light_floor.dm b/code/game/turfs/simulated/floor/light_floor.dm index 8276c0de33f..0d27e02537f 100644 --- a/code/game/turfs/simulated/floor/light_floor.dm +++ b/code/game/turfs/simulated/floor/light_floor.dm @@ -11,12 +11,12 @@ #define LIGHTFLOOR_CYCLEB 10 /turf/simulated/floor/light - name = "Light floor" + name = "\improper light floor" light_range = 5 icon_state = "light_on" floor_tile = /obj/item/stack/tile/light broken_states = list("light_broken") - var/on = 1 + var/on = TRUE var/state = LIGHTFLOOR_ON var/can_modify_colour = TRUE @@ -30,34 +30,34 @@ switch(state) if(LIGHTFLOOR_ON) icon_state = "light_on" - set_light(5,null,LIGHT_COLOR_LIGHTBLUE) + set_light(5, null,LIGHT_COLOR_LIGHTBLUE) if(LIGHTFLOOR_WHITE) icon_state = "light_on-w" - set_light(5,null,LIGHT_COLOR_WHITE) + set_light(5, null,LIGHT_COLOR_WHITE) if(LIGHTFLOOR_RED) icon_state = "light_on-r" - set_light(5,null,LIGHT_COLOR_RED) + set_light(5, null,LIGHT_COLOR_RED) if(LIGHTFLOOR_GREEN) icon_state = "light_on-g" - set_light(5,null,LIGHT_COLOR_PURE_GREEN) + set_light(5, null,LIGHT_COLOR_PURE_GREEN) if(LIGHTFLOOR_YELLOW) icon_state = "light_on-y" - set_light(5,null,"#FFFF00") + set_light(5, null,"#FFFF00") if(LIGHTFLOOR_BLUE) icon_state = "light_on-b" - set_light(5,null,LIGHT_COLOR_DARKBLUE) + set_light(5, null,LIGHT_COLOR_DARKBLUE) if(LIGHTFLOOR_PURPLE) icon_state = "light_on-p" - set_light(5,null,LIGHT_COLOR_PURPLE) + set_light(5, null,LIGHT_COLOR_PURPLE) if(LIGHTFLOOR_GENERICCYCLE) icon_state = "light_on-cycle_all" - set_light(5,null,LIGHT_COLOR_WHITE) + set_light(5, null,LIGHT_COLOR_WHITE) if(LIGHTFLOOR_CYCLEA) icon_state = "light_on-dancefloor_A" set_light(5,null,LIGHT_COLOR_RED) if(LIGHTFLOOR_CYCLEB) icon_state = "light_on-dancefloor_B" - set_light(5,null,LIGHT_COLOR_DARKBLUE) + set_light(5, null,LIGHT_COLOR_DARKBLUE) else icon_state = "light_off" set_light(0) @@ -72,11 +72,10 @@ /turf/simulated/floor/light/attack_hand(mob/user) if(!can_modify_colour) return - on = !on - update_icon() + toggle_light(!on) /turf/simulated/floor/light/attackby(obj/item/C, mob/user, params) - if(istype(C,/obj/item/light/bulb)) //only for light tiles + if(istype(C, /obj/item/light/bulb)) //only for light tiles if(!state) qdel(C) state = LIGHTFLOOR_ON @@ -103,6 +102,16 @@ else to_chat(user, "[src]'s light bulb appears to have burned out.") +/turf/simulated/floor/light/proc/toggle_light(light) + // 0 = OFF + // 1 = ON + on = light + update_icon() + +/turf/simulated/floor/light/extinguish_light() + toggle_light(FALSE) + visible_message("[src] flickers and falls dark.") + //Cycles through all of the colours /turf/simulated/floor/light/colour_cycle state = LIGHTFLOOR_GENERICCYCLE @@ -119,3 +128,16 @@ name = "dancefloor" desc = "Funky floor." state = LIGHTFLOOR_CYCLEB + + +#undef LIGHTFLOOR_ON +#undef LIGHTFLOOR_WHITE +#undef LIGHTFLOOR_RED +#undef LIGHTFLOOR_GREEN +#undef LIGHTFLOOR_YELLOW +#undef LIGHTFLOOR_BLUE +#undef LIGHTFLOOR_PURPLE + +#undef LIGHTFLOOR_GENERICCYCLE +#undef LIGHTFLOOR_CYCLEA +#undef LIGHTFLOOR_CYCLEB diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm index dda49fecdbd..b8110cf2b54 100644 --- a/code/game/turfs/space/transit.dm +++ b/code/game/turfs/space/transit.dm @@ -11,72 +11,98 @@ pushdirection = SOUTH // south because the space tile is scrolling south //IF ANYONE KNOWS A MORE EFFICIENT WAY OF MANAGING THESE SPRITES, BE MY GUEST. - shuttlespace_ns1 - icon_state = "speedspace_ns_1" - shuttlespace_ns2 - icon_state = "speedspace_ns_2" - shuttlespace_ns3 - icon_state = "speedspace_ns_3" - shuttlespace_ns4 - icon_state = "speedspace_ns_4" - shuttlespace_ns5 - icon_state = "speedspace_ns_5" - shuttlespace_ns6 - icon_state = "speedspace_ns_6" - shuttlespace_ns7 - icon_state = "speedspace_ns_7" - shuttlespace_ns8 - icon_state = "speedspace_ns_8" - shuttlespace_ns9 - icon_state = "speedspace_ns_9" - shuttlespace_ns10 - icon_state = "speedspace_ns_10" - shuttlespace_ns11 - icon_state = "speedspace_ns_11" - shuttlespace_ns12 - icon_state = "speedspace_ns_12" - shuttlespace_ns13 - icon_state = "speedspace_ns_13" - shuttlespace_ns14 - icon_state = "speedspace_ns_14" - shuttlespace_ns15 - icon_state = "speedspace_ns_15" +/turf/space/transit/north/shuttlespace_ns1 + icon_state = "speedspace_ns_1" + +/turf/space/transit/north/shuttlespace_ns2 + icon_state = "speedspace_ns_2" + +/turf/space/transit/north/shuttlespace_ns3 + icon_state = "speedspace_ns_3" + +/turf/space/transit/north/shuttlespace_ns4 + icon_state = "speedspace_ns_4" + +/turf/space/transit/north/shuttlespace_ns5 + icon_state = "speedspace_ns_5" + +/turf/space/transit/north/shuttlespace_ns6 + icon_state = "speedspace_ns_6" + +/turf/space/transit/north/shuttlespace_ns7 + icon_state = "speedspace_ns_7" + +/turf/space/transit/north/shuttlespace_ns8 + icon_state = "speedspace_ns_8" + +/turf/space/transit/north/shuttlespace_ns9 + icon_state = "speedspace_ns_9" + +/turf/space/transit/north/shuttlespace_ns10 + icon_state = "speedspace_ns_10" + +/turf/space/transit/north/shuttlespace_ns11 + icon_state = "speedspace_ns_11" + +/turf/space/transit/north/shuttlespace_ns12 + icon_state = "speedspace_ns_12" + +/turf/space/transit/north/shuttlespace_ns13 + icon_state = "speedspace_ns_13" + +/turf/space/transit/north/shuttlespace_ns14 + icon_state = "speedspace_ns_14" + +/turf/space/transit/north/shuttlespace_ns15 + icon_state = "speedspace_ns_15" /turf/space/transit/east // moving to the east - pushdirection = WEST - shuttlespace_ew1 - icon_state = "speedspace_ew_1" - shuttlespace_ew2 - icon_state = "speedspace_ew_2" - shuttlespace_ew3 - icon_state = "speedspace_ew_3" - shuttlespace_ew4 - icon_state = "speedspace_ew_4" - shuttlespace_ew5 - icon_state = "speedspace_ew_5" - shuttlespace_ew6 - icon_state = "speedspace_ew_6" - shuttlespace_ew7 - icon_state = "speedspace_ew_7" - shuttlespace_ew8 - icon_state = "speedspace_ew_8" - shuttlespace_ew9 - icon_state = "speedspace_ew_9" - shuttlespace_ew10 - icon_state = "speedspace_ew_10" - shuttlespace_ew11 - icon_state = "speedspace_ew_11" - shuttlespace_ew12 - icon_state = "speedspace_ew_12" - shuttlespace_ew13 - icon_state = "speedspace_ew_13" - shuttlespace_ew14 - icon_state = "speedspace_ew_14" - shuttlespace_ew15 - icon_state = "speedspace_ew_15" +/turf/space/transit/east/shuttlespace_ew1 + icon_state = "speedspace_ew_1" +/turf/space/transit/east/shuttlespace_ew2 + icon_state = "speedspace_ew_2" + +/turf/space/transit/east/shuttlespace_ew3 + icon_state = "speedspace_ew_3" + +/turf/space/transit/east/shuttlespace_ew4 + icon_state = "speedspace_ew_4" + +/turf/space/transit/east/shuttlespace_ew5 + icon_state = "speedspace_ew_5" + +/turf/space/transit/east/shuttlespace_ew6 + icon_state = "speedspace_ew_6" + +/turf/space/transit/east/shuttlespace_ew7 + icon_state = "speedspace_ew_7" + +/turf/space/transit/east/shuttlespace_ew8 + icon_state = "speedspace_ew_8" + +/turf/space/transit/east/shuttlespace_ew9 + icon_state = "speedspace_ew_9" + +/turf/space/transit/east/shuttlespace_ew10 + icon_state = "speedspace_ew_10" + +/turf/space/transit/east/shuttlespace_ew11 + icon_state = "speedspace_ew_11" + +/turf/space/transit/east/shuttlespace_ew12 + icon_state = "speedspace_ew_12" + +/turf/space/transit/east/shuttlespace_ew13 + icon_state = "speedspace_ew_13" + +/turf/space/transit/east/shuttlespace_ew14 + icon_state = "speedspace_ew_14" + +/turf/space/transit/east/shuttlespace_ew15 + icon_state = "speedspace_ew_15" //-tg- stuff /turf/space/transit diff --git a/code/game/world.dm b/code/game/world.dm index c279fa24b54..d2828f9c04b 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -222,8 +222,12 @@ GLOBAL_VAR_INIT(world_topic_spam_protect_time, world.timeofday) if(input["key"] != config.comms_password) return "Bad Key" else + var/prtext = input["announce"] + var/pr_substring = copytext(prtext, 1, 23) + if(pr_substring == "Pull Request merged by") + GLOB.pending_server_update = TRUE for(var/client/C in GLOB.clients) - to_chat(C, "PR: [input["announce"]]") + to_chat(C, "PR: [prtext]") else if("kick" in input) /* @@ -270,7 +274,7 @@ GLOBAL_VAR_INIT(world_topic_spam_protect_time, world.timeofday) else if("hostannounce" in input) if(!key_valid) return keySpamProtect(addr) - + GLOB.pending_server_update = TRUE to_chat(world, "
Server Announcement: [input["message"]]
") /proc/keySpamProtect(var/addr) @@ -339,8 +343,12 @@ GLOBAL_VAR_INIT(world_topic_spam_protect_time, world.timeofday) return #endif + var/secs_before_auto_reconnect = 10 + if(GLOB.pending_server_update) + secs_before_auto_reconnect = 60 + to_chat(world, "Reboot will take a little longer, due to pending updates.") for(var/client/C in GLOB.clients) - var/secs_before_auto_reconnect = 10 // TODO: make it higher if server is due for an update @AffectedArc07 + C << output(list2params(list(secs_before_auto_reconnect)), "browseroutput:reboot") 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]") @@ -486,7 +494,7 @@ GLOBAL_VAR_INIT(failed_old_db_connections, 0) return . //This proc ensures that the connection to the feedback database (global variable dbcon) is established -proc/establish_db_connection() +/proc/establish_db_connection() if(GLOB.failed_db_connections > FAILED_DB_CONNECTION_CUTOFF) return 0 diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm index 1f55fa11f70..fd998677d75 100644 --- a/code/modules/admin/DB ban/functions.dm +++ b/code/modules/admin/DB ban/functions.dm @@ -1,6 +1,6 @@ #define MAX_ADMIN_BANS_PER_ADMIN 1 -datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = -1, var/reason, var/job = "", var/rounds = 0, var/banckey = null, var/banip = null, var/bancid = null) +/datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = -1, var/reason, var/job = "", var/rounds = 0, var/banckey = null, var/banip = null, var/bancid = null) if(!check_rights(R_BAN)) return @@ -153,7 +153,7 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = else flag_account_for_forum_sync(ckey) -datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "") +/datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "") if(!check_rights(R_BAN)) return @@ -233,7 +233,7 @@ datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "") else flag_account_for_forum_sync(ckey) -datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null) +/datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null) if(!check_rights(R_BAN)) return @@ -297,7 +297,7 @@ datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null) to_chat(usr, "Cancelled") return -datum/admins/proc/DB_ban_unban_by_id(var/id) +/datum/admins/proc/DB_ban_unban_by_id(var/id) if(!check_rights(R_BAN)) return diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index d9ceba62830..3f69c2199d0 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -1,5 +1,5 @@ //Blocks an attempt to connect before even creating our client datum thing. -world/IsBanned(key, address, computer_id, type, check_ipintel = TRUE) +/world/IsBanned(key, address, computer_id, type, check_ipintel = TRUE) if(!config.ban_legacy_system) if(address) diff --git a/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm b/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm index 56fcab49293..50c852af03b 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_2_parser.dm @@ -89,403 +89,443 @@ /datum/SDQL_parser/proc/tokenl(i) return lowertext(token(i)) -/datum/SDQL_parser/proc - //query: select_query | delete_query | update_query - query(i, list/node) - query_type = tokenl(i) +/datum/SDQL_parser/proc/query(i, list/node) + query_type = tokenl(i) - switch(query_type) - if("select") - select_query(i, node) + switch(query_type) + if("select") + select_query(i, node) - if("delete") - delete_query(i, node) + if("delete") + delete_query(i, node) - if("update") - update_query(i, node) + if("update") + update_query(i, node) - if("call") - call_query(i, node) + if("call") + call_query(i, node) - if("explain") - node += "explain" - node["explain"] = list() - query(i + 1, node["explain"]) + if("explain") + node += "explain" + node["explain"] = list() + query(i + 1, node["explain"]) // select_query: 'SELECT' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] - select_query(i, list/node) - var/list/select = list() - i = select_list(i + 1, select) +/datum/SDQL_parser/proc/select_query(i, list/node) + var/list/select = list() + i = select_list(i + 1, select) - node += "select" - node["select"] = select + node += "select" + node["select"] = select - var/list/from = list() - if(tokenl(i) in list("from", "in")) - i = from_list(i + 1, from) - else - from += "world" + var/list/from = list() + if(tokenl(i) in list("from", "in")) + i = from_list(i + 1, from) + else + from += "world" - node += "from" - node["from"] = from + node += "from" + node["from"] = from - if(tokenl(i) == "where") - var/list/where = list() - i = bool_expression(i + 1, where) + if(tokenl(i) == "where") + var/list/where = list() + i = bool_expression(i + 1, where) - node += "where" - node["where"] = where + node += "where" + node["where"] = where - return i + return i //delete_query: 'DELETE' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression] - delete_query(i, list/node) - var/list/select = list() - i = select_list(i + 1, select) +/datum/SDQL_parser/proc/delete_query(i, list/node) + var/list/select = list() + i = select_list(i + 1, select) - node += "delete" - node["delete"] = select + node += "delete" + node["delete"] = select - var/list/from = list() - if(tokenl(i) in list("from", "in")) - i = from_list(i + 1, from) - else - from += "world" + var/list/from = list() + if(tokenl(i) in list("from", "in")) + i = from_list(i + 1, from) + else + from += "world" - node += "from" - node["from"] = from + node += "from" + node["from"] = from - if(tokenl(i) == "where") - var/list/where = list() - i = bool_expression(i + 1, where) + if(tokenl(i) == "where") + var/list/where = list() + i = bool_expression(i + 1, where) - node += "where" - node["where"] = where + node += "where" + node["where"] = where - return i + return i //update_query: 'UPDATE' select_list [('FROM' | 'IN') from_list] 'SET' assignments ['WHERE' bool_expression] - update_query(i, list/node) - var/list/select = list() - i = select_list(i + 1, select) +/datum/SDQL_parser/proc/update_query(i, list/node) + var/list/select = list() + i = select_list(i + 1, select) - node += "update" - node["update"] = select + node += "update" + node["update"] = select - var/list/from = list() - if(tokenl(i) in list("from", "in")) - i = from_list(i + 1, from) - else - from += "world" + var/list/from = list() + if(tokenl(i) in list("from", "in")) + i = from_list(i + 1, from) + else + from += "world" - node += "from" - node["from"] = from + node += "from" + node["from"] = from - if(tokenl(i) != "set") - i = parse_error("UPDATE has misplaced SET") + if(tokenl(i) != "set") + i = parse_error("UPDATE has misplaced SET") - var/list/set_assignments = list() - i = assignments(i + 1, set_assignments) + var/list/set_assignments = list() + i = assignments(i + 1, set_assignments) - node += "set" - node["set"] = set_assignments + node += "set" + node["set"] = set_assignments - if(tokenl(i) == "where") - var/list/where = list() - i = bool_expression(i + 1, where) + if(tokenl(i) == "where") + var/list/where = list() + i = bool_expression(i + 1, where) - node += "where" - node["where"] = where + node += "where" + node["where"] = where - return i + return i //call_query: 'CALL' call_function ['ON' select_list [('FROM' | 'IN') from_list] ['WHERE' bool_expression]] - call_query(i, list/node) - var/list/func = list() - i = variable(i + 1, func) +/datum/SDQL_parser/proc/call_query(i, list/node) + var/list/func = list() + i = variable(i + 1, func) - node += "call" - node["call"] = func - - if(tokenl(i) != "on") - return i - - var/list/select = list() - i = select_list(i + 1, select) - - node += "on" - node["on"] = select - - var/list/from = list() - if(tokenl(i) in list("from", "in")) - i = from_list(i + 1, from) - else - from += "world" - - node += "from" - node["from"] = from - - if(tokenl(i) == "where") - var/list/where = list() - i = bool_expression(i + 1, where) - - node += "where" - node["where"] = where + node += "call" + node["call"] = func + if(tokenl(i) != "on") return i + var/list/select = list() + i = select_list(i + 1, select) + + node += "on" + node["on"] = select + + var/list/from = list() + if(tokenl(i) in list("from", "in")) + i = from_list(i + 1, from) + else + from += "world" + + node += "from" + node["from"] = from + + if(tokenl(i) == "where") + var/list/where = list() + i = bool_expression(i + 1, where) + + node += "where" + node["where"] = where + + return i + //select_list: select_item [',' select_list] - select_list(i, list/node) - i = select_item(i, node) +/datum/SDQL_parser/proc/select_list(i, list/node) + i = select_item(i, node) - if(token(i) == ",") - i = select_list(i + 1, node) + if(token(i) == ",") + i = select_list(i + 1, node) - return i + return i //from_list: from_item [',' from_list] - from_list(i, list/node) - i = from_item(i, node) +/datum/SDQL_parser/proc/from_list(i, list/node) + i = from_item(i, node) - if(token(i) == ",") - i = from_list(i + 1, node) + if(token(i) == ",") + i = from_list(i + 1, node) - return i + return i //assignments: assignment, [',' assignments] - assignments(i, list/node) - i = assignment(i, node) +/datum/SDQL_parser/proc/assignments(i, list/node) + i = assignment(i, node) - if(token(i) == ",") - i = assignments(i + 1, node) + if(token(i) == ",") + i = assignments(i + 1, node) - return i + return i //select_item: '*' | select_function | object_type - select_item(i, list/node) +/datum/SDQL_parser/proc/select_item(i, list/node) + if(token(i) == "*") + node += "*" + i++ - if(token(i) == "*") - node += "*" - i++ + else if(tokenl(i) in select_functions) + i = select_function(i, node) - else if(tokenl(i) in select_functions) - i = select_function(i, node) + else + i = object_type(i, node) - else - i = object_type(i, node) - - return i + return i //from_item: 'world' | object_type - from_item(i, list/node) +/datum/SDQL_parser/proc/from_item(i, list/node) - if(token(i) == "world") - node += "world" - i++ + if(token(i) == "world") + node += "world" + i++ - else - i = object_type(i, node) + else + i = object_type(i, node) - return i + return i //bool_expression: expression [bool_operator bool_expression] - bool_expression(i, list/node) +/datum/SDQL_parser/proc/bool_expression(i, list/node) + var/list/bool = list() + i = expression(i, bool) - var/list/bool = list() - i = expression(i, bool) + node[++node.len] = bool - node[++node.len] = bool + if(tokenl(i) in boolean_operators) + i = bool_operator(i, node) + i = bool_expression(i, node) - if(tokenl(i) in boolean_operators) - i = bool_operator(i, node) - i = bool_expression(i, node) - - return i + return i //assignment: '=' expression - assignment(var/i, var/list/node, var/list/assignment_list = list()) - assignment_list += token(i) +/datum/SDQL_parser/proc/assignment(var/i, var/list/node, var/list/assignment_list = list()) + assignment_list += token(i) - if(token(i + 1) == ".") - i = assignment(i + 2, node, assignment_list) + if(token(i + 1) == ".") + i = assignment(i + 2, node, assignment_list) - else if(token(i + 1) == "=") - var/exp_list = list() - node[assignment_list] = exp_list + else if(token(i + 1) == "=") + var/exp_list = list() + node[assignment_list] = exp_list - i = expression(i + 2, exp_list) + i = expression(i + 2, exp_list) - else - parse_error("Assignment expected, but no = found") + else + parse_error("Assignment expected, but no = found") - return i + return i //variable: | '.' variable - variable(i, list/node) - var/list/L = list(token(i)) - node[++node.len] = L +/datum/SDQL_parser/proc/variable(i, list/node) + var/list/L = list(token(i)) + node[++node.len] = L - if(token(i) == "\[") - L += token(i + 1) - i += 2 + if(token(i) == "\[") + L += token(i + 1) + i += 2 - if(token(i) != "\]") - parse_error("Missing \] at end of reference.") + if(token(i) != "\]") + parse_error("Missing \] at end of reference.") - if(token(i + 1) == ".") - L += "." - i = variable(i + 2, L) + if(token(i + 1) == ".") + L += "." + i = variable(i + 2, L) - else if(token(i + 1) == "(") // OH BOY PROC - var/list/arguments = list() - i = call_function(i, null, arguments) - L += ":" - L[++L.len] = arguments + else if(token(i + 1) == "(") // OH BOY PROC + var/list/arguments = list() + i = call_function(i, null, arguments) + L += ":" + L[++L.len] = arguments - else if(token(i + 1) == "\[") // list index - var/list/expression = list() - i = expression(i + 2, expression) - if(token(i) != "]") - parse_error("Missing ] at the end of list access.") + else if(token(i + 1) == "\[") // list index + var/list/expression = list() + i = expression(i + 2, expression) + if(token(i) != "]") + parse_error("Missing ] at the end of list access.") - L += "\[" - L[++L.len] = expression - i++ + L += "\[" + L[++L.len] = expression + i++ - else - i++ + else + i++ - return i + return i //object_type: | string - object_type(i, list/node) +/datum/SDQL_parser/proc/object_type(i, list/node) - if(copytext(token(i), 1, 2) == "/") - node += token(i) + if(copytext(token(i), 1, 2) == "/") + node += token(i) - else - i = string(i, node) + else + i = string(i, node) - return i + 1 + return i + 1 //comparitor: '=' | '==' | '!=' | '<>' | '<' | '<=' | '>' | '>=' - comparitor(i, list/node) +/datum/SDQL_parser/proc/comparitor(i, list/node) - if(token(i) in list("=", "==", "!=", "<>", "<", "<=", ">", ">=")) - node += token(i) + if(token(i) in list("=", "==", "!=", "<>", "<", "<=", ">", ">=")) + node += token(i) - else - parse_error("Unknown comparitor [token(i)]") + else + parse_error("Unknown comparitor [token(i)]") - return i + 1 + return i + 1 //bool_operator: 'AND' | '&&' | 'OR' | '||' - bool_operator(i, list/node) +/datum/SDQL_parser/proc/bool_operator(i, list/node) - if(tokenl(i) in list("and", "or", "&&", "||")) - node += token(i) + if(tokenl(i) in list("and", "or", "&&", "||")) + node += token(i) - else - parse_error("Unknown comparitor [token(i)]") + else + parse_error("Unknown comparitor [token(i)]") - return i + 1 + return i + 1 //string: ''' ''' | '"' '"' - string(i, list/node) +/datum/SDQL_parser/proc/string(i, list/node) - if(copytext(token(i), 1, 2) in list("'", "\"")) - node += token(i) + if(copytext(token(i), 1, 2) in list("'", "\"")) + node += token(i) - else - parse_error("Expected string but found '[token(i)]'") + else + parse_error("Expected string but found '[token(i)]'") - return i + 1 + return i + 1 //array: '{' expression, expression, ... '}' - array(var/i, var/list/node) - // Arrays get turned into this: list("{", list(exp_1a = exp_1b, ...), ...), "{" is to mark the next node as an array. - if(copytext(token(i), 1, 2) != "{") - parse_error("Expected an array but found '[token(i)]'") - return i + 1 - - node += token(i) // Add the "{" - var/list/expression_list = list() - - if(token(i + 1) != "}") - var/list/temp_expression_list = list() - - do - i = expression(i + 1, temp_expression_list) - - if(token(i) == ",") - expression_list[++expression_list.len] = temp_expression_list - temp_expression_list = list() - while(token(i) && token(i) != "}") - - expression_list[++expression_list.len] = temp_expression_list - else - i++ - - node[++node.len] = expression_list +/datum/SDQL_parser/proc/array(var/i, var/list/node) + // Arrays get turned into this: list("{", list(exp_1a = exp_1b, ...), ...), "{" is to mark the next node as an array. + if(copytext(token(i), 1, 2) != "{") + parse_error("Expected an array but found '[token(i)]'") return i + 1 + node += token(i) // Add the "{" + var/list/expression_list = list() + + if(token(i + 1) != "}") + var/list/temp_expression_list = list() + + do + i = expression(i + 1, temp_expression_list) + + if(token(i) == ",") + expression_list[++expression_list.len] = temp_expression_list + temp_expression_list = list() + while(token(i) && token(i) != "}") + + expression_list[++expression_list.len] = temp_expression_list + else + i++ + + node[++node.len] = expression_list + return i + 1 + //call_function: ['(' [arguments] ')'] - call_function(i, list/node, list/arguments) - var/list/cur_argument = list() - if(length(tokenl(i))) - var/procname = "" - if(tokenl(i) == "global" && token(i + 1) == ".") // Global proc. - i += 2 - procname = "global." - node += procname + token(i++) - if(token(i) != "(") - parse_error("Expected ( but found '[token(i)]'") - else if(token(i + 1) != ")") - do - i = expression(i + 1, cur_argument) - if(token(i) == ",") - arguments += list(cur_argument) - cur_argument = list() - continue - while(token(i) && token(i) != ")") - arguments += list(cur_argument) - else - i++ +/datum/SDQL_parser/proc/call_function(i, list/node, list/arguments) + var/list/cur_argument = list() + if(length(tokenl(i))) + var/procname = "" + if(tokenl(i) == "global" && token(i + 1) == ".") // Global proc. + i += 2 + procname = "global." + node += procname + token(i++) + if(token(i) != "(") + parse_error("Expected ( but found '[token(i)]'") + else if(token(i + 1) != ")") + do + i = expression(i + 1, cur_argument) + if(token(i) == ",") + arguments += list(cur_argument) + cur_argument = list() + continue + while(token(i) && token(i) != ")") + arguments += list(cur_argument) else - parse_error("Expected a function but found nothing") - return i + 1 + i++ + else + parse_error("Expected a function but found nothing") + return i + 1 //select_function: count_function - select_function(i, list/node) +/datum/SDQL_parser/proc/select_function(i, list/node) - parse_error("Sorry, function calls aren't available yet") + parse_error("Sorry, function calls aren't available yet") - return i + return i //expression: ( unary_expression | '(' expression ')' | value ) [binary_operator expression] - expression(i, list/node) +/datum/SDQL_parser/proc/expression(i, list/node) + + if(token(i) in unary_operators) + i = unary_expression(i, node) + + else if(token(i) == "(") + var/list/expr = list() + + i = expression(i + 1, expr) + + if(token(i) != ")") + parse_error("Missing ) at end of expression.") + + else + i++ + + node[++node.len] = expr + + else + i = value(i, node) + + if(token(i) in binary_operators) + i = binary_operator(i, node) + i = expression(i, node) + + else if(token(i) in comparitors) + i = binary_operator(i, node) + + var/list/rhs = list() + i = expression(i, rhs) + + node[++node.len] = rhs + + + return i + + +//unary_expression: unary_operator ( unary_expression | value | '(' expression ')' ) +/datum/SDQL_parser/proc/unary_expression(i, list/node) + + if(token(i) in unary_operators) + var/list/unary_exp = list() + + unary_exp += token(i) + i++ if(token(i) in unary_operators) - i = unary_expression(i, node) + i = unary_expression(i, unary_exp) else if(token(i) == "(") var/list/expr = list() @@ -498,99 +538,55 @@ else i++ - node[++node.len] = expr + unary_exp[++unary_exp.len] = expr else - i = value(i, node) + i = value(i, unary_exp) - if(token(i) in binary_operators) - i = binary_operator(i, node) - i = expression(i, node) - - else if(token(i) in comparitors) - i = binary_operator(i, node) - - var/list/rhs = list() - i = expression(i, rhs) - - node[++node.len] = rhs + node[++node.len] = unary_exp - return i + else + parse_error("Expected unary operator but found '[token(i)]'") - -//unary_expression: unary_operator ( unary_expression | value | '(' expression ')' ) - unary_expression(i, list/node) - - if(token(i) in unary_operators) - var/list/unary_exp = list() - - unary_exp += token(i) - i++ - - if(token(i) in unary_operators) - i = unary_expression(i, unary_exp) - - else if(token(i) == "(") - var/list/expr = list() - - i = expression(i + 1, expr) - - if(token(i) != ")") - parse_error("Missing ) at end of expression.") - - else - i++ - - unary_exp[++unary_exp.len] = expr - - else - i = value(i, unary_exp) - - node[++node.len] = unary_exp - - - else - parse_error("Expected unary operator but found '[token(i)]'") - - return i + return i //binary_operator: comparitor | '+' | '-' | '/' | '*' | '&' | '|' | '^' - binary_operator(i, list/node) +/datum/SDQL_parser/proc/binary_operator(i, list/node) - if(token(i) in (binary_operators + comparitors)) - node += token(i) + if(token(i) in (binary_operators + comparitors)) + node += token(i) - else - parse_error("Unknown binary operator [token(i)]") + else + parse_error("Unknown binary operator [token(i)]") - return i + 1 + return i + 1 //value: variable | string | number | 'null' - value(i, list/node) +/datum/SDQL_parser/proc/value(i, list/node) - if(token(i) == "null") - node += "null" - i++ + if(token(i) == "null") + node += "null" + i++ - else if(lowertext(copytext(token(i), 1, 3)) == "0x" && isnum(hex2num(copytext(token(i), 3)))) - node += hex2num(copytext(token(i), 3)) - i++ + else if(lowertext(copytext(token(i), 1, 3)) == "0x" && isnum(hex2num(copytext(token(i), 3)))) + node += hex2num(copytext(token(i), 3)) + i++ - else if(isnum(text2num(token(i)))) - node += text2num(token(i)) - i++ + else if(isnum(text2num(token(i)))) + node += text2num(token(i)) + i++ - else if(copytext(token(i), 1, 2) in list("'", "\"")) - i = string(i, node) + else if(copytext(token(i), 1, 2) in list("'", "\"")) + i = string(i, node) - else if(copytext(token(i), 1, 2) == "{") // Start a list. - i = array(i, node) + else if(copytext(token(i), 1, 2) == "{") // Start a list. + i = array(i, node) - else - i = variable(i, node) + else + i = variable(i, node) - return i + return i /*EXPLAIN SELECT * WHERE 42 = 6 * 9 OR val = - 5 == 7*/ diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 5e05b8ecebd..3caac1d79d7 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -26,9 +26,9 @@ GLOBAL_VAR_INIT(intercom_range_display_status, 0) icon = 'icons/480x480.dmi' icon_state = "25percent" - New() - src.pixel_x = -224 - src.pixel_y = -224 +/obj/effect/debugging/camera_range/New() + src.pixel_x = -224 + src.pixel_y = -224 /obj/effect/debugging/mapfix_marker name = "map fix marker" diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index 5d9d218c90e..0e769ed3e73 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -1,4 +1,4 @@ -client/proc/one_click_antag() +/client/proc/one_click_antag() set name = "Create Antagonist" set desc = "Auto-create an antagonist of your choice" set category = "Event" @@ -242,7 +242,7 @@ client/proc/one_click_antag() var/obj/effect/landmark/nuke_spawn = locate("landmark*Nuclear-Bomb") var/obj/effect/landmark/closet_spawn = locate("landmark*Nuclear-Closet") - var/nuke_code = "[rand(10000, 99999)]" + var/nuke_code = rand(10000, 99999) if(nuke_spawn) var/obj/item/paper/P = new diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 3864f573597..514fc2368e1 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -201,7 +201,7 @@ feedback_add_details("admin_verb","GOD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -proc/cmd_admin_mute(mob/M as mob, mute_type, automute = 0) +/proc/cmd_admin_mute(mob/M as mob, mute_type, automute = 0) if(automute) if(!config.automute_on) return @@ -624,11 +624,11 @@ Traitors and the like can also be revived with the previous role mostly intact. var/beepsound = input(usr, "What sound should the announcement make?", "Announcement Sound", "") as anything in MsgSound GLOB.command_announcement.Announce(input, customname, MsgSound[beepsound], , , type) - print_command_report(input, "[command_name()] Update") + print_command_report(input, customname) if("No") //same thing as the blob stuff - it's not public, so it's classified, dammit GLOB.command_announcer.autosay("A classified message has been printed out at all communication consoles.") - print_command_report(input, "Classified [command_name()] Update") + print_command_report(input, "Classified: [customname]") else return diff --git a/code/modules/admin/verbs/striketeam.dm b/code/modules/admin/verbs/striketeam.dm index 40af6eefe49..87649fe3d4e 100644 --- a/code/modules/admin/verbs/striketeam.dm +++ b/code/modules/admin/verbs/striketeam.dm @@ -164,6 +164,7 @@ GLOBAL_VAR_INIT(sent_strike_team, 0) R.set_frequency(DTH_FREQ) R.requires_tcomms = FALSE R.instant = TRUE + R.freqlock = TRUE equip_to_slot_or_del(R, slot_l_ear) if(is_leader) equip_to_slot_or_del(new /obj/item/clothing/under/rank/centcom_officer(src), slot_w_uniform) diff --git a/code/modules/arcade/prize_datums.dm b/code/modules/arcade/prize_datums.dm index 1edad36b8f3..2b9f17c3d04 100644 --- a/code/modules/arcade/prize_datums.dm +++ b/code/modules/arcade/prize_datums.dm @@ -203,6 +203,12 @@ GLOBAL_DATUM_INIT(global_prizes, /datum/prizes, new()) typepath = /obj/item/toy/toy_xeno cost = 80 +/datum/prize_item/rubberducky + name = "Rubber Ducky" + desc = "Your favorite bathtime buddy, all squeaks and quacks quality assured." + typepath = /obj/item/bikehorn/rubberducky + cost = 80 + /datum/prize_item/tacticool name = "Tacticool Turtleneck" desc = "A cool-looking turtleneck." diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm index bf62e2a828a..33755fc54e8 100644 --- a/code/modules/assembly/bomb.dm +++ b/code/modules/assembly/bomb.dm @@ -52,12 +52,13 @@ if(!status) status = TRUE investigate_log("[key_name(user)] welded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]", INVESTIGATE_BOMB) - msg_admin_attack("[key_name_admin(user)] welded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]", ATKLOG_FEW) log_game("[key_name(user)] welded a single tank bomb. Temperature: [bombtank.air_contents.temperature - T0C]") to_chat(user, "A pressure hole has been bored to [bombtank] valve. [bombtank] can now be ignited.") + add_attack_logs(user, src, "welded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]", ATKLOG_FEW) else status = FALSE investigate_log("[key_name(user)] unwelded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]", INVESTIGATE_BOMB) + add_attack_logs(user, src, "unwelded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]", ATKLOG_ALMOSTALL) to_chat(user, "The hole has been closed.") diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm index 5bbd9a26538..67be53979d8 100644 --- a/code/modules/assembly/timer.dm +++ b/code/modules/assembly/timer.dm @@ -101,8 +101,8 @@ if(href_list["time"]) timing = !timing if(timing && istype(holder, /obj/item/transfer_valve)) - message_admins("[key_name_admin(usr)] activated [src] attachment on [holder].") investigate_log("[key_name(usr)] activated [src] attachment for [loc]", INVESTIGATE_BOMB) + add_attack_logs(usr, holder, "activated [src] attachment on", ATKLOG_FEW) log_game("[key_name(usr)] activated [src] attachment for [loc]") update_icon() if(href_list["reset"]) diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index bac8d64d9f2..5d3d6494e48 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -16,7 +16,9 @@ var/death = TRUE //Kill the mob var/roundstart = TRUE //fires on initialize var/instant = FALSE //fires on New - var/flavour_text = "The mapper forgot to set this!" + var/flavour_text = "" //flavour/fluff about the role, optional. + var/description = "A description for this has not been set. This is either an oversight or an admin-spawned spawner not in normal use." //intended as OOC info about the role + var/important_info = "" //important info such as rules that apply to you, etc. Optional. var/faction = null var/permanent = FALSE //If true, the spawner will not disappear upon running out of uses. var/random = FALSE //Don't set a name or gender, just go random @@ -336,7 +338,7 @@ name = "sleeper" icon = 'icons/obj/cryogenic2.dmi' icon_state = "sleeper" - flavour_text = "You are a space doctor!" + flavour_text = "You are a space doctor!" assignedrole = "Space Doctor" /obj/effect/mob_spawn/human/doctor/alive/equip(mob/living/carbon/human/H) @@ -470,11 +472,14 @@ name = "bartender sleeper" icon = 'icons/obj/cryogenic2.dmi' icon_state = "sleeper" - flavour_text = "You are a space bartender! Time to mix drinks and change lives." + description = "Stuck on Lavaland, you could try getting back to civilisation...or serve drinks to those that wander by." + flavour_text = "You are a space bartender! Time to mix drinks and change lives. Wait, where did your bar just get transported to?" assignedrole = "Space Bartender" /obj/effect/mob_spawn/human/beach/alive/lifeguard - flavour_text = "You're a spunky lifeguard! It's up to you to make sure nobody drowns or gets eaten by sharks and stuff." + flavour_text = "You're a spunky lifeguard! It's up to you to make sure nobody drowns or gets eaten by sharks and stuff. Then suddenly your entire beach was transported to this strange hell.\ + You aren't trained for this, but you'll still keep your guests alive!" + description = "Try to survive on lavaland with the pitiful equipment of a lifeguard. Or hide in your biodome." mob_gender = "female" name = "lifeguard sleeper" id_job = "Lifeguard" @@ -502,7 +507,8 @@ name = "beach bum sleeper" icon = 'icons/obj/cryogenic2.dmi' icon_state = "sleeper" - flavour_text = "You are a beach bum!" + flavour_text = "You are a beach bum! You think something just happened to the beach but you don't really pay too much attention." + description = "Try to survive on lavaland or just enjoy the beach, waiting for visitors." assignedrole = "Beach Bum" /datum/outfit/beachbum @@ -523,6 +529,7 @@ roundstart = FALSE icon = 'icons/effects/blood.dmi' icon_state = "remains" + description = "Be a spooky scary skeleton." //not mapped in anywhere so admin spawner, who knows what they'll use this for. flavour_text = "By unknown powers, your skeletal remains have been reanimated! Walk this mortal plain and terrorize all living adventurers who dare cross your path." assignedrole = "Skeleton" diff --git a/code/modules/awaymissions/mission_code/ghost_role_spawners/golems.dm b/code/modules/awaymissions/mission_code/ghost_role_spawners/golems.dm index 9a5bf275abc..0996f214691 100644 --- a/code/modules/awaymissions/mission_code/ghost_role_spawners/golems.dm +++ b/code/modules/awaymissions/mission_code/ghost_role_spawners/golems.dm @@ -64,9 +64,11 @@ var/has_owner = FALSE var/can_transfer = TRUE //if golems can switch bodies to this new shell var/mob/living/owner = null //golem's owner if it has one - flavour_text = "You are a Free Golem. Your family worships The Liberator. In his infinite and divine wisdom, he set your clan free to \ + important_info = "You are not an antag. Do not mess with the station or create AIs." + description = "As a Free Golem on lavaland, you are unable to use most weapons, but you can mine, research and make more of your kind. Earn enough mining points and you can even move your shuttle out of there." + flavour_text = "You are a Free Golem. Your family worships The Liberator. In his infinite and divine wisdom, he set your clan free to \ travel the stars with a single declaration: \"Yeah go do whatever.\" Though you are bound to the one who created you, it is customary in your society to repeat those same words to newborn \ - golems, so that no golem may ever be forced to serve again." + golems, so that no golem may ever be forced to serve again." /obj/effect/mob_spawn/human/golem/Initialize(mapload, datum/species/golem/species = null, mob/creator = null) if(species) //spawners list uses object name to register so this goes before ..() @@ -77,8 +79,10 @@ if(!mapload && A) notify_ghosts("\A [initial(species.prefix)] golem shell has been completed in [A.name].", source = src) if(has_owner && creator) - flavour_text = "You are a Golem. You move slowly, but are highly resistant to heat and cold as well as blunt trauma. You are unable to wear clothes, but can still use most tools. \ - Serve [creator], and assist [creator.p_them()] in completing [creator.p_their()] goals at any cost." + important_info = "Serve your creator, even if they are an antag." + flavour_text = "You are a golem created to serve your creator." + description = "You are a Golem. You move slowly, but are highly resistant to heat and cold as well as blunt trauma. You are unable to wear clothes, but can still use most tools. \ + Serve [creator], and assist [creator.p_them()] in completing [creator.p_their()] goals at any cost." owner = creator /obj/effect/mob_spawn/human/golem/special(mob/living/new_spawn, name) diff --git a/code/modules/awaymissions/mission_code/ghost_role_spawners/oldstation.dm b/code/modules/awaymissions/mission_code/ghost_role_spawners/oldstation.dm index bb1aae5f8a8..62f4226394d 100644 --- a/code/modules/awaymissions/mission_code/ghost_role_spawners/oldstation.dm +++ b/code/modules/awaymissions/mission_code/ghost_role_spawners/oldstation.dm @@ -10,10 +10,11 @@ death = FALSE random = TRUE mob_species = /datum/species/human - flavour_text = "You are a security officer working for Nanotrasen, stationed onboard a state of the art research station. You vaguely recall rushing into a \ + description = "Work as a team with your fellow survivors aboard a ruined, ancient space station." + important_info = "" + flavour_text = "You are a security officer working for Nanotrasen, stationed onboard a state of the art research station. You vaguely recall rushing into a \ cryogenics pod due to an oncoming radiation storm. The last thing you remember is the station's Artificial Program telling you that you would only be asleep for eight hours. As you open \ - your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod. \ - Work as a team with your fellow survivors and do not abandon them." + your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod." uniform = /obj/item/clothing/under/retro/security shoes = /obj/item/clothing/shoes/jackboots id = /obj/item/card/id/away/old/sec @@ -35,10 +36,11 @@ death = FALSE random = TRUE mob_species = /datum/species/human - flavour_text = "You are a medical working for Nanotrasen, stationed onboard a state of the art research station. You vaguely recall rushing into a \ + description = "Work as a team with your fellow survivors aboard a ruined, ancient space station." + important_info = "" + flavour_text = "You are a medical doctor working for Nanotrasen, stationed onboard a state of the art research station. You vaguely recall rushing into a \ cryogenics pod due to an oncoming radiation storm. The last thing you remember is the station's Artificial Program telling you that you would only be asleep for eight hours. As you open \ - your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod. \ - Work as a team with your fellow survivors and do not abandon them." + your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod." uniform = /obj/item/clothing/under/retro/medical shoes = /obj/item/clothing/shoes/black id = /obj/item/card/id/away/old/med @@ -60,10 +62,11 @@ death = FALSE random = TRUE mob_species = /datum/species/human - flavour_text = "You are an engineer working for Nanotrasen, stationed onboard a state of the art research station. You vaguely recall rushing into a \ + description = "Work as a team with your fellow survivors aboard a ruined, ancient space station." + important_info = "" + flavour_text = "You are an engineer working for Nanotrasen, stationed onboard a state of the art research station. You vaguely recall rushing into a \ cryogenics pod due to an oncoming radiation storm. The last thing you remember is the station's Artificial Program telling you that you would only be asleep for eight hours. As you open \ - your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod. \ - Work as a team with your fellow survivors and do not abandon them." + your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod." uniform = /obj/item/clothing/under/retro/engineering shoes = /obj/item/clothing/shoes/workboots id = /obj/item/card/id/away/old/eng @@ -85,10 +88,11 @@ death = FALSE random = TRUE mob_species = /datum/species/human - flavour_text = "You are a scientist working for Nanotrasen, stationed onboard a state of the art research station. You vaguely recall rushing into a \ + description = "Work as a team with your fellow survivors aboard a ruined, ancient space station." + important_info = "" + flavour_text = "You are a scientist working for Nanotrasen, stationed onboard a state of the art research station. You vaguely recall rushing into a \ cryogenics pod due to an oncoming radiation storm. The last thing you remember is the station's Artificial Program telling you that you would only be asleep for eight hours. As you open \ - your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod. \ - Work as a team with your fellow survivors and do not abandon them." + your eyes, everything seems rusted and broken, a dark feeling swells in your gut as you climb out of your pod." uniform = /obj/item/clothing/under/retro/science shoes = /obj/item/clothing/shoes/laceup id = /obj/item/card/id/away/old/sci diff --git a/code/modules/awaymissions/mission_code/stationCollision.dm b/code/modules/awaymissions/mission_code/stationCollision.dm index 1beba373724..07be3364552 100644 --- a/code/modules/awaymissions/mission_code/stationCollision.dm +++ b/code/modules/awaymissions/mission_code/stationCollision.dm @@ -60,7 +60,7 @@ * Guns - I'm making these specifically so that I dont spawn a pile of fully loaded weapons on the map. */ //Captain's retro laser - Fires practice laser shots instead. -obj/item/gun/energy/laser/retro/sc_retro +/obj/item/gun/energy/laser/retro/sc_retro desc = "An older model of the basic lasergun, no longer used by Nanotrasen's security or military forces." ammo_type = list(/obj/item/ammo_casing/energy/laser/practice) clumsy_check = 0 //No sense in having a harmless gun blow up in the clowns face diff --git a/code/modules/client/message.dm b/code/modules/client/message.dm index 5c612339621..1bb9d03dd88 100644 --- a/code/modules/client/message.dm +++ b/code/modules/client/message.dm @@ -1,6 +1,6 @@ GLOBAL_LIST_EMPTY(clientmessages) -proc/addclientmessage(var/ckey, var/message) +/proc/addclientmessage(var/ckey, var/message) ckey = ckey(ckey) if(!ckey || !message) return diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index b1efd1f0b78..7e593436969 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -120,6 +120,12 @@ else icon = initial(icon) +/** + * Used for any clothing interactions when the user is on fire. (e.g. Cigarettes getting lit.) + */ +/obj/item/clothing/proc/catch_fire() //Called in handle_fire() + return + //Ears: currently only used for headsets and earmuffs /obj/item/clothing/ears name = "ears" diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 05bd3d6f48d..bafe3a9f0a9 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -193,7 +193,7 @@ toggle_sound = 'sound/items/zippoclose.ogg' dog_fashion = null -obj/item/clothing/head/helmet/redtaghelm +/obj/item/clothing/head/helmet/redtaghelm name = "red laser tag helmet" desc = "They have chosen their own end." icon_state = "redtaghelm" @@ -204,7 +204,7 @@ obj/item/clothing/head/helmet/redtaghelm flags_inv = HIDEEARS|HIDEEYES dog_fashion = null -obj/item/clothing/head/helmet/bluetaghelm +/obj/item/clothing/head/helmet/bluetaghelm name = "blue laser tag helmet" desc = "They'll need more men." icon_state = "bluetaghelm" @@ -215,7 +215,7 @@ obj/item/clothing/head/helmet/bluetaghelm flags_inv = HIDEEARS|HIDEEYES dog_fashion = null -obj/item/clothing/head/blob +/obj/item/clothing/head/blob name = "blob hat" desc = "A collectible hat handed out at the latest Blob Family Reunion." icon_state = "blobhat" diff --git a/code/modules/clothing/head/misc.dm b/code/modules/clothing/head/misc.dm index cac07fe5b1d..10005077d33 100644 --- a/code/modules/clothing/head/misc.dm +++ b/code/modules/clothing/head/misc.dm @@ -401,6 +401,7 @@ w_class = WEIGHT_CLASS_SMALL attack_verb = list("warned", "cautioned", "smashed") resistance_flags = NONE + dog_fashion = /datum/dog_fashion/head/cone /obj/item/clothing/head/jester name = "jester hat" diff --git a/code/modules/clothing/shoes/colour.dm b/code/modules/clothing/shoes/colour.dm index 5bf6b90c98e..ffcd28009f2 100644 --- a/code/modules/clothing/shoes/colour.dm +++ b/code/modules/clothing/shoes/colour.dm @@ -9,8 +9,8 @@ heat_protection = FEET max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT - redcoat - item_color = "redcoat" //Exists for washing machines. Is not different from black shoes in any way. +/obj/item/clothing/shoes/black/redcoat + item_color = "redcoat" //Exists for washing machines. Is not different from black shoes in any way. /obj/item/clothing/shoes/black/greytide flags = NODROP @@ -20,18 +20,23 @@ desc = "A pair of brown shoes." icon_state = "brown" - captain - item_color = "captain" //Exists for washing machines. Is not different from brown shoes in any way. - hop - item_color = "hop" //Exists for washing machines. Is not different from brown shoes in any way. - ce - item_color = "chief" //Exists for washing machines. Is not different from brown shoes in any way. - rd - item_color = "director" //Exists for washing machines. Is not different from brown shoes in any way. - cmo - item_color = "medical" //Exists for washing machines. Is not different from brown shoes in any way. - cmo - item_color = "cargo" //Exists for washing machines. Is not different from brown shoes in any way. +/obj/item/clothing/shoes/brown/captain + item_color = "captain" //Exists for washing machines. Is not different from brown shoes in any way. + +/obj/item/clothing/shoes/brown/hop + item_color = "hop" //Exists for washing machines. Is not different from brown shoes in any way. + +/obj/item/clothing/shoes/brown/ce + item_color = "chief" //Exists for washing machines. Is not different from brown shoes in any way. + +/obj/item/clothing/shoes/brown/rd + item_color = "director" //Exists for washing machines. Is not different from brown shoes in any way. + +/obj/item/clothing/shoes/brown/cmo + item_color = "medical" //Exists for washing machines. Is not different from brown shoes in any way. + +/obj/item/clothing/shoes/brown/qm + item_color = "cargo" //Exists for washing machines. Is not different from brown shoes in any way. /obj/item/clothing/shoes/blue name = "blue shoes" diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm index 129b07af36e..a7ee48faec4 100644 --- a/code/modules/clothing/shoes/magboots.dm +++ b/code/modules/clothing/shoes/magboots.dm @@ -53,7 +53,7 @@ magboot_state = "syndiemag" origin_tech = "magnets=4;syndicate=2" -obj/item/clothing/shoes/magboots/syndie/advance //For the Syndicate Strike Team +/obj/item/clothing/shoes/magboots/syndie/advance //For the Syndicate Strike Team desc = "Reverse-engineered magboots that appear to be based on an advanced model, as they have a lighter magnetic pull. Property of Gorlex Marauders." name = "advanced blood-red magboots" slowdown_active = SHOES_SLOWDOWN diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm index 1f8cb7aaed1..62f740ad7b0 100644 --- a/code/modules/clothing/shoes/miscellaneous.dm +++ b/code/modules/clothing/shoes/miscellaneous.dm @@ -344,3 +344,10 @@ recharging_time = world.time + recharging_rate else to_chat(user, "Something prevents you from dashing forward!") + +/obj/item/clothing/shoes/ducky + name = "rubber ducky shoes" + desc = "These shoes are made for quacking, and thats just what they'll do." + icon_state = "ducky" + item_state = "ducky" + shoe_sound = "sound/items/squeaktoy.ogg" diff --git a/code/modules/clothing/spacesuits/ert.dm b/code/modules/clothing/spacesuits/ert.dm index c412bb40f7d..8e68fe7461b 100644 --- a/code/modules/clothing/spacesuits/ert.dm +++ b/code/modules/clothing/spacesuits/ert.dm @@ -16,15 +16,26 @@ "Vox" = 'icons/mob/species/vox/helmet.dmi' ) +/obj/item/clothing/head/helmet/space/hardsuit/ert/Initialize() + var/mob/living/carbon/human/wearer = loc.loc //loc is the hardsuit, so its loc is the wearer + if(ishuman(wearer)) + register_camera(wearer) + ..() + /obj/item/clothing/head/helmet/space/hardsuit/ert/attack_self(mob/user) if(camera || !has_camera) ..(user) else - camera = new /obj/machinery/camera(src) - camera.network = list("ERT") - GLOB.cameranet.removeCamera(camera) - camera.c_tag = user.name - to_chat(user, "User scanned as [camera.c_tag]. Camera activated.") + register_camera(user) + +/obj/item/clothing/head/helmet/space/hardsuit/ert/proc/register_camera(mob/wearer) + if(camera || !has_camera) + return + camera = new /obj/machinery/camera(src) + camera.network = list("ERT") + GLOB.cameranet.removeCamera(camera) + camera.c_tag = wearer.name + to_chat(wearer, "User scanned as [camera.c_tag]. Camera activated.") /obj/item/clothing/head/helmet/space/hardsuit/ert/examine(mob/user) . = ..() diff --git a/code/modules/clothing/spacesuits/syndi.dm b/code/modules/clothing/spacesuits/syndi.dm index 8c65ed02553..890c223d735 100644 --- a/code/modules/clothing/spacesuits/syndi.dm +++ b/code/modules/clothing/spacesuits/syndi.dm @@ -83,7 +83,7 @@ icon_state = "syndicate-helm-black" item_state = "syndicate-helm-black" -obj/item/clothing/head/helmet/space/syndicate/black/strike +/obj/item/clothing/head/helmet/space/syndicate/black/strike name = "Syndicate Strike Team commando helmet" desc = "A heavily armored black helmet that is only given to high-ranking Syndicate operatives." armor = list(melee = 80, bullet = 80, laser = 50, energy = 50, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100) //Matches DS gear. @@ -95,7 +95,7 @@ obj/item/clothing/head/helmet/space/syndicate/black/strike icon_state = "syndicate-black" item_state = "syndicate-black" -obj/item/clothing/suit/space/syndicate/black/strike +/obj/item/clothing/suit/space/syndicate/black/strike name = "Syndicate Strike Team commando space suit" desc = "A heavily armored, black space suit that is only given to high-ranking Syndicate operatives." armor = list(melee = 80, bullet = 80, laser = 50, energy = 50, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100) //Matches DS gear. @@ -156,7 +156,7 @@ obj/item/clothing/suit/space/syndicate/black/strike icon_state = "syndicate-helm-black-red" item_state = "syndicate-helm-black-red" -obj/item/clothing/head/helmet/space/syndicate/black/red/strike +/obj/item/clothing/head/helmet/space/syndicate/black/red/strike name = "Syndicate Strike Team leader helmet" desc = "A heavily armored, black and red space helmet that is only given to elite Syndicate operatives, it looks particularly menacing." armor = list(melee = 80, bullet = 80, laser = 50, energy = 50, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100) //Matches DS gear. @@ -168,7 +168,7 @@ obj/item/clothing/head/helmet/space/syndicate/black/red/strike icon_state = "syndicate-black-red" item_state = "syndicate-black-red" -obj/item/clothing/suit/space/syndicate/black/red/strike +/obj/item/clothing/suit/space/syndicate/black/red/strike name = "Syndicate Strike Team leader space suit" desc = "A heavily armored, black and red space suit that is only given to elite Syndicate operatives, it looks particularly menacing." armor = list(melee = 80, bullet = 80, laser = 50, energy = 50, bomb = 100, bio = 100, rad = 100, fire = 100, acid = 100) //Matches DS gear. diff --git a/code/modules/clothing/under/color.dm b/code/modules/clothing/under/color.dm index b57166d4909..8d0e68eddb0 100644 --- a/code/modules/clothing/under/color.dm +++ b/code/modules/clothing/under/color.dm @@ -128,6 +128,10 @@ item_state = "p_suit" item_color = "purple" +/obj/item/clothing/under/color/purple/sensor //for jani ert + sensor_mode = SENSOR_COORDS + random_sensor = FALSE + /obj/item/clothing/under/color/lightpurple name = "light purple jumpsuit" icon_state = "lightpurple" diff --git a/code/modules/clothing/under/jobs/civilian.dm b/code/modules/clothing/under/jobs/civilian.dm index faa9039c8c4..6384efb2021 100644 --- a/code/modules/clothing/under/jobs/civilian.dm +++ b/code/modules/clothing/under/jobs/civilian.dm @@ -48,6 +48,10 @@ item_state = "bl_suit" item_color = "chapblack" +/obj/item/clothing/under/rank/chaplain/sensor + sensor_mode = SENSOR_COORDS + random_sensor = FALSE + /obj/item/clothing/under/rank/chef desc = "It's an apron which is given only to the most hardcore chefs in space." name = "chef's uniform" diff --git a/code/modules/clothing/under/jobs/engineering.dm b/code/modules/clothing/under/jobs/engineering.dm index aa70fc85db6..3a717a5907f 100644 --- a/code/modules/clothing/under/jobs/engineering.dm +++ b/code/modules/clothing/under/jobs/engineering.dm @@ -39,6 +39,10 @@ armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 10, "fire" = 60, "acid" = 20) resistance_flags = NONE +/obj/item/clothing/under/rank/engineer/sensor + sensor_mode = SENSOR_COORDS + random_sensor = FALSE + /obj/item/clothing/under/rank/engineer/skirt desc = "It's an orange high visibility jumpskirt worn by engineers. It has minor radiation shielding." diff --git a/code/modules/clothing/under/jobs/medsci.dm b/code/modules/clothing/under/jobs/medsci.dm index d8847741db3..ffd730d7a6d 100644 --- a/code/modules/clothing/under/jobs/medsci.dm +++ b/code/modules/clothing/under/jobs/medsci.dm @@ -124,6 +124,10 @@ permeability_coefficient = 0.50 armor = list("melee" = 0, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 10, "rad" = 0, "fire" = 0, "acid" = 0) +/obj/item/clothing/under/rank/medical/sensor + sensor_mode = SENSOR_COORDS + random_sensor = FALSE + /obj/item/clothing/under/rank/medical/skirt name = "medical doctor's jumpskirt" icon_state = "medicalf" diff --git a/code/modules/clothing/under/jobs/security.dm b/code/modules/clothing/under/jobs/security.dm index 0086ba96ef8..afeca2fb3bd 100644 --- a/code/modules/clothing/under/jobs/security.dm +++ b/code/modules/clothing/under/jobs/security.dm @@ -34,6 +34,10 @@ armor = list("melee" = 10, "bullet" = 0, "laser" = 0,"energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 30, "acid" = 30) strip_delay = 50 +/obj/item/clothing/under/rank/security/sensor + sensor_mode = SENSOR_COORDS + random_sensor = FALSE + /obj/item/clothing/under/rank/security/skirt name = "security officer's jumpskirt" desc = "Standard feminine fashion for Security Officers. It's made of sturdier material than the standard jumpskirts." diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 9a2afbc8a60..beedf85c8c7 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -88,6 +88,10 @@ item_state = "g_suit" item_color = "officer" +/obj/item/clothing/under/rank/centcom_officer/sensor + sensor_mode = SENSOR_COORDS + random_sensor = FALSE + /obj/item/clothing/under/rank/centcom_commander desc = "It's a jumpsuit worn by CentComm's highest-tier Commanders." name = "\improper CentComm officer's jumpsuit" diff --git a/code/modules/crafting/tailoring.dm b/code/modules/crafting/tailoring.dm index 6973fd04ad3..38419f718c4 100644 --- a/code/modules/crafting/tailoring.dm +++ b/code/modules/crafting/tailoring.dm @@ -143,3 +143,12 @@ reqs = list(/obj/item/stack/sheet/animalhide/lizard = 1, /obj/item/stack/sheet/leather = 1) time = 60 category = CAT_CLOTHING + +/datum/crafting_recipe/rubberduckyshoes + name = "Rubber Ducky Shoes" + result = /obj/item/clothing/shoes/ducky + time = 45 + reqs = list(/obj/item/bikehorn/rubberducky = 2, + /obj/item/clothing/shoes/sandal = 1) + tools = list(TOOL_WIRECUTTER) + category = CAT_CLOTHING diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm index 530b9095f75..4ee33f4d87e 100644 --- a/code/modules/customitems/item_defines.dm +++ b/code/modules/customitems/item_defines.dm @@ -272,15 +272,6 @@ new /obj/item/reagent_containers/food/drinks/cans/cola(src) -/obj/item/instrument/guitar/jello_guitar //Pineapple Salad: Dan Jello - name = "Dan Jello's Pink Guitar" - desc = "Dan Jello's special pink guitar." - icon = 'icons/obj/custom_items.dmi' - icon_state = "jello_guitar" - item_state = "jello_guitar" - righthand_file = 'icons/mob/inhands/fluff_righthand.dmi' - lefthand_file = 'icons/mob/inhands/fluff_lefthand.dmi' - /obj/item/fluff/wingler_comb name = "blue comb" desc = "A blue comb, it looks like it was made to groom a Tajaran's fur." @@ -1592,13 +1583,17 @@ item_state = "asmer_accordion" -/obj/item/clothing/head/rabbitears/fluff/pinesalad_bunny // Pineapple Salad : Dan Jello - name = "Bluespace rabbit ears" - desc = "A pair of sparkly bluespace rabbit ears, with a small tag on them that reads, 'Dan Jello~'. Yuck, \ - there's some pink slime on the part that goes on your head!" +/obj/item/clothing/head/fluff/pinesalad_horns //Pineapple Salad: Dan Jello + name = "Bluespace Horns" + desc = "A pair of fake horns. Now with added bluespace!" icon = 'icons/obj/custom_items.dmi' - icon_state = "ps_bunny" + icon_state = "ps_horns" +/obj/item/storage/backpack/fluff/hiking //Pineapple Salad: Dan Jello + name = "\improper Fancy Hiking Pack" + desc = "A black and red hiking pack with some nice little accessories." + icon = 'icons/obj/custom_items.dmi' + icon_state = "danpack" /obj/item/clothing/under/fluff/kiaoutfit //FullOfSkittles: Kiachi name = "Suspicious Outfit" diff --git a/code/modules/detective_work/detective_work.dm b/code/modules/detective_work/detective_work.dm index 69ee566124e..4933ff29474 100644 --- a/code/modules/detective_work/detective_work.dm +++ b/code/modules/detective_work/detective_work.dm @@ -1,8 +1,8 @@ //CONTAINS: Suit fibers and Detective's Scanning Computer -atom/var/list/suit_fibers +/atom/var/list/suit_fibers -atom/proc/add_fibers(mob/living/carbon/human/M) +/atom/proc/add_fibers(mob/living/carbon/human/M) if(M.gloves && istype(M.gloves,/obj/item/clothing/)) var/obj/item/clothing/gloves/G = M.gloves if(G.transfer_blood > 1) //bloodied gloves transfer blood to touched objects diff --git a/code/modules/events/apc_overload.dm b/code/modules/events/apc_overload.dm index 13cabe81b3c..2ca2cdbfa70 100644 --- a/code/modules/events/apc_overload.dm +++ b/code/modules/events/apc_overload.dm @@ -21,7 +21,7 @@ SEND_SOUND(M, S) /datum/event/apc_overload/announce() - GLOB.event_announcement.Announce("Overload detected in [station_name()]'s powernet. Engineering, please check all underfloor APC terminals.", "Critical Power Failure", new_sound = 'sound/AI/apc_overload.ogg') + GLOB.event_announcement.Announce("Overload detected in [station_name()]'s powernet. Engineering, please check all underfloor APC terminals.", "Critical Power Failure", new_sound = 'sound/AI/attention.ogg') /datum/event/apc_overload/end() return TRUE @@ -32,7 +32,7 @@ /area/turret_protected/ai) if(announce) - GLOB.event_announcement.Announce("Overload detected in [station_name()]'s powernet. Engineering, please check all underfloor APC terminals.", "Critical Power Failure", new_sound = 'sound/AI/apc_overload.ogg') + GLOB.event_announcement.Announce("Overload detected in [station_name()]'s powernet. Engineering, please check all underfloor APC terminals.", "Critical Power Failure", new_sound = 'sound/AI/attention.ogg') // break APC_BREAK_PROBABILITY% of all of the APCs on the station var/affected_apc_count = 0 diff --git a/code/modules/events/apc_short.dm b/code/modules/events/apc_short.dm index fcb31972204..bb82ceb15c4 100644 --- a/code/modules/events/apc_short.dm +++ b/code/modules/events/apc_short.dm @@ -21,7 +21,7 @@ SEND_SOUND(M, S) /datum/event/apc_short/announce() - GLOB.event_announcement.Announce("Overload detected in [station_name()]'s powernet. Engineering, please repair shorted APCs.", "Systems Power Failure", new_sound = 'sound/AI/apc_short.ogg') + GLOB.event_announcement.Announce("Overload detected in [station_name()]'s powernet. Engineering, please repair shorted APCs.", "Systems Power Failure", new_sound = 'sound/AI/attention.ogg') /datum/event/apc_short/end() return TRUE @@ -32,7 +32,7 @@ /area/turret_protected/ai) if(announce) - GLOB.event_announcement.Announce("Overload detected in [station_name()]'s powernet. Engineering, please repair shorted APCs.", "Systems Power Failure", new_sound = 'sound/AI/apc_short.ogg') + GLOB.event_announcement.Announce("Overload detected in [station_name()]'s powernet. Engineering, please repair shorted APCs.", "Systems Power Failure", new_sound = 'sound/AI/attention.ogg') // break APC_BREAK_PROBABILITY% of all of the APCs on the station var/affected_apc_count = 0 diff --git a/code/modules/events/electrical_storm.dm b/code/modules/events/electrical_storm.dm index 7304469f408..17c697faf11 100644 --- a/code/modules/events/electrical_storm.dm +++ b/code/modules/events/electrical_storm.dm @@ -25,5 +25,5 @@ for(var/thing in epicentreList) var/obj/effect/landmark/epicentre = thing for(var/obj/machinery/power/apc/apc in range(epicentre, lightsoutRange)) - apc.overload_lighting() + INVOKE_ASYNC(apc, /obj/machinery/power/apc.proc/overload_lighting) diff --git a/code/modules/events/rogue_drones.dm b/code/modules/events/rogue_drones.dm index 02fa69b7c3e..f3ea93c80c4 100644 --- a/code/modules/events/rogue_drones.dm +++ b/code/modules/events/rogue_drones.dm @@ -4,24 +4,16 @@ var/list/drones_list = list() /datum/event/rogue_drone/start() - //spawn them at the same place as carp var/list/possible_spawns = list() for(var/thing in GLOB.landmarks_list) var/obj/effect/landmark/C = thing - if(C.name == "carpspawn") + if(C.name == "carpspawn") //spawn them at the same place as carp possible_spawns.Add(C) - //25% chance for this to be a false alarm - var/num - if(prob(25)) - num = 0 - else - num = rand(2,6) - for(var/i=0, i= 100) return original_msg diff --git a/code/modules/food_and_drinks/food/foods/baked_goods.dm b/code/modules/food_and_drinks/food/foods/baked_goods.dm index 57fd36393b5..9a7c0e89999 100644 --- a/code/modules/food_and_drinks/food/foods/baked_goods.dm +++ b/code/modules/food_and_drinks/food/foods/baked_goods.dm @@ -432,6 +432,29 @@ icon_state = "jdonut1" extra_reagent = "cherryjelly" +////////////////////// +// Pancakes // +////////////////////// + +/obj/item/reagent_containers/food/snacks/pancake + name = "pancake" + desc = "A plain pancake." + icon_state = "pancake" + filling_color = "#E7D8AB" + bitesize = 2 + list_reagents = list("nutriment" = 3, "sugar" = 3) + +/obj/item/reagent_containers/food/snacks/pancake/berry_pancake + name = "berry pancake" + desc = "A pancake loaded with berries." + icon_state = "berry_pancake" + list_reagents = list("nutriment" = 3, "sugar" = 3, "berryjuice" = 3) + +/obj/item/reagent_containers/food/snacks/pancake/choc_chip_pancake + name = "choc-chip pancake" + desc = "A pancake loaded with chocolate chips." + icon_state = "choc_chip_pancake" + list_reagents = list("nutriment" = 3, "sugar" = 3, "cocoa" = 3) ////////////////////// // Misc // diff --git a/code/modules/food_and_drinks/food/snacks.dm b/code/modules/food_and_drinks/food/snacks.dm index 8d0408a74fb..38e1acd550b 100644 --- a/code/modules/food_and_drinks/food/snacks.dm +++ b/code/modules/food_and_drinks/food/snacks.dm @@ -34,16 +34,15 @@ /obj/item/reagent_containers/food/snacks/proc/On_Consume(mob/M, mob/user) if(!user) return - spawn(0) - if(!reagents.total_volume) - if(M == user) - to_chat(user, "You finish eating \the [src].") - user.visible_message("[M] finishes eating \the [src].") - user.unEquip(src) //so icons update :[ - Post_Consume(M) - var/obj/item/trash_item = generate_trash(usr) - usr.put_in_hands(trash_item) - qdel(src) + if(!reagents.total_volume) + if(M == user) + to_chat(user, "You finish eating \the [src].") + user.visible_message("[M] finishes eating \the [src].") + user.unEquip(src) //so icons update :[ + Post_Consume(M) + var/obj/item/trash_item = generate_trash(usr) + usr.put_in_hands(trash_item) + qdel(src) return /obj/item/reagent_containers/food/snacks/proc/Post_Consume(mob/living/M) diff --git a/code/modules/food_and_drinks/kitchen_machinery/cereal_maker.dm b/code/modules/food_and_drinks/kitchen_machinery/cereal_maker.dm index dc81717496a..59fe4b78bcd 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/cereal_maker.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/cereal_maker.dm @@ -8,17 +8,17 @@ onicon = "cereal_on" officon = "cereal_off" -obj/machinery/cooker/cerealmaker/setIcon(obj/item/copyme, obj/item/copyto) +/obj/machinery/cooker/cerealmaker/setIcon(obj/item/copyme, obj/item/copyto) var/image/img = new(copyme.icon, copyme.icon_state) img.transform *= 0.7 copyto.overlays += img copyto.overlays += copyme.overlays -obj/machinery/cooker/cerealmaker/changename(obj/item/name, obj/item/setme) +/obj/machinery/cooker/cerealmaker/changename(obj/item/name, obj/item/setme) setme.name = "box of [name] cereal" setme.desc = "[name.desc] It has been [thiscooktype]" -obj/machinery/cooker/cerealmaker/gettype() +/obj/machinery/cooker/cerealmaker/gettype() var/obj/item/reagent_containers/food/snacks/cereal/type = new(get_turf(src)) return type diff --git a/code/modules/food_and_drinks/kitchen_machinery/food_grill.dm b/code/modules/food_and_drinks/kitchen_machinery/food_grill.dm index 54290c80b37..f68f8c31baf 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/food_grill.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/food_grill.dm @@ -11,7 +11,7 @@ onicon = "grill_on" officon = "grill_off" -obj/machinery/cooker/foodgrill/putIn(obj/item/In, mob/chef) +/obj/machinery/cooker/foodgrill/putIn(obj/item/In, mob/chef) ..() var/image/img = new(In.icon, In.icon_state) img.pixel_y = 5 diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm index db078675db1..f65b78f3ca2 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm @@ -234,7 +234,7 @@ return if(UserOverride) - msg_admin_attack("[key_name_admin(occupant)] was gibbed by an autogibber (\the [src]) [ADMIN_JMP(src)]") + add_attack_logs(user, occupant, "gibbed by an autogibber ([src])") log_game("[key_name(occupant)] was gibbed by an autogibber ([src]) (X:[x] Y:[y] Z:[z])") if(operating) diff --git a/code/modules/food_and_drinks/recipes/recipes_grill.dm b/code/modules/food_and_drinks/recipes/recipes_grill.dm index 047b3968176..73b181b8bbb 100644 --- a/code/modules/food_and_drinks/recipes/recipes_grill.dm +++ b/code/modules/food_and_drinks/recipes/recipes_grill.dm @@ -249,3 +249,23 @@ /obj/item/stack/rods, ) result = /obj/item/reagent_containers/food/snacks/fish_skewer + +/datum/recipe/grill/pancake + items = list( + /obj/item/reagent_containers/food/snacks/cookiedough + ) + result = /obj/item/reagent_containers/food/snacks/pancake + +/datum/recipe/grill/berry_pancake + items = list( + /obj/item/reagent_containers/food/snacks/cookiedough, + /obj/item/reagent_containers/food/snacks/grown/berries + ) + result = /obj/item/reagent_containers/food/snacks/pancake/berry_pancake + +/datum/recipe/grill/choc_chip_pancake + items = list( + /obj/item/reagent_containers/food/snacks/cookiedough, + /obj/item/reagent_containers/food/snacks/choc_pile + ) + result = /obj/item/reagent_containers/food/snacks/pancake/choc_chip_pancake diff --git a/code/modules/food_and_drinks/recipes/recipes_microwave.dm b/code/modules/food_and_drinks/recipes/recipes_microwave.dm index f8d720ec56c..df22e612830 100644 --- a/code/modules/food_and_drinks/recipes/recipes_microwave.dm +++ b/code/modules/food_and_drinks/recipes/recipes_microwave.dm @@ -449,7 +449,7 @@ ) result = /obj/item/reagent_containers/food/snacks/twobread -datum/recipe/microwave/slimesandwich +/datum/recipe/microwave/slimesandwich reagents = list("slimejelly" = 5) items = list( /obj/item/reagent_containers/food/snacks/breadslice, diff --git a/code/modules/hydroponics/grown/citrus.dm b/code/modules/hydroponics/grown/citrus.dm index 6e937f45c2a..911b8eae866 100644 --- a/code/modules/hydroponics/grown/citrus.dm +++ b/code/modules/hydroponics/grown/citrus.dm @@ -116,9 +116,8 @@ /obj/item/reagent_containers/food/snacks/grown/firelemon/attack_self(mob/living/user) var/area/A = get_area(user) user.visible_message("[user] primes the [src]!", "You prime the [src]!") - var/message = "[ADMIN_LOOKUPFLW(user)] primed a combustible lemon for detonation at [A] [ADMIN_COORDJMP(user)]" investigate_log("[key_name(user)] primed a combustible lemon for detonation at [A] [COORD(user)].", INVESTIGATE_BOMB) - message_admins(message) + add_attack_logs(user, src, "primed a combustible lemon for detonation", ATKLOG_FEW) log_game("[key_name(user)] primed a combustible lemon for detonation at [A] [COORD(user)].") if(iscarbon(user)) var/mob/living/carbon/C = user diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm index 7d59bd3360b..d5c7744eb4a 100644 --- a/code/modules/hydroponics/hydroitemdefines.dm +++ b/code/modules/hydroponics/hydroitemdefines.dm @@ -27,10 +27,7 @@ w_class = WEIGHT_CLASS_SMALL throw_speed = 3 throw_range = 10 - -/obj/item/reagent_containers/spray/weedspray/New() - ..() - reagents.add_reagent("atrazine", 100) + list_reagents = list("atrazine" = 100) /obj/item/reagent_containers/spray/weedspray/suicide_act(mob/user) user.visible_message("[user] is huffing the [src.name]! It looks like [user.p_theyre()] trying to commit suicide.") @@ -49,10 +46,7 @@ w_class = WEIGHT_CLASS_SMALL throw_speed = 3 throw_range = 10 - -/obj/item/reagent_containers/spray/pestspray/New() - ..() - reagents.add_reagent("pestkiller", 100) + list_reagents = list("pestkiller" = 100) /obj/item/reagent_containers/spray/pestspray/suicide_act(mob/user) user.visible_message("[user] is huffing the [src.name]! It looks like [user.p_theyre()] trying to commit suicide.") @@ -222,79 +216,112 @@ /obj/item/reagent_containers/glass/bottle/nutrient - name = "bottle of nutrient" + name = "jug of nutrient" + desc = "A decent sized plastic jug." icon = 'icons/obj/chemical.dmi' - icon_state = "bottle16" - volume = 50 + icon_state = "plastic_jug" + item_state = "plastic_jug" w_class = WEIGHT_CLASS_TINY amount_per_transfer_from_this = 10 - possible_transfer_amounts = list(1,2,5,10,15,25,50) + possible_transfer_amounts = list(1,2,5,10,20,40,80) + container_type = OPENCONTAINER + volume = 80 + hitsound = 'sound/weapons/jug_empty_impact.ogg' + throwhitsound = 'sound/weapons/jug_empty_impact.ogg' + force = 0.2 + throwforce = 0.2 /obj/item/reagent_containers/glass/bottle/nutrient/New() + ..() + add_lid() + pixel_x = rand(-5, 5) + pixel_y = rand(-5, 5) + +/obj/item/reagent_containers/glass/bottle/nutrient/on_reagent_change() + . = ..() + update_icon() + if(reagents.total_volume) + hitsound = 'sound/weapons/jug_filled_impact.ogg' + throwhitsound = 'sound/weapons/jug_filled_impact.ogg' + else + hitsound = 'sound/weapons/jug_empty_impact.ogg' + throwhitsound = 'sound/weapons/jug_empty_impact.ogg' + +/obj/item/reagent_containers/glass/bottle/nutrient/update_icon() + cut_overlays() + + if(reagents.total_volume) + var/image/filling = image('icons/obj/reagentfillings.dmi', src, "plastic_jug10") + + var/percent = round((reagents.total_volume / volume) * 100) + switch(percent) + if(0 to 10) + filling.icon_state = "plastic_jug-10" + if(11 to 29) + filling.icon_state = "plastic_jug25" + if(30 to 45) + filling.icon_state = "plastic_jug40" + if(46 to 61) + filling.icon_state = "plastic_jug55" + if(62 to 77) + filling.icon_state = "plastic_jug70" + if(78 to 92) + filling.icon_state = "plastic_jug85" + if(93 to INFINITY) + filling.icon_state = "plastic_jug100" + + filling.icon += mix_color_from_reagents(reagents.reagent_list) + add_overlay(filling) + + if(!is_open_container()) + add_overlay("lid_jug") + + +/obj/item/reagent_containers/glass/bottle/nutrient/ez + name = "jug of E-Z-Nutrient" + desc = "Contains a fertilizer that causes mild mutations with each harvest." + icon = 'icons/obj/chemical.dmi' + icon_state = "plastic_jug_ez" + list_reagents = list("eznutriment" = 80) + +/obj/item/reagent_containers/glass/bottle/nutrient/l4z + name = "jug of Left 4 Zed" + desc = "Contains a fertilizer that limits plant yields to no more than one and causes significant mutations in plants." + icon = 'icons/obj/chemical.dmi' + icon_state = "plastic_jug_l4z" + list_reagents = list("left4zednutriment" = 80) + +/obj/item/reagent_containers/glass/bottle/nutrient/rh + name = "jug of Robust Harvest" + desc = "Contains a fertilizer that increases the yield of a plant by 30% while causing no mutations." + icon = 'icons/obj/chemical.dmi' + icon_state = "plastic_jug_rh" + list_reagents = list("robustharvestnutriment" = 80) + +/obj/item/reagent_containers/glass/bottle/nutrient/empty + icon = 'icons/obj/chemical.dmi' + icon_state = "plastic_jug" + +/obj/item/reagent_containers/glass/bottle/nutrient/killer + icon = 'icons/obj/chemical.dmi' + icon_state = "plastic_jug_k" + w_class = WEIGHT_CLASS_TINY + +/obj/item/reagent_containers/glass/bottle/nutrient/killer/New() ..() pixel_x = rand(-5, 5) pixel_y = rand(-5, 5) -/obj/item/reagent_containers/glass/bottle/nutrient/ez - name = "bottle of E-Z-Nutrient" - desc = "Contains a fertilizer that causes mild mutations with each harvest." - icon = 'icons/obj/chemical.dmi' - icon_state = "bottle16" - -/obj/item/reagent_containers/glass/bottle/nutrient/ez/New() - ..() - reagents.add_reagent("eznutriment", 50) - -/obj/item/reagent_containers/glass/bottle/nutrient/l4z - name = "bottle of Left 4 Zed" - desc = "Contains a fertilizer that limits plant yields to no more than one and causes significant mutations in plants." - icon = 'icons/obj/chemical.dmi' - icon_state = "bottle18" - -/obj/item/reagent_containers/glass/bottle/nutrient/l4z/New() - ..() - reagents.add_reagent("left4zednutriment", 50) - -/obj/item/reagent_containers/glass/bottle/nutrient/rh - name = "bottle of Robust Harvest" - desc = "Contains a fertilizer that increases the yield of a plant by 30% while causing no mutations." - icon = 'icons/obj/chemical.dmi' - icon_state = "bottle15" - -/obj/item/reagent_containers/glass/bottle/nutrient/rh/New() - ..() - reagents.add_reagent("robustharvestnutriment", 50) - -/obj/item/reagent_containers/glass/bottle/nutrient/empty - name = "bottle" - icon = 'icons/obj/chemical.dmi' - icon_state = "bottle16" - -/obj/item/reagent_containers/glass/bottle/killer - name = "bottle" - icon = 'icons/obj/chemical.dmi' - icon_state = "bottle16" - volume = 50 - w_class = WEIGHT_CLASS_TINY - amount_per_transfer_from_this = 10 - possible_transfer_amounts = list(1,2,5,10,15,25,50) - -/obj/item/reagent_containers/glass/bottle/killer/weedkiller - name = "bottle of weed killer" +/obj/item/reagent_containers/glass/bottle/nutrient/killer/weedkiller + name = "jug of weed killer" desc = "Contains a herbicide." icon = 'icons/obj/chemical.dmi' - icon_state = "bottle19" + icon_state = "plastic_jug_wk" + list_reagents = list("atrazine" = 80) -/obj/item/reagent_containers/glass/bottle/killer/weedkiller/New() - ..() - reagents.add_reagent("atrazine", 50) - -/obj/item/reagent_containers/glass/bottle/killer/pestkiller - name = "bottle of pest spray" +/obj/item/reagent_containers/glass/bottle/nutrient/killer/pestkiller + name = "jug of pest spray" desc = "Contains a pesticide." icon = 'icons/obj/chemical.dmi' - icon_state = "bottle20" - -/obj/item/reagent_containers/glass/bottle/killer/pestkiller/New() - ..() - reagents.add_reagent("pestkiller", 50) + icon_state = "plastic_jug_pk" + list_reagents = list("pestkiller" = 80) diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index 1be8f11527d..d79a8030a59 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -744,6 +744,10 @@ to_chat(user, "[reagent_source] is empty.") return 1 + if(reagent_source.has_lid && !reagent_source.is_drainable()) //if theres a LID then cannot transfer reagents. + to_chat(user, "You need to open [O] first!") + return TRUE + var/list/trays = list(src)//makes the list just this in cases of syringes and compost etc var/target = myseed ? myseed.plantname : src var/visi_msg = "" diff --git a/code/modules/instruments/songs/_song.dm b/code/modules/instruments/songs/_song.dm index 142eab1fd2d..fc4a9b63579 100644 --- a/code/modules/instruments/songs/_song.dm +++ b/code/modules/instruments/songs/_song.dm @@ -167,6 +167,8 @@ hearing_mobs.len = 0 var/turf/source = get_turf(parent) for(var/mob/M in GLOB.player_list) + if(M.z != source.z) // Z-level check + continue var/dist = get_dist(M, source) if(dist > instrument_range) // Distance check continue @@ -253,16 +255,20 @@ * Processes our song. */ /datum/song/proc/process_song(wait) - if(!length(compiled_chords) || current_chord > length(compiled_chords) || should_stop_playing(user_playing)) + if(!length(compiled_chords) || should_stop_playing(user_playing)) stop_playing() return - var/list/chord = compiled_chords[current_chord] if(++elapsed_delay >= delay_by) + // We were sustaining the final note but not anymore + if(current_chord > length(compiled_chords)) + stop_playing() + return + var/list/chord = compiled_chords[current_chord] play_chord(chord) elapsed_delay = 0 delay_by = tempodiv_to_delay(chord[length(chord)]) current_chord++ - if(current_chord > length(compiled_chords)) + if(current_chord > length(compiled_chords) + 1) if(repeat) repeat-- current_chord = 1 @@ -284,6 +290,8 @@ */ /datum/song/proc/compile_chords() legacy ? compile_legacy() : compile_synthesized() + // Some chords may be null for some reason - exclude them. + listclearnulls(compiled_chords) /** * Plays a chord. diff --git a/code/modules/karma/karma.dm b/code/modules/karma/karma.dm index 837e3a21104..6df1ce19ba7 100644 --- a/code/modules/karma/karma.dm +++ b/code/modules/karma/karma.dm @@ -2,7 +2,7 @@ Everything karma related is here. Part of karma purchase is handled in client_procs.dm */ -proc/sql_report_karma(var/mob/spender, var/mob/receiver) +/proc/sql_report_karma(var/mob/spender, var/mob/receiver) var/sqlspendername = sanitizeSQL(spender.name) var/sqlspenderkey = sanitizeSQL(spender.ckey) var/sqlreceivername = sanitizeSQL(receiver.name) diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm index e74625c8715..4217c4be6f7 100644 --- a/code/modules/library/lib_items.dm +++ b/code/modules/library/lib_items.dm @@ -101,32 +101,32 @@ /obj/structure/bookcase/manuals/medical name = "Medical Manuals bookcase" - New() - ..() - new /obj/item/book/manual/medical_cloning(src) - update_icon() +/obj/structure/bookcase/manuals/medical/New() + ..() + new /obj/item/book/manual/medical_cloning(src) + update_icon() /obj/structure/bookcase/manuals/engineering name = "Engineering Manuals bookcase" - New() - ..() - new /obj/item/book/manual/engineering_construction(src) - new /obj/item/book/manual/engineering_particle_accelerator(src) - new /obj/item/book/manual/engineering_hacking(src) - new /obj/item/book/manual/engineering_guide(src) - new /obj/item/book/manual/engineering_singularity_safety(src) - new /obj/item/book/manual/robotics_cyborgs(src) - update_icon() +/obj/structure/bookcase/manuals/engineering/New() + ..() + new /obj/item/book/manual/engineering_construction(src) + new /obj/item/book/manual/engineering_particle_accelerator(src) + new /obj/item/book/manual/engineering_hacking(src) + new /obj/item/book/manual/engineering_guide(src) + new /obj/item/book/manual/engineering_singularity_safety(src) + new /obj/item/book/manual/robotics_cyborgs(src) + update_icon() /obj/structure/bookcase/manuals/research_and_development name = "R&D Manuals bookcase" - New() - ..() - new /obj/item/book/manual/research_and_development(src) - update_icon() +/obj/structure/bookcase/manuals/research_and_development/New() + ..() + new /obj/item/book/manual/research_and_development(src) + update_icon() /* @@ -288,26 +288,26 @@ var/obj/item/book/book // Currently scanned book var/mode = 0 // 0 - Scan only, 1 - Scan and Set Buffer, 2 - Scan and Attempt to Check In, 3 - Scan and Attempt to Add to Inventory - attack_self(mob/user as mob) - mode += 1 - if(mode > 3) - mode = 0 - to_chat(user, "[src] Status Display:") - var/modedesc - switch(mode) - if(0) - modedesc = "Scan book to local buffer." - if(1) - modedesc = "Scan book to local buffer and set associated computer buffer to match." - if(2) - modedesc = "Scan book to local buffer, attempt to check in scanned book." - if(3) - modedesc = "Scan book to local buffer, attempt to add book to general inventory." - else - modedesc = "ERROR" - to_chat(user, " - Mode [mode] : [modedesc]") - if(src.computer) - to_chat(user, "Computer has been associated with this unit.") +/obj/item/barcodescanner/attack_self(mob/user as mob) + mode += 1 + if(mode > 3) + mode = 0 + to_chat(user, "[src] Status Display:") + var/modedesc + switch(mode) + if(0) + modedesc = "Scan book to local buffer." + if(1) + modedesc = "Scan book to local buffer and set associated computer buffer to match." + if(2) + modedesc = "Scan book to local buffer, attempt to check in scanned book." + if(3) + modedesc = "Scan book to local buffer, attempt to add book to general inventory." else - to_chat(user, "No associated computer found. Only local scans will function properly.") - to_chat(user, "\n") + modedesc = "ERROR" + to_chat(user, " - Mode [mode] : [modedesc]") + if(src.computer) + to_chat(user, "Computer has been associated with this unit.") + else + to_chat(user, "No associated computer found. Only local scans will function properly.") + to_chat(user, "\n") diff --git a/code/modules/martial_arts/krav_maga.dm b/code/modules/martial_arts/krav_maga.dm index 3a6f484b2aa..d348b3765fb 100644 --- a/code/modules/martial_arts/krav_maga.dm +++ b/code/modules/martial_arts/krav_maga.dm @@ -103,7 +103,7 @@ add_attack_logs(A, D, "Melee attacked with martial-art [src] : Neck Chop", ATKLOG_ALL) return 1 -datum/martial_art/krav_maga/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D) +/datum/martial_art/krav_maga/grab_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D) if(check_streak(A,D)) return 1 ..() diff --git a/code/modules/mining/laborcamp/laborshuttle.dm b/code/modules/mining/laborcamp/laborshuttle.dm index 8e585eb15b0..88b0a6601dc 100644 --- a/code/modules/mining/laborcamp/laborshuttle.dm +++ b/code/modules/mining/laborcamp/laborshuttle.dm @@ -13,15 +13,3 @@ possible_destinations = "laborcamp_away" circuit = /obj/item/circuitboard/labor_shuttle/one_way req_access = list( ) - -/obj/machinery/computer/shuttle/labor/one_way/Topic(href, href_list) - if(href_list["move"]) - var/obj/docking_port/mobile/M = SSshuttle.getShuttle("laborcamp") - if(!M) - to_chat(usr, "Cannot locate shuttle!") - return 0 - var/obj/docking_port/stationary/S = M.get_docked() - if(S && S.name == "laborcamp_away") - to_chat(usr, "Shuttle is already at the outpost!") - return 0 - ..() diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm index 54d219e4515..4a07172cad0 100644 --- a/code/modules/mining/machine_vending.dm +++ b/code/modules/mining/machine_vending.dm @@ -340,4 +340,3 @@ #undef EQUIPMENT - diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 31ff0098335..ef5268fa104 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -780,4 +780,4 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp set category = "Ghost" var/datum/spawners_menu/menu = new /datum/spawners_menu(src) - menu.ui_interact(src) + menu.tgui_interact(src) diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index b69c13987b9..2fefc6b7c74 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -592,7 +592,7 @@ message = "[src] sighs[M ? " at [M]" : ""]." m_type = 2 else - message = "[src] makes a weak noise" + message = "[src] makes a weak noise." m_type = 2 if("hsigh", "hsighs") @@ -600,7 +600,7 @@ message = "[src] sighs contentedly." m_type = 2 else - message = "[src] makes a [pick("chill", "relaxed")] noise" + message = "[src] makes a [pick("chill", "relaxed")] noise." m_type = 2 if("laugh", "laughs") diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index c7798a51a08..958afaaef94 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -13,13 +13,20 @@ emp_act if(!dna.species.bullet_act(P, src)) return FALSE if(P.is_reflectable) - if(check_reflect(def_zone)) // Checks if you've passed a reflection% check - visible_message("The [P.name] gets reflected by [src]!", \ - "The [P.name] gets reflected by [src]!") + var/can_reflect = check_reflect(def_zone) + if(!can_reflect) + return (..(P , def_zone)) //Bad luck + else + if(can_reflect == 2) //If target is holding a toy sword + var/list/safe_list = list(/obj/item/projectile/beam/lasertag, /obj/item/projectile/beam/practice) + if(!is_type_in_list(P, safe_list)) //And it's not safe + return (..(P , def_zone)) //Bad luck + visible_message("The [P.name] gets reflected by [src]!", \ + "The [P.name] gets reflected by [src]!") - P.reflect_back(src) + P.reflect_back(src) - return -1 // complete projectile permutation + return -1 // complete projectile permutation //Shields if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration)) @@ -172,10 +179,14 @@ emp_act var/obj/item/I = l_hand if(I.IsReflect(def_zone) == 1) return 1 + if(I.IsReflect(def_zone) == 2) //Toy swords + return 2 if(r_hand && istype(r_hand, /obj/item/)) var/obj/item/I = r_hand if(I.IsReflect(def_zone) == 1) return 1 + if(I.IsReflect(def_zone) == 2) //Toy swords + return 2 return 0 diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 15dfe74880e..a1be84f8163 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -66,9 +66,7 @@ if(!is_station_level(T.z)) return var/area/A = get_area(src) - if(cryo_ssd(src)) - var/obj/effect/portal/P = new /obj/effect/portal(T, null, null, 40) - P.name = "NT SSD Teleportation Portal" + cryo_ssd(src) if(A.fast_despawn) force_cryo_human(src) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 9e9724d20ec..883b781c43c 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -927,6 +927,8 @@ . += T.slowdown if(slowed) . += 10 + if(forced_look) + . += 3 if(ignorewalk) . += config.run_speed else diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 4da8aa97e06..9ecda42de04 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -186,6 +186,8 @@ return 1 if(fire_stacks > 0) adjust_fire_stacks(-0.1) //the fire is slowly consumed + for(var/obj/item/clothing/C in contents) + C.catch_fire() else ExtinguishMob() return diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index e944e692887..f9d6fc436cf 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -38,7 +38,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( GLOBAL_LIST_EMPTY(channel_to_radio_key) -proc/get_radio_key_from_channel(var/channel) +/proc/get_radio_key_from_channel(var/channel) var/key = GLOB.channel_to_radio_key[channel] if(!key) for(var/radio_key in GLOB.department_radio_keys) diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm index 52d58ad659d..6cb0cc53bd0 100644 --- a/code/modules/mob/living/silicon/robot/component.dm +++ b/code/modules/mob/living/silicon/robot/component.dm @@ -243,7 +243,7 @@ add_fingerprint(user) -proc/robot_healthscan(mob/user, mob/living/M) +/proc/robot_healthscan(mob/user, mob/living/M) var/scan_type if(istype(M, /mob/living/silicon/robot)) scan_type = "robot" diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index 270606361cb..2d18131e8cc 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -35,7 +35,6 @@ var/mail_destination = 0 var/reboot_cooldown = 60 // one minute var/last_reboot - var/emagged_time var/list/pullable_drone_items = list( /obj/item/pipe, /obj/structure/disposalconstruct, @@ -208,8 +207,8 @@ log_game("[key_name(user)] emagged drone [key_name(src)]. Laws overridden.") var/time = time2text(world.realtime,"hh:mm:ss") GLOB.lawchanges.Add("[time] : [H.name]([H.key]) emagged [name]([key])") + addtimer(CALLBACK(src, .proc/shut_down, TRUE), EMAG_TIMER) - emagged_time = world.time emagged = 1 density = 1 pass_flags = 0 @@ -361,12 +360,7 @@ /mob/living/silicon/robot/drone/update_canmove(delay_action_updates = 0) . = ..() - if(emagged) - density = 1 - if(world.time - emagged_time > EMAG_TIMER) - shut_down(TRUE) - return - density = 0 //this is reset every canmove update otherwise + density = emagged //this is reset every canmove update otherwise /mob/living/simple_animal/drone/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0) if(affect_silicon) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index af1feef3ee7..8f34314f717 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -83,6 +83,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( var/lockcharge //Used when locking down a borg to preserve cell charge var/speed = 0 //Cause sec borgs gotta go fast //No they dont! var/scrambledcodes = 0 // Used to determine if a borg shows up on the robotics console. Setting to one hides them. + var/can_lock_cover = FALSE //Used to set if a borg can re-lock its cover. var/has_camera = TRUE var/pdahide = 0 //Used to hide the borg from the messenger list var/tracking_entities = 0 //The number of known entities currently accessing the internal camera @@ -752,6 +753,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( if(allowed(W)) locked = !locked to_chat(user, "You [ locked ? "lock" : "unlock"] [src]'s interface.") + to_chat(src, "[user] [ locked ? "locked" : "unlocked"] your interface.") update_icons() else to_chat(user, "Access denied.") @@ -768,7 +770,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( if(!user.drop_item()) return if(U.action(src)) - to_chat(user, "You apply the upgrade to [src].") + user.visible_message("[user] applied [U] to [src].", "You apply [U] to [src].") U.forceMove(src) else to_chat(user, "Upgrade error.") @@ -964,16 +966,24 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( update_icons() return -/mob/living/silicon/robot/verb/unlock_own_cover() +/mob/living/silicon/robot/verb/toggle_own_cover() set category = "Robot Commands" - set name = "Unlock Cover" - set desc = "Unlocks your own cover if it is locked. You can not lock it again. A human will have to lock it for you." - if(locked) - switch(alert("You can not lock your cover again, are you sure?\n (You can still ask for a human to lock it)", "Unlock Own Cover", "Yes", "No")) - if("Yes") - locked = 0 - update_icons() - to_chat(usr, "You unlock your cover.") + set name = "Toggle Cover" + set desc = "Toggles the lock on your cover." + + if(can_lock_cover) + if(alert("Are you sure?", locked ? "Unlock Cover" : "Lock Cover", "Yes", "No") == "Yes") + locked = !locked + update_icons() + to_chat(usr, "You [locked ? "lock" : "unlock"] your cover.") + return + if(!locked) + to_chat(usr, "You cannot lock your cover yourself. Find a robotocist.") + return + if(alert("You cannnot lock your own cover again. Are you sure?\n You will need a robotocist to re-lock you.", "Unlock Own Cover", "Yes", "No") == "Yes") + locked = !locked + update_icons() + to_chat(usr, "You unlock your cover.") /mob/living/silicon/robot/attack_ghost(mob/user) if(wiresexposed) @@ -1119,7 +1129,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( return 1 /mob/living/silicon/robot/proc/radio_menu() - radio.interact(src)//Just use the radio's Topic() instead of bullshit special-snowflake code + radio.interact(src) /mob/living/silicon/robot/proc/control_headlamp() if(stat || lamp_recharging || low_power_mode) @@ -1403,6 +1413,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( modtype = "Commando" faction = list("nanotrasen") is_emaggable = FALSE + can_lock_cover = TRUE default_cell_type = /obj/item/stock_parts/cell/bluespace /mob/living/silicon/robot/deathsquad/init(alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null) @@ -1431,6 +1442,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( static_radio_channels = 1 allow_rename = FALSE weapons_unlock = TRUE + can_lock_cover = TRUE default_cell_type = /obj/item/stock_parts/cell/super var/eprefix = "Amber" @@ -1487,6 +1499,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( ear_protection = 1 // Immunity to the audio part of flashbangs emp_protection = TRUE // Immunity to EMP, due to heavy shielding damage_protection = 20 // Reduce all incoming damage by this number. Very high in the case of /destroyer borgs, since it is an admin-only borg. + can_lock_cover = TRUE default_cell_type = /obj/item/stock_parts/cell/bluespace /mob/living/silicon/robot/destroyer/init(alien = FALSE, connect_to_AI = TRUE, mob/living/silicon/ai/ai_to_sync_to = null) diff --git a/code/modules/mob/living/silicon/robot/syndicate.dm b/code/modules/mob/living/silicon/robot/syndicate.dm index f5b58696059..cfc6e1bd59d 100644 --- a/code/modules/mob/living/silicon/robot/syndicate.dm +++ b/code/modules/mob/living/silicon/robot/syndicate.dm @@ -11,6 +11,7 @@ modtype = "Syndicate" req_access = list(ACCESS_SYNDICATE) ionpulse = 1 + can_lock_cover = TRUE lawchannel = "State" var/playstyle_string = "You are a Syndicate assault cyborg!
\ You are armed with powerful offensive tools to aid you in your mission: help the operatives secure the nuclear authentication disk. \ diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index e51dc527832..97fc3ac469c 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -94,7 +94,6 @@ hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD, DIAG_PATH_HUD = HUD_LIST_LIST)//Diagnostic HUD views /obj/item/radio/headset/bot - subspace_transmission = 1 requires_tcomms = FALSE canhear_range = 0 diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm index 07a21af8a0b..915bf9ae2aa 100644 --- a/code/modules/mob/living/simple_animal/friendly/dog.dm +++ b/code/modules/mob/living/simple_animal/friendly/dog.dm @@ -9,7 +9,7 @@ response_disarm = "bops" response_harm = "kicks" speak = list("YAP", "Woof!", "Bark!", "AUUUUUU") - speak_emote = list("barks", "woofs") + speak_emote = list("barks.", "woofs.") emote_hear = list("barks!", "woofs!", "yaps.","pants.") emote_see = list("shakes its head.", "chases its tail.","shivers.") faction = list("neutral") diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm index c6f3ac845e3..2b9358214b1 100644 --- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm +++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm @@ -71,9 +71,6 @@ var/spawn_delay = 600 var/turn_on = 0 var/auto_spawn = 1 - proc - warpbots() - /mob/living/simple_animal/hostile/hivebot/tele/New() ..() @@ -83,7 +80,7 @@ visible_message("The [src] warps in!") playsound(src.loc, 'sound/effects/empulse.ogg', 25, 1) -/mob/living/simple_animal/hostile/hivebot/tele/warpbots() +/mob/living/simple_animal/hostile/hivebot/tele/proc/warpbots() icon_state = "def_radar" visible_message("The [src] turns on!") while(bot_amt > 0) diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm index 50531f976e9..14d2e933605 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm @@ -524,7 +524,7 @@ Difficulty: Medium else animate(src, pixel_x = -16, pixel_z = 0, time = 5) -obj/effect/temp_visual/fireball +/obj/effect/temp_visual/fireball icon = 'icons/obj/wizard.dmi' icon_state = "fireball" name = "fireball" diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm index bd3314d1453..b6189d56eac 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm @@ -1,6 +1,6 @@ //malfunctioning combat drones -/mob/living/simple_animal/hostile/retaliate/malf_drone +/mob/living/simple_animal/hostile/malf_drone name = "combat drone" desc = "An automated combat drone armed with state of the art weaponry and shielding." icon_state = "drone3" @@ -8,254 +8,175 @@ icon_dead = "drone_dead" ranged = 1 rapid = 3 + retreat_distance = 3 + minimum_distance = 3 speak_chance = 5 turns_per_move = 3 response_help = "pokes the" response_disarm = "gently pushes aside the" response_harm = "hits the" - speak = list("ALERT.","Hostile-ile-ile entities dee-twhoooo-wected.","Threat parameterszzzz- szzet.","Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.") - emote_see = list("beeps menacingly","whirrs threateningly","scans its immediate vicinity") + speak = list("ALERT.", "Hostile-ile-ile entities dee-twhoooo-wected.", "Threat parameterszzzz- szzet.", "Bring sub-sub-sub-systems uuuup to combat alert alpha-a-a.") + emote_see = list("beeps menacingly.", "whirrs threateningly.", "scans for targets.") a_intent = INTENT_HARM - stop_automated_movement_when_pulled = 0 - health = 300 - maxHealth = 300 + stop_automated_movement_when_pulled = FALSE + health = 200 + maxHealth = 200 speed = 8 - projectiletype = /obj/item/projectile/beam/drone + projectiletype = /obj/item/projectile/beam/immolator/weak projectilesound = 'sound/weapons/laser3.ogg' - var/datum/effect_system/trail_follow/ion/ion_trail - - //the drone randomly switches between these states because it's malfunctioning - var/hostile_drone = 0 - //0 - retaliate, only attack enemies that attack it - //1 - hostile, attack everything that comes near - - var/turf/patrol_target - var/explode_chance = 1 - var/disabled = 0 - var/exploding = 0 - - //Drones aren't affected by atmos. atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) minbodytemp = 0 - - var/has_loot = 1 faction = list("malf_drone") deathmessage = "suddenly breaks apart." del_on_death = 1 + var/datum/effect_system/trail_follow/ion/ion_trail + var/passive_mode = TRUE // if true, don't target anything. -/mob/living/simple_animal/hostile/retaliate/malf_drone/New() - ..() - if(prob(5)) - projectiletype = /obj/item/projectile/beam/pulse/drone - projectilesound = 'sound/weapons/pulse2.ogg' +/mob/living/simple_animal/hostile/malf_drone/Initialize(mapload) + . = ..() ion_trail = new ion_trail.set_up(src) ion_trail.start() + update_icons() -/mob/living/simple_animal/hostile/retaliate/malf_drone/Process_Spacemove(var/check_drift = 0) +/mob/living/simple_animal/hostile/malf_drone/Process_Spacemove(check_drift = 0) return 1 -/mob/living/simple_animal/hostile/retaliate/malf_drone/ListTargets() - if(hostile_drone) - return view(src, 10) - else - return ..() - -//self repair systems have a chance to bring the drone back to life -/mob/living/simple_animal/hostile/retaliate/malf_drone/Life(seconds, times_fired) - - //emps and lots of damage can temporarily shut us down - if(disabled > 0) - stat = UNCONSCIOUS - icon_state = "drone_dead" - disabled-- - wander = 0 - speak_chance = 0 - if(disabled <= 0) - stat = CONSCIOUS - icon_state = "drone0" - wander = 1 - speak_chance = 5 - - //repair a bit of damage - if(prob(1)) - src.visible_message("[bicon(src)] [src] shudders and shakes as some of it's damaged systems come back online.") - do_sparks(3, 1, src) - health += rand(25,100) - - //spark for no reason - if(prob(5)) - do_sparks(3, 1, src) - - //sometimes our targetting sensors malfunction, and we attack anyone nearby - if(prob(disabled ? 0 : 1)) - if(hostile_drone) - src.visible_message("[bicon(src)] [src] retracts several targetting vanes, and dulls it's running lights.") - hostile_drone = 0 - else - src.visible_message("[bicon(src)] [src] suddenly lights up, and additional targetting vanes slide into place.") - hostile_drone = 1 - - if(health / maxHealth > 0.9) - icon_state = "drone3" - explode_chance = 0 - else if(health / maxHealth > 0.7) - icon_state = "drone2" - explode_chance = 0 - else if(health / maxHealth > 0.5) - icon_state = "drone1" - explode_chance = 0.5 - else if(health / maxHealth > 0.3) - icon_state = "drone0" - explode_chance = 5 - else if(health > 0) - //if health gets too low, shut down - icon_state = "drone_dead" - exploding = 0 - if(!disabled) - if(prob(50)) - src.visible_message("[bicon(src)] [src] suddenly shuts down!") - else - src.visible_message("[bicon(src)] [src] suddenly lies still and quiet.") - disabled = rand(150, 600) - walk(src,0) - - if(exploding && prob(20)) - if(prob(50)) - src.visible_message("[bicon(src)] [src] begins to spark and shake violenty!") - else - src.visible_message("[bicon(src)] [src] sparks and shakes like it's about to explode!") - do_sparks(3, 1, src) - - if(!exploding && !disabled && prob(explode_chance)) - exploding = 1 - stat = UNCONSCIOUS - wander = 1 - walk(src,0) - spawn(rand(50,150)) - if(!disabled && exploding) - explosion(get_turf(src), 0, 1, 4, 7) - //proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = 1) - ..() - -//ion rifle! -/mob/living/simple_animal/hostile/retaliate/malf_drone/emp_act(severity) - health -= rand(3,15) * (severity + 1) - disabled = rand(150, 600) - hostile_drone = 0 - walk(src,0) - -/mob/living/simple_animal/hostile/retaliate/malf_drone/Destroy() //Seriously, what the actual hell. - //some random debris left behind - if(has_loot) - do_sparks(3, 1, src) - var/obj/O - - //shards - O = new /obj/item/shard(loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(75)) - O = new /obj/item/shard(loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(50)) - O = new /obj/item/shard(loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(25)) - O = new /obj/item/shard(loc) - step_to(O, get_turf(pick(view(7, src)))) - - //rods - O = new /obj/item/stack/rods(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(75)) - O = new /obj/item/stack/rods(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(50)) - O = new /obj/item/stack/rods(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(25)) - O = new /obj/item/stack/rods(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - - //plasteel - O = new /obj/item/stack/sheet/plasteel(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(75)) - O = new /obj/item/stack/sheet/plasteel(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(50)) - O = new /obj/item/stack/sheet/plasteel(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - if(prob(25)) - O = new /obj/item/stack/sheet/plasteel(src.loc) - step_to(O, get_turf(pick(view(7, src)))) - - //also drop dummy circuit boards deconstructable for research (loot) - var/obj/item/circuitboard/C - - //spawn 1-4 boards of a random type - var/spawnees = 0 - var/num_boards = rand(1,4) - var/list/options = list(1,2,4,8,16,32,64,128,256, 512) - for(var/i=0, i 0.9) + icon_state = "drone3" + else if(health / maxHealth > 0.7) + icon_state = "drone2" + else if(health / maxHealth > 0.5) + icon_state = "drone1" + else + icon_state = "drone0" + +/mob/living/simple_animal/hostile/malf_drone/adjustHealth(damage, updating_health) + do_sparks(3, 1, src) + passive_mode = FALSE + update_icons() + . = ..() // this will handle finding a target if there is a valid one nearby + +/mob/living/simple_animal/hostile/malf_drone/Life(seconds, times_fired) + . = ..() + if(.) // mob is alive. We check this just in case Life() can fire for qdel'ed mobs. + if(times_fired % 15 == 0) // every 15 cycles, aka 30 seconds, 50% chance to switch between modes + scramble_settings() + +/mob/living/simple_animal/hostile/malf_drone/proc/scramble_settings() + if(prob(50)) + do_sparks(3, 1, src) + passive_mode = !passive_mode + if(passive_mode) + visible_message("[src] retracts several targetting vanes.") + if(target) + LoseTarget() + else + visible_message("[src] suddenly lights up, and additional targetting vanes slide into place.") + update_icons() + +/mob/living/simple_animal/hostile/malf_drone/emp_act(severity) + adjustHealth(100 / severity) // takes the same damage as a mining drone from emp + +/mob/living/simple_animal/hostile/malf_drone/drop_loot() + do_sparks(3, 1, src) + + var/turf/T = get_turf(src) + + //shards + var/obj/O = new /obj/item/shard(T) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(75)) + O = new /obj/item/shard(T) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(50)) + O = new /obj/item/shard(T) + step_to(O, get_turf(pick(view(7, src)))) + if(prob(25)) + O = new /obj/item/shard(T) + step_to(O, get_turf(pick(view(7, src)))) + + //rods + var/obj/item/stack/K = new /obj/item/stack/rods(T) + step_to(K, get_turf(pick(view(7, src)))) + K.amount = pick(1, 2, 3, 4) + K.update_icon() + + //plasteel + K = new /obj/item/stack/sheet/plasteel(T) + step_to(K, get_turf(pick(view(7, src)))) + K.amount = pick(1, 2, 3, 4) + K.update_icon() + + //also drop dummy circuit boards deconstructable for research (loot) + var/obj/item/circuitboard/C + + //spawn 1-4 boards of a random type + var/spawnees = 0 + var/num_boards = rand(1, 4) + var/list/options = list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512) + for(var/i=0, iERROR: attempt to use evolve queen ability on a non-princess
") - return - var/feedings_left = user.feedings_to_evolve - user.fed - if(feedings_left > 0) - to_chat(user, "You must wrap [feedings_left] more humanoid prey before you can do this!") - return - for(var/mob/living/simple_animal/hostile/poison/terror_spider/queen/Q in GLOB.ts_spiderlist) - if(Q.spider_awaymission == user.spider_awaymission) - to_chat(user, "The presence of another Queen in the area is preventing you from maturing.") - return - user.evolve_to_queen() // ---------- QUEEN ACTIONS @@ -93,19 +72,11 @@ var/mob/living/simple_animal/hostile/poison/terror_spider/queen/user = owner user.LayQueenEggs() -/datum/action/innate/terrorspider/queen/queenfakelings - name = "Fake Spiderlings" - icon_icon = 'icons/effects/effects.dmi' - button_icon_state = "spiderling" - -/datum/action/innate/terrorspider/queen/queenfakelings/Activate() - var/mob/living/simple_animal/hostile/poison/terror_spider/queen/user = owner - user.QueenFakeLings() // ---------- EMPRESS /datum/action/innate/terrorspider/queen/empress/empresserase - name = "Erase Brood" + name = "Empress Erase Brood" icon_icon = 'icons/effects/blood.dmi' button_icon_state = "mgibbl1" @@ -113,6 +84,16 @@ var/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/user = owner user.EraseBrood() +/datum/action/innate/terrorspider/queen/empress/empresslings + name = "Empresss Spiderlings" + icon_icon = 'icons/effects/effects.dmi' + button_icon_state = "spiderling" + +/datum/action/innate/terrorspider/queen/empress/empresslings/Activate() + var/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/user = owner + user.EmpressLings() + + // ---------- WEB /mob/living/simple_animal/hostile/poison/terror_spider/proc/Web() diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/chem.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/chem.dm index 60e11de670a..b685fdd1959 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/chem.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/chem.dm @@ -22,7 +22,7 @@ else if(volume < 90) // bitten thrice, die quickly, severe muscle cramps make movement very difficult. Even calling for help probably won't save you. // total damage: 4, human health 150 until crit, = 37.5 ticks, = 75s = 1m15s until death - update_flags |= M.adjustToxLoss(4, FALSE) // a bit worse than coiine + update_flags |= M.adjustToxLoss(4, FALSE) update_flags |= M.EyeBlurry(6, FALSE) M.Confused(6) else diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm index 137d6739466..f011becf6b8 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/empress.dm @@ -19,7 +19,6 @@ ventcrawler = 1 idle_ventcrawl_chance = 0 ai_playercontrol_allowtype = 0 - rapid = 3 canlay = 1000 spider_tier = TS_TIER_5 projectiletype = /obj/item/projectile/terrorqueenspit/empress @@ -35,6 +34,8 @@ /mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/New() ..() + empresslings_action = new() + empresslings_action.Grant(src) empresserase_action = new() empresserase_action.Grant(src) @@ -44,7 +45,6 @@ /mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/NestMode() ..() queeneggs_action.button.name = "Empress Eggs" - queenfakelings_action.button.name = "Empress Lings" /mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/LayQueenEggs() var/eggtype = input("What kind of eggs?") as null|anything in list(TS_DESC_QUEEN, TS_DESC_MOTHER, TS_DESC_PRINCE, TS_DESC_PRINCESS, TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN, TS_DESC_BLACK, TS_DESC_PURPLE, TS_DESC_WHITE, TS_DESC_BROWN) @@ -70,7 +70,7 @@ if(TS_DESC_PRINCE) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/prince, numlings) if(TS_DESC_PRINCESS) - DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/princess, numlings) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess, numlings) if(TS_DESC_MOTHER) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/mother, numlings) if(TS_DESC_QUEEN) @@ -78,7 +78,7 @@ else to_chat(src, "Unrecognized egg type.") -/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/QueenFakeLings() +/mob/living/simple_animal/hostile/poison/terror_spider/queen/empress/proc/EmpressLings() var/numlings = input("How many?") as null|anything in list(10, 20, 30, 40, 50) var/sbpc = input("%chance to be stillborn?") as null|anything in list(0, 25, 50, 75, 100) for(var/i=0, iThrough the hivemind, the raw power of [src] floods into your body, burning it from the inside out!") @@ -106,8 +107,6 @@ qdel(T) to_chat(src, "All Terror Spiders, except yourself, will die off shortly.") - /obj/item/projectile/terrorqueenspit/empress - damage_type = BURN - damage = 30 - bonus_tox = 0 + damage = 90 + diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/green.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/green.dm index 1946f1a32ee..b07f34ec368 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/green.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/green.dm @@ -39,11 +39,10 @@ to_chat(src, "You must wrap more humanoid prey before you can do this!") return var/list/eggtypes = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN) - var/num_brown = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/brown) - if(num_brown < 2) + var/list/spider_array = CountSpidersDetailed(FALSE) + if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/brown] < 2) eggtypes += TS_DESC_BROWN - var/num_black = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/black) - if(num_black < 2) + if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/black] < 2) eggtypes += TS_DESC_BLACK var/eggtype = pick(eggtypes) if(client) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/hive.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/hive.dm index 245ae95c5e9..407e6f3174e 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/hive.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/hive.dm @@ -4,7 +4,8 @@ /mob/living/simple_animal/hostile/poison/terror_spider/proc/DoHiveSense() var/hsline = "" to_chat(src, "Your Brood: ") - for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist) + for(var/thing in GLOB.ts_spiderlist) + var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing if(T.spider_awaymission != spider_awaymission) continue hsline = "* [T] in [get_area(T)], " @@ -20,21 +21,55 @@ /mob/living/simple_animal/hostile/poison/terror_spider/proc/CountSpiders() var/numspiders = 0 - for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist) + for(var/thing in GLOB.ts_spiderlist) + var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing if(T.stat != DEAD && !T.spider_placed && spider_awaymission == T.spider_awaymission) numspiders += 1 return numspiders -/mob/living/simple_animal/hostile/poison/terror_spider/proc/CountSpidersType(specific_type) - var/numspiders = 0 - for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist) - if(T.stat != DEAD && !T.spider_placed && spider_awaymission == T.spider_awaymission) - if(T.type == specific_type) - numspiders += 1 - for(var/obj/structure/spider/eggcluster/terror_eggcluster/E in GLOB.ts_egg_list) - if(E.spiderling_type == specific_type && E.z == z) - numspiders += E.spiderling_number - for(var/obj/structure/spider/spiderling/terror_spiderling/L in GLOB.ts_spiderling_list) - if(!L.stillborn && L.grow_as == specific_type && L.z == z) - numspiders += 1 - return numspiders +/mob/living/simple_animal/hostile/poison/terror_spider/proc/CountSpidersDetailed(check_mine = FALSE, list/mytypes = list()) + var/list/spider_totals = list("all" = 0) + var/check_list = length(mytypes) > 0 + for(var/thistype in mytypes) + spider_totals[thistype] = 0 + for(var/thing in GLOB.ts_spiderlist) + var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing + if(T.stat == DEAD || T.spider_placed || spider_awaymission != T.spider_awaymission) + continue + if(check_mine && T.spider_myqueen != src) + continue + if(check_list && !(T.type in mytypes)) + continue + if(T == src) + continue + if(spider_totals[T.type]) + spider_totals[T.type]++ + else + spider_totals[T.type] = 1 + spider_totals["all"]++ + for(var/thing in GLOB.ts_egg_list) + var/obj/structure/spider/eggcluster/terror_eggcluster/E = thing + if(check_mine && E.spider_myqueen != src) + continue + if(check_list && E.spiderling_type && !(E.spiderling_type in mytypes)) + continue + if(spider_totals[E.spiderling_type]) + spider_totals[E.spiderling_type] += E.spiderling_number + else + spider_totals[E.spiderling_type] = E.spiderling_number + spider_totals["all"] += E.spiderling_number + for(var/thing in GLOB.ts_spiderling_list) + var/obj/structure/spider/spiderling/terror_spiderling/L = thing + if(L.stillborn) + continue + if(check_mine && L.spider_myqueen != src) + continue + if(check_list && L.grow_as && !(L.grow_as in mytypes)) + continue + if(spider_totals[L.grow_as]) + spider_totals[L.grow_as]++ + else + spider_totals[L.grow_as] = 1 + spider_totals["all"]++ + return spider_totals + diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm index e486872abbb..7b900d8a881 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/prince.dm @@ -29,6 +29,7 @@ spider_opens_doors = 2 web_type = /obj/structure/spider/terrorweb/purple ai_spins_webs = FALSE + gender = MALE /mob/living/simple_animal/hostile/poison/terror_spider/prince/death(gibbed) if(can_die() && !hasdied && spider_uo71) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm index 6f33c51b246..7a840405cd0 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/princess.dm @@ -2,58 +2,76 @@ // -------------------------------------------------------------------------------- // ----------------- TERROR SPIDERS: T3 PRINCESS OF TERROR -------------------------- // -------------------------------------------------------------------------------- -// -------------: ROLE: cutesy -// -------------: AI: as green, but will evolve to queen when it can -// -------------: SPECIAL: can evolve into a queen, if fed enough -// -------------: TO FIGHT IT: kill it before it evolves +// -------------: ROLE: mini-queen, maintains a smaller nest, but also more expendable +// -------------: AI: maintains a small group of spiders. Small fraction of a queen's nest. +// -------------: SPECIAL: lays eggs over time, like a queen +// -------------: TO FIGHT IT: hunt it before it lays eggs // -------------: SPRITES FROM: FoS, https://www.paradisestation.org/forum/profile/335-fos -/mob/living/simple_animal/hostile/poison/terror_spider/princess +/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess name = "Princess of Terror spider" desc = "An enormous spider. It looks strangely cute and fluffy." - spider_role_summary = "Future Queen" + spider_role_summary = "Mini-Queen" ai_target_method = TS_DAMAGE_SIMPLE icon_state = "terror_princess1" icon_living = "terror_princess1" icon_dead = "terror_princess1_dead" maxHealth = 150 health = 150 - regen_points_per_hp = 1 // always regens very fast - force_threshold = 18 // outright immune to anything of force under 18, same as queen - melee_damage_lower = 10 - melee_damage_upper = 20 - idle_ventcrawl_chance = 5 spider_tier = TS_TIER_3 - spider_opens_doors = 2 - web_type = /obj/structure/spider/terrorweb/queen - var/feedings_to_evolve = 3 - var/datum/action/innate/terrorspider/ventsmash/ventsmash_action - var/datum/action/innate/terrorspider/evolvequeen/evolvequeen_action -/mob/living/simple_animal/hostile/poison/terror_spider/princess/New() - ..() - ventsmash_action = new() - ventsmash_action.Grant(src) - evolvequeen_action = new() - evolvequeen_action.Grant(src) + // Unlike queens, no ranged attack. + ranged = 0 + retreat_distance = 0 + minimum_distance = 0 + projectilesound = null + projectiletype = null -/mob/living/simple_animal/hostile/poison/terror_spider/princess/proc/evolve_to_queen() - var/mob/living/simple_animal/hostile/poison/terror_spider/queen/Q = new(loc) - if(mind) - mind.transfer_to(Q) - // Calling `transfer_to()` removes our new body (the Queen's) ability to see the med hud, so we have to re-add the queen here. - var/datum/atom_hud/U = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] - U.add_hud_to(Q) - qdel(src) + canlay = 0 + hasnested = TRUE + spider_spawnfrequency = 300 // 30 seconds + var/grant_prob = 25 // 25% chance every spider_spawnfrequency seconds to gain 1 egg + var/spider_max_children = 8 -/mob/living/simple_animal/hostile/poison/terror_spider/princess/DoWrap() - . = ..() - if(fed == 0) + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/grant_queen_subtype_abilities() + // Queens start in movement mode, where they can ventcrawl but not lay eggs. Then they move to NestMode() where they can wallsmash and egglay, but not ventcrawl. + // Princesses are simpler, and can always lay eggs, always vent crawl, but never smash walls. Unlike queens, they don't have a "nesting" transformation. + queeneggs_action = new() + queeneggs_action.Grant(src) + queensense_action = new() + queensense_action.Grant(src) + + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/ListAvailableEggTypes() + var/list/valid_types = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN) + + // Each princess can also have ONE black/purple/brown. If it dies, they can pick a new spider from the 3 advanced types to lay. + var/list/spider_array = CountSpidersDetailed(TRUE, list(/mob/living/simple_animal/hostile/poison/terror_spider/black, /mob/living/simple_animal/hostile/poison/terror_spider/purple, /mob/living/simple_animal/hostile/poison/terror_spider/brown)) + if(spider_array["all"] < 1) + valid_types |= TS_DESC_BLACK + valid_types |= TS_DESC_PURPLE + valid_types |= TS_DESC_BROWN + + return valid_types + + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/grant_eggs() + spider_lastspawn = world.time + + if(!prob(grant_prob)) + return + + var/list/spider_array = CountSpidersDetailed(TRUE) + var/brood_count = spider_array["all"] + + // Color shifts depending on how much of their brood capacity they have used. + if(brood_count == 0) icon_state = "terror_princess1" icon_living = "terror_princess1" icon_dead = "terror_princess1_dead" desc = "An enormous spider. It looks strangely cute and fluffy, with soft pink fur covering most of its body." - else if(fed == 1) + else if(brood_count < (spider_max_children /2)) icon_state = "terror_princess2" icon_living = "terror_princess2" icon_dead = "terror_princess2_dead" @@ -62,13 +80,45 @@ icon_state = "terror_princess3" icon_living = "terror_princess3" icon_dead = "terror_princess3_dead" - desc = "An enormous spider. Its entire body has turned an ominous blood red color, with actual blood dripping from its jaws. It stares around, hungrily." + desc = "An enormous spider. Its entire body looks to be the color of dried blood." -/mob/living/simple_animal/hostile/poison/terror_spider/princess/spider_special_action() - if(cocoon_target) - handle_cocoon_target() - else if(fed >= feedings_to_evolve) - evolve_to_queen() - else if(world.time > (last_cocoon_object + freq_cocoon_object)) - seek_cocoon_target() + if(!isturf(loc)) + to_chat(src, "You cannot generate eggs while hiding in [loc].") + return + + if((brood_count + canlay) >= spider_max_children) + return + canlay++ + if(canlay == 1) + to_chat(src, "You have an egg available to lay.") + else + to_chat(src, "You have [canlay] eggs available to lay.") + + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/NestMode() + // Princesses don't nest. However, we still need to override this in case an AI princess calls it. + return + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/spider_special_action() + // Princess AI routine. GREATLY simplified version of queen routine. + if(!stat && !ckey) + // Utilize normal queen AI for finding a nest site (neststep=0), and activating NestMode() (neststep=1) + if(neststep != 2) + return ..() + // After that, simply lay an egg once per nestfrequency, until we have the max. + if(world.time < (lastnestsetup + nestfrequency)) + return + lastnestsetup = world.time + if(ai_nest_is_full()) + return + spider_lastspawn = world.time + DoLayTerrorEggs(pick(spider_types_standard), 1) + // Yes, this means NPC princesses won't create T2 spiders. + + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/ai_nest_is_full() + var/list/spider_array = CountSpidersDetailed(TRUE) + if(spider_array["all"] >= spider_max_children) + return TRUE + return FALSE diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm index 737b6eba22a..af475b1a59a 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen.dm @@ -5,7 +5,7 @@ // -------------: ROLE: gamma-level threat to the whole station, like a blob // -------------: AI: builds a nest, lays many eggs, attempts to take over the station // -------------: SPECIAL: spins webs, breaks lights, breaks cameras, webs objects, lays eggs, commands other spiders... -// -------------: TO FIGHT IT: bring an army, and take no prisoners. Mechs and/or decloner guns are a very good idea. +// -------------: TO FIGHT IT: bring an army, and take no prisoners. Mechs are a very good idea. // -------------: SPRITES FROM: IK3I /mob/living/simple_animal/hostile/poison/terror_spider/queen @@ -43,69 +43,94 @@ var/neststep = 0 var/hasnested = FALSE var/spider_max_per_nest = 35 // above this, AI queens become stable - var/canlay = 4 // main counter for egg-laying ability! # = num uses, incremented at intervals + var/canlay = 5 // main counter for egg-laying ability! # = num uses, incremented at intervals var/eggslaid = 0 - var/spider_can_fakelings = 3 // spawns defective spiderlings that don't grow up, used to freak out crew, atmosphere var/list/spider_types_standard = list(/mob/living/simple_animal/hostile/poison/terror_spider/red, /mob/living/simple_animal/hostile/poison/terror_spider/gray, /mob/living/simple_animal/hostile/poison/terror_spider/green, /mob/living/simple_animal/hostile/poison/terror_spider/black) var/datum/action/innate/terrorspider/queen/queennest/queennest_action var/datum/action/innate/terrorspider/queen/queensense/queensense_action var/datum/action/innate/terrorspider/queen/queeneggs/queeneggs_action - var/datum/action/innate/terrorspider/queen/queenfakelings/queenfakelings_action var/datum/action/innate/terrorspider/ventsmash/ventsmash_action + /mob/living/simple_animal/hostile/poison/terror_spider/queen/New() ..() - queennest_action = new() - queennest_action.Grant(src) ventsmash_action = new() ventsmash_action.Grant(src) + grant_queen_subtype_abilities() spider_myqueen = src if(spider_awaymission) - spider_growinstantly = 1 + spider_growinstantly = TRUE spider_spawnfrequency = 150 + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/grant_queen_subtype_abilities() + queennest_action = new() + queennest_action.Grant(src) + /mob/living/simple_animal/hostile/poison/terror_spider/queen/Life(seconds, times_fired) . = ..() if(stat != DEAD) // Can't use if(.) for this due to the fact it can sometimes return FALSE even when mob is alive. - if(ckey && canlay < 12 && hasnested) // max 12 eggs worth stored at any one time, realistically that's tons. + if(ckey && hasnested) if(world.time > (spider_lastspawn + spider_spawnfrequency)) - if(eggslaid >= 20) - canlay += 3 - else if(eggslaid >= 10) - canlay += 2 - else - canlay++ - spider_lastspawn = world.time - if(canlay == 1) - to_chat(src, "You have an egg available to lay.") - else if(canlay == 12) - to_chat(src, "You have [canlay] eggs available to lay. You won't grow any more eggs until you lay some of your existing ones.") - else - to_chat(src, "You have [canlay] eggs available to lay.") + grant_eggs() + + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/grant_eggs() + spider_lastspawn = world.time + canlay += getSpiderLevel() + if(canlay == 1) + to_chat(src, "You have an egg available to lay.") + else if(canlay > 1) + to_chat(src, "You have [canlay] eggs available to lay.") + + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/getSpiderLevel() + return 1 + round(MinutesAlive() / 10) + + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/MinutesAlive() + return round((world.time - spider_creation_time) / 600) + /mob/living/simple_animal/hostile/poison/terror_spider/queen/death(gibbed) if(can_die() && !hasdied) if(spider_uo71) UnlockBlastDoors("UO71_Caves") - // When a queen dies, so do her player-controlled purple-type guardians. Intended as a motivator for purples to ensure they guard her. - for(var/mob/living/simple_animal/hostile/poison/terror_spider/purple/P in GLOB.ts_spiderlist) - if(ckey) - P.visible_message("\The [src] writhes in pain!") - to_chat(P,"\The [src] has died. Without her hivemind link, purple terrors like yourself cannot survive more than a few minutes!") - P.degenerate = 1 + // When a queen (or subtype!) dies, so do all of her spiderlings, and half of all her fully grown offspring + // This feature is intended to provide a way for crew to still win even if the queen has overwhelming numbers - by sniping the queen. + for(var/thing in GLOB.ts_spiderlist) + var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing + if(!T.spider_myqueen) + continue + if(T.spider_myqueen != src) + continue + if(prob(50) || T.spider_tier >= spider_tier) + to_chat(T, "\The psychic backlash from the death of [src] crashes into your mind! Somehow... you find a way to keep going!") + continue + T.visible_message("[T] writhes in pain!") + to_chat(T, "\The psychic backlash from the death of [src] overwhelms you! You feel the life start to drain out of you...") + T.degenerate = TRUE + for(var/thing in GLOB.ts_spiderling_list) + var/obj/structure/spider/spiderling/terror_spiderling/T = thing + if(T.spider_myqueen && T.spider_myqueen == src) + qdel(T) return ..() + /mob/living/simple_animal/hostile/poison/terror_spider/queen/Retaliate() ..() - for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist) + for(var/thing in GLOB.ts_spiderlist) + var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing T.enemies |= enemies + /mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/ai_nest_is_full() var/numspiders = CountSpiders() if(numspiders >= spider_max_per_nest) return TRUE return FALSE + /mob/living/simple_animal/hostile/poison/terror_spider/queen/spider_special_action() if(!stat && !ckey) switch(neststep) @@ -152,11 +177,13 @@ neststep = 2 NestMode() if(2) - // Create initial four purple nest guards. + // Create initial T2 spiders. if(world.time > (lastnestsetup + nestfrequency)) lastnestsetup = world.time spider_lastspawn = world.time - DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, 4) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, 2) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/white, 2) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, 2) neststep = 3 if(3) // Create spiders (random types) until nest is full. @@ -183,28 +210,26 @@ neststep = 4 else spider_lastspawn = world.time - var/num_purple = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/purple) - var/num_white = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/white) - var/num_brown = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/brown) - if(num_purple < 4) + var/list/spider_array = CountSpidersDetailed(FALSE) + if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/purple] < 4) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, 2) - else if(num_white < 2) + else if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/white] < 2) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/white, 2) - else if(num_brown < 4) + else if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/brown] < 4) DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, 4) else DoLayTerrorEggs(pick(spider_types_standard), 5) + /mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/NestPrompt() var/confirm = alert(src, "Are you sure you want to nest? You will be able to lay eggs, and smash walls, but not ventcrawl.","Nest?","Yes","No") if(confirm == "Yes") NestMode() + /mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/NestMode() queeneggs_action = new() queeneggs_action.Grant(src) - queenfakelings_action = new() - queenfakelings_action.Grant(src) queensense_action = new() queensense_action.Grant(src) queennest_action.Remove(src) @@ -213,21 +238,8 @@ ai_ventcrawls = FALSE environment_smash = ENVIRONMENT_SMASH_RWALLS DoQueenScreech(8, 100, 8, 100) - MassFlicker() to_chat(src, "You have matured to your egglaying stage. You can now smash through walls, and lay eggs, but can no longer ventcrawl.") -/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/MassFlicker() - var/list/target_lights = list() - for(var/mob/living/carbon/human/H in GLOB.player_list) - if(H.z != z) - continue - if(H.stat == DEAD) - continue - for(var/obj/machinery/light/L in orange(7, H)) - if(L.on && prob(25)) - target_lights += L - for(var/obj/machinery/light/I in target_lights) - I.flicker() /mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/LayQueenEggs() if(stat == DEAD) @@ -242,42 +254,21 @@ else to_chat(src, "Too soon to attempt that again. Wait just a few more seconds...") return - var/list/eggtypes = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN, TS_DESC_BLACK, TS_DESC_PURPLE) - if(canlay >= 4) - eggtypes |= TS_DESC_BROWN - if(canlay >= 12) - eggtypes |= TS_DESC_MOTHER - eggtypes |= TS_DESC_PRINCE - var/num_purples = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/purple) - if(num_purples >= 2) - eggtypes -= TS_DESC_PURPLE - var/num_blacks = CountSpidersType(/mob/living/simple_animal/hostile/poison/terror_spider/black) - if(num_blacks >= 2) - eggtypes -= TS_DESC_BLACK + var/list/eggtypes = ListAvailableEggTypes() + var/list/eggtypes_uncapped = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN) + var/eggtype = input("What kind of eggs?") as null|anything in eggtypes + if(canlay < 1) + // this was checked before input() but we have to check again to prevent them spam-clicking the popup. + to_chat(src, "Too soon to lay another egg.") + return if(!(eggtype in eggtypes)) to_chat(src, "Unrecognized egg type.") return 0 - if(eggtype == TS_DESC_MOTHER || eggtype == TS_DESC_PRINCE) - if(canlay < 12) - to_chat(src, "Insufficient strength. It takes as much effort to lay one of those as it does to lay 12 normal eggs.") - else - if(eggtype == TS_DESC_MOTHER) - canlay -= 12 - DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/mother, 1) - else if(eggtype == TS_DESC_PRINCE) - canlay -= 12 - DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/prince, 1) - return - else if(eggtype == TS_DESC_BROWN) - if(canlay < 4) - to_chat(src, "Insufficient strength. It takes as much effort to lay one of those as it does to lay 4 normal eggs.") - else - canlay -= 4 - DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, 1) - return + + // Multiple of eggtypes_uncapped can be laid at once. Other types must be laid one at a time (to prevent exploits) var/numlings = 1 - if(eggtype != TS_DESC_PURPLE) + if(eggtype in eggtypes_uncapped) if(canlay >= 5) numlings = input("How many in the batch?") as null|anything in list(1, 2, 3, 4, 5) else if(canlay >= 3) @@ -287,27 +278,55 @@ if(eggtype == null || numlings == null) to_chat(src, "Cancelled.") return + // Actually lay the eggs. if(canlay < numlings) // We have to check this again after the popups, to account for people spam-clicking the button, then doing all the popups at once. to_chat(src, "Too soon to do this again!") return canlay -= numlings eggslaid += numlings - if(eggtype == TS_DESC_RED) - DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/red, numlings) - else if(eggtype == TS_DESC_GRAY) - DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/gray, numlings) - else if(eggtype == TS_DESC_GREEN) - DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/green, numlings) - else if(eggtype == TS_DESC_BLACK) - DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/black, numlings) - else if(eggtype == TS_DESC_PURPLE) - DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, numlings) - else - to_chat(src, "Unrecognized egg type.") + switch(eggtype) + if(TS_DESC_RED) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/red, numlings) + if(TS_DESC_GRAY) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/gray, numlings) + if(TS_DESC_GREEN) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/green, numlings) + if(TS_DESC_BLACK) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/black, numlings) + if(TS_DESC_PURPLE) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/purple, numlings) + if(TS_DESC_BROWN) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/brown, numlings) + if(TS_DESC_MOTHER) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/mother, numlings) + if(TS_DESC_PRINCE) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/prince, numlings) + if(TS_DESC_PRINCESS) + DoLayTerrorEggs(/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess, numlings) + else + to_chat(src, "Unrecognized egg type.") + + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/ListAvailableEggTypes() + if(MinutesAlive() >= 20) + var/list/spider_array = CountSpidersDetailed(TRUE, list(/mob/living/simple_animal/hostile/poison/terror_spider/mother, /mob/living/simple_animal/hostile/poison/terror_spider/prince, /mob/living/simple_animal/hostile/poison/terror_spider/queen/princess)) + if(spider_array["all"] == 0) + return list(TS_DESC_PRINCE, TS_DESC_PRINCESS) // Mother will be added to this list.... AFTER mothers are reworked. + + var/list/valid_types = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN) + var/list/spider_array = CountSpidersDetailed(FALSE, list(/mob/living/simple_animal/hostile/poison/terror_spider/brown, /mob/living/simple_animal/hostile/poison/terror_spider/purple, /mob/living/simple_animal/hostile/poison/terror_spider/black)) + if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/brown] < 2) + valid_types += TS_DESC_BROWN + if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/purple] < 2) + valid_types += TS_DESC_PURPLE + if(spider_array[/mob/living/simple_animal/hostile/poison/terror_spider/black] < 2) + valid_types += TS_DESC_BLACK + return valid_types + /mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/DoQueenScreech(light_range, light_chance, camera_range, camera_chance) - visible_message("\The [src] emits a bone-chilling shriek!") + visible_message("[src] emits a bone-chilling shriek!") for(var/obj/machinery/light/L in orange(light_range, src)) if(L.on && prob(light_chance)) L.break_light_tube() @@ -315,46 +334,33 @@ if(C.status && prob(camera_chance)) C.toggle_cam(src, 0) -/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/QueenFakeLings() - if(eggslaid < 10) - to_chat(src, "You must lay at least 10 eggs before doing this.") + +/mob/living/simple_animal/hostile/poison/terror_spider/queen/examine(mob/user) + . = ..() + if(!key || stat == DEAD) return - if(spider_can_fakelings) - spider_can_fakelings-- - var/numlings = 25 - for(var/i in 1 to numlings) - var/obj/structure/spider/spiderling/terror_spiderling/S = new /obj/structure/spider/spiderling/terror_spiderling(get_turf(src)) - S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/red - S.stillborn = 1 - S.spider_mymother = src - if(!spider_can_fakelings) - queenfakelings_action.Remove(src) - else - to_chat(src, "You have run out of uses of this ability.") + if(!isobserver(user) && !isterrorspider(user)) + return + . += "[p_they(TRUE)] has laid [eggslaid] egg[eggslaid != 1 ? "s" : ""]." + . += "[p_they(TRUE)] has lived for [MinutesAlive()] minutes." + /obj/item/projectile/terrorqueenspit - name = "poisonous spit" - damage = 0 + name = "acid spit" + damage = 40 icon_state = "toxin" - damage_type = TOX - var/bonus_tox = 30 + damage_type = BURN -/obj/item/projectile/terrorqueenspit/on_hit(mob/living/carbon/target, blocked = 0, hit_zone) - if(ismob(target) && blocked < 100) - var/mob/living/L = target - if(L.reagents) - if(L.can_inject(null, FALSE, "chest", FALSE)) - L.Hallucinate(400) - if(!isterrorspider(L)) - L.adjustToxLoss(bonus_tox) /obj/structure/spider/terrorweb/queen - name = "shimmering web" - desc = "This web seems to shimmer all different colors in the light." + name = "airtight web" + desc = "This multi-layered web seems to be able to resist air pressure." + + +/obj/structure/spider/terrorweb/queen/New() + . = ..() + air_update_turf(TRUE) + +/obj/structure/spider/terrorweb/queen/CanAtmosPass(turf/T) + return FALSE -/obj/structure/spider/terrorweb/queen/web_special_ability(mob/living/carbon/C) - if(istype(C)) - var/inject_target = pick("chest","head") - if(C.can_inject(null, FALSE, inject_target, FALSE)) - C.Hallucinate(400) - C.adjustToxLoss(30) diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm index a889bc6d328..8961fcdddb5 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/reproduction.dm @@ -188,7 +188,7 @@ C.enemies = enemies if(spider_growinstantly) C.amount_grown = 250 - C.spider_growinstantly = 1 + C.spider_growinstantly = TRUE spawn(10) stop_automated_movement = 0 @@ -196,7 +196,7 @@ name = "terror egg cluster" desc = "A cluster of tiny spider eggs. They pulse with a strong inner life, and appear to have sharp thorns on the sides." icon_state = "eggs" - var/spider_growinstantly = 0 + var/spider_growinstantly = FALSE var/spider_myqueen = null var/spider_mymother = null var/spiderling_type = null diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_ai.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_ai.dm index 11e4cac3e4a..c3e0c9a0511 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_ai.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_ai.dm @@ -126,7 +126,7 @@ spider_steps_taken++ CreatePath(entry_vent) step_to(src,entry_vent) - if(spider_debug > 0) + if(spider_debug) visible_message("[src] moves towards the vent [entry_vent].") else path_to_vent = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm index ab36c6ca313..6c943b26f53 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/terror_spiders.dm @@ -17,6 +17,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) // Name / Description name = "terror spider" desc = "The generic parent of all other terror spider types. If you see this in-game, it is a bug." + gender = FEMALE // Icons icon = 'icons/mob/terrorspider.dmi' @@ -141,29 +142,33 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) var/mylocation = null var/chasecycles = 0 var/web_infects = 0 + var/spider_creation_time = 0 var/datum/action/innate/terrorspider/web/web_action var/web_type = /obj/structure/spider/terrorweb var/datum/action/innate/terrorspider/wrap/wrap_action - // Breathing - require some oxygen, and no toxins, but take little damage from this requirement not being met (they can hold their breath) + // Breathing - require some oxygen, and no toxins atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - unsuitable_atmos_damage = 1 - // Temperature - can freeze in space and cook in plasma, but it takes extreme temperatures to do this. - minbodytemp = 100 - maxbodytemp = 500 - heat_damage_per_tick = 3 + // Temperature + heat_damage_per_tick = 5 // Takes 250% normal damage from being in a hot environment ("kill it with fire!") // DEBUG OPTIONS & COMMANDS - var/spider_growinstantly = 0 // DEBUG OPTION, DO NOT ENABLE THIS ON LIVE. IT IS USED TO TEST NEST GROWTH/SETUP AI. - var/spider_debug = 0 + var/spider_growinstantly = FALSE // DEBUG OPTION, DO NOT ENABLE THIS ON LIVE. IT IS USED TO TEST NEST GROWTH/SETUP AI. + var/spider_debug = FALSE // -------------------------------------------------------------------------------- // --------------------- TERROR SPIDERS: SHARED ATTACK CODE ----------------------- // -------------------------------------------------------------------------------- +/mob/living/simple_animal/hostile/poison/terror_spider/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect) + // Forces terrors to use the 'bite' graphic when attacking something. Same as code/modules/mob/living/carbon/alien/larva/larva_defense.dm#L34 + if(!no_effect && !visual_effect_icon) + visual_effect_icon = ATTACK_EFFECT_BITE + ..() + /mob/living/simple_animal/hostile/poison/terror_spider/AttackingTarget() if(isterrorspider(target)) if(target in enemies) @@ -187,14 +192,13 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) if(F.welded) to_chat(src, "The fire door is welded shut.") else - visible_message("\The [src] pries open the firedoor!") + visible_message("[src] pries open the firedoor!") F.open() else to_chat(src, "Closing fire doors does not help.") else if(istype(target, /obj/machinery/door/airlock)) var/obj/machinery/door/airlock/A = target - if(A.density) - try_open_airlock(A) + try_open_airlock(A) else if(isliving(target) && (!client || a_intent == INTENT_HARM)) var/mob/living/G = target if(issilicon(G)) @@ -221,27 +225,23 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) /mob/living/simple_animal/hostile/poison/terror_spider/examine(mob/user) . = ..() - var/list/msgs = list() - if(stat == DEAD) - msgs += "It appears to be dead.\n" - else + if(stat != DEAD) if(key) - msgs += "Its eyes regard you with a curious intelligence." + . += "[p_they(TRUE)] regards [p_their()] surroundings with a curious intelligence." if(health > (maxHealth*0.95)) - msgs += "It is in excellent health." + . += "[p_they(TRUE)] is in excellent health." else if(health > (maxHealth*0.75)) - msgs += "It has a few injuries." + . += "[p_they(TRUE)] has a few injuries." else if(health > (maxHealth*0.55)) - msgs += "It has many injuries." + . += "[p_they(TRUE)] has many injuries." else if(health > (maxHealth*0.25)) - msgs += "It is barely clinging on to life!" + . += "[p_they(TRUE)] is barely clinging on to life!" if(degenerate) - msgs += "It appears to be dying." + . += "[p_they(TRUE)] appears to be dying." else if(health < maxHealth && regen_points > regen_points_per_kill) - msgs += "It appears to be regenerating quickly." + . += "[p_they(TRUE)] appears to be regenerating quickly." if(killcount >= 1) - msgs += "It has blood dribbling from its mouth." - . += msgs.Join("
") + . += "[p_they(TRUE)] has blood dribbling from [p_their()] mouth." /mob/living/simple_animal/hostile/poison/terror_spider/New() ..() @@ -254,9 +254,10 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) if(web_type) web_action = new() web_action.Grant(src) - wrap_action = new() - wrap_action.Grant(src) - + if(regen_points_per_tick < regen_points_per_hp) + // Only grant the Wrap action button to spiders who need to use it to regenerate their health + wrap_action = new() + wrap_action.Grant(src) name += " ([rand(1, 1000)])" real_name = name msg_terrorspiders("[src] has grown in [get_area(src)].") @@ -278,6 +279,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) addtimer(CALLBACK(src, .proc/announcetoghosts), 30) var/datum/atom_hud/U = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED] U.add_hud_to(src) + spider_creation_time = world.time /mob/living/simple_animal/hostile/poison/terror_spider/proc/announcetoghosts() if(spider_awaymission) @@ -285,8 +287,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) if(stat == DEAD) return if(ckey) - var/image/alert_overlay = image('icons/mob/terrorspider.dmi', icon_state) - notify_ghosts("[src] has appeared in [get_area(src)]. (already player-controlled)", source = src, alert_overlay = alert_overlay) + notify_ghosts("[src] (player controlled) has appeared in [get_area(src)].") else if(ai_playercontrol_allowtype) var/image/alert_overlay = image('icons/mob/terrorspider.dmi', icon_state) notify_ghosts("[src] has appeared in [get_area(src)].", enter_link = "(Click to control)", source = src, alert_overlay = alert_overlay, action = NOTIFY_ATTACK) @@ -342,7 +343,7 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) /mob/living/simple_animal/hostile/poison/terror_spider/ObjBump(obj/O) if(istype(O, /obj/machinery/door/airlock)) var/obj/machinery/door/airlock/L = O - if(L.density) + if(L.density) // must check density here, to avoid rapid bumping of an airlock that is in the process of opening, instantly forcing it closed return try_open_airlock(L) if(istype(O, /obj/machinery/door/firedoor)) var/obj/machinery/door/firedoor/F = O @@ -352,7 +353,8 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) . = ..() /mob/living/simple_animal/hostile/poison/terror_spider/proc/msg_terrorspiders(msgtext) - for(var/mob/living/simple_animal/hostile/poison/terror_spider/T in GLOB.ts_spiderlist) + for(var/thing in GLOB.ts_spiderlist) + var/mob/living/simple_animal/hostile/poison/terror_spider/T = thing if(T.stat != DEAD) to_chat(T, "TerrorSense: [msgtext]") @@ -365,21 +367,54 @@ GLOBAL_LIST_EMPTY(ts_spiderling_list) /mob/living/simple_animal/hostile/poison/terror_spider/proc/try_open_airlock(obj/machinery/door/airlock/D) if(D.operating) return - if(!D.density) - to_chat(src, "Closing doors does not help us.") - else if(D.welded) - to_chat(src, "The door is welded shut.") + if(D.welded) + to_chat(src, "The door is welded.") else if(D.locked) - to_chat(src, "The door is bolted shut.") + to_chat(src, "The door is bolted.") else if(D.allowed(src)) - D.open(1) - return 1 + if(D.density) + D.open(TRUE) + else + D.close(TRUE) + return TRUE else if(D.arePowerSystemsOn() && (spider_opens_doors != 2)) to_chat(src, "The door's motors resist your efforts to force it.") else if(!spider_opens_doors) to_chat(src, "Your type of spider is not strong enough to force open doors.") else - visible_message("[src] pries open the door!") + visible_message("[src] forces the door!") playsound(src.loc, "sparks", 100, 1) - D.open(1) - return 1 + if(D.density) + D.open(TRUE) + else + D.close(TRUE) + return TRUE + + +/mob/living/simple_animal/hostile/poison/terror_spider/Stat() + ..() + // Determines what shows in the "Status" tab for player-controlled spiders. Used to help players understand spider health regeneration mechanics. + // Uses because the status panel does NOT accept . + if(statpanel("Status") && ckey && stat == CONSCIOUS) + if(degenerate) + stat(null, "Hivemind Connection Severed! Dying...") // color=red + return + if(health != maxHealth) + var/hp_points_per_second = 0 + var/ltext = "FAST" + var/lcolor = "#fcba03" // orange + var/secs_per_tick = (SSmobs.wait / 10) // This uses SSmobs.wait because it must use the same frequency as mobs are processed + if(regen_points < (regen_points_per_hp * 2)) + // Slow regen speed: using regen_points as we get them. Figure out regen_points/sec, then convert that to hp/sec. + var/regen_points_per_second = (regen_points_per_tick / secs_per_tick) + hp_points_per_second = (regen_points_per_second / regen_points_per_hp) + ltext = "SLOW (HUNGRY!)" + lcolor = "#eb4034" // red + else + // Fast regen speed: healing at full 1 hp / tick rate. Just divide 1hp/tick by seconds/tick to get healing/sec. + hp_points_per_second = 1 / secs_per_tick + if(hp_points_per_second > 0) + var/pc_of_max_per_second = round(((hp_points_per_second / maxHealth) * 100), 0.1) + stat(null, "Regeneration: [ltext]: [num2text(pc_of_max_per_second)]% of health per second") + + diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index d4f8e7c4c3d..4bff2c100bf 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -319,10 +319,9 @@ return verb /mob/living/simple_animal/movement_delay() - . = ..() - . = speed - + if(forced_look) + . += 3 . += config.animal_delay /mob/living/simple_animal/Stat() diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 848606be3ec..4e4bd99e54d 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -478,6 +478,41 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \ return 0 //Unsupported slot //END HUMAN +/mob/proc/get_visible_mobs() + var/list/seen_mobs = list() + for(var/mob/M in view(src)) + seen_mobs += M + + return seen_mobs + +/** + * Returns an assoc list which contains the mobs in range and their "visible" name. + * Mobs out of view but in range will be listed as unknown. Else they will have their visible name +*/ +/mob/proc/get_telepathic_targets() + var/list/validtargets = new /list() + var/turf/T = get_turf(src) + var/list/mobs_in_view = get_visible_mobs() + + for(var/mob/living/M in range(14, T)) + if(M && M.mind) + if(M == src) + continue + var/mob_name + if(M in mobs_in_view) + mob_name = M.name + else + mob_name = "Unknown entity" + var/i = 0 + var/result_name + do + result_name = mob_name + if(i++) + result_name += " ([i])" // Avoid dupes + while(validtargets[result_name]) + validtargets[result_name] = M + return validtargets + // If you're looking for `reset_perspective`, that's a synonym for this proc. /mob/proc/reset_perspective(atom/A) if(client) diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index ff01fbe5cc9..6acfb92a515 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -288,7 +288,7 @@ S.message = Gibberish(S.message, p) -proc/muffledspeech(phrase) +/proc/muffledspeech(phrase) phrase = html_decode(phrase) var/leng=length(phrase) var/counter=length(phrase) @@ -675,4 +675,3 @@ GLOBAL_LIST_INIT(intents, list(INTENT_HELP,INTENT_DISARM,INTENT_GRAB,INTENT_HARM return FALSE //This is the only case someone should actually be completely blocked from antag rolling as well return TRUE -#define isterrorspider(A) (istype((A), /mob/living/simple_animal/hostile/poison/terror_spider)) diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index d151a98309f..212bb41720d 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -38,8 +38,7 @@ O.rename_self("AI",1) - spawn() - qdel(src) + INVOKE_ASYNC(GLOBAL_PROC, .proc/qdel, src) // To prevent the proc from returning null. return O @@ -102,8 +101,7 @@ O.Namepick() - spawn(0)//To prevent the proc from returning null. - qdel(src) + INVOKE_ASYNC(GLOBAL_PROC, .proc/qdel, src) // To prevent the proc from returning null. return O //human -> alien @@ -135,9 +133,7 @@ to_chat(new_xeno, "You are now an alien.") new_xeno.update_pipe_vision() - spawn(0)//To prevent the proc from returning null. - qdel(src) - return + qdel(src) /mob/living/carbon/human/proc/slimeize(reproduce as num) if(notransform) @@ -190,9 +186,7 @@ to_chat(new_corgi, "You are now a Corgi. Yap Yap!") new_corgi.update_pipe_vision() - spawn(0)//To prevent the proc from returning null. - qdel(src) - return + qdel(src) /mob/living/carbon/human/Animalize() @@ -221,9 +215,7 @@ to_chat(new_mob, "You suddenly feel more... animalistic.") new_mob.update_pipe_vision() - spawn() - qdel(src) - return + qdel(src) /mob/proc/Animalize() @@ -264,9 +256,7 @@ to_chat(pai, "You have become a pAI! Your name is [pai.name].") pai.update_pipe_vision() - spawn(0)//To prevent the proc from returning null. - qdel(src) - return + qdel(src) /mob/proc/safe_respawn(var/MP) if(!MP) diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm index a2357fd9ebe..6b327fbdbcd 100644 --- a/code/modules/modular_computers/computers/machinery/console_presets.dm +++ b/code/modules/modular_computers/computers/machinery/console_presets.dm @@ -62,8 +62,6 @@ /obj/machinery/modular_computer/console/preset/command/install_programs() var/obj/item/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD] hard_drive.store_file(new/datum/computer_file/program/chatclient()) - hard_drive.store_file(new/datum/computer_file/program/card_mod()) - hard_drive.store_file(new/datum/computer_file/program/comm()) // ===== CIVILIAN CONSOLE ===== /obj/machinery/modular_computer/console/preset/civilian diff --git a/code/modules/modular_computers/documentation.md b/code/modules/modular_computers/documentation.md index 9caae69aade..3172b349bce 100644 --- a/code/modules/modular_computers/documentation.md +++ b/code/modules/modular_computers/documentation.md @@ -36,7 +36,6 @@ for example, the command console one. ```DM /obj/machinery/modular_computer/console/preset/command/install_programs() cpu.hard_drive.store_file(new/datum/computer_file/program/chatclient()) - cpu.hard_drive.store_file(new/datum/computer_file/program/card_mod()) ``` Basically, you want to do cpu.hard_drive.store_file(new/*program path here*()) and put it in the subtype's install_programs(). Probably pretty self explanatory, but just in case. diff --git a/code/modules/modular_computers/file_system/programs/command/card.dm b/code/modules/modular_computers/file_system/programs/command/card.dm deleted file mode 100644 index cae4b5ed2e2..00000000000 --- a/code/modules/modular_computers/file_system/programs/command/card.dm +++ /dev/null @@ -1,493 +0,0 @@ -/datum/computer_file/program/card_mod - filename = "cardmod" - filedesc = "ID card modification program" - program_icon_state = "id" - extended_desc = "Program for programming employee ID cards to access parts of the station." - transfer_access = ACCESS_CHANGE_IDS - requires_ntnet = 0 - size = 8 - var/is_centcom = 0 - var/mode = 0 - var/printing = 0 - - //Cooldown for closing positions in seconds - //if set to -1: No cooldown... probably a bad idea - //if set to 0: Not able to close "original" positions. You can only close positions that you have opened before - var/change_position_cooldown = 60 - //Jobs you cannot open new positions for - var/list/blacklisted = list( - /datum/job/ai, - /datum/job/cyborg, - /datum/job/captain, - /datum/job/hop, - /datum/job/hos, - /datum/job/chief_engineer, - /datum/job/rd, - /datum/job/cmo, - /datum/job/judge, - /datum/job/blueshield, - /datum/job/nanotrasenrep, - /datum/job/pilot, - /datum/job/brigdoc, - /datum/job/mechanic, - /datum/job/barber, - /datum/job/chaplain, - /datum/job/ntnavyofficer, - /datum/job/ntspecops, - /datum/job/civilian, - /datum/job/syndicateofficer, - /datum/job/explorer // blacklisted so that HOPs don't try prioritizing it, then wonder why that doesn't work - ) - - //The scaling factor of max total positions in relation to the total amount of people on board the station in % - var/max_relative_positions = 30 //30%: Seems reasonable, limit of 6 @ 20 players - - //This is used to keep track of opened positions for jobs to allow instant closing - //Assoc array: "JobName" = (int) - var/list/opened_positions = list() - -/datum/computer_file/program/card_mod/proc/is_authenticated(var/mob/user) - if(user.can_admin_interact()) - return 1 - if(computer) - var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD] - if(card_slot) - var/obj/item/card/id/auth_card = card_slot.stored_card2 - if(auth_card) - return check_access(auth_card) - return 0 - -/datum/computer_file/program/card_mod/proc/check_access(obj/item/I) - if(ACCESS_CHANGE_IDS in I.GetAccess()) - return 1 - return 0 - -/datum/computer_file/program/card_mod/proc/get_target_rank() - if(computer) - var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD] - if(card_slot) - var/obj/item/card/id/id_card = card_slot.stored_card - if(id_card && id_card.assignment) - return id_card.assignment - return "Unassigned" - -/datum/computer_file/program/card_mod/proc/format_job_slots() - var/list/formatted = list() - for(var/datum/job/job in SSjobs.occupations) - if(job_blacklisted(job)) - continue - formatted.Add(list(list( - "title" = job.title, - "current_positions" = job.current_positions, - "total_positions" = job.total_positions, - "can_open" = can_open_job(job), - "can_close" = can_close_job(job), - "can_prioritize" = can_prioritize_job(job) - ))) - - return formatted - -/datum/computer_file/program/card_mod/proc/format_card_skins(list/card_skins) - var/list/formatted = list() - for(var/skin in card_skins) - formatted.Add(list(list( - "display_name" = get_skin_desc(skin), - "skin" = skin))) - - return formatted - - -/datum/computer_file/program/card_mod/proc/job_blacklisted(datum/job/job) - return (job.type in blacklisted) - - -//Logic check for if you can open the job -/datum/computer_file/program/card_mod/proc/can_open_job(datum/job/job) - if(job) - if(!job_blacklisted(job)) - if((job.total_positions <= GLOB.player_list.len * (max_relative_positions / 100))) - var/delta = (world.time / 10) - GLOB.time_last_changed_position - if((change_position_cooldown < delta) || (opened_positions[job.title] < 0)) - return 1 - return -2 - return -1 - return 0 - -//Logic check for if you can close the job -/datum/computer_file/program/card_mod/proc/can_close_job(datum/job/job) - if(job) - if(!job_blacklisted(job)) - if(job.total_positions > job.current_positions) - var/delta = (world.time / 10) - GLOB.time_last_changed_position - if((change_position_cooldown < delta) || (opened_positions[job.title] > 0)) - return 1 - return -2 - return -1 - return 0 - -/datum/computer_file/program/card_mod/proc/can_prioritize_job(datum/job/job) - if(job) - if(!job_blacklisted(job)) - if(job in SSjobs.prioritized_jobs) - return 2 - else - if(SSjobs.prioritized_jobs.len >= 3) - return 0 - if(job.total_positions <= job.current_positions) - return 0 - return 1 - return -1 - -/datum/computer_file/program/card_mod/proc/format_jobs(list/jobs, targetrank, list/jobformats) - var/obj/item/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD] - if(!card_slot || !card_slot.stored_card) - return null - var/list/formatted = list() - for(var/job in jobs) - formatted.Add(list(list( - "display_name" = replacetext(job, " ", " "), - "target_rank" = targetrank, - "job" = job, - "jlinkformat" = jobformats[job] ? jobformats[job] : null))) - return formatted - - -/datum/computer_file/program/card_mod/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers) - assets.send(user) - ui = new(user, src, ui_key, "card_prog.tmpl", "ID card modification program", 775, 700) - ui.set_layout_key("program") - ui.open() - -/datum/computer_file/program/card_mod/Topic(href, href_list) - if(..()) - return 1 - - var/obj/item/computer_hardware/card_slot/card_slot - var/obj/item/computer_hardware/printer/printer - if(computer) - card_slot = computer.all_components[MC_CARD] - printer = computer.all_components[MC_PRINT] - if(!card_slot) - return - - var/mob/user = usr - - var/obj/item/card/id/modify = card_slot.stored_card - var/obj/item/card/id/scan = card_slot.stored_card2 - - switch(href_list["action"]) - if("PRG_modify") - if(modify) - GLOB.data_core.manifest_modify(modify.registered_name, modify.assignment) - modify.name = "[modify.registered_name]'s ID Card ([modify.assignment])" - card_slot.try_eject(1, user) - else - var/obj/item/I = usr.get_active_hand() - if(istype(I, /obj/item/card/id)) - if(!usr.drop_item()) - return - I.forceMove(computer) - card_slot.stored_card = I - - if("PRG_scan") - if(scan) - card_slot.try_eject(2, user) - else - var/obj/item/I = usr.get_active_hand() - if(istype(I, /obj/item/card/id)) - if(!usr.drop_item()) - return - I.forceMove(computer) - card_slot.stored_card2 = I - - if("PRG_access") - if(href_list["allowed"]) - if(is_authenticated(usr)) - var/access_type = text2num(href_list["access_target"]) - var/access_allowed = text2num(href_list["allowed"]) - if(access_type in (is_centcom ? get_all_centcom_access() : get_all_accesses())) - modify.access -= access_type - if(!access_allowed) - modify.access += access_type - - if("PRG_skin") - var/skin = href_list["skin_target"] - if(is_authenticated(usr) && modify && ((skin in get_station_card_skins()) || ((skin in get_centcom_card_skins()) && is_centcom))) - modify.icon_state = href_list["skin_target"] - - if("PRG_assign") - if(is_authenticated(usr) && modify) - var/t1 = href_list["assign_target"] - if(t1 == "Custom") - var/temp_t = sanitize(reject_bad_name(copytext(input("Enter a custom job assignment.", "Assignment"), 1, MAX_MESSAGE_LEN), TRUE)) - //let custom jobs function as an impromptu alt title, mainly for sechuds - if(temp_t && modify) - SSjobs.log_job_transfer(modify.registered_name, modify.getRankAndAssignment(), temp_t, scan.registered_name) - modify.assignment = temp_t - log_game("[key_name(usr)] has given \"[modify.registered_name]\" the custom job title \"[temp_t]\".") - else - var/list/access = list() - if(is_centcom && islist(get_centcom_access(t1))) - access = get_centcom_access(t1) - else - var/datum/job/jobdatum - for(var/jobtype in typesof(/datum/job)) - var/datum/job/J = new jobtype - if(ckey(J.title) == ckey(t1)) - jobdatum = J - break - if(!jobdatum) - to_chat(usr, "No log exists for this job: [t1]") - return - - access = jobdatum.get_access() - - var/jobnamedata = modify.getRankAndAssignment() - log_game("[key_name(usr)] has reassigned \"[modify.registered_name]\" from \"[jobnamedata]\" to \"[t1]\".") - if(t1 == "Civilian") - message_admins("[key_name_admin(usr)] has reassigned \"[modify.registered_name]\" from \"[jobnamedata]\" to \"[t1]\".") - - SSjobs.log_job_transfer(modify.registered_name, jobnamedata, t1, scan.registered_name) - if(modify.owner_uid) - SSjobs.slot_job_transfer(modify.rank, t1) - - var/mob/living/carbon/human/H = modify.getPlayer() - if(istype(H)) - if(jobban_isbanned(H, t1)) - message_admins("[ADMIN_FULLMONTY(H)] has been assigned the job [t1], in possible violation of their job ban.") - if(H.mind) - H.mind.playtime_role = t1 - - modify.access = access - modify.assignment = t1 - modify.rank = t1 - - if("PRG_reg") - if(is_authenticated(usr)) - var/temp_name = reject_bad_name(href_list["reg"], TRUE) - if(temp_name) - modify.registered_name = temp_name - else - computer.visible_message("[src] buzzes rudely.") - - if("PRG_account") - if(is_authenticated(usr)) - var/account_num = text2num(href_list["account"]) - modify.associated_account_number = account_num - - if("PRG_mode") - mode = text2num(href_list["mode_target"]) - - if("PRG_wipe_my_logs") - if(is_authenticated(usr) && is_centcom) - var/delcount = SSjobs.delete_log_records(scan.registered_name, FALSE) - if(delcount) - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) - - if("PRG_wipe_all_logs") - if(is_authenticated(usr)) - var/delcount = SSjobs.delete_log_records(scan.registered_name, TRUE) - if(delcount) - message_admins("[key_name_admin(usr)] has wiped all ID computer logs.") - usr.create_log(MISC_LOG, "wiped all ID computer logs.") - playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) - - if("PRG_print") - if(!printing && computer) - printing = 1 - playsound(computer.loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1) - spawn(50) - printing = 0 - SSnanoui.update_uis(src) - var/title - var/content - if(mode == 2) - title = "crew manifest ([station_time_timestamp()])" - content = "

Crew Manifest


[GLOB.data_core ? GLOB.data_core.get_manifest(0) : ""]" - else if(modify && !mode) - title = "access report" - content = {"

Access Report

- Prepared By: [scan && scan.registered_name ? scan.registered_name : "Unknown"]
- For: [modify.registered_name ? modify.registered_name : "Unregistered"]
-
- Assignment: [modify.assignment]
- Account Number: #[modify.associated_account_number]
- Blood Type: [modify.blood_type]

- Access:
"} - - var/first = 1 - for(var/A in modify.access) - content += "[first ? "" : ", "][get_access_desc(A)]" - first = 0 - content += "
" - - if(content) - if(!printer.print_text(content, title)) - to_chat(user, "Hardware error: Printer was unable to print the file. It may be out of paper.") - return 1 - else - computer.visible_message("\The [computer] prints out paper.") - - if("PRG_terminate") - if(is_authenticated(usr)) - var/jobnamedata = modify.getRankAndAssignment() - var/reason = sanitize(copytext(input("Enter legal reason for termination. Enter nothing to cancel.", "Employment Termination"), 1, MAX_MESSAGE_LEN)) - if(!reason || !is_authenticated(usr) || !modify) - return - log_game("[key_name(usr)] has terminated the employment of \"[modify.registered_name]\" the \"[jobnamedata]\" for: \"[reason]\".") - message_admins("[key_name_admin(usr)] has terminated the employment of \"[modify.registered_name]\" the \"[jobnamedata]\" for: \"[reason]\".") - usr.create_log(MISC_LOG, "terminated the employment of \"[modify.registered_name]\" the \"[jobnamedata]\"") - SSjobs.log_job_transfer(modify.registered_name, jobnamedata, "Terminated", scan.registered_name) - SSjobs.notify_dept_head(modify.rank, "[scan.registered_name] has terminated the employment of \"[modify.registered_name]\" the \"[jobnamedata]\" for \"[reason]\".") - modify.assignment = "Terminated" - modify.access = list() - - if("PRG_make_job_available") - // MAKE ANOTHER JOB POSITION AVAILABLE FOR LATE JOINERS - if(is_authenticated(usr)) - var/edit_job_target = href_list["job"] - var/datum/job/j = SSjobs.GetJob(edit_job_target) - if(!j) - return 1 - if(can_open_job(j) != 1) - return 1 - if(opened_positions[edit_job_target] >= 0) - GLOB.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]\".") - - if("PRG_make_job_unavailable") - // MAKE JOB POSITION UNAVAILABLE FOR LATE JOINERS - if(is_authenticated(usr)) - var/edit_job_target = href_list["job"] - var/datum/job/j = SSjobs.GetJob(edit_job_target) - if(!j) - return 1 - if(can_close_job(j) != 1) - return 1 - //Allow instant closing without cooldown if a position has been opened before - if(opened_positions[edit_job_target] <= 0) - GLOB.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]\".") - - - if("PRG_prioritize_job") - // TOGGLE WHETHER JOB APPEARS AS PRIORITIZED IN THE LOBBY - if(is_authenticated(usr)) - var/priority_target = href_list["job"] - var/datum/job/j = SSjobs.GetJob(priority_target) - if(!j) - return 0 - // Unlike the proper ID computer, this does not check job_in_department - var/priority = TRUE - if(j in SSjobs.prioritized_jobs) - SSjobs.prioritized_jobs -= j - priority = FALSE - else if(SSjobs.prioritized_jobs.len < 3) - SSjobs.prioritized_jobs += j - else - return 0 - log_game("[key_name(usr)] [priority ? "prioritized" : "unprioritized"] the job \"[j.title]\".") - playsound(computer.loc, 'sound/machines/terminal_prompt_confirm.ogg', 50, 0) - - if(modify) - modify.name = text("[modify.registered_name]'s ID Card ([modify.assignment])") - - SSnanoui.update_uis(src) - return 1 - -/datum/computer_file/program/card_mod/ui_data(mob/user) - var/list/data = get_header_data() - - var/obj/item/card/id/modify = null - var/obj/item/card/id/scan = null - - var/obj/item/computer_hardware/card_slot/card_slot - var/obj/item/computer_hardware/printer/printer - if(computer) - card_slot = computer.all_components[MC_CARD] - printer = computer.all_components[MC_PRINT] - if(card_slot) - modify = card_slot.stored_card - scan = card_slot.stored_card2 - - data["src"] = UID() - data["station_name"] = station_name() - data["mode"] = mode - data["printing"] = printing - data["printer"] = printer ? TRUE : FALSE - data["manifest"] = GLOB.data_core ? GLOB.data_core.get_manifest(0) : null - data["target_name"] = modify ? modify.name : "-----" - data["target_owner"] = modify && modify.registered_name ? modify.registered_name : "-----" - data["target_rank"] = get_target_rank() - data["scan_name"] = scan ? scan.name : "-----" - data["scan_owner"] = scan && scan.registered_name ? scan.registered_name : null - data["authenticated"] = is_authenticated(user) - data["has_modify"] = !!modify - data["account_number"] = modify ? modify.associated_account_number : null - data["centcom_access"] = is_centcom - data["all_centcom_access"] = null - data["regions"] = null - - var/list/job_formats = SSjobs.format_jobs_for_id_computer(modify) - - data["top_jobs"] = format_jobs(list("Captain", "Custom"), data["target_rank"], job_formats) - data["engineering_jobs"] = format_jobs(GLOB.engineering_positions, data["target_rank"], job_formats) - data["medical_jobs"] = format_jobs(GLOB.medical_positions, data["target_rank"], job_formats) - data["science_jobs"] = format_jobs(GLOB.science_positions, data["target_rank"], job_formats) - data["security_jobs"] = format_jobs(GLOB.security_positions, data["target_rank"], job_formats) - data["support_jobs"] = format_jobs(GLOB.support_positions, data["target_rank"], job_formats) - data["civilian_jobs"] = format_jobs(GLOB.civilian_positions, data["target_rank"], job_formats) - data["special_jobs"] = format_jobs(GLOB.whitelisted_positions, data["target_rank"], job_formats) - data["centcom_jobs"] = format_jobs(get_all_centcom_jobs(), data["target_rank"], job_formats) - data["card_skins"] = format_card_skins(get_station_card_skins()) - - data["job_slots"] = format_job_slots() - - var/time_to_wait = round(change_position_cooldown - ((world.time / 10) - GLOB.time_last_changed_position), 1) - var/mins = round(time_to_wait / 60) - var/seconds = time_to_wait - (60*mins) - data["cooldown_mins"] = mins - data["cooldown_secs"] = (seconds < 10) ? "0[seconds]" : seconds - - if(mode == 3 && is_authenticated(user)) - data["id_change_html"] = SSjobs.fetch_transfer_record_html(is_centcom) - - if(modify) - data["current_skin"] = modify.icon_state - - if(modify && is_centcom) - var/list/all_centcom_access = list() - for(var/access in get_all_centcom_access()) - all_centcom_access.Add(list(list( - "desc" = replacetext(get_centcom_access_desc(access), " ", " "), - "ref" = access, - "allowed" = (access in modify.access) ? 1 : 0))) - - data["all_centcom_access"] = all_centcom_access - data["all_centcom_skins"] = format_card_skins(get_centcom_card_skins()) - - else if(modify) - var/list/regions = list() - for(var/i = 1; i <= 7; i++) - var/list/accesses = list() - for(var/access in get_region_accesses(i)) - if(get_access_desc(access)) - accesses.Add(list(list( - "desc" = replacetext(get_access_desc(access), " ", " "), - "ref" = access, - "allowed" = (access in modify.access) ? 1 : 0))) - - regions.Add(list(list( - "name" = get_region_accesses_name(i), - "accesses" = accesses))) - - data["regions"] = regions - - return data diff --git a/code/modules/modular_computers/file_system/programs/command/comms.dm b/code/modules/modular_computers/file_system/programs/command/comms.dm deleted file mode 100644 index c23f0c9e3c7..00000000000 --- a/code/modules/modular_computers/file_system/programs/command/comms.dm +++ /dev/null @@ -1,385 +0,0 @@ -/datum/computer_file/program/comm - filename = "comm" - filedesc = "Command and communications" - program_icon_state = "comm" - extended_desc = "Used to command and control the station. Can relay long-range communications. This program can not be run on tablet computers." - required_access = ACCESS_HEADS - requires_ntnet = 1 - size = 12 - usage_flags = PROGRAM_CONSOLE | PROGRAM_LAPTOP - network_destination = "station long-range communication array" - - var/authenticated = COMM_AUTHENTICATION_NONE - var/list/messagetitle = list() - var/list/messagetext = list() - var/currmsg = 0 - var/aicurrmsg = 0 - var/menu_state = COMM_SCREEN_MAIN - var/ai_menu_state = COMM_SCREEN_MAIN - var/message_cooldown = 0 - var/centcomm_message_cooldown = 0 - var/tmp_alertlevel = 0 - - var/stat_msg1 - var/stat_msg2 - var/display_type="blank" - - var/datum/announcement/priority/crew_announcement = new - -/datum/computer_file/program/comm/New() - GLOB.shuttle_caller_list += src - ..() - crew_announcement.newscast = 0 - -/datum/computer_file/program/comm/Destroy() - GLOB.shuttle_caller_list -= src - SSshuttle.autoEvac() - return ..() - -/datum/computer_file/program/comm/proc/is_authenticated(mob/user, loud = 1) - if(authenticated == COMM_AUTHENTICATION_MAX) - return COMM_AUTHENTICATION_MAX - else if(user.can_admin_interact()) - return COMM_AUTHENTICATION_MAX - else if(authenticated) - return COMM_AUTHENTICATION_MIN - else - if(loud) - to_chat(user, "Access denied.") - return COMM_AUTHENTICATION_NONE - -/datum/computer_file/program/comm/proc/change_security_level(mob/user, new_level) - tmp_alertlevel = new_level - var/old_level = GLOB.security_level - if(!tmp_alertlevel) - tmp_alertlevel = SEC_LEVEL_GREEN - if(tmp_alertlevel < SEC_LEVEL_GREEN) - tmp_alertlevel = SEC_LEVEL_GREEN - if(tmp_alertlevel > SEC_LEVEL_BLUE) - tmp_alertlevel = SEC_LEVEL_BLUE //Cannot engage delta with this - set_security_level(tmp_alertlevel) - if(GLOB.security_level != old_level) - log_game("[key_name(user)] has changed the security level to [get_security_level()].") - message_admins("[key_name_admin(user)] has changed the security level to [get_security_level()].") - switch(GLOB.security_level) - if(SEC_LEVEL_GREEN) - feedback_inc("alert_comms_green", 1) - if(SEC_LEVEL_BLUE) - feedback_inc("alert_comms_blue", 1) - tmp_alertlevel = 0 - -/datum/computer_file/program/comm/proc/setCurrentMessage(mob/user, value) - if(isAI(user) || isrobot(user)) - aicurrmsg = value - else - currmsg = value - -/datum/computer_file/program/comm/proc/getCurrentMessage(mob/user) - if(isAI(user) || isrobot(user)) - return aicurrmsg - else - return currmsg - -/datum/computer_file/program/comm/proc/setMenuState(mob/user, value) - if(isAI(user) || isrobot(user)) - ai_menu_state=value - else - menu_state=value - -/datum/computer_file/program/comm/proc/getMenuState(mob/user) - if(isAI(user) || isrobot(user)) - return ai_menu_state - else - return menu_state - -/datum/computer_file/program/comm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui) - if(!ui) - var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers) - assets.send(user) - ui = new(user, src, ui_key, "comm_program.tmpl", "Command and communications program", 575, 500) - ui.set_layout_key("program") - ui.open() - -/datum/computer_file/program/comm/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/list/data = get_header_data() - data["is_ai"] = isAI(user) || isrobot(user) - data["menu_state"] = data["is_ai"] ? ai_menu_state : menu_state - data["emagged"] = computer ? computer.emagged : null - data["authenticated"] = is_authenticated(user, 0) - data["screen"] = getMenuState(usr) - - data["stat_display"] = list( - "type" = display_type, - "line_1" = (stat_msg1 ? stat_msg1 : "-----"), - "line_2" = (stat_msg2 ? stat_msg2 : "-----"), - - "presets" = list( - list("name" = "blank", "label" = "Clear", "desc" = "Blank slate"), - list("name" = "shuttle", "label" = "Shuttle ETA", "desc" = "Display how much time is left."), - list("name" = "message", "label" = "Message", "desc" = "A custom message.") - ), - - "alerts"=list( - list("alert" = "default", "label" = "Nanotrasen", "desc" = "Oh god."), - list("alert" = "redalert", "label" = "Red Alert", "desc" = "Nothing to do with communists."), - list("alert" = "lockdown", "label" = "Lockdown", "desc" = "Let everyone know they're on lockdown."), - list("alert" = "biohazard", "label" = "Biohazard", "desc" = "Great for virus outbreaks and parties."), - ) - ) - - data["security_level"] = GLOB.security_level - data["str_security_level"] = capitalize(get_security_level()) - data["levels"] = list( - list("id" = SEC_LEVEL_GREEN, "name" = "Green"), - list("id" = SEC_LEVEL_BLUE, "name" = "Blue"), - ) - - var/list/msg_data = list() - for(var/i = 1; i <= messagetext.len; i++) - msg_data.Add(list(list("title" = messagetitle[i], "body" = messagetext[i], "id" = i))) - - data["messages"] = msg_data - if((data["is_ai"] && aicurrmsg) || (!data["is_ai"] && currmsg)) - data["current_message"] = data["is_ai"] ? messagetext[aicurrmsg] : messagetext[currmsg] - data["current_message_title"] = data["is_ai"] ? messagetitle[aicurrmsg] : messagetitle[currmsg] - - data["lastCallLoc"] = SSshuttle.emergencyLastCallLoc ? format_text(SSshuttle.emergencyLastCallLoc.name) : null - - var/shuttle[0] - switch(SSshuttle.emergency.mode) - if(SHUTTLE_IDLE, SHUTTLE_RECALL) - shuttle["callStatus"] = 2 //#define - else - shuttle["callStatus"] = 1 - if(SSshuttle.emergency.mode == SHUTTLE_CALL) - var/timeleft = SSshuttle.emergency.timeLeft() - shuttle["eta"] = "[timeleft / 60 % 60]:[add_zero(num2text(timeleft % 60), 2)]" - - data["shuttle"] = shuttle - - return data - -/datum/computer_file/program/comm/Topic(href, href_list) - if(..()) - return 1 - - var/turf/T = get_turf(computer) - if(!is_secure_level(T.z)) - to_chat(usr, "Unable to establish a connection: You're too far away from the station!") - return 1 - - if(href_list["PRG_login"]) - if(!ishuman(usr)) - to_chat(usr, "Access denied.") - return - - var/list/access = usr.get_access() - if(ACCESS_HEADS in access) - authenticated = COMM_AUTHENTICATION_MIN - - if(ACCESS_CAPTAIN in access) - authenticated = COMM_AUTHENTICATION_MAX - var/mob/living/carbon/human/H = usr - var/obj/item/card/id = H.get_idcard(TRUE) - if(istype(id)) - crew_announcement.announcer = GetNameAndAssignmentFromId(id) - - SSnanoui.update_uis(src) - return 1 - - if(href_list["PRG_logout"]) - authenticated = COMM_AUTHENTICATION_NONE - crew_announcement.announcer = "" - setMenuState(usr, COMM_SCREEN_MAIN) - SSnanoui.update_uis(src) - return 1 - - if(is_authenticated(usr)) - switch(href_list["PRG_operation"]) - if("main") - setMenuState(usr, COMM_SCREEN_MAIN) - - if("changeseclevel") - setMenuState(usr,COMM_SCREEN_SECLEVEL) - - if("newalertlevel") - if(isAI(usr) || isrobot(usr)) - to_chat(usr, "Firewalls prevent you from changing the alert level.") - return 1 - else if(usr.can_admin_interact()) - change_security_level(usr, text2num(href_list["level"])) - return 1 - else if(!ishuman(usr)) - to_chat(usr, "Security measures prevent you from changing the alert level.") - return 1 - - var/mob/living/carbon/human/L = usr - var/obj/item/card = L.get_active_hand() - var/obj/item/card/id/I = (card && card.GetID()) || L.wear_id || L.wear_pda - if(istype(I, /obj/item/pda)) - var/obj/item/pda/pda = I - I = pda.id - if(I && istype(I)) - if(ACCESS_CAPTAIN in I.access) - change_security_level(usr, text2num(href_list["level"])) - else - to_chat(usr, "You are not authorized to do this.") - setMenuState(usr, COMM_SCREEN_MAIN) - else - to_chat(usr, "You need to swipe your ID.") - - if("announce") - if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX) - if(message_cooldown) - to_chat(usr, "Please allow at least one minute to pass between announcements.") - SSnanoui.update_uis(src) - return 1 - var/input = input(usr, "Please write a message to announce to the station crew.", "Priority Announcement") - if(!input || message_cooldown || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)) - SSnanoui.update_uis(src) - return 1 - crew_announcement.Announce(input) - message_cooldown = 1 - spawn(600)//One minute cooldown - message_cooldown = 0 - - if("callshuttle") - var/input = clean_input("Please enter the reason for calling the shuttle.", "Shuttle Call Reason.","") - if(!input || ..() || !is_authenticated(usr)) - SSnanoui.update_uis(src) - return 1 - - call_shuttle_proc(usr, input) - if(SSshuttle.emergency.timer) - post_status("shuttle") - setMenuState(usr, COMM_SCREEN_MAIN) - - if("cancelshuttle") - if(isAI(usr) || isrobot(usr)) - to_chat(usr, "Firewalls prevent you from recalling the shuttle.") - SSnanoui.update_uis(src) - return 1 - var/response = alert("Are you sure you wish to recall the shuttle?", "Confirm", "Yes", "No") - if(response == "Yes") - cancel_call_proc(usr) - if(SSshuttle.emergency.timer) - post_status("shuttle") - setMenuState(usr, COMM_SCREEN_MAIN) - - if("messagelist") - currmsg = 0 - if(href_list["msgid"]) - setCurrentMessage(usr, text2num(href_list["msgid"])) - setMenuState(usr,COMM_SCREEN_MESSAGES) - - if("delmessage") - if(href_list["msgid"]) - currmsg = text2num(href_list["msgid"]) - var/response = alert("Are you sure you wish to delete this message?", "Confirm", "Yes", "No") - if(response == "Yes") - if(currmsg) - var/id = getCurrentMessage() - var/title = messagetitle[id] - var/text = messagetext[id] - messagetitle.Remove(title) - messagetext.Remove(text) - if(currmsg == id) - currmsg = 0 - if(aicurrmsg == id) - aicurrmsg = 0 - setMenuState(usr,COMM_SCREEN_MESSAGES) - - if("status") - setMenuState(usr,COMM_SCREEN_STAT) - - // Status display stuff - if("setstat") - display_type=href_list["statdisp"] - switch(display_type) - if("message") - post_status("message", stat_msg1, stat_msg2, usr) - if("alert") - post_status("alert", href_list["alert"], user = usr) - else - post_status(href_list["statdisp"], user = usr) - setMenuState(usr, COMM_SCREEN_STAT) - - if("setmsg1") - stat_msg1 = clean_input("Line 1", "Enter Message Text", stat_msg1) - setMenuState(usr, COMM_SCREEN_STAT) - - if("setmsg2") - stat_msg2 = clean_input("Line 2", "Enter Message Text", stat_msg2) - setMenuState(usr, COMM_SCREEN_STAT) - - if("nukerequest") - if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX) - if(centcomm_message_cooldown) - to_chat(usr, "Arrays recycling. Please stand by.") - SSnanoui.update_uis(src) - return 1 - var/input = stripped_input(usr, "Please enter the reason for requesting the nuclear self-destruct codes. Misuse of the nuclear request system will not be tolerated under any circumstances. Transmission does not guarantee a response.", "Self Destruct Code Request.","") - if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)) - SSnanoui.update_uis(src) - return 1 - Nuke_request(input, usr) - to_chat(usr, "Request sent.") - log_game("[key_name(usr)] has requested the nuclear codes from Centcomm") - GLOB.priority_announcement.Announce("The codes for the on-station nuclear self-destruct have been requested by [usr]. Confirmation or denial of this request will be sent shortly.", "Nuclear Self Destruct Codes Requested",'sound/AI/commandreport.ogg') - centcomm_message_cooldown = 1 - spawn(6000)//10 minute cooldown - centcomm_message_cooldown = 0 - setMenuState(usr,COMM_SCREEN_MAIN) - - if("MessageCentcomm") - if(is_authenticated(usr) == COMM_AUTHENTICATION_MAX) - if(centcomm_message_cooldown) - to_chat(usr, "Arrays recycling. Please stand by.") - SSnanoui.update_uis(src) - return 1 - var/input = stripped_input(usr, "Please choose a message to transmit to Centcomm via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "To abort, send an empty message.", "") - if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)) - SSnanoui.update_uis(src) - return 1 - Centcomm_announce(input, usr) - to_chat(usr, "Message transmitted.") - log_game("[key_name(usr)] has made a Centcomm announcement: [input]") - centcomm_message_cooldown = 1 - spawn(6000)//10 minute cooldown - centcomm_message_cooldown = 0 - setMenuState(usr,COMM_SCREEN_MAIN) - - // OMG SYNDICATE ...LETTERHEAD - if("MessageSyndicate") - if((is_authenticated(usr) == COMM_AUTHENTICATION_MAX) && (computer && computer.emagged)) - if(centcomm_message_cooldown) - to_chat(usr, "Arrays recycling. Please stand by.") - SSnanoui.update_uis(src) - return 1 - var/input = stripped_input(usr, "Please choose a message to transmit to \[ABNORMAL ROUTING CORDINATES\] via quantum entanglement. Please be aware that this process is very expensive, and abuse will lead to... termination. Transmission does not guarantee a response.", "To abort, send an empty message.", "") - if(!input || ..() || !(is_authenticated(usr) == COMM_AUTHENTICATION_MAX)) - SSnanoui.update_uis(src) - return 1 - Syndicate_announce(input, usr) - to_chat(usr, "Message transmitted.") - log_game("[key_name(usr)] has made a Syndicate announcement: [input]") - centcomm_message_cooldown = 1 - spawn(6000)//10 minute cooldown - centcomm_message_cooldown = 0 - setMenuState(usr,COMM_SCREEN_MAIN) - - if("RestartNanoMob") - if(SSmob_hunt) - if(SSmob_hunt.manual_reboot()) - var/loading_msg = pick("Respawning spawns", "Reticulating splines", "Flipping hat", - "Capturing all of them", "Fixing minor text issues", "Being the very best", - "Nerfing this", "Not communicating with playerbase", "Coding a ripoff in a 2D spaceman game") - to_chat(usr, "Restarting Nano-Mob Hunter GO! game server. [loading_msg]...") - else - to_chat(usr, "Nano-Mob Hunter GO! game server reboot failed due to recent restart. Please wait before re-attempting.") - else - to_chat(usr, "Nano-Mob Hunter GO! game server is offline for extended maintenance. Contact your Central Command administrators for more info if desired.") - - SSnanoui.update_uis(src) - return 1 diff --git a/code/modules/modular_computers/laptop_vendor.dm b/code/modules/modular_computers/laptop_vendor.dm index aa69b85b1df..a6aee63a3af 100644 --- a/code/modules/modular_computers/laptop_vendor.dm +++ b/code/modules/modular_computers/laptop_vendor.dm @@ -237,7 +237,7 @@ data["totalprice"] = total_price return data -obj/machinery/lapvend/attackby(obj/item/I, mob/user) +/obj/machinery/lapvend/attackby(obj/item/I, mob/user) var/obj/item/card/id/C if(istype(I, /obj/item/card/id)) C = I diff --git a/code/modules/nano/modules/ert_manager.dm b/code/modules/nano/modules/ert_manager.dm deleted file mode 100644 index 98a3e19d052..00000000000 --- a/code/modules/nano/modules/ert_manager.dm +++ /dev/null @@ -1,105 +0,0 @@ -/datum/nano_module/ert_manager - name = "ERT Manager" - var/ert_type = "Code Red" - var/commander_slots = 1 - var/security_slots = 3 - var/medical_slots = 3 - var/engineering_slots = 3 - var/janitor_slots = 0 - var/paranormal_slots = 0 - var/cyborg_slots = 0 - var/autoclose = 0 - - -/datum/nano_module/ert_manager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.admin_state) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) - if(ui && autoclose) - ui.close() - return 0 - if(!ui) - ui = new(user, src, ui_key, "ert_config.tmpl", "ERT Panel", 600, 600, state = state) - ui.open() - ui.set_auto_update(1) - -/datum/nano_module/ert_manager/Topic(href, href_list) - if(..()) - return 1 - - if(href_list["set_code"]) - ert_type = href_list["set_code"] - - if(href_list["set_com"]) - commander_slots = text2num(href_list["set_com"]) - - if(href_list["set_sec"]) - security_slots = text2num(href_list["set_sec"]) - - if(href_list["set_med"]) - medical_slots = text2num(href_list["set_med"]) - - if(href_list["set_eng"]) - engineering_slots = text2num(href_list["set_eng"]) - - if(href_list["set_jan"]) - janitor_slots = text2num(href_list["set_jan"]) - - if(href_list["set_par"]) - paranormal_slots = text2num(href_list["set_par"]) - - if(href_list["set_cyb"]) - cyborg_slots = text2num(href_list["set_cyb"]) - - if(href_list["dispatch_ert"]) - GLOB.ert_request_answered = TRUE - var/slots_list = list() - if(commander_slots > 0) - slots_list += "commander: [commander_slots]" - if(security_slots > 0) - slots_list += "security: [security_slots]" - if(medical_slots > 0) - slots_list += "medical: [medical_slots]" - if(engineering_slots > 0) - slots_list += "engineering: [engineering_slots]" - if(janitor_slots > 0) - slots_list += "janitor: [janitor_slots]" - if(paranormal_slots > 0) - slots_list += "paranormal: [paranormal_slots]" - if(cyborg_slots > 0) - slots_list += "cyborg: [cyborg_slots]" - var/slot_text = jointext(slots_list, ", ") - notify_ghosts("An ERT is being dispatched. Open positions: [slot_text]") - message_admins("[key_name_admin(usr)] dispatched a [ert_type] ERT. Slots: [slot_text]", 1) - log_admin("[key_name(usr)] dispatched a [ert_type] ERT. Slots: [slot_text]") - GLOB.event_announcement.Announce("Attention, [station_name()]. We are attempting to assemble an ERT. Standby.", "ERT Protocol Activated") - autoclose = 1 - ui_interact(usr) - trigger_armed_response_team(convert_ert_string(ert_type), commander_slots, security_slots, medical_slots, engineering_slots, janitor_slots, paranormal_slots, cyborg_slots) - return 0 - - ui_interact(usr) - - -/proc/convert_ert_string(thestring) - switch(thestring) - if("Code Amber") - return new /datum/response_team/amber - if("Code Red") - return new /datum/response_team/red - if("Code Gamma") - return new /datum/response_team/gamma - - -/datum/nano_module/ert_manager/ui_data() - var/data[0] - data["alert_level"] = get_security_level() - data["ert_type"] = ert_type - data["com"] = commander_slots - data["sec"] = security_slots - data["med"] = medical_slots - data["eng"] = engineering_slots - data["jan"] = janitor_slots - data["par"] = paranormal_slots - data["cyb"] = cyborg_slots - - return data - diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm index a65610c7382..f495466d3f5 100644 --- a/code/modules/paperwork/clipboard.dm +++ b/code/modules/paperwork/clipboard.dm @@ -42,7 +42,7 @@ if(in_range(user, src) && toppaper) . += toppaper.examine(user) -obj/item/clipboard/proc/penPlacement(mob/user, obj/item/pen/P, placing) +/obj/item/clipboard/proc/penPlacement(mob/user, obj/item/pen/P, placing) if(placing) if(containedpen) to_chat(user, "There's already a pen in [src]!") diff --git a/code/modules/paperwork/faxmachine.dm b/code/modules/paperwork/faxmachine.dm index 09858073142..32416a8d5e7 100644 --- a/code/modules/paperwork/faxmachine.dm +++ b/code/modules/paperwork/faxmachine.dm @@ -12,24 +12,32 @@ GLOBAL_LIST_EMPTY(fax_blacklist) insert_anim = "faxsend" pass_flags = PASSTABLE var/fax_network = "Local Fax Network" - var/syndie_restricted = FALSE //is it a syndicate base fax restricted from contacting NT assets? + /// If true, prevents fax machine from sending messages to NT machines + var/syndie_restricted = FALSE - var/long_range_enabled = 0 // Can we send messages off the station? + /// Can we send messages off-station? + var/long_range_enabled = FALSE req_one_access = list(ACCESS_LAWYER, ACCESS_HEADS, ACCESS_ARMORY) use_power = IDLE_POWER_USE idle_power_usage = 30 active_power_usage = 200 - var/obj/item/card/id/scan = null // identification + /// ID card inserted into the machine, used to log in with + var/obj/item/card/id/scan = null - var/authenticated = 0 - var/sendcooldown = 0 // to avoid spamming fax messages + /// Whether the machine is "logged in" or not + var/authenticated = FALSE + /// Next world.time at which this fax machine can send a message to CC/syndicate + var/sendcooldown = 0 + /// After sending a message to CC/syndicate, cannot send another to them for this many deciseconds var/cooldown_time = 1800 - var/department = "Unknown" // our department + /// Our department, determines whether this machine gets faxes sent to a department + var/department = "Unknown" - var/destination = "Not Selected" // the department we're sending to + /// Target department to send outgoing faxes to + var/destination /obj/machinery/photocopier/faxmachine/New() ..() @@ -44,7 +52,7 @@ GLOBAL_LIST_EMPTY(fax_blacklist) /obj/machinery/photocopier/faxmachine/longrange name = "long range fax machine" fax_network = "Central Command Quantum Entanglement Network" - long_range_enabled = 1 + long_range_enabled = TRUE /obj/machinery/photocopier/faxmachine/longrange/syndie name = "syndicate long range fax machine" @@ -58,17 +66,17 @@ GLOBAL_LIST_EMPTY(fax_blacklist) GLOB.hidden_departments |= department /obj/machinery/photocopier/faxmachine/attack_hand(mob/user) - ui_interact(user) + tgui_interact(user) /obj/machinery/photocopier/faxmachine/attack_ghost(mob/user) - ui_interact(user) + tgui_interact(user) /obj/machinery/photocopier/faxmachine/attackby(obj/item/item, mob/user, params) if(istype(item,/obj/item/card/id) && !scan) scan(item) else if(istype(item, /obj/item/paper) || istype(item, /obj/item/photo) || istype(item, /obj/item/paper_bundle)) ..() - SSnanoui.update_uis(src) + SStgui.update_uis(src) else return ..() @@ -80,42 +88,6 @@ GLOBAL_LIST_EMPTY(fax_blacklist) else to_chat(user, "You swipe the card through [src], but nothing happens.") -/obj/machinery/photocopier/faxmachine/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "faxmachine.tmpl", "Fax Machine UI", 540, 450) - ui.open() - -/obj/machinery/photocopier/faxmachine/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - var/is_authenticated = is_authenticated(user) - - if(scan) - data["scan_name"] = scan.name - else - data["scan_name"] = "-----" - data["authenticated"] = is_authenticated - if(!is_authenticated) - data["network"] = "Disconnected" - else if(!emagged) - data["network"] = fax_network - else - data["network"] = "ERR*?*%!*" - if(copyitem) - data["paper"] = copyitem.name - data["paperinserted"] = 1 - else - data["paper"] = "-----" - data["paperinserted"] = 0 - data["destination"] = destination - data["cooldown"] = sendcooldown - if((destination in GLOB.admin_departments) || (destination in GLOB.hidden_admin_departments)) - data["respectcooldown"] = 1 - else - data["respectcooldown"] = 0 - - return data - /obj/machinery/photocopier/faxmachine/proc/is_authenticated(mob/user) if(authenticated) return TRUE @@ -123,87 +95,134 @@ GLOBAL_LIST_EMPTY(fax_blacklist) return TRUE return FALSE -/obj/machinery/photocopier/faxmachine/Topic(href, href_list) - if(..()) - return 1 +/obj/machinery/photocopier/faxmachine/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "FaxMachine", name, 540, 300, master_ui, state) + ui.open() +/obj/machinery/photocopier/faxmachine/tgui_data(mob/user) + var/list/data = list() + data["authenticated"] = is_authenticated(user) + data["scan_name"] = scan ? scan.name : FALSE + if(!data["authenticated"]) + data["network"] = "Disconnected" + else if(!emagged) + data["network"] = fax_network + else + data["network"] = "ERR*?*%!*" + data["paper"] = copyitem ? copyitem.name : FALSE + data["paperinserted"] = copyitem ? TRUE : FALSE + data["destination"] = destination ? destination : FALSE + data["sendError"] = FALSE + if(stat & (BROKEN|NOPOWER)) + data["sendError"] = "No Power" + else if(!data["authenticated"]) + data["sendError"] = "Not Logged In" + else if(!data["paper"]) + data["sendError"] = "Nothing Inserted" + else if(!data["destination"]) + data["sendError"] = "Destination Not Set" + else if((destination in GLOB.admin_departments) || (destination in GLOB.hidden_admin_departments)) + var/cooldown_seconds = cooldown_seconds() + if(cooldown_seconds) + data["sendError"] = "Re-aligning in [cooldown_seconds] seconds..." + return data + + +/obj/machinery/photocopier/faxmachine/tgui_act(action, params) + if(..()) + return var/is_authenticated = is_authenticated(usr) - if(href_list["send"]) - if(copyitem && is_authenticated) + . = TRUE + switch(action) + if("scan") // insert/remove your ID card + scan() + if("auth") // log in/out + if(!is_authenticated && scan) + if(scan.registered_name in GLOB.fax_blacklist) + to_chat(usr, "Login rejected: individual is blacklisted from fax network.") + playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) + . = FALSE + else if(check_access(scan)) + authenticated = TRUE + else // ID doesn't have access to this machine + to_chat(usr, "Login rejected: ID card does not have required access.") + playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) + . = FALSE + else if(is_authenticated) + authenticated = FALSE + if("paper") // insert/eject paper/paperbundle/photo + if(copyitem) + copyitem.forceMove(get_turf(src)) + if(ishuman(usr)) + if(!usr.get_active_hand() && Adjacent(usr)) + usr.put_in_hands(copyitem) + to_chat(usr, "You eject [copyitem] from [src].") + copyitem = null + else + var/obj/item/I = usr.get_active_hand() + if(istype(I, /obj/item/paper) || istype(I, /obj/item/photo) || istype(I, /obj/item/paper_bundle)) + usr.drop_item() + copyitem = I + I.forceMove(src) + to_chat(usr, "You insert [I] into [src].") + flick(insert_anim, src) + else + to_chat(usr, "[src] only accepts paper, paper bundles, and photos.") + . = FALSE + if("rename") // rename the item that is currently in the fax machine + if(copyitem) + var/n_name = sanitize(copytext(input(usr, "What would you like to label the fax?", "Fax Labelling", copyitem.name) as text, 1, MAX_MESSAGE_LEN)) + if((copyitem && copyitem.loc == src && usr.stat == 0)) + if(istype(copyitem, /obj/item/paper)) + copyitem.name = "[(n_name ? text("[n_name]") : initial(copyitem.name))]" + copyitem.desc = "This is a paper titled '" + copyitem.name + "'." + else if(istype(copyitem, /obj/item/photo)) + copyitem.name = "[(n_name ? text("[n_name]") : "photo")]" + else if(istype(copyitem, /obj/item/paper_bundle)) + copyitem.name = "[(n_name ? text("[n_name]") : "paper")]" + else + . = FALSE + else + . = FALSE + else + . = FALSE + if("dept") // choose which department receives the fax + if(is_authenticated) + var/lastdestination = destination + var/list/combineddepartments = GLOB.alldepartments.Copy() + if(long_range_enabled) + combineddepartments += GLOB.admin_departments.Copy() + if(emagged) + combineddepartments += GLOB.hidden_admin_departments.Copy() + combineddepartments += GLOB.hidden_departments.Copy() + if(syndie_restricted) + combineddepartments = GLOB.hidden_admin_departments.Copy() + combineddepartments += GLOB.hidden_departments.Copy() + for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes) + if(F.emagged)//we can contact emagged faxes on the station + combineddepartments |= F.department + destination = input(usr, "To which department?", "Choose a department", "") as null|anything in combineddepartments + if(!destination) + destination = lastdestination + if("send") // actually send the fax + if(!copyitem || !is_authenticated || !destination) + return + if(stat & (BROKEN|NOPOWER)) + return if((destination in GLOB.admin_departments) || (destination in GLOB.hidden_admin_departments)) + var/cooldown_seconds = cooldown_seconds() + if(cooldown_seconds > 0) + playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) + to_chat(usr, "[src] is not ready for another [cooldown_seconds] seconds.") + return send_admin_fax(usr, destination) + sendcooldown = world.time + cooldown_time else sendfax(destination, usr) - - if(sendcooldown) - spawn(sendcooldown) // cooldown time - sendcooldown = 0 - SSnanoui.update_uis(src) - - if(href_list["paper"]) - if(copyitem) - copyitem.forceMove(get_turf(src)) - if(ishuman(usr)) - if(!usr.get_active_hand() && Adjacent(usr)) - usr.put_in_hands(copyitem) - to_chat(usr, "You eject \the [copyitem] from \the [src].") - copyitem = null - else - var/obj/item/I = usr.get_active_hand() - if(istype(I, /obj/item/paper) || istype(I, /obj/item/photo) || istype(I, /obj/item/paper_bundle)) - usr.drop_item() - copyitem = I - I.forceMove(src) - to_chat(usr, "You insert \the [I] into \the [src].") - flick(insert_anim, src) - - if(href_list["scan"]) - scan() - - if(href_list["dept"]) - if(is_authenticated) - var/lastdestination = destination - var/list/combineddepartments = GLOB.alldepartments.Copy() - if(long_range_enabled) - combineddepartments += GLOB.admin_departments.Copy() - - if(emagged) - combineddepartments += GLOB.hidden_admin_departments.Copy() - combineddepartments += GLOB.hidden_departments.Copy() - - if(syndie_restricted) - combineddepartments = GLOB.hidden_admin_departments.Copy() - combineddepartments += GLOB.hidden_departments.Copy() - for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes) - if(F.emagged)//we can contact emagged faxes on the station - combineddepartments |= F.department - - destination = input(usr, "To which department?", "Choose a department", "") as null|anything in combineddepartments - if(!destination) - destination = lastdestination - - if(href_list["auth"]) - if(!is_authenticated && scan) - if(scan.registered_name in GLOB.fax_blacklist) - playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) - else if(check_access(scan)) - authenticated = 1 - else if(is_authenticated) - authenticated = 0 - - if(href_list["rename"]) - if(copyitem) - var/n_name = sanitize(copytext(input(usr, "What would you like to label the fax?", "Fax Labelling", copyitem.name) as text, 1, MAX_MESSAGE_LEN)) - if((copyitem && copyitem.loc == src && usr.stat == 0)) - if(istype(copyitem, /obj/item/paper)) - copyitem.name = "[(n_name ? text("[n_name]") : initial(copyitem.name))]" - copyitem.desc = "This is a paper titled '" + copyitem.name + "'." - else if(istype(copyitem, /obj/item/photo)) - copyitem.name = "[(n_name ? text("[n_name]") : "photo")]" - else if(istype(copyitem, /obj/item/paper_bundle)) - copyitem.name = "[(n_name ? text("[n_name]") : "paper")]" - - SSnanoui.update_uis(src) + if(.) + add_fingerprint(usr) /obj/machinery/photocopier/faxmachine/proc/scan(var/obj/item/card/id/card = null) if(scan) // Card is in machine @@ -226,7 +245,7 @@ GLOBAL_LIST_EMPTY(fax_blacklist) usr.drop_item() card.forceMove(src) scan = card - SSnanoui.update_uis(src) + SStgui.update_uis(src) /obj/machinery/photocopier/faxmachine/verb/eject_id() set category = null @@ -237,25 +256,20 @@ GLOBAL_LIST_EMPTY(fax_blacklist) return if(scan) - to_chat(usr, "You remove \the [scan] from \the [src].") + to_chat(usr, "You remove [scan] from [src].") scan.forceMove(get_turf(src)) if(!usr.get_active_hand() && Adjacent(usr)) usr.put_in_hands(scan) scan = null else - to_chat(usr, "There is nothing to remove from \the [src].") + to_chat(usr, "There is nothing to remove from [src].") /obj/machinery/photocopier/faxmachine/proc/sendfax(var/destination,var/mob/sender) - if(stat & (BROKEN|NOPOWER)) - return - - use_power(200) - + use_power(active_power_usage) var/success = 0 for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes) if(F.department == destination) success = F.receivefax(copyitem) - if(success) var/datum/fax/F = new /datum/fax() F.name = copyitem.name @@ -272,10 +286,10 @@ GLOBAL_LIST_EMPTY(fax_blacklist) /obj/machinery/photocopier/faxmachine/proc/receivefax(var/obj/item/incoming) if(stat & (BROKEN|NOPOWER)) - return 0 + return FALSE if(department == "Unknown") - return 0 //You can't send faxes to "Unknown" + return FALSE //You can't send faxes to "Unknown" flick("faxreceive", src) @@ -291,19 +305,13 @@ GLOBAL_LIST_EMPTY(fax_blacklist) else if(istype(incoming, /obj/item/paper_bundle)) bundlecopy(incoming) else - return 0 + return FALSE use_power(active_power_usage) - return 1 + return TRUE /obj/machinery/photocopier/faxmachine/proc/send_admin_fax(var/mob/sender, var/destination) - if(stat & (BROKEN|NOPOWER)) - return - - if(sendcooldown) - return - - use_power(200) + use_power(active_power_usage) if(!(istype(copyitem, /obj/item/paper) || istype(copyitem, /obj/item/paper_bundle) || istype(copyitem, /obj/item/photo))) visible_message("[src] beeps, \"Error transmitting message.\"") @@ -327,10 +335,12 @@ GLOBAL_LIST_EMPTY(fax_blacklist) for(var/obj/machinery/photocopier/faxmachine/F in GLOB.allfaxes) if(F.department == destination) F.receivefax(copyitem) - sendcooldown = cooldown_time - spawn(50) - visible_message("[src] beeps, \"Message transmitted successfully.\"") + visible_message("[src] beeps, \"Message transmitted successfully.\"") +/obj/machinery/photocopier/faxmachine/proc/cooldown_seconds() + if(sendcooldown < world.time) + return 0 + return round((sendcooldown - world.time) / 10) /obj/machinery/photocopier/faxmachine/proc/message_admins(var/mob/sender, var/faxname, var/faxtype, var/obj/item/sent, font_colour="#9A04D1") var/msg = "[faxname]: [key_name_admin(sender)] | REPLY: (RADIO) (FAX) ([ADMIN_SM(sender,"SM")]) | REJECT: (TEMPLATE) ([ADMIN_BSA(sender,"BSA")]) (EVILFAX) : Receiving '[sent.name]' via secure connection... view message" diff --git a/code/modules/paperwork/silicon_photography.dm b/code/modules/paperwork/silicon_photography.dm index eb8904cf3e8..17cfcacec62 100644 --- a/code/modules/paperwork/silicon_photography.dm +++ b/code/modules/paperwork/silicon_photography.dm @@ -150,7 +150,7 @@ // Explicitly only allow deletion from the local camera deletepicture(src) -obj/item/camera/siliconcam/proc/getsource() +/obj/item/camera/siliconcam/proc/getsource() if(istype(src.loc, /mob/living/silicon/ai)) return src diff --git a/code/modules/pda/radio.dm b/code/modules/pda/radio.dm index f214e705268..cd549759c1c 100644 --- a/code/modules/pda/radio.dm +++ b/code/modules/pda/radio.dm @@ -70,26 +70,22 @@ switch(href_list["op"]) if("control") active = locate(href_list["bot"]) - spawn(0) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) if("scanbots") // find all bots botlist = null - spawn(0) - post_signal(control_freq, "command", "bot_status", s_filter = bot_filter) + post_signal(control_freq, "command", "bot_status", s_filter = bot_filter) if("botlist") active = null if("stop", "go", "home") - spawn(0) - post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = bot_filter) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) + post_signal(control_freq, "command", href_list["op"], "active", active, s_filter = bot_filter) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) if("summon") - spawn(0) - post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(hostpda), "useraccess", hostpda.GetAccess(), "user", usr, s_filter = bot_filter) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) + post_signal(control_freq, "command", "summon", "active", active, "target", get_turf(hostpda), "useraccess", hostpda.GetAccess(), "user", usr, s_filter = bot_filter) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = bot_filter) /obj/item/integrated_radio/proc/add_to_radio(bot_filter) //Master filter control for bots. Must be placed in the bot's local New() to support map spawned bots. if(SSradio) @@ -123,38 +119,30 @@ ..() switch(href_list["op"]) if("start") - spawn(0) - post_signal(control_freq, "command", "start", "active", active, s_filter = RADIO_MULEBOT) + post_signal(control_freq, "command", "start", "active", active, s_filter = RADIO_MULEBOT) if("unload") - spawn(0) - post_signal(control_freq, "command", "unload", "active", active, s_filter = RADIO_MULEBOT) + post_signal(control_freq, "command", "unload", "active", active, s_filter = RADIO_MULEBOT) if("setdest") if(GLOB.deliverybeacons) var/dest = input("Select Bot Destination", "Mulebot [active.suffix] Interlink", active.destination) as null|anything in GLOB.deliverybeacontags if(dest) - spawn(0) - post_signal(control_freq, "command", "target", "active", active, "destination", dest, s_filter = RADIO_MULEBOT) + post_signal(control_freq, "command", "target", "active", active, "destination", dest, s_filter = RADIO_MULEBOT) if("retoff") - spawn(0) - post_signal(control_freq, "command", "autoret", "active", active, "value", 0, s_filter = RADIO_MULEBOT) + post_signal(control_freq, "command", "autoret", "active", active, "value", 0, s_filter = RADIO_MULEBOT) if("reton") - spawn(0) - post_signal(control_freq, "command", "autoret", "active", active, "value", 1, s_filter = RADIO_MULEBOT) + post_signal(control_freq, "command", "autoret", "active", active, "value", 1, s_filter = RADIO_MULEBOT) if("pickoff") - spawn(0) - post_signal(control_freq, "command", "autopick", "active", active, "value", 0, s_filter = RADIO_MULEBOT) + post_signal(control_freq, "command", "autopick", "active", active, "value", 0, s_filter = RADIO_MULEBOT) if("pickon") - spawn(0) - post_signal(control_freq, "command", "autopick", "active", active, "value", 1, s_filter = RADIO_MULEBOT) + post_signal(control_freq, "command", "autopick", "active", active, "value", 1, s_filter = RADIO_MULEBOT) - spawn(10) - post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_MULEBOT) + post_signal(control_freq, "command", "bot_status", "active", active, s_filter = RADIO_MULEBOT) diff --git a/code/modules/pda/utilities.dm b/code/modules/pda/utilities.dm index 1dfb819c826..c527e1dd12d 100644 --- a/code/modules/pda/utilities.dm +++ b/code/modules/pda/utilities.dm @@ -10,6 +10,10 @@ name = fon ? "Disable Flashlight" : "Enable Flashlight" pda.update_shortcuts() pda.set_light(fon ? f_lum : 0) + if(fon) + pda.overlays += image('icons/obj/pda.dmi', "pda-light") + else + pda.overlays -= image('icons/obj/pda.dmi', "pda-light") /datum/data/pda/utility/honk name = "Honk Synthesizer" diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 4b64266f2b7..c4d3fb6cb91 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -940,7 +940,7 @@ update() if("overload") if(usr.has_unlimited_silicon_privilege) - overload_lighting() + INVOKE_ASYNC(src, /obj/machinery/power/apc.proc/overload_lighting) if("hack") if(get_malf_status(usr)) malfhack(usr) @@ -1287,11 +1287,10 @@ return if(cell && cell.charge >= 20) cell.use(20) - spawn(0) - for(var/obj/machinery/light/L in area) - if(prob(chance)) - L.break_light_tube(0, 1) - stoplag() + for(var/obj/machinery/light/L in area) + if(prob(chance)) + L.break_light_tube(0, 1) + stoplag() /obj/machinery/power/apc/proc/null_charge() for(var/obj/machinery/light/L in area) diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 992020e7090..40969d7e677 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -229,7 +229,7 @@ By design, d1 is the smallest direction and d2 is the highest if(current_size >= STAGE_FIVE) deconstruct() -obj/structure/cable/proc/cable_color(colorC) +/obj/structure/cable/proc/cable_color(colorC) if(!colorC) color = COLOR_RED else if(colorC == "rainbow") diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm index 3ad96050123..d1c7d3433fe 100644 --- a/code/modules/power/singularity/particle_accelerator/particle_control.dm +++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm @@ -235,6 +235,7 @@ investigate_log("turned [active?"ON":"OFF"] by [usr ? usr.key : "outside forces"]","singulo") if(active) msg_admin_attack("PA Control Computer turned ON by [key_name_admin(usr)]", ATKLOG_FEW) + usr.create_log(MISC_LOG, "PA Control Computer turned ON", src) log_game("PA Control Computer turned ON by [key_name(usr)] in ([x],[y],[z])") use_log += text("\[[time_stamp()]\] [key_name(usr)] has turned on the PA Control Computer.") if(active) diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm index 59ce091b170..2fa2c4c1573 100644 --- a/code/modules/power/smes.dm +++ b/code/modules/power/smes.dm @@ -227,8 +227,8 @@ if(terminal) terminal.master = null terminal = null - return 1 - return 0 + return TRUE + return FALSE /obj/machinery/power/smes/proc/make_terminal(user, tempDir, tempLoc) // create a terminal object at the same position as original turf loc @@ -339,89 +339,91 @@ /obj/machinery/power/smes/attack_ai(mob/user) add_hiddenprint(user) - ui_interact(user) + tgui_interact(user) /obj/machinery/power/smes/attack_ghost(mob/user) - ui_interact(user) + tgui_interact(user) /obj/machinery/power/smes/attack_hand(mob/user) add_fingerprint(user) - ui_interact(user) + tgui_interact(user) -/obj/machinery/power/smes/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) +/obj/machinery/power/smes/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) if(stat & BROKEN) return - - - // update the ui if it exists, returns null if no ui is passed/found - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - // the ui does not exist, so we'll create a new() one - // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm - ui = new(user, src, ui_key, "smes.tmpl", "SMES Power Storage Unit", 540, 380) - // open the new ui window + ui = new(user, src, ui_key, "Smes", name, 340, 350, master_ui, state) ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) - -/obj/machinery/power/smes/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - - data["nameTag"] = name_tag - data["storedCapacity"] = round(100.0*charge/capacity, 0.1) - data["charging"] = inputting - data["chargeMode"] = input_attempt - data["chargeLevel"] = input_level - data["chargeMax"] = input_level_max - data["outputOnline"] = output_attempt - data["outputLevel"] = output_level - data["outputMax"] = output_level_max - data["outputLoad"] = round(output_used) - - if(outputting) - data["outputting"] = 2 // smes is outputting - else if(!outputting && output_attempt) - data["outputting"] = 1 // smes is online but not outputting because it's charge level is too low - else - data["outputting"] = 0 // smes is not outputting +/obj/machinery/power/smes/tgui_data(mob/user) + var/list/data = list( + "capacity" = capacity, + "capacityPercent" = round(100*charge/capacity, 0.1), + "charge" = charge, + "inputAttempt" = input_attempt, + "inputting" = inputting, + "inputLevel" = input_level, + "inputLevel_text" = DisplayPower(input_level), + "inputLevelMax" = input_level_max, + "inputAvailable" = input_available, + "outputAttempt" = output_attempt, + "outputting" = outputting, + "outputLevel" = output_level, + "outputLevel_text" = DisplayPower(output_level), + "outputLevelMax" = output_level_max, + "outputUsed" = round(output_used), + ) return data -/obj/machinery/power/smes/Topic(href, href_list) +/obj/machinery/power/smes/tgui_act(action, params) if(..()) - return 1 + return + . = TRUE + switch(action) + if("tryinput") + inputting(!input_attempt) + update_icon() + if("tryoutput") + outputting(!output_attempt) + update_icon() + if("input") + var/target = params["target"] + var/adjust = text2num(params["adjust"]) + if(target == "min") + target = 0 + else if(target == "max") + target = input_level_max + else if(adjust) + target = input_level + adjust + else if(text2num(target) != null) + target = text2num(target) + else + . = FALSE + if(.) + input_level = clamp(target, 0, input_level_max) + if("output") + var/target = params["target"] + var/adjust = text2num(params["adjust"]) + if(target == "min") + target = 0 + else if(target == "max") + target = output_level_max + else if(adjust) + target = output_level + adjust + else if(text2num(target) != null) + target = text2num(target) + else + . = FALSE + if(.) + output_level = clamp(target, 0, output_level_max) + else + . = FALSE + if(.) + log_smes(usr) - if( href_list["cmode"] ) - inputting(!input_attempt) - update_icon() - - else if( href_list["online"] ) - outputting(!output_attempt) - update_icon() - - else if( href_list["input"] ) - switch( href_list["input"] ) - if("min") - input_level = 0 - if("max") - input_level = input_level_max - if("set") - input_level = input(usr, "Enter new input level (0-[input_level_max])", "SMES Input Power Control", input_level) as num - input_level = max(0, min(input_level_max, input_level)) // clamp to range - - else if( href_list["output"] ) - switch( href_list["output"] ) - if("min") - output_level = 0 - if("max") - output_level = output_level_max - if("set") - output_level = input(usr, "Enter new output level (0-[output_level_max])", "SMES Output Power Control", output_level) as num - output_level = max(0, min(output_level_max, output_level)) // clamp to range - - investigate_log("input/output; [input_level>output_level?"":""][input_level]/[output_level] | Output-mode: [output_attempt?"on":"off"] | Input-mode: [input_attempt?"auto":"off"] by [usr.key]","singulo") - - return 1 +/obj/machinery/power/smes/proc/log_smes(mob/user) + investigate_log("input/output; [input_level>output_level?"":""][input_level]/[output_level] | Charge: [charge] | Output-mode: [output_attempt?"on":"off"] | Input-mode: [input_attempt?"auto":"off"] by [user ? key_name(user) : "outside forces"]", "singulo") /obj/machinery/power/smes/proc/ion_act() if(is_station_level(src.z)) @@ -448,6 +450,7 @@ smoke.attach(src) smoke.start() + /obj/machinery/power/smes/proc/inputting(var/do_input) input_attempt = do_input if(!input_attempt) @@ -459,14 +462,15 @@ outputting = 0 /obj/machinery/power/smes/emp_act(severity) - inputting(rand(0,1)) - outputting(rand(0,1)) + inputting(rand(0, 1)) + outputting(rand(0, 1)) output_level = rand(0, output_level_max) input_level = rand(0, input_level_max) charge -= 1e6/severity if(charge < 0) charge = 0 update_icon() + log_smes() ..() /obj/machinery/power/smes/engineering diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index d99df1de7bb..7bb2f16b64a 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -254,13 +254,17 @@ // Solar Control Computer // +#define TRACKER_OFF 0 +#define TRACKER_TIMED 1 +#define TRACKER_AUTO 2 + /obj/machinery/power/solar_control name = "solar panel control" desc = "A controller for solar panel arrays." icon = 'icons/obj/computer.dmi' icon_state = "computer" - anchored = 1 - density = 1 + anchored = TRUE + density = TRUE use_power = IDLE_POWER_USE idle_power_usage = 250 max_integrity = 200 @@ -272,17 +276,17 @@ var/targetdir = 0 // target angle in manual tracking (since it updates every game minute) var/gen = 0 var/lastgen = 0 - var/track = 0 // 0= off 1=timed 2=auto (tracker) + var/track = TRACKER_OFF var/trackrate = 600 // 300-900 seconds var/nexttime = 0 // time for a panel to rotate of 1? in manual tracking - var/autostart = 0 // Automatically search for connected devices + var/autostart = FALSE // Automatically search for connected devices var/obj/machinery/power/tracker/connected_tracker = null var/list/connected_panels = list() // Used for mapping in solar array which automatically starts itself (telecomms, for example) /obj/machinery/power/solar_control/autostart - track = 2 // Auto tracking mode - autostart = 1 // Automatically start + track = TRACKER_AUTO + autostart = TRUE // Automatically search for connected devices /obj/machinery/power/solar_control/Initialize() SSsun.solars |= src @@ -294,7 +298,7 @@ set_panels(cdir) if(autostart) search_for_connected() - if(connected_tracker && track == 2) + if(connected_tracker && track == TRACKER_AUTO) connected_tracker.set_angle(SSsun.angle) set_panels(cdir) @@ -334,15 +338,9 @@ if(stat & (NOPOWER | BROKEN)) return - switch(track) - if(1) - if(trackrate) //we're manual tracking. If we set a rotation speed... - cdir = targetdir //...the current direction is the targetted one (and rotates panels to it) - if(2) // auto-tracking - if(connected_tracker) - connected_tracker.set_angle(SSsun.angle) - - set_panels(cdir) + if(track == TRACKER_AUTO && connected_tracker) // auto-tracking + connected_tracker.set_angle(SSsun.angle) + set_panels(cdir) updateDialog() /obj/machinery/power/solar_control/update_icon() @@ -359,44 +357,73 @@ overlays += image('icons/obj/computer.dmi', "solcon-o", FLY_LAYER, angle2dir(cdir)) /obj/machinery/power/solar_control/attack_ai(mob/user as mob) - src.add_hiddenprint(user) - ui_interact(user) + add_hiddenprint(user) + tgui_interact(user) /obj/machinery/power/solar_control/attack_ghost(mob/user as mob) - ui_interact(user) + tgui_interact(user) /obj/machinery/power/solar_control/attack_hand(mob/user) if(..(user)) - return 1 - + return TRUE if(stat & BROKEN) return + tgui_interact(user) - ui_interact(user) - -/obj/machinery/power/solar_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/power/solar_control/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "solar_control.tmpl", name, 490, 420) + ui = new(user, src, ui_key, "SolarControl", name, 490, 300) ui.open() - ui.set_auto_update(1) - -/obj/machinery/power/solar_control/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - - data["generated"] = round(lastgen) - data["angle"] = cdir - data["direction"] = angle2text(cdir) - - data["tracking_state"] = track - data["tracking_rate"] = trackrate - data["rotating_way"] = (trackrate<0 ? "CCW" : "CW") +/obj/machinery/power/solar_control/tgui_data(mob/user) + var/list/data = list() + data["generated"] = round(lastgen) //generated power by all connected panels + data["generated_ratio"] = data["generated"] / round(max(connected_panels.len, 1) * SOLARGENRATE) //power generation ratio. Used for the power bar + data["direction"] = angle2text(cdir) //current orientation of the panels + data["cdir"] = cdir //current orientation of the of the panels in degrees + data["tracking_state"] = track //tracker status: TRACKER_OFF, TRACKER_TIMED, TRACKER_AUTO + data["tracking_rate"] = trackrate //rotation speed of tracker in degrees/h + data["rotating_direction"] = (trackrate < 0 ? "Counter clockwise" : "Clockwise") //direction of tracker data["connected_panels"] = connected_panels.len - data["connected_tracker"] = (connected_tracker ? 1 : 0) - + data["connected_tracker"] = (connected_tracker ? TRUE : FALSE) return data +/obj/machinery/power/solar_control/tgui_act(action, params) + if(..()) + return + . = TRUE + + switch(action) + if("cdir") //change panel orientation + var/newAngle = text2num(params["cdir"]) + if(!isnull(newAngle)) //0 is ok + cdir = clamp(newAngle, 0, 359) + targetdir = cdir + set_panels(cdir) + if("tdir") //change tracker rotation + var/newTrackrate = text2num(params["tdir"]) + if(!newTrackrate) + newTrackrate = 1 + trackrate = clamp(newTrackrate, -7200, 7200) + nexttime = world.time + 36000 / abs(trackrate) + if("track") //change tracker status + track = text2num(params["track"]) + if(track == TRACKER_AUTO) + if(connected_tracker) + connected_tracker.set_angle(SSsun.angle) + set_panels(cdir) + else if(track == TRACKER_TIMED) + targetdir = cdir + if(trackrate) + nexttime = world.time + 36000 / abs(trackrate) + set_panels(targetdir) + if("refresh") + search_for_connected() + if(connected_tracker && track == TRACKER_AUTO) + connected_tracker.set_angle(SSsun.angle) + set_panels(cdir) + /obj/machinery/power/solar_control/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/screwdriver)) playsound(src.loc, I.usesound, 50, 1) @@ -450,50 +477,16 @@ if(stat & (NOPOWER | BROKEN)) return - if(connected_tracker) //NOTE : handled here so that we don't add trackers to the processing list - if(connected_tracker.powernet != powernet) - connected_tracker.unset_control() + if(connected_tracker && connected_tracker.powernet != powernet) //NOTE : handled here so that we don't add trackers to the processing list + connected_tracker.unset_control() - if(track==1 && trackrate) //manual tracking and set a rotation speed - if(nexttime <= world.time) //every time we need to increase/decrease the angle by 1?... - targetdir = (targetdir + trackrate/abs(trackrate) + 360) % 360 //... do it - nexttime += 36000/abs(trackrate) //reset the counter for the next 1? - -/obj/machinery/power/solar_control/Topic(href, href_list) - if(..()) - return - - if(href_list["rate_control"]) - if(href_list["cdir"]) - src.cdir = dd_range(0,359,(360+src.cdir+text2num(href_list["cdir"]))%360) - src.targetdir = src.cdir - if(track == 2) //manual update, so losing auto-tracking - track = 0 - spawn(1) - set_panels(cdir) - if(href_list["tdir"]) - src.trackrate = dd_range(-7200,7200,src.trackrate+text2num(href_list["tdir"])) - if(src.trackrate) nexttime = world.time + 36000/abs(trackrate) - - if(href_list["track"]) - track = text2num(href_list["track"]) - if(track == 2) - if(connected_tracker) - connected_tracker.set_angle(SSsun.angle) - set_panels(cdir) - else if(track == 1) //begin manual tracking - src.targetdir = src.cdir - if(src.trackrate) nexttime = world.time + 36000/abs(trackrate) - set_panels(targetdir) - - if(href_list["search_connected"]) - search_for_connected() - if(connected_tracker && track == 2) - connected_tracker.set_angle(SSsun.angle) + //manual tracking and set a rotation speed + if(track == TRACKER_TIMED && trackrate && nexttime <= world.time) //every time we need to increase/decrease the angle by 1?... + targetdir = (targetdir + trackrate / abs(trackrate) + 360) % 360 //... do it + nexttime += 36000 / abs(trackrate) //reset the counter for the next 1? + cdir = targetdir set_panels(cdir) - return - //rotates the panel to the passed angle /obj/machinery/power/solar_control/proc/set_panels(var/cdir) diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm index e6165103234..fd526d0e12a 100644 --- a/code/modules/projectiles/ammunition.dm +++ b/code/modules/projectiles/ammunition.dm @@ -97,6 +97,7 @@ var/ammo_type = /obj/item/ammo_casing var/max_ammo = 7 var/multiple_sprites = 0 + var/icon_prefix // boxes with multiple sprites use this as their base var/caliber var/multiload = 1 var/list/initial_mats //For calculating refund values. @@ -192,11 +193,12 @@ update_icon() /obj/item/ammo_box/update_icon() + var/icon_base = initial(icon_prefix) ? initial(icon_prefix) : initial(icon_state) switch(multiple_sprites) if(1) - icon_state = "[initial(icon_state)]-[stored_ammo.len]" + icon_state = "[icon_base]-[stored_ammo.len]" if(2) - icon_state = "[initial(icon_state)]-[stored_ammo.len ? "[max_ammo]" : "0"]" + icon_state = "[icon_base]-[stored_ammo.len ? "[max_ammo]" : "0"]" desc = "[initial(desc)] There are [stored_ammo.len] shell\s left!" /obj/item/ammo_box/proc/update_mat_value() diff --git a/code/modules/projectiles/ammunition/boxes.dm b/code/modules/projectiles/ammunition/boxes.dm index 4484be63c83..53004b768db 100644 --- a/code/modules/projectiles/ammunition/boxes.dm +++ b/code/modules/projectiles/ammunition/boxes.dm @@ -1,10 +1,11 @@ /obj/item/ammo_box/a357 name = "speed loader (.357)" desc = "Designed to quickly reload revolvers." - icon_state = "357" ammo_type = /obj/item/ammo_casing/a357 max_ammo = 7 - multiple_sprites = 1 + icon_state = "357-7" // DEFAULT icon, composed of prefix + "-" + max_ammo for multiple_sprites == 1 boxes + multiple_sprites = 1 // see: /obj/item/ammo_box/update_icon() + icon_prefix = "357" // icon prefix, used in above formula to generate dynamic icons /obj/item/ammo_box/c38 name = "speed loader (.38)" @@ -12,7 +13,9 @@ icon_state = "38" ammo_type = /obj/item/ammo_casing/c38 max_ammo = 6 + icon_state = "38-6" // see previous entry for explanation of these vars multiple_sprites = 1 + icon_prefix = "38" /obj/item/ammo_box/c9mm name = "ammo box (9mm)" diff --git a/code/modules/projectiles/guns/projectile/saw.dm b/code/modules/projectiles/guns/projectile/saw.dm index 3c25bc30f93..bb800214020 100644 --- a/code/modules/projectiles/guns/projectile/saw.dm +++ b/code/modules/projectiles/guns/projectile/saw.dm @@ -87,7 +87,7 @@ damage = 7 armour_penetration = 0 -obj/item/projectile/bullet/saw/incen/Move() +/obj/item/projectile/bullet/saw/incen/Move() ..() var/turf/location = get_turf(src) if(location) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index c33c649ae77..2a7fd2e602d 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -287,7 +287,7 @@ Range() sleep(max(1, speed)) -obj/item/projectile/proc/reflect_back(atom/source, list/position_modifiers = list(0, 0, 0, 0, 0, -1, 1, -2, 2)) +/obj/item/projectile/proc/reflect_back(atom/source, list/position_modifiers = list(0, 0, 0, 0, 0, -1, 1, -2, 2)) if(starting) var/new_x = starting.x + pick(position_modifiers) var/new_y = starting.y + pick(position_modifiers) @@ -306,7 +306,7 @@ obj/item/projectile/proc/reflect_back(atom/source, list/position_modifiers = lis xo = new_x - curloc.x Angle = null // Will be calculated in fire() -obj/item/projectile/Crossed(atom/movable/AM, oldloc) //A mob moving on a tile with a projectile is hit by it. +/obj/item/projectile/Crossed(atom/movable/AM, oldloc) //A mob moving on a tile with a projectile is hit by it. ..() if(isliving(AM) && AM.density && !checkpass(PASSMOB)) Bump(AM, 1) diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 2323aa06cf4..d6140d28f4e 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -31,16 +31,17 @@ M.AdjustDrowsy(10) A.volume += 5 //Because we can -/obj/item/projectile/bullet/weakbullet2 //detective revolver instastuns, but multiple shots are better for keeping punks down +/obj/item/projectile/bullet/weakbullet2 //detective revolver name = "rubber bullet" damage = 5 - weaken = 3 - stamina = 60 + stamina = 35 icon_state = "bullet-r" /obj/item/projectile/bullet/weakbullet2/invisible //finger gun bullets name = "invisible bullet" damage = 0 + weaken = 3 + stamina = 60 icon_state = null hitsound_wall = null diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index 7f0ed2c91dc..c5ef03040b4 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -144,56 +144,69 @@ return STATUS_UPDATE_NONE /datum/reagent/proc/addiction_act_stage2(mob/living/M) - if(prob(8)) - M.emote("shiver") - if(prob(8)) - M.emote("sneeze") - if(prob(4)) - to_chat(M, "You feel a dull headache.") + if(minor_addiction) + if(prob(4)) + to_chat(M, "You briefly think about getting some more [name].") + else + if(prob(8)) + M.emote("shiver") + if(prob(8)) + M.emote("sneeze") + if(prob(4)) + to_chat(M, "You feel a dull headache.") return STATUS_UPDATE_NONE /datum/reagent/proc/addiction_act_stage3(mob/living/M) - if(prob(8)) - M.emote("twitch_s") - if(prob(8)) - M.emote("shiver") - if(prob(4)) - to_chat(M, "Your head hurts.") - if(prob(4)) - to_chat(M, "You begin craving [name]!") + if(minor_addiction) + if(prob(4)) + to_chat(M, "You could really go for some [name] right now.") + else + if(prob(8)) + M.emote("twitch_s") + if(prob(8)) + M.emote("shiver") + if(prob(4)) + to_chat(M, "Your head hurts.") + if(prob(4)) + to_chat(M, "You begin craving [name]!") return STATUS_UPDATE_NONE /datum/reagent/proc/addiction_act_stage4(mob/living/M) - if(prob(8)) - M.emote("twitch") - if(prob(4)) - to_chat(M, "You have a pounding headache.") - if(prob(4)) - to_chat(M, "You have the strong urge for some [name]!") - else if(prob(4)) - to_chat(M, "You REALLY crave some [name]!") + if(minor_addiction) + if(prob(8)) + to_chat(M, "You could really go for some [name] right now.") + else + if(prob(8)) + M.emote("twitch") + if(prob(4)) + to_chat(M, "You have a pounding headache.") + if(prob(4)) + to_chat(M, "You have the strong urge for some [name]!") + else if(prob(4)) + to_chat(M, "You REALLY crave some [name]!") return STATUS_UPDATE_NONE /datum/reagent/proc/addiction_act_stage5(mob/living/M) var/update_flags = STATUS_UPDATE_NONE if(minor_addiction) - if(prob(6)) - M.AdjustSlowed(3) - to_chat(M, "You feel [pick("tired", "exhausted", "sluggish")].") + if(prob(8)) + to_chat(M, "You can't stop thinking about [name]...") + if(prob(4)) + M.emote(pick("twitch")) else if(prob(6)) to_chat(M, "Your stomach lurches painfully!") M.visible_message("[M] gags and retches!") update_flags |= M.Stun(rand(2,4), FALSE) update_flags |= M.Weaken(rand(2,4), FALSE) - if(prob(8)) - M.emote(pick("twitch", "twitch_s", "shiver")) - if(prob(4)) - to_chat(M, "Your head is killing you!") - if(prob(5)) - to_chat(M, "You feel like you can't live without [name]!") - else if(prob(5)) - to_chat(M, "You would DIE for some [name] right now!") + if(prob(8)) + M.emote(pick("twitch", "twitch_s", "shiver")) + if(prob(4)) + to_chat(M, "Your head is killing you!") + if(prob(5)) + to_chat(M, "You feel like you can't live without [name]!") + else if(prob(5)) + to_chat(M, "You would DIE for some [name] right now!") return update_flags /datum/reagent/proc/fakedeath(mob/living/M) diff --git a/code/modules/reagents/chemistry/reagents/medicine.dm b/code/modules/reagents/chemistry/reagents/medicine.dm index e90789f9d8b..9797951f290 100644 --- a/code/modules/reagents/chemistry/reagents/medicine.dm +++ b/code/modules/reagents/chemistry/reagents/medicine.dm @@ -849,7 +849,7 @@ /datum/reagent/medicine/stimulants name = "Stimulants" id = "stimulants" - description = "Increases run speed and eliminates stuns, can heal minor damage. If overdosed it will deal toxin damage and stun." + description = "An illegal compound that dramatically enhances the body's performance and healing capabilities." color = "#C8A5DC" harmless = FALSE can_synth = FALSE @@ -886,7 +886,7 @@ /datum/reagent/medicine/stimulative_agent name = "Stimulative Agent" id = "stimulative_agent" - description = "An illegal compound that dramatically enhances the body's performance and healing capabilities." + description = "Increases run speed and eliminates stuns, can heal minor damage. If overdosed it will deal toxin damage and be less effective for healing stamina." color = "#C8A5DC" metabolization_rate = 0.5 * REAGENTS_METABOLISM overdose_threshold = 60 diff --git a/code/modules/reagents/chemistry/reagents/misc.dm b/code/modules/reagents/chemistry/reagents/misc.dm index f9a6f974dcf..2b65054f21f 100644 --- a/code/modules/reagents/chemistry/reagents/misc.dm +++ b/code/modules/reagents/chemistry/reagents/misc.dm @@ -603,7 +603,7 @@ name = "Left 4 Zed" id = "left4zednutriment" description = "Unstable nutriment that makes plants mutate more often than usual." - color = "#1A1E4D" // RBG: 26, 30, 77 + color = "#2A1680" // RBG: 42, 128, 22 tox_prob = 25 taste_description = "evolution" diff --git a/code/modules/reagents/chemistry/reagents/toxins.dm b/code/modules/reagents/chemistry/reagents/toxins.dm index b015b75be2a..914fabbc752 100644 --- a/code/modules/reagents/chemistry/reagents/toxins.dm +++ b/code/modules/reagents/chemistry/reagents/toxins.dm @@ -1054,7 +1054,7 @@ id = "atrazine" description = "A herbicidal compound used for destroying unwanted plants." reagent_state = LIQUID - color = "#17002D" + color = "#773E73" //RGB: 47 24 45 lethality = 2 //Atrazine, however, is definitely toxic diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm index abdf0305934..4be84e21d2c 100644 --- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm +++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm @@ -163,8 +163,7 @@ /datum/chemical_reaction/blackpowder_explosion/on_reaction(datum/reagents/holder, created_volume) var/location = get_turf(holder.my_atom) do_sparks(2, 1, location) - spawn(rand(5, 15)) - blackpowder_detonate(holder, created_volume) + addtimer(CALLBACK(null, .proc/blackpowder_detonate, holder, created_volume), rand(5, 15)) /proc/blackpowder_detonate(datum/reagents/holder, created_volume) var/turf/T = get_turf(holder.my_atom) @@ -175,8 +174,7 @@ explosion(T, ex_severe, ex_heavy,ex_light, ex_flash, 1) // If this black powder is in a decal, remove the decal, because it just exploded if(istype(holder.my_atom, /obj/effect/decal/cleanable/dirt/blackpowder)) - spawn(0) - qdel(holder.my_atom) + qdel(holder.my_atom) /datum/chemical_reaction/flash_powder name = "Flash powder" diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm index 1525ed42bd3..5da09309057 100644 --- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm +++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm @@ -146,7 +146,8 @@ /obj/item/reagent_containers/food/snacks/meat/slab, /obj/item/reagent_containers/food/snacks/grown, /obj/item/reagent_containers/food/snacks/grown/mushroom, - /obj/item/reagent_containers/food/snacks/deepfryholder + /obj/item/reagent_containers/food/snacks/deepfryholder, + /obj/item/reagent_containers/food/snacks/monstermeat ) blocked |= typesof(/obj/item/reagent_containers/food/snacks/customizable) diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 01a5e6823a5..f5bc4a3274a 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -39,7 +39,7 @@ reagents.add_reagent("blood", disease_amount, data) add_initial_reagents() -obj/item/reagent_containers/proc/add_initial_reagents() +/obj/item/reagent_containers/proc/add_initial_reagents() if(list_reagents) reagents.add_reagent_list(list_reagents) @@ -50,16 +50,25 @@ obj/item/reagent_containers/proc/add_initial_reagents() if(!QDELETED(src)) ..() + +/obj/item/reagent_containers/proc/add_lid() + if(has_lid) + container_type ^= REFILLABLE | DRAINABLE + update_icon() + +/obj/item/reagent_containers/proc/remove_lid() + if(has_lid) + container_type |= REFILLABLE | DRAINABLE + update_icon() + /obj/item/reagent_containers/attack_self(mob/user) if(has_lid) if(is_open_container()) to_chat(usr, "You put the lid on [src].") - container_type ^= REFILLABLE | DRAINABLE + add_lid() else to_chat(usr, "You take the lid off [src].") - container_type |= REFILLABLE | DRAINABLE - update_icon() - return + remove_lid() /obj/item/reagent_containers/attack(mob/M, mob/user, def_zone) if(user.a_intent == INTENT_HARM) diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index f6980c03620..831a3ddc44f 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -23,13 +23,12 @@ /obj/item/reagent_containers/food/pill/attack(mob/living/carbon/M, mob/user, def_zone) if(!istype(M)) - return 0 + return FALSE bitesize = reagents.total_volume if(M.eat(src, user)) - spawn(0) - qdel(src) - return 1 - return 0 + qdel(src) + return TRUE + return FALSE /obj/item/reagent_containers/food/pill/afterattack(obj/target, mob/user, proximity) if(!proximity) diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 8826efa5eb8..e8862e25584 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -44,7 +44,7 @@ return var/contents_log = reagents.reagent_list.Join(", ") - spray(A) + INVOKE_ASYNC(src, .proc/spray, A) playsound(loc, 'sound/effects/spray2.ogg', 50, 1, -6) user.changeNext_move(CLICK_CD_RANGE*2) @@ -57,24 +57,24 @@ var/attack_log_type = ATKLOG_MOST if(reagents.has_reagent("sacid") || reagents.has_reagent("facid") || reagents.has_reagent("lube")) attack_log_type = ATKLOG_FEW - msg_admin_attack("[key_name_admin(user)] used a spray bottle at [COORD(user)] - Contents: [contents_log] - Temperature: [reagents.chem_temp]K", attack_log_type) + add_attack_logs(user, A, "sprayed [contents_log] at [reagents.chem_temp]K using [src]", attack_log_type) log_game("[key_name(user)] used a spray bottle at [COORD(user)] - Contents: [contents_log] - Temperature: [reagents.chem_temp]K") return -/obj/item/reagent_containers/spray/proc/spray(var/atom/A) +/obj/item/reagent_containers/spray/proc/spray(atom/A) var/obj/effect/decal/chempuff/D = new /obj/effect/decal/chempuff(get_turf(src)) D.create_reagents(amount_per_transfer_from_this) reagents.trans_to(D, amount_per_transfer_from_this, 1/spray_currentrange) D.icon += mix_color_from_reagents(D.reagents.reagent_list) - spawn(0) - for(var/i=0, iJMP)", ATKLOG_FEW) log_game("[key_name(user)] rigged [src.name] with [I.name] for explosion at [COORD(loc)]") - add_attack_logs(user, src, "rigged fuel tank") + add_attack_logs(user, src, "rigged fuel tank with [I.name] for explosion", ATKLOG_FEW) investigate_log("[key_name(user)] rigged [src.name] with [I.name] for explosion at [COORD(loc)]", INVESTIGATE_BOMB) lastrigger = "[key_name(user)]" @@ -159,7 +156,7 @@ else return ..() -obj/structure/reagent_dispensers/fueltank/welder_act(mob/user, obj/item/I) +/obj/structure/reagent_dispensers/fueltank/welder_act(mob/user, obj/item/I) . = TRUE if(!reagents.has_reagent("fuel")) to_chat(user, "[src] is out of fuel!") diff --git a/code/modules/research/designs/biogenerator_designs.dm b/code/modules/research/designs/biogenerator_designs.dm index b70771cb8d3..f01fc5303a9 100644 --- a/code/modules/research/designs/biogenerator_designs.dm +++ b/code/modules/research/designs/biogenerator_designs.dm @@ -88,7 +88,7 @@ id = "weed_killer" build_type = BIOGENERATOR materials = list(MAT_BIOMASS = 50) - build_path = /obj/item/reagent_containers/glass/bottle/killer/weedkiller + build_path = /obj/item/reagent_containers/glass/bottle/nutrient/killer/weedkiller category = list("initial","Botany Chemicals") /datum/design/pest_spray @@ -96,12 +96,12 @@ id = "pest_spray" build_type = BIOGENERATOR materials = list(MAT_BIOMASS = 50) - build_path = /obj/item/reagent_containers/glass/bottle/killer/pestkiller + build_path = /obj/item/reagent_containers/glass/bottle/nutrient/killer/pestkiller category = list("initial","Botany Chemicals") /datum/design/botany_bottle - name = "Empty Bottle" - id = "botany_bottle" + name = "Empty Jug" + id = "botany_jug" build_type = BIOGENERATOR materials = list(MAT_BIOMASS = 5) build_path = /obj/item/reagent_containers/glass/bottle/nutrient/empty diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 75e64a43215..7bd5b3e9c93 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -1094,7 +1094,7 @@ name = "Cyborg Upgrade (Safety Override)" id = "borg_syndicate_module" build_type = MECHFAB - req_tech = list("combat" = 4, "syndicate" = 2) + req_tech = list("combat" = 7, "programming" = 7) build_path = /obj/item/borg/upgrade/syndicate materials = list(MAT_METAL=10000,MAT_GLASS=15000,MAT_DIAMOND = 10000) construction_time = 120 diff --git a/code/modules/research/message_server.dm b/code/modules/research/message_server.dm index 3fe0ef54c0c..009e4810d3e 100644 --- a/code/modules/research/message_server.dm +++ b/code/modules/research/message_server.dm @@ -335,7 +335,7 @@ GLOBAL_DATUM(blackbox, /obj/machinery/blackbox_recorder) return FALSE // don't fuck with the stupid blackbox shit -proc/feedback_set(var/variable,var/value) +/proc/feedback_set(var/variable,var/value) if(IsAdminAdvancedProcCall()) to_chat(usr, "Feedback edit blocked: Advanced ProcCall detected.") message_admins("[key_name(usr)] attempted to edit feedback data via advanced proc-call") @@ -351,7 +351,7 @@ proc/feedback_set(var/variable,var/value) FV.set_value(value) -proc/feedback_inc(var/variable,var/value) +/proc/feedback_inc(var/variable,var/value) if(IsAdminAdvancedProcCall()) to_chat(usr, "Feedback edit blocked: Advanced ProcCall detected.") message_admins("[key_name(usr)] attempted to edit feedback data via advanced proc-call") @@ -367,7 +367,7 @@ proc/feedback_inc(var/variable,var/value) FV.inc(value) -proc/feedback_dec(var/variable,var/value) +/proc/feedback_dec(var/variable,var/value) if(IsAdminAdvancedProcCall()) to_chat(usr, "Feedback edit blocked: Advanced ProcCall detected.") message_admins("[key_name(usr)] attempted to edit feedback data via advanced proc-call") @@ -383,7 +383,7 @@ proc/feedback_dec(var/variable,var/value) FV.dec(value) -proc/feedback_set_details(var/variable,var/details) +/proc/feedback_set_details(var/variable,var/details) if(IsAdminAdvancedProcCall()) to_chat(usr, "Feedback edit blocked: Advanced ProcCall detected.") message_admins("[key_name(usr)] attempted to edit feedback data via advanced proc-call") @@ -400,7 +400,7 @@ proc/feedback_set_details(var/variable,var/details) FV.set_details(details) -proc/feedback_add_details(var/variable,var/details) +/proc/feedback_add_details(var/variable,var/details) if(IsAdminAdvancedProcCall()) to_chat(usr, "Feedback edit blocked: Advanced ProcCall detected.") message_admins("[key_name(usr)] attempted to edit feedback data via advanced proc-call") diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm index 84f15745df6..ce1580d13ce 100644 --- a/code/modules/research/xenobiology/xenobio_camera.dm +++ b/code/modules/research/xenobiology/xenobio_camera.dm @@ -68,6 +68,7 @@ eyeobj = new /mob/camera/aiEye/remote/xenobio(get_turf(src)) eyeobj.origin = src eyeobj.visible_icon = 1 + eyeobj.acceleration = FALSE eyeobj.icon = 'icons/obj/abductor.dmi' eyeobj.icon_state = "camera_target" diff --git a/code/modules/response_team/ert.dm b/code/modules/response_team/ert.dm index f2d559e8b1f..78022bb6d7c 100644 --- a/code/modules/response_team/ert.dm +++ b/code/modules/response_team/ert.dm @@ -33,8 +33,8 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE) to_chat(usr, "Central Command has already dispatched an emergency response team!") return - var/datum/nano_module/ert_manager/E = new() - E.ui_interact(usr) + var/datum/tgui_module/ert_manager/E = new() + E.tgui_interact(usr) /mob/dead/observer/proc/JoinResponseTeam() @@ -209,7 +209,7 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE) var/paranormal_outfit var/borg_path = /mob/living/silicon/robot/ert -/datum/response_team/proc/setSlots(com=1, sec=3, med=3, eng=3, jan=0, par=0, cyb=0) +/datum/response_team/proc/setSlots(com=1, sec=4, med=0, eng=0, jan=0, par=0, cyb=0) slots["Commander"] = com slots["Security"] = sec slots["Medic"] = med @@ -318,3 +318,4 @@ GLOBAL_VAR_INIT(ert_request_answered, FALSE) name = "centcomm bounced radio" frequency = ERT_FREQ icon_state = "radio" + freqlock = TRUE diff --git a/code/modules/response_team/ert_outfits.dm b/code/modules/response_team/ert_outfits.dm index f4ab9561bd5..96825ebdab7 100644 --- a/code/modules/response_team/ert_outfits.dm +++ b/code/modules/response_team/ert_outfits.dm @@ -36,7 +36,7 @@ rt_job = "Emergency Response Team Leader" rt_mob_job = "ERT Commander" - uniform = /obj/item/clothing/under/rank/centcom_officer + uniform = /obj/item/clothing/under/rank/centcom_officer/sensor back = /obj/item/storage/backpack/ert/commander id = /obj/item/card/id/ert/commander @@ -56,12 +56,12 @@ gloves = /obj/item/clothing/gloves/color/black suit = /obj/item/clothing/suit/armor/vest/ert/command glasses = /obj/item/clothing/glasses/sunglasses + mask = /obj/item/clothing/mask/gas/sechailer belt = /obj/item/gun/energy/gun backpack_contents = list( /obj/item/clothing/head/helmet/ert/command = 1, - /obj/item/clothing/mask/gas/sechailer = 1, /obj/item/restraints/handcuffs = 1, /obj/item/storage/lockbox/mindshield = 1, /obj/item/flashlight = 1 @@ -73,6 +73,7 @@ gloves = /obj/item/clothing/gloves/combat suit = /obj/item/clothing/suit/space/hardsuit/ert/commander glasses = /obj/item/clothing/glasses/sunglasses + mask = /obj/item/clothing/mask/gas/sechailer/swat cybernetic_implants = list( /obj/item/organ/internal/cyberimp/eyes/hud/security, /obj/item/organ/internal/cyberimp/chest/nutriment @@ -80,7 +81,6 @@ belt = /obj/item/gun/energy/gun/blueshield/pdw9 backpack_contents = list( - /obj/item/clothing/mask/gas/sechailer/swat = 1, /obj/item/gun/energy/ionrifle/carbine = 1, /obj/item/restraints/handcuffs = 1, /obj/item/clothing/shoes/magboots = 1, @@ -93,11 +93,11 @@ gloves = /obj/item/clothing/gloves/combat suit = /obj/item/clothing/suit/space/hardsuit/ert/commander/gamma glasses = /obj/item/clothing/glasses/night + mask = /obj/item/clothing/mask/gas/sechailer/swat suit_store = /obj/item/gun/energy/gun/blueshield/pdw9 belt = /obj/item/gun/projectile/automatic/pistol/enforcer/lethal backpack_contents = list( - /obj/item/clothing/mask/gas/sechailer/swat = 1, /obj/item/restraints/handcuffs = 1, /obj/item/storage/lockbox/mindshield = 1, /obj/item/gun/energy/ionrifle/carbine = 1, @@ -107,7 +107,7 @@ cybernetic_implants = list( /obj/item/organ/internal/cyberimp/chest/nutriment/plus, /obj/item/organ/internal/cyberimp/eyes/hud/security, - /obj/item/organ/internal/cyberimp/brain/anti_stun, + /obj/item/organ/internal/cyberimp/brain/anti_stun/hardened, /obj/item/organ/internal/cyberimp/arm/flash ) @@ -117,7 +117,7 @@ name = "RT Security" rt_job = "Emergency Response Team Officer" rt_mob_job = "ERT Security" - uniform = /obj/item/clothing/under/rank/security + uniform = /obj/item/clothing/under/rank/security/sensor back = /obj/item/storage/backpack/ert/security belt = /obj/item/storage/belt/security/response_team pda = /obj/item/pda/heads/ert/security @@ -130,12 +130,12 @@ suit = /obj/item/clothing/suit/armor/vest/ert/security suit_store = /obj/item/gun/energy/gun/advtaser glasses = /obj/item/clothing/glasses/hud/security/sunglasses + mask = /obj/item/clothing/mask/gas/sechailer r_hand = /obj/item/gun/energy/laser backpack_contents = list( /obj/item/clothing/head/helmet/ert/security = 1, - /obj/item/clothing/mask/gas/sechailer = 1, /obj/item/storage/box/zipties = 1, /obj/item/storage/box/teargas = 1, /obj/item/flashlight/seclite = 1 @@ -149,6 +149,7 @@ suit = /obj/item/clothing/suit/space/hardsuit/ert/security suit_store = /obj/item/gun/energy/gun/blueshield/pdw9 glasses = /obj/item/clothing/glasses/sunglasses + mask = /obj/item/clothing/mask/gas/sechailer r_hand = /obj/item/gun/projectile/automatic/lasercarbine @@ -159,11 +160,9 @@ ) backpack_contents = list( - /obj/item/clothing/mask/gas/sechailer = 1, /obj/item/clothing/shoes/magboots = 1, /obj/item/storage/box/handcuffs = 1, - /obj/item/storage/box/teargas = 1, - /obj/item/grenade/flashbang = 1, + /obj/item/grenade/flashbang = 2, /obj/item/ammo_box/magazine/laser = 2 ) @@ -175,13 +174,13 @@ belt = /obj/item/storage/belt/security/response_team_gamma suit_store = /obj/item/gun/energy/gun/nuclear glasses = /obj/item/clothing/glasses/night + mask = /obj/item/clothing/mask/gas/sechailer/swat l_pocket = /obj/item/restraints/legcuffs/bola/energy r_pocket = /obj/item/extinguisher/mini r_hand = /obj/item/gun/energy/immolator/multi backpack_contents = list( - /obj/item/clothing/mask/gas/sechailer/swat = 1, /obj/item/storage/box/handcuffs = 1, /obj/item/storage/box/flashbangs = 1, /obj/item/whetstone = 1, @@ -191,9 +190,9 @@ cybernetic_implants = list( /obj/item/organ/internal/cyberimp/chest/nutriment/plus, /obj/item/organ/internal/cyberimp/eyes/hud/security, - /obj/item/organ/internal/cyberimp/brain/anti_stun, + /obj/item/organ/internal/cyberimp/brain/anti_stun/hardened, /obj/item/organ/internal/cyberimp/arm/telebaton, - /obj/item/organ/internal/cyberimp/chest/reviver + /obj/item/organ/internal/cyberimp/chest/reviver/hardened ) @@ -217,12 +216,12 @@ suit = /obj/item/clothing/suit/space/hardsuit/ert/engineer suit_store = /obj/item/tank/emergency_oxygen/engi glasses = /obj/item/clothing/glasses/meson + mask = /obj/item/clothing/mask/gas l_pocket = /obj/item/gun/energy/gun/mini r_pocket = /obj/item/melee/classic_baton/telescopic backpack_contents = list( - /obj/item/clothing/mask/gas = 1, /obj/item/t_scanner = 1, /obj/item/stack/sheet/glass/fifty = 1, /obj/item/stack/sheet/metal/fifty = 1, @@ -237,6 +236,7 @@ suit = /obj/item/clothing/suit/space/hardsuit/ert/engineer/gamma suit_store = /obj/item/tank/emergency_oxygen/engi glasses = /obj/item/clothing/glasses/meson + mask = /obj/item/clothing/mask/gas cybernetic_implants = list( /obj/item/organ/internal/cyberimp/eyes/shield, /obj/item/organ/internal/cyberimp/chest/nutriment @@ -245,7 +245,6 @@ r_pocket = /obj/item/melee/classic_baton/telescopic backpack_contents = list( - /obj/item/clothing/mask/gas = 1, /obj/item/rcd/preloaded = 1, /obj/item/rcd_ammo = 3, /obj/item/gun/energy/gun = 1 @@ -259,12 +258,12 @@ suit = /obj/item/clothing/suit/space/hardsuit/ert/engineer/gamma suit_store = /obj/item/gun/energy/gun/blueshield/pdw9 glasses = /obj/item/clothing/glasses/meson/night + mask = /obj/item/clothing/mask/gas/sechailer/swat l_pocket = /obj/item/t_scanner/extended_range r_pocket = /obj/item/melee/classic_baton/telescopic backpack_contents = list( - /obj/item/clothing/mask/gas/sechailer/swat = 1, /obj/item/rcd/combat = 1, /obj/item/rcd_ammo/large = 3 ) @@ -272,7 +271,7 @@ cybernetic_implants = list( /obj/item/organ/internal/cyberimp/chest/nutriment/plus, /obj/item/organ/internal/cyberimp/eyes/hud/security, - /obj/item/organ/internal/cyberimp/brain/anti_stun, + /obj/item/organ/internal/cyberimp/brain/anti_stun/hardened, /obj/item/organ/internal/cyberimp/eyes/shield, /obj/item/organ/internal/cyberimp/arm/toolset ) @@ -353,6 +352,7 @@ gloves = /obj/item/clothing/gloves/combat suit = /obj/item/clothing/suit/space/hardsuit/ert/medical/gamma glasses = /obj/item/clothing/glasses/night + mask = /obj/item/clothing/mask/gas/sechailer/swat suit_store = /obj/item/gun/energy/gun/blueshield/pdw9 belt = /obj/item/defibrillator/compact/loaded @@ -361,7 +361,6 @@ r_pocket = /obj/item/reagent_containers/hypospray/autoinjector backpack_contents = list( - /obj/item/clothing/mask/gas/sechailer/swat = 1, /obj/item/bodyanalyzer/advanced = 1, /obj/item/extinguisher/mini = 1, /obj/item/roller = 1, @@ -375,7 +374,7 @@ /obj/item/organ/internal/cyberimp/arm/medibeam, /obj/item/organ/internal/cyberimp/chest/nutriment/plus, /obj/item/organ/internal/cyberimp/eyes/hud/medical, - /obj/item/organ/internal/cyberimp/brain/anti_stun + /obj/item/organ/internal/cyberimp/brain/anti_stun/hardened ) //////////////////// PARANORMAL /////////////////// @@ -390,11 +389,11 @@ shoes = /obj/item/clothing/shoes/combat l_ear = /obj/item/radio/headset/ert/alt glasses = /obj/item/clothing/glasses/hud/security/sunglasses + mask = /obj/item/clothing/mask/gas/sechailer/swat belt = /obj/item/storage/belt/security/response_team id = /obj/item/card/id/centcom pda = /obj/item/pda/centcom backpack_contents = list( - /obj/item/clothing/mask/gas/sechailer/swat = 1, /obj/item/storage/box/zipties = 1, /obj/item/flashlight/seclite = 1 ) @@ -435,7 +434,7 @@ cybernetic_implants = list( /obj/item/organ/internal/cyberimp/chest/nutriment/plus, /obj/item/organ/internal/cyberimp/eyes/hud/security, - /obj/item/organ/internal/cyberimp/brain/anti_stun + /obj/item/organ/internal/cyberimp/brain/anti_stun/hardened ) //////////////////// JANITORIAL /////////////////// @@ -444,7 +443,7 @@ name = "RT Janitor" rt_job = "Emergency Response Team Janitor" rt_mob_job = "ERT Janitor" - uniform = /obj/item/clothing/under/color/purple + uniform = /obj/item/clothing/under/color/purple/sensor back = /obj/item/storage/backpack/ert/janitor belt = /obj/item/storage/belt/janitor/full gloves = /obj/item/clothing/gloves/color/yellow @@ -500,5 +499,6 @@ ) cybernetic_implants = list( - /obj/item/organ/internal/cyberimp/arm/advmop + /obj/item/organ/internal/cyberimp/arm/advmop, + /obj/item/organ/internal/cyberimp/brain/anti_stun/hardened ) diff --git a/code/modules/ruins/lavalandruin_code/animal_hospital.dm b/code/modules/ruins/lavalandruin_code/animal_hospital.dm index 1cf21d5a890..18ea13770a6 100644 --- a/code/modules/ruins/lavalandruin_code/animal_hospital.dm +++ b/code/modules/ruins/lavalandruin_code/animal_hospital.dm @@ -6,9 +6,10 @@ name = "broken rejuvenation pod" desc = "A small sleeper typically used to instantly restore minor wounds. This one seems broken, and its occupant is comatose." mob_name = "a translocated vet" - flavour_text = "What...? Where are you? Where are the others? This is still the animal hospital - you should know, you've been an intern here for weeks - but \ + description = "You are an intern working in an animal hospital that suddenly got transported to lavaland. Good luck." + flavour_text = "What...? Where are you? Where are the others? This is still the animal hospital - you should know, you've been an intern here for weeks - but \ everyone's gone. One of the cats scratched you just a few minutes ago. That's why you were in the pod - to heal the scratch. The scabs are still fresh; you see them right now. So where is \ - everyone? Where did they go? What happened to the hospital? And is that smoke you smell? You need to find someone else. Maybe they can tell you what happened." + everyone? Where did they go? What happened to the hospital? And is that smoke you smell? You need to find someone else. Maybe they can tell you what happened." assignedrole = "Translocated Vet" allow_species_pick = TRUE diff --git a/code/modules/ruins/lavalandruin_code/ash_walker_den.dm b/code/modules/ruins/lavalandruin_code/ash_walker_den.dm index 62b2343f10a..c173097fcad 100644 --- a/code/modules/ruins/lavalandruin_code/ash_walker_den.dm +++ b/code/modules/ruins/lavalandruin_code/ash_walker_den.dm @@ -67,9 +67,10 @@ anchored = FALSE move_resist = MOVE_FORCE_NORMAL density = FALSE - flavour_text = "You are an ash walker. Your tribe worships the Necropolis. The wastes are sacred ground, its monsters a blessed bounty. \ - You have seen lights in the distance... they foreshadow the arrival of outsiders that seek to tear apart the Necropolis and its domain. Fresh sacrifices for your nest. \ -
You are free to attack miners and other outsiders. DO NOT leave Lavaland without admin permission! DO NOT attack the mining outpost without being provoked.
" + important_info = "Do not leave Lavaland without admin permission. Do not attack the mining outpost without being provoked." + description = "You are an ashwalker, a native inhabitant of Lavaland. Try to survive with nothing but spears and other tribal technology. Bring dead bodies back to your tendril to create more of your kind. You are free to attack miners and other outsiders." + flavour_text = "Your tribe worships the Necropolis. The wastes are sacred ground, its monsters a blessed bounty. \ + You have seen lights in the distance... they foreshadow the arrival of outsiders that seek to tear apart the Necropolis and its domain. Fresh sacrifices for your nest." assignedrole = "Ash Walker" /obj/effect/mob_spawn/human/ash_walker/special(mob/living/carbon/human/new_spawn) diff --git a/code/modules/ruins/lavalandruin_code/hermit.dm b/code/modules/ruins/lavalandruin_code/hermit.dm index a28f30b9ed1..93056ee1d9a 100644 --- a/code/modules/ruins/lavalandruin_code/hermit.dm +++ b/code/modules/ruins/lavalandruin_code/hermit.dm @@ -10,7 +10,8 @@ random = TRUE allow_species_pick = TRUE mob_species = /datum/species/human - flavour_text = "You've been stranded in this godless prison of a planet for longer than you can remember. Each day you barely scrape by, and between the terrible \ + description = "You are a single survivor stranded on lavaland in a makeshift shelter. Try to survive with barely any equipment. For when miner is just too boring." + flavour_text = "You've been stranded in this godless prison of a planet for longer than you can remember. Each day you barely scrape by, and between the terrible \ conditions of your makeshift shelter, the hostile creatures, and the ash drakes swooping down from the cloudless skies, all you can wish for is the feel of soft grass between your toes and \ the fresh air of Earth. These thoughts are dispelled by yet another recollection of how you got here... " assignedrole = "Hermit" @@ -22,28 +23,28 @@ if(1) flavour_text += "you were a [pick("arms dealer", "shipwright", "docking manager")]'s assistant on a small trading station several sectors from here. Raiders attacked, and there was \ only one pod left when you got to the escape bay. You took it and launched it alone, and the crowd of terrified faces crowding at the airlock door as your pod's engines burst to \ - life and sent you to this hell are forever branded into your memory." + life and sent you to this hell are forever branded into your memory." outfit.uniform = /obj/item/clothing/under/assistantformal outfit.shoes = /obj/item/clothing/shoes/black outfit.back = /obj/item/storage/backpack if(2) flavour_text += "you're an exile from the Tiger Cooperative. Their technological fanaticism drove you to question the power and beliefs of the Exolitics, and they saw you as a \ heretic and subjected you to hours of horrible torture. You were hours away from execution when a high-ranking friend of yours in the Cooperative managed to secure you a pod, \ - scrambled its destination's coordinates, and launched it. You awoke from stasis when you landed and have been surviving - barely - ever since.
" + scrambled its destination's coordinates, and launched it. You awoke from stasis when you landed and have been surviving - barely - ever since." outfit.uniform = /obj/item/clothing/under/color/orange outfit.shoes = /obj/item/clothing/shoes/orange outfit.back = /obj/item/storage/backpack if(3) flavour_text += "you were a doctor on one of Nanotrasen's space stations, but you left behind that damn corporation's tyranny and everything it stood for. From a metaphorical hell \ - to a literal one, you find yourself nonetheless missing the recycled air and warm floors of what you left behind... but you'd still rather be here than there." + to a literal one, you find yourself nonetheless missing the recycled air and warm floors of what you left behind... but you'd still rather be here than there." outfit.uniform = /obj/item/clothing/under/rank/medical outfit.suit = /obj/item/clothing/suit/storage/labcoat outfit.back = /obj/item/storage/backpack/medic outfit.shoes = /obj/item/clothing/shoes/black if(4) - flavour_text += "you were always joked about by your friends for \"not playing with a full deck\", as they so kindly put it. It seems that they were right when you, on a tour \ + flavour_text += "you were always joked about by your friends for \"not playing with a full deck\", as they so kindly put it. It seems that they were right when you, on a tour \ at one of Nanotrasen's state-of-the-art research facilities, were in one of the escape pods alone and saw the red button. It was big and shiny, and it caught your eye. You pressed \ - it, and after a terrifying and fast ride for days, you landed here. You've had time to wisen up since then, and you think that your old friends wouldn't be laughing now." + it, and after a terrifying and fast ride for days, you landed here. You've had time to wisen up since then, and you think that your old friends wouldn't be laughing now." outfit.uniform = /obj/item/clothing/under/color/grey/glorf outfit.shoes = /obj/item/clothing/shoes/black outfit.back = /obj/item/storage/backpack diff --git a/code/modules/ruins/lavalandruin_code/seed_vault.dm b/code/modules/ruins/lavalandruin_code/seed_vault.dm index 2c999a7ce29..1a5e863c52f 100644 --- a/code/modules/ruins/lavalandruin_code/seed_vault.dm +++ b/code/modules/ruins/lavalandruin_code/seed_vault.dm @@ -18,9 +18,10 @@ roundstart = FALSE death = FALSE mob_species = /datum/species/diona/pod - flavour_text = "You are a sentient ecosystem, an example of the mastery over life that your creators possessed. Your masters, benevolent as they were, created uncounted \ + description = "You are a diona on Lavaland with access to a full botany setup. Perfect to mess around with plants in peace." + flavour_text = "You are a sentient ecosystem, an example of the mastery over life that your creators possessed. Your masters, benevolent as they were, created uncounted \ seed vaults and spread them across the universe to every planet they could chart. You are in one such seed vault. Your goal is to cultivate and spread life wherever it will go while waiting \ - for contact from your creators. Estimated time of last contact: Deployment, 5x10^3 millennia ago." + for contact from your creators. Estimated time of last contact: Deployment, 5x10^3 millennia ago." assignedrole = "Lifebringer" /obj/effect/mob_spawn/human/seed_vault/special(mob/living/new_spawn) diff --git a/code/modules/ruins/lavalandruin_code/syndicate_base.dm b/code/modules/ruins/lavalandruin_code/syndicate_base.dm index d053e139f61..1e745e8d3ed 100644 --- a/code/modules/ruins/lavalandruin_code/syndicate_base.dm +++ b/code/modules/ruins/lavalandruin_code/syndicate_base.dm @@ -28,8 +28,10 @@ death = FALSE icon = 'icons/obj/cryogenic2.dmi' icon_state = "sleeper_s" - flavour_text = "You are a syndicate agent, employed in a top secret research facility developing biological weapons. Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. Continue your research as best you can, and try to keep a low profile. The base is rigged with explosives, do not abandon it or let it fall into enemy hands! \ -
You are free to attack anyone not aligned with the Syndicate in the vicinity of your base. DO NOT work against Syndicate personnel (such as traitors or nuclear operatives). You may work with or against non-Syndicate antagonists on a case-by-case basis. DO NOT leave your base without admin permission." + important_info = "Do not work against Syndicate personnel (such as traitors or nuclear operatives). You may work with or against non-Syndicate antagonists on a case-by-case basis. Do not leave your base without admin permission." + description = "Experiment with deadly chems and viruses in peace or help any visiting Syndicate Agent." + flavour_text = "You are a syndicate agent, employed in a top secret research facility developing biological weapons. Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. Continue your research as best you can, and try to keep a low profile. The base is rigged with explosives, do not abandon it or let it fall into enemy hands!\ + It's been made clear to you that the Syndicate will make you regret it if you disappoint them." outfit = /datum/outfit/lavaland_syndicate assignedrole = "Lavaland Syndicate" del_types = list() // Necessary to prevent del_types from removing radio! @@ -59,13 +61,13 @@ /obj/effect/mob_spawn/human/lavaland_syndicate/comms name = "Syndicate Comms Agent sleeper" mob_name = "Syndicate Comms Agent" - flavour_text = "You are a syndicate agent, employed in a top secret research facility developing biological weapons. Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. Monitor enemy activity as best you can, and try to keep a low profile. Do not abandon the base. Use the communication equipment to provide support to any field agents, and sow disinformation to throw Nanotrasen off your trail. Do not let the base fall into enemy hands! \ -
You are free to attack anyone not aligned with the Syndicate in the vicinity of your base. DO NOT work against Syndicate personnel (such as traitors or nuclear operatives). You may work with or against non-Syndicate antagonists on a case-by-case basis. DO NOT leave your base without admin permission." + important_info = "Do not work against Syndicate personnel (such as traitors or nuclear operatives). You may work with or against non-Syndicate antagonists on a case-by-case basis. Do not leave your base without admin permission. Do not reveal the existence of yourself to NT." + description = "Monitor comms and cameras and try to assist any agents on station while keeping your existence a secret." + flavour_text = "You are a syndicate agent, employed in a top secret research facility developing biological weapons. Unfortunately, your hated enemy, Nanotrasen, has begun mining in this sector. Monitor enemy activity as best you can, and try to keep a low profile." outfit = /datum/outfit/lavaland_syndicate/comms /obj/effect/mob_spawn/human/lavaland_syndicate/comms/space - flavour_text = "You are a syndicate agent, assigned to a small listening post station situated near your hated enemy's top secret research facility: Space Station 13. Monitor enemy activity as best you can, and try to keep a low profile. Do not abandon the base. Use the communication equipment to provide support to any field agents, and sow disinformation to throw Nanotrasen off your trail. Do not let the base fall into enemy hands! \ -
You are free to attack anyone not aligned with the Syndicate in the vicinity of your base. DO NOT work against Syndicate personnel (such as traitors or nuclear operatives). You may work with or against non-Syndicate antagonists on a case-by-case basis. DO NOT leave your base without admin permission." + flavour_text = "You are a syndicate agent, employed in a small listening outpost. You'd be bored to death if you couldn't listen in on those NT idiots mess up all the time." /obj/effect/mob_spawn/human/lavaland_syndicate/comms/space/Initialize(mapload) . = ..() diff --git a/code/modules/security_levels/keycard authentication.dm b/code/modules/security_levels/keycard authentication.dm index 87723701281..e51355e89bb 100644 --- a/code/modules/security_levels/keycard authentication.dm +++ b/code/modules/security_levels/keycard authentication.dm @@ -4,17 +4,17 @@ icon = 'icons/obj/monitors.dmi' icon_state = "auth_off" - var/active = 0 //This gets set to 1 on all devices except the one where the initial request was made. - var/event = "" - var/screen = 1 + var/active = FALSE // This gets set to TRUE on all devices except the one where the initial request was made. + var/event + var/swiping = FALSE // on swiping screen? var/list/ert_chosen = list() - var/confirmed = 0 //This variable is set by the device that confirms the request. - var/confirm_delay = 20 //(2 seconds) - var/busy = 0 //Busy when waiting for authentication or an event request has been sent from this device. + var/confirmed = FALSE // This variable is set by the device that confirms the request. + var/confirm_delay = 5 SECONDS // time allowed for a second person to confirm a swipe. + var/busy = FALSE // Busy when waiting for authentication or an event request has been sent from this device. var/obj/machinery/keycard_auth/event_source var/mob/event_triggered_by var/mob/event_confirmed_by - var/ert_reason = "Reason for ERT" + var/ert_reason anchored = 1 use_power = IDLE_POWER_USE @@ -35,16 +35,19 @@ return if(istype(W, /obj/item/card/id) || istype(W, /obj/item/pda)) if(check_access(W)) - if(active == 1) + if(active) //This is not the device that made the initial request. It is the device confirming the request. if(event_source) - event_source.confirmed = 1 + event_source.confirmed = TRUE event_source.event_confirmed_by = usr - else if(screen == 2) - if(event == "Emergency Response Team" && ert_reason == "Reason for ERT") - to_chat(user, "Supply a reason for calling the ERT first!") + SStgui.update_uis(event_source) + SStgui.update_uis(src) + else if(swiping) + if(event == "Emergency Response Team" && !ert_reason) + to_chat(user, "Supply a reason for calling the ERT first!") return event_triggered_by = usr + SStgui.update_uis(src) broadcast_request() //This is the device making the initial event request. It needs to broadcast to other devices else to_chat(user, "Access denied.") @@ -59,57 +62,58 @@ stat |= NOPOWER /obj/machinery/keycard_auth/attack_ghost(mob/user) - ui_interact(user) + tgui_interact(user) -/obj/machinery/keycard_auth/attack_hand(mob/user as mob) +/obj/machinery/keycard_auth/attack_hand(mob/user) if(..()) - return 1 - ui_interact(user) + return TRUE + tgui_interact(user) -/obj/machinery/keycard_auth/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - if(busy) - to_chat(user, "This device is busy.") - return - - user.set_machine(src) - - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/keycard_auth/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = TRUE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "keycard_auth.tmpl", "Keycard Authentication Device UI", 540, 320) + ui = new(user, src, ui_key, "KeycardAuth", name, 540, 300, master_ui, state) ui.open() -/obj/machinery/keycard_auth/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - data["screen"] = screen - data["event"] = event - data["ertreason"] = ert_reason + +/obj/machinery/keycard_auth/tgui_data() + var/list/data = list() + data["redAvailable"] = GLOB.security_level == SEC_LEVEL_RED ? FALSE : TRUE + data["swiping"] = swiping + data["busy"] = busy + data["event"] = active && event_source && event_source.event ? event_source.event : event + data["ertreason"] = active && event_source && event_source.ert_reason ? event_source.ert_reason : ert_reason + data["isRemote"] = active ? TRUE : FALSE + data["hasSwiped"] = event_triggered_by ? TRUE : FALSE + data["hasConfirm"] = event_confirmed_by || (active && event_source && event_source.event_confirmed_by) ? TRUE : FALSE return data -/obj/machinery/keycard_auth/Topic(href, href_list) +/obj/machinery/keycard_auth/tgui_act(action, params) if(..()) - return 1 - - if(busy) - to_chat(usr, "This device is busy.") return + if(busy) + to_chat(usr, "This device is busy.") + return + if(!allowed(usr)) + to_chat(usr, "Access denied.") + return + . = TRUE + switch(action) + if("ert") + ert_reason = stripped_input(usr, "Reason for ERT Call:", "", "") + if("reset") + reset() + if("triggerevent") + event = params["triggerevent"] + swiping = TRUE - if(href_list["triggerevent"]) - event = href_list["triggerevent"] - screen = 2 - if(href_list["reset"]) - reset() - if(href_list["ert"]) - ert_reason = stripped_input(usr, "Reason for ERT Call:", "", "") - - SSnanoui.update_uis(src) add_fingerprint(usr) - return /obj/machinery/keycard_auth/proc/reset() - active = 0 - event = "" - screen = 1 - confirmed = 0 + active = FALSE + event = null + swiping = FALSE + confirmed = FALSE event_source = null icon_state = "auth_off" event_triggered_by = null @@ -125,7 +129,7 @@ sleep(confirm_delay) if(confirmed) - confirmed = 0 + confirmed = FALSE trigger_event(event) log_game("[key_name(event_triggered_by)] triggered and [key_name(event_confirmed_by)] confirmed event [event]") message_admins("[key_name_admin(event_triggered_by)] triggered and [key_name_admin(event_confirmed_by)] confirmed event [event]", 1) @@ -135,16 +139,17 @@ if(stat & (BROKEN|NOPOWER)) return event_source = source - busy = 1 - active = 1 + busy = TRUE + active = TRUE + SStgui.update_uis(src) icon_state = "auth_on" sleep(confirm_delay) event_source = null icon_state = "auth_off" - active = 0 - busy = 0 + active = FALSE + busy = FALSE /obj/machinery/keycard_auth/proc/trigger_event() switch(event) @@ -178,7 +183,7 @@ if(fullmin_count) GLOB.ert_request_answered = TRUE ERT_Announce(ert_reason , event_triggered_by, 0) - ert_reason = "Reason for ERT" + ert_reason = null feedback_inc("alert_keycard_auth_ert",1) spawn(3000) if(!GLOB.ert_request_answered) diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index aa0a21a165a..3fb173e7ac2 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -301,6 +301,7 @@ spawn(0) D.open() */ //Leaving this here incase someone decides to port -tg-'s escape shuttle stuff: + // This basically opens a big-ass row of blast doors when the shuttle arrives at centcom /obj/docking_port/mobile/pod name = "escape pod" diff --git a/code/modules/shuttle/ert.dm b/code/modules/shuttle/ert.dm index 5168ce89278..ddb7bb343b6 100644 --- a/code/modules/shuttle/ert.dm +++ b/code/modules/shuttle/ert.dm @@ -6,13 +6,12 @@ resistance_flags = INDESTRUCTIBLE flags = NODECONSTRUCT -/obj/machinery/computer/shuttle/ert/Topic(href, href_list) - if(href_list["move"]) +/obj/machinery/computer/shuttle/ert/can_call_shuttle(mob/user, action) + if(action == "move") var/authorized_roles = list(SPECIAL_ROLE_ERT, SPECIAL_ROLE_DEATHSQUAD) - if(!((usr.mind?.assigned_role in authorized_roles) || is_admin(usr))) - message_admins("Potential ERT shuttle hijack, ERT shuttle moved by unauthorized user: [key_name_admin(usr)]") - ..() - + if(!((user.mind?.assigned_role in authorized_roles) || is_admin(user))) + message_admins("Potential ERT shuttle hijack, ERT shuttle moved by unauthorized user: [key_name_admin(user)]") + return TRUE /obj/machinery/computer/camera_advanced/shuttle_docker/ert name = "specops navigation computer" diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index cfd3ab8e6f2..86cfe2a7444 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -727,13 +727,13 @@ name = "Shuttle Console" icon_screen = "shuttle" icon_keyboard = "tech_key" - req_access = list( ) + req_access = list() circuit = /obj/item/circuitboard/shuttle var/shuttleId var/possible_destinations = "" var/admin_controlled var/max_connect_range = 7 - var/docking_request = 0 + var/moved = FALSE //workaround for nukie shuttle, hope I find a better way to do this... /obj/machinery/computer/shuttle/New(location, obj/item/circuitboard/shuttle/C) ..() @@ -773,21 +773,20 @@ return connect() add_fingerprint(user) - ui_interact(user) + tgui_interact(user) -/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 = SSshuttle.getShuttle(shuttleId) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/machinery/computer/shuttle/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state) + ui = SStgui.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 = new(user, src, ui_key, "ShuttleConsole", name, 350, 150, master_ui, state) ui.open() -/obj/machinery/computer/shuttle/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] +/obj/machinery/computer/shuttle/tgui_data(mob/user) + var/list/data = list() var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId) data["status"] = M ? M.getStatusText() : null if(M) - data["shuttle"] = 1 + data["shuttle"] = TRUE //this should just be boolean, right? var/list/docking_ports = list() data["docking_ports"] = docking_ports var/list/options = params2list(possible_destinations) @@ -799,34 +798,35 @@ 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 - return data -/obj/machinery/computer/shuttle/Topic(href, href_list) - if(..()) - return 1 - +/obj/machinery/computer/shuttle/tgui_act(action, params) + if(..()) //we can't actually interact, so no action + return TRUE if(!allowed(usr)) to_chat(usr, "Access denied.") - return - + return TRUE + if(!can_call_shuttle(usr, action)) + return TRUE var/list/options = params2list(possible_destinations) - if(href_list["move"]) - if(!options.Find(href_list["move"])) //I see you're trying Href exploits, I see you're failing, I SEE ADMIN WARNING. - // Seriously, though, NEVER trust a Topic with something like this. Ever. - // Sidenote for whoever did this last. Why did you set it to echo whatever the user entered to admin chat? You solved one exploit and created another. + if(action == "move") + var/destination = params["move"] + if(!options.Find(destination))//figure out if this translation works message_admins("EXPLOIT: [ADMIN_LOOKUPFLW(usr)] attempted to move [src] to an invalid location! [ADMIN_COORDJMP(src)]") return - switch(SSshuttle.moveShuttle(shuttleId, href_list["move"], 1, usr)) + switch(SSshuttle.moveShuttle(shuttleId, destination, TRUE, usr)) if(0) atom_say("Shuttle departing! Please stand away from the doors.") usr.create_log(MISC_LOG, "used [src] to call the [shuttleId] shuttle") + if(!moved) + moved = TRUE + add_fingerprint(usr) + return TRUE if(1) to_chat(usr, "Invalid shuttle requested.") else to_chat(usr, "Unable to comply.") - return 1 + /obj/machinery/computer/shuttle/emag_act(mob/user) if(!emagged) @@ -834,6 +834,10 @@ emagged = 1 to_chat(user, "You fried the consoles ID checking system.") +//for restricting when the computer can be used, needed for some console subtypes. +/obj/machinery/computer/shuttle/proc/can_call_shuttle(mob/user, action) + return TRUE + /obj/machinery/computer/shuttle/ferry name = "transport ferry console" circuit = /obj/item/circuitboard/ferry @@ -844,25 +848,23 @@ /obj/machinery/computer/shuttle/ferry/request name = "ferry console" circuit = /obj/item/circuitboard/ferry/request - var/cooldown //prevents spamming admins + var/next_request //to prevent spamming admins possible_destinations = "ferry_home" - admin_controlled = 1 + admin_controlled = TRUE resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF -/obj/machinery/computer/shuttle/ferry/request/Topic(href, href_list) - if(..()) - return 1 - if(href_list["request"]) - if(cooldown) +/obj/machinery/computer/shuttle/ferry/request/tgui_act(action, params) + if(..()) // Note that the parent handels normal shuttle movement on top of security checks + return + if(action == "request") + if(world.time < next_request) return - cooldown = 1 + next_request = world.time + 60 SECONDS //1 minute cooldown 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 - SSnanoui.update_uis(src) - spawn(600) //One minute cooldown - cooldown = 0 + return TRUE + /obj/machinery/computer/shuttle/white_ship name = "White Ship Console" diff --git a/code/modules/shuttle/syndicate.dm b/code/modules/shuttle/syndicate.dm index f9ec738b167..1ff2959ff08 100644 --- a/code/modules/shuttle/syndicate.dm +++ b/code/modules/shuttle/syndicate.dm @@ -11,20 +11,18 @@ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF flags = NODECONSTRUCT var/challenge = FALSE - var/moved = FALSE /obj/machinery/computer/shuttle/syndicate/recall name = "syndicate shuttle recall terminal" circuit = /obj/item/circuitboard/shuttle/syndicate/recall possible_destinations = "syndicate_away" -/obj/machinery/computer/shuttle/syndicate/Topic(href, href_list) - if(href_list["move"]) +/obj/machinery/computer/shuttle/syndicate/can_call_shuttle(user, action) + if(action == "move") if(challenge && world.time < SYNDICATE_CHALLENGE_TIMER) - to_chat(usr, "You've issued a combat challenge to the station! You've got to give them at least [round(((SYNDICATE_CHALLENGE_TIMER - world.time) / 10) / 60)] more minutes to allow them to prepare.") - return 0 - moved = TRUE - ..() + to_chat(user, "You've issued a combat challenge to the station! You've got to give them at least [round(((SYNDICATE_CHALLENGE_TIMER - world.time) / 10) / 60)] more minutes to allow them to prepare.") + return FALSE + return TRUE /obj/machinery/computer/shuttle/syndicate/drop_pod name = "syndicate assault pod control" @@ -35,11 +33,11 @@ shuttleId = "steel_rain" possible_destinations = null -/obj/machinery/computer/shuttle/syndicate/drop_pod/Topic(href, href_list) - if(href_list["move"]) +/obj/machinery/computer/shuttle/syndicate/drop_pod/can_call_shuttle(user, action) + if(action == "move") if(z != level_name_to_num(CENTCOMM)) - to_chat(usr, "Pods are one way!") - return 0 + to_chat(user, "Pods are one way!") + return FALSE ..() /obj/machinery/computer/shuttle/sst diff --git a/code/modules/spacepods/construction.dm b/code/modules/spacepods/construction.dm index be2998fc0a3..d24758c3b19 100644 --- a/code/modules/spacepods/construction.dm +++ b/code/modules/spacepods/construction.dm @@ -222,7 +222,7 @@ // EOF ) - spawn_result(mob/user as mob) - ..() - feedback_inc("spacepod_created",1) - return +/datum/construction/reversible2/pod/spawn_result(mob/user as mob) + ..() + feedback_inc("spacepod_created",1) + return diff --git a/code/modules/station_goals/station_goal.dm b/code/modules/station_goals/station_goal.dm index 47f65ea2553..7f13651168b 100644 --- a/code/modules/station_goals/station_goal.dm +++ b/code/modules/station_goals/station_goal.dm @@ -13,7 +13,7 @@ /datum/station_goal/proc/send_report() GLOB.priority_announcement.Announce("Priority Nanotrasen directive received. Project \"[name]\" details inbound.", "Incoming Priority Message", 'sound/AI/commandreport.ogg') - print_command_report(get_report(), "Nanotrasen Directive [pick(GLOB.phonetic_alphabet)] \Roman[rand(1,50)]") + print_command_report(get_report(), "Nanotrasen Directive [pick(GLOB.phonetic_alphabet)] \Roman[rand(1,50)]", FALSE) on_report() /datum/station_goal/proc/on_report() diff --git a/code/modules/surgery/organs/augments_internal.dm b/code/modules/surgery/organs/augments_internal.dm index 19ff7fa37d8..b211d903e8a 100644 --- a/code/modules/surgery/organs/augments_internal.dm +++ b/code/modules/surgery/organs/augments_internal.dm @@ -1,5 +1,3 @@ -#define STUN_SET_AMOUNT 2 - /obj/item/organ/internal/cyberimp name = "cybernetic implant" desc = "a state-of-the-art implant that improves a baseline's functionality" @@ -128,15 +126,16 @@ implant_color = "#FFFF00" slot = "brain_antistun" origin_tech = "materials=5;programming=4;biotech=5" + var/stun_max_amount = 2 /obj/item/organ/internal/cyberimp/brain/anti_stun/on_life() ..() if(crit_fail) return - if(owner.stunned > STUN_SET_AMOUNT) - owner.SetStunned(STUN_SET_AMOUNT) - if(owner.weakened > STUN_SET_AMOUNT) - owner.SetWeakened(STUN_SET_AMOUNT) + if(owner.stunned > stun_max_amount) + owner.SetStunned(stun_max_amount) + if(owner.weakened > stun_max_amount) + owner.SetWeakened(stun_max_amount) /obj/item/organ/internal/cyberimp/brain/anti_stun/emp_act(severity) if(crit_fail || emp_proof) @@ -147,6 +146,12 @@ /obj/item/organ/internal/cyberimp/brain/anti_stun/proc/reboot() crit_fail = FALSE +/obj/item/organ/internal/cyberimp/brain/anti_stun/hardened + name = "Hardened CNS Rebooter implant" + desc = "A military-grade version of the standard implant, for NT's more elite forces." + origin_tech = "materials=6;programming=5;biotech=5" + emp_proof = TRUE + /obj/item/organ/internal/cyberimp/brain/clown_voice name = "Comical implant" desc = "Uh oh." diff --git a/code/modules/surgery/organs/pain.dm b/code/modules/surgery/organs/pain.dm index 91e4a2f6781..70f3ff43fa1 100644 --- a/code/modules/surgery/organs/pain.dm +++ b/code/modules/surgery/organs/pain.dm @@ -30,7 +30,7 @@ // message is the custom message to be displayed -mob/living/carbon/human/proc/custom_pain(message) +/mob/living/carbon/human/proc/custom_pain(message) if(stat >= UNCONSCIOUS) return @@ -49,7 +49,7 @@ mob/living/carbon/human/proc/custom_pain(message) to_chat(src, msg) next_pain_time = world.time + 100 -mob/living/carbon/human/proc/handle_pain() +/mob/living/carbon/human/proc/handle_pain() // not when sleeping if(stat >= UNCONSCIOUS) diff --git a/code/modules/surgery/organs/parasites.dm b/code/modules/surgery/organs/parasites.dm index b61a7c429bc..b9afa20b7d2 100644 --- a/code/modules/surgery/organs/parasites.dm +++ b/code/modules/surgery/organs/parasites.dm @@ -54,8 +54,6 @@ var/eggs_hatched = 0 // num of hatch events completed var/awaymission_checked = FALSE var/awaymission_infection = FALSE // TRUE if infection occurred inside gateway - var/list/types_basic = list(/mob/living/simple_animal/hostile/poison/terror_spider/red, /mob/living/simple_animal/hostile/poison/terror_spider/gray) - var/list/types_adv = list(/mob/living/simple_animal/hostile/poison/terror_spider/red, /mob/living/simple_animal/hostile/poison/terror_spider/gray, /mob/living/simple_animal/hostile/poison/terror_spider/green) /obj/item/organ/internal/body_egg/terror_eggs/on_life() @@ -104,12 +102,16 @@ var/infection_completed = FALSE var/obj/structure/spider/spiderling/terror_spiderling/S = new(get_turf(owner)) switch(eggs_hatched) - if(0) // First spiderling - S.grow_as = pick(types_basic) - if(1) // Second - S.grow_as = pick(types_adv) - if(2) // Last - S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/princess + if(0) // 1st spiderling + S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/gray + if(1) // 2nd + S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/red + if(2) // 3rd + S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/brown + if(3) // 4th + S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/green + if(4) // 5th + S.grow_as = /mob/living/simple_animal/hostile/poison/terror_spider/green infection_completed = TRUE S.immediate_ventcrawl = TRUE eggs_hatched++ diff --git a/code/modules/tgui/modules/ert_manager.dm b/code/modules/tgui/modules/ert_manager.dm new file mode 100644 index 00000000000..582d03f5a54 --- /dev/null +++ b/code/modules/tgui/modules/ert_manager.dm @@ -0,0 +1,100 @@ +/datum/tgui_module/ert_manager + name = "ERT Manager" + var/ert_type = "Red" + var/commander_slots = 1 // defaults for open slots + var/security_slots = 4 + var/medical_slots = 0 + var/engineering_slots = 0 + var/janitor_slots = 0 + var/paranormal_slots = 0 + var/cyborg_slots = 0 + +/datum/tgui_module/ert_manager/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_admin_state) + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + if(!ui) + ui = new(user, src, ui_key, "ERTManager", name, 350, 430, master_ui, state) + ui.autoupdate = TRUE + ui.open() + +/datum/tgui_module/ert_manager/tgui_data(mob/user) + var/list/data = list() + data["str_security_level"] = capitalize(get_security_level()) + switch(GLOB.security_level) + if(SEC_LEVEL_GREEN) + data["security_level_color"] = "green" + if(SEC_LEVEL_BLUE) + data["security_level_color"] = "blue" + if(SEC_LEVEL_RED) + data["security_level_color"] = "red" + else + data["security_level_color"] = "purple" + data["ert_type"] = ert_type + data["com"] = commander_slots + data["sec"] = security_slots + data["med"] = medical_slots + data["eng"] = engineering_slots + data["jan"] = janitor_slots + data["par"] = paranormal_slots + data["cyb"] = cyborg_slots + data["total"] = commander_slots + security_slots + medical_slots + engineering_slots + janitor_slots + paranormal_slots + cyborg_slots + data["spawnpoints"] = GLOB.emergencyresponseteamspawn.len + return data + +/datum/tgui_module/ert_manager/tgui_act(action, params) + if(..()) + return + . = TRUE + switch(action) + if("ert_type") + ert_type = params["ert_type"] + if("toggle_com") + commander_slots = commander_slots ? 0 : 1 + if("set_sec") + security_slots = text2num(params["set_sec"]) + if("set_med") + medical_slots = text2num(params["set_med"]) + if("set_eng") + engineering_slots = text2num(params["set_eng"]) + if("set_jan") + janitor_slots = text2num(params["set_jan"]) + if("set_par") + paranormal_slots = text2num(params["set_par"]) + if("set_cyb") + cyborg_slots = text2num(params["set_cyb"]) + if("dispatch_ert") + var/datum/response_team/D + switch(ert_type) + if("Amber") + D = new /datum/response_team/amber + if("Red") + D = new /datum/response_team/red + if("Gamma") + D = new /datum/response_team/gamma + else + to_chat(usr, "Invalid ERT type.") + return + GLOB.ert_request_answered = TRUE + var/slots_list = list() + if(commander_slots > 0) + slots_list += "commander: [commander_slots]" + if(security_slots > 0) + slots_list += "security: [security_slots]" + if(medical_slots > 0) + slots_list += "medical: [medical_slots]" + if(engineering_slots > 0) + slots_list += "engineering: [engineering_slots]" + if(janitor_slots > 0) + slots_list += "janitor: [janitor_slots]" + if(paranormal_slots > 0) + slots_list += "paranormal: [paranormal_slots]" + if(cyborg_slots > 0) + slots_list += "cyborg: [cyborg_slots]" + var/slot_text = english_list(slots_list) + notify_ghosts("An ERT is being dispatched. Open positions: [slot_text]") + message_admins("[key_name_admin(usr)] dispatched a [ert_type] ERT. Slots: [slot_text]", 1) + log_admin("[key_name(usr)] dispatched a [ert_type] ERT. Slots: [slot_text]") + GLOB.event_announcement.Announce("Attention, [station_name()]. We are attempting to assemble an ERT. Standby.", "ERT Protocol Activated") + trigger_armed_response_team(D, commander_slots, security_slots, medical_slots, engineering_slots, janitor_slots, paranormal_slots, cyborg_slots) + else + return FALSE + diff --git a/icons/atmos/omni_devices.dmi b/icons/atmos/omni_devices.dmi deleted file mode 100644 index 3e7325b0556..00000000000 Binary files a/icons/atmos/omni_devices.dmi and /dev/null differ diff --git a/icons/atmos/vent_scrubber.dmi b/icons/atmos/vent_scrubber.dmi index c6b6d6ccfe4..628a17e8565 100644 Binary files a/icons/atmos/vent_scrubber.dmi and b/icons/atmos/vent_scrubber.dmi differ diff --git a/icons/goonstation/objects/pda_overlay.dmi b/icons/goonstation/objects/pda_overlay.dmi index 4c7cb24a7f4..74be20fc981 100644 Binary files a/icons/goonstation/objects/pda_overlay.dmi and b/icons/goonstation/objects/pda_overlay.dmi differ diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi index e55b06fe8f1..d3253d3e1fb 100644 Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ diff --git a/icons/mob/corgi_head.dmi b/icons/mob/corgi_head.dmi index df2f3a66d84..7492b40833d 100644 Binary files a/icons/mob/corgi_head.dmi and b/icons/mob/corgi_head.dmi differ diff --git a/icons/mob/feet.dmi b/icons/mob/feet.dmi index 3892442c6ea..882e0a0f327 100644 Binary files a/icons/mob/feet.dmi and b/icons/mob/feet.dmi differ diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi index 1bd516110e5..ddc5f3cf05c 100644 Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ diff --git a/icons/mob/human_races/r_skeleton.dmi b/icons/mob/human_races/r_skeleton.dmi index a350c3f4c4d..6f98807254b 100644 Binary files a/icons/mob/human_races/r_skeleton.dmi and b/icons/mob/human_races/r_skeleton.dmi differ diff --git a/icons/mob/inhands/clothing_lefthand.dmi b/icons/mob/inhands/clothing_lefthand.dmi index 379c727930f..9fce742e0bf 100644 Binary files a/icons/mob/inhands/clothing_lefthand.dmi and b/icons/mob/inhands/clothing_lefthand.dmi differ diff --git a/icons/mob/inhands/clothing_righthand.dmi b/icons/mob/inhands/clothing_righthand.dmi index 2fc6aa9c4c1..772f8af73e4 100644 Binary files a/icons/mob/inhands/clothing_righthand.dmi and b/icons/mob/inhands/clothing_righthand.dmi differ diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi index b2f1bfa90c6..88cfce57ed9 100644 Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi index a7772c3ebf4..44934af9bfc 100644 Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ diff --git a/icons/mob/robots.dmi b/icons/mob/robots.dmi index dcbce35fb27..738fb1e0933 100644 Binary files a/icons/mob/robots.dmi and b/icons/mob/robots.dmi differ diff --git a/icons/mob/screen_midnight.dmi b/icons/mob/screen_midnight.dmi index a5f9caa6a90..8d1f1648cf5 100644 Binary files a/icons/mob/screen_midnight.dmi and b/icons/mob/screen_midnight.dmi differ diff --git a/icons/mob/screen_ninja.dmi b/icons/mob/screen_ninja.dmi index 0f527241e0d..df30d63fe76 100644 Binary files a/icons/mob/screen_ninja.dmi and b/icons/mob/screen_ninja.dmi differ diff --git a/icons/mob/screen_operative.dmi b/icons/mob/screen_operative.dmi index 0bb1a0b9d44..4abe226fa84 100644 Binary files a/icons/mob/screen_operative.dmi and b/icons/mob/screen_operative.dmi differ diff --git a/icons/mob/screen_plasmafire.dmi b/icons/mob/screen_plasmafire.dmi index 81453caddef..a9f2a25bd1a 100644 Binary files a/icons/mob/screen_plasmafire.dmi and b/icons/mob/screen_plasmafire.dmi differ diff --git a/icons/mob/screen_retro.dmi b/icons/mob/screen_retro.dmi index 1568e701222..0f2d9ed91e0 100644 Binary files a/icons/mob/screen_retro.dmi and b/icons/mob/screen_retro.dmi differ diff --git a/icons/mob/screen_slimecore.dmi b/icons/mob/screen_slimecore.dmi index 3b2392cb8fc..2cbc53e7ba1 100644 Binary files a/icons/mob/screen_slimecore.dmi and b/icons/mob/screen_slimecore.dmi differ diff --git a/icons/mob/screen_white.dmi b/icons/mob/screen_white.dmi index 361611cf4e0..ab65366bb52 100644 Binary files a/icons/mob/screen_white.dmi and b/icons/mob/screen_white.dmi differ diff --git a/icons/mob/species/drask/head.dmi b/icons/mob/species/drask/head.dmi index f0c888e9f68..ca15dea1cb4 100644 Binary files a/icons/mob/species/drask/head.dmi and b/icons/mob/species/drask/head.dmi differ diff --git a/icons/mob/species/drask/shoes.dmi b/icons/mob/species/drask/shoes.dmi index e51947fdd35..53664dd3d70 100644 Binary files a/icons/mob/species/drask/shoes.dmi and b/icons/mob/species/drask/shoes.dmi differ diff --git a/icons/mob/species/kidan/head.dmi b/icons/mob/species/kidan/head.dmi new file mode 100644 index 00000000000..83818995f69 Binary files /dev/null and b/icons/mob/species/kidan/head.dmi differ diff --git a/icons/mob/species/skrell/head.dmi b/icons/mob/species/skrell/head.dmi index ec5e8dd62e4..5ffe836ffc2 100644 Binary files a/icons/mob/species/skrell/head.dmi and b/icons/mob/species/skrell/head.dmi differ diff --git a/icons/mob/species/vox/shoes.dmi b/icons/mob/species/vox/shoes.dmi index 99eac81e3a9..f04249274b3 100644 Binary files a/icons/mob/species/vox/shoes.dmi and b/icons/mob/species/vox/shoes.dmi differ diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi index 0dbab70dd32..48f2080ea98 100644 Binary files a/icons/obj/card.dmi and b/icons/obj/card.dmi differ diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi index f007687d568..05d04330c38 100644 Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ diff --git a/icons/obj/clothing/glasses.dmi b/icons/obj/clothing/glasses.dmi index c0501f9bb36..fb4063c1bf4 100644 Binary files a/icons/obj/clothing/glasses.dmi and b/icons/obj/clothing/glasses.dmi differ diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi index aae2d9df6fb..f20ca2501a8 100644 Binary files a/icons/obj/clothing/shoes.dmi and b/icons/obj/clothing/shoes.dmi differ diff --git a/icons/obj/custom_items.dmi b/icons/obj/custom_items.dmi index 2b1c7edfa58..0cf67d92ef9 100644 Binary files a/icons/obj/custom_items.dmi and b/icons/obj/custom_items.dmi differ diff --git a/icons/obj/food/containers.dmi b/icons/obj/food/containers.dmi index ff25b77ab45..ad31ac04998 100644 Binary files a/icons/obj/food/containers.dmi and b/icons/obj/food/containers.dmi differ diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi index 303ae139574..ba64299a052 100644 Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ diff --git a/icons/obj/pda.dmi b/icons/obj/pda.dmi index b4956c33a9e..5cf13a408d5 100644 Binary files a/icons/obj/pda.dmi and b/icons/obj/pda.dmi differ diff --git a/icons/obj/reagentfillings.dmi b/icons/obj/reagentfillings.dmi index 51e9b66ee30..c36fbf01876 100644 Binary files a/icons/obj/reagentfillings.dmi and b/icons/obj/reagentfillings.dmi differ diff --git a/nano/templates/ai_fixer.tmpl b/nano/templates/ai_fixer.tmpl deleted file mode 100644 index 4be6fee598d..00000000000 --- a/nano/templates/ai_fixer.tmpl +++ /dev/null @@ -1,58 +0,0 @@ - -{{if data.occupant}} -
-

Stored AI: {{:data.occupant}}

-

Information

-
- Integrity -
-
- {{:data.integrity}}% -
-
- Status -
-
- {{if data.stat == 2}} - Non-functional - {{else}} - Functional - {{/if}} -
-
- Wireless Activity -
-
- {{:helper.link('Enabled','check',{'wireless' : 0},data.wireless == 0 ? 'selected' : '')}} - {{:helper.link('Disabled','close',{'wireless' : 1},data.wireless == 1 ? 'selected' : '')}} -
-
- Subspace Transceiver -
-
- {{:helper.link('Enabled','check',{'radio' : 0},data.radio == 0 ? 'selected' : '')}} - {{:helper.link('Disabled','close',{'radio' : 1},data.radio == 1 ? 'selected' : '')}} -
-

Laws

- {{for data.laws}} - {{:value.number}}: {{:value.law}}
- {{empty}} - No laws detected! - {{/for}} - -

Actions

- {{if data.active}} - Reconstruction in progress, please wait. - {{:helper.displayBar(data.integrity, 0, 100, (data.integrity >= 75) ? 'good' : (data.integrity >= 25) ? 'average' : 'bad')}} - {{:helper.smoothRound(data.integrity)}}% - {{/if}} -
- {{:helper.link('Reconstruct', 'wrench', {'fix' : 1}, data.active || data.integrity >= 100 ? 'disabled' : '')}} -
-
-{{else}} -

No artificial intelligence detected.

-{{/if}} \ No newline at end of file diff --git a/nano/templates/aicard.tmpl b/nano/templates/aicard.tmpl deleted file mode 100644 index 8ebe6cff319..00000000000 --- a/nano/templates/aicard.tmpl +++ /dev/null @@ -1,98 +0,0 @@ - - - - - -{{if data.has_ai}} -
-
- Hardware Integrity: -
-
- {{:data.hardware_integrity}}% -
-
- - {{if data.has_laws}} - - - -
- Laws: -
- {{for data.laws}} - - {{/for}} -
IndexLaw
{{:value.index}}.{{:value.law}}
- {{else}} - No laws found. - {{/if}} - - {{if data.operational}} - - - - - - - - - - - {{if data.flushing}} - - {{else}} - - - - - {{/if}} -
Radio Subspace Transceiver{{:helper.link("Enabled", null, {'radio' : 0}, data.radio ? 'selected' : null)}}{{:helper.link("Disabled", null, {'radio' : 1}, data.radio ? null : 'redButton' )}}
Wireless Interface{{:helper.link("Enabled", null, {'wireless' : 0}, data.wireless ? 'selected' : null)}}{{:helper.link("Disabled", null, {'wireless' : 1}, data.wireless ? null : 'redButton' )}}
AI wipe in progress...
Wipe AI{{:helper.link("Wipe", 'exclamation-circle', {'wipe' : 1}, null, 'redButton')}}
- {{/if}} -{{else}} - Stored AI: No AI detected. -{{/if}} diff --git a/nano/templates/atmos_filter.tmpl b/nano/templates/atmos_filter.tmpl deleted file mode 100644 index e0715e243c5..00000000000 --- a/nano/templates/atmos_filter.tmpl +++ /dev/null @@ -1,24 +0,0 @@ -
-
Power:
-
{{:helper.link(data.on ? 'On' : 'Off', data.on ? 'power-off' : 'times', {'power' : 1}, null, data.on ? 'selected' : null)}}
-
-
-
Output Pressure:
-
- {{:helper.link('Set', 'pencil', {'pressure' : 'input'})}} - {{:helper.link('Max', 'plus', {'pressure' : 'max'}, data.pressure == data.max_pressure ? 'disabled' : null)}} - {{:helper.smoothRound(data.pressure)}} kPa -
-
-
-
Filter:
-
- {{:helper.link('Nothing', null, {'filter' : -1}, data.filter_type == -1 ? 'selected' : null)}} - {{:helper.link('Plasma', null, {'filter' : 0}, data.filter_type == 0 ? 'selected' : null)}} - {{:helper.link('O2', null, {'filter' : 1}, data.filter_type == 1 ? 'selected' : null)}} - {{:helper.link('N2', null, {'filter' : 2}, data.filter_type == 2 ? 'selected' : null)}} - {{:helper.link('CO2', null, {'filter' : 3}, data.filter_type == 3 ? 'selected' : null)}} - {{:helper.link('N2O', null, {'filter' : 4}, data.filter_type == 4 ? 'selected' : null)}} -
-
- diff --git a/nano/templates/atmos_mixer.tmpl b/nano/templates/atmos_mixer.tmpl deleted file mode 100644 index 3bae7f993bd..00000000000 --- a/nano/templates/atmos_mixer.tmpl +++ /dev/null @@ -1,32 +0,0 @@ -
-
Power:
-
{{:helper.link(data.on ? 'On' : 'Off', data.on ? 'power-off' : 'times', {'power' : 1}, null, data.on ? 'selected' : null)}}
-
-
-
Output Pressure:
-
- {{:helper.link('Set', 'pencil', {'pressure' : 'input'})}} - {{:helper.link('Max', 'plus', {'pressure' : 'max'}, data.pressure == data.max_pressure ? 'disabled' : null)}} - {{:helper.smoothRound(data.pressure)}} kPa -
-
-
-
Node 1:
-
- {{:helper.link('', null, {'node1' : -0.1}, data.node1_concentration == 0 ? 'disabled' : null)}} - {{:helper.link('', null, {'node1' : -0.01}, data.node1_concentration == 0 ? 'disabled' : null)}} - {{:helper.link('', null, {'node1' : 0.01}, data.node1_concentration == 100 ? 'disabled' : null)}} - {{:helper.link('', null, {'node1' : 0.1}, data.node1_concentration == 100 ? 'disabled' : null)}} - {{:helper.smoothRound(data.node1_concentration)}}% -
-
-
-
Node 2:
-
- {{:helper.link('', null, {'node2' : -0.1}, data.node2_concentration == 0 ? 'disabled' : null)}} - {{:helper.link('', null, {'node2' : -0.01}, data.node2_concentration == 0 ? 'disabled' : null)}} - {{:helper.link('', null, {'node2' : 0.01}, data.node2_concentration == 100 ? 'disabled' : null)}} - {{:helper.link('', null, {'node2' : 0.1}, data.node2_concentration == 100 ? 'disabled' : null)}} - {{:helper.smoothRound(data.node2_concentration)}}% -
-
\ No newline at end of file diff --git a/nano/templates/atmos_pump.tmpl b/nano/templates/atmos_pump.tmpl deleted file mode 100644 index a27e5b710dd..00000000000 --- a/nano/templates/atmos_pump.tmpl +++ /dev/null @@ -1,24 +0,0 @@ -
-
Power:
-
{{:helper.link(data.on ? 'On' : 'Off', data.on ? 'power-off' : 'times', {'power' : 1}, null, data.on ? 'selected' : null)}}
-
-{{if data.max_rate}} -
-
Transfer Rate:
-
- {{:helper.link('Set', 'pencil', {'rate' : 'input'})}} - {{:helper.link('Max', 'plus', {'rate' : 'max'}, data.rate == data.max_rate ? 'disabled' : null)}} - {{:helper.smoothRound(data.rate)}} L/s -
-
-{{else}} -
-
Output Pressure:
-
- {{:helper.link('Set', 'pencil', {'pressure' : 'input'})}} - {{:helper.link('Max', 'plus', {'pressure' : 'max'}, data.pressure == data.max_pressure ? 'disabled' : null)}} - {{:helper.smoothRound(data.pressure)}} kPa -
-
-{{/if}} - diff --git a/nano/templates/autolathe.tmpl b/nano/templates/autolathe.tmpl deleted file mode 100644 index d56ae4926c3..00000000000 --- a/nano/templates/autolathe.tmpl +++ /dev/null @@ -1,150 +0,0 @@ - - - - - - -{{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 ? '(' + value.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 diff --git a/nano/templates/brig_timer.tmpl b/nano/templates/brig_timer.tmpl deleted file mode 100644 index 2cd1ab73a23..00000000000 --- a/nano/templates/brig_timer.tmpl +++ /dev/null @@ -1,91 +0,0 @@ - -
-
- Cell: -
-
- {{:data.cell_id}} -
-
-
-
- Occupant: -
-
- {{:data.occupant}} -
-
-
-
- Crimes: -
-
- {{:data.crimes}} -
-
-
-
- Brigged By: -
-
- {{:data.brigged_by}} -
-
-
-
- Time Brigged For: -
-
- {{:data.time_set}} -
-
-
-
- Time Left: -
-
- {{:data.time_left}} -
-
-{{if data.isAllowed}} -
-
- Actions: -
-
- {{:helper.link('Flash', 'flash', {'flash' : 1}, null, data.isAllowed ? '' : 'dsabled')}} - {{:helper.link('Release', null, {'release' : 1}, null, data.isAllowed ? '' : 'disabled')}} -
-
- {{if !data.timing}} -

Inmate Information

-
-
- Name: -
-
- {{:helper.link('Set', 'pencil', {'prisoner_name' : 'input'})}} {{:data.prisoner_name}} -
-
-
-
- Charge: -
-
- {{:helper.link('Set', 'pencil', {'prisoner_charge' : 'input'})}} {{:data.prisoner_charge}} -
-
-
-
- Time (in minutes): -
-
- {{:helper.link('Set', 'pencil', {'prisoner_time' : 'input'})}} {{:data.prisoner_time}} -
-
- {{:helper.link('Submit', null, {'set_timer' : 1}, null, data.isAllowed ? '' : 'disabled')}} - {{/if}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/comm_console.tmpl b/nano/templates/comm_console.tmpl deleted file mode 100644 index 2c36a011ac6..00000000000 --- a/nano/templates/comm_console.tmpl +++ /dev/null @@ -1,142 +0,0 @@ - - -{{if !data.authenticated}} -
Please swipe your ID card. {{:helper.link('Log In','unlock',{'login':1},null,'fixed')}}
-{{else}} - {{if !data.is_ai}} -
Please remember to {{:helper.link('Log Out','lock',{'logout':1},null,'fixed')}}
- {{/if}} - {{if data.lastCallLoc}} -
Most recent shuttle call/recall traced to: {{:data.lastCallLoc}}
- {{else}} -
Unable to trace most recent shuttle call/recall signal.
- {{/if}} -
-

Emergency Shuttle:

- {{if data.shuttle.eta}} -
ETA:
-
- {{>data.shuttle.eta}} -
- {{/if}} -
Options:
-
- {{if data.shuttle.callStatus == 1 && !data.is_ai}} - {{:helper.link('Cancel Shuttle','arrow-left',{'operation':'cancelshuttle'})}} - {{else data.shuttle.callStatus == 2}} - {{:helper.link('Call Shuttle','arrow-circle-down',{'operation':'callshuttle'})}} - {{/if}} -
-
- - {{if data.screen==1}} - -

Menu

-
- {{if data.authenticated==2}} -
- {{:helper.link('Make an Announcement','info',{'operation':'announce'})}} -
-
- {{if data.emagged}} - {{:helper.link('Message [UNKNOWN]','envelope',{'operation':'MessageSyndicate'})}} -
-
- {{:helper.link('Reset Relays','refresh',{'operation':'RestoreBackup'})}} - {{else}} - {{:helper.link('Message CentComm','envelope',{'operation':'MessageCentcomm'})}} - {{/if}} -
-
- {{:helper.link('Request Nuclear Authentication Codes','exclamation-triangle',{'operation':'nukerequest'})}} -
- {{/if}} -
- {{:helper.link('Change Alert Level','signal',{'operation':'changeseclevel'})}} -
-
- {{:helper.link('Change Status Displays','info',{'operation':'status'})}} -
-
- {{:helper.link('Message List','comment',{'operation':'messagelist'})}} -
-
- {{:helper.link('Restart Nano-Mob Hunter GO! Server','power-off',{'operation':'RestartNanoMob'})}} -
-
- {{else data.screen==2}} - -

Status Displays

- {{:helper.link('Back','home',{'operation':'main'})}} -

Presets

- {{for data.stat_display.presets}} -
-
{{:helper.link(value.label,'info',{'operation':'setstat','statdisp':value.name},null,(name==data.stat_display.type?'linkOn':''))}}
-
- {{/for}} -

Alerts

- {{for data.stat_display.alerts}} -
-
{{:helper.link(value.label,'exclamation-triangle',{'operation':'setstat','statdisp':'alert','alert':value.alert},null,(value.alert==data.stat_display.type?'linkOn':''))}}
-
- {{/for}} -

Messages

-
- {{if data.stat_display.type}} -
-
{{:helper.link('Line 1:','gear',{'operation':'setmsg1'})}}
-
{{>data.stat_display.line_1}}
-
-
-
{{:helper.link('Line 2:','gear',{'operation':'setmsg2'})}}
-
{{>data.stat_display.line_2}}
-
- {{/if}} -
- {{else data.screen==3}} - -

Messages

- {{if data.current_message}} - {{:helper.link('Messages','home',{'operation':'messagelist'})}} -

{{:data.current_message_title}}

-
- {{:data.current_message}} -
- {{else}} - {{:helper.link('Back','home',{'operation':'main'})}} - {{for data.messages}} -
- {{:value.title}}
- {{:helper.link('Open','envelope-o',{'operation':'messagelist','msgid':value.id})}} - {{:helper.link('Delete','close',{'operation':'delmessage','msgid':value.id})}} -
- {{/for}} - {{/if}} - {{else data.screen==4}} - -

Security Level

- {{:helper.link('Back','home',{'operation':'main'})}} -
-
-
Security Level:
-
{{>data.str_security_level}}
-
-
-
Presets:
-
- {{for data.levels}} - {{:helper.link(value.name,'comment',{'operation':'newalertlevel','level':value.id},null,(value.id==data.security_level?'linkOn':''))}} - {{/for}} -
-
-
- {{/if}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/ert_config.tmpl b/nano/templates/ert_config.tmpl deleted file mode 100644 index c8ff0645b3b..00000000000 --- a/nano/templates/ert_config.tmpl +++ /dev/null @@ -1,75 +0,0 @@ -
- - - - - - -
Station Alert Level{{:data.alert_level}}
ERT Type - {{if data.ert_type == 'Code Amber'}} AMBER {{else}} {{:helper.link('Amber', null, {"set_code": 'Code Amber'})}} {{/if}} - {{if data.ert_type == 'Code Red'}} RED {{else}} {{:helper.link('Red', null, {"set_code": 'Code Red'})}} {{/if}} - {{if data.ert_type == 'Code Gamma'}} GAMMA {{else}} {{:helper.link('Gamma', null, {"set_code": 'Code Gamma'})}} {{/if}} -
-
-
-
- - - - - - - - - -
DepartmentSlotsChange Slots
Command{{if data.com == 0}}-{{else}}{{:helper.smoothRound(data.com)}}{{/if}} - {{:helper.link('0', null, {"set_com": 0})}} - {{:helper.link('1', null, {"set_com": 1})}}
Security{{if data.sec == 0}}-{{else}}{{:helper.smoothRound(data.sec)}}{{/if}} - {{:helper.link('0', null, {"set_sec": 0})}} - {{:helper.link('1', null, {"set_sec": 1})}} - {{:helper.link('2', null, {"set_sec": 2})}} - {{:helper.link('3', null, {"set_sec": 3})}} - {{:helper.link('4', null, {"set_sec": 4})}} - {{:helper.link('5', null, {"set_sec": 5})}} -
Medical{{if data.med == 0}}-{{else}}{{:helper.smoothRound(data.med)}}{{/if}} - {{:helper.link('0', null, {"set_med": 0})}} - {{:helper.link('1', null, {"set_med": 1})}} - {{:helper.link('2', null, {"set_med": 2})}} - {{:helper.link('3', null, {"set_med": 3})}} - {{:helper.link('4', null, {"set_med": 4})}} - {{:helper.link('5', null, {"set_med": 5})}} -
Engineering{{if data.eng == 0}}-{{else}}{{:helper.smoothRound(data.eng)}}{{/if}} - {{:helper.link('0', null, {"set_eng": 0})}} - {{:helper.link('1', null, {"set_eng": 1})}} - {{:helper.link('2', null, {"set_eng": 2})}} - {{:helper.link('3', null, {"set_eng": 3})}} - {{:helper.link('4', null, {"set_eng": 4})}} - {{:helper.link('5', null, {"set_eng": 5})}} -
Paranormal{{if data.par == 0}}-{{else}}{{:helper.smoothRound(data.par)}}{{/if}} - {{:helper.link('0', null, {"set_par": 0})}} - {{:helper.link('1', null, {"set_par": 1})}} - {{:helper.link('2', null, {"set_par": 2})}} - {{:helper.link('3', null, {"set_par": 3})}} - {{:helper.link('4', null, {"set_par": 4})}} - {{:helper.link('5', null, {"set_par": 5})}} -
Janitor{{if data.jan == 0}}-{{else}}{{:helper.smoothRound(data.jan)}}{{/if}} - {{:helper.link('0', null, {"set_jan": 0})}} - {{:helper.link('1', null, {"set_jan": 1})}} - {{:helper.link('2', null, {"set_jan": 2})}} - {{:helper.link('3', null, {"set_jan": 3})}} - {{:helper.link('4', null, {"set_jan": 4})}} - {{:helper.link('5', null, {"set_jan": 5})}} -
{{if data.ert_type == 'Code Gamma'}}GAMMA {{/if}}Cyborg{{if data.cyb == 0}}-{{else}}{{:helper.smoothRound(data.cyb)}}{{/if}} - {{:helper.link('0', null, {"set_cyb": 0})}} - {{:helper.link('1', null, {"set_cyb": 1})}} - {{:helper.link('2', null, {"set_cyb": 2})}} - {{:helper.link('3', null, {"set_cyb": 3})}} - {{:helper.link('4', null, {"set_cyb": 4})}} - {{:helper.link('5', null, {"set_cyb": 5})}} -
-
-
-
- {{:helper.link('Dispatch', null, {"dispatch_ert": 1})}} -
- diff --git a/nano/templates/faxmachine.tmpl b/nano/templates/faxmachine.tmpl deleted file mode 100644 index e52c40eb927..00000000000 --- a/nano/templates/faxmachine.tmpl +++ /dev/null @@ -1,67 +0,0 @@ - -
-

Authorization

-
-
-
- Confirm identity: -
-
- {{:helper.link(data.scan_name, 'eject', {'scan' : 1})}} -
-
-
-
- Authorize: -
-
- {{:helper.link(data.authenticated ? 'Log Out' : 'Log In', data.authenticated ? 'unlock' : 'lock', {'auth' : 1})}} -
-
-
-
-

Fax Menu

-
-
-
- Network: -
- -
- {{:data.network}} -
-
-
-
- Currently sending: -
-
- {{:helper.link(data.paper, 'eject', {'paper' : 1})}} - {{if data.paperinserted}} - {{:helper.link('Rename', 'pencil', {'rename' : 1})}} - {{/if}} -
-
-
-
- Sending to: -
-
- {{:helper.link(data.destination, 'print', {'dept' : 1}, !data.authenticated ? 'disabled' : '')}} -
-
-
-
- Action: -
-
- {{if data.authenticated}} - {{:helper.link(data.cooldown && data.respectcooldown ? "Realigning" : "Send", data.cooldown && data.respectcooldown ? 'clock-o' : "envelope-o", {'send' : 1}, data.cooldown && data.respectcooldown ? 'disabled' : "")}} - {{else}} - {{:helper.link(data.cooldown && data.respectcooldown ? "Realigning" : "Send", data.cooldown && data.respectcooldown ? 'clock-o' : "envelope-o", null, !data.authenticated ? 'disabled' : "")}} - {{/if}} -
-
\ No newline at end of file diff --git a/nano/templates/freezer.tmpl b/nano/templates/freezer.tmpl deleted file mode 100644 index 582598e05c5..00000000000 --- a/nano/templates/freezer.tmpl +++ /dev/null @@ -1,51 +0,0 @@ -
-
- Status: -
-
- {{:helper.link('On', 'power-off', {'toggleStatus' : 1}, data.on ? 'selected' : null)}}{{:helper.link('Off', 'close', {'toggleStatus' : 1}, data.on ? null : 'selected')}} -
-
- -
-
- Gas Pressure: -
-
- {{:helper.smoothRound(data.gasPressure)}} kPa -
-
- -

Gas Temperature

-
-
- Current: -
-
- {{:helper.displayBar(data.gasTemperature, data.minGasTemperature, data.maxGasTemperature, data.gasTemperatureClass)}} -
- {{:helper.smoothRound(data.gasTemperature)}} K ({{:helper.smoothRound(data.gasTemperatureCelsius)}} °C) -
-
-
- -
-
- Target: -
-
- {{:helper.displayBar(data.targetGasTemperature, data.minGasTemperature, data.maxGasTemperature)}} -
- {{:helper.link('Min', null, {'minimum' : 'yes'}, (data.targetGasTemperature > data.minGasTemperature) ? null : 'disabled')}} - {{:helper.link('-', null, {'temp' : -100}, (data.targetGasTemperature > data.minGasTemperature) ? null : 'disabled')}} - {{:helper.link('-', null, {'temp' : -10}, (data.targetGasTemperature > data.minGasTemperature) ? null : 'disabled')}} - {{:helper.link('-', null, {'temp' : -1}, (data.targetGasTemperature > data.minGasTemperature) ? null : 'disabled')}} -
{{:data.targetGasTemperature}} K ({{:data.targetGasTemperatureCelsius}} °C)
- {{:helper.link('+', null, {'temp' : 1}, (data.targetGasTemperature < data.maxGasTemperature) ? null : 'disabled')}} - {{:helper.link('+', null, {'temp' : 10}, (data.targetGasTemperature < data.maxGasTemperature) ? null : 'disabled')}} - {{:helper.link('+', null, {'temp' : 100}, (data.targetGasTemperature < data.maxGasTemperature) ? null : 'disabled')}} - {{:helper.link('Max', null, {'maximum' : 'yes'}, (data.targetGasTemperature < data.maxGasTemperature) ? null : 'disabled')}} -
-
-
- diff --git a/nano/templates/keycard_auth.tmpl b/nano/templates/keycard_auth.tmpl deleted file mode 100644 index 96a3f44f60a..00000000000 --- a/nano/templates/keycard_auth.tmpl +++ /dev/null @@ -1,39 +0,0 @@ - - -
-

Keycard Authentication Device

- This device is used to trigger certain high security events. It requires the simultaneous swipe of two high-level ID cards. -
- {{if data.screen == 1}} -

Trigger Event

- {{:helper.link('Red Alert', 'exclamation-triangle', { 'triggerevent' : 'Red Alert' })}} - {{:helper.link('Emergency Response Team', 'exclamation-triangle', { 'triggerevent' : 'Emergency Response Team' })}} - {{:helper.link('Grant Emergency Maintenance Access', 'unlock', { 'triggerevent' : 'Grant Emergency Maintenance Access' })}} - {{:helper.link('Revoke Emergency Maintenance Access', 'lock', { 'triggerevent' : 'Revoke Emergency Maintenance Access' })}} - {{:helper.link('Activate Station-Wide Emergency Access', 'unlock', { 'triggerevent' : 'Activate Station-Wide Emergency Access' })}} - {{:helper.link('Deactivate Station-Wide Emergency Access', 'lock', { 'triggerevent' : 'Deactivate Station-Wide Emergency Access' })}} - {{else data.screen == 2}} - {{if data.event == 'Emergency Response Team'}} -
-
Reason for ERT Call:
-
- {{:helper.link(data.ertreason, 'exclamation-triangle', { 'ert' : 'callreason' })}} -
-
- {{/if}} -

Please swipe your card to authorize the following event:

-
{{:data.event}}
- {{:helper.link('Back', 'close', { 'reset' : 1 })}} - {{/if}} -
-
\ No newline at end of file diff --git a/nano/templates/mech_bay_console.tmpl b/nano/templates/mech_bay_console.tmpl deleted file mode 100644 index 2a4cf5d6085..00000000000 --- a/nano/templates/mech_bay_console.tmpl +++ /dev/null @@ -1,55 +0,0 @@ -

Subsystems

-
-
- Power Port: -
-
- {{if data.recharge_port}} - OK - {{else}} - ERROR - {{/if}} -
-
-
-
- Mecha: -
-
- {{if data.has_mech}} - LOCATED ({{:data.mecha_name}}) - {{else}} - NONE - {{/if}} -
-
-{{if data.has_mech}} -

Charging

-
-
- Charge Level: -
-
- {{:helper.displayBar(data.mecha_charge_percentage, 0, 100)}} -
- {{:helper.smoothRound(data.mecha_charge_percentage)}}%
-
-
-
-
-
- Cell Rating: -
-
- {{:data.mecha_maxcharge}} -
-
-
-
- Cell Charge: -
-
- {{:helper.smoothRound(data.mecha_charge)}} -
-
-{{/if}} \ No newline at end of file diff --git a/nano/templates/nuclear_bomb.tmpl b/nano/templates/nuclear_bomb.tmpl deleted file mode 100644 index f2a12651af6..00000000000 --- a/nano/templates/nuclear_bomb.tmpl +++ /dev/null @@ -1,145 +0,0 @@ - -{{if data.is_syndicate}} - {{:helper.syndicateMode()}} -{{/if}} -
-
Authorization Disk:
-
- {{if data.auth}} - {{:helper.link('++++++++++', 'eject', {'auth' : 1})}} - {{else}} - {{:helper.link('----------', 'floppy-o', {'auth' : 1})}} - {{/if}} -
-
-
-
-
Status:
-
{{:data.authstatus}} - {{:data.safe}}
-
- -
-
Time Left:
-
{{:data.time}}
-
- -
- {{if data.auth && data.yescode}} -
-
- Timer -
-
- {{:helper.link('On', 'play', {'timer' : 1}, data.timer ? 'selected' : '')}} - {{:helper.link('Off', 'stop', {'timer' : 0}, !data.timer ? 'selected' : '')}} -
-
-
-
- Set Time -
-
- {{:helper.link('--', '', {'time' : -10}, data.time <= 120 ? 'disabled' : '')}} - {{:helper.link('-', '', {'time' : -1}, data.time <= 120 ? 'disabled' : '')}} - - {{:helper.link('+', '', {'time' : 1})}} - {{:helper.link('++', '', {'time' : 10})}} -
-
- - {{else}} - -
-
- Timer -
-
- {{:helper.link('On', 'play', null, 'disabled')}} - {{:helper.link('Off', 'pause', null, 'disabled')}} -
-
-
-
- Set Time -
-
- {{:helper.link('--', '', null, 'disabled')}} - {{:helper.link('-', '', null, 'disabled')}} - - {{:helper.link('+', '', null, 'disabled')}} - {{:helper.link('++', '', null, 'disabled')}} -
-
- {{/if}} -
- -
- {{if data.auth && data.yescode}} -
-
- Safety -
-
- {{:helper.link('Engaged', 'info', {'safety' : 1}, data.safety ? 'selected' : '')}} - {{:helper.link('Disengaged', 'exclamation-triangle', {'safety' : 0}, data.safety ? '' : 'selected')}} -
-
-
-
- Anchor -
-
- {{:helper.link('Engaged', 'lock', {'anchor' : 1}, data.anchored ? 'selected' : '')}} - {{:helper.link('Disengaged', 'unlock', {'anchor' : 0}, data.anchored ? '' : 'selected')}} -
-
- - {{else}} - -
-
- Safety -
-
- {{:helper.link('Engaged', 'info', null, 'disabled')}} - {{:helper.link('Disengaged', 'exclamation-triangle', null, 'disabled')}} -
-
-
-
- Anchor -
-
- {{:helper.link('Engaged', 'lock', null, 'disabled')}} - {{:helper.link('Disengaged', 'unlock', null, 'disabled')}} -
-
- {{/if}} -
-
-
-
- >{{if data.message}} {{:data.message}}{{/if}} -
-
-
- {{:helper.link('1', '', {'type' : 1})}}{{:helper.link('2', '', {'type' : 2})}}{{:helper.link('3', '', {'type' : 3})}} -
-
- {{:helper.link('4', '', {'type' : 4})}}{{:helper.link('5', '', {'type' : 5})}}{{:helper.link('6', '', {'type' : 6})}} -
-
- {{:helper.link('7', '', {'type' : 7})}}{{:helper.link('8', '', {'type' : 8})}}{{:helper.link('9', '', {'type' : 9})}} -
-
- {{:helper.link('R', '', {'type' : 'R'})}}{{:helper.link('0', '', {'type' : 0})}}{{:helper.link('E', '', {'type' : 'E'})}} -
-
-
\ No newline at end of file diff --git a/nano/templates/omni_filter.tmpl b/nano/templates/omni_filter.tmpl deleted file mode 100644 index 8a3ffac0af7..00000000000 --- a/nano/templates/omni_filter.tmpl +++ /dev/null @@ -1,86 +0,0 @@ -
-
- {{:helper.link(data.power ? 'On' : 'Off', null, {'command' : 'power'}, data.config ? 'disabled' : null)}} -
-
- {{:helper.link('Configure', null, {'command' : 'configure'}, null, data.config ? 'selected' : null)}} -
- - {{if data.config}} - -
-
-
Port
- {{for data.ports}} -
{{:value.dir}} Port
- {{/for}} -
-
-
Input
- {{for data.ports}} -
- {{:helper.link(' ', null, {'command' : 'switch_mode', 'mode' : 'in', 'dir' : value.dir}, null, value.input ? 'selected' : null)}} -
- {{/for}} -
-
-
Output
- {{for data.ports}} -
- {{:helper.link(' ', null, {'command' : 'switch_mode', 'mode' : 'out', 'dir' : value.dir}, null, value.output ? 'selected' : null)}} -
- {{/for}} -
-
-
Filter
- {{for data.ports}} -
- {{:helper.link(value.f_type ? value.f_type : 'None', null, {'command' : 'switch_filter', 'mode' : value.f_type, 'dir' : value.dir}, value.filter ? null : 'disabled', value.f_type ? 'selected' : null)}} -
- {{/for}} -
-
- -
- Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s -
-
- {{:helper.link('Set Flow Rate Limit', null, {'command' : 'set_flow_rate'})}} -
- - {{else}} - -
-
-
Port
- {{for data.ports}} -
{{:value.dir}} Port
- {{/for}} -
-
-
Mode
- {{for data.ports}} -
- {{if value.input}} - Input - {{else value.output}} - Output - {{else value.f_type}} - {{:value.f_type}} - {{else}} - Disabled - {{/if}} -
- {{/for}} -
-
- -
- Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s -
- -
- Flow Rate: {{:(data.last_flow_rate/10)}} L/s -
- {{/if}} -
\ No newline at end of file diff --git a/nano/templates/omni_mixer.tmpl b/nano/templates/omni_mixer.tmpl deleted file mode 100644 index 3d637687553..00000000000 --- a/nano/templates/omni_mixer.tmpl +++ /dev/null @@ -1,101 +0,0 @@ -
-
- {{:helper.link(data.power ? 'On' : 'Off', null, {'command' : 'power'}, data.config ? 'disabled' : null)}} -
-
- {{:helper.link('Configure', null, {'command' : 'configure'}, null, data.config ? 'selected' : null)}} -
- - {{if data.config}} - -
-
-
Port
- {{for data.ports}} -
{{:value.dir}} Port
- {{/for}} -
-
-
Input
- {{for data.ports}} -
- {{:helper.link(' ', null, value.input ? {'command' : 'switch_mode', 'mode' : 'none', 'dir' : value.dir} : {'command' : 'switch_mode', 'mode' : 'in', 'dir' : value.dir}, value.output ? 'disabled' : null, value.input ? 'selected' : null)}} -
- {{/for}} -
-
-
Output
- {{for data.ports}} -
- {{:helper.link(' ', null, value.output ? null : {'command' : 'switch_mode', 'mode' : 'out', 'dir' : value.dir}, null, value.output ? 'selected' : null)}} -
- {{/for}} -
-
-
Concentration
- {{for data.ports}} -
- {{:helper.link( value.input ? helper.round(value.concentration*100)+' %' : '-', null, {'command' : 'switch_con', 'dir' : value.dir}, value.input ? null : 'disabled')}} -
- {{/for}} -
-
-
Lock
- {{for data.ports}} -
- {{:helper.link(' ', value.con_lock ? 'lock' : 'unlock', {'command' : 'switch_conlock', 'dir' : value.dir}, value.input ? null : 'disabled', value.con_lock ? 'selected' : null)}} -
- {{/for}} -
-
- -
- Set Flow Rate Limit: {{:(data.set_flow_rate/10)}} L/s -
-
- {{:helper.link('Set Flow Rate Limit', null, {'command' : 'set_flow_rate'})}} -
- - {{else}} - -
-
-
Port
- {{for data.ports}} -
{{:value.dir}} Port
- {{/for}} -
-
-
Mode
- {{for data.ports}} -
- {{if value.input}} - Input - {{else value.output}} - Output - {{else}} - Disabled - {{/if}} -
- {{/for}} -
-
-
Concentration
- {{for data.ports}} -
- {{if value.input}} - {{:helper.round(value.concentration*100)}} % - {{else}} - - - {{/if}} -
- {{/for}} -
-
- -
- Flow Rate: {{:(data.last_flow_rate/10)}} L/s -
- - {{/if}} -
\ No newline at end of file diff --git a/nano/templates/radio_basic.tmpl b/nano/templates/radio_basic.tmpl deleted file mode 100644 index c6a59d59691..00000000000 --- a/nano/templates/radio_basic.tmpl +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - -{{if data.useSyndMode}} - {{:helper.syndicateMode()}} -{{/if}} - -
-
- Microphone -
-
- {{if data.mic_cut}} - {{:helper.link('On', null, null, 'disabled')}} - {{:helper.link('Off', null, null, 'disabled')}} - {{else}} - {{:helper.link('On', null, {'talk' : 0}, data.mic_status ? 'selected' : null)}} - {{:helper.link('Off', null, {'talk' : 1}, data.mic_status ? null : 'selected')}} - {{/if}} -
-
- -
-
- Speaker -
-
- {{if data.spk_cut}} - {{:helper.link('On', null, null, 'disabled')}} - {{:helper.link('Off', null, null, 'disabled')}} - {{else}} - {{:helper.link('On', null, {'listen' : 0}, data.speaker ? 'selected' : null)}} - {{:helper.link('Off', null, {'listen' : 1}, data.speaker ? null : 'selected')}} - {{/if}} -
-
- -{{if data.has_subspace}} -
-
- Subspace Transmission: -
-
- {{:helper.link('On', null, {'mode' : 1}, data.subspace ? 'selected' : null)}} - {{:helper.link('Off', null, {'mode' : 0}, data.subspace ? null : 'selected')}} -
-
-{{/if}} - -{{if data.has_loudspeaker}} -
-
- Loudspeaker: -
-
- {{:helper.link('On', null, {'shutup' : 0}, data.loudspeaker ? 'selected' : null)}} - {{:helper.link('Off', null, {'shutup' : 1}, data.loudspeaker ? null : 'selected')}} -
-
-{{/if}} - -
-
- Frequency: {{:data.freq}} -
-
- {{:helper.link('--', null, {'freq' : -10})}} - {{:helper.link('-', null, {'freq' : -2})}} - {{:helper.link('+', null, {'freq' : 2})}} - {{:helper.link('++', null, {'freq' : 10})}} -
-
- -{{if data.chan_list_len >= 1}} -

Channels

-
- {{for data.chan_list}} -
- {{:value.display_name}} -
-
- {{if value.secure_channel}} - {{:helper.link('On', null, {'ch_name' : value.chan, 'listen' : value.sec_channel_listen}, value.sec_channel_listen ? null : 'selected')}} - {{:helper.link('Off', null, {'ch_name' : value.chan, 'listen' : value.sec_channel_listen}, value.sec_channel_listen ? 'selected' : null)}} - {{else}} - {{:helper.link('Switch', null, {'spec_freq' : value.chan}, data.rawfreq == value.chan ? 'selected' : null)}} - {{/if}} -
- {{/for}} -
-{{/if}} \ No newline at end of file diff --git a/nano/templates/radio_electro.tmpl b/nano/templates/radio_electro.tmpl deleted file mode 100644 index 9fb8183ad01..00000000000 --- a/nano/templates/radio_electro.tmpl +++ /dev/null @@ -1,37 +0,0 @@ - -
-
- Power -
-
- {{:helper.link('On', null, {'power' : 1}, data.power ? 'selected' : null)}} - {{:helper.link('Off', null, {'power' : 1}, data.power ? null : 'selected')}} -
-
- -
-
- Frequency: {{:data.freq}} -
-
- {{:helper.link('--', null, {'freq' : -10})}} - {{:helper.link('-', null, {'freq' : -2})}} - {{:helper.link('+', null, {'freq' : 2})}} - {{:helper.link('++', null, {'freq' : 10})}} -
-
- -
-
- Code: {{:data.code}} -
-
- {{:helper.link('--', null, {'code' : -5})}} - {{:helper.link('-', null, {'code' : -1})}} - {{:helper.link('+', null, {'code' : 1})}} - {{:helper.link('++', null, {'code' : 5})}} -
-
\ No newline at end of file diff --git a/nano/templates/robot_control.tmpl b/nano/templates/robot_control.tmpl deleted file mode 100644 index 6e97ffaf3d7..00000000000 --- a/nano/templates/robot_control.tmpl +++ /dev/null @@ -1,100 +0,0 @@ -{{if data.robots}} - {{if !data.is_ai}} -
-
- Emergency Self-Destruct: -
-
- {{if data.safety}} - {{:helper.link('ARM', 'unlock', {'arm' : 1}, !data.allowed ? 'disabled' : null)}} - {{:helper.link('DETONATE', 'exclamation-circle', {'nuke' : 1}, 'disabled')}} - {{else}} - {{:helper.link('DISARM', 'lock', {'arm' : 1}, !data.allowed ? 'disabled' : null)}} - {{:helper.link('DETONATE', 'exclamation-circle', {'nuke' : 1}, !data.allowed ? 'disabled' : null, 'redButton')}} - {{/if}} -
-
-
- {{/if}} - {{for data.robots}} -
-
-

{{:value.name}}

-

Information

- - Status: - - - {{:value.status}} - - - System Integrity: - - - {{:helper.smoothRound(value.health)}}% - - - Location: - - - ({{:value.xpos}}, {{:value.ypos}}, {{:value.zpos}}): {{:value.area}} - - - Master AI: - - - {{:value.master_ai}} - - - Module: - - - {{:value.module}} - - - {{if value.hackable}} - - Safeties: - - - ENABLED - - {{else value.hacked}} - - Safeties: - - - DISABLED - - {{/if}} -

Power Cell

- {{if value.cell}} - - Rating: - - - {{:value.cell_capacity}} - - {{:helper.displayBar(value.cell_percentage, 0, 100, (value.cell_percentage >= 50) ? 'good' : (value.cell_percentage >= 25) ? 'average' : 'bad')}} - {{:helper.smoothRound(value.cell_percentage)}}% - {{else}} - Not Installed - {{:helper.displayBar(100, 0, 100, 'bad')}} - {{/if}} -

Actions

- {{if value.status == "Operational"}} - {{:helper.link('Lockdown', 'lock', {'lockdown' : value.name}, !data.allowed ? 'disabled' : null)}} - {{else}} - {{:helper.link('Unlock', 'unlock', {'lockdown' : value.name}, !data.allowed ? 'disabled' : null)}} - {{/if}} - {{:helper.link('Self-Destruct', 'exclamation-circle', {'detonate' : value.name}, !data.allowed ? 'disabled' : null, 'redButton')}} - {{if value.hackable}} - {{:helper.link('Hack', 'calculator', {'hack' : value.name}, !data.allowed ? 'disabled' : null, 'redButton')}} - {{/if}} -
- {{/for}} -{{else}} -
-

No robots were found.

-
-{{/if}} \ No newline at end of file diff --git a/nano/templates/shuttle_console.tmpl b/nano/templates/shuttle_console.tmpl deleted file mode 100644 index 8277e92eb76..00000000000 --- a/nano/templates/shuttle_console.tmpl +++ /dev/null @@ -1,37 +0,0 @@ - - -
-
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}} - {{/if}} - - {{if data.docking_request}} -
{{:helper.link('Request docking at the station', 'share-square-o', {'request' : 1})}}
- {{/if}} -{{/if}} diff --git a/nano/templates/smes.tmpl b/nano/templates/smes.tmpl deleted file mode 100644 index 2657c0f724e..00000000000 --- a/nano/templates/smes.tmpl +++ /dev/null @@ -1,89 +0,0 @@ -
-
- Stored Capacity: -
-
- {{:helper.displayBar(data.storedCapacity, 0, 100, data.charging ? 'good' : 'average')}} -
- {{:helper.smoothRound(data.storedCapacity)}}% -
-
-
- -

Input Management

-
-
- Charge Mode: -
-
- {{:helper.link('Auto', 'refresh', {'cmode' : 1}, data.chargeMode ? 'selected' : null)}}{{:helper.link('Off', 'close', {'cmode' : 1}, data.chargeMode ? null : 'selected')}} -   - {{if data.charging == 2}} - [Charging] - {{else data.charging == 1}} - [Partially Charging] - {{else}} - [Not Charging] - {{/if}} -
-
- -
-
- Input Level: -
-
- {{:helper.displayBar(data.chargeLevel, 0, data.chargeMax)}} -
- {{:helper.link('MIN', null, {'input' : 'min'}, (data.chargeLevel > 0) ? null : 'disabled')}} - {{:helper.link('SET', null, {'input' : 'set'}, null)}} - {{:helper.link('MAX', null, {'input' : 'max'}, (data.chargeLevel < data.chargeMax) ? null : 'disabled')}} -
 {{:data.chargeLevel}} W 
-
-
-
- -

Output Management

-
-
- Output Status: -
-
- {{:helper.link('Online', 'power-off', {'online' : 1}, data.outputOnline ? 'selected' : null)}}{{:helper.link('Offline', 'close', {'online' : 1}, data.outputOnline ? null : 'selected')}} -   - {{if data.outputting == 2}} - [Outputting] - {{else data.outputting == 1}} - [Stored energy too low] - {{else}} - [Not Outputting] - {{/if}} -
-
- -
-
- Output Level: -
-
- {{:helper.displayBar(data.outputLevel, 0, data.outputMax)}} -
- {{:helper.link('MIN', null, {'output' : 'min'}, (data.outputLevel > 0) ? null : 'disabled')}} - {{:helper.link('SET', null, {'output' : 'set'}, null)}} - {{:helper.link('MAX', null, {'output' : 'max'}, (data.outputLevel < data.outputMax) ? null : 'disabled')}} -
 {{:data.outputLevel}} W 
-
-
-
- -
-
- Output Load: -
-
- {{:helper.displayBar(data.outputLoad, 0, data.outputMax, (data.outputLoad < data.outputLevel) ? 'good' : 'average')}} -
- {{:helper.smoothRound(data.outputLoad)}} W -
-
-
\ No newline at end of file diff --git a/nano/templates/solar_control.tmpl b/nano/templates/solar_control.tmpl deleted file mode 100644 index f4fbf6ea739..00000000000 --- a/nano/templates/solar_control.tmpl +++ /dev/null @@ -1,96 +0,0 @@ - - -

Status

-
-
-
- Generated power: -
-
- {{:helper.smoothRound(data.generated)}} W -
-
- -
-
- Orientation: -
- -
- {{:helper.smoothRound(data.angle)}}° ({{:data.direction}})  -
- - {{:helper.link('15°', 'minus', {'rate_control' : '1', 'cdir' : '-15'})}} - {{:helper.link('1°', 'minus', {'rate_control' : '1', 'cdir' : '-1'})}} - {{:helper.link('1°', 'plus', {'rate_control' : '1', 'cdir' : '1'})}} - {{:helper.link('15°', 'plus', {'rate_control' : '1', 'cdir' : '15'})}} -
-
- -

Tracking

-
-
-
- Tracker status: -
- - {{:helper.link('Off', 'close', {'track' : '0'}, (data.tracking_state == 0) ? 'selected' : '')}} - {{:helper.link('Timed', 'clock-o', {'track' : '1'}, (data.tracking_state == 1) ? 'selected' : '')}} - {{if data.connected_tracker}} - {{:helper.link('Auto', 'signal', {'track' : '2'}, (data.tracking_state == 2) ? 'selected' : '')}} - {{else}} - {{:helper.link('Auto', 'signal', null, 'disabled')}} - {{/if}} -
- -
-
- Tracking rate: -
- -
- {{:helper.smoothRound(data.tracking_rate)}} deg/h ({{:data.rotating_way}}) -
-
- -
- {{:helper.link('180°', 'minus', {'rate_control' : '1', 'tdir' : '-180'})}} - {{:helper.link('30°', 'minus', {'rate_control' : '1', 'tdir' : '-30'})}} - {{:helper.link('1°', 'minus', {'rate_control' : '1', 'tdir' : '-1'})}} - {{:helper.link('1°', 'plus', {'rate_control' : '1', 'tdir' : '1'})}} - {{:helper.link('30°', 'plus', {'rate_control' : '1', 'tdir' : '30'})}} - {{:helper.link('180°', 'plus', {'rate_control' : '1', 'tdir' : '180'})}} -
-
- -

Connected Devices

-
-
-
- Solars panels: -
-
- {{:data.connected_panels}} connected -
-
- -
-
- Solar tracker: -
- -
- {{if data.connected_tracker}} - Found - {{else}} - Not Found - {{/if}} -
-
-
-
- {{:helper.link('Search for devices', 'refresh', {'search_connected' : '1'})}} -
diff --git a/nano/templates/spawners_menu.tmpl b/nano/templates/spawners_menu.tmpl deleted file mode 100644 index c12490bbb60..00000000000 --- a/nano/templates/spawners_menu.tmpl +++ /dev/null @@ -1,20 +0,0 @@ -
-

Mob Spawners

- - {{for data.spawners}} -
-
-

{{:value.name}}

-

{{:value.amount_left}} spawners left.

-
-
- {{:value.desc}} -
-
- {{:helper.link('Jump', null, {'action': 'jump', 'uid': value.uids}, null)}} - {{:helper.link('Spawn', null, {'action': 'spawn', 'uid': value.uids}, value.amount_left > 0 ? null : 'disabled')}} -
-
- {{/for}} -
-
diff --git a/nano/templates/tanks.tmpl b/nano/templates/tanks.tmpl deleted file mode 100644 index 2cf12746f01..00000000000 --- a/nano/templates/tanks.tmpl +++ /dev/null @@ -1,47 +0,0 @@ -{{if data.maskConnected}} -
This tank is connected to a mask.
-{{else}} -
This tank is NOT connected to a mask.
-{{/if}} - -
-
- Tank Pressure: -
-
- {{:helper.displayBar(data.tankPressure, 0, 1013, (data.tankPressure > 200) ? 'good' : ((data.tankPressure > 100) ? 'average' : 'bad'))}} -
- {{:helper.smoothRound(data.tankPressure)}} kPa -
-
-
- -
 
- -
-
- Mask Release Pressure: -
-
- {{:helper.displayBar(data.releasePressure, 0, data.maxReleasePressure, (data.releasePressure >= 23) ? null : ((data.releasePressure >= 17) ? 'average' : 'bad'))}} -
- {{:helper.link('-', null, {'dist_p' : -10}, (data.releasePressure > 0) ? null : 'disabled')}} - {{:helper.link('-', null, {'dist_p' : -1}, (data.releasePressure > 0) ? null : 'disabled')}} -
 {{:data.releasePressure}} kPa 
- {{:helper.link('+', null, {'dist_p' : 1}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}} - {{:helper.link('+', null, {'dist_p' : 10}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}} - {{:helper.link('Max', null, {'dist_p' : 'max'}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}} - {{:helper.link('Reset', null, {'dist_p' : 'reset'}, (data.releasePressure != data.defaultReleasePressure) ? null : 'disabled')}} -
-
-
- -
-
- Mask Release Valve: -
-
- {{:helper.link('Open', 'unlock', {'stat' : 1}, (!data.maskConnected) ? 'disabled' : (data.valveOpen ? 'selected' : null))}}{{:helper.link('Close', 'lock', {'stat' : 1}, data.valveOpen ? null : 'selected')}} -
-
- diff --git a/nano/templates/teleporter_console.tmpl b/nano/templates/teleporter_console.tmpl deleted file mode 100644 index 026917eb8ef..00000000000 --- a/nano/templates/teleporter_console.tmpl +++ /dev/null @@ -1,36 +0,0 @@ - -

Teleporter Status

-{{if !data.powerstation}} -
No power station linked.
-{{else !data.teleporterhub}} -
No hub linked.
-{{else}} -
-
-
Current Regime
-
{{:data.regime}}
-
-
-
Current Target
-
{{:data.target}}{{if data.target != "None"}}{{if data.regime == "Gate"}} Teleporter{{/if}}{{/if}}
-
-
-
Calibration
-
{{if data.calibrating}}In Progress{{else data.calibrated}}Optimal{{else data.accurate > 2}}Optimal{{else}}Sub-Optimal{{/if}}
-
-
-
-
{{:helper.link('Change regime', 'gear', {'regimeset': 1})}}
-
{{:helper.link('Set target', 'gear', {'settarget': 1})}}
-
-
-
{{:helper.link('Get target from memory', 'arrow-circle-down', {'lock': 1}, data.locked ? '' : 'disabled')}}
-
{{:helper.link('Eject GPS device', 'eject', {'eject': 1}, data.locked ? '' : 'disabled')}}
-
-
-
{{:helper.link('Calibrate hub', 'arrows-alt', {'calibrate': 1}, data.target == 'None' ? 'disabled' : '')}}
-
-{{/if}} \ No newline at end of file diff --git a/nano/templates/transfer_valve.tmpl b/nano/templates/transfer_valve.tmpl deleted file mode 100644 index be64b5cc6f4..00000000000 --- a/nano/templates/transfer_valve.tmpl +++ /dev/null @@ -1,56 +0,0 @@ -
-
- Attachment One: -
-
- {{if data.attachmentOne}} - {{:data.attachmentOne}} - {{else}} - None - {{/if}} - {{:helper.link('Remove', 'eject', {'tankone' : 1}, data.attachmentOne ? null : 'disabled')}} -
-
- -
-
- Attachment Two: -
-
- {{if data.attachmentTwo}} - {{:data.attachmentTwo}} - {{else}} - None - {{/if}} - {{:helper.link('Remove', 'eject', {'tanktwo' : 1}, data.attachmentTwo ? null : 'disabled')}} -
-
- -
-
- Valve Attachment: -
-
- {{if data.valveAttachment}} - {{:data.valveAttachment}} - {{else}} - None - {{/if}} - {{:helper.link('Remove', 'eject', {'rem_device' : 1}, data.valveAttachment ? null : 'disabled')}} - {{if data.valveAttachment}} - {{:helper.link('View', 'wrench', {'device' : 1})}} - {{/if}} -
-
- -
 
- -
-
- Valve Status: -
-
- {{:helper.link('Open', 'unlock', {'open' : 1}, (!data.attachmentOne || !data.attachmentTwo) ? 'disabled' : (data.valveOpen ? 'selected' : null))}}{{:helper.link('Close', 'lock', {'open' : 1}, (!data.attachmentOne || !data.attachmentTwo) ? 'disabled' : (data.valveOpen ? null : 'selected'))}} -
-
- diff --git a/nano/templates/vending_machine.tmpl b/nano/templates/vending_machine.tmpl deleted file mode 100644 index 1849e3e51d5..00000000000 --- a/nano/templates/vending_machine.tmpl +++ /dev/null @@ -1,68 +0,0 @@ - - -{{if data.mode == 0}} -

Items available

-
- {{for data.products}} -
-
- {{if value.price > 0}} - {{:helper.link('Buy (' + value.price + ')', 'shopping-cart', { "vend" : value.key }, value.amount > 0 ? null : 'disabled')}} - {{else}} - {{:helper.link('Vend', 'arrow-circle-down', { "vend" : value.key }, value.amount > 0 ? null : 'disabled')}} - {{/if}} -
-
- {{if value.color}}{{:value.name}} - {{else}}{{:value.name}} - {{/if}} - ({{:value.amount ? value.amount : "NONE LEFT"}}) -
-
- {{empty}} - No items available! - {{/for}} -
-{{if data.coin}} -

Coin

-
-
Coin deposited:
-
{{:helper.link(data.coin, 'eject', {'remove_coin' : 1})}}
-
-{{/if}} -{{if data.item_slot == 1}} -

Item Slot

-
-
Item Slot:
- {{if data.inserted_item}} -
{{:helper.link(data.inserted_item, 'eject', {'remove_item' : 1})}}
- {{else}} -
Empty
- {{/if}} -
-{{/if}} -{{else data.mode == 1}} -

Item selected

-
-
-
Item selected:
{{:data.product}}
-
Charge:
{{:data.price}}
-
-
- {{if data.message_err}} {{/if}} {{:data.message}} -
-
- {{:helper.link('Pay', 'shopping-cart', {'pay' : 1})}} - {{:helper.link('Cancel', 'arrow-left', {'cancelpurchase' : 1})}} -
-
-{{/if}} -{{if data.panel}} -

Maintenance panel

-
-
Speaker
{{:helper.link(data.speaker ? 'Enabled' : 'Disabled', 'gear', {'togglevoice' : 1})}}
-
-{{/if}} \ No newline at end of file diff --git a/paradise.dme b/paradise.dme index 6e1235bfc86..5ed4f7e3bc5 100644 --- a/paradise.dme +++ b/paradise.dme @@ -174,10 +174,6 @@ #include "code\ATMOSPHERICS\components\binary_devices\pump.dm" #include "code\ATMOSPHERICS\components\binary_devices\valve.dm" #include "code\ATMOSPHERICS\components\binary_devices\volume_pump.dm" -#include "code\ATMOSPHERICS\components\omni_devices\_omni_extras.dm" -#include "code\ATMOSPHERICS\components\omni_devices\filter.dm" -#include "code\ATMOSPHERICS\components\omni_devices\mixer.dm" -#include "code\ATMOSPHERICS\components\omni_devices\omni_base.dm" #include "code\ATMOSPHERICS\components\trinary_devices\filter.dm" #include "code\ATMOSPHERICS\components\trinary_devices\mixer.dm" #include "code\ATMOSPHERICS\components\trinary_devices\trinary_base.dm" @@ -218,6 +214,7 @@ #include "code\controllers\subsystem\assets.dm" #include "code\controllers\subsystem\atoms.dm" #include "code\controllers\subsystem\changelog.dm" +#include "code\controllers\subsystem\cleanup.dm" #include "code\controllers\subsystem\events.dm" #include "code\controllers\subsystem\fires.dm" #include "code\controllers\subsystem\garbage.dm" @@ -2081,8 +2078,6 @@ #include "code\modules\modular_computers\file_system\program_events.dm" #include "code\modules\modular_computers\file_system\programs\antagonist\dos.dm" #include "code\modules\modular_computers\file_system\programs\antagonist\revelation.dm" -#include "code\modules\modular_computers\file_system\programs\command\card.dm" -#include "code\modules\modular_computers\file_system\programs\command\comms.dm" #include "code\modules\modular_computers\file_system\programs\engineering\power_monitor.dm" #include "code\modules\modular_computers\file_system\programs\engineering\sm_monitor.dm" #include "code\modules\modular_computers\file_system\programs\generic\configurator.dm" @@ -2121,7 +2116,6 @@ #include "code\modules\nano\interaction\self.dm" #include "code\modules\nano\interaction\zlevel.dm" #include "code\modules\nano\modules\atmos_control.dm" -#include "code\modules\nano\modules\ert_manager.dm" #include "code\modules\nano\modules\human_appearance.dm" #include "code\modules\nano\modules\law_manager.dm" #include "code\modules\nano\modules\nano_module.dm" @@ -2461,6 +2455,7 @@ #include "code\modules\tgui\tgui.dm" #include "code\modules\tgui\modules\_base.dm" #include "code\modules\tgui\modules\crew_monitor.dm" +#include "code\modules\tgui\modules\ert_manager.dm" #include "code\modules\tgui\states\admin.dm" #include "code\modules\tgui\states\always.dm" #include "code\modules\tgui\states\conscious.dm" diff --git a/sound/AI/apc_overload.ogg b/sound/AI/apc_overload.ogg deleted file mode 100644 index ef9357b9eb6..00000000000 Binary files a/sound/AI/apc_overload.ogg and /dev/null differ diff --git a/sound/AI/apc_short.ogg b/sound/AI/apc_short.ogg deleted file mode 100644 index 90afc50f6fb..00000000000 Binary files a/sound/AI/apc_short.ogg and /dev/null differ diff --git a/sound/machines/machine_vend.ogg b/sound/machines/machine_vend.ogg new file mode 100644 index 00000000000..92867a1f3d3 Binary files /dev/null and b/sound/machines/machine_vend.ogg differ diff --git a/sound/weapons/jug_empty_impact.ogg b/sound/weapons/jug_empty_impact.ogg new file mode 100644 index 00000000000..d78c1c5e554 Binary files /dev/null and b/sound/weapons/jug_empty_impact.ogg differ diff --git a/sound/weapons/jug_filled_impact.ogg b/sound/weapons/jug_filled_impact.ogg new file mode 100644 index 00000000000..05e2d364373 Binary files /dev/null and b/sound/weapons/jug_filled_impact.ogg differ diff --git a/tgui/packages/tgui/constants.js b/tgui/packages/tgui/constants.js index 20ba00cb759..024278e39b3 100644 --- a/tgui/packages/tgui/constants.js +++ b/tgui/packages/tgui/constants.js @@ -54,6 +54,11 @@ export const RADIO_CHANNELS = [ freq: 1213, color: '#a52a2a', }, + { + name: 'SyndTeam', + freq: 1244, + color: '#a52a2a', + }, { name: 'Red Team', freq: 1215, @@ -65,8 +70,13 @@ export const RADIO_CHANNELS = [ color: '#3434fd', }, { - name: 'CentCom', - freq: 1337, + name: 'Response Team', + freq: 1345, + color: '#2681a5', + }, + { + name: 'Special Ops', + freq: 1341, color: '#2681a5', }, { @@ -94,6 +104,11 @@ export const RADIO_CHANNELS = [ freq: 1355, color: '#57b8f0', }, + { + name: 'Medical(I)', + freq: 1485, + color: '#57b8f0', + }, { name: 'Engineering', freq: 1357, @@ -104,9 +119,14 @@ export const RADIO_CHANNELS = [ freq: 1359, color: '#dd3535', }, + { + name: 'Security(I)', + freq: 1475, + color: '#dd3535', + }, { name: 'AI Private', - freq: 1447, + freq: 1343, color: '#d65d95', }, { diff --git a/tgui/packages/tgui/interfaces/AICard.js b/tgui/packages/tgui/interfaces/AICard.js new file mode 100644 index 00000000000..8ffe9906e2c --- /dev/null +++ b/tgui/packages/tgui/interfaces/AICard.js @@ -0,0 +1,94 @@ +import { useBackend } from "../backend"; +import { Button, ProgressBar, LabeledList, Box, Section } from "../components"; +import { Window } from "../layouts"; + +export const AICard = (props, context) => { + const { act, data } = useBackend(context); + if (data.has_ai === 0) { + return ( + + +
+ +

No AI detected.

+
+
+
+
+ ); + } else { + + let integrityColor = null; // Handles changing color of the integrity bar + if (data.integrity >= 75) { integrityColor = 'green'; } + else if (data.integrity >= 25) { integrityColor = 'yellow'; } + else { integrityColor = 'red'; } + + return ( + + +
+ +

{data.name}

+
+ + + + + + + + +

{data.flushing === 1 ? "Wipe of AI in progress..." : ""}

+
+
+ +
+ {!!data.has_laws && ( + + {data.laws.map((value, key) => ( + + {value} + + ))} + + ) || ( // Else, no laws. + +

No laws detected.

+
+ )} +
+ +
+ + +
+
+
+ ); + } +}; diff --git a/tgui/packages/tgui/interfaces/AIFixer.js b/tgui/packages/tgui/interfaces/AIFixer.js new file mode 100644 index 00000000000..7a7d65101d5 --- /dev/null +++ b/tgui/packages/tgui/interfaces/AIFixer.js @@ -0,0 +1,110 @@ +import { useBackend } from "../backend"; +import { Button, ProgressBar, Box, LabeledList, Section } from "../components"; +import { Window } from "../layouts"; + +export const AIFixer = (props, context) => { + const { act, data } = useBackend(context); + if (data.occupant === null) { + return ( + + +
+ +

No artificial intelligence detected.

+
+
+
+
+ ); + } else { + + let workingAI = null; // If the AI is dead (stat = 2) or isn't existent + if (data.stat === 2 || data.stat === null) { + workingAI = false; + } else { + workingAI = true; + } + + let integrityColor = null; // Handles changing color of the integrity bar + if (data.integrity >= 75) { integrityColor = 'green'; } + else if (data.integrity >= 25) { integrityColor = 'yellow'; } + else { integrityColor = 'red'; } + + let integrityFull = null; // If integrity >= 100, prevents overchar + if (data.integrity >= 100) { integrityFull = true; } + else { integrityFull = false; } + + + return ( + + +
+ +

{data.occupant}

+
+
+ +
+ + + + + + {workingAI ? "Functional" : "Non-Functional"} + + +
+ +
+ {!!data.has_laws && ( + + {data.laws.map((value, key) => ( + + {value} + + ))} + + ) || ( // Else, no laws. + +

No laws detected.

+
+ )} +
+ +
+ + +
+
+
+ ); + } +}; diff --git a/tgui/packages/tgui/interfaces/AtmosFilter.js b/tgui/packages/tgui/interfaces/AtmosFilter.js new file mode 100644 index 00000000000..37b99bfed7f --- /dev/null +++ b/tgui/packages/tgui/interfaces/AtmosFilter.js @@ -0,0 +1,70 @@ +import { useBackend } from "../backend"; +import { Button, Section, NumberInput, LabeledList } from "../components"; +import { Window } from "../layouts"; + +export const AtmosFilter = (props, context) => { + const { act, data } = useBackend(context); + const { + on, + pressure, + max_pressure, + filter_type, + filter_type_list, + } = data; + + return ( + + +
+ + +
+
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/AtmosMixer.js b/tgui/packages/tgui/interfaces/AtmosMixer.js new file mode 100644 index 00000000000..66621ed8f78 --- /dev/null +++ b/tgui/packages/tgui/interfaces/AtmosMixer.js @@ -0,0 +1,109 @@ +import { useBackend } from "../backend"; +import { Button, Section, NumberInput, LabeledList, Flex } from "../components"; +import { Window } from "../layouts"; + +export const AtmosMixer = (props, context) => { + const { act, data } = useBackend(context); + const { + on, + pressure, + max_pressure, + node1_concentration, + node2_concentration, + } = data; + + return ( + + +
+ + +
+
+
+ ); +}; + +const NodeControls = (props, context) => { + const { act, data } = useBackend(context); + const { + node_name, + node_ref, + } = props; + + return ( + + + {recipe.max_multiplier >= 10 && ( + + )} + {recipe.max_multiplier >= 25 && ( + + )} + {recipe.max_multiplier > 25 && ( + + )} + + + {recipe.requirements && ( + Object + .keys(recipe.requirements) + .map(mat => toTitleCase(mat) + + ": " + recipe.requirements[mat]) + .join(", ") + ) || ( + + No resources required. + + )} + + + ))} + + +
+
+ + + {metalReadable} + + + {glassReadable} + + + {totalReadable} + + + {data.fill_percent}% Full + + +
+
+ + {busyname ? busyname : "Nothing"} + +
+
+ {buildQueueItems} +
+
+
+
+ + + + ); +}; + + diff --git a/tgui/packages/tgui/interfaces/BrigTimer.js b/tgui/packages/tgui/interfaces/BrigTimer.js new file mode 100644 index 00000000000..5895b333c9c --- /dev/null +++ b/tgui/packages/tgui/interfaces/BrigTimer.js @@ -0,0 +1,123 @@ +import { Fragment } from 'inferno'; +import { useBackend } from '../backend'; +import { Button, LabeledList, Dropdown, Box, Section } from '../components'; +import { Window } from '../layouts'; + +export const BrigTimer = (props, context) => { + const { act, data } = useBackend(context); + data.nameText = data.occupant; + if (data.timing) { + if (data.prisoner_hasrec) { + data.nameText = ({data.occupant}); + } else { + data.nameText = ({data.occupant}); + } + } + let nameIcon = "pencil-alt"; + if (data.prisoner_name) { + if (!data.prisoner_hasrec) { + nameIcon = "exclamation-triangle"; + } + } + let nameOptions = []; + let i = 0; + for (i = 0; i < data.spns.length; i++) { + nameOptions.push(data.spns[i]); + } + return ( + + +
+ + + {data.cell_id} + + + {data.nameText} + + + {data.crimes} + + + {data.brigged_by} + + + {data.time_set} + + + {data.time_left} + + + +
+ {!data.timing && ( +
+ + +
+ )} +
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/CardComputer.js b/tgui/packages/tgui/interfaces/CardComputer.js new file mode 100644 index 00000000000..7e460fe1869 --- /dev/null +++ b/tgui/packages/tgui/interfaces/CardComputer.js @@ -0,0 +1,549 @@ +import { Fragment } from 'inferno'; +import { useBackend } from '../backend'; +import { Button, LabeledList, Box, Section, Table, Tabs } from '../components'; +import { Window } from '../layouts'; +import { AccessList } from './common/AccessList'; + +export const CardComputer = (props, context) => { + const { act, data } = useBackend(context); + + + let menuBlock = ( + + act("mode", { mode: 0 })} > + Job Transfers + + {!data.target_dept && ( + act("mode", { mode: 2 })} > + Access Modification + + )} + act("mode", { mode: 1 })}> + Job Management + + act("mode", { mode: 3 })}> + Records + + act("mode", { mode: 4 })}> + Department + + + ); + + + let authBlock = ( +
+ + +
+ ); + + let bodyBlock; + + switch (data.mode) { + case 0: // job transfer + if (!data.authenticated || !data.scan_name) { + bodyBlock = ( +
+ Not logged in. +
+ ); + } else if (!data.modify_name) { + bodyBlock = ( +
+ No card to modify. +
+ ); + } else if (data.target_dept) { + bodyBlock = ( +
+ + {!!data.modify_lastlog && ( + + {data.modify_lastlog} + + )} + + {data.jobs_dept.map(v => ( +
+ ); + } else { + bodyBlock = ( + +
+ +
+
+ + + {data.jobs_top.map(v => ( +
+
+ {data.card_skins.map(v => ( +
+
+ ); + } + break; + case 1: // job slot management + if (!data.authenticated || !data.scan_name) { + bodyBlock = ( +
+ Not logged in. +
+ ); + } else { + bodyBlock = ( + +
+ Next Change Available: + {data.cooldown_time ? data.cooldown_time : "Now"} +
+
+ + + + + Title + Used Slots + Total Slots + Free Slots + Close Slot + Open Slot + Priority + + {data.job_slots.map(slotData => ( + + + {slotData.title} + + + {slotData.current_positions} + + + {slotData.total_positions} + + + {slotData.total_positions + > slotData.current_positions && ( + + {slotData.total_positions + - slotData.current_positions} + + ) || ( + + 0 + + )} + + +
+
+
+ ); + } + break; + case 2: // access change + if (!data.authenticated || !data.scan_name) { + bodyBlock = ( +
+ Not logged in. +
+ ); + } else if (!data.modify_name) { + bodyBlock = ( +
+ No card to modify. +
+ ); + } else { + bodyBlock = ( + act('set', { + access: ref, + })} + grantAll={() => act('grant_all')} + denyAll={() => act('clear_all')} + grantDep={ref => act('grant_region', { + region: ref, + })} + denyDep={ref => act('deny_region', { + region: ref, + })} /> + ); + } + break; + case 3: // records + if (!data.authenticated) { + bodyBlock = ( +
+ Not logged in. +
+ ); + } else if (!data.records.length) { + bodyBlock = ( +
+ No records. +
+ ); + } else { + bodyBlock = ( +
act('wipe_all_logs')} /> + }> + + + Crewman + Old Rank + New Rank + Authorized By + Time + Reason + {!!data.iscentcom && ( + + Deleted By + + )} + + {data.records.map(record => ( + + {record.transferee} + {record.oldvalue} + {record.newvalue} + {record.whodidit} + {record.timestamp} + {record.reason} + {!!data.iscentcom && ( + + {record.deletedby} + + )} + + ))} +
+ {!!data.iscentcom && ( + +
+ ); + } + break; + case 4: // department + if (!data.authenticated || !data.scan_name) { + bodyBlock = ( +
+ Not logged in. +
+ ); + } else { + bodyBlock = ( +
+ + + Name + Rank + Sec Status + Actions + + {data.people_dept.map(record => ( + + {record.name} + {record.title} + {record.crimstat} + +
+
+ ); + } + break; + default: + bodyBlock = ( +
+ ERROR: Unknown Mode. +
+ ); + } + + return ( + + + {menuBlock} + {authBlock} + {bodyBlock} + + + ); + +}; diff --git a/tgui/packages/tgui/interfaces/CommunicationsComputer.js b/tgui/packages/tgui/interfaces/CommunicationsComputer.js new file mode 100644 index 00000000000..7e4cc98d438 --- /dev/null +++ b/tgui/packages/tgui/interfaces/CommunicationsComputer.js @@ -0,0 +1,317 @@ +import { Fragment } from 'inferno'; +import { useBackend } from '../backend'; +import { Button, LabeledList, Box, Section } from '../components'; +import { Window } from '../layouts'; + +export const CommunicationsComputer = (props, context) => { + const { act, data } = useBackend(context); + + let authReadable; + if (!data.authenticated) { + authReadable = "Not Logged In"; + } else if (data.is_ai) { + authReadable = "AI"; + } else if (data.authenticated === 1) { + authReadable = "Command"; + } else if (data.authenticated === 2) { + authReadable = "Captain"; + } else { + authReadable = "ERROR: Report This Bug!"; + } + let reportText = "View (" + data.messages.length + ")"; + let authBlock = ( + +
+ + {data.is_ai && ( + + AI + + ) || ( + +
+ {!!data.esc_section && ( +
+ + {!!data.esc_status && ( + + {data.esc_status} + + )} + {!!data.esc_callable && ( + +
+ )} +
+ ); + let announceText = "Make Priority Announcement"; + if (data.msg_cooldown > 0) { + announceText += " (" + data.msg_cooldown + "s)"; + } + let ccMessageText = data.emagged ? "Message [UNKNOWN]" : "Message CentComm"; + let nukeRequestText = "Request Authentication Codes"; + if (data.cc_cooldown > 0) { + ccMessageText += " (" + data.cc_cooldown + "s)"; + nukeRequestText += " (" + data.cc_cooldown + "s)"; + } + let alertLevelText = data.str_security_level; + let alertLevelButtons = data.levels.map(slevel => { + return ( + + }> + + {capacityPercent >= 100 && 'Fully Charged' + || inputting && 'Charging' + || 'Not Charging'} + +
+ + + + + }> + + {outputting + ? 'Sending' + : charge > 0 + ? 'Not Sending' + : 'No Charge'} + + + + + + + + + + + {/* The duplication of the dropdowns is due to the + updates of selected not affecting the state + of the dropdown */} + {regime === REGIME_TELEPORT && ( + act('settarget', + { + x: targetsTeleport[val]["x"], + y: targetsTeleport[val]["y"], + z: targetsTeleport[val]["z"], + })} /> + )} + {regime === REGIME_GATE && ( + act('settarget', + { + x: targetsTeleport[val]["x"], + y: targetsTeleport[val]["y"], + z: targetsTeleport[val]["z"], + })} /> + )} + {regime === REGIME_GPS && ( + + {target} + + )} + + + {target !== 'None' + && ( + + + {calibrating + && ( + + In Progress + + ) || (calibrated + && ( + + Optimal + + ) || ( + + Sub-Optimal + + ))} + + + +