diff --git a/_maps/map_files/Delta/delta.dmm b/_maps/map_files/Delta/delta.dmm index 28907e9e05e..8436f932d4a 100644 --- a/_maps/map_files/Delta/delta.dmm +++ b/_maps/map_files/Delta/delta.dmm @@ -28449,7 +28449,7 @@ /obj/machinery/light{ dir = 1 }, -/obj/machinery/computer/ordercomp, +/obj/machinery/computer/supplycomp/public, /obj/effect/decal/warning_stripes/yellow/hollow, /turf/simulated/floor/plasteel{ dir = 5; @@ -29206,7 +29206,7 @@ }, /area/hallway/primary/fore) "bed" = ( -/obj/machinery/computer/ordercomp, +/obj/machinery/computer/supplycomp/public, /turf/simulated/floor/plasteel{ dir = 8; icon_state = "purple" @@ -40663,40 +40663,16 @@ /turf/simulated/wall/r_wall, /area/engine/break_room) "byz" = ( -/obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 - }, -/obj/machinery/modular_computer/console/preset/engineering, /obj/machinery/status_display{ pixel_x = -32 }, +/obj/machinery/computer/security/engineering, /turf/simulated/floor/plasteel{ dir = 8; icon_state = "caution" }, /area/atmos) -"byA" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - tag = "" - }, -/obj/structure/chair/office/dark{ - dir = 8 - }, -/turf/simulated/floor/plasteel{ - dir = 8; - icon_state = "neutralfull" - }, -/area/atmos) "byB" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, /obj/structure/cable{ d1 = 1; d2 = 4; @@ -41937,12 +41913,7 @@ icon_state = "1-2"; tag = "" }, -/obj/machinery/modular_computer/console/preset/command, -/obj/structure/cable{ - icon_state = "0-2"; - pixel_y = 1; - d2 = 2 - }, +/obj/machinery/computer/shuttle/mining, /turf/simulated/floor/plasteel{ dir = 1; icon_state = "darkpurple" @@ -51367,18 +51338,6 @@ icon_state = "dark" }, /area/engine/break_room) -"bQf" = ( -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, -/turf/simulated/floor/plasteel{ - icon_state = "neutral"; - dir = 4 - }, -/area/crew_quarters/chief) "bQg" = ( /obj/structure/cable{ d1 = 1; @@ -51405,11 +51364,6 @@ }, /obj/structure/table/reinforced, /obj/item/clipboard, -/obj/structure/cable{ - d1 = 1; - d2 = 8; - icon_state = "1-8" - }, /obj/item/toy/figure/ce, /turf/simulated/floor/plasteel{ dir = 8; @@ -54089,12 +54043,6 @@ /area/crew_quarters/chief) "bUq" = ( /obj/machinery/hologram/holopad, -/obj/structure/cable{ - d1 = 4; - d2 = 8; - icon_state = "4-8"; - pixel_x = 0 - }, /obj/effect/decal/warning_stripes/yellow/hollow, /turf/simulated/floor/plasteel{ dir = 8; @@ -55398,11 +55346,6 @@ }, /area/crew_quarters/chief) "bWl" = ( -/obj/machinery/modular_computer/console/preset/engineering, -/obj/structure/cable{ - icon_state = "0-4"; - d2 = 4 - }, /obj/machinery/keycard_auth{ pixel_x = -24 }, @@ -55420,6 +55363,7 @@ pixel_y = -8; req_access_txt = "11" }, +/obj/machinery/computer/security/engineering, /turf/simulated/floor/plasteel{ icon_state = "dark" }, @@ -58725,9 +58669,6 @@ /area/blueshield) "cce" = ( /obj/structure/table/wood, -/obj/machinery/computer/skills{ - req_one_access = null - }, /turf/simulated/floor/plasteel{ dir = 2; icon_state = "bcarpet05" @@ -59666,9 +59607,6 @@ /area/ntrep) "cdK" = ( /obj/structure/table/wood, -/obj/machinery/computer/skills{ - req_access_txt = "57" - }, /turf/simulated/floor/carpet, /area/ntrep) "cdL" = ( @@ -60483,6 +60421,9 @@ icon_state = "4-8"; tag = "" }, +/obj/machinery/computer/monitor{ + name = "Grid Power Monitoring Computer" + }, /turf/simulated/floor/plasteel{ dir = 5; icon_state = "dark"; @@ -61209,10 +61150,6 @@ /obj/machinery/tcomms/core/station, /turf/simulated/floor/bluegrid, /area/tcommsat/chamber) -"cgA" = ( -/obj/machinery/ntnet_relay, -/turf/simulated/floor/bluegrid, -/area/tcommsat/chamber) "cgB" = ( /obj/machinery/camera{ c_tag = "Singularity NorthEast"; @@ -62517,7 +62454,6 @@ dir = 1; network = list("Engineering","SS13") }, -/obj/machinery/modular_computer/console/preset/engineering, /obj/machinery/firealarm{ dir = 8; pixel_x = -26; @@ -62527,6 +62463,9 @@ icon_state = "0-4"; d2 = 4 }, +/obj/machinery/computer/monitor{ + name = "Grid Power Monitoring Computer" + }, /turf/simulated/floor/plasteel{ dir = 5; icon_state = "dark"; @@ -88635,7 +88574,7 @@ /area/maintenance/starboard) "dey" = ( /obj/structure/table/wood, -/obj/item/modular_computer/tablet/preset/cheap, +/obj/effect/spawner/lootdrop/maintenance, /turf/simulated/floor/plasteel{ icon_state = "wood" }, @@ -97243,7 +97182,6 @@ }, /area/crew_quarters/hor) "dtZ" = ( -/obj/structure/cable, /obj/structure/cable{ d1 = 1; d2 = 4; @@ -97253,7 +97191,6 @@ pixel_x = 0; pixel_y = -30 }, -/obj/machinery/modular_computer/console/preset/research, /turf/simulated/floor/plasteel{ dir = 2; icon_state = "whitepurplecorner" @@ -114782,6 +114719,9 @@ "qrT" = ( /turf/simulated/wall/r_wall, /area/tcommsat/chamber) +"rSI" = ( +/turf/simulated/floor/bluegrid, +/area/tcommsat/chamber) "udT" = ( /obj/structure/chair/comfy/shuttle{ dir = 8 @@ -123168,9 +123108,9 @@ bVO bPI bNM qrT -eaH +rSI ceL -cgu +eaH qrT qrT bkt @@ -123940,7 +123880,7 @@ bXJ bZh caX ccW -ccW +cgu ccW chW qrT @@ -124710,9 +124650,9 @@ bVT bXL bNM qrT -hng +rSI vzz -cgA +hng qrT qrT bkt @@ -138067,7 +138007,7 @@ bIr bKe bMh bOa -bQf +bOa bOa bUh bWk @@ -142426,7 +142366,7 @@ btt buD bvO ban -byA +bzY bzY bBK aOg diff --git a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm index 4152ad16382..c07960eab59 100644 --- a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm +++ b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm @@ -35305,7 +35305,7 @@ }, /area/engine/chiefs_office) "bjJ" = ( -/obj/machinery/computer/ordercomp, +/obj/machinery/computer/supplycomp/public, /obj/effect/decal/warning_stripes/yellow, /turf/simulated/floor/plasteel{ dir = 9; @@ -38185,7 +38185,7 @@ d2 = 2; icon_state = "1-2" }, -/obj/machinery/modular_computer/console/preset/command, +/obj/machinery/computer/card, /turf/simulated/floor/plasteel{ icon_state = "dark" }, @@ -41916,7 +41916,7 @@ d2 = 8; icon_state = "1-8" }, -/obj/machinery/computer/ordercomp, +/obj/machinery/computer/supplycomp/public, /turf/simulated/floor/plasteel{ icon_state = "dark" }, @@ -44531,7 +44531,7 @@ layer = 4; pixel_y = 32 }, -/obj/machinery/computer/ordercomp, +/obj/machinery/computer/supplycomp/public, /turf/simulated/floor/wood, /area/crew_quarters/heads) "byv" = ( @@ -57433,9 +57433,6 @@ }) "bVc" = ( /obj/structure/table/wood, -/obj/machinery/computer/skills{ - req_access_txt = "57" - }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /turf/simulated/floor/carpet, /area/ntrep) @@ -58264,9 +58261,6 @@ /area/blueshield) "bWI" = ( /obj/structure/table/wood, -/obj/machinery/computer/skills{ - req_one_access = null - }, /turf/simulated/floor/plasteel{ icon_state = "bcarpet05" }, @@ -96414,10 +96408,7 @@ d2 = 2; icon_state = "1-2" }, -/turf/simulated/floor/plasteel/dark, -/area/tcommsat/server) -"gIG" = ( -/obj/machinery/ntnet_relay, +/obj/machinery/tcomms/core/station, /turf/simulated/floor/bluegrid, /area/tcommsat/server) "gRw" = ( @@ -96649,10 +96640,6 @@ }, /turf/space, /area/solar/starboard) -"rUQ" = ( -/obj/machinery/tcomms/core/station, -/turf/simulated/floor/bluegrid, -/area/tcommsat/server) "sjF" = ( /obj/structure/window/reinforced{ dir = 1 @@ -151152,7 +151139,7 @@ bDf bFi bIz bKl -gIG +bOa bOb odO bKl @@ -152180,7 +152167,7 @@ bDj bFm bRo bKl -rUQ +bOa dRN kwJ bKl diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index 8f6f8d77f7f..6458f106529 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -26723,10 +26723,6 @@ dir = 4 }, /area/security/nuke_storage) -"aXS" = ( -/obj/machinery/vending/modularpc, -/turf/simulated/floor/plasteel, -/area/storage/primary) "aXU" = ( /obj/item/flag/mime, /obj/machinery/power/apc{ @@ -26847,23 +26843,13 @@ }, /area/crew_quarters/bar) "aYf" = ( -/obj/machinery/modular_computer/console/preset/command, -/obj/structure/cable{ - icon_state = "0-2"; - pixel_y = 1; - d2 = 2 - }, +/obj/machinery/computer/card, /turf/simulated/floor/plasteel{ dir = 10; icon_state = "green" }, /area/bridge) "aYg" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, /turf/simulated/floor/plasteel{ dir = 1; icon_state = "greencorner" @@ -27432,7 +27418,6 @@ /area/storage/primary) "aZf" = ( /obj/structure/table/reinforced, -/obj/machinery/computer/skills, /turf/simulated/floor/plasteel{ icon_state = "red" }, @@ -38278,11 +38263,6 @@ /turf/simulated/floor/plasteel, /area/bridge) "bup" = ( -/obj/structure/cable{ - d1 = 1; - d2 = 2; - icon_state = "1-2" - }, /obj/machinery/atmospherics/unary/vent_pump/on, /turf/simulated/floor/plasteel, /area/bridge) @@ -38895,11 +38875,6 @@ icon_state = "4-8"; tag = "" }, -/obj/structure/cable{ - d1 = 1; - d2 = 4; - icon_state = "1-4" - }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, /turf/simulated/floor/plasteel, /area/bridge) @@ -48824,7 +48799,7 @@ }, /area/engine/gravitygenerator) "bOt" = ( -/obj/machinery/computer/ordercomp, +/obj/machinery/computer/supplycomp/public, /obj/item/radio/intercom{ broadcasting = 0; name = "station intercom (General)"; @@ -51723,9 +51698,6 @@ pixel_x = 0; pixel_y = 32 }, -/obj/machinery/computer/skills{ - req_access_txt = "57" - }, /turf/simulated/floor/plasteel, /area/crew_quarters/heads) "bTd" = ( @@ -61633,9 +61605,6 @@ /area/ntrep) "cjf" = ( /obj/structure/table/wood, -/obj/machinery/computer/skills{ - req_access_txt = "57" - }, /turf/simulated/floor/carpet, /area/ntrep) "cjg" = ( @@ -66311,9 +66280,6 @@ /area/blueshield) "cqJ" = ( /obj/structure/table/wood, -/obj/machinery/computer/skills{ - req_one_access = null - }, /turf/simulated/floor/plasteel{ icon_state = "bcarpet05" }, @@ -95354,6 +95320,11 @@ icon_state = "vault" }, /area/shuttle/escape) +"kIR" = ( +/obj/structure/lattice/catwalk, +/obj/machinery/atmospherics/pipe/simple/hidden/yellow, +/turf/space, +/area/space/nearstation) "kLF" = ( /obj/machinery/atmospherics/pipe/simple/hidden/supply{ dir = 9 @@ -95987,11 +95958,6 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, /turf/simulated/wall, /area/crew_quarters/dorms) -"rOX" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/yellow, -/obj/machinery/ntnet_relay, -/turf/simulated/floor/plasteel/dark, -/area/tcommsat/chamber) "rSv" = ( /obj/structure/shuttle/engine/propulsion{ dir = 8; @@ -96038,10 +96004,6 @@ icon_state = "floor4" }, /area/shuttle/administration) -"sag" = ( -/obj/machinery/atmospherics/pipe/simple/hidden/supply, -/turf/simulated/floor/plasteel/dark, -/area/tcommsat/chamber) "sbp" = ( /turf/simulated/shuttle/wall{ icon_state = "wall3" @@ -115866,7 +115828,7 @@ aKb aNx aVi aWt -aXS +aXQ aZr bbp bdk @@ -131639,7 +131601,7 @@ dmW aaa aab aaa -iUc +aaa iUc iUc iUc @@ -131896,10 +131858,10 @@ ddC doE ddM ddO +kIR oOZ dQC fAw -rOX mkE dpe dpl @@ -132154,8 +132116,8 @@ dmB bfu dnT dpf +iUc rTy -sag wbr hyv dpd diff --git a/_maps/map_files/cyberiad/z2.dmm b/_maps/map_files/cyberiad/z2.dmm index 66f2f61abee..987c1ee28b4 100644 --- a/_maps/map_files/cyberiad/z2.dmm +++ b/_maps/map_files/cyberiad/z2.dmm @@ -9856,7 +9856,7 @@ }, /area/admin) "xV" = ( -/obj/machinery/computer/ordercomp, +/obj/machinery/computer/supplycomp/public, /turf/unsimulated/floor{ tag = "icon-floor"; icon_state = "floor" diff --git a/code/ATMOSPHERICS/atmospherics.dm b/code/ATMOSPHERICS/atmospherics.dm index 8dd95119aff..6f65661e2d4 100644 --- a/code/ATMOSPHERICS/atmospherics.dm +++ b/code/ATMOSPHERICS/atmospherics.dm @@ -173,6 +173,7 @@ GLOBAL_DATUM_INIT(pipe_icon_manager, /datum/pipe_icon_manager, new()) add_fingerprint(user) var/unsafe_wrenching = FALSE + var/safefromgusts = FALSE var/I = int_air ? int_air.return_pressure() : 0 var/E = env_air ? env_air.return_pressure() : 0 var/internal_pressure = I - E @@ -190,9 +191,16 @@ GLOBAL_DATUM_INIT(pipe_icon_manager, /datum/pipe_icon_manager, new()) "You hear ratchet.") investigate_log("was REMOVED by [key_name(usr)]", "atmos") + for(var/obj/item/clothing/shoes/magboots/usermagboots in user.get_equipped_items()) + if(usermagboots.gustprotection && usermagboots.magpulse) + safefromgusts = TRUE + //You unwrenched a pipe full of pressure? let's splat you into the wall silly. if(unsafe_wrenching) - unsafe_pressure_release(user,internal_pressure) + if(safefromgusts) + to_chat(user, "Your magboots cling to the floor as a great burst of wind bellows against you.") + else + unsafe_pressure_release(user,internal_pressure) deconstruct(TRUE) else return ..() diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm index c06e863406d..1ba338e7d88 100755 --- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm @@ -274,3 +274,10 @@ return else return ..() + +#undef FILTER_NOTHING +#undef FILTER_TOXINS +#undef FILTER_OXYGEN +#undef FILTER_NITROGEN +#undef FILTER_CO2 +#undef FILTER_N2O diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 7cd4cc7a918..d000508fdeb 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -241,3 +241,9 @@ #define is_admin(user) (check_rights(R_ADMIN, 0, (user)) != 0) #define SLEEP_CHECK_DEATH(X) sleep(X); if(QDELETED(src) || stat == DEAD) return; + +// Hearing protection +#define HEARING_PROTECTION_NONE 0 +#define HEARING_PROTECTION_MINOR 1 +#define HEARING_PROTECTION_MAJOR 2 +#define HEARING_PROTECTION_TOTAL 3 diff --git a/code/__DEFINES/muzzle_flash.dm b/code/__DEFINES/muzzle_flash.dm new file mode 100644 index 00000000000..e35e1c73ca0 --- /dev/null +++ b/code/__DEFINES/muzzle_flash.dm @@ -0,0 +1,7 @@ +#define MUZZLE_FLASH_STRENGTH_WEAK 1 +#define MUZZLE_FLASH_STRENGTH_NORMAL 2 +#define MUZZLE_FLASH_STRENGTH_STRONG 3 + +#define MUZZLE_FLASH_RANGE_WEAK 1 +#define MUZZLE_FLASH_RANGE_NORMAL 2 +#define MUZZLE_FLASH_RANGE_STRONG 3 diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 829c2c4fade..d4721aa8114 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -472,3 +472,24 @@ if(!C || !C.prefs.windowflashing) return winset(C, "mainwindow", "flash=5") + +/** + * Get a bounding box of a list of atoms. + * + * Arguments: + * - atoms - List of atoms. Can accept output of view() and range() procs. + * + * Returns: list(x1, y1, x2, y2) + */ +/proc/get_bbox_of_atoms(list/atoms) + var/list/list_x = list() + var/list/list_y = list() + for(var/_a in atoms) + var/atom/a = _a + list_x += a.x + list_y += a.y + return list( + min(list_x), + min(list_y), + max(list_x), + max(list_y)) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 49c77ca0a4a..055e52663a6 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -541,7 +541,7 @@ GLOBAL_LIST_INIT(do_after_once_tracker, list()) to_chat(user, "Name = [M.name]; Real_name = [M.real_name]; Mind_name = [M.mind?"[M.mind.name]":""]; Key = [M.key];") to_chat(user, "Location = [location_description];") to_chat(user, "[special_role_description]") - to_chat(user, "(PM) ([ADMIN_PP(M,"PP")]) ([ADMIN_VV(M,"VV")]) ([ADMIN_TP(M,"TP")]) ([ADMIN_SM(M,"SM")]) ([ADMIN_FLW(M,"FLW")])") + to_chat(user, "(PM) ([ADMIN_PP(M,"PP")]) ([ADMIN_VV(M,"VV")]) ([ADMIN_TP(M,"TP")]) ([ADMIN_SM(M,"SM")]) ([ADMIN_FLW(M,"FLW")])") // Gets the first mob contained in an atom, and warns the user if there's not exactly one /proc/get_mob_in_atom_with_warning(atom/A, mob/user = usr) diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 3fb8c2400ab..46559eb6b5c 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -20,31 +20,6 @@ return 0 -//Inverts the colour of an HTML string -/proc/invertHTML(HTMLstring) - - if(!( istext(HTMLstring) )) - CRASH("Given non-text argument!") - else - if(length(HTMLstring) != 7) - CRASH("Given non-HTML argument!") - var/textr = copytext(HTMLstring, 2, 4) - var/textg = copytext(HTMLstring, 4, 6) - var/textb = copytext(HTMLstring, 6, 8) - var/r = hex2num(textr) - var/g = hex2num(textg) - var/b = hex2num(textb) - textr = num2hex(255 - r) - textg = num2hex(255 - g) - textb = num2hex(255 - b) - if(length(textr) < 2) - textr = text("0[]", textr) - if(length(textg) < 2) - textr = text("0[]", textg) - if(length(textb) < 2) - textr = text("0[]", textb) - return text("#[][][]", textr, textg, textb) - //Returns the middle-most value /proc/dd_range(var/low, var/high, var/num) return max(low,min(high,num)) @@ -449,6 +424,18 @@ Turf and target are seperate in case you want to teleport some distance from a t if(M.ckey == key) return M +/proc/get_client_by_ckey(ckey) + if(cmptext(copytext(ckey, 1, 2),"@")) + ckey = findStealthKey(ckey) + return GLOB.directory[ckey] + + +/proc/findStealthKey(txt) + if(txt) + for(var/P in GLOB.stealthminID) + if(GLOB.stealthminID[P] == txt) + return P + // Returns the atom sitting on the turf. // For example, using this on a disk, which is in a bag, on a mob, will return the mob because it's on the turf. /proc/get_atom_on_turf(var/atom/movable/M) @@ -2022,5 +2009,26 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) return TRUE return FALSE +/** + * Proc which gets all adjacent turfs to `src`, including the turf that `src` is on. + * + * This is similar to doing `for(var/turf/T in range(1, src))`. However it is slightly more performant. + * Additionally, the above proc becomes more costly the more atoms there are nearby. This proc does not care about that. + */ +/atom/proc/get_all_adjacent_turfs() + var/turf/src_turf = get_turf(src) + var/list/_list = list( + src_turf, + get_step(src_turf, NORTH), + get_step(src_turf, NORTHEAST), + get_step(src_turf, NORTHWEST), + get_step(src_turf, SOUTH), + get_step(src_turf, SOUTHEAST), + get_step(src_turf, SOUTHWEST), + get_step(src_turf, EAST), + get_step(src_turf, WEST) + ) + return _list + /// Waits at a line of code until X is true #define UNTIL(X) while(!(X)) stoplag() diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index 777a7625fe7..50c5314d0b4 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -161,7 +161,7 @@ user.examinate(src) return -/atom/proc/AICtrlClick(mob/living/silicon/ai/user) +/atom/proc/AICtrlClick(mob/living/silicon/user) return /atom/proc/AIAltClick(atom/A) @@ -182,7 +182,7 @@ // TURRETCONTROL -/obj/machinery/turretid/AICtrlClick(mob/living/silicon/ai/user) //turns off/on Turrets +/obj/machinery/turretid/AICtrlClick(mob/living/silicon/user) //turns off/on Turrets enabled = !enabled updateTurrets() @@ -194,42 +194,35 @@ // AIRLOCKS /obj/machinery/door/airlock/AIAltShiftClick(mob/user) // Sets/Unsets Emergency Access Override - emergency = !emergency - update_icon() + if(!ai_control_check(user)) + return + toggle_emergency_status(user) /obj/machinery/door/airlock/AIShiftClick(mob/user) // Opens and closes doors! - if(welded) - to_chat(user, "The airlock has been welded shut!") - if(locked) - locked = !locked - if(density) - open() - else - close() + if(!ai_control_check(user)) + return + open_close(user) -/obj/machinery/door/airlock/AICtrlClick(mob/living/silicon/ai/user) // Bolts doors - locked = !locked - update_icon() +/obj/machinery/door/airlock/AICtrlClick(mob/living/silicon/user) // Bolts doors + if(!ai_control_check(user)) + return + toggle_bolt(user) -/obj/machinery/door/airlock/AIAltClick(mob/living/silicon/ai/user) // Electrifies doors. +/obj/machinery/door/airlock/AIAltClick(mob/living/silicon/user) // Electrifies doors. + if(!ai_control_check(user)) + return if(wires.is_cut(WIRE_ELECTRIFY)) to_chat(user, "The electrification wire is cut - Cannot electrify the door.") if(isElectrified()) - electrify(0) // un-shock + electrify(0, user, TRUE) // un-shock else - electrify(-1) // permanent shock + electrify(-1, user, TRUE) // permanent shock /obj/machinery/door/airlock/AIMiddleClick(mob/living/user) // Toggles door bolt lights. - if(wires.is_cut(WIRE_BOLT_LIGHT)) - to_chat(user, "The bolt lights wire has been cut - The door bolt lights are permanently disabled.") - else if(lights) - lights = FALSE - to_chat(user, "The door bolt lights have been disabled.") - else if(!lights) - lights = TRUE - to_chat(user, "The door bolt lights have been enabled.") - update_icon() + if(!ai_control_check(user)) + return + toggle_light(user) // FIRE ALARMS diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index e61b9bdc8b6..f35b2cece0b 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -131,47 +131,47 @@ /atom/proc/BorgAltShiftClick() return -/obj/machinery/door/airlock/BorgAltShiftClick() // Enables emergency override on doors! Forwards to AI code. - AIAltShiftClick() +/obj/machinery/door/airlock/BorgAltShiftClick(mob/living/silicon/robot/user) // Enables emergency override on doors! Forwards to AI code. + AIAltShiftClick(user) /atom/proc/BorgShiftClick(var/mob/user) if(user.client && user.client.eye == user) user.examinate(src) return -/obj/machinery/door/airlock/BorgShiftClick() // Opens and closes doors! Forwards to AI code. - AIShiftClick() +/obj/machinery/door/airlock/BorgShiftClick(mob/living/silicon/robot/user) // Opens and closes doors! Forwards to AI code. + AIShiftClick(user) /atom/proc/BorgCtrlClick(var/mob/living/silicon/robot/user) //forward to human click if not overriden CtrlClick(user) -/obj/machinery/door/airlock/BorgCtrlClick() // Bolts doors. Forwards to AI code. - AICtrlClick() +/obj/machinery/door/airlock/BorgCtrlClick(mob/living/silicon/robot/user) // Bolts doors. Forwards to AI code. + AICtrlClick(user) -/obj/machinery/power/apc/BorgCtrlClick() // turns off/on APCs. Forwards to AI code. - AICtrlClick() +/obj/machinery/power/apc/BorgCtrlClick(mob/living/silicon/robot/user) // turns off/on APCs. Forwards to AI code. + AICtrlClick(user) -/obj/machinery/turretid/BorgCtrlClick() //turret control on/off. Forwards to AI code. - AICtrlClick() +/obj/machinery/turretid/BorgCtrlClick(mob/living/silicon/robot/user) //turret control on/off. Forwards to AI code. + AICtrlClick(user) /atom/proc/BorgAltClick(var/mob/living/silicon/robot/user) AltClick(user) return -/obj/machinery/door/airlock/BorgAltClick() // Eletrifies doors. Forwards to AI code. - AIAltClick() +/obj/machinery/door/airlock/BorgAltClick(mob/living/silicon/robot/user) // Eletrifies doors. Forwards to AI code. + AIAltClick(user) -/obj/machinery/turretid/BorgAltClick() //turret lethal on/off. Forwards to AI code. - AIAltClick() +/obj/machinery/turretid/BorgAltClick(mob/living/silicon/robot/user) //turret lethal on/off. Forwards to AI code. + AIAltClick(user) -/obj/machinery/ai_slipper/BorgCtrlClick() //Turns liquid dispenser on or off +/obj/machinery/ai_slipper/BorgCtrlClick(mob/living/silicon/robot/user) //Turns liquid dispenser on or off ToggleOn() -/obj/machinery/ai_slipper/BorgAltClick() //Dispenses liquid if on +/obj/machinery/ai_slipper/BorgAltClick(mob/living/silicon/robot/user) //Dispenses liquid if on Activate() -/obj/machinery/firealarm/BorgCtrlClick() - AICtrlClick() +/obj/machinery/firealarm/BorgCtrlClick(mob/living/silicon/robot/user) + AICtrlClick(user) /* As with AI, these are not used in click code, diff --git a/code/_onclick/hud/map_popups.dm b/code/_onclick/hud/map_popups.dm new file mode 100644 index 00000000000..dc9e255cba9 --- /dev/null +++ b/code/_onclick/hud/map_popups.dm @@ -0,0 +1,170 @@ +/client + /** + * Assoc list with all the active maps - when a screen obj is added to + * a map, it's put in here as well. + * + * Format: list( = list(/obj/screen)) + */ + var/list/screen_maps = list() + +/obj/screen + /** + * Map name assigned to this object. + * Automatically set by /client/proc/add_obj_to_map. + */ + var/assigned_map + /** + * Mark this object as garbage-collectible after you clean the map + * it was registered on. + * + * This could probably be changed to be a proc, for conditional removal. + * But for now, this works. + */ + var/del_on_map_removal = TRUE + +/** + * A screen object, which acts as a container for turfs and other things + * you want to show on the map, which you usually attach to "vis_contents". + */ +/obj/screen/map_view + // Map view has to be on the lowest plane to enable proper lighting + layer = GAME_PLANE + plane = GAME_PLANE + +/** + * A generic background object. + * It is also implicitly used to allocate a rectangle on the map, which will + * be used for auto-scaling the map. + */ +/obj/screen/background + name = "background" + icon = 'icons/mob/map_backgrounds.dmi' + icon_state = "clear" + layer = GAME_PLANE + plane = GAME_PLANE + +/** + * Sets screen_loc of this screen object, in form of point coordinates, + * with optional pixel offset (px, py). + * + * If applicable, "assigned_map" has to be assigned before this proc call. + */ +/obj/screen/proc/set_position(x, y, px = 0, py = 0) + if(assigned_map) + screen_loc = "[assigned_map]:[x]:[px],[y]:[py]" + else + screen_loc = "[x]:[px],[y]:[py]" + +/** + * Sets screen_loc to fill a rectangular area of the map. + * + * If applicable, "assigned_map" has to be assigned before this proc call. + */ +/obj/screen/proc/fill_rect(x1, y1, x2, y2) + if(assigned_map) + screen_loc = "[assigned_map]:[x1],[y1] to [x2],[y2]" + else + screen_loc = "[x1],[y1] to [x2],[y2]" + +/** + * Registers screen obj with the client, which makes it visible on the + * assigned map, and becomes a part of the assigned map's lifecycle. + */ +/client/proc/register_map_obj(obj/screen/screen_obj) + if(!screen_obj.assigned_map) + CRASH("Can't register [screen_obj] without 'assigned_map' property.") + if(!screen_maps[screen_obj.assigned_map]) + screen_maps[screen_obj.assigned_map] = list() + // NOTE: Possibly an expensive operation + var/list/screen_map = screen_maps[screen_obj.assigned_map] + if(!screen_map.Find(screen_obj)) + screen_map += screen_obj + if(!screen.Find(screen_obj)) + screen += screen_obj + +/** + * Clears the map of registered screen objects. + * + * Not really needed most of the time, as the client's screen list gets reset + * on relog. any of the buttons are going to get caught by garbage collection + * anyway. they're effectively qdel'd. + */ +/client/proc/clear_map(map_name) + if(!map_name || !(map_name in screen_maps)) + return FALSE + for(var/obj/screen/screen_obj in screen_maps[map_name]) + screen_maps[map_name] -= screen_obj + if(screen_obj.del_on_map_removal) + qdel(screen_obj) + screen_maps -= map_name + +/** + * Clears all the maps of registered screen objects. + */ +/client/proc/clear_all_maps() + for(var/map_name in screen_maps) + clear_map(map_name) + +/** + * Creates a popup window with a basic map element in it, without any + * further initialization. + * + * Ratio is how many pixels by how many pixels (keep it simple). + * + * Returns a map name. + */ +/client/proc/create_popup(name, ratiox = 100, ratioy = 100) + winclone(src, "popupwindow", name) + var/list/winparams = list() + winparams["size"] = "[ratiox]x[ratioy]" + winparams["on-close"] = "handle-popup-close [name]" + winset(src, "[name]", list2params(winparams)) + winshow(src, "[name]", 1) + + var/list/params = list() + params["parent"] = "[name]" + params["type"] = "map" + params["size"] = "[ratiox]x[ratioy]" + params["anchor1"] = "0,0" + params["anchor2"] = "[ratiox],[ratioy]" + winset(src, "[name]_map", list2params(params)) + + return "[name]_map" + +/** + * Create the popup, and get it ready for generic use by giving + * it a background. + * + * Width and height are multiplied by 64 by default. + */ +/client/proc/setup_popup(popup_name, width = 9, height = 9, \ + tilesize = 2, bg_icon) + if(!popup_name) + return + clear_map("[popup_name]_map") + var/x_value = world.icon_size * tilesize * width + var/y_value = world.icon_size * tilesize * height + var/map_name = create_popup(popup_name, x_value, y_value) + + var/obj/screen/background/background = new + background.assigned_map = map_name + background.fill_rect(1, 1, width, height) + if(bg_icon) + background.icon_state = bg_icon + register_map_obj(background) + + return map_name + +/** + * Closes a popup. + */ +/client/proc/close_popup(popup) + winshow(src, popup, 0) + handle_popup_close(popup) + +/** + * When the popup closes in any way (player or proc call) it calls this. + */ +/client/verb/handle_popup_close(window_id as text) + set hidden = TRUE + clear_map("[window_id]_map") diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 1423720f8f6..9795975a090 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -483,7 +483,7 @@ var/list/cached_healthdoll_overlays = list() // List of icon states (strings) for overlays /obj/screen/healthdoll/Click() - if(ishuman(usr)) + if(ishuman(usr) && !usr.is_dead()) var/mob/living/carbon/H = usr H.check_self_for_injuries() diff --git a/code/controllers/subsystem/shuttles.dm b/code/controllers/subsystem/shuttles.dm index 67b6a1b8dd7..c86f988bcd4 100644 --- a/code/controllers/subsystem/shuttles.dm +++ b/code/controllers/subsystem/shuttles.dm @@ -31,7 +31,7 @@ SUBSYSTEM_DEF(shuttle) var/points_per_intel = 250 //points gained per intel returned var/points_per_plasma = 5 //points gained per plasma returned var/points_per_design = 25 //points gained per research design returned - var/centcom_message = "" //Remarks from Centcom on how well you checked the last order. + var/centcom_message = null //Remarks from Centcom on how well you checked the last order. var/list/discoveredPlants = list() //Typepaths for unusual plants we've already sent CentComm, associated with their potencies var/list/techLevels = list() var/list/researchDesigns = list() @@ -61,6 +61,8 @@ SUBSYSTEM_DEF(shuttle) supply_packs["[P.type]"] = P initial_move() + centcom_message = "
---[station_time_timestamp()]---

Remember to stamp and send back the supply manifests.
" + return ..() /datum/controller/subsystem/shuttle/stat_entry(msg) @@ -252,7 +254,7 @@ SUBSYSTEM_DEF(shuttle) /datum/controller/subsystem/shuttle/proc/generateSupplyOrder(packId, _orderedby, _orderedbyRank, _comment, _crates) if(!packId) return - var/datum/supply_packs/P = supply_packs["[packId]"] + var/datum/supply_packs/P = locateUID(packId) if(!P) return diff --git a/code/controllers/subsystem/tickets/mentor_tickets.dm b/code/controllers/subsystem/tickets/mentor_tickets.dm index af4ea2e914d..97f84263a45 100644 --- a/code/controllers/subsystem/tickets/mentor_tickets.dm +++ b/code/controllers/subsystem/tickets/mentor_tickets.dm @@ -25,4 +25,4 @@ GLOBAL_REAL(SSmentor_tickets, /datum/controller/subsystem/tickets/mentor_tickets message_mentorTicket(msg) /datum/controller/subsystem/tickets/mentor_tickets/create_other_system_ticket(datum/ticket/T) - SStickets.newTicket(T.clientName, T.content, T.title) + SStickets.newTicket(get_client_by_ckey(T.client_ckey), T.content, T.title) diff --git a/code/controllers/subsystem/tickets/tickets.dm b/code/controllers/subsystem/tickets/tickets.dm index 64f91e96b6c..60f3a5fa8dd 100644 --- a/code/controllers/subsystem/tickets/tickets.dm +++ b/code/controllers/subsystem/tickets/tickets.dm @@ -93,7 +93,7 @@ SUBSYSTEM_DEF(tickets) var/datum/ticket/T = new(title, passedContent, getTicketCounterAndInc()) allTickets += T - T.clientName = C + T.client_ckey = C.ckey T.locationSent = C.mob.loc.name T.mobControlled = C.mob @@ -139,14 +139,16 @@ SUBSYSTEM_DEF(tickets) /datum/controller/subsystem/tickets/proc/convert_ticket(datum/ticket/T) T.ticketState = TICKET_CLOSED var/client/C = usr.client - to_chat_safe(T.clientName, list("[key_name_hidden(C)] has converted your ticket to a [other_ticket_name] ticket.",\ + var/client/owner = get_client_by_ckey(T.client_ckey) + to_chat_safe(owner, list("[key_name_hidden(C)] has converted your ticket to a [other_ticket_name] ticket.",\ "Be sure to use the correct type of help next time!")) message_staff("[C] has converted ticket number [T.ticketNum] to a [other_ticket_name] ticket.") log_game("[C] has converted ticket number [T.ticketNum] to a [other_ticket_name] ticket.") create_other_system_ticket(T) /datum/controller/subsystem/tickets/proc/create_other_system_ticket(datum/ticket/T) - SSmentor_tickets.newTicket(T.clientName, T.content, T.title) + var/client/C = get_client_by_ckey(T.client_ckey) + SSmentor_tickets.newTicket(C, T.content, T.title) /datum/controller/subsystem/tickets/proc/autoRespond(N) if(!check_rights(rights_needed)) @@ -177,7 +179,7 @@ SUBSYSTEM_DEF(tickets) sorted_responses += key var/message_key = input("Select an autoresponse. This will mark the ticket as resolved.", "Autoresponse") as null|anything in sortTim(sorted_responses, /proc/cmp_text_asc) //use sortTim and cmp_text_asc to sort alphabetically - + var/client/ticket_owner = get_client_by_ckey(T.client_ckey) switch(message_key) if(null) //they cancelled T.staffAssigned = initial(T.staffAssigned) //if they cancel we dont need to hold this ticket anymore @@ -189,18 +191,18 @@ SUBSYSTEM_DEF(tickets) C.man_up(returnClient(N)) T.lastStaffResponse = "Autoresponse: [message_key]" resolveTicket(N) - message_staff("[C] has auto responded to [T.clientName]\'s adminhelp with: [message_key] ") - log_game("[C] has auto responded to [T.clientName]\'s adminhelp with: [response_phrases[message_key]]") + message_staff("[C] has auto responded to [ticket_owner]\'s adminhelp with: [message_key] ") + log_game("[C] has auto responded to [ticket_owner]\'s adminhelp with: [response_phrases[message_key]]") if("Mentorhelp") convert_ticket(T) else var/msg_sound = sound('sound/effects/adminhelp.ogg') SEND_SOUND(returnClient(N), msg_sound) to_chat_safe(returnClient(N), "[key_name_hidden(C)] is autoresponding with: [response_phrases[message_key]]")//for this we want the full value of whatever key this is to tell the player so we do response_phrases[message_key] - message_staff("[C] has auto responded to [T.clientName]\'s adminhelp with: [message_key] ") //we want to use the short named keys for this instead of the full sentence which is why we just do message_key + message_staff("[C] has auto responded to [ticket_owner]\'s adminhelp with: [message_key] ") //we want to use the short named keys for this instead of the full sentence which is why we just do message_key T.lastStaffResponse = "Autoresponse: [message_key]" resolveTicket(N) - log_game("[C] has auto responded to [T.clientName]\'s adminhelp with: [response_phrases[message_key]]") + log_game("[C] has auto responded to [ticket_owner]\'s adminhelp with: [response_phrases[message_key]]") //Set ticket state with key N to closed /datum/controller/subsystem/tickets/proc/closeTicket(N) @@ -214,7 +216,7 @@ SUBSYSTEM_DEF(tickets) //Check if the user already has a ticket open and within the cooldown period. /datum/controller/subsystem/tickets/proc/checkForOpenTicket(client/C) for(var/datum/ticket/T in allTickets) - if(T.clientName == C && T.ticketState == TICKET_OPEN && (T.ticketCooldown > world.time)) + if(T.client_ckey == C.ckey && T.ticketState == TICKET_OPEN && (T.ticketCooldown > world.time)) return T return FALSE @@ -222,7 +224,7 @@ SUBSYSTEM_DEF(tickets) /datum/controller/subsystem/tickets/proc/checkForTicket(client/C) var/list/tickets = list() for(var/datum/ticket/T in allTickets) - if(T.clientName == C && (T.ticketState == TICKET_OPEN || T.ticketState == TICKET_STALE)) + if(T.client_ckey == C.ckey && (T.ticketState == TICKET_OPEN || T.ticketState == TICKET_STALE)) tickets += T if(tickets.len) return tickets @@ -231,7 +233,7 @@ SUBSYSTEM_DEF(tickets) //return the client of a ticket number /datum/controller/subsystem/tickets/proc/returnClient(N) var/datum/ticket/T = allTickets[N] - return T.clientName + return get_client_by_ckey(T.client_ckey) /datum/controller/subsystem/tickets/proc/assignStaffToTicket(client/C, N) var/datum/ticket/T = allTickets[N] @@ -244,7 +246,8 @@ SUBSYSTEM_DEF(tickets) /datum/ticket var/ticketNum // Ticket number - var/clientName // Client which opened the ticket + /// ckey of the client who opened the ticket + var/client_ckey var/timeOpened // Time the ticket was opened var/title //The initial message with links var/list/content // content of the staff help @@ -379,7 +382,7 @@ UI STUFF dat += "

Ticket #[T.ticketNum]

" - dat += "

[T.clientName] / [T.mobControlled] opened this [ticket_name] at [T.timeOpened] at location [T.locationSent]

" + dat += "

[T.client_ckey] / [T.mobControlled] opened this [ticket_name] at [T.timeOpened] at location [T.locationSent]

" dat += "

Ticket Status: [status]" dat += "" dat += "" diff --git a/code/datums/action.dm b/code/datums/action.dm index 1a146467b5a..84702757e86 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -162,6 +162,14 @@ /datum/action/item_action/print_report name = "Print Report" +/datum/action/item_action/print_forensic_report + name = "Print Report" + button_icon_state = "scanner_print" + use_itemicon = FALSE + +/datum/action/item_action/clear_records + name = "Clear Scanner Records" + /datum/action/item_action/toggle_gunlight name = "Toggle Gunlight" diff --git a/code/datums/components/proximity_monitor.dm b/code/datums/components/proximity_monitor.dm new file mode 100644 index 00000000000..cf5de38b387 --- /dev/null +++ b/code/datums/components/proximity_monitor.dm @@ -0,0 +1,139 @@ +/** + * # Proximity monitor component + * + * Attaching this component to an atom means that the atom will be able to detect mobs/objs moving within a 1 tile of it. + * + * The component creates several `obj/effect/abstract/proximity_checker` objects, which follow the parent atom around, always making sure it's at the center. + * When something crosses one of these `proximiy_checker`s, the parent has the `HasProximity()` proc called on it, with the crossing mob/obj as the argument. + */ +/datum/component/proximity_monitor + var/atom/owner + /// A list of currently created `/obj/effect/abstract/proximity_checker`s in use with this component. + var/list/proximity_checkers + +/datum/component/proximity_monitor/Initialize() + . = ..() + if(!isatom(parent)) + return COMPONENT_INCOMPATIBLE + owner = parent + create_prox_checkers() + +/datum/component/proximity_monitor/Destroy(force, silent) + QDEL_LIST(proximity_checkers) + owner = null + return ..() + +/datum/component/proximity_monitor/RegisterWithParent() + . = ..() + if(ismovable(parent)) + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/HandleMove) + +/datum/component/proximity_monitor/UnregisterFromParent() + . = ..() + if(ismovable(parent)) + UnregisterSignal(parent, COMSIG_MOVABLE_MOVED) + +/** + * Called when the `parent` receives the `COMSIG_MOVABLE_MOVED` signal, which occurs when it `Move()`s + * + * Code is only ran when there is no `Dir`, which occurs when the parent is teleported, gets placed into a storage item, dropped, or picked up. + * Normal movement, for example moving 1 tile to the west, is handled by the `proximity_checker` objects. + * + * Arguments: + * * source - this will be the `parent` + * * OldLoc - the location the parent just moved from + * * Dir - the direction the parent just moved in + * * forced - if we were forced to move + */ +/datum/component/proximity_monitor/proc/HandleMove(datum/source, atom/OldLoc, Dir, forced) + if(!Dir) // No dir means the parent teleported, or moved in a non-standard way like getting placed into disposals, onto a table, dropped, picked up, etc. + recenter_prox_checkers() + +/** + * Called in Initialize(). Generates a set of `/obj/effect/abstract/proximity_checker` objects around the parent, and registers signals to them. + */ +/datum/component/proximity_monitor/proc/create_prox_checkers() + proximity_checkers = list() + for(var/turf/T in range(1, get_turf(parent))) + var/obj/effect/abstract/proximity_checker/P = new(T, parent) + proximity_checkers += P + // Basic movement for the proximity_checker objects. The objects will move 1 tile in the direction the parent just moved. + P.RegisterSignal(parent, COMSIG_MOVABLE_MOVED, /obj/effect/abstract/proximity_checker/.proc/HandleMove) + +/** + * Re-centers all of the parent's `proximity_checker`s around its current location. + */ +/datum/component/proximity_monitor/proc/recenter_prox_checkers() + var/list/prox_checkers = owner.get_all_adjacent_turfs() + for(var/checker in proximity_checkers) + var/obj/effect/abstract/proximity_checker/P = checker + P.loc = pick_n_take(prox_checkers) + +/** + * # Proximity checker abstract object + * + * Inteded for use with the proximity checker component (/datum/component/proximity_monitor). + * Whenever a movable atom crosses this object, it calls `HasProximity()` on the object which is listening for proximity (`hasprox_receiver`). + */ +/obj/effect/abstract/proximity_checker + name = "Proximity checker" + /// Whether or not the proximity checker is listening for things crossing it. + var/active + /// The linked atom which has the proximity_monitor component, and will recieve the `HasProximity()` calls. + var/atom/hasprox_receiver + +// If this object is initialized without a `_hasprox_receiver` arg, it is qdel'd. +/obj/effect/abstract/proximity_checker/Initialize(mapload, atom/_hasprox_receiver) + if(_hasprox_receiver) + hasprox_receiver = _hasprox_receiver + RegisterSignal(hasprox_receiver, COMSIG_PARENT_QDELETING, .proc/OnParentDeletion) + if(isturf(hasprox_receiver.loc)) // if the reciever is inside a locker/crate/etc, they don't detect proximity + active = TRUE + else + stack_trace("/obj/effect/abstract/proximity_checker created without a receiver") + return INITIALIZE_HINT_QDEL + return ..() + +/obj/effect/abstract/proximity_checker/Destroy() + hasprox_receiver = null + return ..() + +/** + * Called when the `hasprox_receiver` receives the `COMSIG_PARENT_QDELETING` signal. When the receiver is deleted, so is this object. + * + * Arugments: + * * source - this will be the `hasprox_receiver` + * * force - the force flag taken from the qdel proc currently running on `hasprox_receiver` + */ +/obj/effect/abstract/proximity_checker/proc/OnParentDeletion(datum/source, force = FALSE) + qdel(src) + +/** + * Something crossed over the proximity_checker. Notify the `hasprox_receiver` it has proximity with something. Only fires if the checker is `active`. + */ +/obj/effect/abstract/proximity_checker/Crossed(atom/movable/AM, oldloc) + set waitfor = FALSE + if(active) + hasprox_receiver.HasProximity(AM) + +/** + * Moves the proximity_checker 1 tile in the `Dir` direction. + * + * If `Dir` is null it will be recentered around the receiver via the `recenter_prox_checkers()` proc. + * If the new location of the receiver is NOT a turf, set `active` to FALSE, so that it does not receive proximity calls. + * If the new location of the receiver IS a turf, set `active` to TRUE, so that it can receive proximity calls again. + * + * Arguments: + * * source - this will be the `hasprox_receiver` + * * OldLoc - the location the `hasprox_receiver` just moved from + * * Dir - the direction the `hasprox_receiver` just moved in + * * forced - if we were forced to move + */ +/obj/effect/abstract/proximity_checker/proc/HandleMove(datum/source, atom/OldLoc, Dir, forced) + if(Dir) + loc = get_step(src, Dir) // Basic movement 1 tile in some direction. + return + if(!isturf(hasprox_receiver.loc)) + active = FALSE // Receiver shouldn't detect proximity while picked up, in a backpack, closet, etc. + else + active = TRUE // Receiver can detect proximity again because it's on a turf. diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index c8f2b6bb99b..98272825e2f 100644 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -55,6 +55,8 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY var/list/announce_beacons = list() // Particular beacons that we'll notify the relevant department when we reach var/special = FALSE //Event/Station Goals/Admin enabled packs var/special_enabled = FALSE + /// List of names for being done in TGUI + var/list/tgui_manifest = list() /datum/supply_packs/New() @@ -63,8 +65,12 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY if(!path) continue var/atom/movable/AM = path manifest += "
  • [initial(AM.name)]
  • " + // Add the name to the UI manifest + tgui_manifest += "[initial(AM.name)]" manifest += "" + + ////// Use the sections to keep things tidy please /Malkevin ////////////////////////////////////////////////////////////////////////////// @@ -344,6 +350,14 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY cost = 15 containername = "tactical armor crate" +/datum/supply_packs/security/armory/webbing + name = "Webbing Crate" + contains = list(/obj/item/storage/belt/security/webbing, + /obj/item/storage/belt/security/webbing, + /obj/item/storage/belt/security/webbing) + cost = 15 + containername = "tactical webbing crate" + /datum/supply_packs/security/armory/swat name = "SWAT gear crate" contains = list(/obj/item/clothing/head/helmet/swat, @@ -980,12 +994,6 @@ GLOBAL_LIST_INIT(all_supply_groups, list(SUPPLY_EMERGENCY,SUPPLY_SECURITY,SUPPLY containername = "shield generators crate" access = ACCESS_TELEPORTER -/datum/supply_packs/science/modularpc - name = "Deluxe Silicate Selections restocking unit" - cost = 15 - contains = list(/obj/item/vending_refill/modularpc) - containername = "computer supply crate" - /datum/supply_packs/science/transfer_valves name = "Tank Transfer Valves Crate" contains = list(/obj/item/transfer_valve, diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index 42f74e234a0..36bd35462d6 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -1183,7 +1183,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) /datum/uplink_item/stealthy_tools/camera_bug name = "Camera Bug" - desc = "Enables you to view all cameras on the network and track a target. Bugging cameras allows you to disable them remotely." + desc = "Enables you to view all cameras on the network to track a target." reference = "CB" item = /obj/item/camera_bug cost = 1 diff --git a/code/defines/procs/admin.dm b/code/defines/procs/admin.dm index 23b485ad252..fa5556b4e40 100644 --- a/code/defines/procs/admin.dm +++ b/code/defines/procs/admin.dm @@ -42,11 +42,11 @@ if(key) if(C && C.holder && C.holder.fakekey && !include_name) if(include_link) - . += "" + . += "" . += "Administrator" else if(include_link && C) - . += "" + . += "" . += key if(include_link) diff --git a/code/game/area/ai_monitored.dm b/code/game/area/ai_monitored.dm index 723574ee949..abfcb7210b0 100644 --- a/code/game/area/ai_monitored.dm +++ b/code/game/area/ai_monitored.dm @@ -9,6 +9,7 @@ for(var/obj/machinery/camera/M in src) if(M.isMotion()) motioncameras.Add(M) + M.AddComponent(/datum/component/proximity_monitor) M.set_area_motion(src) /area/ai_monitored/Entered(atom/movable/O) diff --git a/code/game/gamemodes/changeling/powers/mutations.dm b/code/game/gamemodes/changeling/powers/mutations.dm index d12b970d884..be88e0bb6e0 100644 --- a/code/game/gamemodes/changeling/powers/mutations.dm +++ b/code/game/gamemodes/changeling/powers/mutations.dm @@ -221,6 +221,7 @@ projectile_type = /obj/item/projectile/tentacle caliber = "tentacle" icon_state = "tentacle_end" + muzzle_flash_effect = null var/obj/item/gun/magic/tentacle/gun //the item that shot it /obj/item/ammo_casing/magic/tentacle/New(obj/item/gun/magic/tentacle/tentacle_gun) diff --git a/code/game/gamemodes/changeling/powers/shriek.dm b/code/game/gamemodes/changeling/powers/shriek.dm index 867328c40b3..06332f61670 100644 --- a/code/game/gamemodes/changeling/powers/shriek.dm +++ b/code/game/gamemodes/changeling/powers/shriek.dm @@ -11,6 +11,10 @@ /datum/action/changeling/resonant_shriek/sting_action(var/mob/user) for(var/mob/living/M in get_mobs_in_view(4, user)) if(iscarbon(M)) + if(ishuman(M)) + var/mob/living/carbon/human/H = M + if(H.check_ear_prot() >= HEARING_PROTECTION_TOTAL) + continue if(!M.mind || !M.mind.changeling) M.MinimumDeafTicks(30) M.AdjustConfused(20) diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm index 406ab50b70d..0ff7192a7e6 100644 --- a/code/game/gamemodes/vampire/vampire_powers.dm +++ b/code/game/gamemodes/vampire/vampire_powers.dm @@ -264,7 +264,7 @@ continue if(ishuman(C)) var/mob/living/carbon/human/H = C - if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) || istype(H.r_ear, /obj/item/clothing/ears/earmuffs)) + if(H.check_ear_prot() >= HEARING_PROTECTION_TOTAL) continue if(!affects(C)) continue diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm index efa3303c26b..8efb04483cb 100644 --- a/code/game/gamemodes/wizard/spellbook.dm +++ b/code/game/gamemodes/wizard/spellbook.dm @@ -80,7 +80,7 @@ user.mind.spell_list.Remove(aspell) qdel(aspell) if(S) //If we created a temporary spell above, delete it now. - qdel(S) + QDEL_NULL(S) return cost * (spell_levels + 1) return -1 diff --git a/code/game/jobs/job/supervisor.dm b/code/game/jobs/job/supervisor.dm index 55ae7f4b3ae..87ab2774384 100644 --- a/code/game/jobs/job/supervisor.dm +++ b/code/game/jobs/job/supervisor.dm @@ -33,7 +33,7 @@ GLOBAL_DATUM_INIT(captain_announcement, /datum/announcement/minor, new(do_newsca shoes = /obj/item/clothing/shoes/brown head = /obj/item/clothing/head/caphat l_ear = /obj/item/radio/headset/heads/captain/alt - glasses = /obj/item/clothing/glasses/sunglasses + glasses = /obj/item/clothing/glasses/hud/skills/sunglasses id = /obj/item/card/id/gold pda = /obj/item/pda/captain backpack_contents = list( @@ -89,6 +89,7 @@ GLOBAL_DATUM_INIT(captain_announcement, /datum/announcement/minor, new(do_newsca uniform = /obj/item/clothing/under/rank/head_of_personnel shoes = /obj/item/clothing/shoes/brown head = /obj/item/clothing/head/hopcap + glasses = /obj/item/clothing/glasses/hud/skills/sunglasses l_ear = /obj/item/radio/headset/heads/hop id = /obj/item/card/id/silver pda = /obj/item/pda/heads/hop @@ -134,6 +135,7 @@ GLOBAL_DATUM_INIT(captain_announcement, /datum/announcement/minor, new(do_newsca uniform = /obj/item/clothing/under/rank/ntrep suit = /obj/item/clothing/suit/storage/ntrep shoes = /obj/item/clothing/shoes/centcom + glasses = /obj/item/clothing/glasses/hud/skills/sunglasses l_ear = /obj/item/radio/headset/heads/ntrep id = /obj/item/card/id/nanotrasen l_pocket = /obj/item/lighter/zippo/nt_rep diff --git a/code/game/machinery/atmoalter/pump.dm b/code/game/machinery/atmoalter/pump.dm index 8d974f97a70..8198976bc14 100644 --- a/code/game/machinery/atmoalter/pump.dm +++ b/code/game/machinery/atmoalter/pump.dm @@ -176,3 +176,7 @@ return TRUE add_fingerprint(usr) + +#undef MAX_TARGET_PRESSURE +#undef DIRECTION_IN +#undef DIRECTION_OUT diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm index d7a49e40d4b..6bfb5e07274 100644 --- a/code/game/machinery/atmoalter/scrubber.dm +++ b/code/game/machinery/atmoalter/scrubber.dm @@ -1,18 +1,18 @@ + +#define MAX_RATE 10 * ONE_ATMOSPHERE + /obj/machinery/portable_atmospherics/scrubber name = "Portable Air Scrubber" - icon = 'icons/obj/atmos.dmi' icon_state = "pscrubber:0" - density = 1 - - var/on = 0 - var/volume_rate = 800 - var/widenet = 0 //is this scrubber acting on the 3x3 area around it. - + density = TRUE volume = 750 - - var/minrate = 0//probably useless, but whatever - var/maxrate = 10 * ONE_ATMOSPHERE + /// Whether the scrubber is switched on or off. + var/on = FALSE + /// The volume of gas that can be scrubbed every time `process_atmos()` is called (0.5 seconds). + var/volume_rate = 101.325 + /// Is this scrubber acting on the 3x3 area around it. + var/widenet = FALSE /obj/machinery/portable_atmospherics/scrubber/emp_act(severity) if(stat & (BROKEN|NOPOWER)) @@ -26,7 +26,7 @@ ..(severity) /obj/machinery/portable_atmospherics/scrubber/update_icon() - src.overlays = 0 + overlays = 0 if(on) icon_state = "pscrubber:1" @@ -53,7 +53,7 @@ for(var/turf/simulated/tile in T.GetAtmosAdjacentTurfs(alldir=1)) scrub(tile) -/obj/machinery/portable_atmospherics/scrubber/proc/scrub(var/turf/simulated/tile) +/obj/machinery/portable_atmospherics/scrubber/proc/scrub(turf/simulated/tile) var/datum/gas_mixture/environment if(holding) environment = holding.air_contents @@ -99,62 +99,62 @@ /obj/machinery/portable_atmospherics/scrubber/return_air() return air_contents -/obj/machinery/portable_atmospherics/scrubber/attack_ai(var/mob/user as mob) - src.add_hiddenprint(user) - return src.attack_hand(user) +/obj/machinery/portable_atmospherics/scrubber/attack_ai(mob/user) + add_hiddenprint(user) + return attack_hand(user) -/obj/machinery/portable_atmospherics/scrubber/attack_ghost(var/mob/user as mob) - return src.attack_hand(user) +/obj/machinery/portable_atmospherics/scrubber/attack_ghost(mob/user) + return attack_hand(user) -/obj/machinery/portable_atmospherics/scrubber/attack_hand(var/mob/user as mob) - ui_interact(user) +/obj/machinery/portable_atmospherics/scrubber/attack_hand(mob/user) + tgui_interact(user) return -/obj/machinery/portable_atmospherics/scrubber/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = GLOB.physical_state) - // 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/portable_atmospherics/scrubber/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) - // 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, "portscrubber.tmpl", "Portable Scrubber", 480, 400, state = state) - // open the new ui window + ui = new(user, src, ui_key, "PortableScrubber", "Portable Scrubber", 433, 346, master_ui, state) ui.open() - // auto update every Master Controller tick - ui.set_auto_update(1) + ui.set_autoupdate(TRUE) -/obj/machinery/portable_atmospherics/scrubber/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.physical_state) - var/data[0] - data["portConnected"] = connected_port ? 1 : 0 - data["tankPressure"] = round(air_contents.return_pressure() > 0 ? air_contents.return_pressure() : 0) - data["rate"] = round(volume_rate) - data["minrate"] = round(minrate) - data["maxrate"] = round(maxrate) - data["on"] = on ? 1 : 0 - - data["hasHoldingTank"] = holding ? 1 : 0 +/obj/machinery/portable_atmospherics/scrubber/tgui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.physical_state) + var/list/data = list( + "on" = on, + "port_connected" = connected_port ? TRUE : FALSE, + "max_rate" = MAX_RATE, + "rate" = round(volume_rate, 0.001), + "tank_pressure" = air_contents.return_pressure() > 0 ? round(air_contents.return_pressure(), 0.001) : 0 + ) if(holding) - data["holdingTank"] = list("name" = holding.name, "tankPressure" = round(holding.air_contents.return_pressure() > 0 ? holding.air_contents.return_pressure() : 0)) + data["has_holding_tank"] = TRUE + data["holding_tank"] = list("name" = holding.name, "tank_pressure" = holding.air_contents.return_pressure() > 0 ? round(holding.air_contents.return_pressure(), 0.001) : 0) + else + data["has_holding_tank"] = FALSE return data -/obj/machinery/portable_atmospherics/scrubber/Topic(href, href_list) +/obj/machinery/portable_atmospherics/scrubber/tgui_act(action, list/params) if(..()) - return 1 + return - if(href_list["power"]) - on = !on - update_icon() + switch(action) + if("power") + on = !on + update_icon() + return TRUE - if(href_list["remove_tank"]) - if(holding) - holding.loc = loc - holding = null + if("remove_tank") + if(holding) + holding.forceMove(get_turf(src)) + holding = null + update_icon() + return TRUE - if(href_list["volume_adj"]) - var/diff = text2num(href_list["volume_adj"]) - volume_rate = clamp(volume_rate+diff, minrate, maxrate) + if("set_rate") + volume_rate = clamp(text2num(params["rate"]), 0, MAX_RATE) + return TRUE - src.add_fingerprint(usr) + add_fingerprint(usr) /obj/machinery/portable_atmospherics/scrubber/huge name = "Huge Air Scrubber" @@ -175,18 +175,18 @@ name = "[name] (ID [id])" -/obj/machinery/portable_atmospherics/scrubber/huge/attack_hand(var/mob/user as mob) +/obj/machinery/portable_atmospherics/scrubber/huge/attack_hand(mob/user) to_chat(usr, "You can't directly interact with this machine. Use the area atmos computer.") /obj/machinery/portable_atmospherics/scrubber/huge/update_icon() - src.overlays = 0 + overlays = 0 if(on) icon_state = "scrubber:1" else icon_state = "scrubber:0" -/obj/machinery/portable_atmospherics/scrubber/huge/attackby(var/obj/item/W as obj, var/mob/user as mob, params) +/obj/machinery/portable_atmospherics/scrubber/huge/attackby(obj/item/W, mob/user, params) if((istype(W, /obj/item/analyzer)) && get_dist(user, src) <= 1) atmosanalyzer_scan(air_contents, user) return @@ -208,3 +208,5 @@ /obj/machinery/portable_atmospherics/scrubber/huge/stationary name = "Stationary Air Scrubber" stationary = 1 + +#undef MAX_RATE diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 4e185feb4a8..08c535f1388 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -20,7 +20,6 @@ anchored = TRUE var/start_active = FALSE //If it ignores the random chance to start broken on round start var/invuln = null - var/obj/item/camera_bug/bug = null var/obj/item/camera_assembly/assembly = null //OTHER @@ -58,11 +57,6 @@ SStgui.close_uis(wires) toggle_cam(null, FALSE) //kick anyone viewing out QDEL_NULL(assembly) - if(istype(bug)) - bug.bugged_cameras -= c_tag - if(bug.current == src) - bug.current = null - bug = null QDEL_NULL(wires) GLOB.cameranet.removeCamera(src) //Will handle removal from the camera network and the chunks, so we don't need to worry about that GLOB.cameranet.cameras -= src @@ -201,19 +195,6 @@ to_chat(O, "[U] holds \a [itemname] up to one of the cameras ...") O << browse(text("[][]", itemname, info), text("window=[]", itemname)) - else if(istype(I, /obj/item/camera_bug)) - if(!can_use()) - to_chat(user, "Camera non-functional.") - return - if(istype(bug)) - to_chat(user, "Camera bug removed.") - bug.bugged_cameras -= c_tag - bug = null - else - to_chat(user, "Camera bugged.") - bug = I - bug.bugged_cameras[c_tag] = src - else if(istype(I, /obj/item/laser_pointer)) var/obj/item/laser_pointer/L = I L.laser_act(src, user) diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm index 7d33361e4b9..8a32c6d6374 100644 --- a/code/game/machinery/camera/motion.dm +++ b/code/game/machinery/camera/motion.dm @@ -58,7 +58,7 @@ detectTime = -1 return TRUE -/obj/machinery/camera/HasProximity(atom/movable/AM as mob|obj) +/obj/machinery/camera/HasProximity(atom/movable/AM) // Motion cameras outside of an "ai monitored" area will use this to detect stuff. if(!area_motion) if(isliving(AM)) diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index e91e631cc62..a02c46524c5 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -159,9 +159,6 @@ name = "Circuit board (Security Records)" build_path = /obj/machinery/computer/secure_data origin_tech = "programming=2;combat=2" -/obj/item/circuitboard/skills - name = "Circuit board (Employment Records)" - build_path = /obj/machinery/computer/skills /obj/item/circuitboard/stationalert_engineering name = "Circuit Board (Station Alert Console (Engineering))" build_path = /obj/machinery/computer/station_alert @@ -283,7 +280,7 @@ origin_tech = "programming=3;powerstorage=3" /obj/item/circuitboard/ordercomp name = "Circuit board (Supply Ordering Console)" - build_path = /obj/machinery/computer/ordercomp + build_path = /obj/machinery/computer/supplycomp/public origin_tech = "programming=3" /obj/item/circuitboard/supplycomp name = "Circuit board (Supply Shuttle Console)" diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index cfe82db29e8..cb7e1b2d20b 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -10,75 +10,167 @@ var/mapping = 0 // For the overview file (overview.dm), not used on this page var/list/network = list() - var/list/available_networks = list() - var/list/watchers = list() //who's using the console, associated with the camera they're on. + var/obj/machinery/camera/active_camera + var/list/watchers = list() -/obj/machinery/computer/security/New() // Lists existing networks and their required access. Format: available_networks[] = list() - generate_network_access() - ..() + // Stuff needed to render the map + var/map_name + var/const/default_map_size = 15 + var/obj/screen/map_view/cam_screen + /// All the plane masters that need to be applied. + var/list/cam_plane_masters + var/obj/screen/background/cam_background -/obj/machinery/computer/security/proc/generate_network_access() - available_networks["SS13"] = list(ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Telecomms"] = list(ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Research Outpost"] = list(ACCESS_RD,ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Mining Outpost"] = list(ACCESS_QM,ACCESS_HOP,ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Research"] = list(ACCESS_RD,ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Prison"] = list(ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Labor Camp"] = list(ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Interrogation"] = list(ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Atmosphere Alarms"] = list(ACCESS_CE,ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Fire Alarms"] = list(ACCESS_CE,ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Power Alarms"] = list(ACCESS_CE,ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Supermatter"] = list(ACCESS_CE,ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["MiniSat"] = list(ACCESS_RD,ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Singularity"] = list(ACCESS_CE,ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Anomaly Isolation"] = list(ACCESS_RD,ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Toxins"] = list(ACCESS_RD,ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["Telepad"] = list(ACCESS_RD,ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["TestChamber"] = list(ACCESS_RD,ACCESS_HOS,ACCESS_CAPTAIN) - available_networks["ERT"] = list(ACCESS_CENT_SPECOPS_COMMANDER,ACCESS_CENT_COMMANDER) - available_networks["CentComm"] = list(ACCESS_CENT_SECURITY,ACCESS_CENT_COMMANDER) - available_networks["Thunderdome"] = list(ACCESS_CENT_THUNDER,ACCESS_CENT_COMMANDER) + // Parent object this camera is assigned to. Used for camera bugs + var/atom/movable/parent + +/obj/machinery/computer/security/tgui_host() + return parent ? parent : src + +/obj/machinery/computer/security/Initialize() + . = ..() + // Initialize map objects + map_name = "camera_console_[UID()]_map" + cam_screen = new + cam_screen.name = "screen" + cam_screen.assigned_map = map_name + cam_screen.del_on_map_removal = FALSE + cam_screen.screen_loc = "[map_name]:1,1" + cam_plane_masters = list() + for(var/plane in subtypesof(/obj/screen/plane_master)) + var/obj/screen/instance = new plane() + instance.assigned_map = map_name + instance.del_on_map_removal = FALSE + instance.screen_loc = "[map_name]:CENTER" + cam_plane_masters += instance + cam_background = new + cam_background.assigned_map = map_name + cam_background.del_on_map_removal = FALSE /obj/machinery/computer/security/Destroy() - if(watchers.len) - for(var/mob/M in watchers) - M.unset_machine() //to properly reset the view of the users if the console is deleted. + qdel(cam_screen) + QDEL_LIST(cam_plane_masters) + qdel(cam_background) return ..() -/obj/machinery/computer/security/proc/isCameraFarAway(obj/machinery/camera/C) - var/turf/consoleturf = get_turf(src) - var/turf/cameraturf = get_turf(C) - if((is_away_level(cameraturf.z) || is_away_level(consoleturf.z)) && !atoms_share_level(cameraturf, consoleturf)) //can only recieve away mission cameras on away missions +/obj/machinery/computer/security/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) + // Update UI + ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open) + // Show static if can't use the camera + if(!active_camera?.can_use()) + show_camera_static() + if(!ui) + var/user_uid = user.UID() + var/is_living = isliving(user) + // Ghosts shouldn't count towards concurrent users, which produces + // an audible terminal_on click. + if(is_living) + watchers += user_uid + // Turn on the console + if(length(watchers) == 1 && is_living) + playsound(src, 'sound/machines/terminal_on.ogg', 25, FALSE) + use_power(active_power_usage) + // Register map objects + user.client.register_map_obj(cam_screen) + for(var/plane in cam_plane_masters) + user.client.register_map_obj(plane) + user.client.register_map_obj(cam_background) + // Open UI + ui = new(user, src, ui_key, "CameraConsole", name, 870, 708, master_ui, state) + ui.open() + +/obj/machinery/computer/security/tgui_data() + var/list/data = list() + data["network"] = network + data["activeCamera"] = null + if(active_camera) + data["activeCamera"] = list( + name = active_camera.c_tag, + status = active_camera.status, + ) + return data + +/obj/machinery/computer/security/tgui_static_data() + var/list/data = list() + data["mapRef"] = map_name + var/list/cameras = get_available_cameras() + data["cameras"] = list() + for(var/i in cameras) + var/obj/machinery/camera/C = cameras[i] + data["cameras"] += list(list( + name = C.c_tag, + )) + return data + + +/obj/machinery/computer/security/tgui_act(action, params) + if(..()) + return + + if(action == "switch_camera") + var/c_tag = params["name"] + var/list/cameras = get_available_cameras() + var/obj/machinery/camera/C = cameras[c_tag] + active_camera = C + playsound(src, get_sfx("terminal_type"), 25, FALSE) + + // Show static if can't use the camera + if(!active_camera?.can_use()) + show_camera_static() + return TRUE + + var/list/visible_turfs = list() + for(var/turf/T in (C.isXRay() \ + ? range(C.view_range, C) \ + : view(C.view_range, C))) + visible_turfs += T + + var/list/bbox = get_bbox_of_atoms(visible_turfs) + var/size_x = bbox[3] - bbox[1] + 1 + var/size_y = bbox[4] - bbox[2] + 1 + + cam_screen.vis_contents = visible_turfs + cam_background.icon_state = "clear" + cam_background.fill_rect(1, 1, size_x, size_y) + return TRUE -/obj/machinery/computer/security/check_eye(mob/user) - if((stat & (NOPOWER|BROKEN)) || user.incapacitated() || !user.has_vision()) - user.unset_machine() - return - if(!(user in watchers)) - user.unset_machine() - return - if(!watchers[user]) - user.unset_machine() - return - var/obj/machinery/camera/C = watchers[user] - if(isCameraFarAway(C)) - user.unset_machine() - return - if(!can_access_camera(C, user)) - user.unset_machine() - -/obj/machinery/computer/security/on_unset_machine(mob/user) - watchers.Remove(user) - user.reset_perspective(null) +// Returns the list of cameras accessible from this computer +/obj/machinery/computer/security/proc/get_available_cameras() + var/list/L = list() + for (var/obj/machinery/camera/C in GLOB.cameranet.cameras) + if((is_away_level(z) || is_away_level(C.z)) && (C.z != z))//if on away mission, can only receive feed from same z_level cameras + continue + L.Add(C) + var/list/D = list() + for(var/obj/machinery/camera/C in L) + if(!C.network) + stack_trace("Camera in a cameranet has no camera network") + continue + if(!(islist(C.network))) + stack_trace("Camera in a cameranet has a non-list camera network") + continue + var/list/tempnetwork = C.network & network + if(tempnetwork.len) + D["[C.c_tag]"] = C + return D /obj/machinery/computer/security/attack_hand(mob/user) if(stat || ..()) user.unset_machine() return - ui_interact(user) + tgui_interact(user) + +/obj/machinery/computer/security/attack_ai(mob/user) + to_chat(user, "You realise its kind of stupid to access a camera console when you have the entire camera network at your metaphorical fingertips") + return + + +/obj/machinery/computer/security/proc/show_camera_static() + cam_screen.vis_contents.Cut() + cam_background.icon_state = "scanline2" + cam_background.fill_rect(1, 1, default_map_size, default_map_size) /obj/machinery/computer/security/telescreen/multitool_act(mob/user, obj/item/I) . = TRUE @@ -99,216 +191,6 @@ if("West") pixel_x = -32 -/obj/machinery/computer/security/emag_act(user as mob) - if(!emagged) - emagged = 1 - to_chat(user, "You have authorized full network access!") - attack_hand(user) - else - attack_hand(user) - -/obj/machinery/computer/security/proc/get_user_access(mob/user) - var/list/access = list() - - if(emagged) - access = get_all_accesses() // Assume captain level access when emagged - else if(ishuman(user)) - access = user.get_access() - else if((isAI(user) || isrobot(user)) && CanUseTopic(user, GLOB.default_state) == STATUS_INTERACTIVE) - access = get_all_accesses() // Assume captain level access when AI - else if(user.can_admin_interact()) - access = get_all_accesses() - return access - -/obj/machinery/computer/security/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, "sec_camera.tmpl", "Camera Console", 900, 800) - - // adding a template with the key "mapContent" enables the map ui functionality - ui.add_template("mapContent", "sec_camera_map_content.tmpl") - // adding a template with the key "mapHeader" replaces the map header content - ui.add_template("mapHeader", "sec_camera_map_header.tmpl") - - // Send nanomaps - var/datum/asset/nanomaps = get_asset_datum(/datum/asset/simple/nanomaps) - nanomaps.send(user) - - ui.open() - -/obj/machinery/computer/security/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - - var/list/cameras = list() - for(var/obj/machinery/camera/C in GLOB.cameranet.cameras) - if(isCameraFarAway(C)) - continue - if(!can_access_camera(C, user)) - continue - - cameras[++cameras.len] = C.nano_structure() - - for(var/i = cameras.len, i > 0, i--) //based off /proc/camera_sort, sorts cameras alphabetically for the UI - for(var/j = 1 to i - 1) - var/a = cameras[j] - var/b = cameras[j + 1] - if(sorttext(a["name"], b["name"]) < 0) - cameras.Swap(j, j + 1) - - data["cameras"] = cameras - - var/list/access = get_user_access(user) - if(emagged) - data["emagged"] = 1 - - var/list/networks_list = list() - // Loop through the ID's permission, and check which networks the ID has access to. - for(var/net in available_networks) // Loop through networks. - for(var/req in available_networks[net]) // Loop through access levels of the networks. - if(req in access) - if(net in network) // Checks if the network is currently active. - networks_list.Add(list(list("name" = net, "active" = 1))) - else - networks_list.Add(list(list("name" = net, "active" = 0))) - break - - if(networks_list.len) - data["networks"] = networks_list - - data["current"] = null - if(watchers[user]) - var/obj/machinery/camera/watched = watchers[user] - data["current"] = watched.nano_structure() - - return data - -/obj/machinery/computer/security/Topic(href, href_list) - if(..()) - usr.unset_machine() - return 1 - - if(href_list["switchTo"]) - var/obj/machinery/camera/C = locate(href_list["switchTo"]) in GLOB.cameranet.cameras - if(!C) - return 1 - - switch_to_camera(usr, C) - - else if(href_list["reset"]) - usr.unset_machine() - - else if(href_list["activate"]) // Activate: enable or disable networks - var/net = href_list["activate"] // Network to be enabled or disabled. - var/active = href_list["active"] // Is the network currently active. - var/list/access = get_user_access(usr) - for(var/a in available_networks[net]) - if(a in access) // Re-check for authorization. - if(text2num(active) == 1) - network -= net - break - else - network += net - break - - SSnanoui.update_uis(src) - -// Check if camera is accessible when jumping -/obj/machinery/computer/security/proc/can_access_camera(var/obj/machinery/camera/C, var/mob/M) - if(CanUseTopic(M, GLOB.default_state) != STATUS_INTERACTIVE || M.incapacitated() || !M.has_vision()) - return 0 - - if(isrobot(M)) - var/list/viewing = viewers(src) - if(!viewing.Find(M)) - return 0 - - if(isAI(M)) - var/mob/living/silicon/ai/A = M - if(!A.is_in_chassis()) - return 0 - - if(!issilicon(M) && !Adjacent(M)) - return 0 - - var/list/shared_networks = network & C.network - if(!shared_networks.len || !C.can_use()) - return 0 - - return 1 - -// Switching to cameras -/obj/machinery/computer/security/proc/switch_to_camera(var/mob/user, var/obj/machinery/camera/C) - if(!can_access_camera(C, user)) - user.unset_machine() - return 1 - - if(isAI(user)) - var/mob/living/silicon/ai/A = user - A.eyeobj.setLoc(get_turf(C)) - A.client.eye = A.eyeobj - else - user.reset_perspective(C) - watchers[user] = C - use_power(50) - -//Camera control: moving. -/obj/machinery/computer/security/proc/jump_on_click(var/mob/user, var/A) - if(user.machine != src) - return - - var/obj/machinery/camera/jump_to - - if(istype(A, /obj/machinery/camera)) - jump_to = A - - else if(ismob(A)) - if(ishuman(A)) - var/mob/living/carbon/human/H = A - jump_to = locate() in H.head - else if(isrobot(A)) - var/mob/living/silicon/robot/R = A - jump_to = R.camera - - else if(isobj(A)) - var/obj/O = A - jump_to = locate() in O - - else if(isturf(A)) - var/best_dist = INFINITY - for(var/obj/machinery/camera/camera in get_area(A)) - if(!camera.can_use()) - continue - if(!can_access_camera(camera, user)) - continue - var/dist = get_dist(camera,A) - if(dist < best_dist) - best_dist = dist - jump_to = camera - - if(isnull(jump_to)) - return - - if(can_access_camera(jump_to, user)) - switch_to_camera(user, jump_to) - -// Camera control: mouse. -/atom/DblClick() - ..() - if(istype(usr.machine, /obj/machinery/computer/security)) - var/obj/machinery/computer/security/console = usr.machine - console.jump_on_click(usr, src) - -// Camera control: arrow keys. -/mob/Move(n, direct) - if(istype(machine, /obj/machinery/computer/security)) - var/obj/machinery/computer/security/console = machine - var/turf/T = get_turf(console.watchers[src]) - for(var/i; i < 10; i++) - T = get_step(T, direct) - console.jump_on_click(src, T) - return - return ..() - // Other computer monitors. /obj/machinery/computer/security/telescreen name = "telescreen" diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm index c733a7c92c1..48e946a999b 100644 --- a/code/game/machinery/computer/medical.dm +++ b/code/game/machinery/computer/medical.dm @@ -14,9 +14,6 @@ icon_screen = "medcomp" req_one_access = list(ACCESS_MEDICAL, ACCESS_FORENSICS_LOCKERS) circuit = /obj/item/circuitboard/med_data - var/obj/item/card/id/scan = null - var/authenticated = null - var/rank = null var/screen = null var/datum/data/record/active1 = null var/datum/data/record/active2 = null @@ -65,11 +62,7 @@ return ..() /obj/machinery/computer/med_data/attackby(obj/item/O, mob/user, params) - if(istype(O, /obj/item/card/id) && !scan) - usr.drop_item() - O.forceMove(src) - scan = O - tgui_interact(user) + if(tgui_login_attackby(O, user)) return return ..() @@ -92,14 +85,11 @@ /obj/machinery/computer/med_data/tgui_data(mob/user) var/data[0] data["temp"] = temp - data["scan"] = scan ? scan.name : null - data["authenticated"] = authenticated - data["rank"] = rank data["screen"] = screen data["printing"] = printing - data["isAI"] = isAI(user) - data["isRobot"] = isrobot(user) - if(authenticated) + // This proc appends login state to data. + tgui_login_data(data, user) + if(data["loginState"]["logged_in"]) switch(screen) if(MED_DATA_R_LIST) if(!isnull(GLOB.data_core.general)) @@ -199,58 +189,21 @@ . = TRUE if(tgui_act_modal(action, params)) return + if(tgui_login_act(action, params)) + return switch(action) if("cleartemp") temp = null - if("scan") - if(scan) - scan.forceMove(loc) - if(ishuman(usr) && !usr.get_active_hand()) - usr.put_in_hands(scan) - scan = null - else - var/obj/item/I = usr.get_active_hand() - if(istype(I, /obj/item/card/id)) - usr.drop_item() - I.forceMove(src) - scan = I - if("login") - var/login_type = text2num(params["login_type"]) - if(login_type == LOGIN_TYPE_NORMAL && istype(scan)) - if(check_access(scan)) - authenticated = scan.registered_name - rank = scan.assignment - else if(login_type == LOGIN_TYPE_AI && isAI(usr)) - authenticated = usr.name - rank = "AI" - else if(login_type == LOGIN_TYPE_ROBOT && isrobot(usr)) - authenticated = usr.name - var/mob/living/silicon/robot/R = usr - rank = "[R.modtype] [R.braintype]" - if(authenticated) - active1 = null - active2 = null - screen = MED_DATA_R_LIST else . = FALSE if(.) return - if(authenticated) + if(tgui_login_get().logged_in) . = TRUE switch(action) - if("logout") - if(scan) - scan.forceMove(loc) - if(ishuman(usr) && !usr.get_active_hand()) - usr.put_in_hands(scan) - scan = null - authenticated = null - screen = null - active1 = null - active2 = null if("screen") screen = clamp(text2num(params["screen"]) || 0, MED_DATA_R_LIST, MED_DATA_MEDBOT) active1 = null @@ -403,10 +356,11 @@ else if(istype(active1) && (field in active1.fields)) active1.fields[field] = answer if("add_c") - if(!length(answer) || !istype(active2) || !length(authenticated)) + var/datum/tgui_login/state = tgui_login_get() + if(!length(answer) || !istype(active2) || !length(state.name)) return active2.fields["comments"] += list(list( - header = "Made by [authenticated] ([rank]) on [GLOB.current_date_string] [station_time_timestamp()]", + header = "Made by [state.name] ([state.name]) on [GLOB.current_date_string] [station_time_timestamp()]", text = answer )) else @@ -493,6 +447,10 @@ ..(severity) +/obj/machinery/computer/med_data/tgui_login_on_login(datum/tgui_login/state) + active1 = null + active2 = null + screen = MED_DATA_R_LIST /obj/machinery/computer/med_data/laptop name = "medical laptop" diff --git a/code/game/machinery/computer/skills.dm b/code/game/machinery/computer/skills.dm deleted file mode 100644 index b7361db01a3..00000000000 --- a/code/game/machinery/computer/skills.dm +++ /dev/null @@ -1,328 +0,0 @@ -#define SKILL_DATA_R_LIST 1 // Record list -#define SKILL_DATA_MAINT 2 // Records maintenance -#define SKILL_DATA_RECORD 3 // Record - -/obj/machinery/computer/skills//TODO:SANITY - name = "employment records console" - desc = "Used to view personnel's employment records" - icon_state = "laptop" - icon_keyboard = "laptop_key" - icon_screen = "medlaptop" - density = 0 - light_color = LIGHT_COLOR_GREEN - req_one_access = list(ACCESS_HEADS) - circuit = /obj/item/circuitboard/skills - var/obj/item/card/id/scan = null - var/authenticated = null - var/rank = null - var/screen = null - var/datum/data/record/active1 = null - var/temp = null - var/printing = null - //Sorting Variables - var/sortBy = "name" - var/order = 1 // -1 = Descending - 1 = Ascending - -/obj/machinery/computer/skills/Destroy() - active1 = null - return ..() - -/obj/machinery/computer/skills/attackby(obj/item/O, mob/user, params) - if(istype(O, /obj/item/card/id) && !scan) - user.drop_item() - O.forceMove(src) - scan = O - ui_interact(user) - return - return ..() - -//Someone needs to break down the dat += into chunks instead of long ass lines. -/obj/machinery/computer/skills/attack_hand(mob/user) - if(..()) - return - if(is_away_level(z)) - to_chat(user, "Unable to establish a connection: You're too far away from the station!") - return - add_fingerprint(user) - ui_interact(user) - -/obj/machinery/computer/skills/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, "skills_data.tmpl", name, 800, 380) - ui.open() - -/obj/machinery/computer/skills/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - data["temp"] = temp - data["scan"] = scan ? scan.name : null - data["authenticated"] = authenticated - data["screen"] = screen - if(authenticated) - switch(screen) - if(SKILL_DATA_R_LIST) - if(!isnull(GLOB.data_core.general)) - for(var/datum/data/record/R in sortRecord(GLOB.data_core.general, sortBy, order)) - data["records"] += list(list("ref" = "\ref[R]", "id" = R.fields["id"], "name" = R.fields["name"], "rank" = R.fields["rank"], "fingerprint" = R.fields["fingerprint"])) - if(SKILL_DATA_RECORD) - var/list/general = list() - data["general"] = general - if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1)) - var/list/fields = list() - general["fields"] = fields - fields[++fields.len] = list("field" = "Name:", "value" = active1.fields["name"], "name" = "name") - fields[++fields.len] = list("field" = "ID:", "value" = active1.fields["id"], "name" = "id") - fields[++fields.len] = list("field" = "Sex:", "value" = active1.fields["sex"], "name" = "sex") - fields[++fields.len] = list("field" = "Age:", "value" = active1.fields["age"], "name" = "age") - fields[++fields.len] = list("field" = "Rank:", "value" = active1.fields["rank"], "name" = "rank") - fields[++fields.len] = list("field" = "Fingerprint:", "value" = active1.fields["fingerprint"], "name" = "fingerprint") - fields[++fields.len] = list("field" = "Physical Status:", "value" = active1.fields["p_stat"]) - fields[++fields.len] = list("field" = "Mental Status:", "value" = active1.fields["m_stat"]) - general["notes"] = active1.fields["notes"] - var/list/photos = list() - general["photos"] = photos - photos[++photos.len] = list("photo" = active1.fields["photo-south"]) - photos[++photos.len] = list("photo" = active1.fields["photo-west"]) - general["has_photos"] += (active1.fields["photo-south"] || active1.fields["photo-west"] ? 1 : 0) - general["empty"] = 0 - else - general["empty"] = 1 - return data - -/obj/machinery/computer/skills/Topic(href, href_list) - if(..()) - return 1 - - if(!GLOB.data_core.general.Find(active1)) - active1 = null - - if(href_list["temp"]) - temp = null - - if(href_list["temp_action"]) - var/temp_list = splittext(href_list["temp_action"], "=") - switch(temp_list[1]) - if("del_all2") - if(GLOB.PDA_Manifest && GLOB.PDA_Manifest.len) - GLOB.PDA_Manifest.Cut() - for(var/datum/data/record/R in GLOB.data_core.security) - qdel(R) - setTemp("

    All employment records deleted.

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

    Record not found!

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

    Are you sure you wish to delete all employment records?

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

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

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

    " - if(istype(active1, /datum/data/record) && GLOB.data_core.general.Find(active1)) - P.info += {"Name: [active1.fields["name"]] ID: [active1.fields["id"]] -
    \nSex: [active1.fields["sex"]] -
    \nAge: [active1.fields["age"]] -
    \nFingerprint: [active1.fields["fingerprint"]] -
    \nPhysical Status: [active1.fields["p_stat"]] -
    \nMental Status: [active1.fields["m_stat"]] -
    \nEmployment/Skills Summary:[active1.fields["notes"]]
    "} - else - P.info += "General Record Lost!
    " - P.info += "" - P.name = "paper - 'Employment Record: [active1.fields["name"]]'" - printing = 0 - - if(href_list["field"]) - if(incapable) - return 1 - var/a1 = active1 - switch(href_list["field"]) - if("name") - if(istype(active1, /datum/data/record)) - var/t1 = reject_bad_name(clean_input("Please input name:", "Secure. records", active1.fields["name"], null)) - if(!t1 || !length(trim(t1)) || incapable || active1 != a1) - return 1 - active1.fields["name"] = t1 - if("id") - if(istype(active1, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please input id:", "Secure. records", active1.fields["id"], null) as text)), 1, MAX_MESSAGE_LEN) - if(!t1 || incapable || active1 != a1) - return 1 - active1.fields["id"] = t1 - if("fingerprint") - if(istype(active1, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please input fingerprint hash:", "Secure. records", active1.fields["fingerprint"], null) as text)), 1, MAX_MESSAGE_LEN) - if(!t1 || incapable || active1 != a1) - return 1 - active1.fields["fingerprint"] = t1 - if("sex") - if(istype(active1, /datum/data/record)) - if(active1.fields["sex"] == "Male") - active1.fields["sex"] = "Female" - else - active1.fields["sex"] = "Male" - if("age") - if(istype(active1, /datum/data/record)) - var/t1 = input("Please input age:", "Secure. records", active1.fields["age"], null) as num - if(!t1 || incapable || active1 != a1) - return 1 - active1.fields["age"] = t1 - if("rank") - var/list/L = list("Head of Personnel", "Captain", "AI") - //This was so silly before the change. Now it actually works without beating your head against the keyboard. /N - if(istype(active1, /datum/data/record) && L.Find(rank)) - var/list/buttons = list() - for(var/rank in GLOB.joblist) - buttons[++buttons.len] = list("name" = rank, "icon" = null, "val" = "rank=[rank]", "status" = (active1.fields["rank"] == rank ? "selected" : null)) - setTemp("

    Rank

    ", buttons) - else - setTemp("You do not have the required rank to do this!") - if("species") - if(istype(active1, /datum/data/record)) - var/t1 = copytext(trim(sanitize(input("Please enter race:", "General records", active1.fields["species"], null) as message)), 1, MAX_MESSAGE_LEN) - if(!t1 || incapable || active1 != a1) - return 1 - active1.fields["species"] = t1 - return 1 - -/obj/machinery/computer/skills/proc/setTemp(text, list/buttons = list()) - temp = list("text" = text, "buttons" = buttons, "has_buttons" = buttons.len > 0) - -/obj/machinery/computer/skills/emp_act(severity) - if(stat & (BROKEN|NOPOWER)) - ..(severity) - return - - for(var/datum/data/record/R in GLOB.data_core.security) - if(prob(10/severity)) - switch(rand(1,6)) - if(1) - R.fields["name"] = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]" - if(2) - R.fields["sex"] = pick("Male", "Female") - if(3) - R.fields["age"] = rand(5, 85) - if(4) - R.fields["criminal"] = pick(SEC_RECORD_STATUS_NONE, SEC_RECORD_STATUS_ARREST, SEC_RECORD_STATUS_INCARCERATED, SEC_RECORD_STATUS_PAROLLED, SEC_RECORD_STATUS_RELEASED) - if(5) - R.fields["p_stat"] = pick("*Unconcious*", "Active", "Physically Unfit") - if(6) - R.fields["m_stat"] = pick("*Insane*", "*Unstable*", "*Watch*", "Stable") - continue - - else if(prob(1)) - qdel(R) - continue - - ..(severity) - -#undef SKILL_DATA_R_LIST -#undef SKILL_DATA_MAINT -#undef SKILL_DATA_RECORD diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index ee29504fe99..8ee774d1ae0 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -253,7 +253,6 @@ to destroy them and players will be able to make replacements. /obj/machinery/vending/engineering = "Robco Tool Maker", /obj/machinery/vending/sovietsoda = "BODA", /obj/machinery/vending/security = "SecTech", - /obj/machinery/vending/modularpc = "Deluxe Silicate Selections", /obj/machinery/vending/crittercare = "CritterCare") /obj/item/circuitboard/vendor/screwdriver_act(mob/user, obj/item/I) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 27c37f19c1a..1d6b572d9e5 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -254,7 +254,7 @@ About the new airlock wires panel: backup_power_lost_until = main_power_lost_until == 0 ? -1 : 0 update_icon() -/obj/machinery/door/airlock/proc/electrify(duration, feedback = 0) +/obj/machinery/door/airlock/proc/electrify(duration, mob/user = usr, feedback = FALSE) if(electrified_timer) deltimer(electrified_timer) electrified_timer = null @@ -270,10 +270,10 @@ About the new airlock wires panel: message = "The door is now un-electrified." electrified_until = 0 else if(duration) //electrify door for the given duration seconds - if(usr) - shockedby += text("\[[time_stamp()]\] - [usr](ckey:[usr.ckey])") - usr.create_attack_log("Electrified the [name] at [x] [y] [z]") - add_attack_logs(usr, src, "Electrified", ATKLOG_ALL) + if(user) + shockedby += text("\[[time_stamp()]\] - [user](ckey:[user.ckey])") + user.create_attack_log("Electrified the [name] at [x] [y] [z]") + add_attack_logs(user, src, "Electrified", ATKLOG_ALL) else shockedby += text("\[[time_stamp()]\] - EMP)") message = "The door is now electrified [duration == -1 ? "permanently" : "for [duration] second\s"]." @@ -281,7 +281,7 @@ About the new airlock wires panel: if(duration != -1) electrified_timer = addtimer(CALLBACK(src, .proc/electrify, 0), duration SECONDS, TIMER_UNIQUE | TIMER_STOPPABLE) if(feedback && message) - to_chat(usr, message) + to_chat(user, message) // shock user with probability prb (if all connections & power are working) // returns 1 if shocked, 0 otherwise @@ -516,6 +516,10 @@ About the new airlock wires panel: var/obj/machinery/door/airlock/airlock = painter.available_paint_jobs["[painter.paint_setting]"] // get the airlock type path associated with the airlock name the user just chose var/obj/structure/door_assembly/assembly = initial(airlock.assemblytype) + if(assemblytype == assembly) + to_chat(user, "This airlock is already painted [painter.paint_setting]!") + return + if(airlock_material == "glass" && initial(assembly.noglass)) // prevents painting glass airlocks with a paint job that doesn't have a glass version, such as the freezer to_chat(user, "This paint job can only be applied to non-glass airlocks.") return @@ -753,6 +757,22 @@ About the new airlock wires panel: else try_to_activate_door(user) +/obj/machinery/door/airlock/proc/ai_control_check(mob/user) + if(!issilicon(user)) + return TRUE + if(emagged) + to_chat(user, "Unable to interface: Internal error.") + return FALSE + if(!canAIControl()) + if(canAIHack(user)) + hack(user) + else + if(isAllPowerLoss()) + to_chat(user, "Unable to interface: Connection timed out.") + else + to_chat(user, "Unable to interface: Connection refused.") + return FALSE + return TRUE /obj/machinery/door/airlock/tgui_act(action, params) if(..()) @@ -760,17 +780,7 @@ About the new airlock wires panel: if(!issilicon(usr) && !usr.can_admin_interact()) to_chat(usr, "Access denied. Only silicons may use this interface.") return - if(issilicon(usr) && emagged) - to_chat(usr, "Unable to interface: Internal error.") - return - if(!canAIControl() && !isobserver(usr)) - if(canAIHack(usr)) - hack(usr) - else - if(isAllPowerLoss()) - to_chat(usr, "Unable to interface: Connection timed out.") - else - to_chat(usr, "Unable to interface: Connection refused.") + if(!ai_control_check(usr)) return . = TRUE switch(action) @@ -788,29 +798,20 @@ About the new airlock wires panel: else to_chat(usr, "Backup power is already offline.") if("shock-restore") - to_chat(usr, "The door is now un-electrified.") - electrify(0) + electrify(0, usr, TRUE) if("shock-temp") if(wires.is_cut(WIRE_ELECTRIFY)) to_chat(usr, "The electrification wire is cut - Door permanently electrified.") . = FALSE else //electrify door for 30 seconds - shockedby += text("\[[time_stamp()]\][usr](ckey:[usr.ckey])") - usr.create_attack_log("Electrified the [name] at [x] [y] [z]") - add_attack_logs(usr, src, "Electrified", ATKLOG_ALL) - to_chat(usr, "The door is now electrified for thirty seconds.") - electrify(30) + electrify(30, usr, TRUE) if("shock-perm") if(wires.is_cut(WIRE_ELECTRIFY)) to_chat(usr, "The electrification wire is cut - Cannot electrify the door.") . = FALSE else - shockedby += text("\[[time_stamp()]\][usr](ckey:[usr.ckey])") - usr.create_attack_log("Electrified the [name] at [x] [y] [z]") - add_attack_logs(usr, src, "Electrified", ATKLOG_ALL) - to_chat(usr, "The door is now electrified.") - electrify(-1) + electrify(-1, usr, TRUE) if("idscan-toggle") if(wires.is_cut(WIRE_IDSCAN)) to_chat(usr, "The IdScan wire has been cut - IdScan feature permanently disabled.") @@ -822,29 +823,11 @@ About the new airlock wires panel: aiDisabledIdScanner = TRUE to_chat(usr, "IdScan feature has been disabled.") if("emergency-toggle") - emergency = !emergency - if(emergency) - to_chat(usr, "Emergency access has been enabled.") - else - to_chat(usr, "Emergency access has been disabled.") - update_icon() + toggle_emergency_status(usr) if("bolt-toggle") - if(wires.is_cut(WIRE_DOOR_BOLTS)) - to_chat(usr, "The door bolt control wire has been cut - Door bolts permanently dropped.") - else if(lock()) - to_chat(usr, "The door bolts have been dropped.") - else if(unlock()) - to_chat(usr, "The door bolts have been raised.") + toggle_bolt(usr) if("light-toggle") - if(wires.is_cut(WIRE_BOLT_LIGHT)) - to_chat(usr, "The bolt lights wire has been cut - The door bolt lights are permanently disabled.") - else if(lights) - lights = FALSE - to_chat(usr, "The door bolt lights have been disabled.") - else if(!lights) - lights = TRUE - to_chat(usr, "The door bolt lights have been enabled.") - update_icon() + toggle_light(usr) if("safe-toggle") if(wires.is_cut(WIRE_SAFETY)) to_chat(usr, "The safety wire is cut - Cannot secure the door.") @@ -862,17 +845,49 @@ About the new airlock wires panel: else normalspeed = 1 if("open-close") - if(welded) - to_chat(usr, "The airlock has been welded shut!") - else if(locked) - to_chat(usr, "The door bolts are down!") - else if(density) - open() - else - close() + open_close(usr) else . = FALSE +/obj/machinery/door/airlock/proc/open_close(mob/user) + if(welded) + to_chat(user, "The airlock has been welded shut!") + return FALSE + else if(locked) + to_chat(user, "The door bolts are down!") + return FALSE + else if(density) + return open() + else + return close() + +/obj/machinery/door/airlock/proc/toggle_light(mob/user) + if(wires.is_cut(WIRE_BOLT_LIGHT)) + to_chat(user, "The bolt lights wire has been cut - The door bolt lights are permanently disabled.") + else if(lights) + lights = FALSE + to_chat(user, "The door bolt lights have been disabled.") + else if(!lights) + lights = TRUE + to_chat(user, "The door bolt lights have been enabled.") + update_icon() + +/obj/machinery/door/airlock/proc/toggle_bolt(mob/user) + if(wires.is_cut(WIRE_DOOR_BOLTS)) + to_chat(user, "The door bolt control wire has been cut - Door bolts permanently dropped.") + else if(lock()) + to_chat(user, "The door bolts have been dropped.") + else if(unlock()) + to_chat(user, "The door bolts have been raised.") + +/obj/machinery/door/airlock/proc/toggle_emergency_status(mob/user) + emergency = !emergency + if(emergency) + to_chat(user, "Emergency access has been enabled.") + else + to_chat(user, "Emergency access has been disabled.") + update_icon() + /obj/machinery/door/airlock/attackby(obj/item/C, mob/user, params) add_fingerprint(user) if(!headbutt_shock_check(user)) diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index 911f85be753..6144d1c3883 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -30,7 +30,6 @@ FIRE ALARM light_range = 7 light_color = "#ff3232" - var/last_process = 0 var/wiresexposed = 0 var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone var/enabled = FALSE @@ -85,7 +84,8 @@ FIRE ALARM return attack_hand(user) /obj/machinery/firealarm/attack_ghost(mob/user) - ui_interact(user) + if(user.can_admin_interact()) + toggle_alarm(user) /obj/machinery/firealarm/emp_act(severity) if(prob(50/severity)) @@ -218,21 +218,6 @@ FIRE ALARM else set_light(l_power = 0) -/obj/machinery/firealarm/process()//Note: this processing was mostly phased out due to other code, and only runs when needed - if(stat & (NOPOWER|BROKEN)) - return - - if(timing) - if(time > 0) - time = time - ((world.timeofday - last_process)/10) - else - alarm() - time = 0 - timing = 0 - STOP_PROCESSING(SSobj, src) - updateDialog() - last_process = world.timeofday - /obj/machinery/firealarm/power_change() if(powered(ENVIRON)) stat &= ~NOPOWER @@ -249,56 +234,21 @@ FIRE ALARM if(user.incapacitated()) return 1 - ui_interact(user) + toggle_alarm(user) -/obj/machinery/firealarm/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) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) - if(!ui) - ui = new(user, src, ui_key, "firealarm.tmpl", name, 400, 400, state = state) - ui.open() - ui.set_auto_update(1) - -/obj/machinery/firealarm/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] +/obj/machinery/firealarm/proc/toggle_alarm(mob/user) var/area/A = get_area(src) - data["fire"] = A.fire - data["timing"] = timing + if(istype(A)) + add_fingerprint(user) + if(A.fire) + reset() + else + alarm() - data["sec_level"] = get_security_level() - - var/second = round(time % 60) - var/minute = round(time / 60) - - data["time_left"] = "[minute ? "[minute]:" : ""][add_zero(num2text(second), 2)]" - return data - -/obj/machinery/firealarm/Topic(href, href_list) - if(..()) - return 1 - - if(buildstage != 2) - return 1 - - add_fingerprint(usr) - - if(href_list["reset"]) - reset() - else if(href_list["alarm"]) - alarm() - else if(href_list["time"]) - var/oldTiming = timing - timing = text2num(href_list["time"]) - last_process = world.timeofday - if(oldTiming != timing) - if(timing) - START_PROCESSING(SSobj, src) - else - STOP_PROCESSING(SSobj, src) - else if(href_list["tp"]) - var/tp = text2num(href_list["tp"]) - time += tp - time = min(max(round(time), 0), 120) +/obj/machinery/firealarm/examine(mob/user) + . = ..() + . += "It shows the alert level as: [capitalize(get_security_level())]." /obj/machinery/firealarm/proc/reset() if(!working || !report_fire_alarms) diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index 37766db58fb..369d43e5d94 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -25,20 +25,17 @@ base_state = "pflash" density = 1 -/* -/obj/machinery/flasher/New() - sleep(4) //<--- What the fuck are you doing? D= - sd_set_light(2) -*/ +/obj/machinery/flasher/portable/ComponentInitialize() + . = ..() + AddComponent(/datum/component/proximity_monitor) + /obj/machinery/flasher/power_change() if( powered() ) stat &= ~NOPOWER icon_state = "[base_state]1" -// sd_set_light(2) else stat |= ~NOPOWER icon_state = "[base_state]1-p" -// sd_set_light(0) //Let the AI trigger them directly. /obj/machinery/flasher/attack_ai(mob/user) @@ -81,7 +78,7 @@ flash() ..(severity) -/obj/machinery/flasher/portable/HasProximity(atom/movable/AM as mob|obj) +/obj/machinery/flasher/portable/HasProximity(atom/movable/AM) if((disable) || (last_flash && world.time < last_flash + 150)) return @@ -109,7 +106,7 @@ if(anchored) WRENCH_ANCHOR_MESSAGE overlays.Cut() - else if(anchored) + else WRENCH_UNANCHOR_MESSAGE overlays += "[base_state]-s" diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index 6fb34254f3a..85fe8fcf843 100644 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -12,7 +12,7 @@ active_power_usage = 200 pass_flags = PASSTABLE - var/list/allowed_devices = list(/obj/item/gun/energy, /obj/item/melee/baton, /obj/item/modular_computer, /obj/item/rcs, /obj/item/bodyanalyzer) + var/list/allowed_devices = list(/obj/item/gun/energy, /obj/item/melee/baton, /obj/item/rcs, /obj/item/bodyanalyzer) var/icon_state_off = "rechargeroff" var/icon_state_charged = "recharger2" var/icon_state_charging = "recharger1" @@ -155,12 +155,6 @@ var/obj/item/melee/baton/B = I return B.cell - if(istype(I, /obj/item/modular_computer)) - var/obj/item/modular_computer/C = I - var/obj/item/computer_hardware/battery/B = C.all_components[MC_CELL] - if(B) - return B.battery - if(istype(I, /obj/item/rcs)) var/obj/item/rcs/R = I return R.rcell diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index 56019d22f7c..5d26f0e946e 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -9,7 +9,7 @@ anchored = 1 density = 1 damage_deflection = 15 - var/safety_mode = 0 // Temporarily stops machine if it detects a mob + var/emergency_mode = FALSE // Temporarily stops machine if it detects a mob var/icon_name = "grinder-o" var/blood = 0 var/eat_dir = WEST @@ -42,9 +42,9 @@ /obj/machinery/recycler/examine(mob/user) . = ..() - . += "The power light is [(stat & NOPOWER) ? "off" : "on"]." - . += "The safety-mode light is [safety_mode ? "on" : "off"]." - . += "The safety-sensors status light is [emagged ? "off" : "on"]." + . += "The power light is [(stat & NOPOWER) ? "off" : "on"]." + . += "The operation light is [emergency_mode ? "off. [src] has detected a forbidden object with its sensors, and has shut down temporarily." : "on. [src] is active."]" + . += "The safety sensor light is [emagged ? "off!" : "on."]" /obj/machinery/recycler/power_change() ..() @@ -73,8 +73,8 @@ /obj/machinery/recycler/emag_act(mob/user) if(!emagged) emagged = 1 - if(safety_mode) - safety_mode = 0 + if(emergency_mode) + emergency_mode = FALSE update_icon() playsound(loc, "sparks", 75, 1, -1) to_chat(user, "You use the cryptographic sequencer on the [name].") @@ -82,7 +82,7 @@ /obj/machinery/recycler/update_icon() ..() var/is_powered = !(stat & (BROKEN|NOPOWER)) - if(safety_mode) + if(emergency_mode) is_powered = 0 icon_state = icon_name + "[is_powered]" + "[(blood ? "bld" : "")]" // add the blood tag at the end @@ -98,7 +98,7 @@ return if(!anchored) return - if(safety_mode) + if(emergency_mode) return var/move_dir = get_dir(loc, AM.loc) @@ -145,14 +145,14 @@ /obj/machinery/recycler/proc/emergency_stop(mob/living/L) playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) - safety_mode = 1 + emergency_mode = TRUE update_icon() L.loc = loc addtimer(CALLBACK(src, .proc/reboot), SAFETY_COOLDOWN) /obj/machinery/recycler/proc/reboot() playsound(loc, 'sound/machines/ping.ogg', 50, 0) - safety_mode = 0 + emergency_mode = FALSE update_icon() /obj/machinery/recycler/proc/crush_living(mob/living/L) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index 822c4af3e1a..59865dee52a 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -96,7 +96,7 @@ name = "atmospherics suit storage unit" suit_type = /obj/item/clothing/suit/space/hardsuit/engine/atmos mask_type = /obj/item/clothing/mask/gas - magboots_type = /obj/item/clothing/shoes/magboots + magboots_type = /obj/item/clothing/shoes/magboots/atmos req_access = list(ACCESS_ATMOSPHERICS) /obj/machinery/suit_storage_unit/atmos/secure diff --git a/code/game/machinery/tcomms/_base.dm b/code/game/machinery/tcomms/_base.dm index c3531c7f674..892392a8c54 100644 --- a/code/game/machinery/tcomms/_base.dm +++ b/code/game/machinery/tcomms/_base.dm @@ -40,7 +40,7 @@ GLOBAL_LIST_EMPTY(tcomms_machines) var/network_id = "None" /// Is the machine active var/active = TRUE - /// Has the machine been hit by an ionspheric anomalie + /// Has the machine been hit by an ionospheric anomaly var/ion = FALSE /** @@ -94,15 +94,15 @@ GLOBAL_LIST_EMPTY(tcomms_machines) // Attack overrides. These are needed so the UIs can be opened up // /obj/machinery/tcomms/attack_ai(mob/user) add_hiddenprint(user) - ui_interact(user) + tgui_interact(user) /obj/machinery/tcomms/attack_ghost(mob/user) - ui_interact(user) + tgui_interact(user) /obj/machinery/tcomms/attack_hand(mob/user) if(..(user)) return - ui_interact(user) + tgui_interact(user) /** diff --git a/code/game/machinery/tcomms/core.dm b/code/game/machinery/tcomms/core.dm index 622ce2e2b9f..9f84f3af963 100644 --- a/code/game/machinery/tcomms/core.dm +++ b/code/game/machinery/tcomms/core.dm @@ -164,101 +164,90 @@ // UI STUFF // ////////////// -/obj/machinery/tcomms/core/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - // this is silly but it has to be done because NTTC inits before languages do - if(nttc.valid_languages.len == 1) +/obj/machinery/tcomms/core/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) + // This needs to happen here because of how late the language datum initializes. I dont like it + if(length(nttc.valid_languages) == 1) nttc.update_languages() - // Now the actual UI stuff - 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, "tcomms_core.tmpl", "Telecommunications Core", 900, 600) + ui = new(user, src, ui_key, "TcommsCore", name, 900, 600, master_ui, state) ui.open() - ui.set_auto_update(1) -/obj/machinery/tcomms/core/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - // What tab are we on - data["tab"] = ui_tab +/obj/machinery/tcomms/core/tgui_data(mob/user) + var/list/data = list() data["ion"] = ion - // Only send NTTC settings if were on the right tab. This saves on sending overhead. - if(ui_tab == UI_TAB_CONFIG) - // Z-level list. Note that this will also show sectors with hidden relay links, but you cant see the relays themselves - // This allows the crew to realise that sectors have hidden relays - data["sectors_available"] = "Count: [length(reachable_zlevels)] | List: [jointext(reachable_zlevels, " ")]" - // Toggles - data["active"] = active - data["nttc_toggle_jobs"] = nttc.toggle_jobs - data["nttc_toggle_job_color"] = nttc.toggle_job_color - data["nttc_toggle_name_color"] = nttc.toggle_name_color - data["nttc_toggle_command_bold"] = nttc.toggle_command_bold - // Strings - data["nttc_setting_language"] = nttc.setting_language - data["nttc_job_indicator_type"] = nttc.job_indicator_type - // Network ID - data["network_id"] = network_id + // Z-level list. Note that this will also show sectors with hidden relay links, but you cant see the relays themselves + // This allows the crew to realise that sectors have hidden relays + data["sectors_available"] = "Count: [length(reachable_zlevels)] | List: [jointext(reachable_zlevels, " ")]" + // Toggles + data["active"] = active + data["nttc_toggle_jobs"] = nttc.toggle_jobs + data["nttc_toggle_job_color"] = nttc.toggle_job_color + data["nttc_toggle_name_color"] = nttc.toggle_name_color + data["nttc_toggle_command_bold"] = nttc.toggle_command_bold + // Strings + data["nttc_setting_language"] = nttc.setting_language + data["nttc_job_indicator_type"] = nttc.job_indicator_type + // Network ID + data["network_id"] = network_id - if(ui_tab == UI_TAB_LINKS) - data["link_password"] = link_password - // You ready to see some shit? - for(var/obj/machinery/tcomms/relay/R in linked_relays) - // Dont show relays with a hidden link - if(R.hidden_link) - continue - // Assume false - var/status = FALSE - var/status_color = "'background-color: #eb4034'" // Red - if(R.active && !(R.stat & NOPOWER)) - status = TRUE - status_color = "'background-color: #32a852'" // Green + data["link_password"] = link_password + // You ready to see some awful shit? + var/list/relays = list() + for(var/obj/machinery/tcomms/relay/R in linked_relays) + // Dont show relays with a hidden link + if(R.hidden_link) + continue + // Assume false + var/status = FALSE + if(R.active && !(R.stat & NOPOWER)) + status = TRUE + relays += list(list("addr" = "\ref[R]", "net_id" = R.network_id, "sector" = R.loc.z, "status" = status)) - data["entries"] += list(list("addr" = "\ref[R]", "net_id" = R.network_id, "sector" = R.loc.z, "status" = status, "status_color" = status_color)) - // End the shit + data["relay_entries"] = relays + // End the shit - if(ui_tab == UI_TAB_FILTER) - data["filtered_users"] = nttc.filtering + data["filtered_users"] = nttc.filtering return data -/obj/machinery/tcomms/core/Topic(href, href_list) +/obj/machinery/tcomms/core/tgui_act(action, list/params) // Check against href exploits if(..()) return - if(href_list["tab"]) - // Make sure its a valid tab - if(href_list["tab"] in list(UI_TAB_CONFIG, UI_TAB_LINKS, UI_TAB_FILTER)) - ui_tab = href_list["tab"] + . = TRUE - // Check if they did a href, but only for that current tab - if(ui_tab == UI_TAB_CONFIG) + switch(action) // All the toggle on/offs go here - if(href_list["toggle_active"]) + if("toggle_active") if(check_power_on()) active = !active update_icon() else to_chat(usr, "Error: Another core is already active in this sector. Power-up cancelled due to radio interference.") + // NTTC Toggles - if(href_list["nttc_toggle_jobs"]) + if("nttc_toggle_jobs") nttc.toggle_jobs = !nttc.toggle_jobs log_action(usr, "toggled job tags (Now [nttc.toggle_jobs])") - if(href_list["nttc_toggle_job_color"]) + if("nttc_toggle_job_color") nttc.toggle_job_color = !nttc.toggle_job_color log_action(usr, "toggled job colors (Now [nttc.toggle_job_color])") - if(href_list["nttc_toggle_name_color"]) + if("nttc_toggle_name_color") nttc.toggle_name_color = !nttc.toggle_name_color log_action(usr, "toggled name colors (Now [nttc.toggle_name_color])") - if(href_list["nttc_toggle_command_bold"]) + if("nttc_toggle_command_bold") nttc.toggle_command_bold = !nttc.toggle_command_bold log_action(usr, "toggled command bold (Now [nttc.toggle_command_bold])") // We need to be a little more fancy for the others // Job Format - if(href_list["nttc_job_indicator_type"]) + if("nttc_job_indicator_type") var/card_style = input(usr, "Pick a job card format.", "Job Card Format") as null|anything in nttc.job_card_styles if(!card_style) return @@ -267,7 +256,7 @@ log_action(usr, "has set NTTC job card format to [card_style]") // Language Settings - if(href_list["nttc_setting_language"]) + if("nttc_setting_language") var/new_language = input(usr, "Pick a language to convert messages to.", "Language Conversion") as null|anything in nttc.valid_languages if(!new_language) return @@ -281,24 +270,23 @@ log_action(usr, new_language == "--DISABLE--" ? "disabled NTTC language conversion" : "set NTTC language conversion to [new_language]", TRUE) // Imports and exports - if(href_list["import"]) + if("import") var/json = input(usr, "Provide configuration JSON below.", "Load Config", nttc.nttc_serialize()) as message if(nttc.nttc_deserialize(json, usr.ckey)) log_action(usr, "has uploaded a NTTC JSON configuration: [ADMIN_SHOWDETAILS("Show", json)]", TRUE) - if(href_list["export"]) + if("export") usr << browse(nttc.nttc_serialize(), "window=save_nttc") // Set network ID - if(href_list["network_id"]) + if("network_id") var/new_id = input(usr, "Please enter a new network ID", "Network ID", network_id) log_action(usr, "renamed core with ID [network_id] to [new_id]") to_chat(usr, "Device ID changed from [network_id] to [new_id].") network_id = new_id - if(ui_tab == UI_TAB_LINKS) - if(href_list["unlink"]) - var/obj/machinery/tcomms/relay/R = locate(href_list["unlink"]) + if("unlink") + var/obj/machinery/tcomms/relay/R = locate(params["addr"]) if(istype(R, /obj/machinery/tcomms/relay)) var/confirm = alert("Are you sure you want to unlink this relay?\nID: [R.network_id]\nADDR: \ref[R]", "Relay Unlink", "Yes", "No") if(confirm == "Yes") @@ -307,14 +295,13 @@ else to_chat(usr, "ERROR: Relay not found. Please file an issue report.") - if(href_list["change_password"]) + if("change_password") var/new_password = input(usr, "Please enter a new password","New Password", link_password) log_action(usr, "has changed the password on core with ID [network_id] from [link_password] to [new_password]") to_chat(usr, "Successfully changed password from [link_password] to [new_password].") link_password = new_password - if(ui_tab == UI_TAB_FILTER) - if(href_list["add_filter"]) + if("add_filter") // This is a stripped input because I did NOT come this far for this system to be abused by HTML injection var/name_to_add = stripped_input(usr, "Enter a name to add to the filtering list", "Name Entry") if(name_to_add == "") @@ -326,9 +313,8 @@ log_action(usr, "has added [name_to_add] to the NTTC filter list on core with ID [network_id]", TRUE) to_chat(usr, "Successfully added [name_to_add] to the NTTC filtering list.") - - if(href_list["remove_filter"]) - var/name_to_remove = href_list["remove_filter"] + if("remove_filter") + var/name_to_remove = params["user"] if(!(name_to_remove in nttc.filtering)) to_chat(usr, "ERROR: Name does not exist in filter list. Please file an issue report.") else @@ -339,9 +325,6 @@ to_chat(usr, "Successfully removed [name_to_remove] from the NTTC filtering list.") - // Hack to speed update the nanoUI - SSnanoui.update_uis(src) - #undef UI_TAB_CONFIG #undef UI_TAB_LINKS #undef UI_TAB_FILTER diff --git a/code/game/machinery/tcomms/relay.dm b/code/game/machinery/tcomms/relay.dm index bf5e6e21a9c..27d4e750bc5 100644 --- a/code/game/machinery/tcomms/relay.dm +++ b/code/game/machinery/tcomms/relay.dm @@ -132,15 +132,14 @@ // UI STUFF // ////////////// -/obj/machinery/tcomms/relay/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/tcomms/relay/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, "tcomms_relay.tmpl", "Telecommunications Relay", 600, 400) + ui = new(user, src, ui_key, "TcommsRelay", name, 600, 400, master_ui, state) ui.open() - ui.set_auto_update(1) -/obj/machinery/tcomms/relay/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] +/obj/machinery/tcomms/relay/tgui_data(mob/user) + var/list/data = list() // Are we on or not data["active"] = active // What is our network ID @@ -154,50 +153,58 @@ if(linked) data["linked_core_id"] = linked_core.network_id data["linked_core_addr"] = "\ref[linked_core]" - else + var/list/cores = list() for(var/obj/machinery/tcomms/core/C in GLOB.tcomms_machines) - data["entries"] += list(list("addr" = "\ref[C]", "net_id" = C.network_id, "sector" = C.loc.z)) + cores += list(list("addr" = "\ref[C]", "net_id" = C.network_id, "sector" = C.loc.z)) + data["cores"] = cores return data -/obj/machinery/tcomms/relay/Topic(href, href_list) +/obj/machinery/tcomms/relay/tgui_act(action, list/params) // Check against href exploits if(..()) return - // All the toggle on/offs go here - if(href_list["toggle_active"]) - if(check_power_on()) - active = !active - update_icon() - if(linked_core) - linked_core.refresh_zlevels() - else - to_chat(usr, "Error: Another relay is already active in this sector. Power-up cancelled due to radio interference.") + . = TRUE - // Set network ID - if(href_list["network_id"]) - var/new_id = input(usr, "Please enter a new network ID", "Network ID", network_id) - log_action(usr, "renamed core with ID [network_id] to [new_id]") - to_chat(usr, "Device ID changed from [network_id] to [new_id].") - network_id = new_id + switch(action) + if("toggle_active") + if(check_power_on()) + active = !active + update_icon() + if(linked_core) + linked_core.refresh_zlevels() + else + to_chat(usr, "Error: Another relay is already active in this sector. Power-up cancelled due to radio interference.") + + // Set network ID + if("network_id") + var/new_id = input(usr, "Please enter a new network ID", "Network ID", network_id) + log_action(usr, "renamed core with ID [network_id] to [new_id]") + to_chat(usr, "Device ID changed from [network_id] to [new_id].") + network_id = new_id - if(linked) // Only do these hrefs if we are linked to prevent bugs/exploits - if(href_list["toggle_hidden_link"]) + if("toggle_hidden_link") + if(!linked) + return hidden_link = !hidden_link log_action(usr, "Modified hidden link for [network_id] (Now [hidden_link])") - if(href_list["unlink"]) + if("unlink") + if(!linked) + return var/choice = alert(usr, "Are you SURE you want to unlink this relay?\nYou wont be able to re-link without the core password", "Unlink","Yes","No") if(choice == "Yes") log_action(usr, "Unlinked [network_id] from [linked_core.network_id]") Reset() - else + // You should only be able to link if its not linked, to prevent weirdness - if(href_list["link"]) - var/obj/machinery/tcomms/core/C = locate(href_list["link"]) + if("link") + if(linked) + return + var/obj/machinery/tcomms/core/C = locate(params["addr"]) if(istype(C, /obj/machinery/tcomms/core)) var/user_pass = input(usr, "Please enter core password","Password Entry") // Check the password @@ -210,5 +217,3 @@ to_chat(usr, "ERROR: Core not found. Please file an issue report.") - // Hack to speed update the nanoUI - SSnanoui.update_uis(src) diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 8e87506803b..20fd93547eb 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -1907,46 +1907,3 @@ component_parts += new /obj/item/vending_refill/crittercare(null) RefreshParts() return ..() - -/obj/machinery/vending/modularpc - name = "\improper Deluxe Silicate Selections" - desc = "All the parts you need to build your own custom pc." - icon_state = "modularpc" - icon_deny = "modularpc-deny" - ads_list = list("Get your gamer gear!","The best GPUs for all of your space-crypto needs!","The most robust cooling!","The finest RGB in space!") - vend_reply = "Game on!" - products = list(/obj/item/modular_computer/laptop = 4, - /obj/item/modular_computer/tablet = 4, - /obj/item/computer_hardware/hard_drive = 4, - /obj/item/computer_hardware/hard_drive/small = 4, - /obj/item/computer_hardware/network_card = 8, - /obj/item/computer_hardware/hard_drive/portable = 8, - /obj/item/computer_hardware/battery = 8, - /obj/item/stock_parts/cell/computer = 8, - /obj/item/computer_hardware/processor_unit = 4, - /obj/item/computer_hardware/processor_unit/small = 4) - premium = list(/obj/item/computer_hardware/card_slot = 2, - /obj/item/computer_hardware/ai_slot = 2, - /obj/item/computer_hardware/printer/mini = 2, - /obj/item/computer_hardware/recharger/APC = 2, - /obj/item/paicard = 2) - prices = list(/obj/item/modular_computer/laptop = 300, - /obj/item/modular_computer/tablet = 300, - /obj/item/computer_hardware/hard_drive = 100, - /obj/item/computer_hardware/hard_drive/small = 50, - /obj/item/computer_hardware/network_card = 100, - /obj/item/computer_hardware/hard_drive/portable = 100, - /obj/item/computer_hardware/battery = 100, - /obj/item/stock_parts/cell/computer = 100, - /obj/item/computer_hardware/processor_unit = 100, - /obj/item/computer_hardware/processor_unit/small = 100) - refill_canister = /obj/item/vending_refill/modularpc - -/obj/machinery/vending/modularpc/Initialize(mapload) - component_parts = list() - var/obj/item/circuitboard/vendor/V = new(null) - V.set_type(type) - component_parts += V - component_parts += new /obj/item/vending_refill/modularpc(null) - RefreshParts() - return ..() diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index d1e63deaf0c..e8db08bf37c 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -59,9 +59,7 @@ sleep(max(0, projectile_delay)) set_ready_state(0) log_message("Fired from [name], targeting [target].") - var/turf/T = get_turf(src) - 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]") + add_attack_logs(chassis.occupant, target, "fired a [src]") do_after_cooldown() return @@ -209,7 +207,7 @@ for(var/mob/living/carbon/M in ohearers(6, chassis)) if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/H = M - if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) || istype(H.r_ear, /obj/item/clothing/ears/earmuffs)) + if(H.check_ear_prot() >= HEARING_PROTECTION_TOTAL) continue to_chat(M, "HONK") M.SetSleeping(0) diff --git a/code/game/objects/effects/effects.dm b/code/game/objects/effects/effects.dm index 7497b148788..625d2ad8fd9 100644 --- a/code/game/objects/effects/effects.dm +++ b/code/game/objects/effects/effects.dm @@ -45,6 +45,42 @@ if(prob(25)) qdel(src) +/** + * # The abstract object + * + * This is an object that is intended to able to be placed, but that is completely invisible. + * The object should be immune to all forms of damage, or things that can delete it, such as the singularity, or explosions. + */ +/obj/effect/abstract + name = "Abstract object" + invisibility = INVISIBILITY_ABSTRACT + layer = TURF_LAYER + density = FALSE + icon = null + icon_state = null + +// Most of these overrides procs below are overkill, but better safe than sorry. +/obj/effect/abstract/swarmer_act() + return + +/obj/effect/abstract/bullet_act(obj/item/projectile/P) + return + +/obj/effect/abstract/decompile_act(obj/item/matter_decompiler/C, mob/user) + return + +/obj/effect/abstract/tesla_act(power) + return + +/obj/effect/abstract/singularity_act() + return + +/obj/effect/abstract/narsie_act() + return + +/obj/effect/abstract/ex_act(severity) + return + /obj/effect/decal plane = FLOOR_PLANE resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF diff --git a/code/game/objects/effects/temporary_visuals/muzzle_flashes.dm b/code/game/objects/effects/temporary_visuals/muzzle_flashes.dm new file mode 100644 index 00000000000..ab7bb7a056d --- /dev/null +++ b/code/game/objects/effects/temporary_visuals/muzzle_flashes.dm @@ -0,0 +1,19 @@ +/obj/effect/temp_visual/target_angled/muzzle_flash + icon = 'icons/effects/projectile.dmi' + icon_state = "firing_effect" + duration = 0.2 + +/obj/effect/temp_visual/target_angled/muzzle_flash/Initialize(mapload, atom/target, duration_override = null) + if(duration_override) + duration = duration_override + . = ..() + if(get_dir(src, target) & NORTH) + layer = BELOW_MOB_LAYER + + +/obj/effect/temp_visual/target_angled/muzzle_flash/energy + icon_state = "firing_effect_energy" + +/obj/effect/temp_visual/target_angled/muzzle_flash/magic + icon = 'icons/effects/effects.dmi' + icon_state = "shieldsparkles" diff --git a/code/game/objects/effects/temporary_visuals/temporary_visual.dm b/code/game/objects/effects/temporary_visuals/temporary_visual.dm index d09acce7255..0bbbb554ace 100644 --- a/code/game/objects/effects/temporary_visuals/temporary_visual.dm +++ b/code/game/objects/effects/temporary_visuals/temporary_visual.dm @@ -35,3 +35,13 @@ if(set_dir) setDir(set_dir) . = ..() + +/obj/effect/temp_visual/target_angled + randomdir = FALSE + +/obj/effect/temp_visual/target_angled/Initialize(mapload, atom/target) + . = ..() + if(target) + var/matrix/M = new + M.Turn(get_angle(src, target)) + transform = M diff --git a/code/game/objects/items/devices/camera_bug.dm b/code/game/objects/items/devices/camera_bug.dm index 7724d499e7e..2305eabb654 100644 --- a/code/game/objects/items/devices/camera_bug.dm +++ b/code/game/objects/items/devices/camera_bug.dm @@ -1,9 +1,4 @@ -#define BUGMODE_LIST 0 -#define BUGMODE_MONITOR 1 -#define BUGMODE_TRACK 2 - - - +// This item just has an integrated camera console, which the data is "proxied" to /obj/item/camera_bug name = "camera bug" desc = "For illicit snooping through the camera network." @@ -14,270 +9,21 @@ throw_speed = 4 throw_range = 20 origin_tech = "syndicate=1;engineering=3" + /// Integrated camera console to serve UI data + var/obj/machinery/computer/security/integrated_console - var/obj/machinery/camera/current = null - - var/last_net_update = 0 - var/list/bugged_cameras = list() - - var/track_mode = BUGMODE_LIST - var/last_tracked = 0 - var/refresh_interval = 50 - - var/tracked_name = null - var/atom/tracking = null - - var/last_found = null - var/last_seen = null - -/obj/item/camera_bug/New() - ..() - START_PROCESSING(SSobj, src) +/obj/item/camera_bug/Initialize(mapload) + . = ..() + integrated_console = new + integrated_console.parent = src + integrated_console.network = list("SS13") /obj/item/camera_bug/Destroy() - get_cameras() - for(var/cam_tag in bugged_cameras) - var/obj/machinery/camera/camera = bugged_cameras[cam_tag] - if(camera.bug == src) - camera.bug = null - bugged_cameras = list() - if(tracking) - tracking = null + QDEL_NULL(integrated_console) return ..() -/obj/item/camera_bug/interact(var/mob/user = usr) - var/datum/browser/popup = new(user, "camerabug","Camera Bug",nref=src) - popup.set_content(menu(get_cameras())) - popup.open() - /obj/item/camera_bug/attack_self(mob/user as mob) - user.set_machine(src) - interact(user) + tgui_interact(user) -/obj/item/camera_bug/check_eye(mob/user) - if(loc != user || user.incapacitated() || !user.has_vision() || !current) - user.unset_machine() - return FALSE - var/turf/T_user = get_turf(user.loc) - var/turf/T_current = get_turf(current) - if(!atoms_share_level(T_user, T_current) || !current.can_use()) - to_chat(user, "[src] has lost the signal.") - current = null - user.unset_machine() - return FALSE - return TRUE - -/obj/item/camera_bug/on_unset_machine(mob/user) - user.reset_perspective(null) - -/obj/item/camera_bug/proc/get_cameras() - if(world.time > (last_net_update + 100)) - bugged_cameras = list() - for(var/obj/machinery/camera/camera in GLOB.cameranet.cameras) - if(camera.stat || !camera.can_use()) - continue - if(length(list("SS13","MINE")&camera.network)) - bugged_cameras[camera.c_tag] = camera - sortTim(bugged_cameras, /proc/cmp_text_asc) - return bugged_cameras - -/obj/item/camera_bug/proc/menu(var/list/cameras) - if(!cameras || !cameras.len) - return "No bugged cameras found." - - var/html - switch(track_mode) - if(BUGMODE_LIST) - html = "

    Select a camera:

    \[Cancel camera view\]
    [T.title]
    " - for(var/entry in cameras) - var/obj/machinery/camera/C = cameras[entry] - var/functions = "" - if(C.bug == src) - functions = " - \[Monitor\]\[Disable\]" - else - functions = " - \[Monitor\]" - html += "" - - if(BUGMODE_MONITOR) - if(current) - html = "Analyzing Camera '[current.c_tag]' \[Select Camera\]
    " - html += camera_report() - else - track_mode = BUGMODE_LIST - return .(cameras) - if(BUGMODE_TRACK) - if(tracking) - html = "Tracking '[tracked_name]' \[Cancel Tracking\]\[Cancel camera view\]
    " - if(last_found) - var/time_diff = round((world.time - last_seen) / 150) - var/obj/machinery/camera/C = bugged_cameras[last_found] - var/outstring - if(C) - outstring = "[last_found]" - else - outstring = last_found - if(!time_diff) - html += "Last seen near [outstring] (now)
    " - else - // 15 second intervals ~ 1/4 minute - var/m = round(time_diff/4) - var/s = (time_diff - 4*m) * 15 - if(!s) s = "00" - html += "Last seen near [outstring] ([m]:[s] minute\s ago)
    " - if( C && (C.bug == src)) //Checks to see if the camera has a bug - html += "\[Disable\]" - - else - html += "Not yet seen." - else - track_mode = BUGMODE_LIST - return .(cameras) - return html - -/obj/item/camera_bug/proc/camera_report() - // this should only be called if current exists - var/dat = "" - if(current && current.can_use()) - var/list/seen = current.can_see() - var/list/names = list() - for(var/obj/singularity/S in seen) // god help you if you see more than one - if(S.name in names) - names[S.name]++ - dat += "[S.name] ([names[S.name]])" - else - names[S.name] = 1 - dat += "[S.name]" - var/stage = round(S.current_size / 2)+1 - dat += " (Stage [stage])" - dat += " \[Track\]
    " - - for(var/obj/mecha/M in seen) - if(M.name in names) - names[M.name]++ - dat += "[M.name] ([names[M.name]])" - else - names[M.name] = 1 - dat += "[M.name]" - dat += " \[Track\]
    " - - - for(var/mob/living/M in seen) - if(M.name in names) - names[M.name]++ - dat += "[M.name] ([names[M.name]])" - else - names[M.name] = 1 - dat += "[M.name]" - if(M.buckled && !M.lying) - dat += " (Sitting)" - if(M.lying) - dat += " (Laying down)" - dat += " \[Track\]
    " - if(length(dat) == 0) - dat += "No motion detected." - return dat - else - return "Camera Offline
    " - -/obj/item/camera_bug/Topic(var/href,var/list/href_list) - if(usr != loc) - usr.unset_machine() - usr << browse(null, "window=camerabug") - return - usr.set_machine(src) - if("mode" in href_list) - track_mode = text2num(href_list["mode"]) - if("monitor" in href_list) - var/obj/machinery/camera/C = locate(href_list["monitor"]) - if(C) - track_mode = BUGMODE_MONITOR - current = C - usr.reset_perspective(null) - interact() - if("track" in href_list) - var/atom/A = locate(href_list["track"]) - if(A) - tracking = A - tracked_name = A.name - last_found = current.c_tag - last_seen = world.time - track_mode = BUGMODE_TRACK - if("emp" in href_list) - var/obj/machinery/camera/C = locate(href_list["emp"]) - if(istype(C) && C.bug == src) - C.emp_act(1) - C.bug = null - bugged_cameras -= C.c_tag - interact() - return - if("close" in href_list) - usr.reset_perspective(null) - usr.unset_machine() - current = null - return // I do not <- I do not remember what I was going to write in this comment -Sayu, sometime later - if("view" in href_list) - var/obj/machinery/camera/C = locate(href_list["view"]) - if(istype(C)) - if(!C.can_use()) - to_chat(usr, "Something's wrong with that camera. You can't get a feed.") - return - var/turf/T = get_turf(loc) - if(!T || C.z != T.z) - to_chat(usr, "You can't get a signal.") - return - current = C - spawn(6) - if(src.check_eye(usr)) - usr.reset_perspective(C) - interact() - else - usr.unset_machine() - usr << browse(null, "window=camerabug") - return - else - usr.unset_machine() - usr.reset_perspective(null) - - interact() - -/obj/item/camera_bug/process() - if(track_mode == BUGMODE_LIST || (world.time < (last_tracked + refresh_interval))) - return - last_tracked = world.time - if(track_mode == BUGMODE_TRACK ) // search for user - // Note that it will be tricked if your name appears to change. - // This is not optimal but it is better than tracking you relentlessly despite everything. - if(!tracking) - src.updateSelfDialog() - return - - if(tracking.name != tracked_name) // Hiding their identity, tricksy - var/mob/M = tracking - if(istype(M)) - if(!(tracked_name == "Unknown" && findtext(tracking.name,"Unknown"))) // we saw then disguised before - if(!(tracked_name == M.real_name && findtext(tracking.name,M.real_name))) // or they're still ID'd - src.updateSelfDialog()//But if it's neither of those cases - return // you won't find em on the cameras - else - src.updateSelfDialog() - return - - var/list/tracking_cams = list() - var/list/b_cams = get_cameras() - for(var/entry in b_cams) - tracking_cams += b_cams[entry] - var/list/target_region = view(tracking) - - for(var/obj/machinery/camera/C in (target_region & tracking_cams)) - if(!can_see(C,tracking)) // target may have xray, that doesn't make them visible to cameras - continue - if(C.can_use()) - last_found = C.c_tag - last_seen = world.time - break - src.updateSelfDialog() - - -#undef BUGMODE_LIST -#undef BUGMODE_MONITOR -#undef BUGMODE_TRACK +/obj/item/camera_bug/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_inventory_state) + integrated_console.tgui_interact(user, ui_key, ui, force_open, master_ui, state) diff --git a/code/game/objects/items/devices/floor_painter.dm b/code/game/objects/items/devices/floor_painter.dm index 889138c9c91..ae5a75d5622 100644 --- a/code/game/objects/items/devices/floor_painter.dm +++ b/code/game/objects/items/devices/floor_painter.dm @@ -4,7 +4,8 @@ name = "floor painter" icon = 'icons/obj/device.dmi' icon_state = "floor_painter" - item_state = "electronic" + item_state = "floor_painter" + usesound = 'sound/effects/spray2.ogg' var/floor_icon var/floor_state = "floor" @@ -31,10 +32,16 @@ return var/turf/simulated/floor/plasteel/F = A + + if(F.icon_state == floor_state && F.dir == floor_dir) + to_chat(user, "This is already painted [floor_state] [dir2text(floor_dir)]!") + return + if(!istype(F)) to_chat(user, "\The [src] can only be used on station flooring.") return + playsound(loc, usesound, 30, TRUE) F.icon_state = floor_state F.icon_regular_floor = floor_state F.dir = floor_dir diff --git a/code/game/objects/items/devices/pipe_painter.dm b/code/game/objects/items/devices/pipe_painter.dm index 842a96c2af2..c386e64a19d 100644 --- a/code/game/objects/items/devices/pipe_painter.dm +++ b/code/game/objects/items/devices/pipe_painter.dm @@ -1,8 +1,9 @@ /obj/item/pipe_painter name = "pipe painter" - icon = 'icons/obj/bureaucracy.dmi' - icon_state = "labeler1" - item_state = "flight" + icon = 'icons/obj/device.dmi' + icon_state = "pipe_painter" + item_state = "pipe_painter" + usesound = 'sound/effects/spray2.ogg' var/list/modes var/mode @@ -18,13 +19,19 @@ return var/obj/machinery/atmospherics/pipe/P = A + if(P.pipe_color == "[GLOB.pipe_colors[mode]]") + to_chat(user, "This pipe is aready painted [mode]!") + return + var/turf/T = P.loc if(P.level < 2 && T.level==1 && isturf(T) && T.intact) to_chat(user, "You must remove the plating first.") return + playsound(loc, usesound, 30, TRUE) P.change_color(GLOB.pipe_colors[mode]) + /obj/item/pipe_painter/attack_self(mob/user as mob) mode = input("Which colour do you want to use?", "Pipe Painter", mode) in modes diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index 1eba4e54056..261b6ba109b 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -62,6 +62,8 @@ to_chat(user, "You attach the [A] to the valve controls and secure it.") A.holder = src A.toggle_secure() //this calls update_icon(), which calls update_icon() on the holder (i.e. the bomb). + if(istype(attached_device, /obj/item/assembly/prox_sensor)) + AddComponent(/datum/component/proximity_monitor) investigate_log("[key_name(user)] attached a [A] to a transfer valve.", INVESTIGATE_BOMB) add_attack_logs(user, src, "attached [A] to a transfer valve", ATKLOG_FEW) @@ -137,6 +139,7 @@ attached_device.forceMove(get_turf(src)) attached_device.holder = null attached_device = null + qdel(GetComponent(/datum/component/proximity_monitor)) update_icon() else . = FALSE diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 4fef7b9f6d5..6b70ac015ca 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -54,7 +54,6 @@ GLOBAL_LIST_INIT(metal_recipes, list( new /datum/stack_recipe/rods("metal rod", /obj/item/stack/rods, 1, 2, 50), null, new /datum/stack_recipe("computer frame", /obj/structure/computerframe, 5, time = 25, one_per_turf = 1, on_floor = 1), - new /datum/stack_recipe("modular console", /obj/machinery/modular_computer/console/buildable/, 10, time = 25, one_per_turf = 1, on_floor = 1), new /datum/stack_recipe("wall girders", /obj/structure/girder, 2, time = 50, one_per_turf = 1, on_floor = 1), new /datum/stack_recipe("machine frame", /obj/machinery/constructable_frame/machine_frame, 5, time = 25, one_per_turf = 1, on_floor = 1), new /datum/stack_recipe("turret frame", /obj/machinery/porta_turret_construct, 5, time = 25, one_per_turf = 1, on_floor = 1), diff --git a/code/game/objects/items/weapons/caution.dm b/code/game/objects/items/weapons/caution.dm index b1b573f77ad..b84f8eba6f4 100644 --- a/code/game/objects/items/weapons/caution.dm +++ b/code/game/objects/items/weapons/caution.dm @@ -15,6 +15,10 @@ var/armed = 0 var/timepassed = 0 +/obj/item/caution/proximity_sign/ComponentInitialize() + . = ..() + AddComponent(/datum/component/proximity_monitor) + /obj/item/caution/proximity_sign/attack_self(mob/user as mob) if(ishuman(user)) var/mob/living/carbon/human/H = user @@ -40,7 +44,7 @@ armed = 1 timing = 0 -/obj/item/caution/proximity_sign/HasProximity(atom/movable/AM as mob|obj) +/obj/item/caution/proximity_sign/HasProximity(atom/movable/AM) if(armed) if(istype(AM, /mob/living/carbon) && !istype(AM, /mob/living/carbon/brain)) var/mob/living/carbon/C = AM diff --git a/code/game/objects/items/weapons/chrono_eraser.dm b/code/game/objects/items/weapons/chrono_eraser.dm index 1dc0b22abdf..ef158e3758c 100644 --- a/code/game/objects/items/weapons/chrono_eraser.dm +++ b/code/game/objects/items/weapons/chrono_eraser.dm @@ -141,6 +141,8 @@ /obj/item/ammo_casing/energy/chrono_beam name = "eradication beam" projectile_type = /obj/item/projectile/energy/chrono_beam + muzzle_flash_effect = /obj/effect/temp_visual/target_angled/muzzle_flash/energy + muzzle_flash_color = null icon_state = "chronobolt" e_cost = 0 diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm index ee98d309876..fb4c86c59d1 100644 --- a/code/game/objects/items/weapons/defib.dm +++ b/code/game/objects/items/weapons/defib.dm @@ -141,6 +141,8 @@ if(paddles_on_defib) //Detach the paddles into the user's hands + if(usr.incapacitated()) return + if(!usr.put_in_hands(paddles)) to_chat(user, "You need a free hand to hold the paddles!") update_icon() diff --git a/code/game/objects/items/weapons/extinguisher.dm b/code/game/objects/items/weapons/extinguisher.dm index f4ab41fab7b..1b1352c372f 100644 --- a/code/game/objects/items/weapons/extinguisher.dm +++ b/code/game/objects/items/weapons/extinguisher.dm @@ -106,6 +106,8 @@ src.last_use = world.time + if(reagents.chem_temp > 300 || reagents.chem_temp < 280) + add_attack_logs(user, target, "Sprayed with superheated or cooled fire extinguisher at Temperature [reagents.chem_temp]K") playsound(src.loc, 'sound/effects/extinguish.ogg', 75, 1, -3) var/direction = get_dir(src,target) diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm index 3aa658b0812..f756929e5ab 100644 --- a/code/game/objects/items/weapons/grenades/chem_grenade.dm +++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm @@ -190,6 +190,8 @@ user.drop_item() nadeassembly = A + if(nadeassembly.has_prox_sensors()) + AddComponent(/datum/component/proximity_monitor) A.master = src A.loc = src assemblyattacher = user.ckey @@ -219,6 +221,7 @@ nadeassembly.loc = get_turf(src) nadeassembly.master = null nadeassembly = null + qdel(GetComponent(/datum/component/proximity_monitor)) if(beakers.len) for(var/obj/O in beakers) O.loc = get_turf(src) @@ -304,6 +307,8 @@ /obj/item/grenade/chem_grenade/proc/CreateDefaultTrigger(var/typekey) if(ispath(typekey,/obj/item/assembly)) nadeassembly = new(src) + if(nadeassembly.has_prox_sensors()) + AddComponent(/datum/component/proximity_monitor) nadeassembly.a_left = new /obj/item/assembly/igniter(nadeassembly) nadeassembly.a_left.holder = nadeassembly nadeassembly.a_left.secured = 1 diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm index 0be9178967c..ec7cb14f9ed 100644 --- a/code/game/objects/items/weapons/storage/belt.dm +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -258,6 +258,14 @@ new /obj/item/grenade/flashbang(src) update_icon() +/obj/item/storage/belt/security/webbing + name = "security webbing" + desc = "Unique and versatile chest rig, can hold security gear." + icon_state = "securitywebbing" + item_state = "securitywebbing" + storage_slots = 6 + use_item_overlays = FALSE + /obj/item/storage/belt/soulstone name = "soul stone belt" desc = "Designed for ease of access to the shards during a fight, as to not let a single enemy spirit slip away" diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm index 0e2844579e7..000cb96d720 100644 --- a/code/game/objects/items/weapons/storage/boxes.dm +++ b/code/game/objects/items/weapons/storage/boxes.dm @@ -525,7 +525,7 @@ desc = "Instructions:Heat in microwave. Product will cool if not eaten within seven minutes." icon_state = "donk_kit" -/obj/item/storage/box/dockpockets/New() +/obj/item/storage/box/donkpockets/New() ..() new /obj/item/reagent_containers/food/snacks/donkpocket(src) new /obj/item/reagent_containers/food/snacks/donkpocket(src) diff --git a/code/game/objects/items/weapons/vending_items.dm b/code/game/objects/items/weapons/vending_items.dm index 258771870d8..e7743f961f1 100644 --- a/code/game/objects/items/weapons/vending_items.dm +++ b/code/game/objects/items/weapons/vending_items.dm @@ -126,10 +126,6 @@ machine_name = "NanoMed" icon_state = "refill_medical" -/obj/item/vending_refill/modularpc - machine_name = "Deluxe Silicate Selections" - icon_state = "refill_engi" - /obj/item/vending_refill/hydronutrients machine_name = "NutriMax" icon_state = "refill_plant" diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm index 033787cce75..4661ff125cc 100644 --- a/code/game/objects/structures/aliens.dm +++ b/code/game/objects/structures/aliens.dm @@ -280,12 +280,14 @@ /obj/structure/alien/egg/proc/Grow() icon_state = "egg" status = GROWN + AddComponent(/datum/component/proximity_monitor) /obj/structure/alien/egg/proc/Burst(kill = TRUE) //drops and kills the hugger if any is remaining if(status == GROWN || status == GROWING) icon_state = "egg_hatched" flick("egg_opening", src) status = BURSTING + qdel(GetComponent(/datum/component/proximity_monitor)) spawn(15) status = BURST var/obj/item/clothing/mask/facehugger/child = GetFacehugger() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index be004a82912..ac5be74f96d 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -48,7 +48,7 @@ /obj/structure/closet/secure_closet/hop/New() ..() - new /obj/item/clothing/glasses/sunglasses(src) + new /obj/item/clothing/glasses/hud/skills/sunglasses(src) new /obj/item/clothing/head/hopcap(src) new /obj/item/cartridge/hop(src) new /obj/item/radio/headset/heads/hop(src) @@ -251,7 +251,8 @@ new /obj/item/melee/baton/loaded(src) new /obj/item/clothing/glasses/sunglasses(src) new /obj/item/clothing/glasses/hud/security/sunglasses/read_only(src) - new /obj/item/clothing/glasses/hud/health/sunglasses + new /obj/item/clothing/glasses/hud/health/sunglasses(src) + new /obj/item/clothing/glasses/hud/skills/sunglasses(src) new /obj/item/clothing/head/beret/centcom/officer(src) new /obj/item/clothing/head/beret/centcom/officer/navy(src) new /obj/item/clothing/suit/armor/vest/blueshield(src) @@ -279,7 +280,7 @@ new /obj/item/storage/briefcase(src) new /obj/item/paicard(src) new /obj/item/flash(src) - new /obj/item/clothing/glasses/sunglasses(src) + new /obj/item/clothing/glasses/hud/skills/sunglasses(src) new /obj/item/clothing/gloves/color/white(src) new /obj/item/clothing/shoes/centcom(src) new /obj/item/clothing/under/lawyer/oldman(src) diff --git a/code/game/objects/structures/stool_bed_chair_nest/bed.dm b/code/game/objects/structures/stool_bed_chair_nest/bed.dm index 9d0d4568e73..d91caa4244f 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm @@ -117,7 +117,7 @@ /obj/structure/bed/roller/MouseDrop(over_object, src_location, over_location) ..() if(over_object == usr && Adjacent(usr) && (in_range(src, usr) || usr.contents.Find(src))) - if(!ishuman(usr)) + if(!ishuman(usr) || usr.incapacitated()) return if(has_buckled_mobs()) return 0 diff --git a/code/game/objects/structures/tank_dispenser.dm b/code/game/objects/structures/tank_dispenser.dm index 692d15d79ec..b6796755b79 100644 --- a/code/game/objects/structures/tank_dispenser.dm +++ b/code/game/objects/structures/tank_dispenser.dm @@ -57,24 +57,37 @@ if(..()) return 1 add_fingerprint(user) - ui_interact(user) + tgui_interact(user) /obj/structure/dispenser/attack_ghost(mob/user) - ui_interact(user) + tgui_interact(user) -/obj/structure/dispenser/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1, master_ui = null, datum/topic_state/state = GLOB.default_state) - user.set_machine(src) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open) +/obj/structure/dispenser/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, "tank_dispenser.tmpl", name, 275, 100, state = state) + ui = new(user, src, ui_key, "TankDispenser", name, 275, 100, master_ui, state) ui.open() -/obj/structure/dispenser/ui_data(user) +/obj/structure/dispenser/tgui_data(user) var/list/data = list() data["o_tanks"] = LAZYLEN(stored_oxygen_tanks) data["p_tanks"] = LAZYLEN(stored_plasma_tanks) return data +/obj/structure/dispenser/tgui_act(action, list/params) + if(..()) + return + + switch(action) + if("oxygen") + try_remove_tank(usr, stored_oxygen_tanks) + + if("plasma") + try_remove_tank(usr, stored_plasma_tanks) + + add_fingerprint(usr) + return TRUE + /obj/structure/dispenser/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/tank/oxygen) || istype(I, /obj/item/tank/air) || istype(I, /obj/item/tank/anesthetic)) try_insert_tank(user, stored_oxygen_tanks, I) @@ -94,28 +107,6 @@ return return ..() -/obj/structure/dispenser/Topic(href, href_list) - if(..()) - return TRUE - - if(Adjacent(usr)) - usr.set_machine(src) - - // The oxygen tank button - if(href_list["oxygen"]) - try_remove_tank(usr, stored_oxygen_tanks) - - // The plasma tank button - if(href_list["plasma"]) - try_remove_tank(usr, stored_plasma_tanks) - - add_fingerprint(usr) - updateUsrDialog() - SSnanoui.try_update_ui(usr, src) - else - SSnanoui.close_user_uis(usr,src) - return TRUE - /// Called when the user clicks on the oxygen or plasma tank UI buttons, and tries to withdraw a tank. /obj/structure/dispenser/proc/try_remove_tank(mob/living/user, list/tank_list) if(!LAZYLEN(tank_list)) @@ -144,7 +135,7 @@ tank_list.Add(T) update_icon() to_chat(user, "You put [T] in [src].") - SSnanoui.try_update_ui(user, src) + SStgui.update_uis(src) /obj/structure/tank_dispenser/deconstruct(disassembled = TRUE) if(!(flags & NODECONSTRUCT)) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 2f90e4d7cc4..8170f9fbe5f 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -166,13 +166,6 @@ if(!O.lastarea) O.lastarea = get_area(O.loc) - var/loopsanity = 100 - for(var/atom/A in range(1)) - if(loopsanity == 0) - break - loopsanity-- - A.HasProximity(M) - // If an opaque movable atom moves around we need to potentially update visibility. if(M.opacity) has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case. diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 07dd4975ddb..45971e6993e 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -85,7 +85,7 @@ GLOBAL_VAR_INIT(nologevent, 0) body += "VV - " body += "[ADMIN_TP(M,"TP")] - " if(M.client) - body += "PM - " + body += "PM - " body += "[ADMIN_SM(M,"SM")] - " if(ishuman(M) && M.mind) body += "HM -" diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index b3957a86b44..0802e6e8b1a 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -420,13 +420,8 @@ GLOBAL_LIST_INIT(admin_verbs_ticket, list( feedback_add_details("admin_verb","S") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! return -/client/proc/findStealthKey(txt) - if(txt) - for(var/P in GLOB.stealthminID) - if(GLOB.stealthminID[P] == txt) - return P - txt = GLOB.stealthminID[ckey] - return txt +/client/proc/getStealthKey() + return GLOB.stealthminID[ckey] /client/proc/createStealthKey() var/num = (rand(0,1000)) diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index c2248261baa..700e8381695 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -65,7 +65,7 @@ } - function expand(id,job,name,real_name,image,key,ip,antagonist,mobUID,clientUID,eyeUID){ + function expand(id,job,name,real_name,image,key,ip,antagonist,mobUID,client_ckey,eyeUID){ clearAll(); @@ -83,7 +83,7 @@ body += "N - " body += "VV - " body += "TP - " - body += "PM - " + body += "PM - " body += "SM - " body += "FLW" if(eyeUID) @@ -297,7 +297,7 @@ var/mob/living/silicon/ai/A = M if(A.client && A.eyeobj) // No point following clientless AI eyes M_eyeUID = "[A.eyeobj.UID()]" - var/clientUID = M.client ? M.client.UID() : null + var/client_ckey = M.client ? M.client.ckey : null //output for each mob dat += {" @@ -305,7 +305,7 @@ - [close ? "" : ""]"} + [close ? "" : ""]"} /datum/admins/proc/check_antagonists() if(!check_rights(R_ADMIN)) @@ -418,7 +418,7 @@ var/mob/M = blob.current if(M) dat += "" - dat += "" + dat += "" else dat += "" dat += "
    [entry][functions]
    [M_name] - [M_rname] - [M_key] ([M_job]) @@ -342,7 +342,7 @@ dname = M return {"
    [dname][caption][logout_status][istype(A, /area/security/permabrig) ? " (PERMA) " : ""][M.stat == 2 ? " (DEAD)" : ""]PM [ADMIN_FLW(M, "FLW")]
    PM [ADMIN_FLW(M, "FLW")]
    [ADMIN_PP(M,"[M.real_name]")][M.client ? "" : " (ghost)"][M.stat == 2 ? " (DEAD)" : ""]PMPM
    Blob not found!
    " diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index ce5f06053eb..48c407e6866 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -64,9 +64,7 @@ var/client/C if(istext(whom)) - if(cmptext(copytext(whom,1,2),"@")) - whom = findStealthKey(whom) - C = GLOB.directory[whom] + C = get_client_by_ckey(whom) else if(istype(whom,/client)) C = whom diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm index 514fc2368e1..fa7ffa1ece8 100644 --- a/code/modules/admin/verbs/randomverbs.dm +++ b/code/modules/admin/verbs/randomverbs.dm @@ -874,6 +874,9 @@ Traitors and the like can also be revived with the previous role mostly intact. if(!check_rights(R_ADMIN)) return + if(alert(usr, "Do you want to [SSshuttle.emergencyNoEscape ? "ALLOW" : "DENY"] shuttle calls?", "Toggle Deny Shuttle", "Yes", "No") != "Yes") + return + if(SSshuttle) SSshuttle.emergencyNoEscape = !SSshuttle.emergencyNoEscape diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm index 33755fc54e8..855c113a71a 100644 --- a/code/modules/assembly/bomb.dm +++ b/code/modules/assembly/bomb.dm @@ -12,6 +12,10 @@ var/obj/item/tank/bombtank = null //the second part of the bomb is a plasma tank origin_tech = "materials=1;engineering=1" +/obj/item/onetankbomb/ComponentInitialize() + . = ..() + AddComponent(/datum/component/proximity_monitor) + /obj/item/onetankbomb/examine(mob/user) . = ..() . += bombtank.examine(user) diff --git a/code/modules/assembly/holder.dm b/code/modules/assembly/holder.dm index 6a6cd7e8d8e..87fefe4fc65 100644 --- a/code/modules/assembly/holder.dm +++ b/code/modules/assembly/holder.dm @@ -41,19 +41,25 @@ if(!A1.remove_item_from_storage(src)) if(user) user.remove_from_mob(A1) - A1.loc = src + A1.forceMove(src) if(!A2.remove_item_from_storage(src)) if(user) user.remove_from_mob(A2) - A2.loc = src + A2.forceMove(src) A1.holder = src A2.holder = src a_left = A1 a_right = A2 + if(has_prox_sensors()) + AddComponent(/datum/component/proximity_monitor) name = "[A1.name]-[A2.name] assembly" update_icon() return TRUE +/obj/item/assembly_holder/proc/has_prox_sensors() + if(istype(a_left, /obj/item/assembly/prox_sensor) || istype(a_right, /obj/item/assembly/prox_sensor)) + return TRUE + return FALSE /obj/item/assembly_holder/update_icon() overlays.Cut() diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm index caefabcb1f8..ced9fbca932 100644 --- a/code/modules/assembly/proximity.dm +++ b/code/modules/assembly/proximity.dm @@ -13,6 +13,10 @@ var/timing = 0 var/time = 10 +/obj/item/assembly/prox_sensor/ComponentInitialize() + . = ..() + AddComponent(/datum/component/proximity_monitor) + /obj/item/assembly/prox_sensor/describe() if(timing) return "The proximity sensor is arming." diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index ea099ea53b3..b5f5c51ba59 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -108,13 +108,9 @@ //Admin PM if(href_list["priv_msg"]) - var/client/C = locate(href_list["priv_msg"]) + var/ckey_txt = href_list["priv_msg"] - if(!C) // Might be a stealthmin ID, so pass it in straight - C = href_list["priv_msg"] - else if(C.UID() != href_list["priv_msg"]) - C = null // 404 client not found. Let cmd_admin_pm handle the error - cmd_admin_pm(C, null, href_list["type"]) + cmd_admin_pm(ckey_txt, null, href_list["type"]) return if(href_list["irc_msg"]) diff --git a/code/modules/client/preference/loadout/loadout_general.dm b/code/modules/client/preference/loadout/loadout_general.dm index 8c08063ad7e..6c18fbda0a7 100644 --- a/code/modules/client/preference/loadout/loadout_general.dm +++ b/code/modules/client/preference/loadout/loadout_general.dm @@ -18,22 +18,68 @@ display_name = "a pack of Midoris" path = /obj/item/storage/fancy/cigarettes/cigpack_midori +/datum/gear/smokingpipe + display_name = "smoking pipe" + path = /obj/item/clothing/mask/cigarette/pipe + cost = 2 + /datum/gear/lighter display_name = "a cheap lighter" path = /obj/item/lighter +/datum/gear/matches + display_name = "a box of matches" + path = /obj/item/storage/box/matches + +/datum/gear/candlebox + display_name = "a box candles" + description = "For setting the mood or for occult rituals." + path = /obj/item/storage/fancy/candle_box + /datum/gear/rock display_name = "a pet rock" path = /obj/item/toy/pet_rock +/datum/gear/camera + display_name = "a camera" + path = /obj/item/camera + +/datum/gear/redfoxplushie + display_name = "a red fox plushie" + path = /obj/item/toy/plushie/red_fox + +/datum/gear/blackcatplushie + display_name = "a black cat plushie" + path = /obj/item/toy/plushie/black_cat + +/datum/gear/voxplushie + display_name = "a vox plushie" + path = /obj/item/toy/plushie/voxplushie + +/datum/gear/lizardplushie + display_name = "a lizard plushie" + path = /obj/item/toy/plushie/lizardplushie + +/datum/gear/deerplushie + display_name = "a deer plushie" + path = /obj/item/toy/plushie/deer + +/datum/gear/carpplushie + display_name = "a carp plushie" + path = /obj/item/toy/carpplushie + /datum/gear/sechud display_name = "a classic security HUD" path = /obj/item/clothing/glasses/hud/security allowed_roles = list("Head of Security", "Warden", "Security Officer", "Security Pod Pilot", "Internal Affairs Agent","Magistrate") -/datum/gear/matches - display_name = "a box of matches" - path = /obj/item/storage/box/matches +/datum/gear/cryaonbox + display_name = "a box of crayons" + path = /obj/item/storage/fancy/crayons + +/datum/gear/cane + display_name = "a walking cane" + path = /obj/item/cane /datum/gear/cards display_name = "a deck of standard cards" @@ -51,6 +97,10 @@ display_name = "a pair of headphones" path = /obj/item/clothing/ears/headphones +/datum/gear/fannypack + display_name = "a fannypack" + path = /obj/item/storage/belt/fannypack + /datum/gear/blackbandana display_name = "bandana, black" path = /obj/item/clothing/mask/bandana/black @@ -105,6 +155,11 @@ cost = 2 sort_category = "Mugs" +/datum/gear/mug/flask + display_name = "flask" + description = "A flask for drink transportation. You'll need to supply your own beverage though." + path = /obj/item/reagent_containers/food/drinks/flask/barflask + /datum/gear/mug/department subtype_path = /datum/gear/mug/department sort_category = "Mugs" diff --git a/code/modules/client/preference/loadout/loadout_gloves.dm b/code/modules/client/preference/loadout/loadout_gloves.dm index 879cb840506..fece3456e56 100644 --- a/code/modules/client/preference/loadout/loadout_gloves.dm +++ b/code/modules/client/preference/loadout/loadout_gloves.dm @@ -6,3 +6,11 @@ /datum/gear/gloves/fingerless display_name = "Fingerless Gloves" path = /obj/item/clothing/gloves/fingerless + +/datum/gear/gloves/silverring + display_name = "Silver ring" + path = /obj/item/clothing/gloves/ring/silver + +/datum/gear/gloves/goldring + display_name = "Gold ring" + path = /obj/item/clothing/gloves/ring/gold diff --git a/code/modules/client/preference/loadout/loadout_hat.dm b/code/modules/client/preference/loadout/loadout_hat.dm index 7e277677f94..fccc0eadc86 100644 --- a/code/modules/client/preference/loadout/loadout_hat.dm +++ b/code/modules/client/preference/loadout/loadout_hat.dm @@ -26,10 +26,22 @@ display_name = "flat cap" path = /obj/item/clothing/head/flatcap +/datum/gear/hat/witch + display_name = "witch hat" + path = /obj/item/clothing/head/wizard/marisa/fake + +/datum/gear/hat/piratecaphat + display_name = "pirate captian hat" + path = /obj/item/clothing/head/pirate + /datum/gear/hat/fez display_name = "fez" path = /obj/item/clothing/head/fez +/datum/gear/hat/rasta + display_name = "rasta hat" + path = /obj/item/clothing/head/beanie/rasta + /datum/gear/hat/bfedora display_name = "fedora, black" path = /obj/item/clothing/head/fedora diff --git a/code/modules/client/preference/loadout/loadout_shoes.dm b/code/modules/client/preference/loadout/loadout_shoes.dm index ab000b209ac..dbc7f970a33 100644 --- a/code/modules/client/preference/loadout/loadout_shoes.dm +++ b/code/modules/client/preference/loadout/loadout_shoes.dm @@ -17,12 +17,10 @@ /datum/gear/shoes/fancysandals display_name = "sandals, fancy" - cost = 2 path = /obj/item/clothing/shoes/sandal/fancy /datum/gear/shoes/dressshoes display_name = "dress shoes" - cost = 2 path = /obj/item/clothing/shoes/centcom /datum/gear/shoes/cowboyboots @@ -41,6 +39,14 @@ display_name = "cowboy boots, pink" path = /obj/item/clothing/shoes/cowboy/pink +/datum/gear/shoes/jackboots + display_name = "jackboots" + path = /obj/item/clothing/shoes/jackboots + +/datum/gear/shoes/jacksandals + display_name = "jacksandals" + path = /obj/item/clothing/shoes/jackboots/jacksandals + /datum/gear/shoes/laceup display_name = "laceup shoes" path = /obj/item/clothing/shoes/laceup diff --git a/code/modules/client/preference/loadout/loadout_suit.dm b/code/modules/client/preference/loadout/loadout_suit.dm index 57e7ea63414..113f01f2144 100644 --- a/code/modules/client/preference/loadout/loadout_suit.dm +++ b/code/modules/client/preference/loadout/loadout_suit.dm @@ -208,3 +208,11 @@ display_name = "mantle, research director" path = /obj/item/clothing/suit/mantle/labcoat allowed_roles = list("Research Director") + +//Robes! + +/datum/gear/suit/witch + display_name = "witch robes" + path = /obj/item/clothing/suit/wizrobe/marisa/fake + + diff --git a/code/modules/client/preference/loadout/loadout_uniform.dm b/code/modules/client/preference/loadout/loadout_uniform.dm index eb5264a0975..ca6ddb96ed4 100644 --- a/code/modules/client/preference/loadout/loadout_uniform.dm +++ b/code/modules/client/preference/loadout/loadout_uniform.dm @@ -4,6 +4,103 @@ slot = slot_w_uniform sort_category = "Uniforms and Casual Dress" +/datum/gear/uniform/suits + subtype_path = /datum/gear/uniform/suit + +//there's a lot more colors than I thought there were @_@ + +/datum/gear/uniform/suit/jumpsuitblack + display_name = "jumpsuit, black" + path = /obj/item/clothing/under/color/black + +/datum/gear/uniform/suit/jumpsuitblue + display_name = "jumpsuit, blue" + path = /obj/item/clothing/under/color/blue + +/datum/gear/uniform/suit/jumpsuitgreen + display_name = "jumpsuit, green" + path = /obj/item/clothing/under/color/green + +/datum/gear/uniform/suit/jumpsuitgrey + display_name = "jumpsuit, grey" + path = /obj/item/clothing/under/color/grey + +/datum/gear/uniform/suit/jumpsuitorange + display_name = "jumpsuit, orange" + path = /obj/item/clothing/under/color/orange + +/datum/gear/uniform/suit/jumpsuitpink + display_name = "jumpsuit, pink" + path = /obj/item/clothing/under/color/pink + +/datum/gear/uniform/suit/jumpsuitred + display_name = "jumpsuit, red" + path = /obj/item/clothing/under/color/red + +/datum/gear/uniform/suit/jumpsuitwhite + display_name = "jumpsuit, white" + path = /obj/item/clothing/under/color/white + +/datum/gear/uniform/suit/jumpsuityellow + display_name = "jumpsuit, yellow" + path = /obj/item/clothing/under/color/yellow + +/datum/gear/uniform/suit/jumpsuitlightblue + display_name = "jumpsuit, lightblue" + path = /obj/item/clothing/under/color/lightblue + +/datum/gear/uniform/suit/jumpsuitaqua + display_name = "jumpsuit, aqua" + path = /obj/item/clothing/under/color/aqua + +/datum/gear/uniform/suit/jumpsuitpurple + display_name = "jumpsuit, purple" + path = /obj/item/clothing/under/color/purple + +/datum/gear/uniform/suit/jumpsuitlightpurple + display_name = "jumpsuit, lightpurple" + path = /obj/item/clothing/under/color/lightpurple + +/datum/gear/uniform/suit/jumpsuitlightgreen + display_name = "jumpsuit, lightgreen" + path = /obj/item/clothing/under/color/lightgreen + +/datum/gear/uniform/suit/jumpsuitlightblue + display_name = "jumpsuit, lightblue" + path = /obj/item/clothing/under/color/lightblue + +/datum/gear/uniform/suit/jumpsuitlightbrown + display_name = "jumpsuit, lightbrown" + path = /obj/item/clothing/under/color/lightbrown + +/datum/gear/uniform/suit/jumpsuitbrown + display_name = "jumpsuit, brown" + path = /obj/item/clothing/under/color/brown + +/datum/gear/uniform/suit/jumpsuityellowgreen + display_name = "jumpsuit, yellowgreen" + path = /obj/item/clothing/under/color/yellowgreen + +/datum/gear/uniform/suit/jumpsuitdarkblue + display_name = "jumpsuit, darkblue" + path = /obj/item/clothing/under/color/darkblue + +/datum/gear/uniform/suit/jumpsuitlightred + display_name = "jumpsuit, lightred" + path = /obj/item/clothing/under/color/lightred + +/datum/gear/uniform/suit/jumpsuitdarkred + display_name = "jumpsuit, darkred" + path = /obj/item/clothing/under/color/darkred + +/datum/gear/uniform/suit/soviet + display_name = "USSP uniform" + path = /obj/item/clothing/under/soviet + +/datum/gear/uniform/suit/kilt + display_name = "a kilt" + path = /obj/item/clothing/under/kilt + /datum/gear/uniform/skirt subtype_path = /datum/gear/uniform/skirt diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm index 4d2255a09ab..67e001987d2 100644 --- a/code/modules/clothing/glasses/hud.dm +++ b/code/modules/clothing/glasses/hud.dm @@ -196,3 +196,17 @@ /obj/item/clothing/glasses/hud/health/tajblind/attack_self() toggle_veil() + +/obj/item/clothing/glasses/hud/skills + name = "Skills HUD" + desc = "A heads-up display capable of showing the employment history records of NT crew members." + icon_state = "material" + item_state = "glasses" + +/obj/item/clothing/glasses/hud/skills/sunglasses + name = "Skills HUD Sunglasses" + desc = "Sunglasses with a build-in skills HUD, showing the employment history of nearby NT crew members." + see_in_dark = 1 // None of these three can be converted to booleans. Do not try it. + flash_protect = 1 + tint = 1 + prescription_upgradable = TRUE diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm index 5cc891b56af..15895046dbc 100644 --- a/code/modules/clothing/masks/miscellaneous.dm +++ b/code/modules/clothing/masks/miscellaneous.dm @@ -146,6 +146,7 @@ trigger.forceMove(src) trigger.master = src trigger.holder = src + AddComponent(/datum/component/proximity_monitor) to_chat(user, "You attach the [W] to [src].") return TRUE else if(istype(W, /obj/item/assembly)) @@ -165,6 +166,7 @@ trigger.master = null trigger.holder = null trigger = null + qdel(GetComponent(/datum/component/proximity_monitor)) /obj/item/clothing/mask/muzzle/safety/shock/proc/can_shock(obj/item/clothing/C) if(istype(C)) @@ -186,7 +188,7 @@ M.Jitter(20) return -/obj/item/clothing/mask/muzzle/safety/shock/HasProximity(atom/movable/AM as mob|obj) +/obj/item/clothing/mask/muzzle/safety/shock/HasProximity(atom/movable/AM) if(trigger) trigger.HasProximity(AM) diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm index a7ee48faec4..abe67fb68e6 100644 --- a/code/modules/clothing/shoes/magboots.dm +++ b/code/modules/clothing/shoes/magboots.dm @@ -8,11 +8,19 @@ var/slowdown_active = 2 var/slowdown_passive = SHOES_SLOWDOWN var/magpulse_name = "mag-pulse traction system" + var/gustprotection = FALSE //this is for unsafe_unwrenching protection actions_types = list(/datum/action/item_action/toggle) strip_delay = 70 put_on_delay = 70 resistance_flags = FIRE_PROOF +/obj/item/clothing/shoes/magboots/atmos + desc = "Magnetic boots, made to withstand gusts of space wind over 500kmph." + name = "atmospheric magboots" + icon_state = "atmosmagboots0" + magboot_state = "atmosmagboots" + gustprotection = TRUE + /obj/item/clothing/shoes/magboots/attack_self(mob/user) if(magpulse) flags &= ~NOSLIP @@ -42,6 +50,7 @@ name = "advanced magboots" icon_state = "advmag0" magboot_state = "advmag" + gustprotection = TRUE slowdown_active = SHOES_SLOWDOWN origin_tech = null resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF diff --git a/code/modules/detective_work/scanner.dm b/code/modules/detective_work/scanner.dm index dea08c602f9..d043c3e1263 100644 --- a/code/modules/detective_work/scanner.dm +++ b/code/modules/detective_work/scanner.dm @@ -12,17 +12,17 @@ flags = CONDUCT | NOBLUDGEON slot_flags = SLOT_BELT origin_tech = "engineering=4;biotech=2;programming=5" - var/scanning = 0 + var/scanning = FALSE var/list/log = list() - actions_types = list(/datum/action/item_action/print_report) + actions_types = list(/datum/action/item_action/print_forensic_report, /datum/action/item_action/clear_records) -/obj/item/detective_scanner/attack_self(var/mob/user) +/obj/item/detective_scanner/attack_self(mob/user) var/search = input(user, "Enter name, fingerprint or blood DNA.", "Find record", "") if(!search || user.stat || user.incapacitated()) return - search = lowertext(search) + search = lowertext(search) //This is here so that it doesn't run 'lowertext()' until the checks have passed. var/name var/fingerprint = "FINGERPRINT NOT FOUND" @@ -30,85 +30,95 @@ // I really, really wish I didn't have to split this into two seperate loops. But the datacore is awful. - for(var/record in GLOB.data_core.general) + for(var/record in GLOB.data_core.general) // Search in the 'general' datacore var/datum/data/record/S = record - if(S && (search == lowertext(S.fields["fingerprint"]) || search == lowertext(S.fields["name"]))) + if(S && (search == lowertext(S.fields["fingerprint"]) || search == lowertext(S.fields["name"]))) // Get Fingerprint and Name name = S.fields["name"] fingerprint = S.fields["fingerprint"] - continue + break - for(var/record in GLOB.data_core.medical) + for(var/record in GLOB.data_core.medical) // Then search in the 'medical' datacore var/datum/data/record/M = record - if(M && ( search == lowertext(M.fields["b_dna"]) || name == M.fields["name"]) ) + if(M && (search == lowertext(M.fields["b_dna"]) || name == M.fields["name"])) // Get Blood DNA dna = M.fields["b_dna"] - if(fingerprint == "FINGERPRINT NOT FOUND") // We have searched by DNA, and do not have the relevant information from the fingerprint records. + if(fingerprint == "FINGERPRINT NOT FOUND") // We have searched for DNA, and so do not have the relevant information from the fingerprint records. name = M.fields["name"] for(var/gen_record in GLOB.data_core.general) var/datum/data/record/S = gen_record if(S && (name == S.fields["name"])) fingerprint = S.fields["fingerprint"] - continue - continue + break + else //Eveything's been set, break the loop + break if(name) to_chat(user, "Match found in station records: [name]
    \ Fingerprint: [fingerprint]
    \ Blood DNA: [dna]") - return + else + to_chat(user, "No match found in station records.") - to_chat(user, "No match found in station records.") - -/obj/item/detective_scanner/ui_action_click() - print_scanner_report() +/obj/item/detective_scanner/ui_action_click(mob/user, actiontype) + if(actiontype == /datum/action/item_action/print_forensic_report) + print_scanner_report() + else + clear_scanner() /obj/item/detective_scanner/proc/print_scanner_report() - if(log.len && !scanning) - scanning = 1 + if(length(log) && !scanning) + scanning = TRUE to_chat(usr, "Printing report, please wait...") playsound(loc, 'sound/goonstation/machines/printer_thermal.ogg', 50, 1) - spawn(100) - // Create our paper - var/obj/item/paper/P = new(get_turf(src)) - P.name = "paper- 'Scanner Report'" - P.info = "
    Scanner Report


    " - P.info += jointext(log, "
    ") - P.info += "
    Notes:
    " - P.info_links = P.info - - if(ismob(loc)) - var/mob/M = loc - M.put_in_hands(P) - to_chat(M, "Report printed. Log cleared.") - - // Clear the logs - log = list() - scanning = 0 + addtimer(CALLBACK(src, .proc/make_paper, log), 10 SECONDS) // Create our paper + log = list() // Clear the logs + scanning = FALSE else - to_chat(usr, "The scanner has no logs or is in use.") + to_chat(usr, "The scanner has no logs or is in use.") + +/obj/item/detective_scanner/proc/make_paper(log) // Moved to a proc because 'spawn()' is evil + var/obj/item/paper/P = new(get_turf(src)) + P.name = "paper- 'Scanner Report'" + P.info = "
    Scanner Report


    " + P.info += jointext(log, "
    ") + P.info += "
    Notes:
    " + P.info_links = P.info + + if(ismob(loc)) + var/mob/M = loc + M.put_in_hands(P) + to_chat(M, "Report printed. Log cleared.") -/obj/item/detective_scanner/attack(mob/living/M as mob, mob/user as mob) +/obj/item/detective_scanner/proc/clear_scanner() + if(length(log) && !scanning) + log = list() + playsound(loc, 'sound/machines/ding.ogg', 40) + addtimer(CALLBACK(GLOBAL_PROC, .proc/to_chat, usr, "Scanner logs cleared."), 1.5 SECONDS) //Timer so that it clears on the 'ding' + else + to_chat(usr, "The scanner has no logs or is in use.") + + +/obj/item/detective_scanner/attack() return - -/obj/item/detective_scanner/afterattack(atom/A, mob/user as mob, proximity) +/obj/item/detective_scanner/afterattack(atom/A, mob/user) scan(A, user) -/obj/item/detective_scanner/proc/scan(var/atom/A, var/mob/user) +/obj/item/detective_scanner/proc/scan(atom/A, mob/user) if(!scanning) // Can remotely scan objects and mobs. - if(!in_range(A, user) && !(A in view(world.view, user))) + if(!(A in view(world.view, user))) return if(loc != user) return - scanning = 1 + scanning = TRUE - user.visible_message("\The [user] points the [src.name] at \the [A] and performs a forensic scan.") - to_chat(user, "You scan \the [A]. The scanner is now analysing the results...") + user.visible_message("[user] points [src] at [A] and performs a forensic scan.", + "You scan [A]. The scanner is now analysing the results...") // GATHER INFORMATION @@ -123,10 +133,10 @@ // Start gathering - if(A.blood_DNA && A.blood_DNA.len) + if(length(A.blood_DNA)) blood = A.blood_DNA.Copy() - if(A.suit_fibers && A.suit_fibers.len) + if(length(A.suit_fibers)) fibers = A.suit_fibers.Copy() if(ishuman(A)) @@ -137,11 +147,11 @@ else if(!ismob(A)) - if(A.fingerprints && A.fingerprints.len) + if(length(A.fingerprints)) fingerprints = A.fingerprints.Copy() // Only get reagents from non-mobs. - if(A.reagents && A.reagents.reagent_list.len) + if(A.reagents && length(A.reagents.reagent_list)) for(var/datum/reagent/R in A.reagents.reagent_list) reagents[R.name] = R.volume @@ -154,63 +164,60 @@ var/blood_type = R.data["blood_type"] blood[blood_DNA] = blood_type - // We gathered everything. Create a fork and slowly display the results to the holder of the scanner. - spawn(0) + // We gathered everything. Slowly display the results to the holder of the scanner. + var/found_something = FALSE + add_log("[station_time_timestamp()][get_timestamp()] - [target_name]", FALSE) - var/found_something = 0 - add_log("[station_time_timestamp()][get_timestamp()] - [target_name]", 0) + // Fingerprints + if(length(fingerprints)) + sleep(30) + add_log("Prints:") + for(var/finger in fingerprints) + add_log("[finger]") + found_something = TRUE - // Fingerprints - if(fingerprints && fingerprints.len) - sleep(30) - add_log("Prints:") - for(var/finger in fingerprints) - add_log("[finger]") - found_something = 1 + // Blood + if(length(blood)) + sleep(30) + add_log("Blood:") + found_something = TRUE + for(var/B in blood) + add_log("Type: [blood[B]] DNA: [B]") - // Blood - if(blood && blood.len) - sleep(30) - add_log("Blood:") - found_something = 1 - for(var/B in blood) - add_log("Type: [blood[B]] DNA: [B]") + //Fibers + if(length(fibers)) + sleep(30) + add_log("Fibers:") + for(var/fiber in fibers) + add_log("[fiber]") + found_something = TRUE - //Fibers - if(fibers && fibers.len) - sleep(30) - add_log("Fibers:") - for(var/fiber in fibers) - add_log("[fiber]") - found_something = 1 + //Reagents + if(length(reagents)) + sleep(30) + add_log("Reagents:") + for(var/R in reagents) + add_log("Reagent: [R] Volume: [reagents[R]]") + found_something = TRUE - //Reagents - if(reagents && reagents.len) - sleep(30) - add_log("Reagents:") - for(var/R in reagents) - add_log("Reagent: [R] Volume: [reagents[R]]") - found_something = 1 + // Get a new user + var/mob/holder = null + if(ismob(loc)) + holder = loc - // Get a new user - var/mob/holder = null - if(ismob(src.loc)) - holder = src.loc + if(!found_something) + add_log("# No forensic traces found #", FALSE) // Don't display this to the holder user + if(holder) + to_chat(holder, "Unable to locate any fingerprints, materials, fibers, or blood on [A]!") + else + if(holder) + to_chat(holder, "You finish scanning [A].") - if(!found_something) - add_log("# No forensic traces found #", 0) // Don't display this to the holder user - if(holder) - to_chat(holder, "Unable to locate any fingerprints, materials, fibers, or blood on \the [target_name]!") - else - if(holder) - to_chat(holder, "You finish scanning \the [target_name].") + add_log("---------------------------------------------------------", FALSE) + scanning = FALSE - add_log("---------------------------------------------------------", 0) - scanning = 0 - return - -/obj/item/detective_scanner/proc/add_log(var/msg, var/broadcast = 1) +/obj/item/detective_scanner/proc/add_log(msg, broadcast = TRUE) if(scanning) if(broadcast && ismob(loc)) var/mob/M = loc diff --git a/code/modules/mining/lavaland/loot/tendril_loot.dm b/code/modules/mining/lavaland/loot/tendril_loot.dm index 0af08e40c74..f7a555f104b 100644 --- a/code/modules/mining/lavaland/loot/tendril_loot.dm +++ b/code/modules/mining/lavaland/loot/tendril_loot.dm @@ -358,6 +358,7 @@ projectile_type = /obj/item/projectile/hook caliber = "hook" icon_state = "hook" + muzzle_flash_effect = null /obj/item/projectile/hook name = "hook" diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm index 1dcd76c0358..b3f6d73a163 100644 --- a/code/modules/mob/living/carbon/alien/special/facehugger.dm +++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm @@ -28,6 +28,10 @@ var/attached = 0 +/obj/item/clothing/mask/facehugger/ComponentInitialize() + . = ..() + AddComponent(/datum/component/proximity_monitor) + /obj/item/clothing/mask/facehugger/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) ..() if(obj_integrity < 90) @@ -78,7 +82,7 @@ return HasProximity(finder) return 0 -/obj/item/clothing/mask/facehugger/HasProximity(atom/movable/AM as mob|obj) +/obj/item/clothing/mask/facehugger/HasProximity(atom/movable/AM) if(CanHug(AM) && Adjacent(AM)) return Attach(AM) return 0 @@ -210,6 +214,7 @@ icon_state = "[initial(icon_state)]_dead" item_state = "facehugger_inactive" stat = DEAD + qdel(GetComponent(/datum/component/proximity_monitor)) visible_message("[src] curls up into a ball!") diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 2fefc6b7c74..87a327f3427 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -30,8 +30,15 @@ //handle_emote_CD() located in [code\modules\mob\emote.dm] var/on_CD = FALSE act = lowertext(act) - switch(act) - //Cooldown-inducing emotes + + switch(act) //This switch makes sure you have air in your lungs before you scream + if("growl", "growls", "howl", "howls", "hiss", "hisses", "scream", "screams", "sneeze", "sneezes") + if(getOxyLoss() > 35) //no screaming if you don't have enough breath to scream + on_CD = handle_emote_CD() + emote("gasp") + return + + switch(act) //This switch adds cooldowns to some emotes if("ping", "pings", "buzz", "buzzes", "beep", "beeps", "yes", "no", "buzz2") var/found_machine_head = FALSE if(ismachineperson(src)) //Only Machines can beep, ping, and buzz, yes, no, and make a silly sad trombone noise. @@ -44,7 +51,7 @@ found_machine_head = TRUE if(!found_machine_head) //Everyone else fails, skip the emote attempt - return //Everyone else fails, skip the emote attempt + return //Everyone else fails, skip the emote attempt if("drone","drones","hum","hums","rumble","rumbles") if(isdrask(src)) //Only Drask can make whale noises on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm @@ -133,7 +140,7 @@ if(!force && on_CD == 1) // Check if we need to suppress the emote attempt. return // Suppress emote, you're still cooling off. - switch(act) + switch(act) //This is for actually making the emotes happen if("me") //OKAY SO RANT TIME, THIS FUCKING HAS TO BE HERE OR A SHITLOAD OF THINGS BREAK return custom_emote(m_type, message) //DO YOU KNOW WHY SHIT BREAKS? BECAUSE SO MUCH OLDCODE CALLS mob.emote("me",1,"whatever_the_fuck_it_wants_to_emote") //WHO THE FUCK THOUGHT THAT WAS A GOOD FUCKING IDEA!?!? diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 3739e337542..cf517dc7389 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -364,6 +364,17 @@ msg += "Security records: \[View comment log\] \[Add comment\]\n" msg += "Latest entry: [commentLatest]\n" + if(hasHUD(user, "skills")) + var/perpname = get_visible_name(TRUE) + var/skills + + if(perpname) + for(var/datum/data/record/E in GLOB.data_core.general) + if(E.fields["name"] == perpname) + skills = E.fields["notes"] + if(skills) + msg += "Employment records: [skills]\n" + if(hasHUD(user,"medical")) var/perpname = get_visible_name(TRUE) var/medical = "None" @@ -404,8 +415,11 @@ return !istype(CIH,/obj/item/organ/internal/cyberimp/eyes/hud/security) && S && S.read_only if("medical") return istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(CIH,/obj/item/organ/internal/cyberimp/eyes/hud/medical) + if("skills") + return istype(H.glasses, /obj/item/clothing/glasses/hud/skills) else return FALSE + else if(isrobot(M) || isAI(M)) //Stand-in/Stopgap to prevent pAIs from freely altering records, pending a more advanced Records system switch(hudtype) if("security") @@ -420,6 +434,8 @@ switch(hudtype) if("security") return TRUE + if("skills") + return TRUE else return FALSE else diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 4cb846139f7..6393a8333bb 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -254,7 +254,7 @@ limbs_affected -= 1 else valid_limbs -= processing_dismember - if(!istype(l_ear, /obj/item/clothing/ears/earmuffs) && !istype(r_ear, /obj/item/clothing/ears/earmuffs)) + if(check_ear_prot() < HEARING_PROTECTION_TOTAL) AdjustEarDamage(30, 120) if(prob(70) && !shielded) Paralyse(10) @@ -278,7 +278,7 @@ limbs_affected -= 1 else valid_limbs -= processing_dismember - if(!istype(l_ear, /obj/item/clothing/ears/earmuffs) && !istype(r_ear, /obj/item/clothing/ears/earmuffs)) + if(check_ear_prot() < HEARING_PROTECTION_TOTAL) AdjustEarDamage(15, 60) if(prob(50) && !shielded) Paralyse(10) @@ -931,12 +931,18 @@ return number /mob/living/carbon/human/check_ear_prot() + if(!can_hear()) + return HEARING_PROTECTION_TOTAL + if(istype(l_ear, /obj/item/clothing/ears/earmuffs)) + return HEARING_PROTECTION_TOTAL + if(istype(r_ear, /obj/item/clothing/ears/earmuffs)) + return HEARING_PROTECTION_TOTAL if(head && (head.flags & HEADBANGPROTECT)) - return 1 + return HEARING_PROTECTION_MINOR if(l_ear && (l_ear.flags & EARBANGPROTECT)) - return 1 + return HEARING_PROTECTION_MINOR if(r_ear && (r_ear.flags & EARBANGPROTECT)) - return 1 + return HEARING_PROTECTION_MINOR ///tintcheck() ///Checks eye covering items for visually impairing tinting, such as welding masks @@ -1173,7 +1179,7 @@ set src in view(1) var/self = 0 - if(usr.stat == 1 || usr.restrained() || !isliving(usr)) return + if(usr.stat == 1 || usr.restrained() || !isliving(usr) || usr.is_dead()) return if(usr == src) self = 1 diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm index 1ba796c0435..69518e96cf7 100644 --- a/code/modules/mob/living/carbon/human/species/_species.dm +++ b/code/modules/mob/living/carbon/human/species/_species.dm @@ -371,7 +371,7 @@ return /datum/species/proc/help(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) - if(attacker_style && attacker_style.help_act(user, target))//adminfu only... + if(attacker_style && attacker_style.help_act(user, target) == TRUE)//adminfu only... return TRUE if(target.health >= HEALTH_THRESHOLD_CRIT && !(target.status_flags & FAKEDEATH)) target.help_shake_act(user) @@ -383,7 +383,7 @@ if(target.check_block()) target.visible_message("[target] blocks [user]'s grab attempt!") return FALSE - if(attacker_style && attacker_style.grab_act(user, target)) + if(attacker_style && attacker_style.grab_act(user, target) == TRUE) return TRUE else target.grabbedby(user) @@ -412,7 +412,7 @@ if(target.check_block()) target.visible_message("[target] blocks [user]'s attack!") return FALSE - if(attacker_style && attacker_style.harm_act(user, target)) + if(attacker_style && attacker_style.harm_act(user, target) == TRUE) return TRUE else var/datum/unarmed_attack/attack = user.dna.species.unarmed @@ -460,7 +460,7 @@ if(target.check_block()) target.visible_message("[target] blocks [user]'s disarm attempt!") return FALSE - if(attacker_style && attacker_style.disarm_act(user, target)) + if(attacker_style && attacker_style.disarm_act(user, target) == TRUE) return TRUE else add_attack_logs(user, target, "Disarmed", ATKLOG_ALL) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index a5a9269d63b..cebac878c6b 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -1332,8 +1332,10 @@ GLOBAL_LIST_INIT(ai_verbs_default, list( if(istype(A)) switch(alert(src, "Do you want to open \the [A] for [target]?", "Doorknob_v2a.exe", "Yes", "No")) if("Yes") - A.AIShiftClick() - to_chat(src, "You open \the [A] for [target].") + if(!A.density) + to_chat(src, "[A] was already opened.") + else if(A.open_close(src)) + to_chat(src, "You open \the [A] for [target].") else to_chat(src, "You deny the request.") else diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm index 2d18131e8cc..a8485853be1 100644 --- a/code/modules/mob/living/silicon/robot/drone/drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/drone.dm @@ -126,6 +126,11 @@ /mob/living/silicon/robot/drone/pick_module() return +/mob/living/silicon/robot/drone/can_be_revived() + . = ..() + if(emagged) + return FALSE + //Drones cannot be upgraded with borg modules so we need to catch some items before they get used in ..(). /mob/living/silicon/robot/drone/attackby(obj/item/W as obj, mob/user as mob, params) diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/pet.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/pet.dm index e92bc114936..6be9725e9aa 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/pet.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/pet.dm @@ -18,3 +18,5 @@ melee_damage_upper = 20 unique_pet = TRUE atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 2, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) + gender = FEMALE + diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm index 218e01af6a2..eb0d1a37b60 100644 --- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm +++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/actions.dm @@ -167,13 +167,26 @@ // ---------- WRAP +/mob/living/simple_animal/hostile/poison/terror_spider/proc/mobIsWrappable(mob/living/M) + if(!istype(M)) + return FALSE + if(M.stat != DEAD) + return FALSE + if(M.anchored) + return FALSE + if(!Adjacent(M)) + return FALSE + if(isterrorspider(M)) + return FALSE + return TRUE + /mob/living/simple_animal/hostile/poison/terror_spider/proc/FindWrapTarget() if(!cocoon_target) var/list/choices = list() for(var/mob/living/L in oview(1,src)) - if(Adjacent(L) && !L.anchored) - if(L.stat == DEAD) - choices += L + if(!mobIsWrappable(L)) + continue + choices += L for(var/obj/O in oview(1,src)) if(Adjacent(O) && !O.anchored) if(!istype(O, /obj/structure/spider/terrorweb) && !istype(O, /obj/structure/spider/cocoon) && !istype(O, /obj/structure/spider/spiderling/terror_spiderling)) @@ -207,9 +220,7 @@ O.loc = C large_cocoon = 1 for(var/mob/living/L in C.loc) - if(istype(L, /mob/living/simple_animal/hostile/poison/terror_spider)) - continue - if(L.stat != DEAD) + if(!mobIsWrappable(L)) continue if(iscarbon(L)) regen_points += regen_points_per_kill 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 7a840405cd0..787d89b722f 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 @@ -59,6 +59,10 @@ /mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/grant_eggs() spider_lastspawn = world.time + if(!isturf(loc)) + to_chat(src, "You cannot generate eggs while hiding in [loc].") + return + if(!prob(grant_prob)) return @@ -82,10 +86,6 @@ icon_dead = "terror_princess3_dead" desc = "An enormous spider. Its entire body looks to be the color of dried blood." - if(!isturf(loc)) - to_chat(src, "You cannot generate eggs while hiding in [loc].") - return - if((brood_count + canlay) >= spider_max_children) return canlay++ @@ -94,6 +94,9 @@ else to_chat(src, "You have [canlay] eggs available to lay.") +/mob/living/simple_animal/hostile/poison/terror_spider/queen/princess/show_egg_timer() + var/average_timer = (1 / (grant_prob / 100)) * (spider_spawnfrequency / 10) + to_chat(src, "Too soon to attempt that again. You generate a new egg every [average_timer] seconds, on average.") /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. 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 af475b1a59a..8f423dfb5d2 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 @@ -248,11 +248,7 @@ to_chat(src, "You must nest before doing this.") return if(canlay < 1) - var/remainingtime = round(((spider_lastspawn + spider_spawnfrequency) - world.time) / 10, 1) - if(remainingtime > 0) - to_chat(src, "Too soon to attempt that again. Wait another [num2text(remainingtime)] seconds.") - else - to_chat(src, "Too soon to attempt that again. Wait just a few more seconds...") + show_egg_timer() return var/list/eggtypes = ListAvailableEggTypes() var/list/eggtypes_uncapped = list(TS_DESC_RED, TS_DESC_GRAY, TS_DESC_GREEN) @@ -307,6 +303,12 @@ else to_chat(src, "Unrecognized egg type.") +/mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/show_egg_timer() + var/remainingtime = round(((spider_lastspawn + spider_spawnfrequency) - world.time) / 10, 1) + if(remainingtime > 0) + to_chat(src, "Too soon to attempt that again. Wait another [num2text(remainingtime)] seconds.") + else + to_chat(src, "Too soon to attempt that again. Wait just a few more seconds...") /mob/living/simple_animal/hostile/poison/terror_spider/queen/proc/ListAvailableEggTypes() if(MinutesAlive() >= 20) diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index c222f76eadb..639f3da7aaf 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -20,10 +20,10 @@ spawn() alert("You have logged in already with another key this round, please log out of this one NOW or risk being banned!") if(matches) if(M.client) - message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(M)].", 1) + message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(M)].", 1) log_adminwarn("Notice: [key_name(src)] has the same [matches] as [key_name(M)].") else - message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(M)] (no longer logged in). ", 1) + message_admins("Notice: [key_name_admin(src)] has the same [matches] as [key_name_admin(M)] (no longer logged in). ", 1) log_adminwarn("Notice: [key_name(src)] has the same [matches] as [key_name(M)] (no longer logged in).") /mob/Login() diff --git a/code/modules/modular_computers/NTNet/NTNRC/conversation.dm b/code/modules/modular_computers/NTNet/NTNRC/conversation.dm deleted file mode 100644 index 948824fa32e..00000000000 --- a/code/modules/modular_computers/NTNet/NTNRC/conversation.dm +++ /dev/null @@ -1,70 +0,0 @@ -GLOBAL_VAR_INIT(ntnrc_uid, 0) - -/datum/ntnet_conversation - var/id = null - var/title = "Untitled Conversation" - var/datum/computer_file/program/chatclient/operator // "Administrator" of this channel. Creator starts as channel's operator, - var/list/messages = list() - var/list/clients = list() - var/password - -/datum/ntnet_conversation/New() - id = GLOB.ntnrc_uid - GLOB.ntnrc_uid++ - if(GLOB.ntnet_global) - GLOB.ntnet_global.chat_channels.Add(src) - ..() - -/datum/ntnet_conversation/Destroy() - if(GLOB.ntnet_global) - GLOB.ntnet_global.chat_channels.Remove(src) - return ..() - -/datum/ntnet_conversation/proc/add_message(message, username) - message = "[station_time_timestamp()] [username]: [message]" - messages.Add(message) - trim_message_list() - -/datum/ntnet_conversation/proc/add_status_message(message) - messages.Add("[station_time_timestamp()] -!- [message]") - trim_message_list() - -/datum/ntnet_conversation/proc/trim_message_list() - if(messages.len <= 50) - return - messages = messages.Copy(messages.len-50 ,0) - -/datum/ntnet_conversation/proc/add_client(datum/computer_file/program/chatclient/C) - if(!istype(C)) - return - clients.Add(C) - add_status_message("[C.username] has joined the channel.") - // No operator, so we assume the channel was empty. Assign this user as operator. - if(!operator) - changeop(C) - -/datum/ntnet_conversation/proc/remove_client(datum/computer_file/program/chatclient/C) - if(!istype(C) || !(C in clients)) - return - clients.Remove(C) - add_status_message("[C.username] has left the channel.") - - // Channel operator left, pick new operator - if(C == operator) - operator = null - if(clients.len) - var/datum/computer_file/program/chatclient/newop = pick(clients) - changeop(newop) - - -/datum/ntnet_conversation/proc/changeop(datum/computer_file/program/chatclient/newop) - if(istype(newop)) - operator = newop - add_status_message("Channel operator status transferred to [newop.username].") - -/datum/ntnet_conversation/proc/change_title(newtitle, datum/computer_file/program/chatclient/client) - if(operator != client) - return 0 // Not Authorised - - add_status_message("[client.username] has changed channel title from [title] to [newtitle]") - title = newtitle diff --git a/code/modules/modular_computers/NTNet/NTNet.dm b/code/modules/modular_computers/NTNet/NTNet.dm deleted file mode 100644 index 2f9aa3f2e7d..00000000000 --- a/code/modules/modular_computers/NTNet/NTNet.dm +++ /dev/null @@ -1,145 +0,0 @@ -GLOBAL_DATUM_INIT(ntnet_global, /datum/ntnet, new()) - - -// This is the NTNet datum. There can be only one NTNet datum in game at once. Modular computers read data from this. -/datum/ntnet - var/list/relays = list() - var/list/logs = list() - var/list/available_station_software = list() - var/list/available_antag_software = list() - var/list/chat_channels = list() - var/list/fileservers = list() - // Amount of logs the system tries to keep in memory. Keep below 999 to prevent byond from acting weirdly. - // High values make displaying logs much laggier. - var/setting_maxlogcount = 100 - - // These only affect wireless. LAN (consoles) are unaffected since it would be possible to create scenario where someone turns off NTNet, and is unable to turn it back on since it refuses connections - var/setting_softwaredownload = 1 - var/setting_peertopeer = 1 - var/setting_communication = 1 - var/setting_systemcontrol = 1 - var/setting_disabled = 0 // Setting to 1 will disable all wireless, independently on relays status. - - var/intrusion_detection_enabled = 1 // Whether the IDS warning system is enabled - var/intrusion_detection_alarm = 0 // Set when there is an IDS warning due to malicious (antag) software. - - -// If new NTNet datum is spawned, it replaces the old one. -/datum/ntnet/New() - if(GLOB.ntnet_global && (GLOB.ntnet_global != src)) - GLOB.ntnet_global = src // There can be only one. - for(var/obj/machinery/ntnet_relay/R in GLOB.machines) - relays.Add(R) - R.NTNet = src - build_software_lists() - add_log("NTNet logging system activated.") - -// Simplified logging: Adds a log. log_string is mandatory parameter, source is optional. -/datum/ntnet/proc/add_log(log_string, obj/item/computer_hardware/network_card/source = null) - var/log_text = "[station_time_timestamp()] - " - if(source) - log_text += "[source.get_network_tag()] - " - else - log_text += "*SYSTEM* - " - log_text += log_string - logs.Add(log_text) - - - // We have too many logs, remove the oldest entries until we get into the limit - if(logs.len > setting_maxlogcount) - logs = logs.Copy(logs.len-setting_maxlogcount,0) - - -// Checks whether NTNet operates. If parameter is passed checks whether specific function is enabled. -/datum/ntnet/proc/check_function(specific_action = 0) - if(!relays || !relays.len) // No relays found. NTNet is down - return 0 - - var/operating = 0 - - // Check all relays. If we have at least one working relay, network is up. - for(var/M in relays) - var/obj/machinery/ntnet_relay/R = M - if(R.operable()) - operating = 1 - break - - if(setting_disabled) - return 0 - - switch(specific_action) - if(NTNET_SOFTWAREDOWNLOAD) - return (operating && setting_softwaredownload) - if(NTNET_PEERTOPEER) - return (operating && setting_peertopeer) - if(NTNET_COMMUNICATION) - return (operating && setting_communication) - if(NTNET_SYSTEMCONTROL) - return (operating && setting_systemcontrol) - return operating - -// Builds lists that contain downloadable software. -/datum/ntnet/proc/build_software_lists() - available_station_software = list() - available_antag_software = list() - for(var/F in typesof(/datum/computer_file/program)) - var/datum/computer_file/program/prog = new F - // Invalid type (shouldn't be possible but just in case), invalid filetype (not executable program) or invalid filename (unset program) - if(!prog || prog.filename == "UnknownProgram" || prog.filetype != "PRG") - continue - // Check whether the program should be available for station/antag download, if yes, add it to lists. - if(prog.available_on_ntnet) - available_station_software.Add(prog) - if(prog.available_on_syndinet) - available_antag_software.Add(prog) - -// Attempts to find a downloadable file according to filename var -/datum/ntnet/proc/find_ntnet_file_by_name(filename) - for(var/N in available_station_software) - var/datum/computer_file/program/P = N - if(filename == P.filename) - return P - for(var/N in available_antag_software) - var/datum/computer_file/program/P = N - if(filename == P.filename) - return P - -// Resets the IDS alarm -/datum/ntnet/proc/resetIDS() - intrusion_detection_alarm = 0 - -/datum/ntnet/proc/toggleIDS() - resetIDS() - intrusion_detection_enabled = !intrusion_detection_enabled - -// Removes all logs -/datum/ntnet/proc/purge_logs() - logs = list() - add_log("-!- LOGS DELETED BY SYSTEM OPERATOR -!-") - -// Updates maximal amount of stored logs. Use this instead of setting the number, it performs required checks. -/datum/ntnet/proc/update_max_log_count(lognumber) - if(!lognumber) - return 0 - // Trim the value if necessary - lognumber = max(MIN_NTNET_LOGS, min(lognumber, MAX_NTNET_LOGS)) - setting_maxlogcount = lognumber - add_log("Configuration Updated. Now keeping [setting_maxlogcount] logs in system memory.") - -/datum/ntnet/proc/toggle_function(function) - if(!function) - return - function = text2num(function) - switch(function) - if(NTNET_SOFTWAREDOWNLOAD) - setting_softwaredownload = !setting_softwaredownload - add_log("Configuration Updated. Wireless network firewall now [setting_softwaredownload ? "allows" : "disallows"] connection to software repositories.") - if(NTNET_PEERTOPEER) - setting_peertopeer = !setting_peertopeer - add_log("Configuration Updated. Wireless network firewall now [setting_peertopeer ? "allows" : "disallows"] peer to peer network traffic.") - if(NTNET_COMMUNICATION) - setting_communication = !setting_communication - add_log("Configuration Updated. Wireless network firewall now [setting_communication ? "allows" : "disallows"] instant messaging and similar communication services.") - if(NTNET_SYSTEMCONTROL) - setting_systemcontrol = !setting_systemcontrol - add_log("Configuration Updated. Wireless network firewall now [setting_systemcontrol ? "allows" : "disallows"] remote control of station's systems.") diff --git a/code/modules/modular_computers/NTNet/NTNet_relay.dm b/code/modules/modular_computers/NTNet/NTNet_relay.dm deleted file mode 100644 index 97ddcfb69c0..00000000000 --- a/code/modules/modular_computers/NTNet/NTNet_relay.dm +++ /dev/null @@ -1,125 +0,0 @@ -// Relays don't handle any actual communication. Global NTNet datum does that, relays only tell the datum if it should or shouldn't work. -/obj/machinery/ntnet_relay - name = "NTNet Quantum Relay" - desc = "A very complex router and transmitter capable of connecting electronic devices together. Looks fragile." - use_power = ACTIVE_POWER_USE - active_power_usage = 100 // 100 watts. Yes I know this is a high power machine but this fucking obliterates an unpowered smes (AI sat) - idle_power_usage = 100 - icon = 'icons/obj/stationobjs.dmi' - icon_state = "bus" - anchored = 1 - density = 1 - var/datum/ntnet/NTNet = null // This is mostly for backwards reference and to allow varedit modifications from ingame. - var/enabled = 1 // Set to 0 if the relay was turned off - var/dos_failure = 0 // Set to 1 if the relay failed due to (D)DoS attack - var/list/dos_sources = list() // Backwards reference for qdel() stuff - - // Denial of Service attack variables - var/dos_overload = 0 // Amount of DoS "packets" in this relay's buffer - var/dos_capacity = 500 // Amount of DoS "packets" in buffer required to crash the relay - var/dos_dissipate = 1 // Amount of DoS "packets" dissipated over time. - - -// TODO: Implement more logic here. For now it's only a placeholder. -/obj/machinery/ntnet_relay/inoperable(additional_flags = 0) - if(stat & (BROKEN | NOPOWER | EMPED | additional_flags)) - return 1 - if(dos_failure) - return 1 - if(!enabled) - return 1 - return 0 - -/obj/machinery/ntnet_relay/update_icon() - if(operable()) - icon_state = "bus" - else - icon_state = "bus_off" - -/obj/machinery/ntnet_relay/process() - if(operable()) - use_power = ACTIVE_POWER_USE - else - use_power = IDLE_POWER_USE - - update_icon() - - if(dos_overload) - dos_overload = max(0, dos_overload - dos_dissipate) - - // If DoS traffic exceeded capacity, crash. - if((dos_overload > dos_capacity) && !dos_failure) - dos_failure = 1 - update_icon() - GLOB.ntnet_global.add_log("Quantum relay switched from normal operation mode to overload recovery mode.") - // If the DoS buffer reaches 0 again, restart. - if((dos_overload == 0) && dos_failure) - dos_failure = 0 - update_icon() - GLOB.ntnet_global.add_log("Quantum relay switched from overload recovery mode to normal operation mode.") - ..() - -/obj/machinery/ntnet_relay/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, "ntnet_relay.tmpl", "NTNet Quantum Relay", 500, 300) - ui.open() - -/obj/machinery/ntnet_relay/ui_data(mob/user) - var/list/data = list() - data["enabled"] = enabled - data["dos_capacity"] = dos_capacity - data["dos_overload"] = dos_overload - data["dos_crashed"] = dos_failure - return data - - -/obj/machinery/ntnet_relay/Topic(href, list/href_list) - if(..()) - return - switch(href_list["action"]) - if("restart") - dos_overload = 0 - dos_failure = 0 - update_icon() - GLOB.ntnet_global.add_log("Quantum relay manually restarted from overload recovery mode to normal operation mode.") - if("toggle") - enabled = !enabled - GLOB.ntnet_global.add_log("Quantum relay manually [enabled ? "enabled" : "disabled"].") - update_icon() - return 1 - - -/obj/machinery/ntnet_relay/attack_hand(mob/living/user) - ui_interact(user) - -/obj/machinery/ntnet_relay/New() - uid = gl_uid - gl_uid++ - component_parts = list() - component_parts += new /obj/item/circuitboard/machine/ntnet_relay(null) - component_parts += new /obj/item/stack/cable_coil(null, 2) - - if(GLOB.ntnet_global) - GLOB.ntnet_global.relays.Add(src) - NTNet = GLOB.ntnet_global - GLOB.ntnet_global.add_log("New quantum relay activated. Current amount of linked relays: [NTNet.relays.len]") - ..() - -/obj/machinery/ntnet_relay/Destroy() - if(GLOB.ntnet_global) - GLOB.ntnet_global.relays.Remove(src) - GLOB.ntnet_global.add_log("Quantum relay connection severed. Current amount of linked relays: [NTNet.relays.len]") - NTNet = null - - for(var/datum/computer_file/program/ntnet_dos/D in dos_sources) - D.target = null - D.error = "Connection to quantum relay severed" - - return ..() - -/obj/item/circuitboard/machine/ntnet_relay - name = "NTNet Relay (Machine Board)" - build_path = /obj/machinery/ntnet_relay - origin_tech = "programming=3;bluespace=3;magnets=2" - req_components = list(/obj/item/stack/cable_coil = 2) diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm deleted file mode 100644 index 1dd45a33603..00000000000 --- a/code/modules/modular_computers/computers/item/computer.dm +++ /dev/null @@ -1,369 +0,0 @@ -// This is the base type that does all the hardware stuff. -// Other types expand it - tablets use a direct subtypes, and -// consoles and laptops use "procssor" item that is held inside machinery piece -/obj/item/modular_computer - name = "modular microcomputer" - desc = "A small portable microcomputer." - - var/enabled = 0 // Whether the computer is turned on. - var/screen_on = 1 // Whether the computer is active/opened/it's screen is on. - var/datum/computer_file/program/active_program = null // A currently active program running on the computer. - var/hardware_flag = 0 // A flag that describes this device type - var/last_power_usage = 0 - var/last_battery_percent = 0 // Used for deciding if battery percentage has chandged - var/last_world_time = "00:00" - var/list/last_header_icons - var/emagged = 0 // Whether the computer is emagged. - - var/base_active_power_usage = 50 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too. - var/base_idle_power_usage = 5 // Power usage when the computer is idle and screen is off (currently only applies to laptops) - - // Modular computers can run on various devices. Each DEVICE (Laptop, Console, Tablet,..) - // must have it's own DMI file. Icon states must be called exactly the same in all files, but may look differently - // If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example. - - icon = 'icons/obj/computer.dmi' - icon_state = "laptop-open" - var/icon_state_unpowered = null // Icon state when the computer is turned off. - var/icon_state_powered = null // Icon state when the computer is turned on. - var/icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen. - var/max_hardware_size = 0 // Maximal hardware w_class. Tablets/PDAs have 1, laptops 2, consoles 4. - var/steel_sheet_cost = 5 // Amount of steel sheets refunded when disassembling an empty frame of this computer. - - integrity_failure = 50 - max_integrity = 100 - armor = list("melee" = 0, "bullet" = 20, "laser" = 20, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 0, "acid" = 0) - - // Important hardware (must be installed for computer to work) - - // Optional hardware (improves functionality, but is not critical for computer to work) - - var/list/all_components // List of "connection ports" in this computer and the components with which they are plugged - - var/list/idle_threads // Idle programs on background. They still receive process calls but can't be interacted with. - var/obj/physical = null // Object that represents our computer. It's used for Adjacent() and UI visibility checks. - - - -/obj/item/modular_computer/New() - update_icon() - if(!physical) - physical = src - ..() - START_PROCESSING(SSobj, src) - all_components = list() - idle_threads = list() - -/obj/item/modular_computer/Destroy() - kill_program(forced = TRUE) - for(var/H in all_components) - var/obj/item/computer_hardware/CH = all_components[H] - if(CH.holder == src) - CH.on_remove(src) - CH.holder = null - all_components.Remove(CH.device_type) - qdel(CH) - physical = null - STOP_PROCESSING(SSobj, src) - return ..() - - -/obj/item/modular_computer/proc/add_verb(var/path) - switch(path) - if(MC_CARD) - verbs += /obj/item/modular_computer/proc/eject_id - if(MC_SDD) - verbs += /obj/item/modular_computer/proc/eject_disk - if(MC_AI) - verbs += /obj/item/modular_computer/proc/eject_card - -/obj/item/modular_computer/proc/remove_verb(path) - switch(path) - if(MC_CARD) - verbs -= /obj/item/modular_computer/proc/eject_id - if(MC_SDD) - verbs -= /obj/item/modular_computer/proc/eject_disk - if(MC_AI) - verbs -= /obj/item/modular_computer/proc/eject_card - -// Eject ID card from computer, if it has ID slot with card inside. -/obj/item/modular_computer/proc/eject_id() - set name = "Eject ID" - set category = "Object" - set src in view(1) - - if(issilicon(usr)) - return - var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD] - if(!usr.incapacitated()) - card_slot.try_eject(null, usr) - -// Eject ID card from computer, if it has ID slot with card inside. -/obj/item/modular_computer/proc/eject_card() - set name = "Eject Intellicard" - set category = "Object" - set src in view(1) - - if(issilicon(usr)) - return - var/obj/item/computer_hardware/ai_slot/ai_slot = all_components[MC_AI] - if(!usr.incapacitated()) - ai_slot.try_eject(null, usr, 1) - - -// Eject ID card from computer, if it has ID slot with card inside. -/obj/item/modular_computer/proc/eject_disk() - set name = "Eject Data Disk" - set category = "Object" - set src in view(1) - - if(issilicon(usr)) - return - - if(!usr.incapacitated()) - var/obj/item/computer_hardware/hard_drive/portable/portable_drive = all_components[MC_SDD] - if(uninstall_component(portable_drive, usr)) - portable_drive.verb_pickup() - -/obj/item/modular_computer/AltClick(mob/user) - ..() - if(issilicon(user)) - return - - if(!user.incapacitated() && Adjacent(user)) - var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD] - var/obj/item/computer_hardware/ai_slot/ai_slot = all_components[MC_AI] - var/obj/item/computer_hardware/hard_drive/portable/portable_drive = all_components[MC_SDD] - if(portable_drive) - if(uninstall_component(portable_drive, user)) - portable_drive.verb_pickup() - else - if(card_slot && card_slot.try_eject(null, user)) - return - if(ai_slot) - ai_slot.try_eject(null, user) - - -// Gets IDs/access levels from card slot. Would be useful when/if PDAs would become modular PCs. -/obj/item/modular_computer/GetAccess() - var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD] - if(card_slot) - return card_slot.GetAccess() - return ..() - -/obj/item/modular_computer/GetID() - var/obj/item/computer_hardware/card_slot/card_slot = all_components[MC_CARD] - if(card_slot) - return card_slot.GetID() - return ..() - -/obj/item/modular_computer/attack_ai(mob/user) - return attack_self(user) - -/obj/item/modular_computer/attack_ghost(mob/dead/observer/user) - if(enabled) - ui_interact(user) - else if(user.can_admin_interact()) - var/response = alert(user, "This computer is turned off. Would you like to turn it on?", "Admin Override", "Yes", "No") - if(response == "Yes") - turn_on(user) - -/obj/item/modular_computer/emag_act(mob/user) - if(emagged) - to_chat(user, "\The [src] was already emagged.") - return 0 - else - emagged = 1 - to_chat(user, "You emag \the [src]. It's screen briefly shows a \"OVERRIDE ACCEPTED: New software downloads available.\" message.") - return 1 - -/obj/item/modular_computer/examine(mob/user) - . = ..() - if(obj_integrity <= integrity_failure) - . += "It is heavily damaged!" - else if(obj_integrity < max_integrity) - . += "It is damaged." - -/obj/item/modular_computer/update_icon() - overlays.Cut() - if(!enabled) - icon_state = icon_state_unpowered - else - icon_state = icon_state_powered - if(active_program && active_program.program_state != PROGRAM_STATE_KILLED) - overlays += active_program.program_icon_state ? active_program.program_icon_state : icon_state_menu - else - overlays += icon_state_menu - - if(obj_integrity <= integrity_failure) - overlays += "bsod" - overlays += "broken" - - -// On-click handling. Turns on the computer if it's off and opens the GUI. -/obj/item/modular_computer/attack_self(mob/user) - if(enabled) - ui_interact(user) - else - turn_on(user) - -/obj/item/modular_computer/proc/turn_on(mob/user) - var/issynth = issilicon(user) // Robots and AIs get different activation messages. - if(obj_integrity <= integrity_failure) - if(issynth) - to_chat(user, "You send an activation signal to \the [src], but it responds with an error code. It must be damaged.") - else - to_chat(user, "You press the power button, but the computer fails to boot up, displaying variety of errors before shutting down again.") - return - - // If we have a recharger, enable it automatically. Lets computer without a battery work. - var/obj/item/computer_hardware/recharger/recharger = all_components[MC_CHARGE] - if(recharger) - recharger.enabled = 1 - - if(all_components[MC_CPU] && use_power()) // use_power() checks if the PC is powered - if(issynth) - to_chat(user, "You send an activation signal to \the [src], turning it on.") - else - to_chat(user, "You press the power button and start up \the [src].") - enabled = 1 - update_icon() - ui_interact(user) - else // Unpowered - if(issynth) - to_chat(user, "You send an activation signal to \the [src] but it does not respond.") - else - to_chat(user, "You press the power button but \the [src] does not respond.") - -// Process currently calls handle_power(), may be expanded in future if more things are added. -/obj/item/modular_computer/process() - if(!enabled) // The computer is turned off - last_power_usage = 0 - return 0 - - if(obj_integrity <= integrity_failure) - shutdown_computer() - return 0 - - if(active_program && active_program.requires_ntnet && !get_ntnet_status(active_program.requires_ntnet_feature)) - active_program.event_networkfailure(0) // Active program requires NTNet to run but we've just lost connection. Crash. - - if(active_program) - if(active_program.program_state != PROGRAM_STATE_KILLED) - active_program.process_tick() - active_program.ntnet_status = get_ntnet_status() - else - active_program = null - - for(var/I in idle_threads) - var/datum/computer_file/program/P = I - if(P.program_state != PROGRAM_STATE_KILLED) - if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature)) - P.event_networkfailure(1) - P.process_tick() - P.ntnet_status = get_ntnet_status() - else - idle_threads.Remove(P) - - handle_power() // Handles all computer power interaction - -// Relays kill program request to currently active program. Use this to quit current program. -/obj/item/modular_computer/proc/kill_program(forced = FALSE) - if(active_program && active_program.program_state != PROGRAM_STATE_KILLED) - active_program.kill_program(forced) - active_program = null - var/mob/user = usr - if(user && istype(user)) - ui_interact(user) // Re-open the UI on this computer. It should show the main screen now. - update_icon() - -// Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on) -/obj/item/modular_computer/proc/get_ntnet_status(specific_action = 0) - var/obj/item/computer_hardware/network_card/network_card = all_components[MC_NET] - if(network_card) - return network_card.get_signal(specific_action) - else - return 0 - -/obj/item/modular_computer/proc/add_log(text) - if(!get_ntnet_status()) - return FALSE - var/obj/item/computer_hardware/network_card/network_card = all_components[MC_NET] - return GLOB.ntnet_global.add_log(text, network_card) - -/obj/item/modular_computer/proc/shutdown_computer(loud = 1) - if(enabled) - kill_program(forced = TRUE) - for(var/datum/computer_file/program/P in idle_threads) - P.kill_program(forced = TRUE) - idle_threads.Remove(P) - if(loud) - physical.visible_message("\The [src] shuts down.") - enabled = 0 - update_icon() - - -/obj/item/modular_computer/attackby(obj/item/W, mob/user) - // Insert items into the components - for(var/h in all_components) - var/obj/item/computer_hardware/H = all_components[h] - if(H.try_insert(W, user)) - return - - // Insert new hardware - if(istype(W, /obj/item/computer_hardware)) - if(install_component(W, user)) - return - - if(istype(W, /obj/item/wrench)) - if(all_components.len) - to_chat(user, "Remove all components from \the [src] before disassembling it.") - return - new /obj/item/stack/sheet/metal(get_turf(loc), steel_sheet_cost) - physical.visible_message("\The [src] has been disassembled by [user].") - relay_qdel() - qdel(src) - return - - if(istype(W, /obj/item/screwdriver)) - if(!all_components.len) - to_chat(user, "This device doesn't have any components installed.") - return - var/list/component_names = list() - for(var/h in all_components) - var/obj/item/computer_hardware/H = all_components[h] - component_names.Add(H.name) - - var/choice = input(user, "Which component do you want to uninstall?", "Computer maintenance", null) as null|anything in component_names - - if(!choice) - return - - if(!Adjacent(user)) - return - - var/obj/item/computer_hardware/H = find_hardware_by_name(choice) - - if(!H) - return - - uninstall_component(H, user) - return - - ..() - -/obj/item/modular_computer/welder_act(mob/user, obj/item/I) - . = TRUE - if(!I.tool_use_check(user, 0)) - return - default_welder_repair(user, I) - -// Used by processor to relay qdel() to machinery type. -/obj/item/modular_computer/proc/relay_qdel() - return - -// Perform adjacency checks on our physical counterpart, if any. -/obj/item/modular_computer/Adjacent(atom/neighbor) - if(physical && physical != src) - return physical.Adjacent(neighbor) - return ..() diff --git a/code/modules/modular_computers/computers/item/computer_components.dm b/code/modules/modular_computers/computers/item/computer_components.dm deleted file mode 100644 index fb6d41d989f..00000000000 --- a/code/modules/modular_computers/computers/item/computer_components.dm +++ /dev/null @@ -1,58 +0,0 @@ -/obj/item/modular_computer/proc/can_install_component(obj/item/computer_hardware/H, mob/living/user = null) - if(!H.can_install(src, user)) - return FALSE - - if(H.w_class > max_hardware_size) - if(user) - to_chat(user, "This component is too large for \the [src]!") - return FALSE - - if(all_components[H.device_type]) - if(user) - to_chat(user, "This computer's hardware slot is already occupied by \the [all_components[H.device_type]].") - return FALSE - return TRUE - - -// Installs component. -/obj/item/modular_computer/proc/install_component(obj/item/computer_hardware/H, mob/living/user = null) - if(!can_install_component(H, user)) - return FALSE - - if(user && !user.unEquip(H)) - return FALSE - H.forceMove(src) - - all_components[H.device_type] = H - - if(user) - to_chat(user, "You install \the [H] into \the [src].") - H.holder = src - H.on_install(src, user) - - -// Uninstalls component. -/obj/item/modular_computer/proc/uninstall_component(obj/item/computer_hardware/H, mob/living/user = null) - if(H.holder != src) // Not our component at all. - return FALSE - - all_components.Remove(H.device_type) - - if(user) - to_chat(user, "You remove \the [H] from \the [src].") - - H.forceMove(get_turf(src)) - H.holder = null - H.on_remove(src, user) - if(enabled && !use_power()) - shutdown_computer() - update_icon() - - -// Checks all hardware pieces to determine if name matches, if yes, returns the hardware piece, otherwise returns null -/obj/item/modular_computer/proc/find_hardware_by_name(name) - for(var/i in all_components) - var/obj/O = all_components[i] - if(O.name == name) - return O - return null diff --git a/code/modules/modular_computers/computers/item/computer_damage.dm b/code/modules/modular_computers/computers/item/computer_damage.dm deleted file mode 100644 index 08a8ca6aaf4..00000000000 --- a/code/modules/modular_computers/computers/item/computer_damage.dm +++ /dev/null @@ -1,30 +0,0 @@ -/obj/item/modular_computer/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1) - . = ..() - var/component_probability = min(50, max(damage_amount*0.1, 1 - obj_integrity/max_integrity)) - switch(damage_flag) - if("bullet") - component_probability = damage_amount * 0.5 - if("laser") - component_probability = damage_amount * 0.66 - if(component_probability) - for(var/I in all_components) - var/obj/item/computer_hardware/H = all_components[I] - if(prob(component_probability)) - H.take_damage(round(damage_amount*0.5), damage_type, damage_flag, 0) - -/obj/item/modular_computer/deconstruct(disassembled = TRUE) - break_apart() - -/obj/item/modular_computer/proc/break_apart() - if(!(flags & NODECONSTRUCT)) - physical.visible_message("\The [src] breaks apart!") - var/turf/newloc = get_turf(src) - new /obj/item/stack/sheet/metal(newloc, round(steel_sheet_cost/2)) - for(var/C in all_components) - var/obj/item/computer_hardware/H = all_components[C] - uninstall_component(H) - H.forceMove(newloc) - if(prob(25)) - H.take_damage(rand(10,30), BRUTE, 0, 0) - relay_qdel() - qdel(src) diff --git a/code/modules/modular_computers/computers/item/computer_power.dm b/code/modules/modular_computers/computers/item/computer_power.dm deleted file mode 100644 index 27c81d48190..00000000000 --- a/code/modules/modular_computers/computers/item/computer_power.dm +++ /dev/null @@ -1,77 +0,0 @@ -// Tries to draw power from charger or, if no operational charger is present, from power cell. -/obj/item/modular_computer/proc/use_power(amount = 0) - if(check_power_override()) - return TRUE - - var/obj/item/computer_hardware/recharger/recharger = all_components[MC_CHARGE] - - if(recharger && recharger.check_functionality()) - if(recharger.use_power(amount)) - return TRUE - - var/obj/item/computer_hardware/battery/battery_module = all_components[MC_CELL] - - if(battery_module && battery_module.battery && battery_module.battery.charge) - var/obj/item/stock_parts/cell/cell = battery_module.battery - if(cell.use(amount * GLOB.CELLRATE)) - return TRUE - else // Discharge the cell anyway. - cell.use(min(amount*GLOB.CELLRATE, cell.charge)) - return FALSE - return FALSE - -/obj/item/modular_computer/proc/give_power(amount) - var/obj/item/computer_hardware/battery/battery_module = all_components[MC_CELL] - if(battery_module && battery_module.battery) - return battery_module.battery.give(amount) - return 0 - -/obj/item/modular_computer/get_cell() - var/obj/item/computer_hardware/battery/battery_module = all_components[MC_CELL] - if(battery_module && battery_module.battery) - return battery_module.battery - -// Used in following function to reduce copypaste -/obj/item/modular_computer/proc/power_failure() - if(enabled) // Shut down the computer - if(active_program) - active_program.event_powerfailure(0) - for(var/I in idle_threads) - var/datum/computer_file/program/PRG = I - PRG.event_powerfailure(1) - shutdown_computer(0) - -// Handles power-related things, such as battery interaction, recharging, shutdown when it's discharged -/obj/item/modular_computer/proc/handle_power() - var/obj/item/computer_hardware/recharger/recharger = all_components[MC_CHARGE] - if(recharger) - recharger.process() - - var/power_usage = screen_on ? base_active_power_usage : base_idle_power_usage - - for(var/obj/item/computer_hardware/H in all_components) - if(H.enabled) - power_usage += H.power_usage - - if(use_power(power_usage)) - last_power_usage = power_usage - return TRUE - else - power_failure() - return FALSE - -/obj/item/modular_computer/proc/get_power_eta() - var/obj/item/computer_hardware/battery/battery_module = all_components[MC_CELL] - if(battery_module && battery_module.battery) - var/hours = 0 - var/minutes = (battery_module.battery.charge) / (last_power_usage / 20) // 20 = obj processing interval - if(minutes > 60) - hours = minutes/60 - minutes = (hours - round(hours)) * 60 - var/seconds = (minutes - round(minutes)) * 60 - return list("hours" = hours, "minutes" = minutes, "seconds" = seconds) - return list() - -// Used by child types if they have other power source than battery or recharger -/obj/item/modular_computer/proc/check_power_override() - return FALSE diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm deleted file mode 100644 index 36df0243f54..00000000000 --- a/code/modules/modular_computers/computers/item/computer_ui.dm +++ /dev/null @@ -1,194 +0,0 @@ -// Operates NanoUI -/obj/item/modular_computer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - if(!enabled) - if(ui) - ui.close() - return 0 - if(!use_power()) - if(ui) - ui.close() - return 0 - - // Robots don't really need to see the screen, their wireless connection works as long as computer is on. - if(!screen_on && !issilicon(user)) - if(ui) - ui.close() - return 0 - - // If we have an active program switch to it now. - if(active_program) - if(ui) // This is the main laptop screen. Since we are switching to program's UI close it for now. - ui.close() - active_program.ui_interact(user) - return - - // We are still here, that means there is no program loaded. Load the BIOS/ROM/OS/whatever you want to call it. - // This screen simply lists available programs and user may select them. - var/obj/item/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD] - if(!hard_drive || !hard_drive.stored_files || !hard_drive.stored_files.len) - to_chat(user, "\The [src] beeps three times, it's screen displaying a \"DISK ERROR\" warning.") - return // No HDD, No HDD files list or no stored files. Something is very broken. - - 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, "computer_main.tmpl", "NTOS Main menu", 400, 500) - ui.set_auto_update(1) - ui.set_layout_key("program") - ui.open() - - -/obj/item/modular_computer/ui_data(mob/user) - var/list/data = get_header_data() - data["programs"] = list() - var/obj/item/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD] - for(var/datum/computer_file/program/P in hard_drive.stored_files) - var/running = 0 - if(P in idle_threads) - running = 1 - - data["programs"] += list(list("name" = P.filename, "desc" = P.filedesc, "running" = running)) - - return data - -// Function used by NanoUI's to obtain data for header. All relevant entries begin with "PC_" -/obj/item/modular_computer/proc/get_header_data() - var/list/data = list() - - var/obj/item/computer_hardware/battery/battery_module = all_components[MC_CELL] - var/obj/item/computer_hardware/recharger/recharger = all_components[MC_CHARGE] - - if(battery_module && battery_module.battery) - switch(battery_module.battery.percent()) - if(80 to 200) // 100 should be maximal but just in case.. - data["PC_batteryicon"] = "batt_100.gif" - if(60 to 80) - data["PC_batteryicon"] = "batt_80.gif" - if(40 to 60) - data["PC_batteryicon"] = "batt_60.gif" - if(20 to 40) - data["PC_batteryicon"] = "batt_40.gif" - if(5 to 20) - data["PC_batteryicon"] = "batt_20.gif" - else - data["PC_batteryicon"] = "batt_5.gif" - data["PC_batterypercent"] = "[round(battery_module.battery.percent())] %" - data["PC_showbatteryicon"] = 1 - else - data["PC_batteryicon"] = "batt_5.gif" - data["PC_batterypercent"] = "N/C" - data["PC_showbatteryicon"] = battery_module ? 1 : 0 - - if(recharger && recharger.enabled && recharger.check_functionality() && recharger.use_power(0)) - data["PC_apclinkicon"] = "charging.gif" - - switch(get_ntnet_status()) - if(0) - data["PC_ntneticon"] = "sig_none.gif" - if(1) - data["PC_ntneticon"] = "sig_low.gif" - if(2) - data["PC_ntneticon"] = "sig_high.gif" - if(3) - data["PC_ntneticon"] = "sig_lan.gif" - - if(idle_threads.len) - var/list/program_headers = list() - for(var/I in idle_threads) - var/datum/computer_file/program/P = I - if(!P.ui_header) - continue - program_headers.Add(list(list( - "icon" = P.ui_header - ))) - - data["PC_programheaders"] = program_headers - - data["PC_stationtime"] = station_time_timestamp() - data["PC_showexitprogram"] = active_program ? 1 : 0 // Hides "Exit Program" button on mainscreen - return data - - -// Handles user's GUI input -/obj/item/modular_computer/Topic(href, list/href_list) - if(..()) - return - var/obj/item/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD] - switch(href_list["action"]) - if("PC_exit") - kill_program() - return 1 - if("PC_shutdown") - shutdown_computer() - return 1 - if("PC_minimize") - var/mob/user = usr - if(!active_program || !all_components[MC_CPU]) - return 1 - - idle_threads.Add(active_program) - active_program.program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs - - active_program = null - update_icon() - if(user && istype(user)) - ui_interact(user) // Re-open the UI on this computer. It should show the main screen now. - - if("PC_killprogram") - var/prog = href_list["name"] - var/datum/computer_file/program/P = null - var/mob/user = usr - if(hard_drive) - P = hard_drive.find_file_by_name(prog) - - if(!istype(P) || P.program_state == PROGRAM_STATE_KILLED) - return 1 - - P.kill_program(forced = TRUE) - to_chat(user, "Program [P.filename].[P.filetype] with PID [rand(100,999)] has been killed.") - - if("PC_runprogram") - var/prog = href_list["name"] - var/datum/computer_file/program/P = null - var/mob/user = usr - if(hard_drive) - P = hard_drive.find_file_by_name(prog) - - if(!P || !istype(P)) // Program not found or it's not executable program. - to_chat(user, "\The [src]'s screen shows \"I/O ERROR - Unable to run program\" warning.") - return 1 - - P.computer = src - - if(!P.is_supported_by_hardware(hardware_flag, 1, user)) - return 1 - - // The program is already running. Resume it. - if(P in idle_threads) - P.program_state = PROGRAM_STATE_ACTIVE - active_program = P - idle_threads.Remove(P) - update_icon() - return - - var/obj/item/computer_hardware/processor_unit/PU = all_components[MC_CPU] - - if(idle_threads.len > PU.max_idle_programs) - to_chat(user, "\The [src] displays a \"Maximal CPU load reached. Unable to run another program.\" error.") - return 1 - - if(P.requires_ntnet && !get_ntnet_status(P.requires_ntnet_feature)) // The program requires NTNet connection, but we are not connected to NTNet. - to_chat(user, "\The [src]'s screen shows \"Unable to connect to NTNet. Please retry. If problem persists contact your system administrator.\" warning.") - return 1 - if(P.run_program(user)) - active_program = P - update_icon() - return 1 - else - return - -/obj/item/modular_computer/nano_host() - if(physical) - return physical - return src diff --git a/code/modules/modular_computers/computers/item/laptop.dm b/code/modules/modular_computers/computers/item/laptop.dm deleted file mode 100644 index 223627bd69e..00000000000 --- a/code/modules/modular_computers/computers/item/laptop.dm +++ /dev/null @@ -1,109 +0,0 @@ -/obj/item/modular_computer/laptop - name = "laptop" - desc = "A portable laptop computer." - - icon = 'icons/obj/modular_laptop.dmi' - icon_state = "laptop-closed" - icon_state_powered = "laptop" - icon_state_unpowered = "laptop-off" - icon_state_menu = "menu" - - hardware_flag = PROGRAM_LAPTOP - max_hardware_size = 2 - w_class = WEIGHT_CLASS_NORMAL - - flags = HANDSLOW // No running around with open laptops in hands. - - screen_on = 0 // Starts closed - var/start_open = 1 // unless this var is set to 1 - var/icon_state_closed = "laptop-closed" - var/w_class_open = WEIGHT_CLASS_BULKY - var/slowdown_open = 1 - -/obj/item/modular_computer/laptop/New() - ..() - if(start_open && !screen_on) - toggle_open() - -/obj/item/modular_computer/laptop/update_icon() - if(screen_on) - ..() - else - overlays.Cut() - icon_state = icon_state_closed - -/obj/item/modular_computer/laptop/attack_self(mob/user) - if(!screen_on) - try_toggle_open(user) - else - return ..() - -/obj/item/modular_computer/laptop/verb/open_computer() - set name = "Toggle Open" - set category = "Object" - set src in view(1) - - try_toggle_open(usr) - -/obj/item/modular_computer/laptop/MouseDrop(obj/over_object, src_location, over_location) - if(over_object == usr || over_object == src) - try_toggle_open(usr) - if(ishuman(usr)) - if(!isturf(loc) || !Adjacent(usr)) - return - if(over_object && !usr.incapacitated()) - if(!usr.canUnEquip(src)) - to_chat(usr, "[src] appears stuck on you!") - return - switch(over_object.name) - if("r_hand") - usr.unEquip(src) - usr.put_in_r_hand(src) - if("l_hand") - usr.unEquip(src) - usr.put_in_l_hand(src) - -/obj/item/modular_computer/laptop/attack_hand(mob/user) - if(screen_on && isturf(loc)) - return attack_self(user) - - return ..() - - -/obj/item/modular_computer/laptop/proc/try_toggle_open(mob/living/user) - if(issilicon(user)) - return - if(!isturf(loc) && !ismob(loc)) // No opening it in backpack. - return - if(user.incapacitated() || !Adjacent(user)) - return - - toggle_open(user) - - -/obj/item/modular_computer/laptop/AltClick(mob/user) - if(screen_on) // Close it. - try_toggle_open(user) - else - return ..() - -/obj/item/modular_computer/laptop/proc/toggle_open(mob/living/user=null) - if(screen_on) - if(user) - to_chat(user, "You close \the [src].") - slowdown = initial(slowdown) - w_class = initial(w_class) - else - if(user) - to_chat(user, "You open \the [src].") - slowdown = slowdown_open - w_class = w_class_open - - screen_on = !screen_on - update_icon() - - - -// Laptop frame, starts empty and closed. -/obj/item/modular_computer/laptop/buildable - start_open = 0 diff --git a/code/modules/modular_computers/computers/item/laptop_presets.dm b/code/modules/modular_computers/computers/item/laptop_presets.dm deleted file mode 100644 index 43720dfa2fc..00000000000 --- a/code/modules/modular_computers/computers/item/laptop_presets.dm +++ /dev/null @@ -1,21 +0,0 @@ -/obj/item/modular_computer/laptop/preset/New() - . = ..() - install_component(new /obj/item/computer_hardware/processor_unit/small) - install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer)) - install_component(new /obj/item/computer_hardware/hard_drive) - install_component(new /obj/item/computer_hardware/network_card) - install_programs() - - -/obj/item/modular_computer/laptop/preset/proc/install_programs() - return - - -/obj/item/modular_computer/laptop/preset/civillian - desc = "A low-end laptop often used for personal recreation." - - -/obj/item/modular_computer/laptop/preset/civillian/install_programs() - var/obj/item/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD] - hard_drive.store_file(new/datum/computer_file/program/chatclient()) - hard_drive.store_file(new/datum/computer_file/program/nttransfer()) diff --git a/code/modules/modular_computers/computers/item/processor.dm b/code/modules/modular_computers/computers/item/processor.dm deleted file mode 100644 index 3095e0af876..00000000000 --- a/code/modules/modular_computers/computers/item/processor.dm +++ /dev/null @@ -1,73 +0,0 @@ -// Held by /obj/machinery/modular_computer to reduce amount of copy-pasted code. -/obj/item/modular_computer/processor - name = "processing unit" - desc = "You shouldn't see this. If you do, report it." - icon = null - icon_state = null - icon_state_unpowered = null - icon_state_menu = null - hardware_flag = 0 - - var/obj/machinery/modular_computer/machinery_computer = null - -/obj/item/modular_computer/processor/Destroy() - . = ..() - if(machinery_computer && (machinery_computer.cpu == src)) - machinery_computer.cpu = null - machinery_computer = null - -/obj/item/modular_computer/processor/New(comp) - if(!comp || !istype(comp, /obj/machinery/modular_computer)) - CRASH("Inapropriate type passed to obj/item/modular_computer/processor/New()! Aborting.") - // Obtain reference to machinery computer - all_components = list() - idle_threads = list() - machinery_computer = comp - machinery_computer.cpu = src - hardware_flag = machinery_computer.hardware_flag - max_hardware_size = machinery_computer.max_hardware_size - steel_sheet_cost = machinery_computer.steel_sheet_cost - obj_integrity = machinery_computer.obj_integrity - max_integrity = machinery_computer.max_integrity - integrity_failure = machinery_computer.integrity_failure - base_active_power_usage = machinery_computer.base_active_power_usage - base_idle_power_usage = machinery_computer.base_idle_power_usage - -/obj/item/modular_computer/processor/relay_qdel() - qdel(machinery_computer) - -/obj/item/modular_computer/processor/update_icon() - if(machinery_computer) - return machinery_computer.update_icon() - -// This thing is not meant to be used on it's own, get topic data from our machinery owner. -//obj/item/modular_computer/processor/canUseTopic(user, state) -// if(!machinery_computer) -// return 0 - -// return machinery_computer.canUseTopic(user, state) - -/obj/item/modular_computer/processor/shutdown_computer() - if(!machinery_computer) - return - ..() - machinery_computer.update_icon() - return - -/obj/item/modular_computer/processor/add_verb(path) - switch(path) - if(MC_CARD) - machinery_computer.verbs += /obj/machinery/modular_computer/proc/eject_id - if(MC_SDD) - machinery_computer.verbs += /obj/machinery/modular_computer/proc/eject_disk - if(MC_AI) - machinery_computer.verbs += /obj/machinery/modular_computer/proc/eject_card - -/obj/item/modular_computer/processor/remove_verb(path) - switch(path) - if(MC_CARD) - machinery_computer.verbs -= /obj/machinery/modular_computer/proc/eject_id - if(MC_SDD) - machinery_computer.verbs -= /obj/machinery/modular_computer/proc/eject_disk - if(MC_AI) - machinery_computer.verbs -= /obj/machinery/modular_computer/proc/eject_card diff --git a/code/modules/modular_computers/computers/item/tablet.dm b/code/modules/modular_computers/computers/item/tablet.dm deleted file mode 100644 index f0a044b1d36..00000000000 --- a/code/modules/modular_computers/computers/item/tablet.dm +++ /dev/null @@ -1,12 +0,0 @@ -/obj/item/modular_computer/tablet //Its called tablet for theme of 90ies but actually its a "big smartphone" sized - name = "tablet computer" - icon = 'icons/obj/modular_tablet.dmi' - icon_state = "tablet" - icon_state_unpowered = "tablet" - icon_state_powered = "tablet" - icon_state_menu = "menu" - hardware_flag = PROGRAM_TABLET - max_hardware_size = 1 - w_class = WEIGHT_CLASS_SMALL - steel_sheet_cost = 1 - slot_flags = SLOT_ID | SLOT_BELT diff --git a/code/modules/modular_computers/computers/item/tablet_presets.dm b/code/modules/modular_computers/computers/item/tablet_presets.dm deleted file mode 100644 index 3ac32e30ca9..00000000000 --- a/code/modules/modular_computers/computers/item/tablet_presets.dm +++ /dev/null @@ -1,29 +0,0 @@ - -// This is literally the worst possible cheap tablet -/obj/item/modular_computer/tablet/preset/cheap - desc = "A low-end tablet often seen among low ranked station personnel." - -/obj/item/modular_computer/tablet/preset/cheap/New() - . = ..() - install_component(new /obj/item/computer_hardware/processor_unit/small) - install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer/micro)) - install_component(new /obj/item/computer_hardware/hard_drive/small) - install_component(new /obj/item/computer_hardware/network_card) - -// Alternative version, an average one, for higher ranked positions mostly -/obj/item/modular_computer/tablet/preset/advanced/New() - . = ..() - install_component(new /obj/item/computer_hardware/processor_unit/small) - install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer)) - install_component(new /obj/item/computer_hardware/hard_drive/small) - install_component(new /obj/item/computer_hardware/network_card) - install_component(new /obj/item/computer_hardware/card_slot) - install_component(new /obj/item/computer_hardware/printer/mini) - -/obj/item/modular_computer/tablet/preset/cargo/New() - . = ..() - install_component(new /obj/item/computer_hardware/processor_unit/small) - install_component(new /obj/item/computer_hardware/battery(src, /obj/item/stock_parts/cell/computer)) - install_component(new /obj/item/computer_hardware/hard_drive/small) - install_component(new /obj/item/computer_hardware/network_card) - install_component(new /obj/item/computer_hardware/printer/mini) diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm deleted file mode 100644 index 6b327fbdbcd..00000000000 --- a/code/modules/modular_computers/computers/machinery/console_presets.dm +++ /dev/null @@ -1,74 +0,0 @@ -/obj/machinery/modular_computer/console/preset - // Can be changed to give devices specific hardware - var/_has_id_slot = 0 - var/_has_printer = 0 - var/_has_battery = 0 - var/_has_ai = 0 - -/obj/machinery/modular_computer/console/preset/New() - . = ..() - if(!cpu) - return - cpu.install_component(new /obj/item/computer_hardware/processor_unit) - - if(_has_id_slot) - cpu.install_component(new /obj/item/computer_hardware/card_slot) - if(_has_printer) - cpu.install_component(new /obj/item/computer_hardware/printer) - if(_has_battery) - cpu.install_component(new /obj/item/computer_hardware/battery(cpu, /obj/item/stock_parts/cell/computer/super)) - if(_has_ai) - cpu.install_component(new /obj/item/computer_hardware/ai_slot) - install_programs() - -// Override in child types to install preset-specific programs. -/obj/machinery/modular_computer/console/preset/proc/install_programs() - return - - - -// ===== ENGINEERING CONSOLE ===== -/obj/machinery/modular_computer/console/preset/engineering - console_department = "Engineering" - desc = "A stationary computer. This one comes preloaded with engineering programs." - -/obj/machinery/modular_computer/console/preset/engineering/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/power_monitor()) -// hard_drive.store_file(new/datum/computer_file/program/alarm_monitor()) //TO-DO:TGUI--Uncomment Modular computers - hard_drive.store_file(new/datum/computer_file/program/supermatter_monitor()) - -// ===== RESEARCH CONSOLE ===== -/obj/machinery/modular_computer/console/preset/research - console_department = "Research" - desc = "A stationary computer. This one comes preloaded with research programs." - _has_ai = 1 - -/obj/machinery/modular_computer/console/preset/research/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/ntnetmonitor()) - hard_drive.store_file(new/datum/computer_file/program/nttransfer()) - hard_drive.store_file(new/datum/computer_file/program/chatclient()) - hard_drive.store_file(new/datum/computer_file/program/aidiag()) - - -// ===== COMMAND CONSOLE ===== -/obj/machinery/modular_computer/console/preset/command - console_department = "Command" - desc = "A stationary computer. This one comes preloaded with command programs." - _has_id_slot = 1 - _has_printer = 1 - -/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()) - -// ===== CIVILIAN CONSOLE ===== -/obj/machinery/modular_computer/console/preset/civilian - console_department = "Civilian" - desc = "A stationary computer. This one comes preloaded with generic programs." - -/obj/machinery/modular_computer/console/preset/civilian/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/nttransfer()) diff --git a/code/modules/modular_computers/computers/machinery/modular_computer.dm b/code/modules/modular_computers/computers/machinery/modular_computer.dm deleted file mode 100644 index 391396a7d75..00000000000 --- a/code/modules/modular_computers/computers/machinery/modular_computer.dm +++ /dev/null @@ -1,154 +0,0 @@ -// Global var to track modular computers -GLOBAL_LIST_EMPTY(global_modular_computers) - -// Modular Computer - device that runs various programs and operates with hardware -// DO NOT SPAWN THIS TYPE. Use /laptop/ or /console/ instead. -/obj/machinery/modular_computer - name = "modular computer" - desc = "An advanced computer." - - use_power = IDLE_POWER_USE - idle_power_usage = 5 - var/hardware_flag = 0 // A flag that describes this device type - var/last_power_usage = 0 // Power usage during last tick - - // Modular computers can run on various devices. Each DEVICE (Laptop, Console, Tablet,..) - // must have it's own DMI file. Icon states must be called exactly the same in all files, but may look differently - // If you create a program which is limited to Laptops and Consoles you don't have to add it's icon_state overlay for Tablets too, for example. - - icon = null - icon_state = null - var/icon_state_unpowered = null // Icon state when the computer is turned off. - var/icon_state_powered = null // Icon state when the computer is turned on. - var/screen_icon_state_menu = "menu" // Icon state overlay when the computer is turned on, but no program is loaded that would override the screen. - var/screen_icon_screensaver = "standby" // Icon state overlay when the computer is powered, but not 'switched on'. - var/max_hardware_size = 0 // Maximal hardware size. Currently, tablets have 1, laptops 2 and consoles 3. Limits what hardware types can be installed. - var/steel_sheet_cost = 10 // Amount of steel sheets refunded when disassembling an empty frame of this computer. - var/light_strength = 0 // Light luminosity when turned on - var/base_active_power_usage = 100 // Power usage when the computer is open (screen is active) and can be interacted with. Remember hardware can use power too. - var/base_idle_power_usage = 10 // Power usage when the computer is idle and screen is off (currently only applies to laptops) - - var/obj/item/modular_computer/processor/cpu = null // CPU that handles most logic while this type only handles power and other specific things. - -/obj/machinery/modular_computer/New() - ..() - cpu = new(src) - cpu.physical = src - GLOB.global_modular_computers.Add(src) - -/obj/machinery/modular_computer/Destroy() - QDEL_NULL(cpu) - return ..() - -/obj/machinery/modular_computer/attack_ghost(mob/dead/observer/user) - if(cpu) - cpu.attack_ghost(user) - -/obj/machinery/modular_computer/emag_act(mob/user) - return cpu ? cpu.emag_act(user) : 1 - -/obj/machinery/modular_computer/update_icon() - overlays.Cut() - icon_state = icon_state_powered - - if(!cpu || !cpu.enabled) - if (!(stat & NOPOWER) && (cpu && cpu.use_power())) - overlays += screen_icon_screensaver - else - icon_state = icon_state_unpowered - set_light(0) - else - set_light(light_strength) - if(cpu.active_program) - overlays += cpu.active_program.program_icon_state ? cpu.active_program.program_icon_state : screen_icon_state_menu - else - overlays += screen_icon_state_menu - - if(cpu && cpu.obj_integrity <= cpu.integrity_failure) - overlays += "bsod" - overlays += "broken" - -// Eject ID card from computer, if it has ID slot with card inside. -/obj/machinery/modular_computer/proc/eject_id() - set name = "Eject ID" - set category = "Object" - - if(cpu) - cpu.eject_id() - -// Eject ID card from computer, if it has ID slot with card inside. -/obj/machinery/modular_computer/proc/eject_disk() - set name = "Eject Data Disk" - set category = "Object" - - if(cpu) - cpu.eject_disk() - -/obj/machinery/modular_computer/proc/eject_card() - set name = "Eject Intellicard" - set category = "Object" - set src in view(1) - - if(cpu) - cpu.eject_card() - -/obj/machinery/modular_computer/AltClick(mob/user) - if(cpu) - cpu.AltClick(user) - -// On-click handling. Turns on the computer if it's off and opens the GUI. -/obj/machinery/modular_computer/attack_hand(mob/user) - if(cpu) - cpu.attack_self(user) // CPU is an item, that's why we route attack_hand to attack_self - -// Process currently calls handle_power(), may be expanded in future if more things are added. -/obj/machinery/modular_computer/process() - if(cpu) - // Keep names in sync. - cpu.name = src.name - cpu.process() - -// Used in following function to reduce copypaste -/obj/machinery/modular_computer/proc/power_failure(malfunction = 0) - var/obj/item/computer_hardware/battery/battery_module = cpu.all_components[MC_CELL] - if(cpu && cpu.enabled) // Shut down the computer - visible_message("\The [src]'s screen flickers [battery_module ? "\"BATTERY [malfunction ? "MALFUNCTION" : "CRITICAL"]\"" : "\"EXTERNAL POWER LOSS\""] warning as it shuts down unexpectedly.") - if(cpu) - cpu.shutdown_computer(0) - stat |= NOPOWER - update_icon() - - -// Modular computers can have battery in them, we handle power in previous proc, so prevent this from messing it up for us. -/obj/machinery/modular_computer/power_change() - if(cpu && cpu.use_power()) // If MC_CPU still has a power source, PC wouldn't go offline. - stat &= ~NOPOWER - update_icon() - return - ..() - update_icon() - -/obj/machinery/modular_computer/attackby(obj/item/W, mob/user) - if(cpu) - return cpu.attackby(W, user) - return ..() - - -// Stronger explosions cause serious damage to internal components -// Minor explosions are mostly mitigitated by casing. -/obj/machinery/modular_computer/ex_act(severity) - if(cpu) - cpu.ex_act(severity) - ..() - -// EMPs are similar to explosions, but don't cause physical damage to the casing. Instead they screw up the components -/obj/machinery/modular_computer/emp_act(severity) - if(cpu) - cpu.emp_act(severity) - -// "Stun" weapons can cause minor damage to components (short-circuits?) -// "Burn" damage is equally strong against internal components and exterior casing -// "Brute" damage mostly damages the casing. -/obj/machinery/modular_computer/bullet_act(obj/item/projectile/Proj) - if(cpu) - cpu.bullet_act(Proj) diff --git a/code/modules/modular_computers/computers/machinery/modular_console.dm b/code/modules/modular_computers/computers/machinery/modular_console.dm deleted file mode 100644 index e16ce82702c..00000000000 --- a/code/modules/modular_computers/computers/machinery/modular_console.dm +++ /dev/null @@ -1,53 +0,0 @@ -/obj/machinery/modular_computer/console - name = "console" - desc = "A stationary computer." - - icon = 'icons/obj/modular_console.dmi' - icon_state = "console" - icon_state_powered = "console" - icon_state_unpowered = "console-off" - screen_icon_state_menu = "menu" - hardware_flag = PROGRAM_CONSOLE - anchored = 1 - density = 1 - base_idle_power_usage = 100 - base_active_power_usage = 500 - max_hardware_size = 4 - steel_sheet_cost = 10 - light_strength = 2 - max_integrity = 300 - integrity_failure = 150 - - var/console_department = "" // Used in New() to set network tag according to our area. - var/components = TRUE // Install basic components? - -/obj/machinery/modular_computer/console/buildable - components = FALSE - -/obj/machinery/modular_computer/console/New() - ..() - var/obj/item/computer_hardware/battery/battery_module = cpu.all_components[MC_CELL] - if(battery_module) - qdel(battery_module) - - if(components) - var/obj/item/computer_hardware/network_card/wired/network_card = new() - - cpu.install_component(network_card) - cpu.install_component(new /obj/item/computer_hardware/recharger/APC) - cpu.install_component(new /obj/item/computer_hardware/hard_drive/super) // Consoles generally have better HDDs due to lower space limitations - - var/area/A = get_area(src) - // Attempts to set this console's tag according to our area. Since some areas have stuff like "XX - YY" in their names we try to remove that too. - if(A && console_department) - network_card.identification_string = replacetext(replacetext(replacetext("[A.name] [console_department] Console", " ", "_"), "-", ""), "__", "_") // Replace spaces with "_" - else if(A) - network_card.identification_string = replacetext(replacetext(replacetext("[A.name] Console", " ", "_"), "-", ""), "__", "_") - else if(console_department) - network_card.identification_string = replacetext(replacetext(replacetext("[console_department] Console", " ", "_"), "-", ""), "__", "_") - else - network_card.identification_string = "Unknown Console" - - if(cpu) - cpu.screen_on = 1 - update_icon() diff --git a/code/modules/modular_computers/documentation.md b/code/modules/modular_computers/documentation.md deleted file mode 100644 index 3172b349bce..00000000000 --- a/code/modules/modular_computers/documentation.md +++ /dev/null @@ -1,44 +0,0 @@ - - -#Modular computer programs -Ok. so a quick rundown on how to make a program. This is kind of a shitty documentation, but oh well I was asked to. - - -## Base setup -This is how the base program is setup. the rest is mostly tgui stuff. I'll use the ntnetmonitor as a base - - -```DM -/datum/computer_file/program/ntnetmonitor - filename = "ntmonitor" //This is obviously the name of the file itself. not much to be said - filedesc = "NTNet Diagnostics and Monitoring" // This is sort of the official name. it's what shows up on the main menu - program_icon_state = "comm_monitor" // This is what the screen will look like when the program is active - extended_desc = "This program is a dummy. // This is a sort of a description, visible when looking on the ntnet - size = 12 // size of the program. Big programs need more hard drive space. Don't make it too big though. - requires_ntnet = 1 // If this is set, the program will not run without an ntnet connection, and will close if the connection is lost. Mainly for primarily online programs. - required_access = ACCESS_NETWORK //This is access required to run the program itself. ONLY SET THIS FOR SUPER SECURE SHIT. This also acts as transfer_access as well. - transfer_access = ACCESS_CHANGE_IDS // This is the access needed to download from ntnet or host on the ptp program. This is what you want to use most of the time. - available_on_ntnet = 1 //If it's available to download on ntnet. pretty self explanatory. - available_on_syndinet = 0 // ditto but on emagged syndie net. Use this for antag programs - usage_flags = PROGRAM_ALL // Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL - //^^- The comment above sorta explains it. Use this to limit what kind of machines can run the program. For example, comms program should be limited to consoles and laptops. - var/ui_header = "downloader_finished.gif" //This one is kinda cool. If you have the program minimized, this will show up in the header of the computer screen. - //you can even have the program change what the header is based on the situation! see alarm.dm for an example. -``` - -##Preinstalls -Now. for pre-installing stuff. - -Primarily done for consoles, there's an install_programs() proc in the console presets file in the machines folder. - -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()) -``` -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. - -Will probably be expanded when new features come around or I get asked to mention something. - diff --git a/code/modules/modular_computers/file_system/computer_file.dm b/code/modules/modular_computers/file_system/computer_file.dm deleted file mode 100644 index b3f8064b72a..00000000000 --- a/code/modules/modular_computers/file_system/computer_file.dm +++ /dev/null @@ -1,50 +0,0 @@ -GLOBAL_VAR_INIT(file_uid, 0) - -/datum/computer_file - var/filename = "NewFile" // Placeholder. No spacebars - var/filetype = "XXX" // File full names are [filename].[filetype] so like NewFile.XXX in this case - var/size = 1 // File size in GQ. Integers only! - var/obj/item/computer_hardware/hard_drive/holder // Holder that contains this file. - var/unsendable = 0 // Whether the file may be sent to someone via NTNet transfer or other means. - var/undeletable = 0 // Whether the file may be deleted. Setting to 1 prevents deletion/renaming/etc. - var/uid // UID of this file - var/password = "" // Placeholder for password. - -/datum/computer_file/New() - ..() - uid = GLOB.file_uid - GLOB.file_uid++ - -/datum/computer_file/Destroy() - if(!holder) - return ..() - - holder.remove_file(src) - // holder.holder is the computer that has drive installed. If we are Destroy()ing program that's currently running kill it. - if(holder.holder && holder.holder.active_program == src) - holder.holder.kill_program(forced = TRUE) - holder = null - return ..() - -// Returns independent copy of this file. -/datum/computer_file/proc/clone(rename = 0) - var/datum/computer_file/temp = new type - temp.unsendable = unsendable - temp.undeletable = undeletable - temp.size = size - if(rename) - temp.filename = filename + "(Copy)" - else - temp.filename = filename - temp.filetype = filetype - temp.password = password - return temp - -/datum/computer_file/proc/can_access_file(mob/user, input_password = "") - if(!password) - return TRUE - if(!input_password) - input_password = sanitize(input(user, "Please enter a password to access file '[filename]':")) - if(input_password == password) - return TRUE - return FALSE diff --git a/code/modules/modular_computers/file_system/data.dm b/code/modules/modular_computers/file_system/data.dm deleted file mode 100644 index 32ef6f53dd1..00000000000 --- a/code/modules/modular_computers/file_system/data.dm +++ /dev/null @@ -1,20 +0,0 @@ -// /data/ files store data in string format. -// They don't contain other logic for now. -/datum/computer_file/data - var/stored_data = "" // Stored data in string format. - filetype = "DAT" - var/block_size = 250 - var/do_not_edit = 0 // Whether the user will be reminded that the file probably shouldn't be edited. - -/datum/computer_file/data/clone() - var/datum/computer_file/data/temp = ..() - temp.stored_data = stored_data - return temp - -// Calculates file size from amount of characters in saved string -/datum/computer_file/data/proc/calculate_size() - size = max(1, round(length(stored_data) / block_size)) - -/datum/computer_file/data/logfile - filetype = "LOG" - diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm deleted file mode 100644 index 6f779312c15..00000000000 --- a/code/modules/modular_computers/file_system/program.dm +++ /dev/null @@ -1,200 +0,0 @@ -// /program/ files are executable programs that do things. -/datum/computer_file/program - filetype = "PRG" - filename = "UnknownProgram" // File name. FILE NAME MUST BE UNIQUE IF YOU WANT THE PROGRAM TO BE DOWNLOADABLE FROM NTNET! - var/required_access = null // List of required accesses to *run* the program. - var/transfer_access = null // List of required access to download or file host the program - var/program_state = PROGRAM_STATE_KILLED// PROGRAM_STATE_KILLED or PROGRAM_STATE_BACKGROUND or PROGRAM_STATE_ACTIVE - specifies whether this program is running. - var/obj/item/modular_computer/computer // Device that runs this program. - var/filedesc = "Unknown Program" // User-friendly name of this program. - var/extended_desc = "N/A" // Short description of this program's function. - var/program_icon_state = null // Program-specific screen icon state - var/requires_ntnet = 0 // Set to 1 for program to require nonstop NTNet connection to run. If NTNet connection is lost program crashes. - var/requires_ntnet_feature = 0 // Optional, if above is set to 1 checks for specific function of NTNet (currently NTNET_SOFTWAREDOWNLOAD, NTNET_PEERTOPEER, NTNET_SYSTEMCONTROL and NTNET_COMMUNICATION) - var/ntnet_status = 1 // NTNet status, updated every tick by computer running this program. Don't use this for checks if NTNet works, computers do that. Use this for calculations, etc. - var/usage_flags = PROGRAM_ALL // Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL - var/network_destination = null // Optional string that describes what NTNet server/system this program connects to. Used in default logging. - var/available_on_ntnet = 1 // Whether the program can be downloaded from NTNet. Set to 0 to disable. - var/available_on_syndinet = 0 // Whether the program can be downloaded from SyndiNet (accessible via emagging the computer). Set to 1 to enable. - var/ui_header = null // Example: "something.gif" - a header image that will be rendered in computer's UI when this program is running at background. Images are taken from /icons/program_icons. Be careful not to use too large images! - -/datum/computer_file/program/New(obj/item/modular_computer/comp = null) - ..() - if(comp && istype(comp)) - computer = comp - -/datum/computer_file/program/Destroy() - computer = null - . = ..() - -/datum/computer_file/program/clone() - var/datum/computer_file/program/temp = ..() - temp.required_access = required_access - temp.filedesc = filedesc - temp.program_icon_state = program_icon_state - temp.requires_ntnet = requires_ntnet - temp.requires_ntnet_feature = requires_ntnet_feature - temp.usage_flags = usage_flags - return temp - -// Relays icon update to the computer. -/datum/computer_file/program/proc/update_computer_icon() - if(computer) - computer.update_icon() - -// Attempts to create a log in global ntnet datum. Returns 1 on success, 0 on fail. -/datum/computer_file/program/proc/generate_network_log(text) - if(computer) - return computer.add_log(text) - return 0 - -/datum/computer_file/program/proc/is_supported_by_hardware(hardware_flag = 0, loud = 0, mob/user = null) - if(!(hardware_flag & usage_flags)) - if(loud && computer && user) - to_chat(user, "\The [computer] flashes an \"Hardware Error - Incompatible software\" warning.") - return 0 - return 1 - -/datum/computer_file/program/proc/get_signal(specific_action = 0) - if(computer) - return computer.get_ntnet_status(specific_action) - return 0 - -// Called by Process() on device that runs us, once every tick. -/datum/computer_file/program/proc/process_tick() - return 1 - -// Check if the user can run program. Only humans can operate computer. Automatically called in run_program() -// User has to wear their ID for ID Scan to work. -// Can also be called manually, with optional parameter being access_to_check to scan the user's ID -/datum/computer_file/program/proc/can_run(mob/user, loud = 0, access_to_check, transfer = 0) - // Defaults to required_access - if(!access_to_check) - if(transfer && transfer_access) - access_to_check = transfer_access - else - access_to_check = required_access - if(!access_to_check) // No required_access, allow it. - return 1 - - if(!transfer && computer && computer.emagged) //emags can bypass the execution locks but not the download ones. - return 1 - - if(user.can_admin_interact()) - return 1 - - if(issilicon(user)) - return 1 - - if(ishuman(user)) - var/obj/item/card/id/D - var/obj/item/computer_hardware/card_slot/card_slot - if(computer && card_slot) - card_slot = computer.all_components[MC_CARD] - D = card_slot.GetID() - var/mob/living/carbon/human/h = user - var/obj/item/card/id/I = h.get_idcard() - var/obj/item/card/id/C = h.get_active_hand() - if(C) - C = C.GetID() - if(!(C && istype(C))) - C = null - - if(!I && !C && !D) - if(loud) - to_chat(user, "\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning.") - return 0 - - if(I) - if(access_to_check in I.GetAccess()) - return 1 - else if(C) - if(access_to_check in C.GetAccess()) - return 1 - else if(D) - if(access_to_check in D.GetAccess()) - return 1 - if(loud) - to_chat(user, "\The [computer] flashes an \"Access Denied\" warning.") - return 0 - -// This attempts to retrieve header data for UIs. If implementing completely new device of different type than existing ones -// always include the device here in this proc. This proc basically relays the request to whatever is running the program. -/datum/computer_file/program/proc/get_header_data() - if(computer) - return computer.get_header_data() - return list() - -// This is performed on program startup. May be overriden to add extra logic. Remember to include ..() call. Return 1 on success, 0 on failure. -// When implementing new program based device, use this to run the program. -/datum/computer_file/program/proc/run_program(mob/living/user) - if(can_run(user, 1)) - if(requires_ntnet && network_destination) - generate_network_log("Connection opened to [network_destination].") - program_state = PROGRAM_STATE_ACTIVE - return 1 - return 0 - -// Use this proc to kill the program. Designed to be implemented by each program if it requires on-quit logic, such as the NTNRC client. -/datum/computer_file/program/proc/kill_program(forced = FALSE) - program_state = PROGRAM_STATE_KILLED - computer.update_icon() - if(network_destination) - generate_network_log("Connection to [network_destination] closed.") - return 1 - -// This is called every tick when the program is enabled. Ensure you do parent call if you override it. If parent returns 1 continue with UI initialisation. - -/datum/computer_file/program/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) - if(program_state != PROGRAM_STATE_ACTIVE) // Our program was closed. Close the ui if it exists. - return computer.ui_interact(user) - return 1 - - -// CONVENTIONS, READ THIS WHEN CREATING NEW PROGRAM AND OVERRIDING THIS PROC: -// Topic calls are automagically forwarded from NanoModule this program contains. -// Calls beginning with "PRG_" are reserved for programs handling. -// Calls beginning with "PC_" are reserved for computer handling (by whatever runs the program) -// ALWAYS INCLUDE PARENT CALL ..() OR DIE IN FIRE. -/datum/computer_file/program/Topic(href, list/href_list) - if(..()) - return 1 - - var/datum/nanoui/ui = SSnanoui.get_open_ui(usr, src, "main") - - if(computer) - switch(href_list["action"]) - if("PC_exit") - computer.kill_program() - ui.close() - return 1 - if("PC_shutdown") - computer.shutdown_computer() - ui.close() - return 1 - if("PC_minimize") - var/mob/user = usr - if(!computer.active_program || !computer.all_components[MC_CPU]) - return - - computer.idle_threads.Add(computer.active_program) - program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs - - computer.active_program = null - computer.update_icon() - ui.close() - - if(user && istype(user)) - computer.ui_interact(user) // Re-open the UI on this computer. It should show the main screen now. - - -/datum/computer_file/program/nano_host() - if(computer.physical) - return computer.physical - else - return computer - -/datum/computer_file/program/CanUseTopic(mob/user) - if(program_state != PROGRAM_STATE_ACTIVE) // Our program was closed. Close the ui if it exists. - return STATUS_CLOSE - return ..() diff --git a/code/modules/modular_computers/file_system/program_events.dm b/code/modules/modular_computers/file_system/program_events.dm deleted file mode 100644 index 279d646cfd7..00000000000 --- a/code/modules/modular_computers/file_system/program_events.dm +++ /dev/null @@ -1,18 +0,0 @@ -// Events are sent to the program by the computer. -// Always include a parent call when overriding an event. - -// Called when the ID card is removed from computer. ID is removed AFTER this proc. -/datum/computer_file/program/proc/event_idremoved(background, slot) - return - -// Called when the computer fails due to power loss. Override when program wants to specifically react to power loss. -/datum/computer_file/program/proc/event_powerfailure(background) - kill_program(forced = TRUE) - -// Called when the network connectivity fails. Computer does necessary checks and only calls this when requires_ntnet_feature and similar variables are not met. -/datum/computer_file/program/proc/event_networkfailure(background) - kill_program(forced = TRUE) - if(background) - computer.visible_message("\The [computer]'s screen displays an \"Process [filename].[filetype] (PID [rand(100,999)]) terminated - Network Error\" error") - else - computer.visible_message("\The [computer]'s screen briefly freezes and then shows \"NETWORK ERROR - NTNet connection lost. Please retry. If problem persists contact your system administrator.\" error.") diff --git a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm deleted file mode 100644 index f6bc293db7d..00000000000 --- a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm +++ /dev/null @@ -1,103 +0,0 @@ -/datum/computer_file/program/ntnet_dos - filename = "ntn_dos" - filedesc = "DoS Traffic Generator" - program_icon_state = "hostile" - extended_desc = "This advanced script can perform denial of service attacks against NTNet quantum relays. The system administrator will probably notice this. Multiple devices can run this program together against same relay for increased effect" - size = 20 - requires_ntnet = 1 - available_on_ntnet = 0 - available_on_syndinet = 1 - var/obj/machinery/ntnet_relay/target = null - var/dos_speed = 0 - var/error = "" - var/executed = 0 - -/datum/computer_file/program/ntnet_dos/process_tick() - dos_speed = 0 - switch(ntnet_status) - if(1) - dos_speed = NTNETSPEED_LOWSIGNAL * 10 - if(2) - dos_speed = NTNETSPEED_HIGHSIGNAL * 10 - if(3) - dos_speed = NTNETSPEED_ETHERNET * 10 - if(target && executed) - target.dos_overload += dos_speed - if(target.inoperable()) - target.dos_sources.Remove(src) - target = null - error = "Connection to destination relay lost." - -/datum/computer_file/program/ntnet_dos/kill_program(forced = FALSE) - if(target) - target.dos_sources.Remove(src) - target = null - executed = 0 - ..() - -/datum/computer_file/program/ntnet_dos/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, "ntnet_dos.tmpl", "DoS Traffic Generator", 575, 250) - ui.set_auto_update(1) - ui.set_layout_key("program") - ui.open() - - -/datum/computer_file/program/ntnet_dos/Topic(href, list/href_list) - if(..()) - return 1 - switch(href_list["action"]) - if("PRG_target_relay") - for(var/obj/machinery/ntnet_relay/R in GLOB.ntnet_global.relays) - if("[R.uid]" == href_list["targid"]) - target = R - return 1 - if("PRG_reset") - if(target) - target.dos_sources.Remove(src) - target = null - executed = 0 - error = "" - return 1 - if("PRG_execute") - if(target) - executed = 1 - target.dos_sources.Add(src) - if(GLOB.ntnet_global.intrusion_detection_enabled) - var/obj/item/computer_hardware/network_card/network_card = computer.all_components[MC_NET] - GLOB.ntnet_global.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [network_card.get_network_tag()]") - GLOB.ntnet_global.intrusion_detection_alarm = 1 - return 1 - -/datum/computer_file/program/ntnet_dos/ui_data(mob/user) - if(!GLOB.ntnet_global) - return - - var/list/data = get_header_data() - - if(error) - data["error"] = error - else if(target && executed) - data["target"] = 1 - data["speed"] = dos_speed - - // This is mostly visual, generate some strings of 1s and 0s - // Probability of 1 is equal of completion percentage of DoS attack on this relay. - // Combined with UI updates this adds quite nice effect to the UI - var/percentage = target.dos_overload * 100 / target.dos_capacity - data["dos_strings"] = list() - for(var/j, j<10, j++) - var/string = "" - for(var/i, i<20, i++) - string = "[string][prob(percentage)]" - data["dos_strings"] += list(list("nums" = string)) - else - data["relays"] = list() - for(var/obj/machinery/ntnet_relay/R in GLOB.ntnet_global.relays) - data["relays"] += list(list("id" = R.uid)) - data["focus"] = target ? target.uid : null - - return data diff --git a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm deleted file mode 100644 index 42f722af799..00000000000 --- a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm +++ /dev/null @@ -1,74 +0,0 @@ -/datum/computer_file/program/revelation - filename = "revelation" - filedesc = "Revelation" - program_icon_state = "hostile" - extended_desc = "This virus can destroy hard drive of system it is executed on. It may be obfuscated to look like another non-malicious program. Once armed, it will destroy the system upon next execution." - size = 13 - requires_ntnet = 0 - available_on_ntnet = 0 - available_on_syndinet = 1 - var/armed = 0 - -/datum/computer_file/program/revelation/run_program(var/mob/living/user) - . = ..(user) - if(armed) - activate() - -/datum/computer_file/program/revelation/proc/activate() - if(computer) - computer.visible_message("\The [computer]'s screen brightly flashes and loud electrical buzzing is heard.") - computer.enabled = 0 - computer.update_icon() - var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD] - var/obj/item/computer_hardware/battery/battery_module = computer.all_components[MC_CELL] - var/obj/item/computer_hardware/recharger/recharger = computer.all_components[MC_CHARGE] - qdel(hard_drive) - computer.take_damage(25, BRUTE, 0, 0) - if(battery_module && prob(25)) - qdel(battery_module) - computer.visible_message("\The [computer]'s battery explodes in rain of sparks.") - do_sparks(5, 0, computer.loc) - - if(recharger && prob(50)) - qdel(recharger) - computer.visible_message("\The [computer]'s recharger explodes in rain of sparks.") - do_sparks(5, 0, computer.loc) - - -/datum/computer_file/program/revelation/Topic(href, list/href_list) - if(..()) - return 1 - switch(href_list["action"]) - if("PRG_arm") - armed = !armed - if("PRG_activate") - activate() - if("PRG_obfuscate") - var/mob/living/user = usr - var/newname = sanitize(input(user, "Enter new program name: ")) - if(!newname) - return - filedesc = newname - - -/datum/computer_file/program/revelation/clone() - var/datum/computer_file/program/revelation/temp = ..() - temp.armed = armed - return temp - -/datum/computer_file/program/revelation/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, "revelation.tmpl", "Revelation Virus", 575, 250) - ui.set_auto_update(1) - ui.set_layout_key("program") - ui.open() - -/datum/computer_file/program/revelation/ui_data(mob/user) - var/list/data = get_header_data() - - data["armed"] = armed - - return data diff --git a/code/modules/modular_computers/file_system/programs/engineering/alarm.dm b/code/modules/modular_computers/file_system/programs/engineering/alarm.dm deleted file mode 100644 index 2f2f4a08232..00000000000 --- a/code/modules/modular_computers/file_system/programs/engineering/alarm.dm +++ /dev/null @@ -1,77 +0,0 @@ -/datum/computer_file/program/alarm_monitor - filename = "alarmmonitor" - filedesc = "Alarm Monitoring" - ui_header = "alarm_green.gif" - program_icon_state = "alert-green" - extended_desc = "This program provides visual interface for station's alarm system." - requires_ntnet = 1 - network_destination = "alarm monitoring network" - size = 5 - var/tgui_id = "NtosStationAlertConsole" - var/ui_x = 315 - var/ui_y = 500 - var/has_alert = 0 - var/list/alarms_listend_for = list("Fire", "Atmosphere", "Power") - -/datum/computer_file/program/alarm_monitor/process_tick() - ..() - - if(has_alert) - program_icon_state = "alert-red" - ui_header = "alarm_red.gif" - update_computer_icon() - else - program_icon_state = "alert-green" - ui_header = "alarm_green.gif" - update_computer_icon() - return TRUE - -/datum/computer_file/program/alarm_monitor/tgui_data(mob/user) - var/list/data = get_header_data() - - data["alarms"] = list() - for(var/class in SSalarm.alarms) - if(!(class in alarms_listend_for)) - continue - data["alarms"][class] = list() - for(var/area in alarms[class]) - data["alarms"][class] += area - - return data - -/datum/computer_file/program/alarm_monitor/proc/alarm_triggered(src, class, area/A, list/O, obj/alarmsource) - if(is_station_level(alarmsource.z)) - if(!(A.type in GLOB.the_station_areas)) - return - else if(!is_mining_level(alarmsource.z) || istype(A, /area/ruin)) - return - update_alarm_display() - -/datum/computer_file/program/alarm_monitor/proc/alarm_cancelled(src, class, area/A, obj/origin, cleared) - if(is_station_level(origin.z)) - if(!(A.type in GLOB.the_station_areas)) - return - else if(!is_mining_level(origin.z) || istype(A, /area/ruin)) - return - update_alarm_display() - -/datum/computer_file/program/alarm_monitor/proc/update_alarm_display() - has_alert = FALSE - for(var/cat in alarms) - if(!(cat in alarms_listend_for)) - continue - var/list/L = alarms[cat] - if(length(L)) - has_alert = TRUE - -/datum/computer_file/program/alarm_monitor/run_program(mob/user) - . = ..(user) - GLOB.alarmdisplay += src - RegisterSignal(SSalarm, COMSIG_TRIGGERED_ALARM, .proc/alarm_triggered) - RegisterSignal(SSalarm, COMSIG_CANCELLED_ALARM, .proc/alarm_cancelled) - -/datum/computer_file/program/alarm_monitor/kill_program(forced = FALSE) - GLOB.alarmdisplay -= src - UnregisterSignal(SSalarm, COMSIG_TRIGGERED_ALARM) - UnregisterSignal(SSalarm, COMSIG_CANCELLED_ALARM) - ..() diff --git a/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm deleted file mode 100644 index 0763d527345..00000000000 --- a/code/modules/modular_computers/file_system/programs/engineering/power_monitor.dm +++ /dev/null @@ -1,48 +0,0 @@ -/datum/computer_file/program/power_monitor - filename = "powermonitor" - filedesc = "Power Monitoring" - program_icon_state = "power_monitor" - extended_desc = "This program connects to sensors around the station to provide information about electrical systems" - ui_header = "power_norm.gif" - transfer_access = ACCESS_ENGINE - usage_flags = PROGRAM_CONSOLE - requires_ntnet = 0 - network_destination = "power monitoring system" - size = 9 - var/obj/structure/cable/attached - -/datum/computer_file/program/power_monitor/run_program(mob/living/user) - . = ..(user) - search() - -/datum/computer_file/program/power_monitor/process_tick() - if(!attached) - search() - -/datum/computer_file/program/power_monitor/proc/search() - var/turf/T = get_turf(computer) - attached = locate() in T - -/datum/computer_file/program/power_monitor/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, "power_monitor.tmpl", "Alarm Monitoring", 800, 700) - ui.set_auto_update(1) - ui.set_layout_key("program") - ui.open() - -/datum/computer_file/program/power_monitor/ui_data() - var/list/data = get_header_data() - - data["powermonitor"] = attached ? TRUE : FALSE - - if(attached) - var/datum/powernet/powernet = attached.powernet - data["poweravail"] = powernet.avail - data["powerload"] = powernet.viewload - data["powerdemand"] = powernet.load - data["apcs"] = GLOB.apc_repository.apc_data(powernet) - - return data diff --git a/code/modules/modular_computers/file_system/programs/engineering/sm_monitor.dm b/code/modules/modular_computers/file_system/programs/engineering/sm_monitor.dm deleted file mode 100644 index 0045b36f30e..00000000000 --- a/code/modules/modular_computers/file_system/programs/engineering/sm_monitor.dm +++ /dev/null @@ -1,137 +0,0 @@ -/datum/computer_file/program/supermatter_monitor - filename = "smmonitor" - filedesc = "Supermatter Monitoring" - ui_header = "smmon_0.gif" - program_icon_state = "smmon_0" - extended_desc = "This program connects to specially calibrated supermatter sensors to provide information on the status of supermatter-based engines." - requires_ntnet = TRUE - transfer_access = ACCESS_CONSTRUCTION - network_destination = "supermatter monitoring system" - size = 5 - var/last_status = SUPERMATTER_INACTIVE - var/list/supermatters - var/obj/machinery/power/supermatter_shard/active // Currently selected supermatter crystal. - - -/datum/computer_file/program/supermatter_monitor/process_tick() - ..() - var/new_status = get_status() - if(last_status != new_status) - last_status = new_status - if(last_status == SUPERMATTER_ERROR) - last_status = SUPERMATTER_INACTIVE - ui_header = "smmon_[last_status].gif" - program_icon_state = "smmon_[last_status]" - if(istype(computer)) - computer.update_icon() - -/datum/computer_file/program/supermatter_monitor/run_program(mob/living/user) - . = ..(user) - refresh() - -/datum/computer_file/program/supermatter_monitor/kill_program(forced = FALSE) - active = null - supermatters = null - ..() - -// Refreshes list of active supermatter crystals -/datum/computer_file/program/supermatter_monitor/proc/refresh() - supermatters = list() - var/turf/T = get_turf(nano_host()) - if(!T) - return - for(var/obj/machinery/power/supermatter_shard/S in SSair.atmos_machinery) - // Delaminating, not within coverage, not on a tile. - if(!(is_station_level(S.z) || is_mining_level(S.z) || atoms_share_level(S, T) || !istype(S.loc, /turf/simulated/))) - continue - supermatters.Add(S) - - if(!(active in supermatters)) - active = null - -/datum/computer_file/program/supermatter_monitor/proc/get_status() - . = SUPERMATTER_INACTIVE - for(var/obj/machinery/power/supermatter_shard/S in supermatters) - . = max(., S.get_status()) - -/datum/computer_file/program/supermatter_monitor/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, "supermatter_monitor.tmpl", "Supermatter Monitoring", 600, 400) - ui.set_auto_update(TRUE) - ui.set_layout_key("program") - ui.open() - -/datum/computer_file/program/supermatter_monitor/ui_data() - var/list/data = get_header_data() - - if(istype(active)) - var/turf/T = get_turf(active) - if(!T) - active = null - refresh() - return - var/datum/gas_mixture/air = T.return_air() - if(!air) - active = null - return - - data["active"] = TRUE - data["SM_integrity"] = active.get_integrity() - data["SM_power"] = active.power - data["SM_ambienttemp"] = air.temperature - data["SM_ambientpressure"] = air.return_pressure() - //data["SM_EPR"] = round((air.total_moles / air.group_multiplier) / 23.1, 0.01) - var/other_moles = air.total_trace_moles() - var/TM = air.total_moles() - if(TM) - data["SM_gas_O2"] = round(100*air.oxygen/TM,0.01) - data["SM_gas_CO2"] = round(100*air.carbon_dioxide/TM,0.01) - data["SM_gas_N2"] = round(100*air.nitrogen/TM,0.01) - data["SM_gas_PL"] = round(100*air.toxins/TM,0.01) - if(other_moles) - data["SM_gas_OTHER"] = round(100 * other_moles / TM, 0.01) - else - data["SM_gas_OTHER"] = 0 - else - data["SM_gas_O2"] = 0 - data["SM_gas_CO2"] = 0 - data["SM_gas_N2"] = 0 - data["SM_gas_PH"] = 0 - data["SM_gas_OTHER"] = 0 - else - var/list/SMS = list() - for(var/obj/machinery/power/supermatter_shard/S in supermatters) - var/area/A = get_area(S) - if(!A) - continue - - SMS.Add(list(list( - "area_name" = A.name, - "integrity" = S.get_integrity(), - "uid" = S.uid - ))) - - data["active"] = FALSE - data["supermatters"] = SMS - - return data - - -/datum/computer_file/program/supermatter_monitor/Topic(href, href_list) - if(..()) - return TRUE - if(href_list["clear"]) - active = null - return TRUE - if(href_list["refresh"]) - refresh() - return TRUE - if(href_list["set"]) - var/newuid = text2num(href_list["set"]) - for(var/obj/machinery/power/supermatter_shard/S in supermatters) - if(S.uid == newuid) - active = S - return TRUE diff --git a/code/modules/modular_computers/file_system/programs/generic/configurator.dm b/code/modules/modular_computers/file_system/programs/generic/configurator.dm deleted file mode 100644 index 70ce4656b9c..00000000000 --- a/code/modules/modular_computers/file_system/programs/generic/configurator.dm +++ /dev/null @@ -1,68 +0,0 @@ -// This is special hardware configuration program. -// It is to be used only with modular computers. -// It allows you to toggle components of your device. - -/datum/computer_file/program/computerconfig - filename = "compconfig" - filedesc = "Computer Configuration Tool" - extended_desc = "This program allows configuration of computer's hardware" - program_icon_state = "generic" - unsendable = 1 - undeletable = 1 - size = 4 - available_on_ntnet = 0 - requires_ntnet = 0 - - -/datum/computer_file/program/computerconfig/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, "laptop_configuration.tmpl", "NTOS Configuration Utility", 575, 700) - ui.set_auto_update(1) - ui.set_layout_key("program") - ui.open() - -/datum/computer_file/program/computerconfig/ui_data(mob/user) - var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD] - var/obj/item/computer_hardware/battery/battery_module = computer.all_components[MC_CELL] - - var/list/data = get_header_data() - - data["disk_size"] = hard_drive.max_capacity - data["disk_used"] = hard_drive.used_capacity - data["power_usage"] = computer.last_power_usage - data["battery_exists"] = battery_module ? 1 : 0 - if(battery_module && battery_module.battery) - data["battery_rating"] = battery_module.battery.maxcharge - data["battery_percent"] = round(battery_module.battery.percent()) - data["eta"] = computer.get_power_eta() - - if(battery_module && battery_module.battery) - data["battery"] = list("max" = battery_module.battery.maxcharge, "charge" = round(battery_module.battery.charge)) - - var/list/all_entries[0] - for(var/I in computer.all_components) - var/obj/item/computer_hardware/H = computer.all_components[I] - all_entries.Add(list(list( - "name" = H.name, - "desc" = H.desc, - "enabled" = H.enabled, - "critical" = H.critical, - "powerusage" = H.power_usage - ))) - - data["hardware"] = all_entries - return data - - -/datum/computer_file/program/computerconfig/Topic(href, list/href_list) - if(..()) - return - switch(href_list["action"]) - if("PC_toggle_component") - var/obj/item/computer_hardware/H = computer.find_hardware_by_name(href_list["name"]) - if(H && istype(H)) - H.enabled = !H.enabled - . = TRUE diff --git a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm b/code/modules/modular_computers/file_system/programs/generic/file_browser.dm deleted file mode 100644 index e7edc437639..00000000000 --- a/code/modules/modular_computers/file_system/programs/generic/file_browser.dm +++ /dev/null @@ -1,228 +0,0 @@ -/datum/computer_file/program/filemanager - filename = "filemanager" - filedesc = "NTOS File Manager" - extended_desc = "This program allows management of files." - program_icon_state = "generic" - size = 8 - requires_ntnet = 0 - available_on_ntnet = 0 - undeletable = 1 - var/open_file - var/error - -/datum/computer_file/program/filemanager/proc/prepare_printjob(t, font = PRINTER_FONT) // Additional stuff to parse if we want to print it and make a happy Head of Personnel. Forms FTW. - t = replacetext(t, "\[field\]", "") - t = replacetext(t, "\[sign\]", "") - t = pencode_to_html(t, sign = 0, fields = 0, deffont = font) - return t - -/datum/computer_file/program/filemanager/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, "file_manager.tmpl", "NTOS File Manager", 575, 700) - ui.set_auto_update(1) - ui.set_layout_key("program") - ui.open() - -/datum/computer_file/program/filemanager/ui_data(mob/user) - var/list/data = get_header_data() - - var/obj/item/computer_hardware/hard_drive/HDD = computer.all_components[MC_HDD] - var/obj/item/computer_hardware/hard_drive/portable/RHDD = computer.all_components[MC_SDD] - if(error) - data["error"] = error - if(open_file) - var/datum/computer_file/data/file - - if(!computer || !HDD) - data["error"] = "I/O ERROR: Unable to access hard drive." - else - file = HDD.find_file_by_name(open_file) - if(!istype(file)) - data["error"] = "I/O ERROR: Unable to open file." - else - data["filedata"] = pencode_to_html(file.stored_data, format = 1, sign = 0, fields = 0) - data["filename"] = "[file.filename].[file.filetype]" - else - if(!computer || !HDD) - data["error"] = "I/O ERROR: Unable to access hard drive." - else - var/list/files[0] - for(var/datum/computer_file/F in HDD.stored_files) - files.Add(list(list( - "name" = F.filename, - "type" = F.filetype, - "size" = F.size, - "undeletable" = F.undeletable, - "encrypted" = !!F.password - ))) - data["files"] = files - if(RHDD) - data["usbconnected"] = 1 - var/list/usbfiles[0] - for(var/datum/computer_file/F in RHDD.stored_files) - usbfiles.Add(list(list( - "name" = F.filename, - "type" = F.filetype, - "size" = F.size, - "undeletable" = F.undeletable, - "encrypted" = !!F.password - ))) - data["usbfiles"] = usbfiles - - return data - -/datum/computer_file/program/filemanager/Topic(href, list/href_list) - if(..()) - return 1 - - var/obj/item/computer_hardware/hard_drive/HDD = computer.all_components[MC_HDD] - var/obj/item/computer_hardware/hard_drive/RHDD = computer.all_components[MC_SDD] - var/obj/item/computer_hardware/printer/printer = computer.all_components[MC_PRINT] - - switch(href_list["action"]) - if("PRG_openfile") - . = 1 - var/datum/computer_file/F = HDD.find_file_by_name(href_list["name"]) - if(!F.can_access_file(usr)) - return - open_file = href_list["name"] - if("PRG_newtextfile") - . = 1 - var/newname = stripped_input(usr, "Enter file name or leave blank to cancel:", "File rename", max_length=50) - if(!newname) - return 1 - if(!HDD) - return 1 - var/datum/computer_file/data/F = new/datum/computer_file/data() - F.filename = newname - F.filetype = "TXT" - HDD.store_file(F) - if("PRG_deletefile") - . = 1 - if(!HDD) - return 1 - var/datum/computer_file/file = HDD.find_file_by_name(href_list["name"]) - if(!file || file.undeletable) - return 1 - HDD.remove_file(file) - if("PRG_usbdeletefile") - . = 1 - if(!RHDD) - return 1 - var/datum/computer_file/file = RHDD.find_file_by_name(href_list["name"]) - if(!file || file.undeletable) - return 1 - RHDD.remove_file(file) - if("PRG_closefile") - . = 1 - open_file = null - error = null - if("PRG_clone") - . = 1 - if(!HDD) - return 1 - var/datum/computer_file/F = HDD.find_file_by_name(href_list["name"]) - if(!F || !istype(F)) - return 1 - var/newname = stripped_input(usr, "Enter clone file name:", "File clone", "Copy of " + F.filename, max_length=50) - if(F && newname) - var/datum/computer_file/C = F.clone(1) - C.filename = newname - if(!HDD.store_file(C)) - error = "I/O error: Unable to clone file. Hard drive is probably full." - if("PRG_rename") - . = 1 - if(!HDD) - return 1 - var/datum/computer_file/file = HDD.find_file_by_name(href_list["name"]) - if(!file || !istype(file)) - return 1 - var/newname = stripped_input(usr, "Enter new file name:", "File rename", file.filename, max_length=50) - if(file && newname) - file.filename = newname - if("PRG_edit") - . = 1 - if(!open_file) - return 1 - if(!HDD) - return 1 - var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) - if(!F || !istype(F)) - return 1 - if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No")) - return 1 - // 16384 is the limit for file length in characters. Currently, papers have value of 2048 so this is 8 times as long, since we can't edit parts of the file independently. - var/newtext = stripped_multiline_input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", html_decode(F.stored_data), 16384, TRUE) - if(!newtext) - return - if(F) - var/datum/computer_file/data/backup = F.clone() - HDD.remove_file(F) - F = backup.clone() //When the file gets removed from the HDD, it gets queued for garbage collection. Hacky fix is to make a copy. - F.stored_data = newtext - F.calculate_size() - // We can't store the updated file, it's probably too large. Print an error and restore backed up version. - // This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space. - // They will be able to copy-paste the text from error screen and store it in notepad or something. - if(!HDD.store_file(F)) - error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:

    [F.stored_data]

    " - HDD.store_file(backup) - if("PRG_printfile") - . = 1 - if(!open_file) - return 1 - if(!HDD) - return 1 - var/datum/computer_file/data/F = HDD.find_file_by_name(open_file) - if(!F || !istype(F)) - return 1 - if(!printer) - error = "Missing Hardware: Your computer does not have required hardware to complete this operation." - return 1 - if(!printer.print_text(prepare_printjob(F.stored_data, computer.emagged ? CRAYON_FONT : PRINTER_FONT), open_file)) - error = "Hardware error: Printer was unable to print the file. It may be out of paper." - return 1 - if("PRG_copytousb") - . = 1 - if(!HDD || !RHDD) - return 1 - var/datum/computer_file/F = HDD.find_file_by_name(href_list["name"]) - if(!F || !istype(F)) - return 1 - var/datum/computer_file/C = F.clone(0) - RHDD.store_file(C) - if("PRG_copyfromusb") - . = 1 - if(!HDD || !RHDD) - return 1 - var/datum/computer_file/F = RHDD.find_file_by_name(href_list["name"]) - if(!F || !istype(F)) - return 1 - var/datum/computer_file/C = F.clone(0) - HDD.store_file(C) - if("PRG_encrypt") - . = 1 - if(!HDD) - return 1 - var/datum/computer_file/F = HDD.find_file_by_name(href_list["name"]) - if(!F || F.undeletable) - return 1 - if(F.password) - return - var/new_password = sanitize(input(usr, "Enter an encryption key:", "Encrypt File")) - if(!new_password) - to_chat(usr, "File not encrypted.") - return - F.password=new_password - if("PRG_decrypt") - . = 1 - if(!HDD) - return 1 - var/datum/computer_file/F = HDD.find_file_by_name(href_list["name"]) - if(!F || F.undeletable) - return 1 - if(F.can_access_file(usr)) - F.password = "" diff --git a/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm b/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm deleted file mode 100644 index b4e5ab4674c..00000000000 --- a/code/modules/modular_computers/file_system/programs/generic/ntdownloader.dm +++ /dev/null @@ -1,178 +0,0 @@ -/datum/computer_file/program/ntnetdownload - filename = "ntndownloader" - filedesc = "NTNet Software Download Tool" - program_icon_state = "generic" - extended_desc = "This program allows downloads of software from official NT repositories" - unsendable = 1 - undeletable = 1 - size = 4 - requires_ntnet = 1 - requires_ntnet_feature = NTNET_SOFTWAREDOWNLOAD - available_on_ntnet = 0 - ui_header = "downloader_finished.gif" - var/datum/computer_file/program/downloaded_file = null - var/hacked_download = 0 - var/download_completion = 0 //GQ of downloaded data. - var/download_netspeed = 0 - var/downloaderror = "" - var/obj/item/modular_computer/my_computer = null - -/datum/computer_file/program/ntnetdownload/proc/begin_file_download(filename) - if(downloaded_file) - return 0 - - var/datum/computer_file/program/PRG = GLOB.ntnet_global.find_ntnet_file_by_name(filename) - - if(!PRG || !istype(PRG)) - return 0 - - // Attempting to download antag only program, but without having emagged computer. No. - if(PRG.available_on_syndinet && !computer.emagged) - return 0 - - var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD] - - if(!computer || !hard_drive || !hard_drive.can_store_file(PRG)) - return 0 - - ui_header = "downloader_running.gif" - - if(PRG in GLOB.ntnet_global.available_station_software) - generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from NTNet Software Repository.") - hacked_download = 0 - else if(PRG in GLOB.ntnet_global.available_antag_software) - generate_network_log("Began downloading file **ENCRYPTED**.[PRG.filetype] from unspecified server.") - hacked_download = 1 - else - generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from unspecified server.") - hacked_download = 0 - - downloaded_file = PRG.clone() - -/datum/computer_file/program/ntnetdownload/proc/abort_file_download() - if(!downloaded_file) - return - generate_network_log("Aborted download of file [hacked_download ? "**ENCRYPTED**" : "[downloaded_file.filename].[downloaded_file.filetype]"].") - downloaded_file = null - download_completion = 0 - ui_header = "downloader_finished.gif" - -/datum/computer_file/program/ntnetdownload/proc/complete_file_download() - if(!downloaded_file) - return - generate_network_log("Completed download of file [hacked_download ? "**ENCRYPTED**" : "[downloaded_file.filename].[downloaded_file.filetype]"].") - var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD] - if(!computer || !hard_drive || !hard_drive.store_file(downloaded_file)) - // The download failed - downloaderror = "I/O ERROR - Unable to save file. Check whether you have enough free space on your hard drive and whether your hard drive is properly connected. If the issue persists contact your system administrator for assistance." - downloaded_file = null - download_completion = 0 - ui_header = "downloader_finished.gif" - -/datum/computer_file/program/ntnetdownload/process_tick() - if(!downloaded_file) - return - if(download_completion >= downloaded_file.size) - complete_file_download() - // Download speed according to connectivity state. NTNet server is assumed to be on unlimited speed so we're limited by our local connectivity - download_netspeed = 0 - // Speed defines are found in misc.dm - switch(ntnet_status) - if(1) - download_netspeed = NTNETSPEED_LOWSIGNAL - if(2) - download_netspeed = NTNETSPEED_HIGHSIGNAL - if(3) - download_netspeed = NTNETSPEED_ETHERNET - download_completion += download_netspeed - -/datum/computer_file/program/ntnetdownload/Topic(href, list/href_list) - if(..()) - return 1 - switch(href_list["action"]) - if("PRG_downloadfile") - if(!downloaded_file) - begin_file_download(href_list["filename"]) - return 1 - if("PRG_reseterror") - if(downloaderror) - download_completion = 0 - download_netspeed = 0 - downloaded_file = null - downloaderror = "" - return 1 - return 0 - -/datum/computer_file/program/ntnetdownload/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, "ntnet_downloader.tmpl", "NTNet Download Program", 575, 700) - ui.set_auto_update(1) - ui.set_layout_key("program") - ui.open() - -/datum/computer_file/program/ntnetdownload/ui_data(mob/user) - my_computer = computer - - if(!istype(my_computer)) - return - - var/list/data = get_header_data() - - // This IF cuts on data transferred to client, so i guess it's worth it. - if(downloaderror) // Download errored. Wait until user resets the program. - data["error"] = downloaderror - else if(downloaded_file) // Download running. Wait please.. - data["downloadname"] = downloaded_file.filename - data["downloaddesc"] = downloaded_file.filedesc - data["downloadsize"] = downloaded_file.size - data["downloadspeed"] = download_netspeed - data["downloadcompletion"] = round(min(download_completion, downloaded_file.size), 0.1) - else // No download running, pick file. - var/obj/item/computer_hardware/hard_drive/hard_drive = my_computer.all_components[MC_HDD] - data["disk_size"] = hard_drive.max_capacity - data["disk_used"] = hard_drive.used_capacity - var/list/all_entries[0] - for(var/A in GLOB.ntnet_global.available_station_software) - var/datum/computer_file/program/P = A - // Only those programs our user can run will show in the list - if(!P.can_run(user,transfer = 1)) - continue - all_entries.Add(list(list( - "filename" = P.filename, - "filedesc" = P.filedesc, - "fileinfo" = P.extended_desc, - "compatibility" = check_compatibility(P), - "size" = P.size, - "status" = !hard_drive || !hard_drive.can_store_file(P) ? "disabled" : null - ))) - data["hackedavailable"] = 0 - if(computer.emagged) // If we are running on emagged computer we have access to some "bonus" software - var/list/hacked_programs[0] - for(var/S in GLOB.ntnet_global.available_antag_software) - var/datum/computer_file/program/P = S - data["hackedavailable"] = 1 - hacked_programs.Add(list(list( - "filename" = P.filename, - "filedesc" = P.filedesc, - "fileinfo" = P.extended_desc, - "size" = P.size - ))) - data["hacked_programs"] = hacked_programs - - data["downloadable_programs"] = all_entries - - return data - -/datum/computer_file/program/ntnetdownload/proc/check_compatibility(datum/computer_file/program/P) - var/hardflag = computer.hardware_flag - - if(P && P.is_supported_by_hardware(hardflag,0)) - return "Compatible" - return "Incompatible!" - -/datum/computer_file/program/ntnetdownload/kill_program(forced) - abort_file_download() - return ..(forced) diff --git a/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm deleted file mode 100644 index ca208c22b02..00000000000 --- a/code/modules/modular_computers/file_system/programs/generic/ntnrc_client.dm +++ /dev/null @@ -1,229 +0,0 @@ -/datum/computer_file/program/chatclient - filename = "ntnrc_client" - filedesc = "NTNet Relay Chat Client" - program_icon_state = "command" - extended_desc = "This program allows communication over NTNRC network" - size = 8 - requires_ntnet = 1 - requires_ntnet_feature = NTNET_COMMUNICATION - network_destination = "NTNRC server" - ui_header = "ntnrc_idle.gif" - available_on_ntnet = 1 - var/last_message = null // Used to generate the toolbar icon - var/username - var/datum/ntnet_conversation/channel = null - var/operator_mode = 0 // Channel operator mode - var/netadmin_mode = 0 // Administrator mode (invisible to other users + bypasses passwords) - -/datum/computer_file/program/chatclient/New() - ..() - username = "DefaultUser[rand(100, 999)]" - -/datum/computer_file/program/chatclient/process_tick() - ..() - if(program_state != PROGRAM_STATE_KILLED) - ui_header = "ntnrc_idle.gif" - if(channel) - // Remember the last message. If there is no message in the channel remember null. - last_message = channel.messages.len ? channel.messages[channel.messages.len - 1] : null - else - last_message = null - return 1 - if(channel && channel.messages && channel.messages.len) - ui_header = last_message == channel.messages[channel.messages.len - 1] ? "ntnrc_idle.gif" : "ntnrc_new.gif" - else - ui_header = "ntnrc_idle.gif" - -/datum/computer_file/program/chatclient/kill_program(forced = FALSE) - if(channel) - channel.remove_client(src) - channel = null - ..() - -/datum/computer_file/program/chatclient/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, "ntnet_chat.tmpl", "NTNet Relay Chat Client", 575, 700) - ui.set_auto_update(1) - ui.set_layout_key("program") - ui.open() - - -/datum/computer_file/program/chatclient/ui_data(mob/user) - if(!GLOB.ntnet_global || !GLOB.ntnet_global.chat_channels) - return - - var/list/data = get_header_data() - - data["adminmode"] = netadmin_mode - if(channel) - data["title"] = channel.title - var/list/messages[0] - for(var/M in channel.messages) - messages.Add(list(list( - "msg" = M - ))) - data["messages"] = messages - var/list/clients[0] - for(var/C in channel.clients) - var/datum/computer_file/program/chatclient/cl = C - clients.Add(list(list( - "name" = cl.username - ))) - data["clients"] = clients - operator_mode = (channel.operator == src) ? 1 : 0 - data["is_operator"] = operator_mode || netadmin_mode - - else // Channel selection screen - var/list/all_channels[0] - for(var/C in GLOB.ntnet_global.chat_channels) - var/datum/ntnet_conversation/conv = C - if(conv && conv.title) - all_channels.Add(list(list( - "chan" = conv.title, - "id" = conv.id - ))) - data["all_channels"] = all_channels - - return data - -/datum/computer_file/program/chatclient/Topic(href, list/href_list) - if(..()) - return 1 - - switch(href_list["action"]) - if("PRG_speak") - . = 1 - if(!channel) - return 1 - var/mob/living/user = usr - var/message = reject_bad_text(input(user, "Enter message or leave blank to cancel: ")) - if(!message || !channel) - return - channel.add_message(message, username) - log_chat("[username] sent to [channel.title]: [message]", user) - - if("PRG_joinchannel") - . = 1 - var/datum/ntnet_conversation/C - for(var/datum/ntnet_conversation/chan in GLOB.ntnet_global.chat_channels) - if(chan.id == text2num(href_list["id"])) - C = chan - break - - if(!C) - return 1 - - if(netadmin_mode) - channel = C // Bypasses normal leave/join and passwords. Technically makes the user invisible to others. - return 1 - - if(C.password) - var/mob/living/user = usr - var/password = reject_bad_text(input(user,"Access Denied. Enter password:")) - if(C && (password == C.password)) - C.add_client(src) - channel = C - return 1 - C.add_client(src) - channel = C - if("PRG_leavechannel") - . = 1 - if(channel) - channel.remove_client(src) - channel = null - if("PRG_newchannel") - . = 1 - var/mob/living/user = usr - var/channel_title = reject_bad_text(input(user,"Enter channel name or leave blank to cancel:")) - if(!channel_title) - return 1 - var/datum/ntnet_conversation/C = new/datum/ntnet_conversation() - C.add_client(src) - C.operator = src - channel = C - C.title = channel_title - if("PRG_toggleadmin") - . = 1 - if(netadmin_mode) - netadmin_mode = 0 - if(channel) - channel.remove_client(src) // We shouldn't be in channel's user list, but just in case... - channel = null - return 1 - var/mob/living/user = usr - if(can_run(user, 1, ACCESS_NETWORK)) - if(channel) - var/response = alert(user, "Really engage admin-mode? You will be disconnected from your current channel!", "NTNRC Admin mode", "Yes", "No") - if(response == "Yes") - if(channel) - channel.remove_client(src) - channel = null - else - return 1 - netadmin_mode = 1 - if("PRG_changename") - . = 1 - var/mob/living/user = usr - var/newname = sanitize(input(user,"Enter new nickname or leave blank to cancel:")) - if(!newname) - return 1 - if(channel) - channel.add_status_message("[username] is now known as [newname].") - username = newname - - if("PRG_savelog") - . = 1 - if(!channel) - return 1 - var/mob/living/user = usr - var/logname = input(user,"Enter desired logfile name (.log) or leave blank to cancel:") - if(!logname || !channel) - return 1 - var/datum/computer_file/data/logfile = new/datum/computer_file/data/logfile() - // Now we will generate HTML-compliant file that can actually be viewed/printed. - logfile.filename = logname - logfile.stored_data = "\[b\]Logfile dump from NTNRC channel [channel.title]\[/b\]\[BR\]" - for(var/logstring in channel.messages) - logfile.stored_data += "[logstring]\[BR\]" - logfile.stored_data += "\[b\]Logfile dump completed.\[/b\]" - logfile.calculate_size() - var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD] - if(!computer || !hard_drive || !hard_drive.store_file(logfile)) - if(!computer) - // This program shouldn't even be runnable without computer. - CRASH("Var computer is null!") - if(!hard_drive) - computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.") - else // In 99.9% cases this will mean our HDD is full - computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning.") - if("PRG_renamechannel") - . = 1 - if(!operator_mode || !channel) - return 1 - var/mob/living/user = usr - var/newname = reject_bad_text(input(user, "Enter new channel name or leave blank to cancel:")) - if(!newname || !channel) - return 1 - channel.add_status_message("Channel renamed from [channel.title] to [newname] by operator.") - channel.title = newname - if("PRG_deletechannel") - . = 1 - if(channel && ((channel.operator == src) || netadmin_mode)) - QDEL_NULL(channel) - if("PRG_setpassword") - . = 1 - if(!channel || ((channel.operator != src) && !netadmin_mode)) - return 1 - - var/mob/living/user = usr - var/newpassword = sanitize(input(user, "Enter new password for this channel. Leave blank to cancel, enter 'nopassword' to remove password completely:")) - if(!channel || !newpassword || ((channel.operator != src) && !netadmin_mode)) - return 1 - - if(newpassword == "nopassword") - channel.password = "" - else - channel.password = newpassword diff --git a/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm b/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm deleted file mode 100644 index 1ccefa9311a..00000000000 --- a/code/modules/modular_computers/file_system/programs/generic/nttransfer.dm +++ /dev/null @@ -1,195 +0,0 @@ -GLOBAL_VAR_INIT(nttransfer_uid, 0) - -/datum/computer_file/program/nttransfer - filename = "nttransfer" - filedesc = "NTNet P2P Transfer Client" - extended_desc = "This program allows for simple file transfer via direct peer to peer connection." - program_icon_state = "comm_logs" - size = 7 - requires_ntnet = 1 - requires_ntnet_feature = NTNET_PEERTOPEER - network_destination = "other device via P2P tunnel" - available_on_ntnet = 1 - - var/error = "" // Error screen - var/server_password = "" // Optional password to download the file. - var/datum/computer_file/provided_file = null // File which is provided to clients. - var/datum/computer_file/downloaded_file = null // File which is being downloaded - var/list/connected_clients = list() // List of connected clients. - var/datum/computer_file/program/nttransfer/remote // Client var, specifies who are we downloading from. - var/download_completion = 0 // Download progress in GQ - var/download_netspeed = 0 // Our connectivity speed in GQ/s - var/actual_netspeed = 0 // Displayed in the UI, this is the actual transfer speed. - var/unique_token // UID of this program - var/upload_menu = 0 // Whether we show the program list and upload menu - -/datum/computer_file/program/nttransfer/New() - unique_token = GLOB.nttransfer_uid - GLOB.nttransfer_uid++ - ..() - -/datum/computer_file/program/nttransfer/process_tick() - // Server mode - update_netspeed() - if(provided_file) - for(var/datum/computer_file/program/nttransfer/C in connected_clients) - // Transfer speed is limited by device which uses slower connectivity. - // We can have multiple clients downloading at same time, but let's assume we use some sort of multicast transfer - // so they can all run on same speed. - C.actual_netspeed = min(C.download_netspeed, download_netspeed) - C.download_completion += C.actual_netspeed - if(C.download_completion >= provided_file.size) - C.finish_download() - else if(downloaded_file) // Client mode - if(!remote) - crash_download("Connection to remote server lost") - -/datum/computer_file/program/nttransfer/kill_program(forced = FALSE) - if(downloaded_file) // Client mode, clean up variables for next use - finalize_download() - - if(provided_file) // Server mode, disconnect all clients - for(var/datum/computer_file/program/nttransfer/P in connected_clients) - P.crash_download("Connection terminated by remote server") - downloaded_file = null - ..(forced) - -/datum/computer_file/program/nttransfer/proc/update_netspeed() - download_netspeed = 0 - switch(ntnet_status) - if(1) - download_netspeed = NTNETSPEED_LOWSIGNAL - if(2) - download_netspeed = NTNETSPEED_HIGHSIGNAL - if(3) - download_netspeed = NTNETSPEED_ETHERNET - -// Finishes download and attempts to store the file on HDD -/datum/computer_file/program/nttransfer/proc/finish_download() - var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD] - if(!computer || !hard_drive || !hard_drive.store_file(downloaded_file)) - error = "I/O Error: Unable to save file. Check your hard drive and try again." - finalize_download() - -// Crashes the download and displays specific error message -/datum/computer_file/program/nttransfer/proc/crash_download(var/message) - error = message ? message : "An unknown error has occurred during download" - finalize_download() - -// Cleans up variables for next use -/datum/computer_file/program/nttransfer/proc/finalize_download() - if(remote) - remote.connected_clients.Remove(src) - downloaded_file = null - remote = null - download_completion = 0 - - -/datum/computer_file/program/nttransfer/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, "ntnet_transfer.tmpl", "NTNet P2P Transfer Client", 575, 700) - ui.set_auto_update(1) - ui.set_layout_key("program") - ui.open() - -/datum/computer_file/program/nttransfer/Topic(href, list/href_list) - if(..()) - return 1 - switch(href_list["action"]) - if("PRG_downloadfile") - for(var/datum/computer_file/program/nttransfer/P in GLOB.ntnet_global.fileservers) - if("[P.unique_token]" == href_list["id"]) - remote = P - break - if(!remote || !remote.provided_file) - return - if(remote.server_password) - var/pass = reject_bad_text(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required")) - if(pass != remote.server_password) - error = "Incorrect Password" - return 1 - downloaded_file = remote.provided_file.clone() - remote.connected_clients.Add(src) - return 1 - if("PRG_reset") - error = "" - upload_menu = 0 - finalize_download() - if(src in GLOB.ntnet_global.fileservers) - GLOB.ntnet_global.fileservers.Remove(src) - for(var/datum/computer_file/program/nttransfer/T in connected_clients) - T.crash_download("Remote server has forcibly closed the connection") - provided_file = null - return 1 - if("PRG_setpassword") - var/pass = reject_bad_text(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none")) - if(!pass) - return - if(pass == "none") - server_password = "" - return - server_password = pass - return 1 - if("PRG_uploadfile") - var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD] - for(var/datum/computer_file/F in hard_drive.stored_files) - if("[F.uid]" == href_list["id"]) - if(F.unsendable) - error = "I/O Error: File locked." - return - if(istype(F, /datum/computer_file/program)) - var/datum/computer_file/program/P = F - if(!P.can_run(usr,transfer = 1)) - error = "Access Error: Insufficient rights to upload file." - provided_file = F - GLOB.ntnet_global.fileservers.Add(src) - return - error = "I/O Error: Unable to locate file on hard drive." - return 1 - if("PRG_uploadmenu") - upload_menu = 1 - - -/datum/computer_file/program/nttransfer/ui_data(mob/user) - - var/list/data = get_header_data() - - if(error) - data["error"] = error - else if(downloaded_file) - data["downloading"] = 1 - data["download_size"] = downloaded_file.size - data["download_progress"] = download_completion - data["download_netspeed"] = actual_netspeed - data["download_name"] = "[downloaded_file.filename].[downloaded_file.filetype]" - else if (provided_file) - data["uploading"] = 1 - data["upload_uid"] = unique_token - data["upload_clients"] = connected_clients.len - data["upload_haspassword"] = server_password ? 1 : 0 - data["upload_filename"] = "[provided_file.filename].[provided_file.filetype]" - else if (upload_menu) - var/list/all_files[0] - var/obj/item/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD] - for(var/datum/computer_file/F in hard_drive.stored_files) - all_files.Add(list(list( - "uid" = F.uid, - "filename" = "[F.filename].[F.filetype]", - "size" = F.size - ))) - data["upload_filelist"] = all_files - else - var/list/all_servers[0] - for(var/datum/computer_file/program/nttransfer/P in GLOB.ntnet_global.fileservers) - all_servers.Add(list(list( - "uid" = P.unique_token, - "filename" = "[P.provided_file.filename].[P.provided_file.filetype]", - "size" = P.provided_file.size, - "haspassword" = P.server_password ? 1 : 0 - ))) - data["servers"] = all_servers - - return data diff --git a/code/modules/modular_computers/file_system/programs/research/airestorer.dm b/code/modules/modular_computers/file_system/programs/research/airestorer.dm deleted file mode 100644 index a87a2cd87b4..00000000000 --- a/code/modules/modular_computers/file_system/programs/research/airestorer.dm +++ /dev/null @@ -1,137 +0,0 @@ -/datum/computer_file/program/aidiag - filename = "aidiag" - filedesc = "AI Maintenance Utility" - program_icon_state = "generic" - extended_desc = "This program is capable of reconstructing damaged AI systems. Requires direct AI connection via intellicard slot." - size = 12 - requires_ntnet = 0 - usage_flags = PROGRAM_CONSOLE - transfer_access = ACCESS_HEADS - available_on_ntnet = 1 - var/restoring = FALSE - -/datum/computer_file/program/aidiag/proc/get_ai(cardcheck) - - var/obj/item/computer_hardware/ai_slot/ai_slot - - if(computer) - ai_slot = computer.all_components[MC_AI] - - if(computer && ai_slot && ai_slot.check_functionality()) - if(cardcheck == 1) - return ai_slot - if(ai_slot.enabled && ai_slot.stored_card) - if(cardcheck == 2) - return ai_slot.stored_card - if(locate(/mob/living/silicon/ai) in ai_slot.stored_card) - return locate(/mob/living/silicon/ai) in ai_slot.stored_card - - return null - -/datum/computer_file/program/aidiag/Topic(href, list/href_list) - if(..()) - return TRUE - - var/mob/living/silicon/ai/A = get_ai() - if(!A) - restoring = FALSE - - switch(href_list["action"]) - if("PRG_beginReconstruction") - if(A && A.health < 100) - restoring = TRUE - return TRUE - if("PRG_eject") - if(computer.all_components[MC_AI]) - var/obj/item/computer_hardware/ai_slot/ai_slot = computer.all_components[MC_AI] - if(ai_slot && ai_slot.stored_card) - ai_slot.try_eject(0,usr) - return TRUE - -/datum/computer_file/program/aidiag/process_tick() - ..() - if(!restoring) //Put the check here so we don't check for an ai all the time - return - var/obj/item/aicard/cardhold = get_ai(2) - - var/obj/item/computer_hardware/ai_slot/ai_slot = get_ai(1) - - - var/mob/living/silicon/ai/A = get_ai() - if(!A || !cardhold) - restoring = FALSE // If the AI was removed, stop the restoration sequence. - if(ai_slot) - ai_slot.locked = FALSE - return - - if(cardhold.flush) - ai_slot.locked = FALSE - restoring = FALSE - return - ai_slot.locked = TRUE - A.adjustOxyLoss(-1) - A.adjustFireLoss(-1) - A.adjustToxLoss(-1) - A.adjustBruteLoss(-1) - A.updatehealth() - if(A.health >= 0 && A.stat == DEAD) - A.stat = CONSCIOUS - A.lying = 0 - GLOB.dead_mob_list -= A - GLOB.alive_mob_list += A - // Finished restoring - if(A.health >= 100) - ai_slot.locked = FALSE - restoring = FALSE - - return TRUE - - -/datum/computer_file/program/aidiag/ui_data(mob/user) - var/list/data = get_header_data() - var/mob/living/silicon/ai/AI - // A shortcut for getting the AI stored inside the computer. The program already does necessary checks. - AI = get_ai() - - var/obj/item/aicard/aicard = get_ai(2) - - if(!aicard) - data["nocard"] = TRUE - data["error"] = "Please insert an intelliCard." - else - if(!AI) - data["error"] = "No AI located" - else - var/obj/item/aicard/cardhold = AI.loc - if(cardhold.flush) - data["error"] = "Flush in progress" - else - data["name"] = AI.name - data["restoring"] = restoring - data["health"] = (AI.health + 100) / 2 - data["isDead"] = AI.stat == DEAD - - var/list/all_laws[0] - for(var/datum/ai_law/L in AI.laws.all_laws()) - all_laws.Add(list(list( - "index" = L.index, - "text" = L.law - ))) - - data["ai_laws"] = all_laws - - return data - -/datum/computer_file/program/aidiag/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, "ai_restorer.tmpl", "Integrity Restorer", 600, 400) - ui.set_auto_update(1) - ui.set_layout_key("program") - ui.open() - -/datum/computer_file/program/aidiag/kill_program(forced) - restoring = FALSE - return ..(forced) diff --git a/code/modules/modular_computers/file_system/programs/research/ntmonitor.dm b/code/modules/modular_computers/file_system/programs/research/ntmonitor.dm deleted file mode 100644 index 0a839a6d13f..00000000000 --- a/code/modules/modular_computers/file_system/programs/research/ntmonitor.dm +++ /dev/null @@ -1,90 +0,0 @@ -/datum/computer_file/program/ntnetmonitor - filename = "ntmonitor" - filedesc = "NTNet Diagnostics and Monitoring" - program_icon_state = "comm_monitor" - extended_desc = "This program monitors stationwide NTNet network, provides access to logging systems, and allows for configuration changes" - size = 12 - requires_ntnet = 1 - required_access = ACCESS_NETWORK //Network control is a more secure program. - available_on_ntnet = 1 - -/datum/computer_file/program/ntnetmonitor/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, "ntnet_monitor.tmpl", "NTNet Diagnostics and Monitoring Tool", 575, 700) - ui.set_auto_update(1) - ui.set_layout_key("program") - ui.open() - -/datum/computer_file/program/ntnetmonitor/Topic(href, list/href_list) - if(..()) - return 1 - switch(href_list["action"]) - if("resetIDS") - . = 1 - if(GLOB.ntnet_global) - GLOB.ntnet_global.resetIDS() - return 1 - if("toggleIDS") - . = 1 - if(GLOB.ntnet_global) - GLOB.ntnet_global.toggleIDS() - return 1 - if("toggleWireless") - . = 1 - if(!GLOB.ntnet_global) - return 1 - - // NTNet is disabled. Enabling can be done without user prompt - if(GLOB.ntnet_global.setting_disabled) - GLOB.ntnet_global.setting_disabled = 0 - return 1 - - // NTNet is enabled and user is about to shut it down. Let's ask them if they really want to do it, as wirelessly connected computers won't connect without NTNet being enabled (which may prevent people from turning it back on) - var/mob/user = usr - if(!user) - return 1 - var/response = alert(user, "Really disable NTNet wireless? If your computer is connected wirelessly you won't be able to turn it back on! This will affect all connected wireless devices.", "NTNet shutdown", "Yes", "No") - if(response == "Yes") - GLOB.ntnet_global.setting_disabled = 1 - return 1 - if("purgelogs") - . = 1 - if(GLOB.ntnet_global) - GLOB.ntnet_global.purge_logs() - if("updatemaxlogs") - . = 1 - var/mob/user = usr - var/logcount = text2num(input(user,"Enter amount of logs to keep in memory ([MIN_NTNET_LOGS]-[MAX_NTNET_LOGS]):")) - if(GLOB.ntnet_global) - GLOB.ntnet_global.update_max_log_count(logcount) - if("toggle_function") - . = 1 - if(!GLOB.ntnet_global) - return 1 - GLOB.ntnet_global.toggle_function(text2num(href_list["id"])) - -/datum/computer_file/program/ntnetmonitor/ui_data(mob/user) - if(!GLOB.ntnet_global) - return - var/list/data = get_header_data() - - data["ntnetstatus"] = GLOB.ntnet_global.check_function() - data["ntnetrelays"] = GLOB.ntnet_global.relays.len - data["idsstatus"] = GLOB.ntnet_global.intrusion_detection_enabled - data["idsalarm"] = GLOB.ntnet_global.intrusion_detection_alarm - - data["config_softwaredownload"] = GLOB.ntnet_global.setting_softwaredownload - data["config_peertopeer"] = GLOB.ntnet_global.setting_peertopeer - data["config_communication"] = GLOB.ntnet_global.setting_communication - data["config_systemcontrol"] = GLOB.ntnet_global.setting_systemcontrol - - data["ntnetlogs"] = list() - - for(var/i in GLOB.ntnet_global.logs) - data["ntnetlogs"] += list(list("entry" = i)) - data["ntnetmaxlogs"] = GLOB.ntnet_global.setting_maxlogcount - - return data diff --git a/code/modules/modular_computers/hardware/CPU.dm b/code/modules/modular_computers/hardware/CPU.dm deleted file mode 100644 index 02e7d41d512..00000000000 --- a/code/modules/modular_computers/hardware/CPU.dm +++ /dev/null @@ -1,44 +0,0 @@ -// CPU that allows the computer to run programs. -// Better CPUs are obtainable via research and can run more programs on background. - -/obj/item/computer_hardware/processor_unit - name = "processor board" - desc = "A standard CPU board used in most computers. It can run up to three programs simultaneously." - icon_state = "cpuboard" - w_class = WEIGHT_CLASS_SMALL - power_usage = 50 - critical = 1 - malfunction_probability = 1 - origin_tech = "programming=3;engineering=2" - var/max_idle_programs = 2 // 2 idle, + 1 active = 3 as said in description. - device_type = MC_CPU - -/obj/item/computer_hardware/processor_unit/on_remove(obj/item/modular_computer/MC, mob/user) - MC.shutdown_computer() - -/obj/item/computer_hardware/processor_unit/small - name = "microprocessor" - desc = "A miniaturised CPU used in portable devices. It can run up to two programs simultaneously." - icon_state = "cpu" - w_class = WEIGHT_CLASS_TINY - power_usage = 25 - max_idle_programs = 1 - origin_tech = "programming=2;engineering=2" - -/obj/item/computer_hardware/processor_unit/photonic - name = "photonic processor board" - desc = "An advanced experimental CPU board that uses photonic core instead of regular circuitry. It can run up to five programs simultaneously, but uses a lot of power." - icon_state = "cpuboard_super" - w_class = WEIGHT_CLASS_SMALL - power_usage = 250 - max_idle_programs = 4 - origin_tech = "programming=5;engineering=4" - -/obj/item/computer_hardware/processor_unit/photonic/small - name = "photonic microprocessor" - desc = "An advanced miniaturised CPU for use in portable devices. It uses photonic core instead of regular circuitry. It can run up to three programs simultaneously." - icon_state = "cpu_super" - w_class = WEIGHT_CLASS_TINY - power_usage = 75 - max_idle_programs = 2 - origin_tech = "programming=4;engineering=3" diff --git a/code/modules/modular_computers/hardware/_hardware.dm b/code/modules/modular_computers/hardware/_hardware.dm deleted file mode 100644 index 3e82455c53b..00000000000 --- a/code/modules/modular_computers/hardware/_hardware.dm +++ /dev/null @@ -1,105 +0,0 @@ -/obj/item/computer_hardware - name = "hardware" - desc = "Unknown Hardware." - icon = 'icons/obj/module.dmi' - icon_state = "std_mod" - - w_class = WEIGHT_CLASS_TINY // w_class limits which devices can contain this component. - // 1: PDAs/Tablets, 2: Laptops, 3-4: Consoles only - var/obj/item/modular_computer/holder = null - // Computer that holds this hardware, if any. - - max_integrity = 200 - - var/power_usage = 0 // If the hardware uses extra power, change this. - var/enabled = 1 // If the hardware is turned off set this to 0. - var/critical = 0 // Prevent disabling for important component, like the CPU. - var/can_install = 1 // Prevents direct installation of removable media. - var/damage = 0 // Current damage level - var/max_damage = 100 // Maximal damage level. - var/damage_malfunction = 20 // "Malfunction" threshold. When damage exceeds this value the hardware piece will semi-randomly fail and do !!FUN!! things - var/damage_failure = 50 // "Failure" threshold. When damage exceeds this value the hardware piece will not work at all. - var/malfunction_probability = 10// Chance of malfunction when the component is damaged - var/device_type - -/obj/item/computer_hardware/New(var/obj/L) - ..() - pixel_x = rand(-8, 8) - pixel_y = rand(-8, 8) - -/obj/item/computer_hardware/Destroy() - if(holder) - holder.uninstall_component(src) - return ..() - - -/obj/item/computer_hardware/attackby(obj/item/I, mob/living/user) - // Multitool. Runs diagnostics - if(istype(I, /obj/item/multitool)) - to_chat(user, "***** DIAGNOSTICS REPORT *****") - diagnostics(user) - to_chat(user, "******************************") - return 1 - - // Cable coil. Works as repair method, but will probably require multiple applications and more cable. - if(istype(I, /obj/item/stack/cable_coil)) - var/obj/item/stack/S = I - if(obj_integrity == max_integrity) - to_chat(user, "\The [src] doesn't seem to require repairs.") - return 1 - if(S.use(1)) - to_chat(user, "You patch up \the [src] with a bit of \the [I].") - obj_integrity = min(obj_integrity + 10, max_integrity) - return 1 - - if(try_insert(I, user)) - return 1 - - return ..() - -// Called on multitool click, prints diagnostic information to the user. -/obj/item/computer_hardware/proc/diagnostics(var/mob/user) - to_chat(user, "Hardware Integrity Test... (Corruption: [damage]/[max_damage]) [damage > damage_failure ? "FAIL" : damage > damage_malfunction ? "WARN" : "PASS"]") - -// Handles damage checks -/obj/item/computer_hardware/proc/check_functionality() - if(!enabled) // Disabled. - return FALSE - - if(damage > damage_failure) // Too damaged to work at all. - return FALSE - - if(damage > damage_malfunction) // Still working. Well, sometimes... - if(prob(malfunction_probability)) - return FALSE - - return TRUE // Good to go. - -/obj/item/computer_hardware/examine(var/mob/user) - . = ..() - if(damage > damage_failure) - . += "It seems to be severely damaged!" - else if(damage > damage_malfunction) - . += "It seems to be damaged!" - else if(damage) - . += "It seems to be slightly damaged." - -// Component-side compatibility check. -/obj/item/computer_hardware/proc/can_install(obj/item/modular_computer/M, mob/living/user = null) - return can_install - -// Called when component is installed into PC. -/obj/item/computer_hardware/proc/on_install(obj/item/modular_computer/M, mob/living/user = null) - return - -// Called when component is removed from PC. -/obj/item/computer_hardware/proc/on_remove(obj/item/modular_computer/M, mob/living/user = null) - try_eject(forced = 1) - -// Called when someone tries to insert something in it - paper in printer, card in card reader, etc. -/obj/item/computer_hardware/proc/try_insert(obj/item/I, mob/living/user = null) - return FALSE - -// Called when someone tries to eject something from it - card from card reader, etc. -/obj/item/computer_hardware/proc/try_eject(slot=0, mob/living/user = null, forced = 0) - return FALSE diff --git a/code/modules/modular_computers/hardware/ai_slot.dm b/code/modules/modular_computers/hardware/ai_slot.dm deleted file mode 100644 index 1b97ae5ede8..00000000000 --- a/code/modules/modular_computers/hardware/ai_slot.dm +++ /dev/null @@ -1,80 +0,0 @@ -/obj/item/computer_hardware/ai_slot - name = "intelliCard interface slot" - desc = "A module allowing this computer to interface with most common intelliCard modules. Necessary for some programs to run properly." - power_usage = 100 //W - icon_state = "card_mini" - w_class = WEIGHT_CLASS_SMALL - origin_tech = "programming=2" - device_type = MC_AI - - var/obj/item/aicard/stored_card = null - var/locked = FALSE - -/obj/item/computer_hardware/ai_slot/Destroy() - QDEL_NULL(stored_card) - return ..() - - -/obj/item/computer_hardware/ai_slot/examine(mob/user) - . = ..() - if(stored_card) - . += "There appears to be an intelliCard loaded. There appears to be a pinhole protecting a manual eject button. A screwdriver could probably press it" - -/obj/item/computer_hardware/ai_slot/on_install(obj/item/modular_computer/M, mob/living/user = null) - M.add_verb(device_type) - -/obj/item/computer_hardware/ai_slot/on_remove(obj/item/modular_computer/M, mob/living/user = null) - M.remove_verb(device_type) - try_eject(0, forced = 1) - -/obj/item/computer_hardware/ai_slot/try_insert(obj/item/I, mob/living/user = null) - if(!holder) - return FALSE - - if(!istype(I, /obj/item/aicard)) - return FALSE - - if(stored_card) - if(user) - to_chat(user, "You try to insert \the [I] into \the [src], but the slot is occupied.") - return FALSE - if(user && !user.unEquip(I)) - return FALSE - - I.forceMove(src) - stored_card = I - if(user) - to_chat(user, "You insert \the [I] into \the [src].") - - return TRUE - - -/obj/item/computer_hardware/ai_slot/try_eject(slot=0, mob/living/user = null, forced = 0) - if(!stored_card) - if(user) - to_chat(user, "There is no card in \the [src].") - return FALSE - - if(locked && !forced) - if(user) - to_chat(user, "Safeties prevent you from removing the card until reconstruction is complete...") - return FALSE - - if(stored_card) - stored_card.forceMove(get_turf(src)) - locked = FALSE - stored_card.verb_pickup() - stored_card = null - - if(user) - to_chat(user, "You remove the card from \the [src].") - return TRUE - return FALSE - -/obj/item/computer_hardware/ai_slot/attackby(obj/item/I, mob/living/user) - if(..()) - return - if(istype(I, /obj/item/screwdriver)) - to_chat(user, "You press down on the manual eject button with \the [I].") - try_eject(0, user, 1) - return diff --git a/code/modules/modular_computers/hardware/battery_module.dm b/code/modules/modular_computers/hardware/battery_module.dm deleted file mode 100644 index 1a48110006a..00000000000 --- a/code/modules/modular_computers/hardware/battery_module.dm +++ /dev/null @@ -1,108 +0,0 @@ -/obj/item/computer_hardware/battery - name = "power cell controller" - desc = "A charge controller for standard power cells, used in all kinds of modular computers." - icon_state = "cell_con" - critical = 1 - malfunction_probability = 1 - origin_tech = "powerstorage=1;engineering=1" - var/obj/item/stock_parts/cell/battery = null - device_type = MC_CELL - -/obj/item/computer_hardware/battery/get_cell() - return battery - -/obj/item/computer_hardware/battery/New(loc, battery_type = null) - if(battery_type) - battery = new battery_type(src) - ..() - -/obj/item/computer_hardware/battery/Destroy() - QDEL_NULL(battery) - return ..() - -/obj/item/computer_hardware/battery/on_remove(obj/item/modular_computer/M, mob/living/user = null) - try_eject(0, forced = 1) - -/obj/item/computer_hardware/battery/try_insert(obj/item/I, mob/living/user = null) - if(!holder) - return FALSE - - if(!istype(I, /obj/item/stock_parts/cell)) - return FALSE - - if(battery) - if(user) - to_chat(user, "You try to connect \the [I] to \the [src], but its connectors are occupied.") - return FALSE - - if(I.w_class > holder.max_hardware_size) - if(user) - to_chat(user, "This power cell is too large for \the [holder]!") - return FALSE - - if(user && !user.unEquip(I)) - return FALSE - - I.forceMove(src) - battery = I - if(user) - to_chat(user, "You connect \the [I] to \the [src].") - - return TRUE - - -/obj/item/computer_hardware/battery/try_eject(slot=0, mob/living/user = null, forced = 0) - if(!battery) - if(user) - to_chat(user, "There is no power cell connected to \the [src].") - return FALSE - else - battery.forceMove(get_turf(src)) - if(user) - to_chat(user, "You detach \the [battery] from \the [src].") - battery = null - - if(holder) - if(holder.enabled && !holder.use_power()) - holder.shutdown_computer() - - return TRUE - - -// Stock parts -/obj/item/stock_parts/cell/computer - name = "standard battery" - desc = "A standard power cell, commonly seen in high-end portable microcomputers or low-end laptops." - icon = 'icons/obj/module.dmi' - icon_state = "cell_mini" - origin_tech = "powerstorage=2;engineering=1" - w_class = WEIGHT_CLASS_TINY - maxcharge = 750 - -/obj/item/stock_parts/cell/computer/advanced - name = "advanced battery" - desc = "An advanced power cell, often used in most laptops. It is too large to be fitted into smaller devices." - icon_state = "cell" - origin_tech = "powerstorage=2;engineering=2" - maxcharge = 1500 - -/obj/item/stock_parts/cell/computer/super - name = "super battery" - desc = "An advanced power cell, often used in high-end laptops." - icon_state = "cell" - origin_tech = "powerstorage=3;engineering=3" - maxcharge = 2000 - -/obj/item/stock_parts/cell/computer/micro - name = "micro battery" - desc = "A small power cell, commonly seen in most portable microcomputers." - icon_state = "cell_micro" - w_class = WEIGHT_CLASS_TINY - maxcharge = 500 - -/obj/item/stock_parts/cell/computer/nano - name = "nano battery" - desc = "A tiny power cell, commonly seen in low-end portable microcomputers." - icon_state = "cell_micro" - w_class = WEIGHT_CLASS_TINY - maxcharge = 300 diff --git a/code/modules/modular_computers/hardware/card_slot.dm b/code/modules/modular_computers/hardware/card_slot.dm deleted file mode 100644 index fc1abc207a5..00000000000 --- a/code/modules/modular_computers/hardware/card_slot.dm +++ /dev/null @@ -1,112 +0,0 @@ -/obj/item/computer_hardware/card_slot - name = "identification card authentication module" // \improper breaks the find_hardware_by_name proc - desc = "A module allowing this computer to read or write data on ID cards. Necessary for some programs to run properly." - power_usage = 10 //W - icon_state = "card_mini" - w_class = WEIGHT_CLASS_TINY - origin_tech = "programming=2" - device_type = MC_CARD - - var/obj/item/card/id/stored_card = null - var/obj/item/card/id/stored_card2 = null - -/obj/item/computer_hardware/card_slot/Destroy() - QDEL_NULL(stored_card) - QDEL_NULL(stored_card2) - return ..() - -/obj/item/computer_hardware/card_slot/GetAccess() - if(stored_card && stored_card2) // Best of both worlds - return (stored_card.GetAccess() | stored_card2.GetAccess()) - else if(stored_card) - return stored_card.GetAccess() - else if(stored_card2) - return stored_card2.GetAccess() - return ..() - -/obj/item/computer_hardware/card_slot/GetID() - if(stored_card) - return stored_card - else if(stored_card2) - return stored_card2 - return ..() - -/obj/item/computer_hardware/card_slot/on_install(obj/item/modular_computer/M, mob/living/user = null) - M.add_verb(device_type) - -/obj/item/computer_hardware/card_slot/on_remove(obj/item/modular_computer/M, mob/living/user = null) - M.remove_verb(device_type) - try_eject(0, forced = 1) - -/obj/item/computer_hardware/card_slot/try_insert(obj/item/I, mob/living/user = null) - if(!holder) - return FALSE - - if(!istype(I, /obj/item/card/id)) - return FALSE - - if(stored_card && stored_card2) - if(user) - to_chat(user, "You try to insert \the [I] into \the [src], but its slots are occupied.") - return FALSE - if(user && !user.unEquip(I)) - return FALSE - - I.forceMove(src) - - if(!stored_card) - stored_card = I - else - stored_card2 = I - - if(user) - to_chat(user, "You insert \the [I] into \the [src].") - - return TRUE - - -/obj/item/computer_hardware/card_slot/try_eject(slot = 0, mob/living/user = null, forced = 0) - if(!stored_card && !stored_card2) - if(user) - to_chat(user, "There are no cards in \the [src].") - return FALSE - - var/ejected = 0 - if(stored_card && (!slot || slot == 1)) - stored_card.forceMove(get_turf(src)) - stored_card.verb_pickup() - stored_card = null - ejected++ - - if(stored_card2 && (!slot || slot == 2)) - stored_card2.forceMove(get_turf(src)) - stored_card2.verb_pickup() - stored_card2 = null - ejected++ - - if(ejected) - if(holder) - if(holder.active_program) - holder.active_program.event_idremoved(0, slot) - - for(var/I in holder.idle_threads) - var/datum/computer_file/program/P = I - P.event_idremoved(1, slot) - - if(user) - to_chat(user, "You remove the card[ejected>1 ? "s" : ""] from \the [src].") - return TRUE - return FALSE - -/obj/item/computer_hardware/card_slot/attackby(obj/item/I, mob/living/user) - if(..()) - return - if(istype(I, /obj/item/screwdriver)) - to_chat(user, "You press down on the manual eject button with \the [I].") - try_eject(0,user) - return - -/obj/item/computer_hardware/card_slot/examine(mob/user) - . = ..() - if(stored_card || stored_card2) - . += "There appears to be something loaded in the card slots." diff --git a/code/modules/modular_computers/hardware/hard_drive.dm b/code/modules/modular_computers/hardware/hard_drive.dm deleted file mode 100644 index ce7fc997192..00000000000 --- a/code/modules/modular_computers/hardware/hard_drive.dm +++ /dev/null @@ -1,173 +0,0 @@ -/obj/item/computer_hardware/hard_drive - name = "hard disk drive" - desc = "A small HDD, for use in basic computers where power efficiency is desired." - power_usage = 25 - icon_state = "harddisk_mini" - critical = 1 - w_class = WEIGHT_CLASS_TINY - origin_tech = "programming=1;engineering=1" - device_type = MC_HDD - var/max_capacity = 128 - var/used_capacity = 0 - var/list/stored_files = list() // List of stored files on this drive. DO NOT MODIFY DIRECTLY! - -/obj/item/computer_hardware/hard_drive/on_remove(obj/item/modular_computer/MC, mob/user) - MC.shutdown_computer() - -/obj/item/computer_hardware/hard_drive/proc/install_default_programs() - store_file(new/datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar - store_file(new/datum/computer_file/program/ntnetdownload(src)) // NTNet Downloader Utility, allows users to download more software from NTNet repository - store_file(new/datum/computer_file/program/filemanager(src)) // File manager, allows text editor functions and basic file manipulation. - -/obj/item/computer_hardware/hard_drive/examine(user) - . = ..() - . += "It has [max_capacity] GQ of storage capacity." - -/obj/item/computer_hardware/hard_drive/diagnostics(var/mob/user) - ..() - // 999 is a byond limit that is in place. It's unlikely someone will reach that many files anyway, since you would sooner run out of space. - to_chat(user, "NT-NFS File Table Status: [stored_files.len]/999") - to_chat(user, "Storage capacity: [used_capacity]/[max_capacity]GQ") - -// Use this proc to add file to the drive. Returns 1 on success and 0 on failure. Contains necessary sanity checks. -/obj/item/computer_hardware/hard_drive/proc/store_file(var/datum/computer_file/F) - if(!F || !istype(F)) - return 0 - - if(!can_store_file(F)) - return 0 - - if(!check_functionality()) - return 0 - - if(!stored_files) - return 0 - - // This file is already stored. Don't store it again. - if(F in stored_files) - return 0 - - F.holder = src - stored_files.Add(F) - recalculate_size() - return 1 - -// Use this proc to remove file from the drive. Returns 1 on success and 0 on failure. Contains necessary sanity checks. -/obj/item/computer_hardware/hard_drive/proc/remove_file(var/datum/computer_file/F) - if(!F || !istype(F)) - return 0 - - if(!stored_files) - return 0 - - if(!check_functionality()) - return 0 - - if(F in stored_files) - stored_files -= F - recalculate_size() - return 1 - else - return 0 - -// Loops through all stored files and recalculates used_capacity of this drive -/obj/item/computer_hardware/hard_drive/proc/recalculate_size() - var/total_size = 0 - for(var/datum/computer_file/F in stored_files) - total_size += F.size - - used_capacity = total_size - -// Checks whether file can be stored on the hard drive. We can only store unique files, so this checks whether we wouldn't get a duplicity by adding a file. -/obj/item/computer_hardware/hard_drive/proc/can_store_file(var/datum/computer_file/F) - if(!F || !istype(F)) - return 0 - - if(F in stored_files) - return 0 - - var/name = F.filename + "." + F.filetype - for(var/datum/computer_file/file in stored_files) - if((file.filename + "." + file.filetype) == name) - return 0 - - // In the unlikely event someone manages to create that many files. - // BYOND is acting weird with numbers above 999 in loops (infinite loop prevention) - if(stored_files.len >= 999) - return 0 - if((used_capacity + F.size) > max_capacity) - return 0 - else - return 1 - - -// Tries to find the file by filename. Returns null on failure -/obj/item/computer_hardware/hard_drive/proc/find_file_by_name(var/filename) - if(!check_functionality()) - return null - - if(!filename) - return null - - if(!stored_files) - return null - - for(var/datum/computer_file/F in stored_files) - if(F.filename == filename) - return F - return null - -/obj/item/computer_hardware/hard_drive/Destroy() - stored_files = null - return ..() - -/obj/item/computer_hardware/hard_drive/New() - install_default_programs() - ..() - - -/obj/item/computer_hardware/hard_drive/advanced - name = "advanced hard disk drive" - desc = "A hybrid HDD, for use in higher grade computers where balance between power efficiency and capacity is desired." - max_capacity = 256 - origin_tech = "programming=2;engineering=2" - power_usage = 50 // Hybrid, medium capacity and medium power storage - icon_state = "harddisk_mini" - w_class = WEIGHT_CLASS_SMALL - -/obj/item/computer_hardware/hard_drive/super - name = "super hard disk drive" - desc = "A high capacity HDD, for use in cluster storage solutions where capacity is more important than power efficiency." - max_capacity = 512 - origin_tech = "programming=3;engineering=3" - power_usage = 100 // High-capacity but uses lots of power, shortening battery life. Best used with APC link. - icon_state = "harddisk_mini" - w_class = WEIGHT_CLASS_SMALL - -/obj/item/computer_hardware/hard_drive/cluster - name = "cluster hard disk drive" - desc = "A large storage cluster consisting of multiple HDDs for usage in dedicated storage systems." - power_usage = 500 - origin_tech = "programming=4;engineering=4" - max_capacity = 2048 - icon_state = "harddisk" - w_class = WEIGHT_CLASS_NORMAL - -// For tablets, etc. - highly power efficient. -/obj/item/computer_hardware/hard_drive/small - name = "solid state drive" - desc = "An efficient SSD for portable devices." - power_usage = 10 - origin_tech = "programming=2;engineering=2" - max_capacity = 64 - icon_state = "ssd_mini" - w_class = WEIGHT_CLASS_TINY - -/obj/item/computer_hardware/hard_drive/micro - name = "micro solid state drive" - desc = "A highly efficient SSD chip for portable devices." - power_usage = 2 - origin_tech = "programming=1;engineering=1" - max_capacity = 32 - icon_state = "ssd_micro" - w_class = WEIGHT_CLASS_TINY diff --git a/code/modules/modular_computers/hardware/network_card.dm b/code/modules/modular_computers/hardware/network_card.dm deleted file mode 100644 index 3e5409b5d61..00000000000 --- a/code/modules/modular_computers/hardware/network_card.dm +++ /dev/null @@ -1,82 +0,0 @@ -GLOBAL_VAR_INIT(ntnet_card_uid, 1) - -/obj/item/computer_hardware/network_card - name = "network card" - desc = "A basic wireless network card for usage with standard NTNet frequencies." - power_usage = 50 - origin_tech = "programming=2;engineering=1" - icon_state = "radio_mini" - var/identification_id = null // Identification ID. Technically MAC address of this device. Can't be changed by user. - var/identification_string = "" // Identification string, technically nickname seen in the network. Can be set by user. - var/long_range = 0 - var/ethernet = 0 // Hard-wired, therefore always on, ignores NTNet wireless checks. - malfunction_probability = 1 - device_type = MC_NET - -/obj/item/computer_hardware/network_card/diagnostics(var/mob/user) - ..() - to_chat(user, "NIX Unique ID: [identification_id]") - to_chat(user, "NIX User Tag: [identification_string]") - to_chat(user, "Supported protocols:") - to_chat(user, "511.m SFS (Subspace) - Standard Frequency Spread") - if(long_range) - to_chat(user, "511.n WFS/HB (Subspace) - Wide Frequency Spread/High Bandiwdth") - if(ethernet) - to_chat(user, "OpenEth (Physical Connection) - Physical network connection port") - -/obj/item/computer_hardware/network_card/New(var/l) - ..(l) - identification_id = GLOB.ntnet_card_uid - GLOB.ntnet_card_uid++ - -// Returns a string identifier of this network card -/obj/item/computer_hardware/network_card/proc/get_network_tag() - return "[identification_string] (NID [identification_id])" - -// 0 - No signal, 1 - Low signal, 2 - High signal. 3 - Wired Connection -/obj/item/computer_hardware/network_card/proc/get_signal(var/specific_action = 0) - if(!holder) // Hardware is not installed in anything. No signal. How did this even get called? - return 0 - - if(!check_functionality()) - return 0 - - if(ethernet) // Computer is connected via wired connection. - return 3 - - if(!GLOB.ntnet_global || !GLOB.ntnet_global.check_function(specific_action)) // NTNet is down and we are not connected via wired connection. No signal. - return 0 - - if(holder) - - var/turf/T = get_turf(holder) - if((T && istype(T)) && is_station_contact(T.z)) - // Computer is on station. Low/High signal depending on what type of network card you have - if(long_range) - return 2 - else - return 1 - - if(long_range) // Computer is not on station, but it has upgraded network card. Low signal. - return 1 - - return 0 // Computer is not on station and does not have upgraded network card. No signal. - - -/obj/item/computer_hardware/network_card/advanced - name = "advanced network card" - desc = "An advanced network card for usage with standard NTNet frequencies. Its transmitter is strong enough to connect even off-station." - long_range = 1 - origin_tech = "programming=4;engineering=2" - power_usage = 100 // Better range but higher power usage. - icon_state = "radio" - w_class = WEIGHT_CLASS_TINY - -/obj/item/computer_hardware/network_card/wired - name = "wired network card" - desc = "An advanced network card for usage with standard NTNet frequencies. This one also supports wired connection." - ethernet = 1 - origin_tech = "programming=5;engineering=3" - power_usage = 100 // Better range but higher power usage. - icon_state = "net_wired" - w_class = WEIGHT_CLASS_NORMAL diff --git a/code/modules/modular_computers/hardware/portable_disk.dm b/code/modules/modular_computers/hardware/portable_disk.dm deleted file mode 100644 index 93c9c1f412b..00000000000 --- a/code/modules/modular_computers/hardware/portable_disk.dm +++ /dev/null @@ -1,35 +0,0 @@ -/obj/item/computer_hardware/hard_drive/portable - name = "data disk" - desc = "Removable disk used to store data." - power_usage = 10 - icon_state = "datadisk6" - w_class = WEIGHT_CLASS_TINY - critical = 0 - max_capacity = 16 - origin_tech = "programming=1" - device_type = MC_SDD - -/obj/item/computer_hardware/hard_drive/portable/on_install(obj/item/modular_computer/M, mob/living/user = null) - M.add_verb(device_type) - -/obj/item/computer_hardware/hard_drive/portable/on_remove(obj/item/modular_computer/M, mob/living/user = null) - ..() - M.remove_verb(device_type) - -/obj/item/computer_hardware/hard_drive/portable/install_default_programs() - return // Empty by default - -/obj/item/computer_hardware/hard_drive/portable/advanced - name = "advanced data disk" - power_usage = 20 - icon_state = "datadisk5" - max_capacity = 64 - origin_tech = "programming=2" - -/obj/item/computer_hardware/hard_drive/portable/super - name = "super data disk" - desc = "Removable disk used to store large amounts of data." - power_usage = 40 - icon_state = "datadisk3" - max_capacity = 256 - origin_tech = "programming=4" diff --git a/code/modules/modular_computers/hardware/printer.dm b/code/modules/modular_computers/hardware/printer.dm deleted file mode 100644 index 49c5d72a6f1..00000000000 --- a/code/modules/modular_computers/hardware/printer.dm +++ /dev/null @@ -1,70 +0,0 @@ -/obj/item/computer_hardware/printer - name = "printer" - desc = "Computer-integrated printer with paper recycling module." - power_usage = 100 - origin_tech = "programming=2;engineering=2" - icon_state = "printer" - w_class = WEIGHT_CLASS_NORMAL - device_type = MC_PRINT - var/stored_paper = 20 - var/max_paper = 30 - -/obj/item/computer_hardware/printer/diagnostics(mob/living/user) - ..() - to_chat(user, "Paper level: [stored_paper]/[max_paper]") - -/obj/item/computer_hardware/printer/examine(mob/user) - . = ..() - . += "Paper level: [stored_paper]/[max_paper]" - - -/obj/item/computer_hardware/printer/proc/print_text(var/text_to_print, var/paper_title = "") - if(!stored_paper) - return FALSE - if(!check_functionality()) - return FALSE - - var/obj/item/paper/P = new/obj/item/paper(holder.drop_location()) - - // Damaged printer causes the resulting paper to be somewhat harder to read. - if(damage > damage_malfunction) - P.info = stars(text_to_print, 100-malfunction_probability) - else - P.info = text_to_print - if(paper_title) - P.name = paper_title - P.update_icon() - P.populatefields() - P.updateinfolinks() - stored_paper-- - P = null - - playsound(loc, 'sound/goonstation/machines/printer_thermal.ogg', 50, 1) - - return TRUE - -/obj/item/computer_hardware/printer/try_insert(obj/item/I, mob/living/user = null) - if(istype(I, /obj/item/paper)) - if(stored_paper >= max_paper) - if(user) - to_chat(user, "You try to add \the [I] into [src], but its paper bin is full!") - return FALSE - - if(user && !user.unEquip(I)) - return FALSE - - if(user) - to_chat(user, "You insert \the [I] into [src]'s paper recycler.") - qdel(I) - stored_paper++ - return TRUE - return FALSE - -/obj/item/computer_hardware/printer/mini - name = "miniprinter" - desc = "A small printer with paper recycling module." - power_usage = 50 - icon_state = "printer_mini" - w_class = WEIGHT_CLASS_TINY - stored_paper = 5 - max_paper = 15 diff --git a/code/modules/modular_computers/hardware/recharger.dm b/code/modules/modular_computers/hardware/recharger.dm deleted file mode 100644 index 418a9736528..00000000000 --- a/code/modules/modular_computers/hardware/recharger.dm +++ /dev/null @@ -1,94 +0,0 @@ -/obj/item/computer_hardware/recharger - critical = 1 - enabled = 1 - var/charge_rate = 100 - device_type = MC_CHARGE - -/obj/item/computer_hardware/recharger/proc/use_power(amount, charging=0) - if(charging) - return 1 - return 0 - -/obj/item/computer_hardware/recharger/process() - ..() - var/obj/item/computer_hardware/battery/battery_module = holder.all_components[MC_CELL] - if(!holder || !battery_module || !battery_module.battery) - return - - var/obj/item/stock_parts/cell/cell = battery_module.battery - if(cell.charge >= cell.maxcharge) - return - - if(use_power(charge_rate, charging=1)) - holder.give_power(charge_rate * GLOB.CELLRATE) - - -/obj/item/computer_hardware/recharger/APC - name = "area power connector" - desc = "A device that wirelessly recharges connected device from nearby APC." - icon_state = "charger_APC" - w_class = WEIGHT_CLASS_SMALL // Can't be installed into tablets/PDAs - origin_tech = "programming=2;engineering=2;powerstorage=3" - -/obj/item/computer_hardware/recharger/APC/use_power(amount, charging=0) - if(istype(holder.physical, /obj/machinery)) - var/obj/machinery/M = holder.physical - if(M.powered()) - M.use_power(amount) - return 1 - - else - var/area/A = get_area(src) - if(!istype(A)) - return 0 - - if(A.powered(EQUIP)) - A.use_power(amount, EQUIP) - return 1 - return 0 - -/obj/item/computer_hardware/recharger/wired - name = "wired power connector" - desc = "A power connector that recharges connected device from nearby power wire. Incompatible with portable computers." - icon_state = "charger_wire" - w_class = WEIGHT_CLASS_NORMAL - origin_tech = "engineering=2;powerstorage=1" - -/obj/item/computer_hardware/recharger/wired/can_install(obj/item/modular_computer/M, mob/living/user = null) - if(istype(M.physical, /obj/machinery) && M.physical.anchored) - return ..() - if(user) - to_chat(user, "\The [src] is incompatible with portable computers!") - return 0 - -/obj/item/computer_hardware/recharger/wired/use_power(amount, charging=0) - if(istype(holder.physical, /obj/machinery) && holder.physical.anchored) - var/obj/machinery/M = holder.physical - var/turf/T = M.loc - if(!T || !istype(T)) - return 0 - - var/obj/structure/cable/C = T.get_cable_node() - if(!C || !C.powernet) - return 0 - - var/power_in_net = C.powernet.avail-C.powernet.load - - if(power_in_net && power_in_net > amount) - C.powernet.load += amount - return 1 - - return 0 - - - -// This is not intended to be obtainable in-game. Intended for adminbus and debugging purposes. -/obj/item/computer_hardware/recharger/lambda - name = "lambda coil" - desc = "A very complex device that draws power from its own bluespace dimension." - icon_state = "charger_lambda" - w_class = WEIGHT_CLASS_TINY - charge_rate = 100000 - -/obj/item/computer_hardware/recharger/lambda/use_power(amount, charging=0) - return 1 diff --git a/code/modules/modular_computers/laptop_vendor.dm b/code/modules/modular_computers/laptop_vendor.dm deleted file mode 100644 index a6aee63a3af..00000000000 --- a/code/modules/modular_computers/laptop_vendor.dm +++ /dev/null @@ -1,291 +0,0 @@ -// A vendor machine for modular computer portable devices - Laptops and Tablets - -/obj/machinery/lapvend - name = "computer vendor" - desc = "A vending machine with a built-in microfabricator, capable of dispensing various NT-branded computers." - icon = 'icons/obj/vending.dmi' - icon_state = "robotics" - layer = BELOW_OBJ_LAYER - anchored = 1 - density = 1 - - // The actual laptop/tablet - var/obj/item/modular_computer/laptop/fabricated_laptop = null - var/obj/item/modular_computer/tablet/fabricated_tablet = null - - // Utility vars - var/state = 0 // 0: Select device type, 1: Select loadout, 2: Payment, 3: Thankyou screen - var/devtype = 0 // 0: None(unselected), 1: Laptop, 2: Tablet - var/total_price = 0 // Price of currently vended device. - - // Device loadout - var/dev_cpu = 1 // 1: Default, 2: Upgraded - var/dev_battery = 1 // 1: Default, 2: Upgraded, 3: Advanced - var/dev_disk = 1 // 1: Default, 2: Upgraded, 3: Advanced - var/dev_netcard = 0 // 0: None, 1: Basic, 2: Long-Range - var/dev_apc_recharger = 0 // 0: None, 1: Standard (LAPTOP ONLY) - var/dev_printer = 0 // 0: None, 1: Standard - var/dev_card = 0 // 0: None, 1: Standard - -// Removes all traces of old order and allows you to begin configuration from scratch. -/obj/machinery/lapvend/proc/reset_order() - state = 0 - devtype = 0 - QDEL_NULL(fabricated_laptop) - QDEL_NULL(fabricated_tablet) - dev_cpu = 1 - dev_battery = 1 - dev_disk = 1 - dev_netcard = 0 - dev_apc_recharger = 0 - dev_printer = 0 - dev_card = 0 - -// Recalculates the price and optionally even fabricates the device. -/obj/machinery/lapvend/proc/fabricate_and_recalc_price(fabricate = 0) - total_price = 0 - if(devtype == 1) // Laptop, generally cheaper to make it accessible for most station roles - var/obj/item/computer_hardware/battery/battery_module = null - if(fabricate) - fabricated_laptop = new /obj/item/modular_computer/laptop/buildable(src) - fabricated_laptop.install_component(new /obj/item/computer_hardware/battery) - battery_module = fabricated_laptop.all_components[MC_CELL] - total_price = 99 - switch(dev_cpu) - if(1) - if(fabricate) - fabricated_laptop.install_component(new /obj/item/computer_hardware/processor_unit/small) - if(2) - if(fabricate) - fabricated_laptop.install_component(new /obj/item/computer_hardware/processor_unit) - total_price += 299 - switch(dev_battery) - if(1) // Basic(750C) - if(fabricate) - battery_module.try_insert(new /obj/item/stock_parts/cell/computer) - if(2) // Upgraded(1100C) - if(fabricate) - battery_module.try_insert(new /obj/item/stock_parts/cell/computer/advanced) - total_price += 199 - if(3) // Advanced(1500C) - if(fabricate) - battery_module.try_insert(new /obj/item/stock_parts/cell/computer/super) - total_price += 499 - switch(dev_disk) - if(1) // Basic(128GQ) - if(fabricate) - fabricated_laptop.install_component(new /obj/item/computer_hardware/hard_drive) - if(2) // Upgraded(256GQ) - if(fabricate) - fabricated_laptop.install_component(new /obj/item/computer_hardware/hard_drive/advanced) - total_price += 99 - if(3) // Advanced(512GQ) - if(fabricate) - fabricated_laptop.install_component(new /obj/item/computer_hardware/hard_drive/super) - total_price += 299 - switch(dev_netcard) - if(1) // Basic(Short-Range) - if(fabricate) - fabricated_laptop.install_component(new /obj/item/computer_hardware/network_card) - total_price += 99 - if(2) // Advanced (Long Range) - if(fabricate) - fabricated_laptop.install_component(new /obj/item/computer_hardware/network_card/advanced) - total_price += 299 - if(dev_apc_recharger) - total_price += 399 - if(fabricate) - fabricated_laptop.install_component(new /obj/item/computer_hardware/recharger/APC) - if(dev_printer) - total_price += 99 - if(fabricate) - fabricated_laptop.install_component(new /obj/item/computer_hardware/printer/mini) - if(dev_card) - total_price += 199 - if(fabricate) - fabricated_laptop.install_component(new /obj/item/computer_hardware/card_slot) - - return total_price - else if(devtype == 2) // Tablet, more expensive, not everyone could probably afford this. - var/obj/item/computer_hardware/battery/battery_module = null - if(fabricate) - fabricated_tablet = new(src) - fabricated_tablet.install_component(new /obj/item/computer_hardware/battery) - fabricated_tablet.install_component(new /obj/item/computer_hardware/processor_unit/small) - battery_module = fabricated_tablet.all_components[MC_CELL] - total_price = 199 - switch(dev_battery) - if(1) // Basic(300C) - if(fabricate) - battery_module.try_insert(new /obj/item/stock_parts/cell/computer/nano) - if(2) // Upgraded(500C) - if(fabricate) - battery_module.try_insert(new /obj/item/stock_parts/cell/computer/micro) - total_price += 199 - if(3) // Advanced(750C) - if(fabricate) - battery_module.try_insert(new /obj/item/stock_parts/cell/computer) - total_price += 499 - switch(dev_disk) - if(1) // Basic(32GQ) - if(fabricate) - fabricated_tablet.install_component(new /obj/item/computer_hardware/hard_drive/micro) - if(2) // Upgraded(64GQ) - if(fabricate) - fabricated_tablet.install_component(new /obj/item/computer_hardware/hard_drive/small) - total_price += 99 - if(3) // Advanced(128GQ) - if(fabricate) - fabricated_tablet.install_component(new /obj/item/computer_hardware/hard_drive) - total_price += 299 - switch(dev_netcard) - if(1) // Basic(Short-Range) - if(fabricate) - fabricated_tablet.install_component(new/obj/item/computer_hardware/network_card) - total_price += 99 - if(2) // Advanced (Long Range) - if(fabricate) - fabricated_tablet.install_component(new/obj/item/computer_hardware/network_card/advanced) - total_price += 299 - if(dev_printer) - total_price += 99 - if(fabricate) - fabricated_tablet.install_component(new/obj/item/computer_hardware/printer) - if(dev_card) - total_price += 199 - if(fabricate) - fabricated_tablet.install_component(new/obj/item/computer_hardware/card_slot) - return total_price - return 0 - - -/obj/machinery/lapvend/Topic(href, href_list) - if(..()) - return 1 - - switch(href_list["action"]) - if("pick_device") - if(state) // We've already picked a device type - return 0 - devtype = text2num(href_list["pick"]) - state = 1 - fabricate_and_recalc_price(0) - return 1 - if("clean_order") - reset_order() - return 1 - if((state != 1) && devtype) // Following IFs should only be usable when in the Select Loadout mode - return 0 - switch(href_list["action"]) - if("confirm_order") - state = 2 // Wait for ID swipe for payment processing - fabricate_and_recalc_price(0) - return 1 - if("hw_cpu") - dev_cpu = text2num(href_list["cpu"]) - fabricate_and_recalc_price(0) - return 1 - if("hw_battery") - dev_battery = text2num(href_list["battery"]) - fabricate_and_recalc_price(0) - return 1 - if("hw_disk") - dev_disk = text2num(href_list["disk"]) - fabricate_and_recalc_price(0) - return 1 - if("hw_netcard") - dev_netcard = text2num(href_list["netcard"]) - fabricate_and_recalc_price(0) - return 1 - if("hw_tesla") - dev_apc_recharger = text2num(href_list["tesla"]) - fabricate_and_recalc_price(0) - return 1 - if("hw_nanoprint") - dev_printer = text2num(href_list["print"]) - fabricate_and_recalc_price(0) - return 1 - if("hw_card") - dev_card = text2num(href_list["card"]) - fabricate_and_recalc_price(0) - return 1 - return 0 - -/obj/machinery/lapvend/attack_hand(mob/user) - ui_interact(user) - -/obj/machinery/lapvend/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, "computer_fabricator.tmpl", "Personal Computer Vendor", 500, 700) - ui.set_auto_update(1) - ui.open() - -/obj/machinery/lapvend/ui_data(mob/user) - var/list/data[0] - data["state"] = state - if(state == 1) - data["devtype"] = devtype - data["hw_battery"] = dev_battery - data["hw_disk"] = dev_disk - data["hw_netcard"] = dev_netcard - data["hw_tesla"] = dev_apc_recharger - data["hw_nanoprint"] = dev_printer - data["hw_card"] = dev_card - data["hw_cpu"] = dev_cpu - if(state == 1 || state == 2) - data["totalprice"] = total_price - return data - -/obj/machinery/lapvend/attackby(obj/item/I, mob/user) - var/obj/item/card/id/C - if(istype(I, /obj/item/card/id)) - C = I - if(istype(I, /obj/item/pda)) - var/obj/item/pda/PDA = I - if(PDA.id) - C = PDA.id - - if(C && istype(C) && state == 2) - if(process_payment(C, I)) - fabricate_and_recalc_price(1) - if((devtype == 1) && fabricated_laptop) - fabricated_laptop.forceMove(loc) - fabricated_laptop = null - else if((devtype == 2) && fabricated_tablet) - fabricated_tablet.update_icon() - fabricated_tablet.forceMove(loc) - fabricated_tablet = null - atom_say("Enjoy your new product!") - state = 3 - return 1 - return 0 - return ..() - - -// Simplified payment processing, returns 1 on success. -/obj/machinery/lapvend/proc/process_payment(obj/item/card/id/I, obj/item/ID_container) - visible_message("\The [usr] swipes \the [ID_container] through \the [src].") - var/datum/money_account/customer_account = get_card_account(I) - if(!customer_account || customer_account.suspended) - atom_say("Connection error. Unable to connect to account.") - return 0 - - 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 - customer_account = attempt_account_access(I.associated_account_number, attempt_pin, 2) - - if(!customer_account) - atom_say("Unable to access account: incorrect credentials.") - return 0 - - if(total_price > customer_account.money) - atom_say("Insufficient funds in account.") - return 0 - else - customer_account.charge(total_price, GLOB.vendor_account, - "Purchase of [(devtype == 1) ? "laptop computer" : "tablet microcomputer"].", - name, customer_account.owner_name, "Sale of [(devtype == 1) ? "laptop computer" : "tablet microcomputer"].", - customer_account.owner_name) - - return 1 diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm index fd526d0e12a..0938dd7af76 100644 --- a/code/modules/projectiles/ammunition.dm +++ b/code/modules/projectiles/ammunition.dm @@ -19,6 +19,15 @@ var/click_cooldown_override = 0 //Override this to make your gun have a faster fire rate, in tenths of a second. 4 is the default gun cooldown. var/harmful = TRUE //pacifism check for boolet, set to FALSE if bullet is non-lethal + /// What type of muzzle flash effect will be shown. If null then no effect and flash of light will be shown + var/muzzle_flash_effect = /obj/effect/temp_visual/target_angled/muzzle_flash + /// What color the flash has. If null then the flash won't cause lighting + var/muzzle_flash_color = LIGHT_COLOR_TUNGSTEN + /// What range the muzzle flash has + var/muzzle_flash_range = MUZZLE_FLASH_RANGE_WEAK + /// How strong the flash is + var/muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_WEAK + /obj/item/ammo_casing/New() ..() if(projectile_type) diff --git a/code/modules/projectiles/ammunition/ammo_casings.dm b/code/modules/projectiles/ammunition/ammo_casings.dm index 92ecf815104..ec2bb5e6ad3 100644 --- a/code/modules/projectiles/ammunition/ammo_casings.dm +++ b/code/modules/projectiles/ammunition/ammo_casings.dm @@ -2,6 +2,8 @@ desc = "A .357 bullet casing." caliber = "357" projectile_type = /obj/item/projectile/bullet + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG /obj/item/ammo_casing/rubber9mm desc = "A 9mm rubber bullet casing." @@ -14,6 +16,8 @@ icon_state = "762-casing" caliber = "a762" projectile_type = /obj/item/projectile/bullet + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_STRONG + muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG /obj/item/ammo_casing/a762/enchanted projectile_type = /obj/item/projectile/bullet/weakbullet3 @@ -22,15 +26,20 @@ desc = "A .50AE bullet casing." caliber = ".50" projectile_type = /obj/item/projectile/bullet + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG /obj/item/ammo_casing/c38 desc = "A .38 bullet casing." caliber = "38" icon_state = "r-casing" projectile_type = /obj/item/projectile/bullet/weakbullet2 + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/c38/invisible projectile_type = /obj/item/projectile/bullet/weakbullet2/invisible + muzzle_flash_effect = null // invisible eh /obj/item/ammo_casing/c38/invisible/fake projectile_type = /obj/item/projectile/bullet/weakbullet2/invisible/fake @@ -39,12 +48,15 @@ desc = "A 10mm bullet casing." caliber = "10mm" projectile_type = /obj/item/projectile/bullet/midbullet3 + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/c10mm/ap projectile_type = /obj/item/projectile/bullet/midbullet3/ap /obj/item/ammo_casing/c10mm/fire projectile_type = /obj/item/projectile/bullet/midbullet3/fire + muzzle_flash_color = LIGHT_COLOR_FIRE /obj/item/ammo_casing/c10mm/hp projectile_type = /obj/item/projectile/bullet/midbullet3/hp @@ -53,62 +65,60 @@ desc = "A 9mm bullet casing." caliber = "9mm" projectile_type = /obj/item/projectile/bullet/weakbullet3 + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_WEAK + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL -/obj/item/ammo_casing/c9mmap - desc = "A 9mm bullet casing." - caliber = "9mm" +/obj/item/ammo_casing/c9mm/ap projectile_type = /obj/item/projectile/bullet/armourpiercing -/obj/item/ammo_casing/c9mmtox - desc = "A 9mm bullet casing." - caliber = "9mm" +/obj/item/ammo_casing/c9mm/tox projectile_type = /obj/item/projectile/bullet/toxinbullet -/obj/item/ammo_casing/c9mminc - desc = "A 9mm bullet casing." - caliber = "9mm" +/obj/item/ammo_casing/c9mm/inc projectile_type = /obj/item/projectile/bullet/incendiary/firebullet + muzzle_flash_color = LIGHT_COLOR_FIRE /obj/item/ammo_casing/c46x30mm desc = "A 4.6x30mm bullet casing." caliber = "4.6x30mm" projectile_type = /obj/item/projectile/bullet/weakbullet3 + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_WEAK + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL -/obj/item/ammo_casing/c46x30mmap - desc = "A 4.6x30mm bullet casing." - caliber = "4.6x30mm" +/obj/item/ammo_casing/c46x30mm/ap projectile_type = /obj/item/projectile/bullet/armourpiercing -/obj/item/ammo_casing/c46x30mmtox - desc = "A 4.6x30mm bullet casing." - caliber = "4.6x30mm" +/obj/item/ammo_casing/c46x30mm/tox projectile_type = /obj/item/projectile/bullet/toxinbullet -/obj/item/ammo_casing/c46x30mminc - desc = "A 4.6x30mm bullet casing." - caliber = "4.6x30mm" +/obj/item/ammo_casing/c46x30mm/inc projectile_type = /obj/item/projectile/bullet/incendiary/firebullet + muzzle_flash_color = LIGHT_COLOR_FIRE /obj/item/ammo_casing/rubber45 desc = "A .45 rubber bullet casing." caliber = ".45" icon_state = "r-casing" projectile_type = /obj/item/projectile/bullet/midbullet_r + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/c45 desc = "A .45 bullet casing." caliber = ".45" projectile_type = /obj/item/projectile/bullet/midbullet + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL -/obj/item/ammo_casing/c45nostamina - desc = "A .45 bullet casing." - caliber = ".45" +/obj/item/ammo_casing/c45/nostamina projectile_type = /obj/item/projectile/bullet/midbullet3 /obj/item/ammo_casing/n762 desc = "A 7.62x38mmR bullet casing." caliber = "n762" projectile_type = /obj/item/projectile/bullet + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG /obj/item/ammo_casing/caseless/magspear name = "magnetic spear" @@ -118,6 +128,7 @@ icon_state = "magspear" throwforce = 15 //still deadly when thrown throw_speed = 3 + muzzle_flash_color = null /obj/item/ammo_casing/shotgun name = "shotgun slug" @@ -127,6 +138,8 @@ drop_sound = 'sound/weapons/gun_interactions/shotgun_fall.ogg' projectile_type = /obj/item/projectile/bullet materials = list(MAT_METAL=4000) + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_STRONG + muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG /obj/item/ammo_casing/shotgun/buckshot @@ -153,6 +166,8 @@ icon_state = "bshell" projectile_type = /obj/item/projectile/bullet/weakbullet materials = list(MAT_METAL=250) + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/shotgun/improvised @@ -163,6 +178,8 @@ materials = list(MAT_METAL=250) pellets = 10 variance = 25 + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/shotgun/improvised/overload @@ -174,6 +191,8 @@ materials = list(MAT_METAL=250) pellets = 4 variance = 40 + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG /obj/item/ammo_casing/shotgun/stunslug @@ -182,6 +201,9 @@ icon_state = "stunshell" projectile_type = /obj/item/projectile/bullet/stunshot materials = list(MAT_METAL=250) + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL + muzzle_flash_color = "#FFFF00" /obj/item/ammo_casing/shotgun/meteorshot @@ -203,12 +225,14 @@ would have difficulty with." icon_state = "pshell" projectile_type = /obj/item/projectile/beam/pulse/shot + muzzle_flash_color = LIGHT_COLOR_DARKBLUE /obj/item/ammo_casing/shotgun/incendiary name = "incendiary slug" desc = "An incendiary-coated shotgun slug." icon_state = "ishell" projectile_type = /obj/item/projectile/bullet/incendiary/shell + muzzle_flash_color = LIGHT_COLOR_FIRE /obj/item/ammo_casing/shotgun/frag12 name = "FRAG-12 slug" @@ -223,6 +247,7 @@ projectile_type = /obj/item/projectile/bullet/incendiary/shell/dragonsbreath pellets = 4 variance = 35 + muzzle_flash_color = LIGHT_COLOR_FIRE /obj/item/ammo_casing/shotgun/ion name = "ion shell" @@ -232,12 +257,18 @@ projectile_type = /obj/item/projectile/ion/weak pellets = 4 variance = 35 + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL + muzzle_flash_color = LIGHT_COLOR_LIGHTBLUE /obj/item/ammo_casing/shotgun/laserslug name = "laser slug" desc = "An advanced shotgun shell that uses a micro laser to replicate the effects of a laser weapon in a ballistic package." icon_state = "lshell" projectile_type = /obj/item/projectile/beam/laser + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL + muzzle_flash_color = LIGHT_COLOR_DARKRED /obj/item/ammo_casing/shotgun/techshell name = "unloaded technological shell" @@ -251,6 +282,8 @@ icon_state = "cshell" container_type = OPENCONTAINER projectile_type = /obj/item/projectile/bullet/dart + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/shotgun/dart/New() ..() @@ -275,18 +308,24 @@ desc = "A tranquilizer round used to subdue individuals utilizing stimulants." icon_state = "nshell" projectile_type = /obj/item/projectile/bullet/dart/syringe/tranquilizer + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL materials = list(MAT_METAL=250) /obj/item/ammo_casing/a556 desc = "A 5.56mm bullet casing." caliber = "a556" projectile_type = /obj/item/projectile/bullet/heavybullet + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/shotgun/fakebeanbag name = "beanbag shell" desc = "A weak beanbag shell." icon_state = "bshell" projectile_type = /obj/item/projectile/bullet/weakbullet/booze + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/rocket name = "rocket shell" @@ -294,6 +333,8 @@ icon_state = "rocketshell" projectile_type = /obj/item/missile caliber = "rocket" + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_STRONG + muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG /obj/item/ammo_casing/caseless desc = "A caseless bullet casing." @@ -309,6 +350,8 @@ desc = "A .75 bullet casing." caliber = "75" projectile_type = /obj/item/projectile/bullet/gyro + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_STRONG + muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG /obj/item/ammo_casing/a40mm name = "40mm HE shell" @@ -316,11 +359,14 @@ caliber = "40mm" icon_state = "40mmHE" projectile_type = /obj/item/projectile/bullet/a40mm + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/caseless/foam_dart name = "foam dart" desc = "It's nerf or nothing! Ages 8 and up." projectile_type = /obj/item/projectile/bullet/reusable/foam_dart + muzzle_flash_effect = null caliber = "foam_force" icon = 'icons/obj/guns/toy.dmi' icon_state = "foamdart" @@ -403,6 +449,7 @@ name = "assassination shell" desc = "A specialist shrapnel shell that has been laced with a silencing toxin." projectile_type = /obj/item/projectile/bullet/pellet/assassination + muzzle_flash_effect = null icon_state = "gshell" pellets = 6 variance = 25 @@ -411,9 +458,15 @@ desc = "A cap for children toys." caliber = "cap" projectile_type = /obj/item/projectile/bullet/cap + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL /obj/item/ammo_casing/laser desc = "An experimental laser casing." caliber = "laser" projectile_type = /obj/item/projectile/beam/laser + muzzle_flash_effect = /obj/effect/temp_visual/target_angled/muzzle_flash/energy + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_WEAK + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL + muzzle_flash_color = LIGHT_COLOR_DARKRED icon_state = "lasercasing" diff --git a/code/modules/projectiles/ammunition/energy.dm b/code/modules/projectiles/ammunition/energy.dm index bcadfc62e08..a809953b8fd 100644 --- a/code/modules/projectiles/ammunition/energy.dm +++ b/code/modules/projectiles/ammunition/energy.dm @@ -6,9 +6,11 @@ var/e_cost = 100 //The amount of energy a cell needs to expend to create this shot. var/select_name = "energy" fire_sound = 'sound/weapons/laser.ogg' + muzzle_flash_effect = /obj/effect/temp_visual/target_angled/muzzle_flash/energy /obj/item/ammo_casing/energy/laser projectile_type = /obj/item/projectile/beam/laser + muzzle_flash_color = LIGHT_COLOR_DARKRED select_name = "kill" /obj/item/ammo_casing/energy/laser/cyborg //to balance cyborg energy cost seperately @@ -16,6 +18,7 @@ /obj/item/ammo_casing/energy/lasergun projectile_type = /obj/item/projectile/beam/laser + muzzle_flash_color = LIGHT_COLOR_DARKRED e_cost = 83 select_name = "kill" @@ -40,6 +43,7 @@ /obj/item/ammo_casing/energy/laser/pulse projectile_type = /obj/item/projectile/beam/pulse + muzzle_flash_color = LIGHT_COLOR_DARKBLUE e_cost = 200 select_name = "DESTROY" fire_sound = 'sound/weapons/pulse.ogg' @@ -52,6 +56,7 @@ /obj/item/ammo_casing/energy/laser/bluetag projectile_type = /obj/item/projectile/beam/lasertag/bluetag + muzzle_flash_color = LIGHT_COLOR_BLUE select_name = "bluetag" harmful = FALSE @@ -62,6 +67,7 @@ /obj/item/ammo_casing/energy/xray projectile_type = /obj/item/projectile/beam/xray + muzzle_flash_color = LIGHT_COLOR_GREEN e_cost = 100 fire_sound = 'sound/weapons/laser3.ogg' @@ -92,6 +98,7 @@ /obj/item/ammo_casing/energy/electrode projectile_type = /obj/item/projectile/energy/electrode + muzzle_flash_color = "#FFFF00" select_name = "stun" fire_sound = 'sound/weapons/taser.ogg' e_cost = 200 @@ -107,11 +114,13 @@ /obj/item/ammo_casing/energy/ion projectile_type = /obj/item/projectile/ion + muzzle_flash_color = LIGHT_COLOR_LIGHTBLUE select_name = "ion" fire_sound = 'sound/weapons/ionrifle.ogg' /obj/item/ammo_casing/energy/declone projectile_type = /obj/item/projectile/energy/declone + muzzle_flash_color = LIGHT_COLOR_GREEN select_name = "declone" fire_sound = 'sound/weapons/pulse3.ogg' @@ -122,6 +131,7 @@ /obj/item/ammo_casing/energy/flora fire_sound = 'sound/effects/stealthoff.ogg' + muzzle_flash_color = LIGHT_COLOR_GREEN harmful = FALSE /obj/item/ammo_casing/energy/flora/yield @@ -146,10 +156,13 @@ /obj/item/ammo_casing/energy/meteor projectile_type = /obj/item/projectile/meteor + muzzle_flash_effect = /obj/effect/temp_visual/target_angled/muzzle_flash + muzzle_flash_color = null select_name = "goddamn meteor" /obj/item/ammo_casing/energy/disabler projectile_type = /obj/item/projectile/beam/disabler + muzzle_flash_color = LIGHT_COLOR_LIGHTBLUE select_name = "disable" e_cost = 50 fire_sound = 'sound/weapons/taser2.ogg' @@ -160,6 +173,7 @@ /obj/item/ammo_casing/energy/plasma projectile_type = /obj/item/projectile/plasma + muzzle_flash_color = LIGHT_COLOR_PURPLE select_name = "plasma burst" fire_sound = 'sound/weapons/plasma_cutter.ogg' delay = 15 @@ -172,6 +186,7 @@ /obj/item/ammo_casing/energy/wormhole projectile_type = /obj/item/projectile/beam/wormhole + muzzle_flash_color = "#33CCFF" e_cost = 0 fire_sound = 'sound/weapons/pulse3.ogg' var/obj/item/gun/energy/wormhole_projector/gun = null @@ -183,10 +198,13 @@ /obj/item/ammo_casing/energy/wormhole/orange projectile_type = /obj/item/projectile/beam/wormhole/orange + muzzle_flash_color = "#FF6600" select_name = "orange" /obj/item/ammo_casing/energy/bolt projectile_type = /obj/item/projectile/energy/bolt + muzzle_flash_color = null + muzzle_flash_effect = /obj/effect/temp_visual/target_angled/muzzle_flash select_name = "bolt" e_cost = 500 fire_sound = 'sound/weapons/genhit.ogg' @@ -203,17 +221,21 @@ /obj/item/ammo_casing/energy/instakill projectile_type = /obj/item/projectile/beam/instakill + muzzle_flash_color = LIGHT_COLOR_PURPLE e_cost = 0 select_name = "DESTROY" /obj/item/ammo_casing/energy/instakill/blue projectile_type = /obj/item/projectile/beam/instakill/blue + muzzle_flash_color = LIGHT_COLOR_DARKBLUE /obj/item/ammo_casing/energy/instakill/red projectile_type = /obj/item/projectile/beam/instakill/red + muzzle_flash_color = LIGHT_COLOR_DARKRED /obj/item/ammo_casing/energy/plasma projectile_type = /obj/item/projectile/plasma + muzzle_flash_color = LIGHT_COLOR_PURPLE select_name = "plasma burst" fire_sound = 'sound/weapons/pulse.ogg' @@ -224,26 +246,31 @@ fire_sound = 'sound/magic/lightningbolt.ogg' e_cost = 200 select_name = "lightning beam" + muzzle_flash_color = LIGHT_COLOR_FADEDPURPLE projectile_type = /obj/item/projectile/energy/shock_revolver /obj/item/ammo_casing/energy/toxplasma projectile_type = /obj/item/projectile/energy/toxplasma + muzzle_flash_color = LIGHT_COLOR_FADEDPURPLE fire_sound = 'sound/weapons/taser2.ogg' select_name = "plasma dart" /obj/item/ammo_casing/energy/clown projectile_type = /obj/item/projectile/clown + muzzle_flash_effect = null fire_sound = 'sound/weapons/gunshots/gunshot_smg.ogg' select_name = "clown" /obj/item/ammo_casing/energy/sniper projectile_type = /obj/item/projectile/beam/sniper + muzzle_flash_color = LIGHT_COLOR_PINK fire_sound = 'sound/weapons/marauder.ogg' delay = 50 select_name = "snipe" /obj/item/ammo_casing/energy/teleport projectile_type = /obj/item/projectile/energy/teleport + muzzle_flash_color = LIGHT_COLOR_LIGHTBLUE fire_sound = 'sound/weapons/wave.ogg' e_cost = 250 select_name = "teleport beam" @@ -258,6 +285,7 @@ /obj/item/ammo_casing/energy/mimic projectile_type = /obj/item/projectile/mimic + muzzle_flash_effect = null fire_sound = 'sound/weapons/bite.ogg' select_name = "gun mimic" var/mimic_type diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm index 5cc6a19b840..135f8c14718 100644 --- a/code/modules/projectiles/ammunition/magazines.dm +++ b/code/modules/projectiles/ammunition/magazines.dm @@ -271,15 +271,15 @@ /obj/item/ammo_box/magazine/wt550m9/wtap name = "wt550 magazine (Armour Piercing 4.6x30mm)" - ammo_type = /obj/item/ammo_casing/c46x30mmap + ammo_type = /obj/item/ammo_casing/c46x30mm/ap /obj/item/ammo_box/magazine/wt550m9/wttx name = "wt550 magazine (Toxin Tipped 4.6x30mm)" - ammo_type = /obj/item/ammo_casing/c46x30mmtox + ammo_type = /obj/item/ammo_casing/c46x30mm/tox /obj/item/ammo_box/magazine/wt550m9/wtic name = "wt550 magazine (Incendiary 4.6x30mm)" - ammo_type = /obj/item/ammo_casing/c46x30mminc + ammo_type = /obj/item/ammo_casing/c46x30mm/inc /obj/item/ammo_box/magazine/uzim9mm name = "uzi magazine (9mm)" @@ -302,17 +302,17 @@ /obj/item/ammo_box/magazine/smgm9mm/ap name = "SMG magazine (Armour Piercing 9mm)" - ammo_type = /obj/item/ammo_casing/c9mmap + ammo_type = /obj/item/ammo_casing/c9mm/ap materials = list(MAT_METAL = 3000) /obj/item/ammo_box/magazine/smgm9mm/toxin name = "SMG magazine (Toxin Tipped 9mm)" - ammo_type = /obj/item/ammo_casing/c9mmtox + ammo_type = /obj/item/ammo_casing/c9mm/tox materials = list(MAT_METAL = 3000) /obj/item/ammo_box/magazine/smgm9mm/fire name = "SMG Magazine (Incendiary 9mm)" - ammo_type = /obj/item/ammo_casing/c9mminc + ammo_type = /obj/item/ammo_casing/c9mm/inc materials = list(MAT_METAL = 3000) /obj/item/ammo_box/magazine/smgm9mm/update_icon() diff --git a/code/modules/projectiles/ammunition/special.dm b/code/modules/projectiles/ammunition/special.dm index 5fa53566fe5..f37690e2787 100644 --- a/code/modules/projectiles/ammunition/special.dm +++ b/code/modules/projectiles/ammunition/special.dm @@ -2,6 +2,8 @@ name = "magic casing" desc = "I didn't even know magic needed ammo..." projectile_type = /obj/item/projectile/magic + muzzle_flash_color = COLOR_BLUE_GRAY + muzzle_flash_effect = /obj/effect/temp_visual/target_angled/muzzle_flash/magic /obj/item/ammo_casing/magic/change projectile_type = /obj/item/projectile/magic/change @@ -40,13 +42,14 @@ projectile_type = pick(typesof(/obj/item/projectile/magic)) ..() -/obj/item/ammo_casing/forcebolt +/obj/item/ammo_casing/magic/forcebolt projectile_type = /obj/item/projectile/forcebolt /obj/item/ammo_casing/syringegun name = "syringe gun spring" desc = "A high-power spring that throws syringes." projectile_type = null + muzzle_flash_effect = null /obj/item/ammo_casing/energy/c3dbullet projectile_type = /obj/item/projectile/bullet/midbullet3 diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 3e41bf81271..ab21182e98f 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -109,20 +109,33 @@ to_chat(user, "*click*") playsound(user, 'sound/weapons/empty.ogg', 100, 1) -/obj/item/gun/proc/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1) +/obj/item/gun/proc/shoot_live_shot(mob/living/user, atom/target, pointblank = FALSE, message = TRUE) if(recoil) shake_camera(user, recoil + 1, recoil) + var/muzzle_range = chambered.muzzle_flash_range + var/muzzle_strength = chambered.muzzle_flash_strength + var/muzzle_flash_time = 0.2 SECONDS if(suppressed) playsound(user, fire_sound, 10, 1) + muzzle_range *= 0.5 + muzzle_strength *= 0.2 + muzzle_flash_time *= 0.5 else playsound(user, fire_sound, 50, 1) - if(!message) - return - if(pointblank) - user.visible_message("[user] fires [src] point blank at [pbtarget]!", "You fire [src] point blank at [pbtarget]!", "You hear \a [fire_sound_text]!") + if(message) + if(pointblank) + user.visible_message("[user] fires [src] point blank at [target]!", "You fire [src] point blank at [target]!", "You hear \a [fire_sound_text]!") + else + user.visible_message("[user] fires [src]!", "You fire [src]!", "You hear \a [fire_sound_text]!") + if(chambered.muzzle_flash_effect) + var/obj/effect/temp_visual/target_angled/muzzle_flash/effect = new chambered.muzzle_flash_effect(get_turf(src), target, muzzle_flash_time) + effect.alpha = min(255, muzzle_strength * 255) + if(chambered.muzzle_flash_color) + effect.color = chambered.muzzle_flash_color + effect.set_light(muzzle_range, muzzle_strength, chambered.muzzle_flash_color) else - user.visible_message("[user] fires [src]!", "You fire [src]!", "You hear \a [fire_sound_text]!") + effect.color = LIGHT_COLOR_TUNGSTEN /obj/item/gun/emp_act(severity) for(var/obj/O in contents) @@ -228,9 +241,9 @@ break else if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot - shoot_live_shot(user, 1, target, message) + shoot_live_shot(user, target, TRUE, message) else - shoot_live_shot(user, 0, target, message) + shoot_live_shot(user, target, FALSE, message) else shoot_with_empty_chamber(user) break @@ -250,9 +263,9 @@ return else if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot - shoot_live_shot(user, 1, target, message) + shoot_live_shot(user, target, TRUE, message) else - shoot_live_shot(user, 0, target, message) + shoot_live_shot(user, target, FALSE, message) else shoot_with_empty_chamber(user) return diff --git a/code/modules/projectiles/guns/alien.dm b/code/modules/projectiles/guns/alien.dm index d9f149b3b17..aec047ad89b 100644 --- a/code/modules/projectiles/guns/alien.dm +++ b/code/modules/projectiles/guns/alien.dm @@ -49,6 +49,7 @@ name = "alloy spike" desc = "A broadhead spike made out of a weird silvery metal." projectile_type = /obj/item/projectile/bullet/spike + muzzle_flash_effect = null throwforce = 5 w_class = WEIGHT_CLASS_NORMAL caliber = "spike" diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index 19316cb9540..c715ba966dd 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -88,7 +88,7 @@ if(!holds_charge) empty() -/obj/item/gun/energy/kinetic_accelerator/shoot_live_shot() +/obj/item/gun/energy/kinetic_accelerator/shoot_live_shot(mob/living/user, atom/target, pointblank = FALSE, message = TRUE) . = ..() attempt_reload() @@ -173,6 +173,7 @@ //Casing /obj/item/ammo_casing/energy/kinetic projectile_type = /obj/item/projectile/kinetic + muzzle_flash_color = null select_name = "kinetic" e_cost = 500 fire_sound = 'sound/weapons/kenetic_accel.ogg' // fine spelling there chap diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index da72c971130..44e393f9762 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -132,7 +132,7 @@ if(!suppressed) playsound(loc, 'sound/weapons/kenetic_reload.ogg', 60, 1) user.visible_message("[user] cocks the [name] and pretends to blow [user.p_their()] brains out! It looks like [user.p_theyre()] trying to commit suicide!") - shoot_live_shot() + shoot_live_shot(user, user, FALSE, FALSE) return OXYLOSS // Plasma Cutters // diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm index 72d128178a6..e028d970894 100644 --- a/code/modules/projectiles/guns/magic/staff.dm +++ b/code/modules/projectiles/guns/magic/staff.dm @@ -71,7 +71,7 @@ icon = 'icons/obj/wizard.dmi' icon_state = "focus" item_state = "focus" - ammo_type = list(/obj/item/ammo_casing/forcebolt) + ammo_type = /obj/item/ammo_casing/magic/forcebolt /obj/item/gun/magic/staff/spellblade name = "spellblade" diff --git a/code/modules/projectiles/guns/projectile/bow.dm b/code/modules/projectiles/guns/projectile/bow.dm index 70229a7c6b0..d87b9a08d98 100644 --- a/code/modules/projectiles/guns/projectile/bow.dm +++ b/code/modules/projectiles/guns/projectile/bow.dm @@ -78,6 +78,7 @@ icon_state = "arrow" force = 10 projectile_type = /obj/item/projectile/bullet/reusable/arrow + muzzle_flash_effect = null caliber = "arrow" //quiver diff --git a/code/modules/projectiles/guns/projectile/saw.dm b/code/modules/projectiles/guns/projectile/saw.dm index bb800214020..9c55f3b23fd 100644 --- a/code/modules/projectiles/guns/projectile/saw.dm +++ b/code/modules/projectiles/guns/projectile/saw.dm @@ -142,6 +142,8 @@ icon_state = "762-casing" caliber = "mm55645" projectile_type = /obj/item/projectile/bullet/saw + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_STRONG + muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG /obj/item/ammo_casing/mm556x45/bleeding desc = "A 556x45mm bullet casing with specialized inner-casing, that when it makes contact with a target, release tiny shrapnel to induce internal bleeding." @@ -159,3 +161,4 @@ /obj/item/ammo_casing/mm556x45/incen desc = "A 556x45mm bullet casing designed with a chemical-filled capsule on the tip that when bursted, reacts with the atmosphere to produce a fireball, engulfing the target in flames. " projectile_type = /obj/item/projectile/bullet/saw/incen + muzzle_flash_color = LIGHT_COLOR_FIRE diff --git a/code/modules/projectiles/guns/projectile/shotgun.dm b/code/modules/projectiles/guns/projectile/shotgun.dm index 6c11fda5fd7..c1824b48f7e 100644 --- a/code/modules/projectiles/guns/projectile/shotgun.dm +++ b/code/modules/projectiles/guns/projectile/shotgun.dm @@ -260,7 +260,7 @@ ..() guns_left = 0 -/obj/item/gun/projectile/shotgun/boltaction/enchanted/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1) +/obj/item/gun/projectile/shotgun/boltaction/enchanted/shoot_live_shot(mob/living/user, atom/target, pointblank = FALSE, message = TRUE) ..() if(guns_left) var/obj/item/gun/projectile/shotgun/boltaction/enchanted/GUN = new @@ -278,7 +278,7 @@ /obj/item/gun/projectile/shotgun/automatic -/obj/item/gun/projectile/shotgun/automatic/shoot_live_shot(mob/living/user as mob|obj) +/obj/item/gun/projectile/shotgun/automatic/shoot_live_shot(mob/living/user, atom/target, pointblank = FALSE, message = TRUE) ..() pump(user) diff --git a/code/modules/projectiles/guns/projectile/sniper.dm b/code/modules/projectiles/guns/projectile/sniper.dm index 761c15a6141..316a22a4db1 100644 --- a/code/modules/projectiles/guns/projectile/sniper.dm +++ b/code/modules/projectiles/guns/projectile/sniper.dm @@ -78,6 +78,8 @@ desc = "A .50 bullet casing." caliber = ".50" projectile_type = /obj/item/projectile/bullet/sniper + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_STRONG + muzzle_flash_range = MUZZLE_FLASH_RANGE_STRONG icon_state = ".50" /obj/item/projectile/bullet/sniper @@ -192,6 +194,8 @@ desc = "A .50 caliber compact round casing." caliber = ".50" projectile_type = /obj/item/projectile/bullet/sniper/compact + muzzle_flash_strength = MUZZLE_FLASH_STRENGTH_NORMAL + muzzle_flash_range = MUZZLE_FLASH_RANGE_NORMAL icon_state = ".50" /obj/item/projectile/bullet/sniper/compact //Can't dismember, and can't break things; just deals massive damage. diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index 13f959be590..c320296e0bd 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -11,7 +11,7 @@ impact_effect_type = /obj/effect/temp_visual/impact_effect/red_laser is_reflectable = TRUE light_range = 2 - light_color = LIGHT_COLOR_RED + light_color = LIGHT_COLOR_DARKRED ricochets_max = 50 //Honk! ricochet_chance = 80 @@ -109,11 +109,12 @@ icon_state = "laser" suit_types = list(/obj/item/clothing/suit/bluetag) impact_effect_type = /obj/effect/temp_visual/impact_effect/red_laser - light_color = LIGHT_COLOR_RED + light_color = LIGHT_COLOR_DARKRED /obj/item/projectile/beam/lasertag/bluetag icon_state = "bluelaser" suit_types = list(/obj/item/clothing/suit/redtag) + light_color = LIGHT_COLOR_BLUE /obj/item/projectile/beam/sniper name = "sniper beam" @@ -161,7 +162,7 @@ /obj/item/projectile/beam/instakill/red icon_state = "red_laser" impact_effect_type = /obj/effect/temp_visual/impact_effect/red_laser - light_color = LIGHT_COLOR_RED + light_color = LIGHT_COLOR_DARKRED /obj/item/projectile/beam/instakill/on_hit(atom/target) . = ..() diff --git a/code/modules/reagents/reagent_containers/glass_containers.dm b/code/modules/reagents/reagent_containers/glass_containers.dm index 175ae757df4..48534c7ab73 100644 --- a/code/modules/reagents/reagent_containers/glass_containers.dm +++ b/code/modules/reagents/reagent_containers/glass_containers.dm @@ -179,6 +179,7 @@ to_chat(usr, "You detach [assembly] from [src]") usr.put_in_hands(assembly) assembly = null + qdel(GetComponent(/datum/component/proximity_monitor)) update_icon() else to_chat(usr, "There is no assembly to remove.") @@ -194,7 +195,9 @@ return ..() assembly = W user.drop_item() - W.loc = src + W.forceMove(src) + if(assembly.has_prox_sensors()) + AddComponent(/datum/component/proximity_monitor) overlays += "assembly" else ..() diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index e8862e25584..5e20dbf6f35 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -57,8 +57,8 @@ var/attack_log_type = ATKLOG_MOST if(reagents.has_reagent("sacid") || reagents.has_reagent("facid") || reagents.has_reagent("lube")) attack_log_type = ATKLOG_FEW - 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") + + add_attack_logs(user, A, "Used a potentially harmful spray bottle. Contents: [contents_log] - Temperature: [reagents.chem_temp]K", attack_log_type) return diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index ff01fc34506..79ba8deccbd 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -126,6 +126,7 @@ usr.visible_message("[usr] detaches [rig] from [src].", "You detach [rig] from [src].") rig.forceMove(get_turf(usr)) rig = null + qdel(GetComponent(/datum/component/proximity_monitor)) lastrigger = null overlays.Cut() @@ -148,7 +149,8 @@ rig = H user.drop_item() H.forceMove(src) - + if(rig.has_prox_sensors()) + AddComponent(/datum/component/proximity_monitor) var/icon/test = getFlatIcon(H) test.Shift(NORTH, 1) test.Shift(EAST, 6) diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm index e82db0ddc60..6bd3a47a87f 100644 --- a/code/modules/recycling/conveyor2.dm +++ b/code/modules/recycling/conveyor2.dm @@ -13,7 +13,9 @@ GLOBAL_LIST_INIT(conveyor_switches, list()) icon = 'icons/obj/recycling.dmi' icon_state = "conveyor_stopped_cw" name = "conveyor belt" - desc = "It's a conveyor belt, commonly used to transport large numbers of items elsewhere quite quickly." + desc = "It's a conveyor belt, commonly used to transport large numbers of items elsewhere quite quickly.
    \ + Use a wrench on the belt to rotate it.
    \ + Use a crowbar on the belt to dislodge it." layer = CONVEYOR_LAYER // so they appear under stuff but not below stuff like vents anchored = TRUE move_force = MOVE_FORCE_DEFAULT @@ -231,7 +233,10 @@ GLOBAL_LIST_INIT(conveyor_switches, list()) /obj/machinery/conveyor_switch name = "conveyor switch" - desc = "This switch controls any and all conveyor belts it is linked to." + desc = "This switch controls any and all conveyor belts it is linked to.
    \ + Use a multitool to toggle one-way mode.
    \ + Use a crowbar to dislodge it.
    \ + Dislodge the switch and use it on a section of conveyor belt or conveyor placer to link them.
    " icon = 'icons/obj/recycling.dmi' icon_state = "switch-off" var/position = DIRECTION_OFF @@ -338,7 +343,9 @@ GLOBAL_LIST_INIT(conveyor_switches, list()) icon = 'icons/obj/recycling.dmi' icon_state = "conveyor_loose" name = "conveyor belt assembly" - desc = "A conveyor belt assembly, used for the assembly of conveyor belt systems." + desc = "A conveyor belt assembly, used for the assembly of conveyor belt systems.
    \ + Use the assembly on the ground to finalize it.
    \ + Use a conveyor belt switch on the assembly to link them.
    " w_class = WEIGHT_CLASS_BULKY var/id @@ -369,7 +376,9 @@ GLOBAL_LIST_INIT(conveyor_switches, list()) /obj/item/conveyor_switch_construct name = "conveyor switch assembly" - desc = "A conveyor control switch assembly. When set up, it'll control any and all conveyor belts it is linked to." + desc = "A conveyor control switch assembly. When set up, it'll control any and all conveyor belts it is linked to.
    \ + Use it on a section of conveyor belt to link them together.
    \ + Use the assembly on the ground to finalize it." icon = 'icons/obj/recycling.dmi' icon_state = "switch" w_class = WEIGHT_CLASS_BULKY diff --git a/code/modules/research/circuitprinter.dm b/code/modules/research/circuitprinter.dm index eda48794d86..309cdb7eef1 100644 --- a/code/modules/research/circuitprinter.dm +++ b/code/modules/research/circuitprinter.dm @@ -15,7 +15,6 @@ using metal and glass, it uses glass and reagents (usually sulfuric acis). var/list/categories = list( "AI Modules", "Computer Boards", - "Computer Parts", "Engineering Machinery", "Exosuit Modules", "Hydroponics Machinery", diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm index e813597c4d8..a014a6be34b 100644 --- a/code/modules/research/designs/autolathe_designs.dm +++ b/code/modules/research/designs/autolathe_designs.dm @@ -872,22 +872,6 @@ build_path = /obj/item/storage/conveyor category = list("initial", "Construction") -/datum/design/laptop - name = "Laptop Frame" - id = "laptop" - build_type = AUTOLATHE - materials = list(MAT_METAL = 10000, MAT_GLASS = 1000) - build_path = /obj/item/modular_computer/laptop/buildable - category = list("initial", "Miscellaneous") - -/datum/design/tablet - name = "Tablet Frame" - id = "tablet" - build_type = AUTOLATHE - materials = list(MAT_METAL = 2000, MAT_GLASS = 1000) - build_path = /obj/item/modular_computer/tablet - category = list("initial", "Miscellaneous") - /datum/design/mousetrap name = "Mousetrap" id = "mousetrap" diff --git a/code/modules/research/designs/computer_part_designs.dm b/code/modules/research/designs/computer_part_designs.dm deleted file mode 100644 index 438a679f97a..00000000000 --- a/code/modules/research/designs/computer_part_designs.dm +++ /dev/null @@ -1,251 +0,0 @@ -//////////////////////////////////////// -///////////Computer Parts/////////////// -//////////////////////////////////////// - -/datum/design/disk/normal - name = "hard disk drive" - id = "hdd_basic" - req_tech = list("programming" = 1, "engineering" = 1) - build_type = PROTOLATHE - materials = list(MAT_METAL = 400, MAT_GLASS = 100) - build_path = /obj/item/computer_hardware/hard_drive - category = list("Computer Parts") - -/datum/design/disk/advanced - name = "advanced hard disk drive" - id = "hdd_advanced" - req_tech = list("programming" = 2, "engineering" = 2) - build_type = PROTOLATHE - materials = list(MAT_METAL = 800, MAT_GLASS = 200) - build_path = /obj/item/computer_hardware/hard_drive/advanced - category = list("Computer Parts") - -/datum/design/disk/super - name = "super hard disk drive" - id = "hdd_super" - req_tech = list("programming" = 3, "engineering" = 3) - build_type = PROTOLATHE - materials = list(MAT_METAL = 1600, MAT_GLASS = 400) - build_path = /obj/item/computer_hardware/hard_drive/super - category = list("Computer Parts") - -/datum/design/disk/cluster - name = "cluster hard disk drive" - id = "hdd_cluster" - req_tech = list("programming" = 4, "engineering" = 4) - build_type = PROTOLATHE - materials = list(MAT_METAL = 3200, MAT_GLASS = 800) - build_path = /obj/item/computer_hardware/hard_drive/cluster - category = list("Computer Parts") - -/datum/design/disk/small - name = "solid state drive" - id = "ssd_small" - req_tech = list("programming" = 2, "engineering" = 2) - build_type = PROTOLATHE - materials = list(MAT_METAL = 800, MAT_GLASS = 200) - build_path = /obj/item/computer_hardware/hard_drive/small - category = list("Computer Parts") - -/datum/design/disk/micro - name = "micro solid state drive" - id = "ssd_micro" - req_tech = list("programming" = 1, "engineering" = 1) - build_type = PROTOLATHE - materials = list(MAT_METAL = 400, MAT_GLASS = 100) - build_path = /obj/item/computer_hardware/hard_drive/micro - category = list("Computer Parts") - - -// Network cards -/datum/design/netcard/basic - name = "network card" - id = "netcard_basic" - req_tech = list("programming" = 2, "engineering" = 1) - build_type = IMPRINTER - materials = list(MAT_METAL = 250, MAT_GLASS = 100) - build_path = /obj/item/computer_hardware/network_card - category = list("Computer Parts") - -/datum/design/netcard/advanced - name = "advanced network card" - id = "netcard_advanced" - req_tech = list("programming" = 4, "engineering" = 2) - build_type = IMPRINTER - materials = list(MAT_METAL = 500, MAT_GLASS = 200) - build_path = /obj/item/computer_hardware/network_card/advanced - category = list("Computer Parts") - -/datum/design/netcard/wired - name = "wired network card" - id = "netcard_wired" - req_tech = list("programming" = 5, "engineering" = 3) - build_type = IMPRINTER - materials = list(MAT_METAL = 2500, MAT_GLASS = 400) - build_path = /obj/item/computer_hardware/network_card/wired - category = list("Computer Parts") - - -// Data disks -/datum/design/portabledrive/basic - name = "data disk" - id = "portadrive_basic" - req_tech = list("programming" = 1) - build_type = IMPRINTER - materials = list(MAT_GLASS = 800) - build_path = /obj/item/computer_hardware/hard_drive/portable - category = list("Computer Parts") - -/datum/design/portabledrive/advanced - name = "advanced data disk" - id = "portadrive_advanced" - req_tech = list("programming" = 2) - build_type = IMPRINTER - materials = list(MAT_GLASS = 1600) - build_path = /obj/item/computer_hardware/hard_drive/portable/advanced - category = list("Computer Parts") - -/datum/design/portabledrive/super - name = "super data disk" - id = "portadrive_super" - req_tech = list("programming" = 4) - build_type = IMPRINTER - materials = list(MAT_GLASS = 3200) - build_path = /obj/item/computer_hardware/hard_drive/portable/super - category = list("Computer Parts") - - -// Card slot -/datum/design/cardslot - name = "ID card slot" - id = "cardslot" - req_tech = list("programming" = 2) - build_type = PROTOLATHE - materials = list(MAT_METAL = 600) - build_path = /obj/item/computer_hardware/card_slot - category = list("Computer Parts") - -// Intellicard slot -/datum/design/aislot - name = "Intellicard slot" - id = "aislot" - req_tech = list("programming" = 2) - build_type = PROTOLATHE - materials = list(MAT_METAL = 600) - build_path = /obj/item/computer_hardware/ai_slot - category = list("Computer Parts") - -// Mini printer -/datum/design/miniprinter - name = "miniprinter" - id = "miniprinter" - req_tech = list("programming" = 2, "engineering" = 2) - build_type = PROTOLATHE - materials = list(MAT_METAL = 600) - build_path = /obj/item/computer_hardware/printer/mini - category = list("Computer Parts") - - -// APC Link -/datum/design/APClink - name = "area power connector" - id = "APClink" - req_tech = list("programming" = 2, "powerstorage" = 3, "engineering" = 2) - build_type = PROTOLATHE - materials = list(MAT_METAL = 2000) - build_path = /obj/item/computer_hardware/recharger/APC - category = list("Computer Parts") - - -// Batteries -/datum/design/battery/controller - name = "power cell controller" - id = "bat_control" - req_tech = list("powerstorage" = 1, "engineering" = 1) - build_type = PROTOLATHE - materials = list(MAT_METAL = 400) - build_path = /obj/item/computer_hardware/battery - category = list("Computer Parts") - -/datum/design/battery/normal - name = "battery module" - id = "bat_normal" - req_tech = list("powerstorage" = 1, "engineering" = 1) - build_type = PROTOLATHE - materials = list(MAT_METAL = 400) - build_path = /obj/item/stock_parts/cell/computer - category = list("Computer Parts") - -/datum/design/battery/advanced - name = "advanced battery module" - id = "bat_advanced" - req_tech = list("powerstorage" = 2, "engineering" = 2) - build_type = PROTOLATHE - materials = list(MAT_METAL = 800) - build_path = /obj/item/stock_parts/cell/computer/advanced - category = list("Computer Parts") - -/datum/design/battery/super - name = "super battery module" - id = "bat_super" - req_tech = list("powerstorage" = 3, "engineering" = 3) - build_type = PROTOLATHE - materials = list(MAT_METAL = 1600) - build_path = /obj/item/stock_parts/cell/computer/super - category = list("Computer Parts") - -/datum/design/battery/nano - name = "nano battery module" - id = "bat_nano" - req_tech = list("powerstorage" = 1, "engineering" = 1) - build_type = PROTOLATHE - materials = list(MAT_METAL = 200) - build_path = /obj/item/stock_parts/cell/computer/nano - category = list("Computer Parts") - -/datum/design/battery/micro - name = "micro battery module" - id = "bat_micro" - req_tech = list("powerstorage" = 2, "engineering" = 2) - build_type = PROTOLATHE - materials = list(MAT_METAL = 400) - build_path = /obj/item/stock_parts/cell/computer/micro - category = list("Computer Parts") - - -// Processor unit -/datum/design/cpu - name = "processor board" - id = "cpu_normal" - req_tech = list("programming" = 3, "engineering" = 2) - build_type = IMPRINTER - materials = list(MAT_GLASS = 1600) - build_path = /obj/item/computer_hardware/processor_unit - category = list("Computer Parts") - -/datum/design/cpu/small - name = "microprocessor" - id = "cpu_small" - req_tech = list("programming" = 2, "engineering" = 2) - build_type = IMPRINTER - materials = list(MAT_GLASS = 800) - build_path = /obj/item/computer_hardware/processor_unit/small - category = list("Computer Parts") - -/datum/design/cpu/photonic - name = "photonic processor board" - id = "pcpu_normal" - req_tech = list("programming" = 5, "engineering" = 4) - build_type = IMPRINTER - materials = list(MAT_GLASS= 6400, MAT_GOLD = 2000) - build_path = /obj/item/computer_hardware/processor_unit/photonic - category = list("Computer Parts") - -/datum/design/cpu/photonic/small - name = "photonic microprocessor" - id = "pcpu_small" - req_tech = list("programming" = 4, "engineering" = 3) - build_type = IMPRINTER - materials = list(MAT_GLASS = 3200, MAT_GOLD = 1000) - build_path = /obj/item/computer_hardware/processor_unit/photonic/small - category = list("Computer Parts") diff --git a/code/modules/research/designs/equipment_designs.dm b/code/modules/research/designs/equipment_designs.dm index eb0901b71e2..af6fc828ad3 100644 --- a/code/modules/research/designs/equipment_designs.dm +++ b/code/modules/research/designs/equipment_designs.dm @@ -71,6 +71,16 @@ build_path = /obj/item/clothing/glasses/hud/security/night category = list("Equipment") +/datum/design/skills_hud + name = "Skills HUD" + desc = "A heads-up display that scans the humans in view and shows a summary of their NT employment history." + id = "skills_hud" + req_tech = list("magnets" = 3, "combat" = 2) + build_type = PROTOLATHE + materials = list(MAT_METAL = 500, MAT_GLASS = 500) + build_path = /obj/item/clothing/glasses/hud/skills + category = list("Equipment") + /datum/design/mesons name = "Optical Meson Scanners" desc = "Used for seeing walls, floors, and stuff through anything." diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index 3900acf5093..5cd4c9bdc81 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -531,13 +531,3 @@ materials = list(MAT_GLASS=1000) build_path = /obj/item/circuitboard/plantgenes category = list("Hydroponics Machinery") - -/datum/design/ntnet_relay - name = "Machine Design (NTNet Relay Board)" - desc = "The circuit board for a wireless network relay." - id = "ntnet_relay" - req_tech = list("programming" = 2, "engineering" = 2, "bluespace" = 2) - build_type = IMPRINTER - materials = list(MAT_GLASS=1000) - build_path = /obj/item/circuitboard/machine/ntnet_relay - category = list("Subspace Telecomms") diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm index 6f2e608ef4b..8e85c041708 100644 --- a/code/modules/research/protolathe.dm +++ b/code/modules/research/protolathe.dm @@ -17,7 +17,6 @@ Note: Must be placed west/left of and R&D console to function. var/list/categories = list( "Bluespace", - "Computer Parts", "Equipment", "Janitorial", "Medical", diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm index b1eeb07a6de..5d8e9a6f914 100644 --- a/code/modules/shuttle/supply.dm +++ b/code/modules/shuttle/supply.dm @@ -1,8 +1,3 @@ -#define ORDER_SCREEN_WIDTH 625 //width of order computer interaction window -#define ORDER_SCREEN_HEIGHT 580 //height of order computer interaction window -#define SUPPLY_SCREEN_WIDTH 625 //width of supply computer interaction window -#define SUPPLY_SCREEN_HEIGHT 620 //height of supply computer interaction window - /obj/item/paper/manifest name = "supply manifest" var/erroneous = 0 @@ -98,7 +93,7 @@ var/intel_count = 0 var/crate_count = 0 - var/msg = "" + var/msg = "
    ---[station_time_timestamp()]---

    " var/pointsEarned for(var/atom/movable/MA in areaInstance) @@ -231,7 +226,7 @@ msg += "+[pointsEarned]: Received [crate_count] crate(s).
    " SSshuttle.points += pointsEarned - SSshuttle.centcom_message = msg + SSshuttle.centcom_message += "[msg]
    " /proc/forbidden_atoms_check(atom/A) var/list/blacklist = list( @@ -387,156 +382,23 @@ icon_screen = "supply" req_access = list(ACCESS_CARGO) circuit = /obj/item/circuitboard/supplycomp - var/temp = null + /// Is this a public console (Confirm + Shuttle controls are not visible) + var/is_public = FALSE + /// Time of last request var/reqtime = 0 - var/hacked = 0 - var/can_order_contraband = 0 - var/last_viewed_group = "categories" - var/datum/supply_packs/content_pack + /// Can we order special supplies + var/hacked = FALSE + /// Can we order contraband + var/can_order_contraband = FALSE -/obj/machinery/computer/ordercomp +/obj/machinery/computer/supplycomp/public name = "Supply Ordering Console" desc = "Used to order supplies from cargo staff." icon = 'icons/obj/computer.dmi' icon_screen = "request" circuit = /obj/item/circuitboard/ordercomp - var/reqtime = 0 - var/last_viewed_group = "categories" - var/datum/supply_packs/content_pack - -/obj/machinery/computer/ordercomp/attack_ai(var/mob/user as mob) - return attack_hand(user) - -/obj/machinery/computer/ordercomp/attack_hand(var/mob/user as mob) - ui_interact(user) - -/obj/machinery/computer/ordercomp/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui) - if(!ui) - ui = new(user, src, ui_key, "order_console.tmpl", name, ORDER_SCREEN_WIDTH, ORDER_SCREEN_HEIGHT) - ui.open() - -/obj/machinery/computer/ordercomp/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - data["last_viewed_group"] = last_viewed_group - - var/category_list[0] - for(var/category in GLOB.all_supply_groups) - category_list.Add(list(list("name" = get_supply_group_name(category), "category" = category))) - data["categories"] = category_list - var/cat = text2num(last_viewed_group) - var/packs_list[0] - for(var/set_name in SSshuttle.supply_packs) - var/datum/supply_packs/pack = SSshuttle.supply_packs[set_name] - if((!pack.contraband && !pack.hidden && !pack.special && pack.group == cat) || (!pack.contraband && !pack.hidden && (pack.special && pack.special_enabled) && pack.group == cat)) - // 0/1 after the pack name (set_name) is a boolean for ordering multiple crates - packs_list.Add(list(list("name" = pack.name, "amount" = pack.amount, "cost" = pack.cost, "command1" = list("doorder" = "[set_name]0"), "command2" = list("doorder" = "[set_name]1"), "command3" = list("contents" = set_name)))) - - data["supply_packs"] = packs_list - if(content_pack) - var/pack_name = sanitize(content_pack.name) - data["contents_name"] = pack_name - data["contents"] = content_pack.manifest - data["contents_access"] = content_pack.access ? get_access_desc(content_pack.access) : "None" - - var/requests_list[0] - for(var/set_name in SSshuttle.requestlist) - var/datum/supply_order/SO = set_name - if(SO) - // Check if the user owns the request, so they can cancel requests - var/obj/item/card/id/I = user.get_id_card() - var/owned = 0 - if(I && SO.orderedby == I.registered_name) - owned = 1 - requests_list.Add(list(list("ordernum" = SO.ordernum, "supply_type" = SO.object.name, "orderedby" = SO.orderedby, "owned" = owned, "command1" = list("rreq" = SO.ordernum)))) - data["requests"] = requests_list - var/orders_list[0] - for(var/set_name in SSshuttle.shoppinglist) - var/datum/supply_order/SO = set_name - if(SO) - orders_list.Add(list(list("ordernum" = SO.ordernum, "supply_type" = SO.object.name, "orderedby" = SO.orderedby))) - data["orders"] = orders_list - - data["points"] = round(SSshuttle.points) - data["send"] = list("send" = 1) - - data["moving"] = SSshuttle.supply.mode != SHUTTLE_IDLE - data["at_station"] = SSshuttle.supply.getDockedId() == "supply_home" - data["timeleft"] = SSshuttle.supply.timeLeft(600) - return data - -/obj/machinery/computer/ordercomp/Topic(href, href_list) - if(..()) - return 1 - - if(href_list["doorder"]) - if(world.time < reqtime) - visible_message("[src]'s monitor flashes, \"[world.time - reqtime] seconds remaining until another requisition form may be printed.\"") - SSnanoui.update_uis(src) - return 1 - - var/index = copytext(href_list["doorder"], 1, length(href_list["doorder"])) //text2num(copytext(href_list["doorder"], 1)) - var/multi = text2num(copytext(href_list["doorder"], -1)) - if(!isnum(multi)) - return 1 - var/datum/supply_packs/P = SSshuttle.supply_packs[index] - if(!istype(P)) - return 1 - var/crates = 1 - if(multi) - var/num_input = input(usr, "Amount:", "How many crates?") as null|num - if(!num_input || ..()) - return 1 - crates = clamp(round(num_input), 1, 20) - - var/timeout = world.time + 600 - var/reason = input(usr,"Reason:","Why do you require this item?","") as null|text - if(world.time > timeout || !reason || ..()) - return 1 - reason = sanitize(copytext(reason, 1, MAX_MESSAGE_LEN)) - - var/idname = "*None Provided*" - var/idrank = "*None Provided*" - if(ishuman(usr)) - var/mob/living/carbon/human/H = usr - idname = H.get_authentification_name() - idrank = H.get_assignment() - else if(issilicon(usr)) - idname = usr.real_name - - reqtime = (world.time + 5) % 1e5 - - //make our supply_order datums - for(var/i = 1; i <= crates; i++) - var/datum/supply_order/O = SSshuttle.generateSupplyOrder(index, idname, idrank, reason, crates) - if(!O) return - if(i == 1) - O.generateRequisition(loc) - - else if(href_list["rreq"]) - var/ordernum = text2num(href_list["rreq"]) - var/obj/item/card/id/I = usr.get_id_card() - for(var/i=1, i<=SSshuttle.requestlist.len, i++) - var/datum/supply_order/SO = SSshuttle.requestlist[i] - if(SO.ordernum == ordernum && (I && SO.orderedby == I.registered_name)) - SSshuttle.requestlist.Cut(i,i+1) - break - - else if(href_list["last_viewed_group"]) - content_pack = null - last_viewed_group = text2num(href_list["last_viewed_group"]) - - else if(href_list["contents"]) - var/topic = href_list["contents"] - if(topic == 1) - content_pack = null - else - var/datum/supply_packs/P = SSshuttle.supply_packs[topic] - content_pack = P - - add_fingerprint(usr) - SSnanoui.update_uis(src) - return 1 + req_access = list() + is_public = TRUE /obj/machinery/computer/supplycomp/attack_ai(var/mob/user as mob) return attack_hand(user) @@ -547,47 +409,25 @@ return 1 post_signal("supply") - ui_interact(user) + tgui_interact(user) return /obj/machinery/computer/supplycomp/emag_act(user as mob) if(!hacked) to_chat(user, "Special supplies unlocked.") - hacked = 1 + hacked = TRUE return -/obj/machinery/computer/supplycomp/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null) - ui = SSnanoui.try_update_ui(user, src, ui_key, ui) +/obj/machinery/computer/supplycomp/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, "supply_console.tmpl", name, SUPPLY_SCREEN_WIDTH, SUPPLY_SCREEN_HEIGHT) + ui = new(user, src, ui_key, "CargoConsole", name, 900, 800, master_ui, state) ui.open() -/obj/machinery/computer/supplycomp/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state) - var/data[0] - data["last_viewed_group"] = last_viewed_group +/obj/machinery/computer/supplycomp/tgui_data(mob/user) + var/list/data = list() - var/category_list[0] - for(var/category in GLOB.all_supply_groups) - category_list.Add(list(list("name" = get_supply_group_name(category), "category" = category))) - data["categories"] = category_list - - var/cat = text2num(last_viewed_group) - var/packs_list[0] - for(var/set_name in SSshuttle.supply_packs) - var/datum/supply_packs/pack = SSshuttle.supply_packs[set_name] - if((pack.hidden && hacked) || (pack.contraband && can_order_contraband) || (pack.special && pack.special_enabled) || (!pack.contraband && !pack.hidden && !pack.special)) - if(pack.group == cat) - // 0/1 after the pack name (set_name) is a boolean for ordering multiple crates - packs_list.Add(list(list("name" = pack.name, "amount" = pack.amount, "cost" = pack.cost, "command1" = list("doorder" = "[set_name]0"), "command2" = list("doorder" = "[set_name]1"), "command3" = list("contents" = set_name)))) - - data["supply_packs"] = packs_list - if(content_pack) - var/pack_name = sanitize(content_pack.name) - data["contents_name"] = pack_name - data["contents"] = content_pack.manifest - data["contents_access"] = content_pack.access ? get_access_desc(content_pack.access) : "None" - - var/requests_list[0] + var/list/requests_list = list() for(var/set_name in SSshuttle.requestlist) var/datum/supply_order/SO = set_name if(SO) @@ -596,146 +436,177 @@ requests_list.Add(list(list("ordernum" = SO.ordernum, "supply_type" = SO.object.name, "orderedby" = SO.orderedby, "comment" = SO.comment, "command1" = list("confirmorder" = SO.ordernum), "command2" = list("rreq" = SO.ordernum)))) data["requests"] = requests_list - var/orders_list[0] + var/list/orders_list = list() for(var/set_name in SSshuttle.shoppinglist) var/datum/supply_order/SO = set_name if(SO) orders_list.Add(list(list("ordernum" = SO.ordernum, "supply_type" = SO.object.name, "orderedby" = SO.orderedby, "comment" = SO.comment))) data["orders"] = orders_list - data["canapprove"] = (SSshuttle.supply.getDockedId() == "supply_away") && !(SSshuttle.supply.mode != SHUTTLE_IDLE) + data["is_public"] = is_public + + data["canapprove"] = (SSshuttle.supply.getDockedId() == "supply_away") && !(SSshuttle.supply.mode != SHUTTLE_IDLE) && !is_public data["points"] = round(SSshuttle.points) - data["send"] = list("send" = 1) - data["message"] = SSshuttle.centcom_message ? SSshuttle.centcom_message : "Remember to stamp and send back the supply manifests." data["moving"] = SSshuttle.supply.mode != SHUTTLE_IDLE data["at_station"] = SSshuttle.supply.getDockedId() == "supply_home" data["timeleft"] = SSshuttle.supply.timeLeft(600) data["can_launch"] = !SSshuttle.supply.canMove() + + return data + +/obj/machinery/computer/supplycomp/tgui_static_data(mob/user) + var/list/data = list() + var/list/packs_list = list() + + for(var/set_name in SSshuttle.supply_packs) + var/datum/supply_packs/pack = SSshuttle.supply_packs[set_name] + if((pack.hidden && hacked) || (pack.contraband && can_order_contraband) || (pack.special && pack.special_enabled) || (!pack.contraband && !pack.hidden && !pack.special)) + packs_list.Add(list(list("name" = pack.name, "cost" = pack.cost, "ref" = "[pack.UID()]", "contents" = pack.tgui_manifest, "cat" = pack.group))) + + data["supply_packs"] = packs_list + + var/list/categories = list() // meow + for(var/category in GLOB.all_supply_groups) + categories.Add(list(list("name" = get_supply_group_name(category), "category" = category))) + data["categories"] = categories + return data /obj/machinery/computer/supplycomp/proc/is_authorized(mob/user) if(allowed(user)) - return 1 + return TRUE if(user.can_admin_interact()) - return 1 + return TRUE - return 0 + return FALSE -/obj/machinery/computer/supplycomp/Topic(href, href_list) +/obj/machinery/computer/supplycomp/tgui_act(action, list/params) if(..()) - return 1 + return - if(!is_authorized(usr)) - return 1 + // If its not a public console, and they aint authed, dont let them use this + if(!is_public && !is_authorized(usr)) + return if(!SSshuttle) - log_runtime(EXCEPTION("The SSshuttle controller datum is missing somehow."), src) - return 1 - - if(href_list["send"]) - if(SSshuttle.supply.canMove()) - to_chat(usr, "For safety reasons the automated supply shuttle cannot transport live organisms, classified nuclear weaponry or homing beacons.") - else if(SSshuttle.supply.getDockedId() == "supply_home") - SSshuttle.toggleShuttle("supply", "supply_home", "supply_away", 1) - investigate_log("[key_name(usr)] has sent the supply shuttle away. Remaining points: [SSshuttle.points]. Shuttle contents: [SSshuttle.sold_atoms]", "cargo") - else if(!SSshuttle.supply.request(SSshuttle.getDock("supply_home"))) - post_signal("supply") - if(LAZYLEN(SSshuttle.shoppinglist) && prob(10)) - var/datum/supply_order/O = new /datum/supply_order() - O.ordernum = SSshuttle.ordernum - O.object = SSshuttle.supply_packs[pick(SSshuttle.supply_packs)] - O.orderedby = random_name(pick(MALE,FEMALE), species = "Human") - SSshuttle.shoppinglist += O - investigate_log("Random [O.object] crate added to supply shuttle") - - else if(href_list["doorder"]) - if(world.time < reqtime) - visible_message("[src]'s monitor flashes, \"[world.time - reqtime] seconds remaining until another requisition form may be printed.\"") - SSnanoui.update_uis(src) - return 1 - - var/index = copytext(href_list["doorder"], 1, length(href_list["doorder"])) //text2num(copytext(href_list["doorder"], 1)) - var/multi = text2num(copytext(href_list["doorder"], -1)) - if(!isnum(multi)) - return 1 - var/datum/supply_packs/P = SSshuttle.supply_packs[index] - if(!istype(P)) - return 1 - var/crates = 1 - if(multi) - var/num_input = input(usr, "Amount:", "How many crates?") as null|num - if(!num_input || !is_authorized(usr) || ..()) - return 1 - crates = clamp(round(num_input), 1, 20) - - var/timeout = world.time + 600 - var/reason = input(usr,"Reason:","Why do you require this item?","") as null|text - if(world.time > timeout || !reason || !is_authorized(usr) || ..()) - return 1 - reason = sanitize(copytext(reason, 1, MAX_MESSAGE_LEN)) - - var/idname = "*None Provided*" - var/idrank = "*None Provided*" - - if(ishuman(usr)) - var/mob/living/carbon/human/H = usr - idname = H.get_authentification_name() - idrank = H.get_assignment() - else if(issilicon(usr)) - idname = usr.real_name - - //make our supply_order datums - for(var/i = 1; i <= crates; i++) - var/datum/supply_order/O = SSshuttle.generateSupplyOrder(index, idname, idrank, reason, crates) - if(!O) return 1 - if(i == 1) - O.generateRequisition(loc) - - else if(href_list["confirmorder"]) - if(SSshuttle.supply.getDockedId() != "supply_away" || SSshuttle.supply.mode != SHUTTLE_IDLE) - return 1 - var/ordernum = text2num(href_list["confirmorder"]) - var/datum/supply_order/O - var/datum/supply_packs/P - for(var/i=1, i<=SSshuttle.requestlist.len, i++) - var/datum/supply_order/SO = SSshuttle.requestlist[i] - if(SO.ordernum == ordernum) - O = SO - P = O.object - if(SSshuttle.points >= P.cost) - SSshuttle.requestlist.Cut(i,i+1) - SSshuttle.points -= P.cost - SSshuttle.shoppinglist += O - investigate_log("[key_name(usr)] has authorized an order for [P.name]. Remaining points: [SSshuttle.points].", "cargo") - else - to_chat(usr, "There are insufficient supply points for this request.") - break - - else if(href_list["rreq"]) - var/ordernum = text2num(href_list["rreq"]) - for(var/i=1, i<=SSshuttle.requestlist.len, i++) - var/datum/supply_order/SO = SSshuttle.requestlist[i] - if(SO.ordernum == ordernum) - SSshuttle.requestlist.Cut(i,i+1) - break - - else if(href_list["last_viewed_group"]) - content_pack = null - last_viewed_group = text2num(href_list["last_viewed_group"]) - - else if(href_list["contents"]) - var/topic = href_list["contents"] - if(topic == 1) - content_pack = null - else - var/datum/supply_packs/P = SSshuttle.supply_packs[topic] - content_pack = P + stack_trace("The SSshuttle controller datum is missing somehow.") + return + . = TRUE add_fingerprint(usr) - SSnanoui.update_uis(src) - return 1 + + switch(action) + if("moveShuttle") + // Public consoles cant move the shuttle. Dont allow exploiters. + if(is_public) + return + if(SSshuttle.supply.canMove()) + to_chat(usr, "For safety reasons the automated supply shuttle cannot transport live organisms, classified nuclear weaponry or homing beacons.") + else if(SSshuttle.supply.getDockedId() == "supply_home") + SSshuttle.toggleShuttle("supply", "supply_home", "supply_away", 1) + investigate_log("[key_name(usr)] has sent the supply shuttle away. Remaining points: [SSshuttle.points]. Shuttle contents: [SSshuttle.sold_atoms]", "cargo") + else if(!SSshuttle.supply.request(SSshuttle.getDock("supply_home"))) + post_signal("supply") + if(LAZYLEN(SSshuttle.shoppinglist) && prob(10)) + var/datum/supply_order/O = new /datum/supply_order() + O.ordernum = SSshuttle.ordernum + O.object = SSshuttle.supply_packs[pick(SSshuttle.supply_packs)] + O.orderedby = random_name(pick(MALE,FEMALE), species = "Human") + SSshuttle.shoppinglist += O + investigate_log("Random [O.object] crate added to supply shuttle") + + if("order") + if(world.time < reqtime) + visible_message("[src]'s monitor flashes, \"[world.time - reqtime] seconds remaining until another requisition form may be printed.\"") + return + + var/amount = 1 + if(params["multiple"] == "1") // 1 is a string here. DO NOT MAKE THIS A BOOLEAN YOU DORK + var/num_input = input(usr, "Amount", "How many crates? (20 Max)") as null|num + if(!num_input || (!is_public && !is_authorized(usr)) || ..()) // Make sure they dont walk away + return + amount = clamp(round(num_input), 1, 20) + + + var/datum/supply_packs/P = locateUID(params["crate"]) + if(!istype(P)) + return + + var/timeout = world.time + 600 // If you dont type the reason within a minute, theres bigger problems here + var/reason = input(usr, "Reason", "Why do you require this item?","") as null|text + if(world.time > timeout || !reason || (!is_public && !is_authorized(usr)) || ..()) + // Cancel if they take too long, they dont give a reason, they aint authed, or if they walked away + return + reason = sanitize(copytext(reason, 1, MAX_MESSAGE_LEN)) + + var/idname = "*None Provided*" + var/idrank = "*None Provided*" + + if(ishuman(usr)) + var/mob/living/carbon/human/H = usr + idname = H.get_authentification_name() + idrank = H.get_assignment() + else if(issilicon(usr)) + idname = usr.real_name + + //make our supply_order datums + for(var/i = 1; i <= amount; i++) + var/datum/supply_order/O = SSshuttle.generateSupplyOrder(params["crate"], idname, idrank, reason, amount) + if(!O) + return + if(i == 1) + O.generateRequisition(loc) + + if("approve") + // Public consoles cant approve stuff + if(is_public) + return + if(SSshuttle.supply.getDockedId() != "supply_away" || SSshuttle.supply.mode != SHUTTLE_IDLE) + return + + var/ordernum = text2num(params["ordernum"]) + var/datum/supply_order/O + var/datum/supply_packs/P + for(var/i=1, i<=SSshuttle.requestlist.len, i++) + var/datum/supply_order/SO = SSshuttle.requestlist[i] + if(SO.ordernum == ordernum) + O = SO + P = O.object + if(SSshuttle.points >= P.cost) + SSshuttle.requestlist.Cut(i,i+1) + SSshuttle.points -= P.cost + SSshuttle.shoppinglist += O + investigate_log("[key_name(usr)] has authorized an order for [P.name]. Remaining points: [SSshuttle.points].", "cargo") + else + to_chat(usr, "There are insufficient supply points for this request.") + break + + if("deny") + var/ordernum = text2num(params["ordernum"]) + for(var/i=1, i<=SSshuttle.requestlist.len, i++) + var/datum/supply_order/SO = SSshuttle.requestlist[i] + if(SO.ordernum == ordernum) + // If we are on a public console, only allow cancelling of our own orders + if(is_public) + var/obj/item/card/id/I = usr.get_id_card() + if(I && SO.orderedby == I.registered_name) + SSshuttle.requestlist.Cut(i,i+1) + break + // If we arent public, were cargo access. CANCELLATIONS FOR EVERYONE + else + SSshuttle.requestlist.Cut(i,i+1) + break + + // Popup to show CC message logs. Its easier this way to avoid box-spam in TGUI + if("showMessages") + // Public consoles cant view messages + if(is_public) + return + var/datum/browser/ccmsg_browser = new(usr, "ccmsg", "Central Command Cargo Message Log", 800, 600) + ccmsg_browser.set_content(SSshuttle.centcom_message) + ccmsg_browser.open() /obj/machinery/computer/supplycomp/proc/post_signal(var/command) var/datum/radio_frequency/frequency = SSradio.return_frequency(DISPLAY_FREQ) @@ -748,9 +619,3 @@ status_signal.data["command"] = command frequency.post_signal(src, status_signal) - - -#undef ORDER_SCREEN_WIDTH -#undef ORDER_SCREEN_HEIGHT -#undef SUPPLY_SCREEN_WIDTH -#undef SUPPLY_SCREEN_HEIGHT diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm index c9b26f61228..dd73cf0f02a 100644 --- a/code/modules/surgery/organs/vocal_cords.dm +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -157,7 +157,7 @@ GLOBAL_DATUM_INIT(multispin_words, /regex, regex("like a record baby")) if(L.can_hear() && !L.null_rod_check() && L != owner && L.stat != DEAD) if(ishuman(L)) var/mob/living/carbon/human/H = L - if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) || istype(H.r_ear, /obj/item/clothing/ears/earmuffs)) + if(H.check_ear_prot() >= HEARING_PROTECTION_TOTAL) continue listeners += L diff --git a/code/modules/tgui/plugins/login.dm b/code/modules/tgui/plugins/login.dm new file mode 100644 index 00000000000..af0e42b0364 --- /dev/null +++ b/code/modules/tgui/plugins/login.dm @@ -0,0 +1,204 @@ +/** + * tgui login + * + * Allows the handling of logins using IDs within tgui. + * + * Two key procs: + * * [/obj/proc/tgui_login_act] - Call in your tgui_act() proc to catch any login actions and handle them. + * * [/obj/proc/tgui_login_data] - Call in your tgui_data() proc to pass login info. + * + * How to use (DM side): + * 1. Call [/obj/proc/tgui_login_act] at the start of your tgui_act() proc + * 2. Call [/obj/proc/tgui_login_data] in your tgui_data() proc while passing the data list + * 3. In your object, call [/obj/proc/tgui_login_get] to get the current login state. + * 4. Optional: call [/obj/proc/tgui_login_attackby] in your attackby() to make the login process easier. + * + * How to use (JS side): Use the and interfaces. + */ + +GLOBAL_LIST(tgui_logins) + +/** + * Call this from a proc that is called in tgui_act() to process login actions + * + * Arguments: + * * action - The called action + * * params - The params to the action + */ +/obj/proc/tgui_login_act(action = "", params) + . = null + switch(action) + if("login_insert") + var/datum/tgui_login/state = tgui_login_get() + if(state.id) // An ID is already inserted, eject it + return tgui_login_eject(state = state) + else // No ID, attempt to insert one in + return tgui_login_insert(usr.get_active_hand(), state = state) + if("login_eject") + return tgui_login_eject() + if("login_login") + return tgui_login_login(text2num(params["login_type"])) + if("login_logout") + return tgui_login_logout() + +/** + * Appends login state data. + * + * Arguments: + * * data - The data list to be returned + * * user - The user calling tgui_data() + * * state - The current login state + */ +/obj/proc/tgui_login_data(list/data, mob/user, datum/tgui_login/state = tgui_login_get()) + data["loginState"] = list( + "id" = state.id ? state.id.name : null, + "name" = state.name, + "rank" = state.rank, + "logged_in" = state.logged_in, + ) + data["isAI"] = isAI(user) + data["isRobot"] = isrobot(user) + +/** + * Convenience function to perform login actions when + * the source object is hit by specific items. + * + * Arguments: + * * O - The object + * * user - The user + */ +/obj/proc/tgui_login_attackby(obj/item/O, mob/user) + if(istype(O, /obj/item/card/id) && tgui_login_insert(O)) + tgui_interact(user) + return TRUE + +/** + * Attempts to insert an object as an ID. + * + * Arguments: + * * O - The object to try inserting + * * state - The current login state + */ +/obj/proc/tgui_login_insert(obj/item/O, datum/tgui_login/state = tgui_login_get()) + if(state.id) + return + + if(istype(O, /obj/item/card/id)) + // Move the ID inside + usr.drop_item() + O.forceMove(src) + + // Update the state + state.id = O + + return TRUE + +/** + * Attempts to eject the inserted ID. + * + * Arguments: + * * state - The current login state + */ +/obj/proc/tgui_login_eject(datum/tgui_login/state = tgui_login_get()) + if(!state.id) + return + + // Drop the ID + state.id.forceMove(loc) + if(ishuman(usr) && !usr.get_active_hand()) + usr.put_in_hands(state.id) + + // Update the state + state.id = null + + return TRUE + +/** + * Attempts to log in with the given login type. + * + * Arguments: + * * login_type - The login type: LOGIN_TYPE_NORMAL (checks for inserted ID), LOGIN_TYPE_AI and LOGIN_TYPE_ROBOT + * * state - The current login state + */ +/obj/proc/tgui_login_login(login_type = LOGIN_TYPE_NORMAL, datum/tgui_login/state = tgui_login_get()) + if(!state.id || state.logged_in) + return + + if(login_type == LOGIN_TYPE_NORMAL) + if(check_access(state.id)) + state.name = state.id.registered_name + state.rank = state.id.assignment + else if(login_type == LOGIN_TYPE_AI && isAI(usr)) + state.name = usr.name + state.rank = "AI" + else if(login_type == LOGIN_TYPE_ROBOT && isrobot(usr)) + var/mob/living/silicon/robot/R = usr + state.name = usr.name + state.rank = "[R.modtype] [R.braintype]" + + state.logged_in = TRUE + tgui_login_on_login(state = state) + + return TRUE + +/** + * Attempts to log out. + * + * Arguments: + * * state - The current login state + */ +/obj/proc/tgui_login_logout(datum/tgui_login/state = tgui_login_get()) + if(!state.logged_in) + return + + state.name = "" + state.rank = "" + state.logged_in = FALSE + tgui_login_on_logout(state = state) + + return TRUE + +/** + * Returns (or creates) the login state for the source object. + * + * Arguments: + * * state - The current login state + */ +/obj/proc/tgui_login_get() + RETURN_TYPE(/datum/tgui_login) + . = LAZYACCESS(GLOB.tgui_logins, UID()) + if(!.) + LAZYINITLIST(GLOB.tgui_logins) + . = GLOB.tgui_logins[UID()] = new /datum/tgui_login + +/** + * Called on successful login. + * + * Arguments: + * * state - The current login state + */ +/obj/proc/tgui_login_on_login(datum/tgui_login/state = tgui_login_get()) + return + +/** + * Called on successful logout. + * + * Arguments: + * * state - The current login state + */ +/obj/proc/tgui_login_on_logout(datum/tgui_login/state = tgui_login_get()) + return + +/** + * Login state (there should be only one for one datum) + */ +/datum/tgui_login + var/obj/item/card/id/id = null + var/name = "" + var/rank = "" + var/logged_in = FALSE + +/datum/tgui_login/New(id, name, rank) + src.id = id + src.name = name + src.rank = rank diff --git a/code/modules/tgui/modal.dm b/code/modules/tgui/plugins/modal.dm similarity index 100% rename from code/modules/tgui/modal.dm rename to code/modules/tgui/plugins/modal.dm diff --git a/icons/effects/projectile.dmi b/icons/effects/projectile.dmi new file mode 100644 index 00000000000..48e25c6fe8d Binary files /dev/null and b/icons/effects/projectile.dmi differ diff --git a/icons/mob/actions/actions.dmi b/icons/mob/actions/actions.dmi index 80a5dbe5b04..011baf1e4ac 100644 Binary files a/icons/mob/actions/actions.dmi and b/icons/mob/actions/actions.dmi differ diff --git a/icons/mob/belt.dmi b/icons/mob/belt.dmi index f9c59529b28..f0579eae59b 100644 Binary files a/icons/mob/belt.dmi and b/icons/mob/belt.dmi differ diff --git a/icons/mob/feet.dmi b/icons/mob/feet.dmi index 882e0a0f327..8257a4ffe01 100644 Binary files a/icons/mob/feet.dmi and b/icons/mob/feet.dmi differ diff --git a/icons/mob/inhands/equipment/belt_lefthand.dmi b/icons/mob/inhands/equipment/belt_lefthand.dmi index 366493eebde..febcdb854b8 100644 Binary files a/icons/mob/inhands/equipment/belt_lefthand.dmi and b/icons/mob/inhands/equipment/belt_lefthand.dmi differ diff --git a/icons/mob/inhands/equipment/belt_righthand.dmi b/icons/mob/inhands/equipment/belt_righthand.dmi index 81b075f706e..d7b394cc09b 100644 Binary files a/icons/mob/inhands/equipment/belt_righthand.dmi and b/icons/mob/inhands/equipment/belt_righthand.dmi differ diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi index 88cfce57ed9..ddc012075f6 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 44934af9bfc..b13e2c3307d 100644 Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ diff --git a/icons/mob/map_backgrounds.dmi b/icons/mob/map_backgrounds.dmi new file mode 100644 index 00000000000..dc6e3e46b16 Binary files /dev/null and b/icons/mob/map_backgrounds.dmi differ diff --git a/icons/obj/clothing/belts.dmi b/icons/obj/clothing/belts.dmi index 2521d36697d..000b6b7f1c3 100644 Binary files a/icons/obj/clothing/belts.dmi and b/icons/obj/clothing/belts.dmi differ diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi index f20ca2501a8..4c0b649f615 100644 Binary files a/icons/obj/clothing/shoes.dmi and b/icons/obj/clothing/shoes.dmi differ diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index 75838e00075..668d53ea644 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/icons/obj/modular_console.dmi b/icons/obj/modular_console.dmi deleted file mode 100644 index fba8ad59431..00000000000 Binary files a/icons/obj/modular_console.dmi and /dev/null differ diff --git a/icons/obj/modular_laptop.dmi b/icons/obj/modular_laptop.dmi deleted file mode 100644 index d04e68c2041..00000000000 Binary files a/icons/obj/modular_laptop.dmi and /dev/null differ diff --git a/icons/obj/modular_tablet.dmi b/icons/obj/modular_tablet.dmi deleted file mode 100644 index a6e3223a8d0..00000000000 Binary files a/icons/obj/modular_tablet.dmi and /dev/null differ diff --git a/icons/obj/vending.dmi b/icons/obj/vending.dmi index b39384b9b5b..5be90269399 100755 Binary files a/icons/obj/vending.dmi and b/icons/obj/vending.dmi differ diff --git a/nano/templates/card_prog.tmpl b/nano/templates/card_prog.tmpl deleted file mode 100644 index 7054f8bf4c2..00000000000 --- a/nano/templates/card_prog.tmpl +++ /dev/null @@ -1,309 +0,0 @@ -{{if data.printing}} -
    The computer is currently busy.
    -
    -
    Printing...
    -
    -

    - Thank you for your patience! -

    -{{else}} - {{:helper.link('Access Modification', 'home', {'action' : 'PRG_mode', 'mode_target' : 0}, !data.mode ? 'disabled' : null)}} - {{:helper.link('Job Management', 'gear', {'action' : 'PRG_mode', 'mode_target' : 1}, data.mode == 1 ? 'disabled' : null)}} - {{:helper.link('Crew Manifest', 'folder-open', {'action' : 'PRG_mode', 'mode_target' : 2}, data.mode == 2 ? 'disabled' : null)}} - {{:helper.link('Print', 'print', {'action' : 'PRG_print'}, data.printer && (data.mode == 2 || data.has_modify && !data.mode) ? null : 'disabled')}} - {{:helper.link('Records', 'file', {'action' : 'PRG_mode', 'mode_target' : 3}, (data.mode == 3) ? 'disabled' : null)}} - - {{if data.mode == 1}} -
    -

    Job Management

    -
    -
    -
    - Authorized Identity: -
    -
    - {{:helper.link(data.scan_name, 'eject', {'action' : 'PRG_scan'})}} -
    -
    - Cooldown: -
    -
    - {{if data.cooldown_mins > 0 || data.cooldown_mins == 0 && data.cooldown_secs > 0}} - Next change in: {{:data.cooldown_mins}}:{{:data.cooldown_secs}} - {{else}} - Ready - {{/if}} -
    -
    -
    -
    - {{for data.job_slots}} -
    - {{:value.title}}: {{:value.current_positions}}/{{:value.total_positions}} - {{:helper.link('-', null, {'action' : 'PRG_make_job_unavailable', 'job' : value.title}, value.can_close == 1 && data.authenticated ? null : 'disabled')}} - {{:helper.link('+', null, {'action' : 'PRG_make_job_available', 'job' : value.title}, value.can_open == 1 && data.authenticated ? null : 'disabled')}} - {{:helper.link('Pri', null, {'action' : 'PRG_prioritize_job', 'job' : value.title}, value.can_prioritize > 0 && data.authenticated ? null : 'disabled')}} {{if value.can_prioritize == 2}}Priority Job {{/if}} -
    - {{/for}} -
    - {{else data.mode == 2}} -
    -

    Crew Manifest

    -
    -
    - {{:data.manifest}} -
    - {{else data.mode == 3}} -
    -

    Records

    -
    -
    -
    - Authorized Identity: -
    -
    - {{:helper.link(data.scan_name, 'eject', {'action' : 'PRG_scan'})}} -
    -
    -
    - {{if data.authenticated}} - {{:data.id_change_html}} - {{if data.centcom_access}} - {{:helper.link('Delete Records By: ' + data.scan_owner, null, {'action' : 'PRG_wipe_my_logs'}, null, 'linkDanger')}} - {{/if}} - {{if !data.target_dept}} - {{:helper.link('Delete ALL Records', null, {'action' : 'PRG_wipe_all_logs'}, null, 'linkDanger')}} - {{/if}} - {{else}} - Please insert an authorized ID into the terminal to proceed.
    - {{/if}} -
    - {{else}} -
    -

    Access Modification

    -
    - - {{if !data.authenticated}} - Please insert the IDs into the terminal to proceed.
    - {{/if}} - -
    -
    - Target Identity: -
    -
    - {{:helper.link(data.target_name, 'eject', {'action' : 'PRG_modify'})}} -
    -
    -
    -
    - Authorized Identity: -
    -
    - {{:helper.link(data.scan_name, 'eject', {'action' : 'PRG_scan'})}} -
    -
    -
    - - {{if data.authenticated}} - - - {{if data.has_modify}} -
    -

    Details

    -
    - -
    -
    -
    - - - Registered Name: -
    -
    - - -
    -
    -
    - -
    -
    -
    - - - Account Number: -
    -
    - - -
    -
    -
    - -
    -
    - Terminations: -
    -
    - {{if data.target_rank == "Terminated"}} - {{:data.target_owner}} has already been terminated! - {{else}} - {{:helper.link('Terminate ' + data.target_owner, 'gear', {'action' : 'PRG_terminate'}, data.target_rank == "Terminated" ? 'disabled' : null, data.target_rank == "Terminated" ? 'disabled' : 'linkDanger')}} - {{/if}} -
    -
    - -
    -

    Assignment

    -
    - - -
    - -
    - - {{if data.centcom_access}} -
    -

    Central Command

    -
    -
    - {{for data.all_centcom_access}} - {{:helper.link(value.desc, '', {'action' : 'PRG_access', 'access_target' : value.ref, 'allowed' : value.allowed}, null, value.allowed ? 'selected' : null)}} - {{/for}} -
    -
    Card Skin
    - {{for data.all_centcom_skins}} - {{:helper.link(value.display_name, '', {'action' : 'PRG_skin', 'skin_target' : value.skin}, null,(data.current_skin == value.skin) ? 'selected' : null )}} - {{/for}} -
    -
    - {{else}} -
    -

    {{:data.station_name}}

    -
    -
    - {{for data.regions}} -
    -
    {{:value.name}}
    - {{for value.accesses :accessValue:accessKey}} -
    - {{:helper.link(accessValue.desc, '', {'action' : 'PRG_access', 'access_target' : accessValue.ref, 'allowed' : accessValue.allowed}, null, accessValue.allowed ? 'selected' : null)}} -
    - {{/for}} -
    - {{/for}} -
    -
    Card Skin
    - {{for data.card_skins}} - {{:helper.link(value.display_name, '', {'action' : 'PRG_skin', 'skin_target' : value.skin}, null,(data.current_skin == value.skin) ? 'selected' : null )}} - {{/for}} -
    -
    - {{/if}} - {{/if}} - {{/if}} - {{/if}} -{{/if}} diff --git a/nano/templates/comm_program.tmpl b/nano/templates/comm_program.tmpl deleted file mode 100644 index b1c64c6f4e3..00000000000 --- a/nano/templates/comm_program.tmpl +++ /dev/null @@ -1,129 +0,0 @@ -{{if !data.authenticated}} -
    Please swipe your ID card. {{:helper.link('Log In', 'unlock', {'PRG_login' : 1}, null, 'fixed')}}
    -{{else}} - {{if !data.is_ai}} -
    Please remember to {{:helper.link('Log Out', 'lock', {'PRG_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', {'PRG_operation' : 'cancelshuttle'})}} - {{else data.shuttle.callStatus == 2}} - {{:helper.link('Call Shuttle', 'arrow-circle-down', {'PRG_operation' : 'callshuttle'})}} - {{/if}} -
    -
    - - {{if data.screen==1}} - -

    Menu

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

    Status Displays

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

    Presets

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

    Alerts

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

    Messages

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

    Messages

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

    {{:data.current_message_title}}

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

    Security Level

    - {{:helper.link('Back', 'home', {'PRG_operation' : 'main'})}} -
    -
    -
    Security Level:
    -
    {{>data.str_security_level}}
    -
    -
    -
    Presets:
    -
    - {{for data.levels}} - {{:helper.link(value.name, 'comment', {'PRG_operation' : 'newalertlevel', 'level' : value.id}, value.id == data.security_level ? 'selected' : null)}} - {{/for}} -
    -
    -
    - {{/if}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/computer_fabricator.tmpl b/nano/templates/computer_fabricator.tmpl deleted file mode 100644 index 268f585a3da..00000000000 --- a/nano/templates/computer_fabricator.tmpl +++ /dev/null @@ -1,84 +0,0 @@ -{{:helper.link('Clear Order', 'circle', {'action' : 'clean_order'})}}

    -Your new computer device you always dreamed of is just four steps away...
    -{{if data.state == 0}} -
    -

    Step 1: Select your device type

    - {{:helper.link('Laptop', 'laptop', {'action' : 'pick_device', 'pick' : 1})}} - {{:helper.link('Tablet', 'tablet', {'action' : 'pick_device', 'pick' : 2})}} -
    -{{else data.state == 1}} -
    -

    Step 2: Personalise your device

    - - - - - - - - - - {{if data.devtype != 2}} - - - {{/if}} - - - {{if data.devtype != 2}} - - - - - {{/if}} -
    Current Price: - {{:data.totalprice}}C -
    Battery: - {{:helper.link('Standard', 'bolt', {'action' : 'hw_battery', 'battery' : 1}, data.hw_battery == 1 ? "selected" : null)}} - {{:helper.link('Upgraded', 'bolt', {'action' : 'hw_battery', 'battery' : 2}, data.hw_battery == 2 ? "selected" : null)}} - {{:helper.link('Advanced', 'bolt', {'action' : 'hw_battery', 'battery' : 3}, data.hw_battery == 3 ? "selected" : null)}} -
    Hard Drive: - {{:helper.link('Standard', 'hdd-o', {'action' : 'hw_disk', 'disk' : 1}, data.hw_disk == 1 ? "selected" : null)}} - {{:helper.link('Upgraded', 'hdd-o', {'action' : 'hw_disk', 'disk' : 2}, data.hw_disk == 2 ? "selected" : null)}} - {{:helper.link('Advanced', 'hdd-o', {'action' : 'hw_disk', 'disk' : 3}, data.hw_disk == 3 ? "selected" : null)}} -
    Network Card: - {{:helper.link('None', 'times', {'action' : 'hw_netcard', 'netcard' : 0}, data.hw_netcard == 0 ? "selected" : null)}} - {{:helper.link('Standard', 'signal', {'action' : 'hw_netcard', 'netcard' : 1}, data.hw_netcard == 1 ? "selected" : null)}} - {{:helper.link('Advanced', 'signal', {'action' : 'hw_netcard', 'netcard' : 2}, data.hw_netcard == 2 ? "selected" : null)}} -
    Nano Printer: - {{:helper.link('None', 'times', {'action' : 'hw_nanoprint', 'print' : 0}, data.hw_nanoprint == 0 ? "selected" : null)}} - {{:helper.link('Standard', 'print', {'action' : 'hw_nanoprint', 'print' : 1}, data.hw_nanoprint == 1 ? "selected" : null)}} -
    Card Reader: - {{:helper.link('None', 'times', {'action' : 'hw_card', 'card' : 0}, data.hw_card == 0 ? "selected" : null)}} - {{:helper.link('Standard', 'credit-card', {'action' : 'hw_card', 'card' : 1}, data.hw_card == 1 ? "selected" : null)}} -
    Processor Unit: - {{:helper.link('Standard', 'tasks', {'action' : 'hw_cpu', 'cpu' : 1}, data.hw_cpu == 1 ? "selected" : null)}} - {{:helper.link('Advanced', 'tasks', {'action' : 'hw_cpu', 'cpu' : 2}, data.hw_cpu == 2 ? "selected" : null)}} -
    Tesla Relay: - {{:helper.link('None', 'times', {'action' : 'hw_tesla', 'tesla' : 0}, data.hw_tesla == 0 ? "selected" : null)}} - {{:helper.link('Standard', 'plug', {'action' : 'hw_tesla', 'tesla' : 1}, data.hw_tesla == 1 ? "selected" : null)}} -
    - - - -
    Confirm Order: - {{:helper.link('CONFIRM', 'check', {'action' : 'confirm_order'})}} -
    - -
    - Battery allows your device to operate without external utility power source. Advanced batteries increase battery life.
    - Hard Drive stores file on your device. Advanced drives can store more files, but use more power, shortening battery life.
    - Network Card allows your device to wirelessly connect to stationwide NTNet network. Basic cards are limited to on-station use, while advanced cards can operate anywhere near the station, which includes the asteroid outposts.
    - Processor Unit is critical for your device's functionality. It allows you to run programs from your hard drive. Advanced CPUs use more power, but allow you to run more programs on background at once.
    - Tesla Relay is an advanced wireless power relay that allows your device to connect to nearby area power controller to provide alternative power source. This component is currently unavailable on tablet computers due to size restrictions.
    - Nano Printer is device that allows for various paperwork manipulations, such as, scanning of documents or printing new ones. This device was certified EcoFriendlyPlus and is capable of recycling existing paper for printing purposes.
    - Card Reader adds a slot that allows you to manipulate RFID cards. Please note that this is not necessary to allow the device to read your identification, it is just necessary to manipulate other cards. -
    -{{else data.state == 2}} -

    Step 3: Payment

    - Your device is now ready for fabrication..
    - Please swipe your identification card to finish purchase.
    - Total price: {{:data.totalprice}}C -{{else data.state == 3}} -

    Step 4: Thank you for your purchase

    - Should you experience any issues with your new device, contact technical support at support@computerservice.nt -{{/if}} diff --git a/nano/templates/computer_main.tmpl b/nano/templates/computer_main.tmpl deleted file mode 100644 index 9aad3d58609..00000000000 --- a/nano/templates/computer_main.tmpl +++ /dev/null @@ -1,9 +0,0 @@ -No program loaded. Please select program from list below. -
    - - {{for data.programs}} -
    {{:helper.link(value.desc, null, {'action' : 'PC_runprogram', 'name' : value.name})}} - {{:helper.link('', null, {'action' : 'PC_killprogram', 'name' : value.name}, value.running ? null : 'disabled')}} - {{/for}} -
    -
    \ No newline at end of file diff --git a/nano/templates/file_manager.tmpl b/nano/templates/file_manager.tmpl deleted file mode 100644 index 51d40b84475..00000000000 --- a/nano/templates/file_manager.tmpl +++ /dev/null @@ -1,76 +0,0 @@ -{{if data.error}} -

    An error has occurred and this program can not continue.

    - Additional information: {{:data.error}}
    - Please try again. If the problem persists contact your system administrator for assistance. - {{:helper.link('Restart program', null, {'action' : 'PRG_closefile'})}} -{{else}} - {{if data.filename}} -

    Viewing file {{:data.filename}}

    -
    - {{:helper.link('CLOSE', null, {'action' : 'PRG_closefile'})}} - {{:helper.link('EDIT', null, {'action' : 'PRG_edit'})}} - {{:helper.link('PRINT', null, {'action' : 'PRG_printfile'})}} -

    - {{:data.filedata}} - {{else}} -

    Available files (local):

    -
    - - - - - - - - {{for data.files}} - - - - - - - {{/for}} -
    File nameFile typeFile size (GQ)Operations
    {{:value.name}}.{{:value.type}}{{:value.size}}GQ - {{:helper.link('VIEW', 'eye', {'action' : 'PRG_openfile', 'name' : value.name})}} - {{:helper.link('DELETE', 'trash', {'action' : 'PRG_deletefile', 'name' : value.name}, value.undeletable ? 'disabled' : null)}} - {{:helper.link('RENAME', 'pencil', {'action' : 'PRG_rename', 'name' : value.name}, value.undeletable ? 'disabled' : null)}} - {{:helper.link('CLONE', 'files-o', {'action' : 'PRG_clone', 'name' : value.name}, value.undeletable ? 'disabled' : null)}} - {{if !value.encrypted}} - {{:helper.link('ENCRYPT', null, {'action' : 'PRG_encrypt', 'name' : value.name}, value.undeletable ? 'disabled' : null)}} - {{else}} - {{:helper.link('DECRYPT', null, {'action' : 'PRG_decrypt', 'name' : value.name}, value.undeletable ? 'disabled' : null)}} - {{/if}} - {{if data.usbconnected}} - {{:helper.link('EXPORT', 'upload', {'action' : 'PRG_copytousb', 'name' : value.name}, value.undeletable ? 'disabled' : null)}} - {{/if}} -
    -
    - {{if data.usbconnected}} -

    Available files (portable device):

    -
    - - - - - - - - {{for data.usbfiles}} - - - - - - - {{/for}} -
    File nameFile typeFile size (GQ)Operations
    {{:value.name}}.{{:value.type}}{{:value.size}}GQ - {{:helper.link('DELETE', 'trash', {'action' : 'PRG_usbdeletefile', 'name' : value.name}, value.undeletable ? 'disabled' : null)}} - {{if data.usbconnected}} - {{:helper.link('IMPORT', 'download', {'action' : 'PRG_copyfromusb', 'name' : value.name}, value.undeletable ? 'disabled' : null)}} - {{/if}} -
    -
    - {{/if}} - {{:helper.link('NEW DATA FILE', 'file-text', {'action' : 'PRG_newtextfile'})}} - {{/if}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/firealarm.tmpl b/nano/templates/firealarm.tmpl deleted file mode 100644 index 5ddaa2977f4..00000000000 --- a/nano/templates/firealarm.tmpl +++ /dev/null @@ -1,69 +0,0 @@ - -
    -
    - Fire Alarm -
    -
    - {{:helper.link('Activated', 'lightbulb-o', {'alarm' : 1}, data.fire ? 'selected' : '')}} - {{:helper.link('Deactivated', 'lightbulb-o', {'reset' : 1}, data.fire ? '' : 'selected')}} -
    -
    - -
    -
    - Security Level -
    -
    - {{if data.sec_level == "green"}} - Green - {{else data.sec_level == "blue"}} - Blue - {{else data.sec_level == "red"}} - Red - {{else data.sec_level == "gamma"}} - Gamma - {{else data.sec_level == "epsilon"}} - Contracts terminated. - {{else data.sec_level == "delta"}} - Nuclear device primed. - {{else}} - ERR: Unable to ascertain security level. Please see an authorized NT fire alarm technician. - {{/if}} -
    -
    - -
    -
    - Timer System -
    -
    - {{:helper.link('Initiate', 'play', {'time': 1}, data.timing ? 'selected' : '')}} - {{:helper.link('Stop', 'pause', {'time': 0}, data.timing ? '' : 'selected')}} -
    -
    - -
    -
    - Time Modifiers -
    -
    - {{:helper.link('30', 'minus', {'tp': -30})}} - {{:helper.link('1', 'minus', {'tp': -1 })}} - {{:helper.link('1', 'plus', {'tp': +1 })}} - {{:helper.link('30', 'plus', {'tp': +30})}} -
    -
    - -{{if data.timing}} -
    -
    - Time Left -
    -
    - {{:data.time_left}} -
    -
    -{{/if}} \ No newline at end of file diff --git a/nano/templates/identification_computer.tmpl b/nano/templates/identification_computer.tmpl deleted file mode 100644 index 606af520168..00000000000 --- a/nano/templates/identification_computer.tmpl +++ /dev/null @@ -1,347 +0,0 @@ -{{if data.printing}} -
    The computer is currently busy.
    -
    -
    Printing...
    -
    -

    - Thank you for your patience! -

    -{{else}} - {{:helper.link('Access Modification', 'home', {'choice' : 'mode', 'mode_target' : 0}, !data.mode ? 'disabled' : null)}} - {{if !data.target_dept}}{{:helper.link('Job Management', 'gear', {'choice' : 'mode', 'mode_target' : 1}, data.mode == 1 ? 'disabled' : null)}}{{/if}} - {{:helper.link('Crew Manifest', 'folder-open', {'choice' : 'mode', 'mode_target' : 2}, data.mode == 2 ? 'disabled' : null)}} - {{if !data.target_dept}}{{:helper.link('Print', 'print', {'choice' : 'print'}, (data.mode == 2 || data.has_modify && !data.mode) ? null : 'disabled')}}{{/if}} - {{:helper.link('Records', 'file', {'choice' : 'mode', 'mode_target' : 3}, (data.mode == 3) ? 'disabled' : null)}} - - {{if data.mode == 1 && !data.target_dept}} -
    -

    Job Management

    -
    -
    -
    - Authorized Identity: -
    -
    - {{:helper.link(data.scan_name, 'eject', {'choice' : 'scan'})}} -
    -
    - Cooldown: -
    -
    - {{if data.cooldown_mins > 0 || data.cooldown_mins == 0 && data.cooldown_secs > 0}} - Next change in: {{:data.cooldown_mins}}:{{:data.cooldown_secs}} - {{else}} - Ready - {{/if}} -
    -
    -
    -
    - {{for data.job_slots}} -
    - {{:value.title}}: {{:value.current_positions}}/{{:value.total_positions}} - {{:helper.link('-', null, {'choice' : 'make_job_unavailable', 'job' : value.title}, value.can_close == 1 && data.authenticated ? null : 'disabled')}} - {{:helper.link('+', null, {'choice' : 'make_job_available', 'job' : value.title}, value.can_open == 1 && data.authenticated ? null : 'disabled')}} - {{:helper.link('Pri', null, {'choice' : 'prioritize_job', 'job' : value.title}, value.can_prioritize > 0 && data.authenticated ? null : 'disabled')}} {{if value.can_prioritize == 2}}Priority Job {{/if}} -
    - {{/for}} -
    - {{else data.mode == 2}} -
    -

    Crew Manifest

    -
    -
    - {{:data.manifest}} -
    - {{else data.mode == 3}} -
    -

    Records

    -
    -
    -
    - Authorized Identity: -
    -
    - {{:helper.link(data.scan_name, 'eject', {'choice' : 'scan'})}} -
    -
    -
    - {{if data.authenticated}} - {{:data.id_change_html}} - {{if data.centcom_access}} - {{:helper.link('Delete Records By: ' + data.scan_owner, null, {'choice' : 'wipe_my_logs'}, null, 'linkDanger')}} - {{/if}} - {{if !data.target_dept}} - {{:helper.link('Delete ALL Records', null, {'choice' : 'wipe_all_logs'}, null, 'linkDanger')}} - {{/if}} - {{else}} - Please insert an authorized ID into the terminal to proceed.
    - {{/if}} -
    - {{else}} -
    -

    Access Modification

    -
    - - {{if !data.authenticated}} - Please insert the IDs into the terminal to proceed.
    - {{/if}} - -
    -
    - Target Identity: -
    -
    - {{:helper.link(data.target_name, 'eject', {'choice' : 'modify'})}} -
    -
    -
    -
    - Authorized Identity: -
    -
    - {{:helper.link(data.scan_name, 'eject', {'choice' : 'scan'})}} -
    -
    -
    - - {{if data.authenticated}} - - - {{if data.has_modify}} - {{if !data.target_dept}} -
    -

    Details

    -
    - -
    -
    -
    - - - Registered Name: -
    -
    - - -
    -
    -
    - -
    -
    -
    - - - Account Number: -
    -
    - - -
    -
    -
    - {{/if}} - {{if data.target_rank != "Terminated"}} -
    -
    - Demotions: -
    -
    - {{if data.target_rank == "Demoted"}} - {{:data.target_owner}} has already been demoted! - {{else}} - {{:helper.link('Demote ' + data.target_owner, 'gear', {'choice' : 'demote'}, (data.target_rank == "Civilian" || data.target_rank == "Unassigned") ? 'disabled' : null, (data.target_rank == "Civilian" || data.target_rank == "Unassigned") ? 'disabled' : 'linkDanger')}} - {{/if}} -
    -
    - {{/if}} - {{if !data.target_dept}} -
    -
    - Terminations: -
    -
    - {{if data.target_rank == "Terminated"}} - {{:data.target_owner}} has already been terminated! - {{else}} - {{:helper.link('Terminate ' + data.target_owner, 'gear', {'choice' : 'terminate'}, data.target_rank == "Terminated" ? 'disabled' : null, data.target_rank == "Terminated" ? 'disabled' : 'linkDanger')}} - {{/if}} -
    -
    - -
    -

    Assignment

    -
    - - {{else}} - -
    -

    Assignment for {{:data.target_owner}}

    -
    - - {{/if}} - - -
    - -
    - - {{if data.centcom_access}} -
    -

    Central Command

    -
    -
    - {{for data.all_centcom_access}} - {{:helper.link(value.desc, '', {'choice' : 'access', 'access_target' : value.ref, 'allowed' : value.allowed}, null, value.allowed ? 'selected' : null)}} - {{/for}} -
    -
    Card Skin
    - {{for data.all_centcom_skins}} - {{:helper.link(value.display_name, '', {'choice' : 'skin', 'skin_target' : value.skin}, null,(data.current_skin == value.skin) ? 'selected' : null )}} - {{/for}} -
    -
    - {{else}} - {{if !data.target_dept}} -
    -

    {{:data.station_name}}

    -
    -
    - {{for data.regions}} -
    -
    {{:value.name}}
    - {{for value.accesses :accessValue:accessKey}} -
    - {{:helper.link(accessValue.desc, '', {'choice' : 'access', 'access_target' : accessValue.ref, 'allowed' : accessValue.allowed}, null, accessValue.allowed ? 'selected' : null)}} -
    - {{/for}} -
    - {{/for}} -
    -
    Card Skin
    - {{for data.card_skins}} - {{:helper.link(value.display_name, '', {'choice' : 'skin', 'skin_target' : value.skin}, null,(data.current_skin == value.skin) ? 'selected' : null )}} - {{/for}} -
    -
    - {{/if}} - {{/if}} - {{/if}} - {{/if}} - {{/if}} -{{/if}} diff --git a/nano/templates/laptop_configuration.tmpl b/nano/templates/laptop_configuration.tmpl deleted file mode 100644 index 95dd315b90e..00000000000 --- a/nano/templates/laptop_configuration.tmpl +++ /dev/null @@ -1,71 +0,0 @@ -Welcome to computer configuration utility. Please consult your system administrator if you have any questions about your device.
    -
    -

    Power Supply

    - {{if data.battery}} -
    -
    Battery Status
    -
    Active
    -
    -
    -
    Battery Rating
    -
    {{:data.battery.max}}
    -
    -
    -
    ETA
    -
    {{:data.eta.hours ? helper.smoothRound(data.eta.hours) + "h " : ""}}{{:data.eta.minutes ? helper.smoothRound(data.eta.minutes) + "m " : ""}}{{:helper.smoothRound(data.eta.seconds)}}s
    -
    -
    -
    Battery Charge
    - {{:helper.displayBar(data.battery.charge, 0, data.battery.max, (data.battery.charge > data.battery.max/2) ? 'good' : (data.battery.charge > data.battery.max/4) ? 'average' : 'bad')}} -
    - {{:helper.smoothRound(data.battery.charge, 1)}}/{{:data.battery.max}} -
    -
    - {{else}} -
    -
    Battery Status
    -
    Not Available
    -
    - {{/if}} - -
    -
    Power Usage
    -
    {{:data.power_usage}}W
    -
    -
    - -
    -

    File System

    -
    -
    Used Capacity
    - {{:helper.displayBar(data.disk_used, 0, data.disk_size, (data.disk_used > data.disk_size*0.75) ? 'bad' : (data.disk_used > data.disk_size/2) ? 'average' : 'good')}} -
    - {{:helper.smoothRound(data.disk_used, 1)}}/{{:data.disk_size}}GQ -
    -
    -
    - -
    -

    Computer Components

    - {{for data.hardware}} -

    {{:value.name}}

    - {{:value.desc}}
    -
    -
    State
    -
    {{:value.enabled ? "Enabled" : "Disabled"}}
    -
    - -
    -
    Power Usage
    -
    {{:value.powerusage}}W
    -
    - - {{if !value.critical}} -
    -
    Toggle Component
    -
    {{:helper.link(value.enabled ? 'On' : 'Off', value.enabled ? 'power-off' : 'close', {'action' : 'PC_toggle_component', 'name' : value.name})}}
    -
    - {{/if}} -

    - {{/for}} -
    \ No newline at end of file diff --git a/nano/templates/ntnet_chat.tmpl b/nano/templates/ntnet_chat.tmpl deleted file mode 100644 index c3f2573f8e2..00000000000 --- a/nano/templates/ntnet_chat.tmpl +++ /dev/null @@ -1,58 +0,0 @@ -{{if data.adminmode}} -

    ADMINISTRATIVE MODE

    -{{/if}} - -{{if data.title}} -
    -
    Current channel:
    -
    {{:data.title}}
    -
    -
    -
    Operator access:
    -
    {{if data.is_operator}}Enabled{{else}}Disabled{{/if}}
    -
    -
    -
    Controls:
    -
    - -
    {{:helper.link('Send message', 'comment-o', {'action' : 'PRG_speak'})}} -
    {{:helper.link('Change nickname', 'pencil', {'action' : 'PRG_changename'})}} -
    {{:helper.link('Toggle administration mode', 'lock', {'action' : 'PRG_toggleadmin'})}} -
    {{:helper.link('Leave channel', 'sign-out', {'action' : 'PRG_leavechannel'})}} -
    {{:helper.link('Save log to local drive', 'download', {'action' : 'PRG_savelog'})}} - {{if data.is_operator}} -
    {{:helper.link('Rename channel', 'pencil', {'action' : 'PRG_renamechannel'})}} -
    {{:helper.link('Set password', 'key', {'action' : 'PRG_setpassword'})}} -
    {{:helper.link('Delete channel', 'trash', {'action' : 'PRG_deletechannel'})}} - {{/if}} -
    -
    -
    - Chat Window -
    -
    -
    - {{for data.messages}} - {{:value.msg}}
    - {{/for}} -
    -
    -
    - Connected Users
    - {{for data.clients}} - {{:value.name}}
    - {{/for}} -{{else}} - Controls: - -
    {{:helper.link('Change nickname', 'pencil', {'action' : 'PRG_changename'})}} -
    {{:helper.link('New Channel', 'plus', {'action' : 'PRG_newchannel'})}} -
    {{:helper.link('Toggle administration mode', 'lock', {'action' : 'PRG_toggleadmin'})}} -
    - Available channels: - - {{for data.all_channels}} -
    {{:helper.link(value.chan, 'sign-in', {'action' : 'PRG_joinchannel', 'id' : value.id})}}
    - {{/for}} -
    -{{/if}} \ No newline at end of file diff --git a/nano/templates/ntnet_dos.tmpl b/nano/templates/ntnet_dos.tmpl deleted file mode 100644 index bff7bb3b9f0..00000000000 --- a/nano/templates/ntnet_dos.tmpl +++ /dev/null @@ -1,25 +0,0 @@ -{{:helper.syndicateMode()}} -{{if data.error}} - ##SYSTEM ERROR: {{:data.error}}{{:helper.link('RESET', null, {'action' : 'PRG_reset'})}} -{{else data.target}} - ##DoS traffic generator active. Tx: {{:data.speed}}GQ/s
    - {{for data.dos_strings}} - {{:value.nums}}
    - {{/for}} - {{:helper.link('ABORT', 'ban', {'action' : 'PRG_reset'})}} -{{else}} - ##DoS traffic generator ready. Select target device.
    -
    -
    Targeted device ID:
    -
    {{if data.focus}}{{:data.focus}}{{else}}None{{/if}}
    -
    -
    - {{:helper.link('EXECUTE', 'play', {'action' : 'PRG_execute'})}}
    -
    - Detected devices on network:
    - - {{for data.relays}} -
    {{:helper.link(value.id, null, {'action' : 'PRG_target_relay', 'targid' : value.id})}} - {{/for}} -
    -{{/if}} \ No newline at end of file diff --git a/nano/templates/ntnet_downloader.tmpl b/nano/templates/ntnet_downloader.tmpl deleted file mode 100644 index 35790bb3c7f..00000000000 --- a/nano/templates/ntnet_downloader.tmpl +++ /dev/null @@ -1,102 +0,0 @@ -Welcome to software download utility. Please select which software you wish to download.
    -{{if data.error}} -

    Download Error

    -
    -
    Information
    -
    {{:data.error}}
    -
    -
    -
    Reset Program
    -
    {{:helper.link('RESET', 'times', {'action' : 'PRG_reseterror'})}}
    -
    -{{else}} - {{if data.downloadname}} -

    Download Running

    -
    - Please wait... -
    -
    File name
    -
    {{:data.downloadname}}
    -
    -
    -
    File description
    -
    {{:data.downloaddesc}}
    -
    -
    -
    File size
    -
    {{:helper.smoothRound(data.downloadcompletion, 1)}}/{{:data.downloadsize}}GQ
    -
    -
    -
    Transfer Rate
    -
    {{:data.downloadspeed}} GQ/s
    -
    -
    -
    Download progress
    - {{:helper.displayBar(data.downloadcompletion, 0, data.downloadsize, (data.downloadcompletion > data.downloadsize/2) ? 'good' : (data.downloadcompletion > data.downloadsize/4) ? 'average' : 'bad')}} -
    - {{:helper.smoothRound(data.downloadcompletion, 1)}}/{{:data.downloadsize}}GQ -
    -
    -
    - {{else}} -

    Primary software repository

    -
    -
    -
    Hard drive
    - {{:helper.displayBar(data.disk_used, 0, data.disk_size, (data.disk_used > data.disk_size/2) ? 'bad' : (data.disk_used > data.disk_size/4) ? 'average' : 'good')}} -
    - {{:helper.smoothRound(data.disk_used, 1)}}/{{:data.disk_size}}GQ -
    -
    - {{for data.downloadable_programs}} -
    -
    -
    File name
    -
    {{:value.filename}} ({{:value.size}} GQ)
    -
    -
    -
    Program name
    -
    {{:value.filedesc}}
    -
    -
    -
    Description
    -
    {{:value.fileinfo}}
    -
    -
    -
    Compatibility
    -
    {{:value.compatibility}}
    -
    -
    -
    File controls
    -
    {{:helper.link('DOWNLOAD', 'download', {'action' : 'PRG_downloadfile', 'filename' : value.filename}, value.status)}}
    -
    - {{/for}} -
    - {{if data.hackedavailable}} -

    UNKNOWN software repository

    -
    - Please note that Nanotrasen does not recommend download of software from non-official servers. - {{for data.hacked_programs}} -
    -
    -
    File name
    -
    {{:value.filename}} ({{:value.size}} GQ)
    -
    -
    -
    Program name
    -
    {{:value.filedesc}}
    -
    -
    -
    Description
    -
    {{:value.fileinfo}}
    -
    -
    -
    File controls
    -
    {{:helper.link('DOWNLOAD', 'download', {'action' : 'PRG_downloadfile', 'filename' : value.filename})}}
    -
    - {{/for}} -
    - {{/if}} - {{/if}} -{{/if}} -
    NTOS v2.0.4b Copyright Nanotrasen 2557 - 2559 diff --git a/nano/templates/ntnet_monitor.tmpl b/nano/templates/ntnet_monitor.tmpl deleted file mode 100644 index 319baa872f0..00000000000 --- a/nano/templates/ntnet_monitor.tmpl +++ /dev/null @@ -1,102 +0,0 @@ -

    WIRELESS CONNECTIVITY

    -
    -
    - Active NTNet Relays: -
    -
    - {{:data.ntnetrelays}} -
    - {{if data.ntnetrelays}} -
    -
    - System status: -
    -
    - {{:data.ntnetstatus ? "ENABLED" : "DISABLED"}} -
    -
    -
    -
    - Control: -
    -
    - {{:helper.link('TOGGLE', null, {'action' : 'toggleWireless'})}} -
    -
    - Caution - Disabling wireless transmitters when using wireless device may prevent you from re-enabling them again! - {{else}} -

    Wireless coverage unavailable, no relays are connected.

    - {{/if}} -
    - -

    FIREWALL CONFIGURATION

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    PROTOCOLSTATUSCONTROL
    Software Downloads
    {{:data.config_softwaredownload ? 'ENABLED' : 'DISABLED'}}
    {{:helper.link('TOGGLE', null, {'action' : 'toggle_function', 'id' : 1})}}
    Peer to Peer Traffic
    {{:data.config_peertopeer ? 'ENABLED' : 'DISABLED'}}
    {{:helper.link('TOGGLE', null, {'action' : 'toggle_function', 'id' : 2})}}
    Communication Systems
    {{:data.config_communication ? 'ENABLED' : 'DISABLED'}}
    {{:helper.link('TOGGLE', null, {'action' : 'toggle_function', 'id' : 3})}}
    Remote System Control
    {{:data.config_systemcontrol ? 'ENABLED' : 'DISABLED'}}
    {{:helper.link('TOGGLE', null, {'action' : 'toggle_function', 'id' : 4})}}
    -
    - -

    SECURITY SYSTEMS

    -{{if data.idsalarm}} -
    -
    -
    -

    NETWORK INCURSION DETECTED

    - An abnormal activity has been detected in the network. Please verify system logs for more information -
    -
    -
    -{{/if}} -
    -
    Intrusion Detection System:
    -
    {{:data.idsstatus ? 'ENABLED' : 'DISABLED'}}
    -
    -
    -
    Maximal Log Count:
    -
    {{:data.ntnetmaxlogs}}
    -
    -
    -
    Controls:
    -
    - -
    {{:helper.link('RESET IDS', null, {'action' : 'resetIDS'})}} -
    {{:helper.link('TOGGLE IDS', null, {'action' : 'toggleIDS'})}} -
    {{:helper.link('SET LOG LIMIT', null, {'action' : 'updatemaxlogs'})}} -
    {{:helper.link('PURGE LOGS', null, {'action' : 'purgelogs'})}} -
    -
    -
    -System Logs -
    -
    -
    - {{for data.ntnetlogs}} - {{:value.entry}}
    - {{/for}} -
    -
    -
    \ No newline at end of file diff --git a/nano/templates/ntnet_relay.tmpl b/nano/templates/ntnet_relay.tmpl deleted file mode 100644 index 8625f94dd14..00000000000 --- a/nano/templates/ntnet_relay.tmpl +++ /dev/null @@ -1,19 +0,0 @@ -

    Relay

    -{{if data.dos_crashed}} -

    NETWORK BUFFERS OVERLOADED

    -

    Overload Recovery Mode

    - This system is suffering temporary outage due to overflow of traffic buffers. Until buffered traffic is processed, all further requests will be dropped. Frequent occurences of this error may indicate insufficient hardware capacity of your network. Please contact your network planning department for instructions on how to resolve this issue. -

    ADMINISTRATIVE OVERRIDE

    - CAUTION - Data loss may occur - {{:helper.link('Purge buffered traffic', 'signal', {'action' : 'restart'})}} -{{else}} -
    -
    Relay status
    -
    {{:helper.link(data.enabled ? "ENABLED" : "DISABLED", 'power-off', {'action' : 'toggle'})}}
    -
    - -
    -
    Network buffer status
    -
    {{:data.dos_overload}}/{{:data.dos_capacity}} GQ
    -
    -{{/if}} \ No newline at end of file diff --git a/nano/templates/ntnet_transfer.tmpl b/nano/templates/ntnet_transfer.tmpl deleted file mode 100644 index 660838b94dc..00000000000 --- a/nano/templates/ntnet_transfer.tmpl +++ /dev/null @@ -1,77 +0,0 @@ -{{if data.error}} -
    -

    An error has occurred during operation...

    - Additional information: {{:data.error}}
    - {{:helper.link('Clear', null, {'action' : 'PRG_reset'})}} -
    -{{else data.downloading}} -

    Download in progress...

    -
    -
    Downloaded file:
    -
    {{:data.download_name}}
    -
    -
    -
    Download progress:
    -
    {{:helper.smoothRound(data.download_progress)}}/{{:data.download_size}}GQ
    -
    -
    -
    Transfer speed:
    -
    {{:data.download_netspeed}}GQ/s
    -
    -
    -
    Controls:
    -
    {{:helper.link('Abort download', 'arrow-left', {'action' : 'PRG_reset'})}}
    -
    -{{else data.uploading}} -

    Server enabled

    -
    -
    Connected clients:
    -
    {{:data.upload_clients}}
    -
    -
    -
    Provided file:
    -
    {{:data.upload_filename}}
    -
    -
    -
    Server password:
    -
    {{if data.upload_haspassword}}ENABLED{{else}}DISABLED{{/if}}
    -
    -
    -
    Commands:
    -
    - {{:helper.link('Set password', 'key', {'action' : 'PRG_setpassword'})}} - {{:helper.link('Exit server', 'arrow-left', {'action' : 'PRG_reset'})}} -
    -
    -{{else data.upload_filelist}} -

    File transfer server ready. Select file to upload:

    - -
    File nameFile sizeControls - {{for data.upload_filelist}} -
    {{:value.filename}} - {{:value.size}}GQ - {{:helper.link('Select', 'upload', {'action' : 'PRG_uploadfile', 'id' : value.uid})}} - {{/for}} -
    -
    - {{:helper.link('Set password', 'key', {'action' : 'PRG_setpassword'})}} - {{:helper.link('Return', 'arrow-left', {'action' : 'PRG_reset'})}} -{{else}} -

    Available files:

    -
    Server UIDFile NameFile SizePassword ProtectionOperations - {{for data.servers}} -
    {{:value.uid}} - {{:value.filename}} - {{:value.size}}GQ - {{if value.haspassword}} - Enabled - {{else}} - Disabled - {{/if}} - - {{:helper.link('Download', 'download', {'action' : 'PRG_downloadfile', 'id' : value.uid})}} - {{/for}} -
    -
    - {{:helper.link('Send file', 'upload', {'action' : 'PRG_uploadmenu'})}} -{{/if}} \ No newline at end of file diff --git a/nano/templates/order_console.tmpl b/nano/templates/order_console.tmpl deleted file mode 100644 index 271e35c525a..00000000000 --- a/nano/templates/order_console.tmpl +++ /dev/null @@ -1,111 +0,0 @@ - - - -
    -
    - Supply Points: -
    -
    - {{:data.points}} -
    -
    -
    -
    - Shuttle Status: -
    -
    - {{if !data.moving && !data.at_station}} - Docked off-station. - {{else !data.moving && data.at_station}} - Docked at the station. - {{else data.moving}} - Shuttle is en route (ETA: {{:data.timeleft}} minute{{if data.timeleft != 1}}s{{/if}}). - {{/if}} -
    -
    -
    -
    - Supply Crates -
    -
    -
    -
    - {{if !data.contents}} - {{for data.supply_packs}} -
    -
    -
    {{:helper.link(value.name, null, value.command1)}}
    - {{:helper.link('#', null, value.command2, null)}}{{:helper.link('C', null, value.command3, null)}}
    {{:value.cost}} points
    -
    -
    - {{/for}} - {{else}} -
    - Contents of {{:data.contents_name}} -
    - {{:data.contents}} - {{:helper.link('Return', 'arrow-left', {'contents' : 1})}} - {{/if}} -
    -
    -
    -
    -
    -
    - Categories -
    - {{for data.categories}} -
    - {{:helper.link(value.name, 'gear', {'last_viewed_group':value.category}, (data.last_viewed_group==value.category) ? 'linkOn' : '', 'category')}} -
    - {{/for}} -
    -
    -
    - Supply Orders -
    -
    -
    -
    - Requests -
    - {{for data.requests}} -
    - #{{:value.ordernum}} - {{:value.supply_type}} for {{:value.orderedby}} - {{if value.owned == 1}} - {{:helper.link('CANCEL', null, value.command1, null)}} - {{/if}} -
    - {{empty}} - No active requests. - {{/for}} -
    - Orders -
    - {{for data.orders}} -
    - #{{:value.ordernum}} - {{:value.supply_type}} for {{:value.orderedby}} -
    - {{empty}} - No confirmed orders. - {{/for}} -
    -
    -
    -
    \ No newline at end of file diff --git a/nano/templates/portscrubber.tmpl b/nano/templates/portscrubber.tmpl deleted file mode 100644 index 855b290886e..00000000000 --- a/nano/templates/portscrubber.tmpl +++ /dev/null @@ -1,74 +0,0 @@ -

    Scrubber Status

    -
    -
    - Tank Pressure: -
    -
    - {{:helper.smoothRound(data.tankPressure)}} kPa -
    -
    - -
    -
    - Port Status: -
    -
    - {{:data.portConnected ? 'Connected' : 'Disconnected'}} -
    -
    - -

    Holding Tank Status

    -{{if data.hasHoldingTank}} -
    -
    - Tank Label: -
    -
    -
    {{:data.holdingTank.name}}
    {{:helper.link('Eject', 'eject', {'remove_tank' : 1})}} -
    -
    - -
    -
    - Tank Pressure: -
    -
    - {{:helper.smoothRound(data.holdingTank.tankPressure)}} kPa -
    -
    -{{else}} -
    No holding tank inserted.
    -
     
    -{{/if}} - - -

    Power Regulator Status

    -
    -
    - Volume Rate: -
    -
    - {{:helper.displayBar(data.rate, data.minrate, data.maxrate)}} -
    - {{:helper.link('-', null, {'volume_adj' : -1000}, (data.rate > data.minrate) ? null : 'disabled')}} - {{:helper.link('-', null, {'volume_adj' : -100}, (data.rate > data.minrate) ? null : 'disabled')}} - {{:helper.link('-', null, {'volume_adj' : -10}, (data.rate > data.minrate) ? null : 'disabled')}} - {{:helper.link('-', null, {'volume_adj' : -1}, (data.rate > data.minrate) ? null : 'disabled')}} -
     {{:data.rate}} kPa 
    - {{:helper.link('+', null, {'volume_adj' : 1}, (data.rate < data.maxrate) ? null : 'disabled')}} - {{:helper.link('+', null, {'volume_adj' : 10}, (data.rate < data.maxrate) ? null : 'disabled')}} - {{:helper.link('+', null, {'volume_adj' : 100}, (data.rate < data.maxrate) ? null : 'disabled')}} - {{:helper.link('+', null, {'volume_adj' : 1000}, (data.rate < data.maxrate) ? null : 'disabled')}} -
    -
    -
    - -
    -
    - Power Switch: -
    -
    - {{:helper.link('On', 'unlock', {'power' : 1}, data.on ? 'selected' : null)}}{{:helper.link('Off', 'lock', {'power' : 1}, data.on ? null : 'selected')}} -
    -
    - diff --git a/nano/templates/revelation.tmpl b/nano/templates/revelation.tmpl deleted file mode 100644 index 5412c440caa..00000000000 --- a/nano/templates/revelation.tmpl +++ /dev/null @@ -1,23 +0,0 @@ -{{:helper.syndicateMode()}} -
    -
    - Payload status: -
    -
    - {{if data.armed}} - ARMED - {{else}} - DISARMED - {{/if}} -
    -
    - Controls: -
    -
    - -
    {{:helper.link('OBFUSCATE PROGRAM NAME', 'eye-slash', {'action' : 'PRG_obfuscate'})}} -
    {{:helper.link(data.armed ? 'DISARM' : 'ARM', data.armed ? 'crosshairs' : 'info', {'action' : 'PRG_arm'})}} - {{:helper.link('ACTIVATE', 'exclamation-triangle', {'action' : 'PRG_activate'}, data.armed ? null : 'disabled', data.armed ? 'redButton' : null)}} -
    -
    -
    \ No newline at end of file diff --git a/nano/templates/sec_camera.tmpl b/nano/templates/sec_camera.tmpl deleted file mode 100644 index ebcf44c7ddb..00000000000 --- a/nano/templates/sec_camera.tmpl +++ /dev/null @@ -1,42 +0,0 @@ - -{{:helper.link('Show Map', 'thumb-tack', {'showMap' : 1})}} -{{:helper.link('Reset', 'refresh', {'reset' : 1})}} -
    -
    Current Camera:
    - {{if data.current}} -
    {{:data.current.name}}
    - {{else}} -
    None
    - {{/if}} -
    - -{{if data.networks}} -
    -

    Networks

    - Please select the networks you'd like this console to monitor. - {{if data.emagged}} -
    WARNING: Unauthorized access detected.
    - {{/if}} -
    - {{for data.networks}} - {{:helper.link(value.name, value.active ? 'minus' : 'plus', { 'activate' : value.name, 'active' : value.active }, '', value.active ? 'linkOn' : '')}} - {{/for}} -
    -
    -{{/if}} -
    -

    Cameras

    - {{for data.cameras}} - {{if data.current && value.name == data.current.name}} - {{:helper.link(value.name, '', {'switchTo' : value.camera}, 'selected')}} - {{else value.deact}} - {{:helper.link(value.name + " (deactivated)", '', {}, 'inactive')}} - {{else}} - {{:helper.link(value.name, '', {'switchTo' : value.camera})}} - {{/if}} - {{/for}} -
    - diff --git a/nano/templates/sec_camera_map_content.tmpl b/nano/templates/sec_camera_map_content.tmpl deleted file mode 100644 index 52dc8aeadd6..00000000000 --- a/nano/templates/sec_camera_map_content.tmpl +++ /dev/null @@ -1,20 +0,0 @@ - -{{for data.cameras}} - {{if value.z == 1}} -
    - {{if data.current && value.name == data.current.name}} - {{:helper.link("#", '', {'switchTo' : value.camera}, 'selected')}} - {{else value.deact}} - {{:helper.link('#', '', {}, 'inactive')}} - {{else}} - {{:helper.link("#", '', {'switchTo' : value.camera})}} - {{/if}} - -
    - {{/if}} -{{/for}} \ No newline at end of file diff --git a/nano/templates/sec_camera_map_header.tmpl b/nano/templates/sec_camera_map_header.tmpl deleted file mode 100644 index ebe90da3015..00000000000 --- a/nano/templates/sec_camera_map_header.tmpl +++ /dev/null @@ -1,23 +0,0 @@ - -{{:helper.link('Show Camera List', 'file-text', {'showMap' : 0})}} -{{:helper.link('Reset', 'refresh', {'reset' : 1})}} -
    -
    -
    Current Camera: 
    - {{if data.current}} -
    {{:data.current.name}}
    - {{else}} -
    None
    - {{/if}} -
    -
    -
    - Zoom Level:  - - - - -
    diff --git a/nano/templates/skills_data.tmpl b/nano/templates/skills_data.tmpl deleted file mode 100644 index 6f8fb1d6a0d..00000000000 --- a/nano/templates/skills_data.tmpl +++ /dev/null @@ -1,199 +0,0 @@ - - - - -{{if !data.temp && data.screen == 1}} - -{{/if}} - - -
    -
    - Confirm Identity: -
    -
    - {{:helper.link(data.scan ? data.scan : "----------", 'eject', {'scan' : 1}, null, data.scan ? 'itemContentWide' : 'fixedLeft')}} -
    -
    -
    -{{if data.authenticated}} - {{if data.screen == 1}} -
    -
    {{:helper.link('New Record', 'plus', {'new_g' : 1})}}
    -
    -

    Record List

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

    Menu

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

    Records Maintenance

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

    Employment Record

    -

    General Data

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

    Employment Data

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

    Menu

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

    Menu

    - {{:helper.link('Login', 'unlock', {'login' : 1})}} -{{/if}} - -{{if data.temp}} -
    -
    - {{if data.temp.notice}} -
    {{:data.temp.text}}
    - {{else}} -
    {{:data.temp.text}}
    - {{/if}} - - - {{if data.temp.has_buttons}} -
    -
    -
    - {{for data.temp.buttons}} - {{:helper.link(value.name, value.icon, {'temp' : 1, 'temp_action' : value.val}, value.status)}} - {{/for}} -
    -
    -
    - {{/if}} - -
    -
    {{:helper.link('Clear screen', 'home', {'temp' : 1})}}
    -
    -
    -
    -{{/if}} \ No newline at end of file diff --git a/nano/templates/supermatter_monitor.tmpl b/nano/templates/supermatter_monitor.tmpl deleted file mode 100644 index 3bc87984d79..00000000000 --- a/nano/templates/supermatter_monitor.tmpl +++ /dev/null @@ -1,111 +0,0 @@ -{{if data.active}} - {{:helper.link('Back to Menu', null, {'clear' : 1})}}
    -
    -
    - Core Integrity: -
    -
    - {{:helper.displayBar(data.SM_integrity, 0, 100, (data.SM_integrity == 100) ? 'good' : (data.SM_integrity >= 50) ? 'average' : 'bad')}} {{:data.SM_integrity}}% -
    -
    - Relative EER: -
    -
    - {{if data.SM_power > 300}} - {{:data.SM_power}} MeV/cm3 - {{else data.SM_power > 150}} - {{:data.SM_power}} MeV/cm3 - {{else}} - {{:data.SM_power}} MeV/cm3 - {{/if}} -
    -
    - Temperature: -
    -
    - {{if data.SM_ambienttemp > 5000}} - {{:data.SM_ambienttemp}} K - {{else data.SM_ambienttemp > 4000}} - {{:data.SM_ambienttemp}} K - {{else}} - {{:data.SM_ambienttemp}} K - {{/if}} -
    -
    - Pressure: -
    -
    - {{if data.SM_ambientpressure > 10000}} - {{:data.SM_ambientpressure}} kPa - {{else data.SM_ambientpressure > 5000}} - {{:data.SM_ambientpressure}} kPa - {{else}} - {{:data.SM_ambientpressure}} kPa - {{/if}} -
    -
    -

    -
    - Gas Composition: -
    -
    -
    -
    - O2: -
    -
    - {{:data.SM_gas_O2}} % -
    -
    - CO2: -
    -
    - {{:data.SM_gas_CO2}} % -
    -
    - N2: -
    -
    - {{:data.SM_gas_N2}} % -
    -
    - PL: -
    -
    - {{:data.SM_gas_PL}} % -
    -
    - OTHER: -
    -
    - {{:data.SM_gas_OTHER}} % -
    -
    -
    - -{{else}} - {{:helper.link('Refresh', null, {'refresh' : 1})}}
    - {{for data.supermatters}} -
    -
    - Area: -
    -
    - {{:value.area_name}} -
    -
    - Integrity: -
    -
    - {{:value.integrity}} % -
    -
    - Options: -
    -
    - {{:helper.link('View Details', null, {'set' : value.uid})}} -
    -
    - {{/for}} -{{/if}} diff --git a/nano/templates/supply_console.tmpl b/nano/templates/supply_console.tmpl deleted file mode 100644 index 3402e8982b5..00000000000 --- a/nano/templates/supply_console.tmpl +++ /dev/null @@ -1,130 +0,0 @@ - - - -
    -
    - Supply Points: -
    -
    - {{:data.points}} -
    -
    -
    -
    - Central Command messages: -
    -
    - {{:data.message}} -
    -
    -
    -
    - Shuttle Status: -
    -
    - {{if !data.moving && !data.at_station}} - Docked off-station. - {{else !data.moving && data.at_station}} - Docked at the station. - {{else data.moving}} -
    Shuttle is en route (ETA: {{:data.timeleft}} minute{{if data.timeleft != 1}}s{{/if}}).
    - {{/if}} -
    -
    -
    -
    - Shuttle Control: -
    -
    - {{:helper.link('Call Shuttle', 'arrow-circle-down', data.send, data.moving || data.at_station || !data.can_launch ? 'disabled' : '')}} - {{:helper.link('Return Shuttle', 'arrow-circle-up', data.send, data.moving || !data.at_station || !data.can_launch ? 'disabled' : '')}} -
    -
    -
    -
    - Supply Crates -
    -
    -
    -
    - {{if !data.contents}} - {{for data.supply_packs}} -
    -
    -
    {{:helper.link(value.name, null, value.command1)}}
    - {{:helper.link('#', null, value.command2, null)}} - {{:helper.link('C', null, value.command3, null)}}
    {{:value.cost}} points
    -
    -
    - {{/for}} - {{else}} - {{:helper.link('Return', 'arrow-left', {'contents' : 1})}} -
    - Contents of {{:data.contents_name}} -
    - {{:data.contents}} - {{/if}} -
    -
    -
    -
    -
    -
    - Categories -
    - {{for data.categories}} -
    - {{:helper.link(value.name, 'gear', {'last_viewed_group':value.category}, (data.last_viewed_group==value.category) ? 'linkOn' : '', 'category')}} -
    - {{/for}} -
    -
    -
    - Supply Orders -
    -
    -
    -
    - Requests -
    - {{for data.requests}} -
    - #{{:value.ordernum}} - {{:value.supply_type}} for {{:value.orderedby}} -
    - {{:value.comment}} -
    - {{:helper.link('APPROVE', null, value.command1, !data.canapprove ? 'disabled' : '')}} {{:helper.link('REJECT', null, value.command2, null)}} -
    - {{empty}} - No active requests. - {{/for}} -
    - Orders -
    - {{for data.orders}} -
    - #{{:value.ordernum}} - {{:value.supply_type}} for {{:value.orderedby}} -
    - {{empty}} - No confirmed orders. - {{/for}} -
    -
    -
    -
    \ No newline at end of file diff --git a/nano/templates/tank_dispenser.tmpl b/nano/templates/tank_dispenser.tmpl deleted file mode 100644 index a634a2dde8e..00000000000 --- a/nano/templates/tank_dispenser.tmpl +++ /dev/null @@ -1,7 +0,0 @@ -
    -
    Dispense:
    -
    - {{:helper.link('Plasma (' + helper.smoothRound(data.p_tanks) + ')', data.p_tanks ? 'square' : 'square-o', {'plasma' : 1}, data.p_tanks ? null : 'disabled')}} - {{:helper.link('Oxygen (' + helper.smoothRound(data.o_tanks) + ')', data.o_tanks ? 'square' : 'square-o', {'oxygen' : 1}, data.o_tanks ? null : 'disabled')}} -
    -
    \ No newline at end of file diff --git a/nano/templates/tcomms_core.tmpl b/nano/templates/tcomms_core.tmpl deleted file mode 100644 index ee7bffd0ed0..00000000000 --- a/nano/templates/tcomms_core.tmpl +++ /dev/null @@ -1,189 +0,0 @@ -{{:helper.link('Device Configuration', 'wrench', {'tab' : "CONFIG"}, data.tab == "CONFIG" ? 'selected' : '')}} -{{:helper.link('Device Links', 'link', {'tab' : "LINKS"}, data.tab == "LINKS" ? 'selected' : '')}} -{{:helper.link('User Filtering', 'user-times', {'tab' : "FILTER"}, data.tab == "FILTER" ? 'selected' : '')}} - -{{if data.ion}} -
    -ERROR: An Ionspheric overload has occured. Please wait for the machine to reboot. This cannot be manually done. -
    -{{/if}} - -{{if data.tab == "CONFIG"}} -

    Core Configuration

    -

    Status

    -
    -
    - Machine Active: -
    -
    - {{:helper.link(data.active ? 'Enabled' : 'Disabled', 'power-off', {'toggle_active' : 1}, null, data.active ? 'selected' : '')}} -
    -
    -
    -
    - Sectors with Telecommunications Signal: -
    -
    - {{:data.sectors_available}} -
    -
    -

    Settings

    -
    -
    - Job Announcements: -
    -
    - {{:helper.link(data.nttc_toggle_jobs ? 'Enabled' : 'Disabled', 'clipboard', {'nttc_toggle_jobs' : 1}, null, data.nttc_toggle_jobs ? 'selected' : null)}} -
    -
    -
    -
    - Job Departmentalisation: -
    -
    - {{:helper.link(data.nttc_toggle_job_color ? 'Enabled' : 'Disabled', 'clipboard', {'nttc_toggle_job_color' : 1}, null, data.nttc_toggle_job_color ? 'selected' : null)}} -
    -
    -
    -
    - Name Departmentalisation: -
    -
    - {{:helper.link(data.nttc_toggle_name_color ? 'Enabled' : 'Disabled', 'users', {'nttc_toggle_name_color' : 1}, null, data.nttc_toggle_name_color ? 'selected' : null)}} -
    -
    -
    -
    - Command Amplification: -
    -
    - {{:helper.link(data.nttc_toggle_command_bold ? 'Enabled' : 'Disabled', 'volume-up', {'nttc_toggle_command_bold' : 1}, null, data.nttc_toggle_command_bold ? 'selected' : null)}} -
    -
    -

    Advanced

    -
    -
    - Job Announcement Format: -
    -
    - {{:helper.link(data.nttc_job_indicator_type ? data.nttc_job_indicator_type : 'Unset', 'pencil', {'nttc_job_indicator_type' : 1}, null, data.nttc_job_indicator_type ? 'selected' : null)}} -
    -
    -
    -
    - Language Conversion: -
    -
    - {{:helper.link(data.nttc_setting_language ? data.nttc_setting_language : 'Unset', 'globe', {'nttc_setting_language' : 1}, null, data.nttc_setting_language ? 'selected' : null)}} -
    -
    -
    -
    - Network ID: -
    -
    - {{:helper.link(data.network_id ? data.network_id : 'Unset', 'server', {'network_id' : 1}, null, data.network_id ? 'selected' : null)}} -
    -
    -

    Maintenance

    - {{:helper.link('Import Configuration', 'sign-in', {'import' : 1})}} - {{:helper.link('Export Configuration', 'sign-out', {'export' : 1})}} -{{else data.tab == "LINKS"}} - -

    Connected Devices

    -
    -
    - Link Password: -
    -
    - {{:helper.link(data.link_password ? data.link_password : 'Unset', 'lock', {'change_password' : 1}, null, data.link_password ? 'selected' : null)}} -
    -
    -
    - - - - - - - - - - - - - - - - - - - {{for data.entries}} - - - - - - - - {{/for}} - -
    Network AddressNetwork IDSectorStatusUnlink
    {{:value.addr}}{{:value.net_id}}{{:value.sector}}{{:value.status ? 'Active' : 'Offline'}}{{:helper.link('Unlink', 'unlink', {'unlink' : value.addr}, null, 'infoButton')}}
    -{{else data.tab == "FILTER"}} - -

    Filtering List

    -
    -
    - {{:helper.link('Add User', 'plus', {'add_filter': 1})}} -
    -
    -
    - - - - - - - - - - - - - {{for data.filtered_users}} - - - - - {{/for}} - -
    NameRemove
    {{:value}}{{:helper.link('Remove', 'times', {'remove_filter' : value}, null, 'infoButton')}}
    -{{/if}} diff --git a/nano/templates/tcomms_relay.tmpl b/nano/templates/tcomms_relay.tmpl deleted file mode 100644 index ae549eff78f..00000000000 --- a/nano/templates/tcomms_relay.tmpl +++ /dev/null @@ -1,107 +0,0 @@ -

    Relay Configuration

    -
    -
    - Device Active: -
    -
    - {{:helper.link(data.active ? 'Enabled' : 'Disabled', 'power-off', {'toggle_active' : 1}, null, data.active ? 'selected' : '')}} -
    -
    -
    -
    - Network ID: -
    -
    - {{:helper.link(data.network_id ? data.network_id : 'Unset', 'pencil', {'network_id' : 1}, null, data.network_id ? 'selected' : null)}} -
    -
    -
    -
    - Link Status: -
    -
    - {{if data.linked}} - Linked - {{else}} - Unlinked - {{/if}} -
    -
    - -{{if data.linked}} -
    -
    - Linked Core ID: -
    -
    - {{:data.linked_core_id}} -
    -
    -
    -
    - Linked Core Address: -
    -
    - {{:data.linked_core_addr}} -
    -
    -
    -
    - Hidden Link: -
    -
    - {{:helper.link(data.hidden_link ? 'Yes' : 'No', data.hidden_link ? 'eye-slash' : 'eye', {'toggle_hidden_link' : 1}, null, data.hidden_link ? 'selected' : null)}} -
    -
    -
    -
    - Unlink: -
    -
    - {{:helper.link('Unlink', 'unlink', {'unlink' : 1}, null, 'redButton')}} -
    -
    -{{else}} - -

    Please select a Core to link to

    - - - - - - - - - - - - - - - - - {{for data.entries}} - - - - - - - {{/for}} - -
    Network AddressNetwork IDSectorLink
    {{:value.addr}}{{:value.net_id}}{{:value.sector}}{{:helper.link('Link', 'link', {'link' : value.addr}, null, 'infoButton')}}
    -{{/if}} diff --git a/paradise.dme b/paradise.dme index 7fe2674b7d8..efddfaea144 100644 --- a/paradise.dme +++ b/paradise.dme @@ -58,6 +58,7 @@ #include "code\__DEFINES\misc.dm" #include "code\__DEFINES\mobs.dm" #include "code\__DEFINES\move_force.dm" +#include "code\__DEFINES\muzzle_flash.dm" #include "code\__DEFINES\pda.dm" #include "code\__DEFINES\pipes.dm" #include "code\__DEFINES\preferences.dm" @@ -155,6 +156,7 @@ #include "code\_onclick\hud\guardian.dm" #include "code\_onclick\hud\hud.dm" #include "code\_onclick\hud\human.dm" +#include "code\_onclick\hud\map_popups.dm" #include "code\_onclick\hud\movable_screen_objects.dm" #include "code\_onclick\hud\other_mobs.dm" #include "code\_onclick\hud\parallax.dm" @@ -305,6 +307,7 @@ #include "code\datums\components\label.dm" #include "code\datums\components\material_container.dm" #include "code\datums\components\paintable.dm" +#include "code\datums\components\proximity_monitor.dm" #include "code\datums\components\slippery.dm" #include "code\datums\components\spawner.dm" #include "code\datums\components\spooky.dm" @@ -731,7 +734,6 @@ #include "code\game\machinery\computer\robot.dm" #include "code\game\machinery\computer\salvage_ship.dm" #include "code\game\machinery\computer\security.dm" -#include "code\game\machinery\computer\skills.dm" #include "code\game\machinery\computer\sm_monitor.dm" #include "code\game\machinery\computer\specops_shuttle.dm" #include "code\game\machinery\computer\station_alert.dm" @@ -851,6 +853,7 @@ #include "code\game\objects\effects\temporary_visuals\clockcult.dm" #include "code\game\objects\effects\temporary_visuals\cult.dm" #include "code\game\objects\effects\temporary_visuals\miscellaneous.dm" +#include "code\game\objects\effects\temporary_visuals\muzzle_flashes.dm" #include "code\game\objects\effects\temporary_visuals\temporary_visual.dm" #include "code\game\objects\items\ashtray.dm" #include "code\game\objects\items\blueprints.dm" @@ -2080,48 +2083,6 @@ #include "code\modules\mob\new_player\sprite_accessories\vulpkanin\vulpkanin_head_markings.dm" #include "code\modules\mob\new_player\sprite_accessories\vulpkanin\vulpkanin_tail_markings.dm" #include "code\modules\mob\new_player\sprite_accessories\wryn\wryn_face.dm" -#include "code\modules\modular_computers\laptop_vendor.dm" -#include "code\modules\modular_computers\computers\item\computer.dm" -#include "code\modules\modular_computers\computers\item\computer_components.dm" -#include "code\modules\modular_computers\computers\item\computer_damage.dm" -#include "code\modules\modular_computers\computers\item\computer_power.dm" -#include "code\modules\modular_computers\computers\item\computer_ui.dm" -#include "code\modules\modular_computers\computers\item\laptop.dm" -#include "code\modules\modular_computers\computers\item\laptop_presets.dm" -#include "code\modules\modular_computers\computers\item\processor.dm" -#include "code\modules\modular_computers\computers\item\tablet.dm" -#include "code\modules\modular_computers\computers\item\tablet_presets.dm" -#include "code\modules\modular_computers\computers\machinery\console_presets.dm" -#include "code\modules\modular_computers\computers\machinery\modular_computer.dm" -#include "code\modules\modular_computers\computers\machinery\modular_console.dm" -#include "code\modules\modular_computers\file_system\computer_file.dm" -#include "code\modules\modular_computers\file_system\data.dm" -#include "code\modules\modular_computers\file_system\program.dm" -#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\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" -#include "code\modules\modular_computers\file_system\programs\generic\file_browser.dm" -#include "code\modules\modular_computers\file_system\programs\generic\ntdownloader.dm" -#include "code\modules\modular_computers\file_system\programs\generic\ntnrc_client.dm" -#include "code\modules\modular_computers\file_system\programs\generic\nttransfer.dm" -#include "code\modules\modular_computers\file_system\programs\research\airestorer.dm" -#include "code\modules\modular_computers\file_system\programs\research\ntmonitor.dm" -#include "code\modules\modular_computers\hardware\_hardware.dm" -#include "code\modules\modular_computers\hardware\ai_slot.dm" -#include "code\modules\modular_computers\hardware\battery_module.dm" -#include "code\modules\modular_computers\hardware\card_slot.dm" -#include "code\modules\modular_computers\hardware\CPU.dm" -#include "code\modules\modular_computers\hardware\hard_drive.dm" -#include "code\modules\modular_computers\hardware\network_card.dm" -#include "code\modules\modular_computers\hardware\portable_disk.dm" -#include "code\modules\modular_computers\hardware\printer.dm" -#include "code\modules\modular_computers\hardware\recharger.dm" -#include "code\modules\modular_computers\NTNet\NTNet.dm" -#include "code\modules\modular_computers\NTNet\NTNet_relay.dm" -#include "code\modules\modular_computers\NTNet\NTNRC\conversation.dm" #include "code\modules\nano\nanoexternal.dm" #include "code\modules\nano\nanoui.dm" #include "code\modules\nano\subsystem.dm" @@ -2342,7 +2303,6 @@ #include "code\modules\research\designs\biogenerator_designs.dm" #include "code\modules\research\designs\bluespace_designs.dm" #include "code\modules\research\designs\comp_board_designs.dm" -#include "code\modules\research\designs\computer_part_designs.dm" #include "code\modules\research\designs\equipment_designs.dm" #include "code\modules\research\designs\janitorial_designs.dm" #include "code\modules\research\designs\machine_designs.dm" @@ -2472,12 +2432,13 @@ #include "code\modules\telesci\telepad.dm" #include "code\modules\telesci\telesci_computer.dm" #include "code\modules\tgui\external.dm" -#include "code\modules\tgui\modal.dm" #include "code\modules\tgui\states.dm" #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\plugins\login.dm" +#include "code\modules\tgui\plugins\modal.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/strings/tips.txt b/strings/tips.txt index 4218e01bbfe..d28943913d3 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -23,7 +23,6 @@ If you find yourself in a fistfight with another player, running away and callin Different weapons have different strengths. Some weapons, such as spears, floor tiles, and throwing stars, deal more damage when thrown compared to when attacked normally. Clicking on a tile on harm intent with a glass of water can make a slippery tile, allowing you to slow down your pursuers in a pinch. When dealing with security, you can often get your sentence negated entirely through cooperation and deception. -The P2P chat function found on tablet computers allows for a stealthy way to communicate with people. We were all new once, be patient and guide new players in the right direction. On most clothing items that go in the exosuit slot, you can put certain small items into your suit storage, such as a spraycan, your emergency oxygen tank, or a flashlight. Most job-related exosuit clothing can fit job-related items into it. For example, the atmospheric technician's hardsuit/winter coat can hold an RPD, and labcoats can hold most medicine. @@ -68,7 +67,7 @@ As a Medical Cyborg, you can partially perform surgery, as you cannot replace or As a Janitor Cyborg, you are the bane of all slaughter demons. Cleaning up blood stains will severely gimp them. As the Chief Engineer, you can rename areas or create entirely new ones using your station blueprints. As the Chief Engineer, your hardsuit is significantly better than everybody else's. It has the best features of both engineering and atmospherics hardsuits, boasting nigh-invulnerability to radiation and all atmospheric conditions. -As the Chief Engineer, the power flow control console in your office will show you APC infos and lets you control them remotely. +As the Chief Engineer, the power flow control console in your office will show you APC infos and lets you control them remotely. As an Engineer, you can electrify grilles by placing wire "nodes" beneath them: the big seemingly unconnected bulges from a half completed wiring job. The wire will be need to be connected to an active power source in order to function. As an Engineer, return to Engineering once in a while to check on the engine and SMES cells. It's always a good idea to make sure containment isn't compromised. As an Engineer, you can power the station solely with the solar arrays. They will provide just enough electricity to power the station, however their output is still much worse compared to the true engine. @@ -86,7 +85,7 @@ As the Head of Security, don't let the power go to your head. You may have high As the Warden, your duty is to be the watchdog of the brig and handler of prisoners when little is happening, and to hand out equipment and weapons to the security officers when a crisis strikes. As the Warden, keep a close eye on the armory at all times, as it is a favored strike point of nuclear operatives and cocky traitors. As the Warden, if a prisoner's crimes are heinous enough you can put them in permabrig or the gulag. Make sure to check on them once in a while! -As the Warden, you can implant criminals you suspect might re-offend with devices that will track their location and allow you to remotely inject them with disabling chemicals. +As the Warden, you can implant criminals you suspect might re-offend with devices that will track their location and allow you to remotely inject them with disabling chemicals. As a Security Officer, communicate and coordinate with your fellow officers using the security channel (:s) to avoid confusion. As a Security Officer, your sechuds or HUDsunglasses let you see crewmates' job assignments, their criminal status, and whether they have a mindshield or not. A flashing green border around their job icon means they are mindshielded. As a Security Officer, mindshield implants can only prevent someone from being turned into a cultist. It will not de-cult them if they have already been converted. @@ -98,7 +97,6 @@ As the IAA, try to negotiate with the Warden if sentences seem too high for the As the IAA, you can try to convince the Captain and Head of Security to hold trials for prisoners in the courtroom. As the Head of Personnel, you are not higher ranking than other heads of staff, even though you are expected to take the Captain's place first should he go missing. If the situation seems too rough for you, consider allowing another head to become temporary Captain. As the Head of Personnel, you are just as large a target as the Captain because of the potential power your ID and computer can hand out. -As the Head of Personnel, consider getting a laptop with an ID slot. It allows you to do your job even when out of your office. As the Mime, your invisible wall power blocks people as well as projectiles. You can use it in a pinch to delay your pursuer. As the Mime, your oath of silence is your source of power. Breaking it robs you of your powers and of your honor. As the Clown, if you lose your banana peel, you can still slip people with your PDA! Honk! @@ -178,7 +176,7 @@ As a Swarmer, you can teleport fellow swarmers away if you think they are in dan As a Ghost, you can double click on just about anything to follow it. Or just warp around! As a Devil, you gain power for every three souls you control, however you also become more obvious. As a Devil, as long as you control at least one other soul, you will automatically resurrect, as long as a banishment ritual is not performed. -At which time a Devil's nameth is spake on the tongue of man, the Devil may appeareth. +At which time a Devil's nameth is spake on the tongue of man, the Devil may appeareth. As a Security Officer, remember that correlation does not equal causation. Someone may have just been at the wrong place at the wrong time! As a Security Officer, remember that you can attach a sec-lite to your taser! As a Terror Spider, leave wrapping of corpses to green spiders unless absolutely necessary. They need it to lay eggs! diff --git a/tgui/packages/tgui/components/NanoMap.js b/tgui/packages/tgui/components/NanoMap.js index 8f3c9445e12..6c4d8c48b16 100644 --- a/tgui/packages/tgui/components/NanoMap.js +++ b/tgui/packages/tgui/components/NanoMap.js @@ -93,7 +93,7 @@ export class NanoMap extends Component { const { dragging, offsetX, offsetY, zoom = 1 } = this.state; const { children } = this.props; - const mapUrl = config.map + "_nanomap_z1.png?" + Date.now(); + const mapUrl = config.map + "_nanomap_z1.png"; const mapSize = (510 * zoom) + 'px'; const newStyle = { width: mapSize, diff --git a/tgui/packages/tgui/interfaces/CameraConsole.js b/tgui/packages/tgui/interfaces/CameraConsole.js new file mode 100644 index 00000000000..594de52eb2c --- /dev/null +++ b/tgui/packages/tgui/interfaces/CameraConsole.js @@ -0,0 +1,135 @@ +import { filter, sortBy } from 'common/collections'; +import { flow } from 'common/fp'; +import { classes } from 'common/react'; +import { createSearch } from 'common/string'; +import { Fragment } from 'inferno'; +import { useBackend, useLocalState } from '../backend'; +import { Button, ByondUi, Input, Section } from '../components'; +import { refocusLayout, Window } from '../layouts'; + +/** + * Returns previous and next camera names relative to the currently + * active camera. + */ +const prevNextCamera = (cameras, activeCamera) => { + if (!activeCamera) { + return []; + } + const index = cameras.findIndex(camera => ( + camera.name === activeCamera.name + )); + return [ + cameras[index - 1]?.name, + cameras[index + 1]?.name, + ]; +}; + +/** + * Camera selector. + * + * Filters cameras, applies search terms and sorts the alphabetically. + */ +const selectCameras = (cameras, searchText = '') => { + const testSearch = createSearch(searchText, camera => camera.name); + return flow([ + // Null camera filter + filter(camera => camera?.name), + // Optional search term + searchText && filter(testSearch), + // Slightly expensive, but way better than sorting in BYOND + sortBy(camera => camera.name), + ])(cameras); +}; + +export const CameraConsole = (props, context) => { + const { act, data, config } = useBackend(context); + const { mapRef, activeCamera } = data; + const cameras = selectCameras(data.cameras); + const [ + prevCameraName, + nextCameraName, + ] = prevNextCamera(cameras, activeCamera); + return ( + +
    + + + +
    +
    +
    + Camera: + {activeCamera + && activeCamera.name + || '—'} +
    +
    +
    + +
    +
    + ); +}; + +export const CameraConsoleContent = (props, context) => { + const { act, data } = useBackend(context); + const [ + searchText, + setSearchText, + ] = useLocalState(context, 'searchText', ''); + const { activeCamera } = data; + const cameras = selectCameras(data.cameras, searchText); + return ( + + setSearchText(value)} /> +
    + {cameras.map(camera => ( + // We're not using the component here because performance + // would be absolutely abysmal (50+ ms for each re-render). +
    { + refocusLayout(); + act('switch_camera', { + name: camera.name, + }); + }}> + {camera.name} +
    + ))} +
    +
    + ); +}; diff --git a/tgui/packages/tgui/interfaces/CargoConsole.js b/tgui/packages/tgui/interfaces/CargoConsole.js new file mode 100644 index 00000000000..a9ae19b5e10 --- /dev/null +++ b/tgui/packages/tgui/interfaces/CargoConsole.js @@ -0,0 +1,280 @@ +import { flow } from 'common/fp'; +import { Fragment } from 'inferno'; +import { filter, sortBy } from 'common/collections'; +import { useBackend, useSharedState, useLocalState } from "../backend"; +import { Button, LabeledList, Box, AnimatedNumber, Section, Dropdown, Input, Table, Modal } from "../components"; +import { Window } from "../layouts"; +import { LabeledListItem } from "../components/LabeledList"; +import { createSearch, toTitleCase } from 'common/string'; + +export const CargoConsole = (props, context) => { + return ( + + + + + + + + + ); +}; + +const ContentsModal = (_properties, context) => { + const [ + contentsModal, + setContentsModal, + ] = useLocalState(context, 'contentsModal', null); + + const [ + contentsModalTitle, + setContentsModalTitle, + ] = useLocalState(context, 'contentsModalTitle', null); + if ((contentsModal !== null) && (contentsModalTitle !== null)) { + return ( + +

    {contentsModalTitle} contents:

    + + {contentsModal.map(i => ( + // This needs keying. I hate it. + + - {i} + + ))} + + + + }> + + + Tank Label: + + + {holding_tank.name} + + + + + Tank Pressure: + + + + {holding_tank.tank_pressure} kPa + + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/TankDispenser.js b/tgui/packages/tgui/interfaces/TankDispenser.js new file mode 100644 index 00000000000..ee30b9a5649 --- /dev/null +++ b/tgui/packages/tgui/interfaces/TankDispenser.js @@ -0,0 +1,33 @@ +import { useBackend } from "../backend"; +import { Button, LabeledList, Box, AnimatedNumber, Section } from "../components"; +import { Window } from "../layouts"; + +export const TankDispenser = (props, context) => { + const { act, data } = useBackend(context); + const { + o_tanks, + p_tanks, + } = data; + return ( + + + +