diff --git a/_maps/map_files/generic/centcomm.dmm b/_maps/map_files/generic/centcomm.dmm index 6949d75e90f..3bae9832cf0 100644 --- a/_maps/map_files/generic/centcomm.dmm +++ b/_maps/map_files/generic/centcomm.dmm @@ -4462,7 +4462,7 @@ /area/centcom/specops) "oQ" = ( /obj/machinery/door/poddoor/multi_tile/impassable/four_tile_ver{ - name = "Jupiter Station Central Access" + name = "Trading Satellite Central Access" }, /turf/simulated/floor/plating/airless, /area/trader_station/sol) @@ -5873,7 +5873,7 @@ dwidth = 4; height = 11; id = "trade_sol_base"; - name = "docking bay 2 at Jupiter Station"; + name = "docking bay at Trading Satellite"; width = 9 }, /obj/structure/fans/tiny, @@ -12878,7 +12878,7 @@ /area/shuttle/transport) "Tu" = ( /obj/machinery/door/airlock/centcom/glass{ - name = "Jupiter Station Central Access" + name = "Trading Satellite Central Access" }, /turf/simulated/floor/wood, /area/trader_station/sol) diff --git a/_maps/map_files/stations/boxstation.dmm b/_maps/map_files/stations/boxstation.dmm index 01ace0aec76..eea05eb169f 100644 --- a/_maps/map_files/stations/boxstation.dmm +++ b/_maps/map_files/stations/boxstation.dmm @@ -679,7 +679,6 @@ /obj/machinery/requests_console{ department = "Security"; departmentType = 5; - name = "Security Requests Console"; pixel_y = 30 }, /obj/machinery/economy/vending/secdrobe, @@ -3149,7 +3148,6 @@ announcementConsole = 1; department = "Head of Security's Desk"; departmentType = 5; - name = "Head of Security Requests Console"; pixel_x = 30 }, /obj/machinery/computer/brigcells{ @@ -4214,7 +4212,6 @@ /obj/machinery/requests_console{ department = "Warden"; departmentType = 7; - name = "Warden's Requests Console"; pixel_y = -30 }, /obj/item/radio/intercom/department/security{ @@ -6839,7 +6836,6 @@ /obj/structure/bookcase/sop, /obj/machinery/requests_console{ department = "Internal Affairs Office"; - name = "Internal Affairs Requests Console"; pixel_x = -30 }, /obj/machinery/light{ @@ -9694,8 +9690,7 @@ pixel_y = -28 }, /obj/machinery/requests_console{ - department = "Internal Affairs Office"; - name = "Magistrate Requests Console"; + department = "Magistrate"; pixel_x = 30; departmentType = 5 }, @@ -10030,8 +10025,7 @@ "aGu" = ( /obj/item/kirbyplants, /obj/machinery/requests_console{ - department = "Internal Affairs Office"; - name = "Courtroom Requests Console"; + department = "Courtroom"; pixel_x = 30 }, /turf/simulated/floor/wood, @@ -10394,8 +10388,7 @@ icon_state = "1-2" }, /obj/machinery/requests_console{ - department = "Internal Affairs Office"; - name = "Courtroom Gallery Requests Console"; + department = "Courtroom"; pixel_x = 30 }, /turf/simulated/floor/plasteel{ @@ -15139,7 +15132,6 @@ /obj/machinery/requests_console{ department = "Security"; departmentType = 5; - name = "Security Requests Console"; pixel_y = 30 }, /obj/machinery/computer/secure_data, @@ -15189,7 +15181,6 @@ }, /obj/machinery/requests_console{ department = "Tool Storage"; - name = "Tool Storage Requests Console"; pixel_y = 30 }, /obj/item/assembly/igniter{ @@ -15989,9 +15980,8 @@ c_tag = "Medbay Paramedic" }, /obj/machinery/requests_console{ - department = "Medbay"; + department = "Paramedic"; departmentType = 1; - name = "Paramedic Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel, @@ -18024,7 +18014,6 @@ "bex" = ( /obj/machinery/requests_console{ department = "Arrival Shuttle"; - name = "Arrival Shuttle Requests Console"; pixel_y = -30 }, /turf/simulated/floor/mineral/titanium/blue, @@ -18291,7 +18280,6 @@ /obj/machinery/requests_console{ department = "Bar"; departmentType = 2; - name = "Bar Requests Console"; pixel_y = 30 }, /obj/structure/table/reinforced, @@ -22961,8 +22949,7 @@ /area/station/service/bar) "brI" = ( /obj/machinery/requests_console{ - department = "Primary Tool Storage"; - name = "Chapel Request Console"; + department = "Chapel"; pixel_x = -30; departmentType = 2 }, @@ -23976,7 +23963,6 @@ /obj/machinery/requests_console{ department = "Kitchen"; departmentType = 2; - name = "Kitchen Requests Console"; pixel_x = 30 }, /turf/simulated/floor/plasteel{ @@ -24787,7 +24773,6 @@ /obj/machinery/requests_console{ department = "Science"; departmentType = 2; - name = "Science Requests Console"; pixel_x = 30 }, /obj/structure/table, @@ -25167,7 +25152,6 @@ /obj/machinery/requests_console{ department = "Cargo Bay"; departmentType = 2; - name = "Cargo Requests Console"; pixel_y = 30 }, /obj/item/stack/tape_roll, @@ -26929,7 +26913,6 @@ /obj/machinery/requests_console{ department = "Robotics"; departmentType = 2; - name = "Robotics Requests Console"; pixel_y = 30 }, /obj/structure/rack{ @@ -27579,7 +27562,6 @@ /obj/machinery/requests_console{ department = "Cargo Bay"; departmentType = 2; - name = "Cargo Requests Console"; pixel_y = 30 }, /obj/effect/turf_decal/delivery/hollow, @@ -27928,7 +27910,6 @@ /obj/machinery/requests_console{ department = "Medbay"; departmentType = 1; - name = "Medbay Requests Console"; pixel_x = -30 }, /obj/structure/table, @@ -29465,7 +29446,6 @@ announcementConsole = 1; department = "Quartermaster's Desk"; departmentType = 5; - name = "Quartermaster Requests Console"; pixel_x = -30 }, /turf/simulated/floor/carpet, @@ -30477,7 +30457,6 @@ /obj/machinery/requests_console{ department = "Cargo Bay"; departmentType = 2; - name = "Cargo Requests Console"; pixel_x = -30 }, /obj/machinery/camera{ @@ -30512,9 +30491,8 @@ dir = 4 }, /obj/machinery/requests_console{ - department = "Medbay"; + department = "Chemistry"; departmentType = 1; - name = "Chemistry Requests Console"; pixel_x = -30 }, /turf/simulated/floor/plasteel{ @@ -32850,7 +32828,6 @@ announcementConsole = 1; department = "Chief Medical Officer's Desk"; departmentType = 5; - name = "Chief Medical Officer Requests Console"; pixel_x = 30 }, /turf/simulated/floor/plasteel{ @@ -33953,7 +33930,6 @@ /obj/machinery/requests_console{ department = "Science"; departmentType = 2; - name = "Science Requests Console"; pixel_y = -30 }, /turf/simulated/floor/plasteel{ @@ -34960,7 +34936,6 @@ /obj/machinery/requests_console{ department = "Virology"; departmentType = 3; - name = "Virology Requests Console"; pixel_y = 30 }, /obj/machinery/newscaster{ @@ -36065,7 +36040,6 @@ announcementConsole = 1; department = "Blueshield"; departmentType = 5; - name = "Blueshield Requests Console"; pixel_y = -30 }, /obj/machinery/atmospherics/unary/vent_scrubber/on{ @@ -39539,7 +39513,6 @@ "cAK" = ( /obj/machinery/requests_console{ department = "Tech Storage"; - name = "Tech Storage Requests Console"; pixel_y = -32 }, /turf/simulated/floor/plating, @@ -40038,7 +40011,6 @@ announcementConsole = 1; department = "NT Representative"; departmentType = 5; - name = "NT Representative Requests Console"; pixel_y = 30 }, /obj/machinery/photocopier, @@ -41501,7 +41473,6 @@ /obj/machinery/requests_console{ department = "Science"; departmentType = 2; - name = "Science Requests Console"; pixel_y = -30 }, /turf/simulated/floor/plasteel{ @@ -42397,7 +42368,6 @@ /obj/machinery/requests_console{ department = "Atmospherics"; departmentType = 3; - name = "Atmospherics Requests Console"; pixel_x = 30 }, /obj/machinery/atmospherics/pipe/simple/hidden/cyan{ @@ -44056,7 +44026,6 @@ /obj/machinery/requests_console{ department = "Engineering"; departmentType = 3; - name = "Engineering Requests Console"; pixel_x = 30 }, /obj/item/stack/sheet/glass{ @@ -44509,9 +44478,8 @@ /area/station/engineering/atmos) "cSf" = ( /obj/machinery/requests_console{ - department = "Science"; + department = "Xenobiology"; departmentType = 2; - name = "Science Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -45193,7 +45161,6 @@ /obj/machinery/requests_console{ department = "Engineering"; departmentType = 3; - name = "Engineering Requests Console"; pixel_y = 30 }, /obj/structure/table, @@ -45741,7 +45708,6 @@ /obj/machinery/requests_console{ department = "Atmospherics"; departmentType = 3; - name = "Atmospherics Requests Console"; pixel_y = -30 }, /obj/item/stack/sheet/glass{ @@ -46480,9 +46446,8 @@ /area/station/engineering/atmos) "cZa" = ( /obj/machinery/requests_console{ - department = "Bar"; + department = "Expedition"; departmentType = 2; - name = "Expedition Requests Console"; pixel_x = 30 }, /turf/simulated/floor/plasteel{ @@ -46779,7 +46744,6 @@ /obj/item/book/manual/evaguide, /obj/machinery/requests_console{ department = "EVA"; - name = "EVA Requests Console"; pixel_x = -32 }, /obj/effect/turf_decal/delivery/white/hollow, @@ -47411,12 +47375,6 @@ /area/station/engineering/break_room) "dcF" = ( /obj/structure/closet/firecloset, -/obj/machinery/requests_console{ - department = "Atmospherics"; - departmentType = 3; - name = "Atmospherics Requests Console"; - pixel_x = -30 - }, /turf/simulated/floor/plasteel, /area/station/engineering/atmos) "dcG" = ( @@ -48855,7 +48813,6 @@ "dig" = ( /obj/machinery/requests_console{ department = "Locker Room"; - name = "Locker Room Requests Console"; pixel_x = -32 }, /turf/simulated/floor/plasteel, @@ -50680,7 +50637,6 @@ /obj/machinery/requests_console{ department = "Hydroponics"; departmentType = 2; - name = "Hydroponics Requests Console"; pixel_y = 30 }, /obj/machinery/plantgenes, @@ -51645,7 +51601,6 @@ /obj/machinery/requests_console{ department = "AI"; departmentType = 5; - name = "AI Requests Console"; pixel_x = 32; pixel_y = -32 }, @@ -55080,8 +55035,7 @@ }, /obj/item/storage/briefcase, /obj/machinery/requests_console{ - department = "Medbay"; - name = "Psych Requests Console"; + department = "Psychiatrist"; pixel_x = -30; departmentType = 2 }, @@ -59849,7 +59803,6 @@ announcementConsole = 1; department = "Bridge"; departmentType = 5; - name = "Bridge Requests Console"; pixel_y = 30 }, /turf/simulated/floor/wood, @@ -62147,7 +62100,6 @@ /obj/machinery/requests_console{ department = "Library"; departmentType = 2; - name = "Library Requests Console"; pixel_x = 30 }, /turf/simulated/floor/wood, @@ -67018,8 +66970,7 @@ /area/station/security/permabrig) "kFd" = ( /obj/machinery/requests_console{ - department = "Primary Tool Storage"; - name = "Chapel Office Request Console"; + department = "Chapel"; departmentType = 2; pixel_y = -30 }, @@ -68801,7 +68752,6 @@ /obj/item/camera_film, /obj/item/camera/detective, /obj/machinery/requests_console{ - name = "Detective Requests Console"; pixel_y = -30; department = "Detective"; departmentType = 5 @@ -70463,7 +70413,6 @@ announcementConsole = 1; department = "Chief Engineer's Desk"; departmentType = 7; - name = "Chief Engineer Requests Console"; pixel_y = 32 }, /obj/machinery/light{ @@ -70917,7 +70866,6 @@ /obj/machinery/requests_console{ department = "Morgue"; departmentType = 5; - name = "Morgue Requests Console"; pixel_x = -30 }, /turf/simulated/floor/plasteel{ @@ -71655,7 +71603,6 @@ /obj/item/storage/firstaid/regular, /obj/machinery/requests_console{ department = "Crew Quarters"; - name = "Crew Quarters Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -74294,7 +74241,6 @@ announcementConsole = 1; department = "Bridge"; departmentType = 5; - name = "Bridge Requests Console"; pixel_y = -30 }, /obj/structure/cable{ @@ -79830,7 +79776,6 @@ /obj/machinery/requests_console{ department = "Science"; departmentType = 2; - name = "Science Requests Console"; pixel_x = 30 }, /obj/structure/disposalpipe/segment, @@ -85470,7 +85415,6 @@ announcementConsole = 1; department = "Head of Personnel's Desk"; departmentType = 5; - name = "Head of Personnel Requests Console"; pixel_y = -30 }, /obj/machinery/camera/autoname{ @@ -85494,7 +85438,6 @@ announcementConsole = 1; department = "Research Director's Desk"; departmentType = 7; - name = "Research Director Requests Console"; pixel_x = -2; pixel_y = 30 }, @@ -87782,9 +87725,8 @@ pixel_y = -30 }, /obj/machinery/requests_console{ - department = "Medbay"; + department = "Genetics"; departmentType = 1; - name = "Genetics Requests Console"; pixel_x = -30 }, /turf/simulated/floor/plasteel{ @@ -91819,9 +91761,8 @@ /area/station/maintenance/apmaint) "wQa" = ( /obj/machinery/requests_console{ - department = "Cargo Bay"; + department = "Mining"; departmentType = 2; - name = "Cargo Requests Console"; pixel_x = -30 }, /obj/effect/landmark/start/shaft_miner, @@ -92191,7 +92132,6 @@ /obj/machinery/requests_console{ department = "Janitorial"; departmentType = 1; - name = "Janitor Requests Console"; pixel_y = -29 }, /obj/effect/turf_decal/delivery/green/hollow, @@ -93031,7 +92971,6 @@ announcementConsole = 1; department = "Captain's Desk"; departmentType = 5; - name = "Captain Requests Console"; pixel_x = 30 }, /turf/simulated/floor/carpet/royalblue, diff --git a/_maps/map_files/stations/cerestation.dmm b/_maps/map_files/stations/cerestation.dmm index b23ff7503b7..6d9352005e5 100644 --- a/_maps/map_files/stations/cerestation.dmm +++ b/_maps/map_files/stations/cerestation.dmm @@ -3893,7 +3893,6 @@ announcementConsole = 1; department = "Head of Security's Desk"; departmentType = 5; - name = "Head of Security Requests Console"; pixel_y = -30 }, /obj/machinery/computer/secure_data{ @@ -9904,7 +9903,6 @@ }, /obj/machinery/requests_console{ department = "EVA"; - name = "EVA Requests Console"; pixel_x = -32 }, /turf/simulated/floor/plasteel{ @@ -16098,7 +16096,6 @@ }, /obj/machinery/requests_console{ department = "Virology"; - name = "Virology Requests Console"; pixel_x = -32 }, /obj/machinery/atmospherics/pipe/simple/hidden/supply, @@ -24251,7 +24248,6 @@ }, /obj/machinery/requests_console{ department = "Crew Quarters"; - name = "Crew Quarters Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -24493,9 +24489,8 @@ /area/space) "cEm" = ( /obj/machinery/requests_console{ - department = "Cargo Bay"; + department = "Quartermaster's Desk"; departmentType = 5; - name = "Quartermaster Requests Console"; pixel_x = 30; announcementConsole = 1 }, @@ -24581,7 +24576,6 @@ /obj/machinery/requests_console{ department = "Warden"; departmentType = 7; - name = "Warden's Requests Console"; pixel_x = -30 }, /turf/simulated/floor/plasteel{ @@ -27688,6 +27682,10 @@ /obj/item/paper_bin/nanotrasen, /obj/item/stamp/magistrate, /obj/item/pen/multi/gold, +/obj/machinery/requests_console{ + department = "Magistrate"; + pixel_x = 30 + }, /turf/simulated/floor/carpet, /area/station/legal/magistrate) "cSQ" = ( @@ -28896,7 +28894,6 @@ }, /obj/machinery/requests_console{ department = "Tool Storage"; - name = "Tool Storage Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -29344,7 +29341,6 @@ /obj/machinery/requests_console{ department = "Bar"; departmentType = 2; - name = "Bar Requests Console"; pixel_x = -30 }, /turf/simulated/floor/wood, @@ -30509,7 +30505,6 @@ /area/station/science/hallway) "dkb" = ( /obj/machinery/requests_console{ - name = "Detective Requests Console"; pixel_y = -30; department = "Detective"; departmentType = 5 @@ -33924,7 +33919,6 @@ /obj/item/multitool, /obj/machinery/requests_console{ department = "Tech Storage"; - name = "Tech Storage Requests Console"; pixel_x = -30 }, /turf/simulated/floor/plating, @@ -43068,7 +43062,6 @@ /obj/machinery/requests_console{ department = "Janitorial"; departmentType = 1; - name = "Janitor Requests Console"; pixel_x = 30 }, /turf/simulated/floor/plasteel, @@ -44348,6 +44341,11 @@ /area/station/maintenance/storage) "hkr" = ( /obj/item/kirbyplants, +/obj/machinery/requests_console{ + department = "Chapel"; + departmentType = 2; + pixel_y = 30 + }, /turf/simulated/floor/carpet/black, /area/station/service/chapel) "hkt" = ( @@ -46618,6 +46616,16 @@ icon_state = "darkblue" }, /area/station/medical/storage/secondary) +"hUK" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/requests_console{ + department = "Mining"; + departmentType = 5; + pixel_x = 30; + announcementConsole = 1 + }, +/turf/simulated/floor/plasteel, +/area/station/supply/miningdock) "hUN" = ( /obj/machinery/atmospherics/unary/portables_connector{ dir = 4 @@ -49554,7 +49562,6 @@ announcementConsole = 1; department = "Blueshield"; departmentType = 5; - name = "Blueshield Requests Console"; pixel_x = 30 }, /obj/structure/table/wood, @@ -52798,6 +52805,14 @@ icon_state = "asteroidplating" }, /area/station/maintenance/port) +"jMh" = ( +/obj/item/kirbyplants, +/obj/machinery/requests_console{ + department = "Psychiatrist"; + pixel_x = -30 + }, +/turf/simulated/floor/carpet, +/area/station/medical/psych) "jMr" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 8 @@ -53924,6 +53939,13 @@ /obj/machinery/atmospherics/portable/canister/air, /turf/simulated/floor/plating, /area/station/maintenance/starboard) +"kgy" = ( +/obj/machinery/requests_console{ + department = "Library"; + pixel_x = -30 + }, +/turf/simulated/floor/wood, +/area/station/service/library) "kgP" = ( /turf/simulated/floor/plasteel{ dir = 4; @@ -54974,7 +54996,6 @@ announcementConsole = 1; department = "NT Representative"; departmentType = 5; - name = "NT Representative Requests Console"; pixel_x = 30 }, /turf/simulated/floor/wood, @@ -62366,7 +62387,6 @@ /obj/structure/closet/wardrobe/black, /obj/machinery/requests_console{ department = "Arrival Shuttle"; - name = "Arrival Shuttle Requests Console"; pixel_y = -30 }, /turf/simulated/floor/mineral/titanium/blue, @@ -63470,7 +63490,6 @@ /obj/machinery/requests_console{ department = "Medbay"; departmentType = 1; - name = "Medbay Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -65774,6 +65793,16 @@ "nTa" = ( /turf/simulated/mineral/ancient, /area/station/hallway/primary/central/east) +"nTo" = ( +/obj/machinery/requests_console{ + department = "Expedition"; + departmentType = 2; + pixel_x = 30 + }, +/turf/simulated/floor/plasteel{ + icon_state = "dark" + }, +/area/station/service/expedition) "nTJ" = ( /obj/structure/disposalpipe/segment/corner{ dir = 8 @@ -67759,7 +67788,6 @@ /obj/machinery/requests_console{ department = "Kitchen"; departmentType = 2; - name = "Kitchen Requests Console"; pixel_y = -30 }, /turf/simulated/floor/plasteel{ @@ -67866,7 +67894,6 @@ /obj/machinery/requests_console{ department = "Engineering"; departmentType = 3; - name = "Engineering Requests Console"; pixel_x = 30 }, /turf/simulated/floor/plasteel{ @@ -70284,6 +70311,17 @@ icon_state = "white" }, /area/station/science/misc_lab) +"pqq" = ( +/obj/machinery/requests_console{ + announcementConsole = 1; + department = "Xenobiology"; + departmentType = 5; + pixel_x = -30 + }, +/turf/simulated/floor/plasteel{ + icon_state = "whitepurplefull" + }, +/area/station/science/xenobiology) "pqr" = ( /obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{ dir = 4 @@ -77273,7 +77311,6 @@ /obj/machinery/requests_console{ department = "Morgue"; departmentType = 5; - name = "Morgue Requests Console"; pixel_x = -30 }, /turf/simulated/floor/plasteel{ @@ -80554,7 +80591,6 @@ /obj/machinery/requests_console{ department = "Hydroponics"; departmentType = 2; - name = "Hydroponics Requests Console"; pixel_y = 30 }, /obj/machinery/hydroponics/constructable, @@ -83266,7 +83302,6 @@ /obj/machinery/requests_console{ department = "Science"; departmentType = 2; - name = "Science Requests Console"; pixel_x = -30 }, /obj/machinery/r_n_d/circuit_imprinter, @@ -87017,6 +87052,14 @@ /obj/structure/falsewall/rock_ancient, /turf/simulated/floor/plasteel, /area/station/public/locker) +"uJE" = ( +/obj/machinery/requests_console{ + department = "Courtroom"; + departmentType = 2; + pixel_x = 30 + }, +/turf/simulated/floor/carpet, +/area/station/legal/courtroom) "uJT" = ( /turf/simulated/wall, /area/station/maintenance/gambling_den) @@ -87998,9 +88041,8 @@ /obj/item/storage/box/monkeycubes/stokcubes, /obj/item/storage/box/monkeycubes/wolpincubes, /obj/machinery/requests_console{ - department = "Medbay"; + department = "Genetics"; departmentType = 1; - name = "Genetics Requests Console"; pixel_x = -30 }, /turf/simulated/floor/plasteel{ @@ -88993,7 +89035,6 @@ /obj/item/pen/multi, /obj/machinery/requests_console{ department = "Internal Affairs Office"; - name = "Internal Affairs Requests Console"; pixel_x = -30 }, /obj/item/taperecorder, @@ -93175,7 +93216,6 @@ /obj/machinery/requests_console{ department = "Security"; departmentType = 5; - name = "Security Requests Console"; pixel_x = 30 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -93366,6 +93406,10 @@ }, /area/station/maintenance/gambling_den) "wyn" = ( +/obj/machinery/requests_console{ + department = "Paramedic"; + pixel_x = 30 + }, /turf/simulated/floor/plasteel{ dir = 4; icon_state = "whiteblue" @@ -98146,7 +98190,6 @@ "xYV" = ( /obj/machinery/requests_console{ department = "Locker Room"; - name = "Locker Room Requests Console"; pixel_y = -30 }, /turf/simulated/floor/plasteel, @@ -112105,7 +112148,7 @@ xJa gbb xJa gLH -xhk +uJE bIR xhk xhk @@ -113724,7 +113767,7 @@ aEe aEe aEe bLH -bHZ +kgy qKM bRi bPj @@ -120723,7 +120766,7 @@ cGd qqa muT uBC -uBC +pqq uBC cAh pon @@ -138883,7 +138926,7 @@ jVI jVI jVI bzs -vId +nTo hou oVI xbO @@ -145816,7 +145859,7 @@ fMl fMl aZM cMM -bcO +jMh oFv oWH poU @@ -153997,7 +154040,7 @@ uHx aFb byd qbb -qbb +hUK aJH cbR aIA diff --git a/_maps/map_files/stations/deltastation.dmm b/_maps/map_files/stations/deltastation.dmm index 0d416241c10..51d579a263d 100644 --- a/_maps/map_files/stations/deltastation.dmm +++ b/_maps/map_files/stations/deltastation.dmm @@ -398,6 +398,10 @@ /area/station/hallway/secondary/entry/east) "aeF" = ( /obj/structure/filingcabinet/chestdrawer, +/obj/machinery/requests_console{ + department = "Psychiatrist"; + pixel_x = -30 + }, /turf/simulated/floor/wood, /area/station/medical/psych) "aeI" = ( @@ -6289,7 +6293,6 @@ /obj/machinery/requests_console{ department = "Janitorial"; departmentType = 1; - name = "Janitor Requests Console"; pixel_y = 29 }, /obj/effect/turf_decal/delivery/hollow, @@ -9096,7 +9099,6 @@ /obj/machinery/requests_console{ department = "Bar"; departmentType = 2; - name = "Bar Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel/dark, @@ -14497,7 +14499,6 @@ /obj/machinery/requests_console{ department = "Cargo Bay"; departmentType = 2; - name = "Cargo Requests Console"; pixel_y = 30 }, /obj/item/storage/firstaid/regular, @@ -14655,7 +14656,6 @@ announcementConsole = 1; department = "Quartermaster's Desk"; departmentType = 5; - name = "Quartermaster Requests Console"; pixel_x = 30 }, /turf/simulated/floor/plasteel{ @@ -18087,7 +18087,6 @@ /obj/machinery/requests_console{ department = "Kitchen"; departmentType = 2; - name = "Kitchen Requests Console"; pixel_x = 30 }, /obj/effect/turf_decal/delivery, @@ -20495,7 +20494,6 @@ announcementConsole = 1; department = "Head of Security's Desk"; departmentType = 5; - name = "Head of Security Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -24996,7 +24994,6 @@ /obj/machinery/requests_console{ department = "Hydroponics"; departmentType = 2; - name = "Hydroponics Requests Console"; pixel_x = 30 }, /obj/effect/turf_decal/delivery/hollow, @@ -27048,7 +27045,6 @@ /obj/machinery/requests_console{ department = "Atmospherics"; departmentType = 3; - name = "Atmospherics Requests Console"; pixel_x = 30 }, /turf/simulated/floor/plasteel{ @@ -27162,7 +27158,7 @@ dir = 4 }, /obj/machinery/requests_console{ - department = "Primary Tool Storage"; + department = "Tool Storage"; name = "Primary Tool Storage Console"; pixel_y = 30 }, @@ -27740,7 +27736,6 @@ /obj/machinery/requests_console{ department = "AI"; departmentType = 5; - name = "AI Requests Console"; pixel_x = 32; pixel_y = 32 }, @@ -30227,7 +30222,6 @@ /obj/item/stack/sheet/glass, /obj/machinery/requests_console{ department = "Tech Storage"; - name = "Tech Storage Requests Console"; pixel_x = 30 }, /turf/simulated/floor/plasteel/dark, @@ -31234,7 +31228,6 @@ dir = 8 }, /obj/machinery/requests_console{ - name = "Detective Requests Console"; pixel_x = 30; department = "Detective"; departmentType = 5 @@ -31576,7 +31569,6 @@ announcementConsole = 1; department = "Chief Engineer's Desk"; departmentType = 7; - name = "Chief Engineer Requests Console"; pixel_x = -32 }, /turf/simulated/floor/plasteel/dark, @@ -34130,7 +34122,6 @@ announcementConsole = 1; department = "Captain's Desk"; departmentType = 5; - name = "Captain Requests Console"; pixel_x = -30 }, /turf/simulated/floor/carpet/black, @@ -34994,7 +34985,6 @@ announcementConsole = 1; department = "Head of Personnel's Desk"; departmentType = 5; - name = "Head of Personnel Requests Console"; pixel_y = 30 }, /turf/simulated/floor/wood, @@ -36821,7 +36811,6 @@ announcementConsole = 1; department = "NT Representative"; departmentType = 5; - name = "NT Representative Requests Console"; pixel_y = 30 }, /turf/simulated/floor/carpet/royalblack, @@ -36864,7 +36853,6 @@ announcementConsole = 1; department = "Blueshield"; departmentType = 5; - name = "Blueshield Requests Console"; pixel_y = 30 }, /turf/simulated/floor/wood, @@ -39217,6 +39205,10 @@ /area/station/legal/magistrate) "cgk" = ( /obj/item/kirbyplants, +/obj/machinery/requests_console{ + department = "Magistrate"; + pixel_y = -30 + }, /turf/simulated/floor/plasteel{ icon_state = "cult" }, @@ -39665,7 +39657,7 @@ "chL" = ( /obj/structure/table/wood, /obj/machinery/photocopier/faxmachine/longrange{ - department = "IAA Office" + department = "Internal Affairs Office" }, /turf/simulated/floor/wood, /area/station/legal/lawoffice) @@ -39693,7 +39685,6 @@ /obj/structure/filingcabinet/security, /obj/machinery/requests_console{ department = "Internal Affairs Office"; - name = "Internal Affairs Requests Console"; pixel_x = 30 }, /turf/simulated/floor/wood, @@ -41501,7 +41492,6 @@ /obj/machinery/requests_console{ department = "Engineering"; departmentType = 3; - name = "Engineering Requests Console"; pixel_y = -30 }, /obj/effect/turf_decal/delivery, @@ -42238,6 +42228,10 @@ pixel_x = 4; pixel_y = 4 }, +/obj/machinery/requests_console{ + department = "Courtroom"; + pixel_x = 30 + }, /turf/simulated/floor/plasteel/dark, /area/station/legal/courtroom) "coQ" = ( @@ -42622,6 +42616,10 @@ /obj/structure/table/wood, /obj/item/storage/bag/books, /obj/item/taperecorder, +/obj/machinery/requests_console{ + department = "Library"; + pixel_x = 30 + }, /turf/simulated/floor/plasteel/grimy, /area/station/service/library) "cpN" = ( @@ -46929,7 +46927,6 @@ }, /obj/machinery/requests_console{ department = "EVA"; - name = "EVA Requests Console"; pixel_x = 32 }, /turf/simulated/floor/plasteel/dark, @@ -51033,6 +51030,10 @@ d2 = 8; icon_state = "2-8" }, +/obj/machinery/requests_console{ + department = "Paramedic"; + pixel_x = 30 + }, /turf/simulated/floor/plasteel{ dir = 6; icon_state = "whiteblue" @@ -53755,7 +53756,6 @@ /obj/structure/closet/wardrobe/yellow, /obj/machinery/requests_console{ department = "Locker Room"; - name = "Locker Room Requests Console"; pixel_x = 30 }, /turf/simulated/floor/plasteel{ @@ -54087,7 +54087,6 @@ /obj/machinery/requests_console{ department = "Xenobiology"; departmentType = 2; - name = "Xenobiology Requests Console"; pixel_x = 30 }, /obj/effect/turf_decal/delivery, @@ -55183,7 +55182,6 @@ /obj/machinery/requests_console{ department = "Science"; departmentType = 2; - name = "Research Request Console"; pixel_x = 30 }, /turf/simulated/floor/plasteel{ @@ -57214,9 +57212,8 @@ name = "Chemistry Cleaner" }, /obj/machinery/requests_console{ - department = "Medbay"; + department = "Chemistry"; departmentType = 1; - name = "Chemistry Requests Console"; pixel_x = -30 }, /turf/simulated/floor/plasteel{ @@ -57999,7 +57996,6 @@ announcementConsole = 1; department = "Research Director's Desk"; departmentType = 7; - name = "Research Director Requests Console"; pixel_x = -30; pixel_y = -2 }, @@ -58835,7 +58831,6 @@ /obj/machinery/requests_console{ department = "Robotics"; departmentType = 2; - name = "Robotics Requests Console"; pixel_y = 30 }, /obj/effect/turf_decal/delivery/hollow, @@ -65227,9 +65222,8 @@ "dYd" = ( /obj/machinery/dna_scannernew, /obj/machinery/requests_console{ - department = "Medbay"; + department = "Genetics"; departmentType = 1; - name = "Genetics Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -65479,7 +65473,6 @@ /obj/machinery/requests_console{ department = "Chapel"; departmentType = 2; - name = "Chapel Requests Console"; pixel_y = -30 }, /turf/simulated/floor/carpet, @@ -68283,6 +68276,12 @@ icon_state = "redyellowfull" }, /area/station/medical/break_room) +"fyq" = ( +/obj/machinery/requests_console{ + department = "Expedition" + }, +/turf/simulated/floor/plasteel, +/area/station/service/expedition) "fzd" = ( /obj/machinery/access_button{ autolink_id = "virolab_btn_int"; @@ -69545,7 +69544,6 @@ /obj/machinery/requests_console{ department = "Science"; departmentType = 2; - name = "Science Requests Console"; pixel_y = -30 }, /turf/simulated/floor/plasteel{ @@ -73899,7 +73897,6 @@ announcementConsole = 1; department = "Chief Medical Officer's Desk"; departmentType = 5; - name = "Chief Medical Officer Requests Console"; pixel_x = 30 }, /turf/simulated/floor/plasteel{ @@ -78176,7 +78173,6 @@ /obj/machinery/requests_console{ department = "Medbay"; departmentType = 1; - name = "Medbay Requests Console"; pixel_x = 30 }, /obj/structure/table, @@ -81016,6 +81012,14 @@ icon_state = "bar" }, /area/station/service/kitchen) +"nnV" = ( +/obj/effect/turf_decal/delivery, +/obj/machinery/requests_console{ + department = "Mining"; + pixel_y = -30 + }, +/turf/simulated/floor/plasteel, +/area/station/supply/miningdock) "nnW" = ( /obj/machinery/door/airlock/security, /obj/effect/mapping_helpers/airlock/autoname, @@ -81829,7 +81833,6 @@ /obj/machinery/requests_console{ department = "Morgue"; departmentType = 5; - name = "Morgue Requests Console"; pixel_y = -30 }, /turf/simulated/floor/plasteel{ @@ -81960,7 +81963,6 @@ announcementConsole = 1; department = "Bridge"; departmentType = 5; - name = "Bridge Requests Console"; pixel_y = -30; dir = 1 }, @@ -82235,7 +82237,6 @@ /obj/machinery/requests_console{ department = "Security"; departmentType = 5; - name = "Security Requests Console"; pixel_y = -30 }, /turf/simulated/floor/plasteel{ @@ -88978,6 +88979,10 @@ c_tag = "Rec Room Aft"; dir = 4 }, +/obj/machinery/requests_console{ + department = "Crew Quarters"; + pixel_x = -30 + }, /turf/simulated/floor/plasteel{ dir = 8; icon_state = "neutralcorner" @@ -92213,7 +92218,6 @@ /obj/machinery/requests_console{ department = "Warden"; departmentType = 7; - name = "Warden's Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -98690,7 +98694,6 @@ /obj/machinery/requests_console{ department = "Virology"; departmentType = 3; - name = "Virology Requests Console"; pixel_y = -30 }, /turf/simulated/floor/plasteel{ @@ -99146,7 +99149,6 @@ /obj/item/kirbyplants, /obj/machinery/requests_console{ department = "Arrival Shuttle"; - name = "Arrival Shuttle Requests Console"; pixel_x = 30 }, /turf/simulated/floor/mineral/titanium/blue, @@ -141263,7 +141265,7 @@ bIX csV cxe cvK -cCX +fyq cyr czW cBw @@ -144822,7 +144824,7 @@ hYQ bgT bih bjL -boD +nnV eNt boE eNt diff --git a/_maps/map_files/stations/metastation.dmm b/_maps/map_files/stations/metastation.dmm index 7380ac46420..1a88285f334 100644 --- a/_maps/map_files/stations/metastation.dmm +++ b/_maps/map_files/stations/metastation.dmm @@ -440,7 +440,6 @@ /area/station/legal/magistrate) "afw" = ( /obj/machinery/requests_console{ - name = "Detective Requests Console"; pixel_y = 30; department = "Detective"; departmentType = 5 @@ -1336,7 +1335,6 @@ /obj/machinery/requests_console{ department = "Security"; departmentType = 5; - name = "Security Requests Console"; pixel_x = 30 }, /turf/simulated/floor/plasteel{ @@ -5795,6 +5793,10 @@ "aFd" = ( /obj/structure/chair/comfy/brown, /obj/effect/landmark/start/magistrate, +/obj/machinery/requests_console{ + department = "Magistrate"; + pixel_y = 30 + }, /turf/simulated/floor/carpet, /area/station/legal/magistrate) "aFe" = ( @@ -7343,7 +7345,6 @@ /obj/machinery/requests_console{ department = "Science"; departmentType = 2; - name = "Science Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -8903,7 +8904,6 @@ announcementConsole = 1; department = "Quartermaster's Desk"; departmentType = 5; - name = "Quartermaster Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -12321,8 +12321,7 @@ /area/station/hallway/secondary/bridge) "bad" = ( /obj/machinery/requests_console{ - department = "Locker Room"; - name = "Dorms Requests Console"; + department = "Crew Quarters"; pixel_x = 30 }, /turf/simulated/floor/plasteel{ @@ -13505,7 +13504,6 @@ }, /obj/machinery/requests_console{ department = "Tech Storage"; - name = "Tech Storage Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -14286,7 +14284,6 @@ announcementConsole = 1; department = "Chief Engineer's Desk"; departmentType = 7; - name = "Chief Engineer Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -15614,7 +15611,6 @@ /obj/machinery/requests_console{ department = "Security"; departmentType = 5; - name = "Security Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -18009,7 +18005,6 @@ /obj/machinery/requests_console{ department = "Janitorial"; departmentType = 1; - name = "Janitor Requests Console"; pixel_x = -30 }, /obj/machinery/camera{ @@ -18800,7 +18795,6 @@ /obj/machinery/requests_console{ department = "AI"; departmentType = 5; - name = "AI Requests Console"; pixel_x = -30 }, /turf/simulated/floor/plasteel{ @@ -18933,7 +18927,7 @@ /area/shuttle/arrival/station) "brt" = ( /obj/machinery/requests_console{ - department = "Arrival shuttle"; + department = "Arrival Shuttle"; pixel_y = -30 }, /obj/machinery/light, @@ -20145,7 +20139,6 @@ announcementConsole = 1; department = "Bridge"; departmentType = 5; - name = "Bridge Requests Console"; pixel_x = 30 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ @@ -21673,7 +21666,6 @@ announcementConsole = 1; department = "Head of Personnel's Desk"; departmentType = 5; - name = "Head of Personnel Requests Console"; pixel_y = 30 }, /turf/simulated/floor/wood, @@ -21793,7 +21785,6 @@ announcementConsole = 1; department = "Captain's Desk"; departmentType = 5; - name = "Captain Requests Console"; pixel_x = 30 }, /turf/simulated/floor/wood, @@ -24280,6 +24271,10 @@ "bHu" = ( /obj/structure/chair/comfy/black, /obj/effect/landmark/start/assistant, +/obj/machinery/requests_console{ + department = "Library"; + pixel_y = 30 + }, /turf/simulated/floor/wood, /area/station/service/library) "bHv" = ( @@ -24802,13 +24797,6 @@ }, /area/station/telecomms/computer) "bJm" = ( -/obj/machinery/requests_console{ - announcementConsole = 1; - department = "Telecoms Admin"; - departmentType = 5; - name = "Telecoms Request Console"; - pixel_y = -30 - }, /obj/machinery/firealarm{ dir = 4; name = "east bump"; @@ -26778,7 +26766,6 @@ /obj/machinery/requests_console{ department = "Kitchen"; departmentType = 2; - name = "Kitchen Requests Console"; pixel_x = -30 }, /turf/simulated/floor/plasteel{ @@ -27303,6 +27290,10 @@ pixel_x = 7; pixel_y = 4 }, +/obj/machinery/requests_console{ + department = "Expedition"; + pixel_x = 30 + }, /turf/simulated/floor/plasteel{ icon_state = "dark" }, @@ -28543,7 +28534,6 @@ announcementConsole = 1; department = "Blueshield"; departmentType = 5; - name = "Blueshield Requests Console"; pixel_x = -30 }, /obj/item/paper_bin, @@ -28839,7 +28829,6 @@ announcementConsole = 1; department = "NT Representative"; departmentType = 5; - name = "NT Representative Requests Console"; pixel_x = -30 }, /turf/simulated/floor/carpet/royalblack, @@ -30211,7 +30200,6 @@ /obj/machinery/requests_console{ department = "Medbay"; departmentType = 1; - name = "Medbay Requests Console"; pixel_y = 30 }, /obj/machinery/light{ @@ -30441,7 +30429,6 @@ /obj/machinery/requests_console{ department = "Hydroponics"; departmentType = 2; - name = "Hydroponics Requests Console"; pixel_x = -32 }, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, @@ -30475,7 +30462,6 @@ /obj/machinery/requests_console{ department = "Robotics"; departmentType = 2; - name = "Robotics Requests Console"; pixel_y = 30 }, /obj/item/stack/sheet/plasteel{ @@ -35503,7 +35489,6 @@ announcementConsole = 1; department = "Research Director's Desk"; departmentType = 7; - name = "Research Director Requests Console"; pixel_x = 30 }, /obj/machinery/computer/aifixer{ @@ -36224,7 +36209,6 @@ announcementConsole = 1; department = "Head of Security's Desk"; departmentType = 5; - name = "Head of Security Requests Console"; pixel_y = 30 }, /turf/simulated/floor/wood, @@ -39084,6 +39068,11 @@ dir = 4 }, /obj/effect/landmark/start/geneticist, +/obj/machinery/requests_console{ + department = "Genetics"; + departmentType = 1; + pixel_y = -30 + }, /turf/simulated/floor/plasteel{ icon_state = "white" }, @@ -43323,9 +43312,8 @@ dir = 5 }, /obj/machinery/requests_console{ - department = "Science"; + department = "Xenobiology"; departmentType = 2; - name = "Science Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -43387,7 +43375,6 @@ /obj/machinery/requests_console{ department = "Security"; departmentType = 5; - name = "Security Requests Console"; pixel_x = 30 }, /turf/simulated/floor/plasteel{ @@ -43579,7 +43566,6 @@ /obj/machinery/requests_console{ department = "Chapel"; departmentType = 2; - name = "Chapel Requests Console"; pixel_y = 30 }, /obj/machinery/atmospherics/unary/vent_pump/on, @@ -46396,7 +46382,6 @@ /obj/machinery/requests_console{ department = "Engineering"; departmentType = 3; - name = "Engineering Requests Console"; pixel_x = -30 }, /turf/simulated/floor/plasteel{ @@ -47234,7 +47219,6 @@ /obj/machinery/requests_console{ department = "Science"; departmentType = 2; - name = "Science Requests Console"; pixel_y = 30 }, /turf/simulated/floor/plasteel{ @@ -55040,7 +55024,6 @@ "hHW" = ( /obj/machinery/requests_console{ department = "Internal Affairs Office"; - name = "Internal Affairs Requests Console"; pixel_x = 30 }, /turf/simulated/floor/plasteel{ @@ -55860,7 +55843,6 @@ /obj/machinery/requests_console{ department = "Science"; departmentType = 2; - name = "Science Requests Console"; pixel_y = 32 }, /turf/simulated/floor/plasteel{ @@ -59880,7 +59862,6 @@ /obj/machinery/requests_console{ department = "Robotics"; departmentType = 2; - name = "Robotics Requests Console"; pixel_x = -30 }, /obj/structure/disposalpipe/segment{ @@ -61796,7 +61777,6 @@ announcementConsole = 1; department = "Chief Medical Officer's Desk"; departmentType = 5; - name = "Chief Medical Officer Requests Console"; pixel_x = -30 }, /turf/simulated/floor/plasteel{ @@ -62465,6 +62445,10 @@ /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{ dir = 6 }, +/obj/machinery/requests_console{ + department = "Paramedic"; + pixel_y = 30 + }, /turf/simulated/floor/plasteel{ dir = 1; icon_state = "whiteblue" @@ -62573,6 +62557,11 @@ /area/station/maintenance/aft2) "kQx" = ( /obj/item/kirbyplants/plant11, +/obj/machinery/requests_console{ + department = "Courtroom"; + departmentType = 1; + pixel_x = -30 + }, /turf/simulated/floor/wood, /area/station/legal/courtroom) "kQB" = ( @@ -63242,9 +63231,8 @@ "lfd" = ( /obj/structure/table/glass, /obj/machinery/requests_console{ - department = "Medbay"; + department = "Chemistry"; departmentType = 1; - name = "Chemistry Requests Console"; pixel_x = -30 }, /obj/machinery/reagentgrinder, @@ -63604,9 +63592,7 @@ /obj/effect/mapping_helpers/airlock/windoor/access/any/security/armory{ dir = 1 }, -/obj/machinery/door/window/classic/normal{ - name = "Request Window" - }, +/obj/machinery/door/window/classic/normal, /obj/item/pen, /obj/item/paper, /obj/machinery/door/firedoor, @@ -63700,7 +63686,6 @@ "llW" = ( /obj/machinery/requests_console{ department = "Locker Room"; - name = "Dorms Requests Console"; pixel_x = -30 }, /turf/simulated/floor/plasteel{ @@ -64495,7 +64480,6 @@ /obj/machinery/requests_console{ department = "Atmospherics"; departmentType = 3; - name = "Atmospherics Requests Console"; pixel_x = 30 }, /obj/structure/disposalpipe/segment, @@ -66295,6 +66279,10 @@ /obj/structure/chair/comfy/beige{ dir = 8 }, +/obj/machinery/requests_console{ + department = "Psychiatrist"; + pixel_x = 30 + }, /turf/simulated/floor/carpet, /area/station/medical/psych) "moV" = ( @@ -68825,7 +68813,6 @@ /obj/machinery/requests_console{ department = "Bar"; departmentType = 2; - name = "Bar Requests Console"; pixel_y = -30 }, /turf/simulated/floor/plasteel{ @@ -74466,7 +74453,6 @@ /obj/machinery/requests_console{ department = "Cargo Bay"; departmentType = 2; - name = "Cargo Requests Console"; pixel_y = -30 }, /turf/simulated/floor/plasteel{ @@ -75012,7 +74998,6 @@ /obj/machinery/requests_console{ department = "Morgue"; departmentType = 5; - name = "Morgue Requests Console"; pixel_x = -30 }, /obj/machinery/light/small, @@ -75564,7 +75549,6 @@ /obj/machinery/requests_console{ department = "Atmospherics"; departmentType = 3; - name = "Atmospherics Requests Console"; pixel_x = -30 }, /turf/simulated/floor/plasteel{ @@ -76988,7 +76972,6 @@ /obj/machinery/requests_console{ department = "Virology"; departmentType = 3; - name = "Virology Requests Console"; pixel_y = -30 }, /obj/item/stack/sheet/mineral/plasma, @@ -79186,7 +79169,6 @@ /obj/machinery/requests_console{ department = "Warden"; departmentType = 7; - name = "Warden's Requests Console"; pixel_y = 30 }, /obj/structure/cable{ @@ -81820,7 +81802,6 @@ /obj/machinery/requests_console{ department = "Science"; departmentType = 2; - name = "Science Requests Console"; pixel_x = 30 }, /obj/effect/turf_decal/stripes/line{ @@ -82962,7 +82943,6 @@ /obj/machinery/requests_console{ department = "Engineering"; departmentType = 3; - name = "Engineering Requests Console"; pixel_y = -30 }, /turf/simulated/floor/plasteel, diff --git a/code/__DEFINES/admin_defines.dm b/code/__DEFINES/admin_defines.dm index 1856a55e010..fd1ada925ef 100644 --- a/code/__DEFINES/admin_defines.dm +++ b/code/__DEFINES/admin_defines.dm @@ -46,12 +46,14 @@ #define R_HOST ((1<<18)-1) //17 bit bitmask, update me if we ever add more admin permissions. Sum of all permissions to allow easy setting. + #define ADMIN_QUE(user,display) "[display]" #define ADMIN_FLW(user,display) "[display]" #define ADMIN_PP(user,display) "[display]" #define ADMIN_VV(atom,display) "[display]" #define ADMIN_SM(user,display) "[display]" #define ADMIN_TP(user,display) "[display]" +#define ADMIN_OBS(user, display) "[display]" #define ADMIN_ALERT(user, display) "[display]" #define ADMIN_BSA(user,display) "[display]" #define ADMIN_CENTCOM_REPLY(user,display) "[display]" diff --git a/code/__DEFINES/atom_states.dm b/code/__DEFINES/atom_states.dm new file mode 100644 index 00000000000..91484f9a51f --- /dev/null +++ b/code/__DEFINES/atom_states.dm @@ -0,0 +1,4 @@ +#define BAD_INIT_QDEL_BEFORE (1<<0) +#define BAD_INIT_DIDNT_INIT (1<<1) +#define BAD_INIT_SLEPT (1<<2) +#define BAD_INIT_NO_HINT (1<<3) diff --git a/code/__DEFINES/crafting.dm b/code/__DEFINES/crafting.dm index 09b35c5d093..5d2cc6632e9 100644 --- a/code/__DEFINES/crafting.dm +++ b/code/__DEFINES/crafting.dm @@ -27,9 +27,9 @@ #define CAT_SPAGHETTI "Spaghettis" #define CAT_ICE "Frozen" -#define RECIPE_MICROWAVE "Microwave" -#define RECIPE_OVEN "Oven" -#define RECIPE_GRILL "Grill" -#define RECIPE_CANDY "Candy" +#define RECIPE_MICROWAVE "microwave" +#define RECIPE_OVEN "oven" +#define RECIPE_GRILL "grill" +#define RECIPE_CANDY "candy machine" #define RECIPE_FAIL null diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 3dd763ba3da..84491eb549b 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -181,6 +181,8 @@ #define COMSIG_ATOM_ORBIT_BEGIN "atom_orbit_begin" ///called when an atom stops orbiting another atom: (atom) #define COMSIG_ATOM_ORBIT_STOP "atom_orbit_stop" +/// called on an atom who has stopped orbiting another atom (atom/orbiter, atom/formerly_orbited) +#define COMSIG_ATOM_ORBITER_STOP "atom_orbiter_stop" ///from base of atom/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) #define COMSIG_ATOM_HITBY "atom_hitby" /// Called when an atom is sharpened or dulled. @@ -945,11 +947,26 @@ ///from base of datum/action/proc/Trigger(): (datum/action) #define COMSIG_ACTION_TRIGGER "action_trigger" #define COMPONENT_ACTION_BLOCK_TRIGGER (1<<0) +/// From /datum/action/Grant(): (mob/grant_to) +#define COMSIG_ACTION_GRANTED "action_grant" +/// From /datum/action/Grant(): (datum/action) +#define COMSIG_MOB_GRANTED_ACTION "mob_action_grant" +/// From /datum/action/Remove(): (mob/removed_from) +#define COMSIG_ACTION_REMOVED "action_removed" +/// From /datum/action/Remove(): (datum/action) +#define COMSIG_MOB_REMOVED_ACTION "mob_action_removed" // Note that this is only defined for actions because this could be a good bit expensive otherwise /// From base of /atom/movable/screen/movable/action_button/MouseWheel(src, delta_x, delta_y, location, control, params) #define COMSIG_ACTION_SCROLLED "action_scrolled" +// ghost signals + +/// from observer_base/do_observe(): (mob/now_followed) +#define COMSIG_GHOST_START_OBSERVING "ghost_start_observing" +/// from observer_base/do_observe(): (mob/no_longer_following) +#define COMSIG_GHOST_STOP_OBSERVING "ghost_stop_observing" + //Xenobio hotkeys ///from slime CtrlClickOn(): (/mob) diff --git a/code/__DEFINES/mecha_defines.dm b/code/__DEFINES/mecha_defines.dm index b414f146705..0d126314227 100644 --- a/code/__DEFINES/mecha_defines.dm +++ b/code/__DEFINES/mecha_defines.dm @@ -15,8 +15,8 @@ #define MECHA_SIDE_ARMOUR 2 #define MECHA_BACK_ARMOUR 3 -#define MECHA_LOCKED 0 -#define MECHA_SECURE_BOLTS 1 -#define MECHA_LOOSE_BOLTS 2 -#define MECHA_OPEN_HATCH 3 -#define MECHA_UNSECURE_CELL 4 +#define MECHA_MAINT_OFF 0 +#define MECHA_MAINT_ON 1 +#define MECHA_BOLTS_UP 2 +#define MECHA_OPEN_HATCH 3 +#define MECHA_BATTERY_UNSCREW 4 diff --git a/code/__DEFINES/misc_defines.dm b/code/__DEFINES/misc_defines.dm index e3fee8035c7..790c9f9ea66 100644 --- a/code/__DEFINES/misc_defines.dm +++ b/code/__DEFINES/misc_defines.dm @@ -400,6 +400,7 @@ #define INVESTIGATE_RENAME "renames" #define INVESTIGATE_BOMB "bombs" +#define INVESTIGATE_HOTMIC "hotmic" // The SQL version required by this version of the code #define SQL_VERSION 56 @@ -702,3 +703,7 @@ do { \ /// A helper used by `restrict_file_types.py` to identify types to restrict in a file. Not used by byond at all. #define RESTRICT_TYPE(type) // do nothing + +#define INGREDIENT_CHECK_EXACT 1 +#define INGREDIENT_CHECK_FAILURE 0 +#define INGREDIENT_CHECK_SURPLUS -1 diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 59da6920026..a907170b5e3 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -164,6 +164,8 @@ if(sight_check && !isInSight(A, O)) continue L |= M + for(var/mob/dead/observer/ghost in M.observers) + L |= ghost //log_world("[recursion_limit] = [M] - [get_turf(M)] - ([M.x], [M.y], [M.z])") if(isobj(A) || ismob(A)) diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index cd6d5d8820b..1f1af7032bd 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -676,6 +676,7 @@ #define UNSETEMPTY(L) if(L && !length(L)) L = null #define LAZYREMOVE(L, I) if(L) { L -= I; if(!length(L)) { L = null; } } #define LAZYADD(L, I) if(!L) { L = list(); } L += I; +/// Add an item to the list if not already present, if the list is null it will initialize it #define LAZYOR(L, I) if(!L) { L = list(); } L |= I; /// Adds I to L, initializing L if necessary, if I is not already in L #define LAZYDISTINCTADD(L, I) if(!L) { L = list(); } L |= I; diff --git a/code/__HELPERS/mob_helpers.dm b/code/__HELPERS/mob_helpers.dm index d4e50baa361..30c2693a643 100644 --- a/code/__HELPERS/mob_helpers.dm +++ b/code/__HELPERS/mob_helpers.dm @@ -554,7 +554,7 @@ GLOBAL_LIST_EMPTY(do_after_once_tracker) 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")]) ([ADMIN_OBS(M, "OBS")])") // 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/trait_helpers.dm b/code/__HELPERS/trait_helpers.dm index 3cb5928179a..112661491d7 100644 --- a/code/__HELPERS/trait_helpers.dm +++ b/code/__HELPERS/trait_helpers.dm @@ -233,6 +233,11 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_TABLE_LEAP "table_leap" // Lets bartender and chef mount tables faster #define TRAIT_NEVER_MISSES_DISPOSALS "trait_never_misses_disposals" // For janitors landing disposal throws #define TRAIT_SLEIGHT_OF_HAND "sleight_of_hand" +#define TRAIT_KNOWS_COOKING_RECIPES "knows_cooking_recipes" + +/// used for dead mobs that are observing, but should not be afforded all the same platitudes as full ghosts. +/// This is a mind trait because ghosts can be frequently deleted and we want to be sure this sticks. +#define TRAIT_MENTOR_OBSERVING "mentor_observe" //***** ITEM AND MOB TRAITS *****// /// Show what machine/door wires do when held. @@ -320,6 +325,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define HOLO_CIGAR "holo_cigar" #define GLADIATOR "gladiator" #define PULSEDEMON_TRAIT "pulse_demon" +/// Mentor observing +#define MENTOR_OBSERVING "mobserving" //quirk traits #define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance" diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 79d3208719c..ca7ef0c3adc 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -2082,3 +2082,18 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) /proc/is_color_dark(color, threshold = 25) var/hsl = rgb2num(color, COLORSPACE_HSL) return hsl[3] < threshold + +/** + * This proc takes a list of types, and returns them in the format below. + * [type] = amount of type in list. + * Useful for recipes. + */ +/proc/type_list_to_counted_assoc_list(list/origin_list) + var/list/return_list = list() + for(var/datum/path as anything in origin_list) + if(isdatum(path)) + path = path.type + if(!return_list[path]) + return_list[path] = 0 + return_list[path] += 1 + return return_list diff --git a/code/_globalvars/lists/reagents_lists.dm b/code/_globalvars/lists/reagents_lists.dm index 39540790b93..94388ef1c72 100644 --- a/code/_globalvars/lists/reagents_lists.dm +++ b/code/_globalvars/lists/reagents_lists.dm @@ -47,5 +47,5 @@ GLOBAL_LIST_INIT(blocked_chems, list("polonium", "initropidril", "concentrated_i "fungalspores", "jagged_crystals", "salmonella", "lavaland_extract", "stable_mutagen", "beer2", "curare", "gluttonytoxin", "smoke_powder", "stimulative_cling", - "teslium_paste" + "teslium_paste", "omnizine_no_addiction" )) diff --git a/code/_globalvars/traits.dm b/code/_globalvars/traits.dm index 2e1fc13f5db..3d3cf117030 100644 --- a/code/_globalvars/traits.dm +++ b/code/_globalvars/traits.dm @@ -81,7 +81,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NOSELFIGNITION_HEAD_ONLY" = TRAIT_NOSELFIGNITION_HEAD_ONLY, "TRAIT_CONTORTED_BODY" = TRAIT_CONTORTED_BODY, "TRAIT_DEFLECTS_PROJECTILES" = TRAIT_DEFLECTS_PROJECTILES, - "TRAIT_TABLE_LEAP" = TRAIT_TABLE_LEAP, "TRAIT_DODGE_ALL_THROWN_OBJECTS" = TRAIT_DODGE_ALL_OBJECTS, "TRAIT_SUPERMATTER_IMMUNE" = TRAIT_SUPERMATTER_IMMUNE, "TRAIT_BADASS" = TRAIT_BADASS, @@ -98,7 +97,8 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_HOLY" = TRAIT_HOLY, "TRAIT_SLEIGHT_OF_HAND" = TRAIT_SLEIGHT_OF_HAND, "TRAIT_TABLE_LEAP" = TRAIT_TABLE_LEAP, - "TRAIT_NEVER_MISSES_DISPOSALS" = TRAIT_NEVER_MISSES_DISPOSALS + "TRAIT_NEVER_MISSES_DISPOSALS" = TRAIT_NEVER_MISSES_DISPOSALS, + "TRAIT_KNOWS_COOKING_RECIPES" = TRAIT_KNOWS_COOKING_RECIPES ), /obj = list( diff --git a/code/_onclick/hud/action_button.dm b/code/_onclick/hud/action_button.dm index 205d4fe1dde..a8303d46fb8 100644 --- a/code/_onclick/hud/action_button.dm +++ b/code/_onclick/hud/action_button.dm @@ -16,6 +16,8 @@ var/id /// UID of the last thing we hovered over. Used for managing action button dragging. var/last_hovered_ref + /// Whether or not this should be shown to observers + var/shown_to_observers = FALSE /// Whether or not this button is locked, preventing it from being dragged. var/locked = FALSE @@ -32,8 +34,14 @@ return ..() /atom/movable/screen/movable/action_button/proc/can_use(mob/user) + if(isobserver(user)) + var/mob/dead/observer/dead_mob = user + if(dead_mob.mob_observed) // Observers can only click on action buttons if they're not observing something + return FALSE if(!linked_action) return TRUE + if(linked_action.owner != user) + return FALSE return !isnull(linked_action.viewers[user.hud_used]) // Entered and Exited won't fire while you're dragging something, because you're still "holding" it @@ -60,7 +68,8 @@ last_hovered.MouseExited(over_location, over_control, params) closeToolTip(usr) last_hovered_ref = UID(over_object) - over_object.MouseEntered(over_location, over_control, params) + if(!isnull(over_object)) + over_object.MouseEntered(over_location, over_control, params) /atom/movable/screen/movable/action_button/MouseDrop(over_object) last_hovered_ref = null @@ -113,6 +122,8 @@ animate(src, transform = matrix(), time = 0.4 SECONDS, alpha = 255) /atom/movable/screen/movable/action_button/Click(location, control, params) + if(!can_use(usr)) + return FALSE var/list/modifiers = params2list(params) if(modifiers["ctrl"] && modifiers["shift"]) INVOKE_ASYNC(src, PROC_REF(set_to_keybind), usr) @@ -578,4 +589,47 @@ GLOBAL_LIST_INIT(palette_removed_matrix, list(1.4,0,0,0, 0.7,0.4,0,0, 0.4,0,0.6, button = action.viewers[src] position_action(button, button.location) + +/** + * Show (most) of the another mob's action buttons to this mob + * + * Used for observers viewing another mob's screen + */ +/mob/proc/show_other_mob_action_buttons(mob/take_from) + if(!hud_used || !client) + return + + for(var/datum/action/action as anything in take_from.actions) + if(!action.show_to_observers) + continue + action.GiveAction(src) + RegisterSignal(take_from, COMSIG_MOB_GRANTED_ACTION, PROC_REF(on_observing_action_granted), override = TRUE) + RegisterSignal(take_from, COMSIG_MOB_REMOVED_ACTION, PROC_REF(on_observing_action_removed), override = TRUE) + +/** + * Hide another mob's action buttons from this mob + * + * Used for observers viewing another mob's screen + */ +/mob/proc/hide_other_mob_action_buttons(mob/take_from) + for(var/datum/action/action as anything in take_from.actions) + action.HideFrom(src) + UnregisterSignal(take_from, list(COMSIG_MOB_GRANTED_ACTION, COMSIG_MOB_REMOVED_ACTION)) + +/// Signal proc for [COMSIG_MOB_GRANTED_ACTION] - If we're viewing another mob's action buttons, +/// we need to update with any newly added buttons granted to the mob. +/mob/proc/on_observing_action_granted(mob/living/source, datum/action/action) + SIGNAL_HANDLER // COMSIG_MOB_GRANTED_ACTION + + if(!action.show_to_observers) + return + action.GiveAction(src) + +/// Signal proc for [COMSIG_MOB_REMOVED_ACTION] - If we're viewing another mob's action buttons, +/// we need to update with any removed buttons from the mob. +/mob/proc/on_observing_action_removed(mob/living/source, datum/action/action) + SIGNAL_HANDLER // COMSIG_MOB_REMOVED_ACTION + + action.HideFrom(src) + #undef AB_MAX_COLUMNS diff --git a/code/_onclick/hud/ai_hud.dm b/code/_onclick/hud/ai_hud.dm index d99b737cc1f..1f0cf58e237 100644 --- a/code/_onclick/hud/ai_hud.dm +++ b/code/_onclick/hud/ai_hud.dm @@ -1,20 +1,27 @@ /atom/movable/screen/ai icon = 'icons/mob/screen_ai.dmi' +/atom/movable/screen/ai/Click() + if(isobserver(usr) || usr.incapacitated()) + return TRUE + /atom/movable/screen/ai/aicore name = "AI core" icon_state = "ai_core" /atom/movable/screen/ai/aicore/Click() - if(isAI(usr)) - var/mob/living/silicon/ai/AI = usr - AI.view_core() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.view_core() /atom/movable/screen/ai/camera_list name = "Show Camera List" icon_state = "camera" /atom/movable/screen/ai/camera_list/Click() + if(..()) + return var/mob/living/silicon/ai/AI = usr var/camera = tgui_input_list(AI, "Choose which camera you want to view", "Cameras", AI.get_camera_list()) AI.ai_camera_list(camera) @@ -24,53 +31,60 @@ icon_state = "track" /atom/movable/screen/ai/camera_track/Click() - if(isAI(usr)) - var/mob/living/silicon/ai/AI = usr - var/target_name = tgui_input_list(AI, "Choose a target you want to track", "Tracking", AI.trackable_mobs()) - if(target_name) - AI.ai_camera_track(target_name) + if(..()) + return + var/mob/living/silicon/ai/AI = usr + var/target_name = tgui_input_list(AI, "Choose a target you want to track", "Tracking", AI.trackable_mobs()) + if(target_name) + AI.ai_camera_track(target_name) /atom/movable/screen/ai/camera_light name = "Toggle Camera Light" icon_state = "camera_light" /atom/movable/screen/ai/camera_light/Click() - if(isAI(usr)) - var/mob/living/silicon/ai/AI = usr - AI.toggle_camera_light() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.toggle_camera_light() /atom/movable/screen/ai/crew_monitor name = "Crew Monitoring Console" icon_state = "crew_monitor" /atom/movable/screen/ai/crew_monitor/Click() - if(isAI(usr)) - var/mob/living/silicon/ai/AI = usr - AI.subsystem_crew_monitor() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.subsystem_crew_monitor() /atom/movable/screen/ai/crew_manifest name = "Crew Manifest" icon_state = "manifest" /atom/movable/screen/ai/crew_manifest/Click() - if(isAI(usr)) - var/mob/living/silicon/ai/AI = usr - AI.ai_roster() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.ai_roster() /atom/movable/screen/ai/alerts name = "Show Alerts" icon_state = "alerts" /atom/movable/screen/ai/alerts/Click() - if(isAI(usr)) - var/mob/living/silicon/ai/AI = usr - AI.ai_alerts() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.ai_alerts() /atom/movable/screen/ai/announcement name = "Make Announcement" icon_state = "announcement" /atom/movable/screen/ai/announcement/Click() + if(..()) + return var/mob/living/silicon/ai/AI = usr AI.announcement() @@ -79,15 +93,18 @@ icon_state = "call_shuttle" /atom/movable/screen/ai/call_shuttle/Click() - if(isAI(usr)) - var/mob/living/silicon/ai/AI = usr - AI.ai_call_shuttle() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.ai_call_shuttle() /atom/movable/screen/ai/state_laws name = "Law Manager" icon_state = "state_laws" /atom/movable/screen/ai/state_laws/Click() + if(..()) + return if(isAI(usr)) var/mob/living/silicon/ai/AI = usr AI.subsystem_law_manager() @@ -97,42 +114,48 @@ icon_state = "pda_send" /atom/movable/screen/ai/pda_msg_send/Click() - if(isAI(usr)) - var/mob/living/silicon/ai/AI = usr - AI.aiPDA.cmd_send_pdamesg() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.aiPDA.cmd_send_pdamesg() /atom/movable/screen/ai/pda_msg_show name = "PDA - Show Message Log" icon_state = "pda_receive" /atom/movable/screen/ai/pda_msg_show/Click() - if(isAI(usr)) - var/mob/living/silicon/ai/AI = usr - AI.aiPDA.cmd_show_message_log() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.aiPDA.cmd_show_message_log() /atom/movable/screen/ai/image_take name = "Take Image" icon_state = "take_picture" /atom/movable/screen/ai/image_take/Click() - if(isAI(usr)) - var/mob/living/silicon/ai/AI = usr - AI.aiCamera.toggle_camera_mode() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.aiCamera.toggle_camera_mode() /atom/movable/screen/ai/image_view name = "View Images" icon_state = "view_images" /atom/movable/screen/ai/image_view/Click() - if(isAI(usr)) - var/mob/living/silicon/ai/AI = usr - AI.aiCamera.viewpictures() + if(..()) + return + var/mob/living/silicon/ai/AI = usr + AI.aiCamera.viewpictures() /atom/movable/screen/ai/sensors name = "Toggle Sensor Augmentation" icon_state = "ai_sensor" /atom/movable/screen/ai/sensors/Click() + if(..()) + return if(isAI(usr)) var/mob/living/silicon/ai/AI = usr AI.sensor_mode() diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 8af3de91da0..80abb2b6f26 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -48,6 +48,8 @@ if(override) alert.timeout = null + alert.attach_owner(src) + if(icon_override) alert.icon = icon_override @@ -100,10 +102,50 @@ name = "Alert" desc = "Something seems to have gone wrong with this alert, so report this bug please" mouse_opacity = MOUSE_OPACITY_ICON - var/timeout = 0 //If set to a number, this alert will clear itself after that many deciseconds + /// How long before this alert automatically clears itself (in deciseconds). If zero, remains until cleared. + var/timeout = 0 + /// Some alerts may have different icon states based on severity, this adjusts that. var/severity = 0 + /// Tool-tip for the alert. var/alerttooltipstyle = "" - var/override_alerts = FALSE //If it is overriding other alerts of the same type + /// If true, this should override any other alerts of the same type thrown. + var/override_alerts = FALSE + /// The mob that this alert was originally thrown to. + var/mob/owner + +/atom/movable/screen/alert/proc/attach_owner(mob/new_owner) + owner = new_owner + RegisterSignal(owner, COMSIG_PARENT_QDELETING, PROC_REF(remove_owner)) + +/atom/movable/screen/alert/proc/remove_owner(mob/source, force) + SIGNAL_HANDLER // COMSIG_PARENT_QDELETING + if(owner == source && !isnull(owner)) + UnregisterSignal(owner, COMSIG_PARENT_QDELETING) + owner = null + +/atom/movable/screen/alert/Destroy() + if(owner) + UnregisterSignal(owner, COMSIG_PARENT_QDELETING) + owner = null + severity = 0 + master = null + screen_loc = "" + return ..() + +/atom/movable/screen/alert/Click(location, control, params) + ..() + if(!usr || !usr.client) + return FALSE + if(usr != owner) + to_chat(usr, "Only [owner] can use that!") + return FALSE + var/paramslist = params2list(params) + if(paramslist["shift"]) // screen objects don't do the normal Click() stuff so we'll cheat + to_chat(usr, "[name] - [desc]") + return FALSE + if(master) + usr.client.Click(master, location, control, params) + return TRUE /atom/movable/screen/alert/MouseEntered(location, control, params) . = ..() @@ -310,7 +352,7 @@ or something covering your eyes." icon_state = "embeddedobject" /atom/movable/screen/alert/embeddedobject/Click() - if(isliving(usr)) + if(isliving(usr) && ..()) var/mob/living/carbon/human/M = usr return M.help_shake_act(M) @@ -333,7 +375,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." icon_state = "fire" /atom/movable/screen/alert/fire/Click() - if(isliving(usr)) + if(isliving(usr) && ..()) var/mob/living/L = usr return L.resist() @@ -343,7 +385,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." icon_state = "direction_lock" /atom/movable/screen/alert/direction_lock/Click() - if(isliving(usr)) + if(isliving(usr) && ..()) var/mob/living/L = usr return L.clear_forced_look() @@ -406,7 +448,7 @@ Recharging stations are available in robotics, the dormitory bathrooms, and the desc = "You have merged with a diona gestalt and are now part of it's biomass. You can still wiggle yourself free though." /atom/movable/screen/alert/nymph/Click() - if(!usr || !usr.client) + if(!..()) return if(isnymph(usr)) var/mob/living/simple_animal/diona/D = usr @@ -417,7 +459,7 @@ Recharging stations are available in robotics, the dormitory bathrooms, and the desc = "You have merged with one or more diona nymphs. Click here to drop it (or one of them)." /atom/movable/screen/alert/gestalt/Click() - if(!usr || !usr.client) + if(!..()) return var/list/nymphs = list() @@ -465,7 +507,7 @@ so as to remain in compliance with the most up-to-date laws." return ..() /atom/movable/screen/alert/hackingapc/Click() - if(!usr || !usr.client) + if(!..()) return if(!target) return @@ -491,7 +533,7 @@ so as to remain in compliance with the most up-to-date laws." return ..() /atom/movable/screen/alert/mech_port_available/Click() - if(!usr || !usr.client) + if(!..()) return if(!ismecha(usr.loc) || !target) return @@ -507,7 +549,7 @@ so as to remain in compliance with the most up-to-date laws." icon_state = "mech_port_x" /atom/movable/screen/alert/mech_port_disconnect/Click() - if(!usr || !usr.client) + if(!..()) return if(!ismecha(usr.loc)) return @@ -566,7 +608,7 @@ so as to remain in compliance with the most up-to-date laws." timeout = 300 /atom/movable/screen/alert/notify_cloning/Click() - if(!usr || !usr.client) + if(!..()) return var/mob/dead/observer/G = usr G.reenter_corpse() @@ -585,6 +627,8 @@ so as to remain in compliance with the most up-to-date laws." overlays += I /atom/movable/screen/alert/ghost/Click() + if(!..()) + return var/mob/living/carbon/human/infected_user = usr if(!istype(infected_user) || infected_user.stat == DEAD) infected_user.clear_alert("ghost_nest") @@ -640,7 +684,7 @@ so as to remain in compliance with the most up-to-date laws." return ..() /atom/movable/screen/alert/notify_action/Click() - if(!usr || !usr.client) + if(!..()) return var/mob/dead/observer/G = usr @@ -721,7 +765,7 @@ so as to remain in compliance with the most up-to-date laws." var/stoner = null /atom/movable/screen/alert/notify_soulstone/Click() - if(!usr || !usr.client) + if(!..()) return if(stone) if(tgui_alert(usr, "Do you want to be captured by [stoner]'s soul stone? This will destroy your corpse and make it \ @@ -738,6 +782,7 @@ so as to remain in compliance with the most up-to-date laws." icon_state = "map_vote" /atom/movable/screen/alert/notify_mapvote/Click() + // ehh sure let observers click on it if they really want, who cares usr.client.vote() //OBJECT-BASED @@ -756,11 +801,14 @@ so as to remain in compliance with the most up-to-date laws." desc = "You're legcuffed, which slows you down considerably. Click the alert to free yourself." /atom/movable/screen/alert/restrained/Click() - if(isliving(usr)) - var/mob/living/L = usr - return L.resist() + if(!isliving(usr) || !..()) + return + var/mob/living/L = usr + return L.resist() /atom/movable/screen/alert/restrained/buckled/Click() + if(!isliving(usr) || !..()) + return var/mob/living/L = usr if(!istype(L) || !L.can_resist()) return @@ -770,20 +818,23 @@ so as to remain in compliance with the most up-to-date laws." // PRIVATE = only edit, use, or override these if you're editing the system as a whole // Re-render all alerts - also called in /datum/hud/show_hud() because it's needed there -/datum/hud/proc/reorganize_alerts() +/datum/hud/proc/reorganize_alerts(mob/viewmob) + var/mob/screenmob = viewmob || mymob + if(!screenmob.client) + return var/list/alerts = mymob.alerts if(!alerts) return FALSE var/icon_pref if(!hud_shown) for(var/i in 1 to length(alerts)) - mymob.client.screen -= alerts[alerts[i]] + screenmob.client.screen -= alerts[alerts[i]] return TRUE for(var/i in 1 to length(alerts)) var/atom/movable/screen/alert/alert = alerts[alerts[i]] if(alert.icon_state == "template") if(!icon_pref) - icon_pref = ui_style2icon(mymob.client.prefs.UI_style) + icon_pref = ui_style2icon(screenmob.client.prefs.UI_style) alert.icon = icon_pref switch(i) if(1) @@ -799,24 +850,12 @@ so as to remain in compliance with the most up-to-date laws." else . = "" alert.screen_loc = . - mymob.client.screen |= alert + screenmob.client.screen |= alert + if(!viewmob) + for(var/viewer in mymob.observers) + reorganize_alerts(viewer) return TRUE -/atom/movable/screen/alert/Click(location, control, params) - if(!usr || !usr.client) - return - var/paramslist = params2list(params) - if(paramslist["shift"]) // screen objects don't do the normal Click() stuff so we'll cheat - to_chat(usr, "[name] - [desc]") - return - if(master) - return usr.client.Click(master, location, control, params) - -/atom/movable/screen/alert/Destroy() - severity = 0 - master = null - screen_loc = "" - return ..() /// Gives the player the option to succumb while in critical condition /atom/movable/screen/alert/succumb @@ -825,7 +864,7 @@ so as to remain in compliance with the most up-to-date laws." icon_state = "succumb" /atom/movable/screen/alert/succumb/Click() - if(!usr || !usr.client) + if(!..()) return var/mob/living/living_owner = usr if(!istype(usr)) diff --git a/code/_onclick/hud/alien_hud.dm b/code/_onclick/hud/alien_hud.dm index eff377796e0..ad4e8d2a05c 100644 --- a/code/_onclick/hud/alien_hud.dm +++ b/code/_onclick/hud/alien_hud.dm @@ -146,19 +146,22 @@ inv_slots[inv.slot_id] = inv inv.update_icon() -/datum/hud/alien/persistent_inventory_update() +/datum/hud/alien/persistent_inventory_update(mob/viewer) if(!mymob) return var/mob/living/carbon/alien/humanoid/H = mymob + var/mob/screenmob = viewer || H if(hud_version != HUD_STYLE_NOHUD) if(H.r_hand) H.r_hand.screen_loc = ui_rhand - H.client.screen += H.r_hand + screenmob.client.screen += H.r_hand if(H.l_hand) H.l_hand.screen_loc = ui_lhand - H.client.screen += H.l_hand + screenmob.client.screen += H.l_hand else if(H.r_hand) H.r_hand.screen_loc = null + screenmob.client.screen -= H.r_hand if(H.l_hand) H.l_hand.screen_loc = null + screenmob.client.screen -= H.l_hand diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm index afc30ca3422..b085669097b 100644 --- a/code/_onclick/hud/fullscreen.dm +++ b/code/_onclick/hud/fullscreen.dm @@ -49,16 +49,17 @@ for(var/category in screens) clear_fullscreen(category) -/datum/hud/proc/reload_fullscreen() - if(mymob.client) - var/atom/movable/screen/fullscreen/screen - var/list/screens = mymob.screens - for(var/category in screens) - screen = screens[category] - if(screen.should_show_to(mymob)) - mymob.client.screen |= screen - continue - mymob.client.screen -= screen +/mob/proc/reload_fullscreen() + if(!client) + return + var/atom/movable/screen/fullscreen/screen + for(var/category in screens) + screen = screens[category] + if(screen.should_show_to(src)) + screen.update_for_view(client.view) + client.screen |= screen + else + client.screen -= screen /atom/movable/screen/fullscreen icon = 'icons/mob/screen_full.dmi' diff --git a/code/_onclick/hud/ghost_hud.dm b/code/_onclick/hud/ghost_hud.dm index f7994d9aa45..40c957b26c9 100644 --- a/code/_onclick/hud/ghost_hud.dm +++ b/code/_onclick/hud/ghost_hud.dm @@ -110,7 +110,24 @@ for(var/atom/movable/screen/S in (static_inventory + toggleable_inventory)) S.hud = src -/datum/hud/ghost/show_hud() - mymob.client.screen = list() - mymob.client.screen += static_inventory - ..() +/datum/hud/ghost/show_hud(version = 0, mob/viewmob) + // don't show this HUD if observing; show the HUD of the observee + var/mob/dead/observer/O = mymob + if(istype(O) && O.mob_observed) + plane_masters_update() + return FALSE + + . = ..() + if(!.) + return + var/mob/screenmob = viewmob || mymob + screenmob.client.screen += static_inventory + + +// We should only see observed mob alerts. +/datum/hud/ghost/reorganize_alerts(mob/viewmob) + var/mob/dead/observer/O = mymob + if(istype(O) && O.mob_observed) + return + return ..() + diff --git a/code/_onclick/hud/hud_datum.dm b/code/_onclick/hud/hud_datum.dm index 566e07c7bb9..4f11604ade2 100644 --- a/code/_onclick/hud/hud_datum.dm +++ b/code/_onclick/hud/hud_datum.dm @@ -11,7 +11,7 @@ var/hud_shown = TRUE /// Current displayed version of the HUD var/hud_version = 1 - /// Whether or not their toggleable inventory + /// Whether or not their toggleable inventory (generally their contents on the left) is expanded var/inventory_shown = TRUE /// This is to hide the buttons that can be used via hotkeys. (hotkeybuttons list of buttons) var/hotkey_ui_hidden = FALSE @@ -147,14 +147,22 @@ QDEL_NULL(screentip_text) return ..() -/datum/hud/proc/show_hud(version = 0) +/** + * Shows this hud's hud to some mob + * + * Arguments + * * version - denotes which style should be displayed. blank or 0 means "next version" + * * viewmob - what mob to show the hud to. Can be this hud's mob, can be another mob, can be null (will use this hud's mob if so) + */ +/datum/hud/proc/show_hud(version = 0, mob/viewmob) if(!ismob(mymob)) return FALSE - - if(!mymob.client) + var/mob/screenmob = viewmob || mymob + if(!screenmob.client) return FALSE - mymob.client.screen = list() + screenmob.client.clear_screen() + screenmob.client.apply_clickcatcher() var/display_hud_version = version if(!display_hud_version) //If 0 or blank, display the next hud version @@ -166,15 +174,15 @@ if(HUD_STYLE_STANDARD) //Default HUD hud_shown = TRUE //Governs behavior of other procs if(length(static_inventory)) - mymob.client.screen += static_inventory - if(length(toggleable_inventory) && inventory_shown) - mymob.client.screen += toggleable_inventory - if(length(hotkeybuttons) && !hotkey_ui_hidden) - mymob.client.screen += hotkeybuttons + screenmob.client.screen += static_inventory + if(length(toggleable_inventory) && screenmob.hud_used?.inventory_shown) + screenmob.client.screen += toggleable_inventory + if(length(hotkeybuttons) && !screenmob.hud_used?.hotkey_ui_hidden) + screenmob.client.screen += hotkeybuttons if(length(infodisplay)) - mymob.client.screen += infodisplay + screenmob.client.screen += infodisplay - mymob.client.screen += toggle_palette + screenmob.client.screen += toggle_palette if(action_intent) action_intent.screen_loc = initial(action_intent.screen_loc) //Restore intent selection to the original position @@ -182,33 +190,33 @@ if(HUD_STYLE_REDUCED) //Reduced HUD hud_shown = FALSE //Governs behavior of other procs if(length(static_inventory)) - mymob.client.screen -= static_inventory + screenmob.client.screen -= static_inventory if(length(toggleable_inventory)) - mymob.client.screen -= toggleable_inventory + screenmob.client.screen -= toggleable_inventory if(length(hotkeybuttons)) - mymob.client.screen -= hotkeybuttons + screenmob.client.screen -= hotkeybuttons if(length(infodisplay)) - mymob.client.screen += infodisplay + screenmob.client.screen += infodisplay //These ones are a part of 'static_inventory', 'toggleable_inventory' or 'hotkeybuttons' but we want them to stay if(inv_slots[SLOT_HUD_LEFT_HAND]) - mymob.client.screen += inv_slots[SLOT_HUD_LEFT_HAND] //we want the hands to be visible + screenmob.client.screen += inv_slots[SLOT_HUD_LEFT_HAND] //we want the hands to be visible if(inv_slots[SLOT_HUD_RIGHT_HAND]) - mymob.client.screen += inv_slots[SLOT_HUD_RIGHT_HAND] //we want the hands to be visible + screenmob.client.screen += inv_slots[SLOT_HUD_RIGHT_HAND] //we want the hands to be visible if(action_intent) - mymob.client.screen += action_intent //we want the intent switcher visible + screenmob.client.screen += action_intent //we want the intent switcher visible action_intent.screen_loc = ui_acti_alt //move this to the alternative position, where zone_select usually is. if(HUD_STYLE_NOHUD) //No HUD hud_shown = FALSE //Governs behavior of other procs if(length(static_inventory)) - mymob.client.screen -= static_inventory + screenmob.client.screen -= static_inventory if(length(toggleable_inventory)) - mymob.client.screen -= toggleable_inventory + screenmob.client.screen -= toggleable_inventory if(length(hotkeybuttons)) - mymob.client.screen -= hotkeybuttons + screenmob.client.screen -= hotkeybuttons if(length(infodisplay)) - mymob.client.screen -= infodisplay + screenmob.client.screen -= infodisplay if(HUD_STYLE_ACTIONHUD) //No HUD hud_shown = TRUE //Governs behavior of other procs @@ -220,36 +228,46 @@ mymob.client.screen -= infodisplay hud_version = display_hud_version - persistent_inventory_update() - mymob.update_action_buttons(1) - reorganize_alerts() - reload_fullscreen() - update_parallax_pref(mymob) + persistent_inventory_update(screenmob) + screenmob.update_action_buttons(TRUE) + reorganize_alerts(screenmob) + screenmob.reload_fullscreen() + update_parallax_pref(screenmob) + if(!viewmob) + // working off of mymob + plane_masters_update() + for(var/M in mymob.observers) + show_hud(hud_version, M) + else if(viewmob.hud_used) + viewmob.hud_used.plane_masters_update() + viewmob.show_other_mob_action_buttons(mymob) plane_masters_update() + return TRUE /datum/hud/proc/plane_masters_update() // Plane masters are always shown to OUR mob, never to observers for(var/thing in plane_masters) var/atom/movable/screen/plane_master/PM = plane_masters[thing] PM.backdrop(mymob) - mymob.client.screen += PM + mymob.client?.screen += PM -/datum/hud/human/show_hud(version = 0) +/datum/hud/human/show_hud(version = 0, mob/viewmob) . = ..() if(!.) return - hidden_inventory_update() + var/mob/screenmob = viewmob || mymob + hidden_inventory_update(screenmob) -/datum/hud/robot/show_hud(version = 0) +/datum/hud/robot/show_hud(version = 0, mob/viewmob) . = ..() if(!.) return - update_robot_modules_display() + update_robot_modules_display(viewmob) -/datum/hud/proc/hidden_inventory_update() +/datum/hud/proc/hidden_inventory_update(mob/viewer) return -/datum/hud/proc/persistent_inventory_update() +/datum/hud/proc/persistent_inventory_update(mob/viewer) return /mob/proc/hide_hud() diff --git a/code/_onclick/hud/human_hud.dm b/code/_onclick/hud/human_hud.dm index 68eb065069f..94c08989d00 100644 --- a/code/_onclick/hud/human_hud.dm +++ b/code/_onclick/hud/human_hud.dm @@ -6,14 +6,22 @@ icon_state = "toggle" /atom/movable/screen/human/toggle/Click() - if(usr.hud_used.inventory_shown) + + var/mob/targetmob = usr + + if(isobserver(usr)) + if(ishuman(usr.client.eye) && (usr.client.eye != usr)) + var/mob/M = usr.client.eye + targetmob = M + + if(usr.hud_used.inventory_shown && targetmob.hud_used) usr.hud_used.inventory_shown = FALSE - usr.client.screen -= usr.hud_used.toggleable_inventory + usr.client.screen -= targetmob.hud_used.toggleable_inventory else usr.hud_used.inventory_shown = TRUE - usr.client.screen += usr.hud_used.toggleable_inventory + usr.client.screen += targetmob.hud_used.toggleable_inventory - usr.hud_used.hidden_inventory_update() + targetmob.hud_used.hidden_inventory_update(usr) /atom/movable/screen/human/equip name = "equip" @@ -21,7 +29,7 @@ /atom/movable/screen/human/equip/Click() if(ismecha(usr.loc)) // stops inventory actions in a mech - return 1 + return TRUE var/mob/living/carbon/human/H = usr H.quick_equip() @@ -33,6 +41,8 @@ screen_loc = ui_lingstingdisplay /atom/movable/screen/ling/sting/Click() + if(isobserver(usr)) + return var/datum/antagonist/changeling/cling = usr.mind.has_antag_datum(/datum/antagonist/changeling) cling?.chosen_sting?.unset_sting() @@ -389,100 +399,118 @@ else crafting.invisibility = initial(crafting.invisibility) -/datum/hud/human/hidden_inventory_update() +/datum/hud/human/hidden_inventory_update(mob/viewer) if(!mymob) return var/mob/living/carbon/human/H = mymob - if(inventory_shown && hud_version == HUD_STYLE_STANDARD) + + var/mob/screenmob = viewer || H + if(screenmob.hud_used.inventory_shown && screenmob.hud_used.hud_shown && screenmob.hud_used.hud_version == HUD_STYLE_STANDARD) + if(H.shoes) H.shoes.screen_loc = ui_shoes - H.client.screen += H.shoes + screenmob.client.screen += H.shoes if(H.gloves) H.gloves.screen_loc = ui_gloves - H.client.screen += H.gloves + screenmob.client.screen += H.gloves if(H.l_ear) H.l_ear.screen_loc = ui_l_ear - H.client.screen += H.l_ear + screenmob.client.screen += H.l_ear if(H.r_ear) H.r_ear.screen_loc = ui_r_ear - H.client.screen += H.r_ear + screenmob.client.screen += H.r_ear if(H.glasses) H.glasses.screen_loc = ui_glasses - H.client.screen += H.glasses + screenmob.client.screen += H.glasses if(H.w_uniform) H.w_uniform.screen_loc = ui_iclothing - H.client.screen += H.w_uniform + screenmob.client.screen += H.w_uniform if(H.wear_suit) H.wear_suit.screen_loc = ui_oclothing - H.client.screen += H.wear_suit + screenmob.client.screen += H.wear_suit if(H.wear_mask) H.wear_mask.screen_loc = ui_mask - H.client.screen += H.wear_mask + screenmob.client.screen += H.wear_mask if(H.head) H.head.screen_loc = ui_head - H.client.screen += H.head + screenmob.client.screen += H.head else - if(H.shoes) H.shoes.screen_loc = null - if(H.gloves) H.gloves.screen_loc = null - if(H.l_ear) H.l_ear.screen_loc = null - if(H.r_ear) H.r_ear.screen_loc = null - if(H.glasses) H.glasses.screen_loc = null - if(H.w_uniform) H.w_uniform.screen_loc = null - if(H.wear_suit) H.wear_suit.screen_loc = null - if(H.wear_mask) H.wear_mask.screen_loc = null - if(H.head) H.head.screen_loc = null + if(H.shoes) + screenmob.client.screen -= H.shoes + if(H.gloves) + screenmob.client.screen -= H.gloves + if(H.l_ear) + screenmob.client.screen -= H.l_ear + if(H.r_ear) + screenmob.client.screen -= H.r_ear + if(H.glasses) + screenmob.client.screen -= H.glasses + if(H.w_uniform) + screenmob.client.screen -= H.w_uniform + if(H.wear_suit) + screenmob.client.screen -= H.wear_suit + if(H.wear_mask) + screenmob.client.screen -= H.wear_mask + if(H.head) + screenmob.client.screen -= H.head -/datum/hud/human/persistent_inventory_update() +/datum/hud/human/persistent_inventory_update(mob/viewer) if(!mymob) return + ..() var/mob/living/carbon/human/H = mymob - if(hud_version == HUD_STYLE_STANDARD) - if(H.s_store) - H.s_store.screen_loc = ui_sstore1 - H.client.screen += H.s_store - if(H.wear_id) - H.wear_id.screen_loc = ui_id - H.client.screen += H.wear_id - if(H.wear_pda) - H.wear_pda.screen_loc = ui_pda - H.client.screen += H.wear_pda - if(H.belt) - H.belt.screen_loc = ui_belt - H.client.screen += H.belt - if(H.back) - H.back.screen_loc = ui_back - H.client.screen += H.back - if(H.l_store) - H.l_store.screen_loc = ui_storage1 - H.client.screen += H.l_store - if(H.r_store) - H.r_store.screen_loc = ui_storage2 - H.client.screen += H.r_store - else - if(H.s_store) - H.s_store.screen_loc = null - if(H.wear_id) - H.wear_id.screen_loc = null - if(H.wear_pda) - H.wear_pda.screen_loc = null - if(H.belt) - H.belt.screen_loc = null - if(H.back) - H.back.screen_loc = null - if(H.l_store) - H.l_store.screen_loc = null - if(H.r_store) - H.r_store.screen_loc = null + var/mob/screenmob = viewer || H + + if(screenmob.hud_used) + if(screenmob.hud_used.hud_shown && screenmob.hud_used.hud_version == HUD_STYLE_STANDARD) + if(H.s_store) + H.s_store.screen_loc = ui_sstore1 + screenmob.client.screen += H.s_store + if(H.wear_id) + H.wear_id.screen_loc = ui_id + screenmob.client.screen += H.wear_id + if(H.wear_pda) + H.wear_pda.screen_loc = ui_pda + screenmob.client.screen += H.wear_pda + if(H.belt) + H.belt.screen_loc = ui_belt + screenmob.client.screen += H.belt + if(H.back) + H.back.screen_loc = ui_back + screenmob.client.screen += H.back + if(H.l_store) + H.l_store.screen_loc = ui_storage1 + screenmob.client.screen += H.l_store + if(H.r_store) + H.r_store.screen_loc = ui_storage2 + screenmob.client.screen += H.r_store + else + if(H.s_store) + screenmob.client.screen -= H.s_store + if(H.wear_id) + screenmob.client.screen -= H.wear_id + if(H.wear_pda) + screenmob.client.screen -= H.wear_pda + if(H.belt) + screenmob.client.screen -= H.belt + if(H.back) + screenmob.client.screen -= H.back + if(H.l_store) + screenmob.client.screen -= H.l_store + if(H.r_store) + screenmob.client.screen -= H.r_store if(hud_version != HUD_STYLE_NOHUD) if(H.r_hand) H.r_hand.screen_loc = ui_rhand - H.client.screen += H.r_hand + screenmob.client.screen += H.r_hand if(H.l_hand) H.l_hand.screen_loc = ui_lhand - H.client.screen += H.l_hand + screenmob.client.screen += H.l_hand else if(H.r_hand) - H.r_hand.screen_loc = null + screenmob.r_hand.screen_loc = null + screenmob.client.screen -= H.r_hand if(H.l_hand) - H.l_hand.screen_loc = null + screenmob.l_hand.screen_loc = null + screenmob.client.screen -= H.l_hand diff --git a/code/_onclick/hud/parallax.dm b/code/_onclick/hud/parallax.dm index 2dca02b6e6d..aec2360eded 100644 --- a/code/_onclick/hud/parallax.dm +++ b/code/_onclick/hud/parallax.dm @@ -1,6 +1,9 @@ -/datum/hud/proc/create_parallax() - var/client/C = mymob.client - if(!apply_parallax_pref()) +/datum/hud/proc/create_parallax(mob/viewmob) + var/mob/screenmob = viewmob || mymob + if(!screenmob.client) + return + var/client/C = screenmob.client + if(!apply_parallax_pref(screenmob)) return // this is needed so it blends properly with the space plane and blackness plane. var/atom/movable/screen/plane_master/space/S = plane_masters["[PLANE_SPACE]"] @@ -34,16 +37,20 @@ C.screen |= (C.parallax_layers + C.parallax_static_layers_tail) -/datum/hud/proc/remove_parallax() - var/client/C = mymob.client +/datum/hud/proc/remove_parallax(mob/viewmob) + var/mob/screenmob = viewmob || mymob + var/client/C = screenmob.client C.screen -= (C.parallax_layers_cached + C.parallax_static_layers_tail) C.parallax_layers = null var/atom/movable/screen/plane_master/space/S = plane_masters["[PLANE_SPACE]"] S.color = null S.appearance_flags &= ~NO_CLIENT_COLOR -/datum/hud/proc/apply_parallax_pref() - var/client/C = mymob.client +/datum/hud/proc/apply_parallax_pref(mob/viewmob) + var/mob/screen_mob = viewmob || mymob + var/client/C = screen_mob.client + if(!istype(C)) + return FALSE if(C.prefs) var/pref = C.prefs.parallax if(isnull(pref)) @@ -72,16 +79,22 @@ C.parallax_layers_max = 4 return TRUE -/datum/hud/proc/update_parallax_pref() - remove_parallax() - create_parallax() - update_parallax() +/datum/hud/proc/update_parallax_pref(mob/viewmob) + var/mob/screen_mob = viewmob || mymob + if(!screen_mob.client) + return + remove_parallax(screen_mob) + create_parallax(screen_mob) + update_parallax(screen_mob) // This sets which way the current shuttle is moving (returns true if the shuttle has stopped moving so the caller can append their animation) // Well, it would if our shuttle code had dynamic areas -/datum/hud/proc/set_parallax_movedir(new_parallax_movedir, skip_windups) +/datum/hud/proc/set_parallax_movedir(mob/viewmob, new_parallax_movedir, skip_windups) . = FALSE - var/client/C = mymob.client + var/mob/screen_mob = viewmob || mymob + var/client/C = screen_mob.client + if(!istype(C)) + return if(new_parallax_movedir == C.parallax_movedir) return var/animatedir = new_parallax_movedir @@ -157,8 +170,9 @@ animate(L, transform = L.transform, time = 0, loop = -1, flags = ANIMATION_END_NOW) animate(transform = matrix(), time = T) -/datum/hud/proc/update_parallax() - var/client/C = mymob.client +/datum/hud/proc/update_parallax(mob/viewmob) + var/mob/screenmob = viewmob || mymob + var/client/C = screenmob.client var/turf/posobj = get_turf(C.eye) if(!posobj) return @@ -167,9 +181,9 @@ // Update the movement direction of the parallax if necessary (for shuttles) var/area/shuttle/SA = areaobj if(!SA || !SA.moving) - set_parallax_movedir(0) + set_parallax_movedir(screenmob, 0) else - set_parallax_movedir(SA.parallax_move_direction) + set_parallax_movedir(screenmob, SA.parallax_move_direction) var/force if(!C.previous_turf || (C.previous_turf.z != posobj.z)) @@ -193,7 +207,7 @@ for(var/thing in C.parallax_layers) var/atom/movable/screen/parallax_layer/L = thing - L.update_status(mymob) + L.update_status(screenmob) if(L.view_sized != C.view) L.update_o(C.view) diff --git a/code/_onclick/hud/robot_hud.dm b/code/_onclick/hud/robot_hud.dm index 30fae75f816..60310611b71 100644 --- a/code/_onclick/hud/robot_hud.dm +++ b/code/_onclick/hud/robot_hud.dm @@ -1,23 +1,34 @@ /atom/movable/screen/robot icon = 'icons/mob/screen_robot.dmi' +/atom/movable/screen/robot/Click() + . = ..() + if(isobserver(usr)) + return TRUE + /atom/movable/screen/robot/module name = "cyborg module" icon_state = "nomod" /atom/movable/screen/robot/module/Click() - if(isrobot(usr)) + if(isrobot(usr) && !..()) var/mob/living/silicon/robot/R = usr - if(R.module) - R.hud_used.toggle_show_robot_modules() - return 1 - R.pick_module() + if(!R.module) + R.pick_module() + return + + // we can let ghosts mess with this one + usr.hud_used.toggle_show_robot_modules(usr) + return TRUE + /atom/movable/screen/robot/module1 name = "module1" icon_state = "inv1" /atom/movable/screen/robot/module1/Click() + if(..()) + return if(isrobot(usr)) var/mob/living/silicon/robot/R = usr R.toggle_module(1) @@ -27,6 +38,8 @@ icon_state = "inv2" /atom/movable/screen/robot/module2/Click() + if(..()) + return if(isrobot(usr)) var/mob/living/silicon/robot/R = usr R.toggle_module(2) @@ -36,6 +49,8 @@ icon_state = "inv3" /atom/movable/screen/robot/module3/Click() + if(..()) + return if(isrobot(usr)) var/mob/living/silicon/robot/R = usr R.toggle_module(3) @@ -46,6 +61,8 @@ icon_state = "radio" /atom/movable/screen/robot/radio/Click() + if(..()) + return if(issilicon(usr)) var/mob/living/silicon/robot/R = usr R.radio_menu() @@ -55,6 +72,8 @@ icon_state = "store" /atom/movable/screen/robot/store/Click() + if(..()) + return if(isrobot(usr)) var/mob/living/silicon/robot/R = usr R.uneq_active() @@ -66,6 +85,8 @@ screen_loc = ui_borg_lamp /atom/movable/screen/robot/lamp/Click() + if(..()) + return if(isrobot(usr)) var/mob/living/silicon/robot/R = usr R.control_headlamp() @@ -75,6 +96,8 @@ icon_state = "ionpulse0" /atom/movable/screen/robot/thrusters/Click() + if(..()) + return var/mob/living/silicon/robot/R = usr R.toggle_ionpulse() @@ -83,11 +106,23 @@ icon_state = "running" /atom/movable/screen/robot/mov_intent/Click() + if(..()) + return usr.toggle_move_intent() +/datum/hud/robot + var/shown_robot_modules = FALSE // Used to determine whether they have the module menu shown or not + var/atom/movable/screen/robot_modules_background + /datum/hud/robot/New(mob/user) ..() + + robot_modules_background = new() + robot_modules_background.icon_state = "block" + robot_modules_background.layer = HUD_LAYER // Objects that appear on screen are on layer 20, UI should be just below it. + robot_modules_background.plane = HUD_PLANE + var/atom/movable/screen/using var/mob/living/silicon/robot/mymobR = mymob @@ -184,41 +219,51 @@ return ..() -/datum/hud/proc/toggle_show_robot_modules() +/datum/hud/proc/toggle_show_robot_modules(mob/viewmob) + return + +/datum/hud/robot/toggle_show_robot_modules(mob/viewmob) + var/mob/screenmob = viewmob || mymob + if(istype(viewmob.hud_used, /datum/hud/robot)) + var/datum/hud/robot/robohud = screenmob.hud_used + robohud.shown_robot_modules = !robohud.shown_robot_modules + + update_robot_modules_display(viewmob) + +/datum/hud/proc/update_robot_modules_display(mob/viewer) + return + +/datum/hud/robot/update_robot_modules_display(mob/viewer) if(!isrobot(mymob)) return var/mob/living/silicon/robot/R = mymob - R.shown_robot_modules = !R.shown_robot_modules - update_robot_modules_display() - -/datum/hud/proc/update_robot_modules_display() - if(!isrobot(mymob)) - return - - var/mob/living/silicon/robot/R = mymob + var/mob/screenmob = viewer || R if(!R.client) return if(!R.module) + shown_robot_modules = FALSE + screenmob.client.screen -= robot_modules_background + screenmob.client?.screen -= screenmob.hud_used.module_store_icon return - if(R.shown_robot_modules && hud_version == HUD_STYLE_STANDARD) + if(shown_robot_modules && hud_shown && hud_version == HUD_STYLE_STANDARD) //Modules display is shown - R.client.screen += module_store_icon //"store" icon + screenmob.client.screen += module_store_icon //"store" icon if(!R.module.modules) to_chat(usr, "Selected module has no modules to select.") return - if(!R.robot_modules_background) + if(!robot_modules_background) return var/display_rows = CEILING(length(R.module.modules) / 8, 1) - R.robot_modules_background.screen_loc = "CENTER-4:16,SOUTH+1:7 to CENTER+3:16,SOUTH+[display_rows]:7" - R.client.screen += R.robot_modules_background + robot_modules_background.screen_loc = "CENTER-4:16,SOUTH+1:7 to CENTER+3:16,SOUTH+[display_rows]:7" + screenmob.client.screen += robot_modules_background var/x = -4 //Start at CENTER-4,SOUTH+1 var/y = 1 @@ -226,7 +271,7 @@ for(var/atom/movable/A in R.module.modules) if((A != R.module_state_1) && (A != R.module_state_2) && (A != R.module_state_3)) //Module is not currently active - R.client.screen += A + screenmob.client.screen += A if(x < 0) A.screen_loc = "CENTER[x]:16,SOUTH+[y]:7" else @@ -241,11 +286,39 @@ else //Modules display is hidden - R.client.screen -= module_store_icon + screenmob.client.screen -= module_store_icon for(var/atom/A in R.module.modules) if((A != R.module_state_1) && (A != R.module_state_2) && (A != R.module_state_3)) //Module is not currently active - R.client.screen -= A - R.shown_robot_modules = FALSE - R.client.screen -= R.robot_modules_background + screenmob.client.screen -= A + shown_robot_modules = FALSE + screenmob.client.screen -= robot_modules_background + +/datum/hud/robot/persistent_inventory_update(mob/viewer) + if(!mymob) + return + var/mob/living/silicon/robot/R = mymob + + var/mob/screenmob = viewer || R + + var/held_items = list(R.module_state_1, R.module_state_2, R.module_state_3) + if(!screenmob.hud_used) + return + if(screenmob.hud_used.hud_shown) + for(var/i in 1 to length(held_items)) + var/obj/item/I = held_items[i] + if(I) + switch(i) + if(1) + I.screen_loc = ui_inv1 + if(2) + I.screen_loc = ui_inv2 + if(3) + I.screen_loc = ui_inv3 + else + return + screenmob.client.screen += I + else + for(var/obj/item/I in held_items) + screenmob.client.screen -= I diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index b4897cd5df7..9216a62bbf3 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -367,6 +367,8 @@ screen_loc = ui_crafting /atom/movable/screen/craft/Click() + if(!isliving(usr)) + return var/mob/living/M = usr M.OpenCraftingMenu() @@ -396,24 +398,26 @@ object_overlays.Cut() /atom/movable/screen/inventory/proc/add_overlays() - var/mob/user = hud.mymob + var/mob/user = hud?.mymob - if(hud && user && slot_id) - var/obj/item/holding = user.get_active_hand() + if(!user || !slot_id || user != usr) + return - if(!holding || user.get_item_by_slot(slot_id)) - return + var/obj/item/holding = user.get_active_hand() - var/image/item_overlay = image(holding) - item_overlay.alpha = 92 + if(!holding || user.get_item_by_slot(slot_id)) + return - if(!user.can_equip(holding, slot_id, disable_warning = TRUE)) - item_overlay.color = "#ff0000" - else - item_overlay.color = "#00ff00" + var/image/item_overlay = image(holding) + item_overlay.alpha = 92 - object_overlays += item_overlay - add_overlay(object_overlays) + if(!user.can_equip(holding, slot_id, TRUE)) + item_overlay.color = "#ff0000" + else + item_overlay.color = "#00ff00" + + object_overlays += item_overlay + add_overlay(object_overlays) /atom/movable/screen/inventory/MouseDrop(atom/over) cut_overlay(object_overlays) diff --git a/code/_onclick/observer_onclick.dm b/code/_onclick/observer_onclick.dm index b0632715a47..44ead52d45b 100644 --- a/code/_onclick/observer_onclick.dm +++ b/code/_onclick/observer_onclick.dm @@ -80,6 +80,8 @@ /atom/proc/attack_ghost(mob/dead/observer/user) if(SEND_SIGNAL(src, COMSIG_ATOM_ATTACK_GHOST, user) & COMPONENT_CANCEL_ATTACK_CHAIN) return TRUE + if(!istype(user)) // Make sure user is actually an observer. Revenents also use attack_ghost, but do not have the health_scan var. + return FALSE if(user.client) if(user.gas_scan && atmos_scan(user=user, target=src, silent=TRUE)) return TRUE diff --git a/code/controllers/subsystem/non_firing/SSatoms.dm b/code/controllers/subsystem/non_firing/SSatoms.dm index a1c515fdb80..038f417c9b0 100644 --- a/code/controllers/subsystem/non_firing/SSatoms.dm +++ b/code/controllers/subsystem/non_firing/SSatoms.dm @@ -1,8 +1,3 @@ -#define BAD_INIT_QDEL_BEFORE (1<<0) -#define BAD_INIT_DIDNT_INIT (1<<1) -#define BAD_INIT_SLEPT (1<<2) -#define BAD_INIT_NO_HINT (1<<3) - SUBSYSTEM_DEF(atoms) name = "Atoms" init_order = INIT_ORDER_ATOMS @@ -123,7 +118,25 @@ SUBSYSTEM_DEF(atoms) old_initialized = SSatoms.old_initialized BadInitializeCalls = SSatoms.BadInitializeCalls -#undef BAD_INIT_QDEL_BEFORE -#undef BAD_INIT_DIDNT_INIT -#undef BAD_INIT_SLEPT -#undef BAD_INIT_NO_HINT + + +/client/proc/debug_atom_init() + set name = "Atom Init Log" + set category = "Debug" + set desc = "Shows what failed to init this round" + + if(!check_rights(R_DEBUG | R_VIEWRUNTIMES)) + return + + var/list/html_data = list() + html_data += "

Bad Initialize() Calls

" + + for(var/typepath in SSatoms.BadInitializeCalls) + var/val = SSatoms.BadInitializeCalls[typepath] + + html_data += "" + + html_data += "
TypeQdeleted before initDid not initSlept during initNo init hint
[typepath][val & BAD_INIT_QDEL_BEFORE ? "X" : " "][val & BAD_INIT_DIDNT_INIT ? "X" : " "][val & BAD_INIT_SLEPT ? "X" : " "][val & BAD_INIT_NO_HINT ? "X" : " "]
" + + usr << browse(html_data.Join(), "window=initdebug") + diff --git a/code/controllers/subsystem/non_firing/SSlate_mapping.dm b/code/controllers/subsystem/non_firing/SSlate_mapping.dm index 9d48af77cfa..ca68dc48e9f 100644 --- a/code/controllers/subsystem/non_firing/SSlate_mapping.dm +++ b/code/controllers/subsystem/non_firing/SSlate_mapping.dm @@ -8,10 +8,32 @@ SUBSYSTEM_DEF(late_mapping) flags = SS_NO_FIRE /// List of all maze generators to process var/list/obj/effect/mazegen/generator/maze_generators = list() + /// List of all bridge spawners to process + var/list/obj/effect/spawner/bridge/bridge_spawners = list() /datum/controller/subsystem/late_mapping/Initialize() if(length(maze_generators)) + var/watch = start_watch() log_startup_progress("Generating mazes...") + for(var/i in maze_generators) var/obj/effect/mazegen/generator/MG = i MG.run_generator() + + var/list/mgcount = length(maze_generators) // Keeping track of this here because we wipe it next line down + QDEL_LIST_CONTENTS(maze_generators) + var/duration = stop_watch(watch) + log_startup_progress("Generated [mgcount] mazes in [duration]s") + + if(length(bridge_spawners)) + var/watch = start_watch() + log_startup_progress("Spawning bridges...") + + for(var/i in bridge_spawners) + var/obj/effect/spawner/bridge/BS = i + BS.generate_bridge() + + var/list/bscount = length(bridge_spawners) // Keeping track of this here because we wipe it next line down + QDEL_LIST_CONTENTS(bridge_spawners) + var/duration = stop_watch(watch) + log_startup_progress("Spawned [bscount] bridges in [duration]s") diff --git a/code/controllers/subsystem/tickets/SStickets.dm b/code/controllers/subsystem/tickets/SStickets.dm index 2949d9b6bfe..a555dfda3a3 100644 --- a/code/controllers/subsystem/tickets/SStickets.dm +++ b/code/controllers/subsystem/tickets/SStickets.dm @@ -37,6 +37,9 @@ SUBSYSTEM_DEF(tickets) // Autoresponse keys, in sorted order. var/sorted_responses + /// Who has what tickets open? Maps client -> open ticket number. + var/list/open_detail_uis = list() + /datum/controller/subsystem/tickets/get_metrics() . = ..() var/list/cust = list() @@ -79,7 +82,7 @@ SUBSYSTEM_DEF(tickets) var/report for(var/num in stales) report += "[num], " - message_staff("Tickets [report] have been open for over [TICKET_TIMEOUT / 600] minutes. Changing status to stale.") + message_staff("Tickets [report] have been open for over [TICKET_TIMEOUT / (60 SECONDS)] minutes. Changing status to stale.") /datum/controller/subsystem/tickets/get_stat_details() return "Tickets: [LAZYLEN(allTickets)]" @@ -206,11 +209,18 @@ SUBSYSTEM_DEF(tickets) to_chat_safe(returnClient(N), "Your [ticket_name] has now been resolved.") return TRUE +/datum/controller/subsystem/tickets/proc/refresh_tickets(list/tickets) + for(var/datum/ticket/T in tickets) + for(var/client/client in open_detail_uis) + if(client && open_detail_uis[client] == T.ticketNum) + showDetailUI(client.mob, T.ticketNum) + /datum/controller/subsystem/tickets/proc/addResponse(list/tickets, who, message) var/list/ticket_numbers = list() for(var/datum/ticket/T in tickets) ticket_numbers += T.ticketNum T.addResponse(who, message) + refresh_tickets(tickets) if(length(ticket_numbers) == 1) for(var/datum/ticket/only_ticket in tickets) @@ -532,9 +542,11 @@ UI STUFF /datum/controller/subsystem/tickets/proc/showUI(mob/user, tab) var/dat = null dat = returnUI(tab) - var/datum/browser/popup = new(user, ticket_system_name, ticket_system_name, 1400, 600) + var/datum/browser/popup = new(user, ticket_system_name, ticket_system_name, 1400, 800) popup.set_content(dat) popup.open() + // This isn't the detail tab, stop listening for the user's typing. + open_detail_uis -= user.client /datum/controller/subsystem/tickets/proc/showDetailUI(mob/user, ticketID) var/datum/ticket/T = allTickets[ticketID] @@ -548,7 +560,8 @@ UI STUFF dat += "

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

" dat += "

Ticket Status: [status]" - dat += "" + dat += "
" + dat += "
" dat += "" if(length(T.ticket_responses) > 1) @@ -556,7 +569,31 @@ UI STUFF var/datum/ticket_response/TR = T.ticket_responses[i] dat += "" - dat += "
[makeUrlMessage(T, one_line = TRUE)]
[TR.to_string()]


" + dat += "" + var/client/C = get_client_by_ckey(T.client_ckey) + for(var/key in C?.pm_tracker.pms) + var/datum/pm_convo/convo = C.pm_tracker.pms[key] + if(convo.typing) + dat += "[key] is typing
" + + var/found_typing = FALSE + for(var/client/X in GLOB.admins) + if(ckey(X.ckey) == ckey(T.client_ckey)) + continue + if(!check_rights_for(X, rights_needed)) + continue + for(var/key in X.pm_tracker.pms) + if(ckey(key) != ckey(T.client_ckey)) + continue + var/datum/pm_convo/convo = X.pm_tracker.pms[key] + if(convo.typing) + dat += "[key] is typing
" + found_typing = TRUE + break + if(found_typing) + break + + dat += "
" dat += "Re-Open[check_rights(rights_needed, 0) ? "Auto": ""]Resolve

" if(!T.staffAssigned) @@ -574,9 +611,19 @@ UI STUFF dat += "Close Ticket" dat += "Convert Ticket" - var/datum/browser/popup = new(user, "[ticket_system_name]detail", "[ticket_system_name] #[T.ticketNum]", 1000, 600) + var/datum/browser/popup = new(user, "[ticket_system_name]detail", "[ticket_system_name] #[T.ticketNum]", 1000, 800, src) + popup.add_head_content(@{""}) popup.set_content(dat) popup.open() + open_detail_uis[user.client] = T.ticketNum + +/datum/controller/subsystem/tickets/proc/onCloseDetailUI(mob/user) + open_detail_uis -= user.client /datum/controller/subsystem/tickets/proc/userDetailUI(mob/user) //dat @@ -591,7 +638,7 @@ UI STUFF dat += "[TR.to_string()]" dat += "" - var/datum/browser/popup = new(user, "[ticket_system_name]userticketsdetail", ticket_system_name, 1000, 600) + var/datum/browser/popup = new(user, "[ticket_system_name]userticketsdetail", ticket_system_name, 1000, 800) popup.set_content(dat) popup.open() @@ -697,6 +744,9 @@ UI STUFF else usr.client.resolveAllAdminTickets() + if(href_list["close"]) + onCloseDetailUI(usr) + /datum/controller/subsystem/tickets/proc/takeTicket(index) if(assignStaffToTicket(usr.client, index)) if(span_class == "mentorhelp") diff --git a/code/datums/action.dm b/code/datums/action.dm index 0a099de316c..33c5681c9b6 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -16,6 +16,8 @@ var/default_button_position = SCRN_OBJ_IN_LIST /// Map of huds viewing a button with our action -> their button var/list/viewers = list() + /// Whether or not this will be shown to observers + var/show_to_observers = TRUE /datum/action/New(Target) @@ -49,6 +51,8 @@ Remove(owner) owner = M RegisterSignal(owner, COMSIG_PARENT_QDELETING, PROC_REF(clear_ref), override = TRUE) + SEND_SIGNAL(src, COMSIG_ACTION_GRANTED, owner) + SEND_SIGNAL(owner, COMSIG_MOB_GRANTED_ACTION, src) GiveAction(M) /datum/action/proc/Remove(mob/remove_from) @@ -64,6 +68,9 @@ if(isnull(owner)) return + SEND_SIGNAL(src, COMSIG_ACTION_REMOVED, owner) + SEND_SIGNAL(owner, COMSIG_MOB_REMOVED_ACTION, src) + if(target == owner) RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(clear_ref), override = TRUE) if(owner == remove_from) diff --git a/code/datums/components/orbiter.dm b/code/datums/components/orbiter.dm index 50ff05d4af1..d7a5a3a8ade 100644 --- a/code/datums/components/orbiter.dm +++ b/code/datums/components/orbiter.dm @@ -163,6 +163,7 @@ orbiter.animate_movement = SLIDE_STEPS if(!QDELETED(parent)) SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_STOP, orbiter) + SEND_SIGNAL(orbiter, COMSIG_ATOM_ORBITER_STOP, parent) orbiter.transform = get_cached_transform(orbiter) orbiter.layer = get_orbiter_layer(orbiter) diff --git a/code/datums/mind.dm b/code/datums/mind.dm index 26d4ba5fa50..c055734bbe5 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -515,7 +515,7 @@ alert("Not before round-start!", "Alert") return - var/list/out = list("[name][(current && (current.real_name != name))?" (as [current.real_name])" : ""]") + var/list/out = list("[name][name][(current && (current.real_name != name))?" (as [current.real_name])" : ""]") out.Add("Mind currently owned by key: [key] [active ? "(synced)" : "(not synced)"]") out.Add("Assigned role: [assigned_role]. Edit") out.Add("Factions and special roles:") @@ -592,6 +592,7 @@ out.Add(gen_objective_text(admin = TRUE)) out.Add("Add objective
") out.Add("Announce objectives
") + out.Add("") usr << browse(out.Join("
"), "window=edit_memory[src];size=500x500") /datum/mind/Topic(href, href_list) diff --git a/code/datums/recipe.dm b/code/datums/recipe.dm index 8d0f7a7c0a1..f10e70ed027 100644 --- a/code/datums/recipe.dm +++ b/code/datums/recipe.dm @@ -42,26 +42,49 @@ var/duplicate = TRUE var/byproduct // example: = /obj/item/kitchen/mould // byproduct to return, such as a mould or trash -/datum/recipe/proc/check_reagents(datum/reagents/avail_reagents) //1=precisely, 0=insufficiently, -1=superfluous - . = 1 +/datum/recipe/proc/check_reagents(datum/reagents/avail_reagents) + . = INGREDIENT_CHECK_EXACT for(var/r_r in reagents) var/aval_r_amnt = avail_reagents.get_reagent_amount(r_r) if(!(abs(aval_r_amnt - reagents[r_r])<0.5)) //if NOT equals if(aval_r_amnt>reagents[r_r]) - . = -1 + . = INGREDIENT_CHECK_SURPLUS else - return 0 - if((reagents?(length(reagents)):(0)) < length(avail_reagents.reagent_list)) - return -1 + return INGREDIENT_CHECK_FAILURE + if((reagents ? length(reagents) : 0) < length(avail_reagents.reagent_list)) + return INGREDIENT_CHECK_SURPLUS + +/** + * Similarly to the function above, this checks for reagents, except instead of being passed a reagent holder, we're passed + * [reagent_id] = amount as num. + * Returns INGREDIENT_CHECK_EXACT if we have the precise amount thats requested. + * Returns INGREDIENT_CHECK_FAILURE if we do not have enough. + * Returns INGREDIENT_CHECK_SURPLUS if we have MORE than requested. + */ +/datum/recipe/proc/check_reagents_assoc_list(list/avail_reagents) + . = INGREDIENT_CHECK_EXACT + for(var/required_reagent_id in reagents) + var/provided_reagent_amount = avail_reagents[required_reagent_id] + if(!provided_reagent_amount) + return INGREDIENT_CHECK_FAILURE + + if(abs(provided_reagent_amount - reagents[required_reagent_id]) >= 0.5) // If amount is outside of the 0.5 unit tolerance + if(provided_reagent_amount > reagents[required_reagent_id]) // we have more than necessary + . = INGREDIENT_CHECK_SURPLUS + else + return INGREDIENT_CHECK_FAILURE // we don't have enough + + if(length(reagents) < length(avail_reagents)) + return INGREDIENT_CHECK_SURPLUS /datum/recipe/proc/check_items(obj/container, list/ignored_items = null) //1=precisely, 0=insufficiently, -1=superfluous - . = 1 + . = INGREDIENT_CHECK_EXACT var/list/checklist = items ? items.Copy() : list() for(var/obj/O in container) if(ignored_items && is_type_in_list(O, ignored_items)) //skip if this is something we are ignoring continue if(!items) - return -1 + return INGREDIENT_CHECK_SURPLUS var/found = 0 for(var/type in checklist) if(istype(O,type)) @@ -69,9 +92,32 @@ found = 1 break if(!found) - . = -1 + . = INGREDIENT_CHECK_SURPLUS if(length(checklist)) - return 0 + return INGREDIENT_CHECK_FAILURE + +/** + * Similarly to the function above, this checks for items, except instead of being passed a reagent holder, we're passed + * [type_path] = amount as num. + * Returns INGREDIENT_CHECK_EXACT if we have the precise amount thats requested. + * Returns INGREDIENT_CHECK_FAILURE if we do not have enough. + * Returns INGREDIENT_CHECK_SURPLUS if we have MORE than requested. + */ +/datum/recipe/proc/check_items_assoc_list(list/given_objects) + . = INGREDIENT_CHECK_EXACT + var/list/checklist = items ? items.Copy() : list() + for(var/obj/item/I as anything in given_objects) // path + var/amount_given = given_objects[I] + if(!length(checklist)) + return INGREDIENT_CHECK_SURPLUS + + for(var/i in 1 to amount_given) + if(I in checklist) + checklist -= I + else if(I in items) // make sure the recipe requires this item before declaring it surplus + . = INGREDIENT_CHECK_SURPLUS + if(length(checklist)) // we didnt get everything + return INGREDIENT_CHECK_FAILURE //general version /datum/recipe/proc/make(obj/container) @@ -94,7 +140,7 @@ container.reagents.clear_reagents() return result_obj -/proc/select_recipe(list/datum/recipe/available_recipes, obj/obj, exact = 1 as num, list/ignored_items = null) +/proc/select_recipe(list/datum/recipe/available_recipes, obj/obj, exact = INGREDIENT_CHECK_EXACT, list/ignored_items = null) if(!exact) exact = -1 var/list/datum/recipe/possible_recipes = new diff --git a/code/datums/ruins/bridges/bridges.dm b/code/datums/ruins/bridges/bridges.dm index 636a94adb18..6d5770419a3 100644 --- a/code/datums/ruins/bridges/bridges.dm +++ b/code/datums/ruins/bridges/bridges.dm @@ -62,7 +62,13 @@ /obj/effect/spawner/bridge/Initialize(mapload) . = ..() + SSlate_mapping.bridge_spawners += src +/obj/effect/spawner/bridge/Destroy() + SSlate_mapping.bridge_spawners -= src + return ..() + +/obj/effect/spawner/bridge/proc/generate_bridge() var/turf/east = locate(x + 3, y, z) var/turf/west = locate(x - 3, y, z) var/turf/north = locate(x, y + 3, z) @@ -79,4 +85,3 @@ else if((ismineralturf(north) || istype(north, /turf/simulated/floor/plating/asteroid)) && (ismineralturf(south) || istype(south, /turf/simulated/floor/plating/asteroid)) && !(ismineralturf(e1) || istype(e1, /turf/simulated/floor/plating/asteroid)) && !(ismineralturf(w1) || istype(w1, /turf/simulated/floor/plating/asteroid))) template = GLOB.bridge_vertical_templates[pick("lavaland_bridge_vertical_1.dmm", "lavaland_bridge_vertical_2.dmm", "lavaland_bridge_vertical_3.dmm", "lavaland_bridge_vertical_4.dmm", "lavaland_bridge_vertical_5.dmm", "lavaland_bridge_vertical_6.dmm")] template.load(loc, centered = TRUE) - qdel(src) //Don't turn to hint qdel, it won't work well at all sadly. diff --git a/code/datums/spells/chef.dm b/code/datums/spells/chef.dm new file mode 100644 index 00000000000..642f5476f44 --- /dev/null +++ b/code/datums/spells/chef.dm @@ -0,0 +1,17 @@ +/datum/spell/chef/expert_chef + name = "Expert Chef Knowledge" + desc = "Find things you can cook with the items in reach." + school = "chef" + clothes_req = FALSE + base_cooldown = 5 SECONDS + human_req = TRUE + action_icon_state = "chef" + action_background_icon_state = "bg_default" + still_recharging_msg = "All this thinking makes your head hurt, wait a bit longer." + +/datum/spell/chef/expert_chef/cast(list/targets, mob/user = usr) + var/mob/living/carbon/human/H = targets[1] + H.expert_chef_knowledge() + +/datum/spell/chef/expert_chef/create_new_targeting() + return new /datum/spell_targeting/self diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 4e976e9e5d6..e476267e04b 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -596,12 +596,14 @@ H.physiology.brute_mod *= 0.8 H.physiology.burn_mod *= 0.8 H.physiology.stamina_mod *= 0.8 + owner.status_flags &= ~CANPUSH add_attack_logs(owner, owner, "gained chainsaw stun immunity", ATKLOG_ALL) owner.add_stun_absorption("chainsaw", INFINITY, 4) owner.playsound_local(get_turf(owner), 'sound/effects/singlebeat.ogg', 40, TRUE, use_reverb = FALSE) /datum/status_effect/chainsaw_slaying/on_remove() add_attack_logs(owner, owner, "lost chainsaw stun immunity", ATKLOG_ALL) + owner.status_flags |= CANPUSH if(islist(owner.stun_absorption) && owner.stun_absorption["chainsaw"]) owner.remove_stun_absorption("chainsaw") if(ishuman(owner)) diff --git a/code/datums/uplink_items/uplink_general.dm b/code/datums/uplink_items/uplink_general.dm index 8fe7955fed5..9a9425ee96b 100644 --- a/code/datums/uplink_items/uplink_general.dm +++ b/code/datums/uplink_items/uplink_general.dm @@ -760,7 +760,8 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) desc = "A pinpointer that tracks any specified coordinates, DNA string, high value item or the nuclear authentication disk." reference = "ADVP" item = /obj/item/pinpointer/advpinpointer - cost = 20 + cost = 10 + can_discount = FALSE /datum/uplink_item/device_tools/ai_detector name = "Artificial Intelligence Detector" // changed name in case newfriends thought it detected disguised ai's diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index e0364ea07b4..66ed38dd37a 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -530,6 +530,8 @@ INVOKE_ASYNC(temp_airlock, TYPE_PROC_REF(/obj/machinery/door/airlock, prison_open)) for(var/obj/machinery/door/window/temp_windoor in src) INVOKE_ASYNC(temp_windoor, TYPE_PROC_REF(/obj/machinery/door, open)) + for(var/obj/machinery/door/poddoor/temp_poddoor in src) + INVOKE_ASYNC(temp_poddoor, TYPE_PROC_REF(/obj/machinery/door, open)) /area/AllowDrop() CRASH("Bad op: area/AllowDrop() called") diff --git a/code/game/area/centcom_areas.dm b/code/game/area/centcom_areas.dm index ca23f1ace4f..455911a1b11 100644 --- a/code/game/area/centcom_areas.dm +++ b/code/game/area/centcom_areas.dm @@ -135,7 +135,7 @@ dynamic_lighting = DYNAMIC_LIGHTING_DISABLED /area/trader_station/sol - name = "Jupiter Station 6" + name = "Trading Satellite" /area/ghost_bar name = "Ghost Bar" diff --git a/code/game/dna/mutations/mutation_powers.dm b/code/game/dna/mutations/mutation_powers.dm index d25a11adfd7..b6712420632 100644 --- a/code/game/dna/mutations/mutation_powers.dm +++ b/code/game/dna/mutations/mutation_powers.dm @@ -562,11 +562,13 @@ for(var/atom/movable/hit_thing in turf_to_check) if(isliving(hit_thing)) var/mob/living/hit_mob = hit_thing - return hit_mob.density + if(hit_mob.density) + return hit_mob if(isobj(hit_thing)) var/obj/hit_obj = hit_thing - return hit_obj.density + if(hit_obj.density) + return hit_obj return FALSE diff --git a/code/game/gamemodes/miniantags/revenant/revenant.dm b/code/game/gamemodes/miniantags/revenant/revenant.dm index 4ee14c9fdf4..bd35548dfe2 100644 --- a/code/game/gamemodes/miniantags/revenant/revenant.dm +++ b/code/game/gamemodes/miniantags/revenant/revenant.dm @@ -223,9 +223,7 @@ playsound(src, 'sound/effects/screech.ogg', 100, 1) visible_message("[src] lets out a waning screech as violet mist swirls around its dissolving body!") icon_state = "revenant_draining" - for(var/i = alpha, i > 0, i -= 10) - sleep(0.1) - alpha = i + animate(src, alpha = 0, time = 3 SECONDS) visible_message("[src]'s body breaks apart into a fine pile of blue dust.") new /obj/item/ectoplasm/revenant(get_turf(src)) ghostize() diff --git a/code/game/jobs/job/support.dm b/code/game/jobs/job/support.dm index c8678be4e11..b24597ec1fa 100644 --- a/code/game/jobs/job/support.dm +++ b/code/game/jobs/job/support.dm @@ -244,7 +244,9 @@ var/datum/martial_art/cqc/under_siege/justacook = new justacook.teach(H) // requires mind ADD_TRAIT(H.mind, TRAIT_TABLE_LEAP, ROUNDSTART_TRAIT) - + ADD_TRAIT(H.mind, TRAIT_KNOWS_COOKING_RECIPES, ROUNDSTART_TRAIT) + if(H.mind) + H.mind.AddSpell(new /datum/spell/chef/expert_chef) /datum/job/hydro title = "Botanist" diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index 40f707866e0..4ab93649c91 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -62,8 +62,8 @@ GLOBAL_VAR_INIT(time_last_changed_position, 0) var/list/opened_positions = list() -/obj/machinery/computer/card/Initialize() - ..() +/obj/machinery/computer/card/Initialize(mapload) + . = ..() Radio = new /obj/item/radio(src) Radio.listening = FALSE Radio.config(list("Command" = 0)) diff --git a/code/game/machinery/computer/medical_records.dm b/code/game/machinery/computer/medical_records.dm index 1c9e8a78768..a57bc83ff48 100644 --- a/code/game/machinery/computer/medical_records.dm +++ b/code/game/machinery/computer/medical_records.dm @@ -28,7 +28,7 @@ light_color = LIGHT_COLOR_DARKBLUE /obj/machinery/computer/med_data/Initialize() - ..() + . = ..() field_edit_questions = list( // General "sex" = "Please select new sex:", diff --git a/code/game/machinery/dye_generator.dm b/code/game/machinery/dye_generator.dm index 3e7d346ec52..3a6e2c2c86f 100644 --- a/code/game/machinery/dye_generator.dm +++ b/code/game/machinery/dye_generator.dm @@ -9,7 +9,7 @@ var/dye_color = "#FFFFFF" /obj/machinery/dye_generator/Initialize() - ..() + . = ..() power_change() /obj/machinery/dye_generator/deconstruct(disassembled = TRUE) diff --git a/code/game/machinery/magnetic_module.dm b/code/game/machinery/magnetic_module.dm index f10aae48db5..5f50939ffd1 100644 --- a/code/game/machinery/magnetic_module.dm +++ b/code/game/machinery/magnetic_module.dm @@ -212,7 +212,6 @@ return INITIALIZE_HINT_LATELOAD /obj/machinery/magnetic_controller/LateInitialize() - ..() if(autolink) // GLOB.machines is populated in /machinery/Initialize // so linkage gets delayed until that one finished. diff --git a/code/game/machinery/turret_control.dm b/code/game/machinery/turret_control.dm index d675f29d405..0641f41f236 100644 --- a/code/game/machinery/turret_control.dm +++ b/code/game/machinery/turret_control.dm @@ -68,7 +68,7 @@ return ..() /obj/machinery/turretid/Initialize() - ..() + . = ..() if(!control_area) control_area = get_area(src) else if(istext(control_area)) diff --git a/code/game/mecha/combat/durand.dm b/code/game/mecha/combat/durand.dm index 1ba971d347f..bbab6fe3e94 100644 --- a/code/game/mecha/combat/durand.dm +++ b/code/game/mecha/combat/durand.dm @@ -1,5 +1,5 @@ /obj/mecha/combat/durand - desc = "It's time to light some fires and kick some tires." + desc = "A heavily armored exosuit designed for front-line combat." name = "Durand Mk. II" icon_state = "durand" initial_icon = "durand" @@ -28,9 +28,18 @@ ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack ME.attach(src) +/obj/mecha/combat/durand/examine_more(mob/user) + . = ..() + . += "A durable heavyweight combat mech designed and produced by Defiance Arms. \ + The Durand is an outdated design among Defiance's line of battlemechs and was initially created to fulfill the role of a combat spearhead, breaking into enemy combat formations. \ + Supplanted by newer, more advanced models, these old machines found themselves on the open market and are popular among corporations, private security firms, and planetary militia." + . += "" + . += "Able to bear a wide array of heavy weapons and defensive tools, Nanotrasen found a use for the Durand as a machine to counter biohazards and hostile alien lifeforms, using it to secure new research installations or to fend off hostile fauna and bioforms. \ + As with all station-side mechs, Nanotrasen has purchased the license to produce the Durand in their facilities." + /obj/mecha/combat/durand/old - desc = "A retired, third-generation combat exosuit utilized by the Nanotrasen corporation. Originally developed to combat hostile alien lifeforms." - name = "Durand" + desc = "A retired, third-generation combat exosuit designed by Defiance Arms. Originally developed to combat hostile alien lifeforms" + name = "Old Durand" icon_state = "old_durand" initial_icon = "old_durand" step_in = 4 @@ -42,3 +51,12 @@ infra_luminosity = 8 force = 40 wreckage = /obj/structure/mecha_wreckage/durand/old + +/obj/mecha/combat/durand/old/examine_more(mob/user) + ..() + . = list() + . += "A relic of a mech, once produced by Defiance Arms in the decade of 2470. \ + It is now sought after by collectors and museums alike and has found its way into the hands of many a black market over the decades since its later versions replaced it." + . += "" + . += "Built initially to break into and destroy Xenomorph infestations, bigger and better war machines exist. \ + But many still uphold this version of the Durand as an unstoppable classic, and finding one intact and functional has become increasingly rare." diff --git a/code/game/mecha/combat/gygax.dm b/code/game/mecha/combat/gygax.dm index da18bf23f57..6742c606111 100644 --- a/code/game/mecha/combat/gygax.dm +++ b/code/game/mecha/combat/gygax.dm @@ -1,5 +1,5 @@ /obj/mecha/combat/gygax - desc = "A lightweight, security exosuit. Popular among private and corporate security." + desc = "A lightweight security exosuit. Popular among private and corporate security." name = "Gygax" icon_state = "gygax" initial_icon = "gygax" @@ -33,6 +33,16 @@ ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang ME.attach(src) +/obj/mecha/combat/gygax/examine_more(mob/user) + . = ..() + . += "A light, fast and cheap combat mech designed and produced by Shellguard Munitions. \ + Originally developed as a mobile flanker for open combat scenarios, a substantial flaw in the mech's Leg Overdrive systems caused poor sales. \ + When using this system, the legs of the Gygax are prone to overheating and damaging the rest of the machine, leading overzealous pilots to harm themselves more than the enemy." + . += "" + . += "Despite this flaw, Shellguard was able to reconsider the use of the mech and instead marketed it as a civil defence and policing mech. \ + Popularity soared, especially among corporations like Nanotrasen, who were seeking a light, fast, cheap design to use to equip their security teams. \ + As with all station-side mechs, Nanotrasen has purchased the license to produce the Gygax in their facilities." + /obj/mecha/combat/gygax/dark desc = "A lightweight exosuit, painted in a dark scheme. This model appears to have some modifications." name = "Dark Gygax" @@ -68,3 +78,12 @@ /obj/mecha/combat/gygax/dark/add_cell() cell = new /obj/item/stock_parts/cell/bluespace(src) + +/obj/mecha/combat/gygax/dark/examine_more(mob/user) + ..() + . = list() + . += "A light, fast and cheap combat mech designed and produced by Shellguard Munitions, though this one appears to be modified. \ + With minor alterations to the loadout, armor, and a slick black paint job, this variant strikes a menacing silhouette, its owner clearly being someone you should not mess with." + . += "" + . += "Despite the flaws of the base model, this modified Gygax has no trouble being a speedy, dangerous killing machine. \ + Alterations such as this are common amongst fringe users and outlaw groups, and the upgrades are most certainly illegal. Don't cut yourself." diff --git a/code/game/mecha/combat/honker.dm b/code/game/mecha/combat/honker.dm index 8e25bf3dac6..6d54e9dc01a 100644 --- a/code/game/mecha/combat/honker.dm +++ b/code/game/mecha/combat/honker.dm @@ -135,3 +135,11 @@ if("sadtrombone") playsound(src, 'sound/misc/sadtrombone.ogg', 50) return + +/obj/mecha/combat/honker/examine_more(mob/user) + . = ..() + . += "A cheerful, colorful modification of a Durand chassis, the Honk mech is designed as heavy laughterfield support for producing mass honking casualties. \ + Built and perfected by some of the most skilled Clowns ever known to the galaxy, with materials and labor provided by Donk Co, the Honk has somehow managed to have its design smuggled aboard almost ever Nanotrasen station, to the imminent laughter (screams) and joy (despair) of it's crew!" + . += "" + . += "Equipped with a massive HoNkER BlAsT 5000 horn and long range mortars capable of firing both slippery banana peels and dangerous mousetraps, the Honk is well equipped to provide a Clown with everything they need to 'entertain' a station's crew, and to draw the ire of any nearby Security. \ + Honk!" diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm index 80b8263d2e1..14176514fbc 100644 --- a/code/game/mecha/combat/marauder.dm +++ b/code/game/mecha/combat/marauder.dm @@ -1,5 +1,5 @@ /obj/mecha/combat/marauder - desc = "Heavy-duty, combat exosuit, developed after the Durand model. Rarely found among civilian populations." + desc = "Heavy-duty combat exosuit, developed after the Durand model. Rarely found among civilian populations." name = "Marauder" icon_state = "marauder" initial_icon = "marauder" @@ -48,9 +48,17 @@ /obj/mecha/combat/marauder/add_cell() cell = new /obj/item/stock_parts/cell/bluespace(src) +/obj/mecha/combat/marauder/examine_more(mob/user) + . = ..() + . += "The newest combat mech developed by Defiance Arms, the Marauder is now their mainline offering in the galactic arms market. \ + Based on the earlier Durand chassis, the Marauder is a high-tech weapon of war and destruction, fulfilling the spearhead role of Defiance's earlier design while supporting more firepower than ever before." + . += "" + . += "The Marauder is rarely seen in civilian hands; instead, it is marketed towards military and mercenary forces. \ + Recently, Defiance has opened sales to more customers; This includes Nanotrasen, who uses it to equip their ERT dvision." + /obj/mecha/combat/marauder/ares name = "Ares" - desc = "Heavy-duty, combat exosuit, adapted from rejected early versions of the Marauder to serve as a biohazard containment exosuit. This model, albeit rare, can be found among civilian populations." + desc = "Heavy-duty combat exosuit, adapted from rejected early versions of the Marauder to serve as a biohazard containment exosuit. This model, albeit rare, can be found among civilian populations." icon_state = "ares" initial_icon = "ares" operation_req_access = list(ACCESS_SECURITY) @@ -75,8 +83,17 @@ ME = new /obj/item/mecha_parts/mecha_equipment/thrusters ME.attach(src) +/obj/mecha/combat/marauder/ares/examine_more(mob/user) + ..() + . = list() + . += "Developed from earlier Durand prototypes that never saw production, the Ares is produced by Defiance Arms and marketed as the final word in biohazard containment and protection. \ + Heavily armed and armored, and perhaps a little out of date, the Ares is built from the ground up to destroy biological incursions, whatever those may be." + . += "" + . += "Defiance does not sell the license for the Ares to be produced, and as such, it is rarer than most combat mechs, but is more commonly seen among civilian markets compared to their mainline Marauder chassis. \ + Nanotrases supports a small stable of Ares battlemechs to be used in times of dire emergency." + /obj/mecha/combat/marauder/seraph - desc = "Heavy-duty, command-type exosuit. This is a custom model, utilized only by high-ranking military personnel." + desc = "Heavy-duty command-type exosuit. This is a custom model, utilized only by high-ranking personnel." name = "Seraph" icon_state = "seraph" initial_icon = "seraph" @@ -110,8 +127,17 @@ ME = new /obj/item/mecha_parts/mecha_equipment/thrusters ME.attach(src) +/obj/mecha/combat/marauder/seraph/examine_more(mob/user) + ..() + . = list() + . += "In the field, Nanotrasen teams often needed a command and control unit that could assist where comms failed, and thus, they created a retrofit of the Marauder. \ + This new Seraph variant would serve as a command model, with enhanced comms and command capabilities, but would otherwise be incredibly rare." + . += "" + . += "Due to the rarity of the Seraph, it can be assumed that things are well and truly fucked if one is seen operating. \ + Deployed only in the direst of emergencies, it will inevitably be the lynchpin of any defense or assault." + /obj/mecha/combat/marauder/mauler - desc = "Heavy-duty, combat exosuit, developed off of the existing Marauder model." + desc = "Heavy-duty combat exosuit, modified with illegal technology and weapons." name = "Mauler" icon_state = "mauler" initial_icon = "mauler" @@ -137,3 +163,12 @@ ME.attach(src) ME = new /obj/item/mecha_parts/mecha_equipment/thrusters ME.attach(src) + +/obj/mecha/combat/marauder/mauler/examine_more(mob/user) + ..() + . = list() + . += "A bulky, brutish combat mech painted a deep, matte black, highlighted with a menacing red; the Mauler is an illegal retrofit of Defiance's Marauder chassis. \ + Armed to the teeth with various weapons and armored more thickly than some main battle tanks, this mechanical monstrosity is incredibly rare, and little is known about who makes them or why they exist." + . += "" + . += "The few confirmed sightings have recently been in the hands of the Gorlex Marauders, a group of hostile pirates with suspected ties to the Syndicate. \ + The Mauler poses a severe threat to any force and should never be taken lightly." diff --git a/code/game/mecha/combat/phazon.dm b/code/game/mecha/combat/phazon.dm index 9eb80d4b21f..f1825b56759 100644 --- a/code/game/mecha/combat/phazon.dm +++ b/code/game/mecha/combat/phazon.dm @@ -1,5 +1,5 @@ /obj/mecha/combat/phazon - desc = "An exosuit which can only be described as 'WTF?'." + desc = "An experimental, phase-shifting exosuit developed by Nanotrasen's research division" name = "Phazon" icon_state = "phazon" initial_icon = "phazon" @@ -47,3 +47,13 @@ "} output += ..() return output + +/obj/mecha/combat/phazon/examine_more(mob/user) + . = ..() + . += "The Phazon is an experimental Nanotrasen combat design, using a Bluespace Anomaly Core as its heart. \ + This odd crystal allows the mech to phase part way out of reality, allowing it to pass through walls, floors, and other structures as if they never existed in the first place. \ + Designed by an NT research team, the design has recently been distributed to their science stations for testing and preliminary production." + . += "" + . += "Due to the nature of finding Anomaly Cores, Phazons are exceedingly rare. \ + It seems to hum with stored energy, the edges of its chassis blurry in the eyes of others, even at rest. \ + Early test pilots report strange hallucinations and “visions” after extensive use of the phasing ability." diff --git a/code/game/mecha/combat/reticence.dm b/code/game/mecha/combat/reticence.dm index e6970740a80..62393bc84a8 100644 --- a/code/game/mecha/combat/reticence.dm +++ b/code/game/mecha/combat/reticence.dm @@ -26,3 +26,12 @@ ME.attach(src) ME = new /obj/item/mecha_parts/mecha_equipment/mimercd //HAHA IT MAKES WALLS GET IT ME.attach(src) + +/obj/mecha/combat/reticence/examine_more(mob/user) + . = ..() + . += "A dour, colorless modification of a Gygax chassis, the Reticence is a sight to behold…or not behold. \ + It utilizes a mysterious dampening field, added by a cabal of nearly unheard-of mimes, to be entirely silent as it moves over any terrain, making it a favored weapon of this supposed conspiracy and the assassins they may, or may not, employ." + . += "" + . += "Armed with an S.H.H. “Quietus” Carbine, an utterly silent weapon that can drain the stamina of targets unfortunate enough to be shot by it, it can ensure swift getaways. \ + As a secondary tool, it comes equipped with a mime R.C.D., a device capable of replicating a mime's mysterious ability to create impenetrable, invisible walls. \ + Strangely, the design for the Reticence seems to be present aboard every Nanotrasen station, though to what ends, no one knows." diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm index f6a33da3af4..c4d9484ad1f 100644 --- a/code/game/mecha/equipment/tools/work_tools.dm +++ b/code/game/mecha/equipment/tools/work_tools.dm @@ -254,7 +254,7 @@ qdel(target) playsound(target, usesound, 50, 1) if(MECH_RCD_MODE_WALL_OR_FLOOR) - if(isspaceturf(target)) + if(isspaceturf(target) || ischasm(target)) var/turf/space/S = target occupant_message("Building Floor...") if(do_after_cooldown(S)) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index fd1975ccc0c..ee12fd81f94 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -29,8 +29,8 @@ var/overload_step_energy_drain_min = 100 var/deflect_chance = 10 //chance to deflect the incoming projectiles, hits, or lesser the effect of ex_act. var/obj/item/stock_parts/cell/cell - var/state = 0 - var/list/log = new + var/state = MECHA_MAINT_OFF + var/list/log = list() var/last_message = 0 var/add_req_access = 1 var/maint_access = 1 @@ -84,7 +84,7 @@ var/destruction_sleep_duration = 2 SECONDS //Time that mech pilot is put to sleep for if mech is destroyed var/melee_cooldown = 10 - var/melee_can_hit = 1 + var/melee_can_hit = TRUE /// How many ion thrusters we got on this bad boy var/thruster_count = 0 @@ -247,9 +247,9 @@ if(!melee_can_hit || !isatom(target)) return target.mech_melee_attack(src) - melee_can_hit = 0 + melee_can_hit = FALSE spawn(melee_cooldown) - melee_can_hit = 1 + melee_can_hit = TRUE /obj/mecha/proc/mech_toxin_damage(mob/living/target) playsound(src, 'sound/effects/spray2.ogg', 50, 1) @@ -270,11 +270,11 @@ /obj/mecha/Process_Spacemove(movement_dir = 0) . = ..() if(.) - return 1 + return TRUE if(thrusters_active && movement_dir && use_power(step_energy_drain)) step_in = initial(step_in) / thruster_count new /obj/effect/particle_effect/ion_trails(get_turf(src), dir) - return 1 + return TRUE var/atom/movable/backup = get_spacemove_backup() if(backup) @@ -282,7 +282,7 @@ if(backup.newtonian_move(turn(movement_dir, 180))) if(occupant) to_chat(occupant, "You push off of [backup] to propel yourself.") - return 1 + return TRUE /obj/mecha/relaymove(mob/user, direction) if(!direction || frozen) @@ -290,12 +290,12 @@ if(user != occupant) //While not "realistic", this piece is player friendly. user.forceMove(get_turf(src)) to_chat(user, "You climb out from [src].") - return 0 + return FALSE if(connected_port) if(world.time - last_message > 20) occupant_message("Unable to move while connected to the air system port!") last_message = world.time - return 0 + return FALSE if(state) occupant_message("Maintenance protocols in effect.") return @@ -303,21 +303,21 @@ /obj/mecha/proc/domove(direction) if(can_move >= world.time) - return 0 + return FALSE if(!Process_Spacemove(direction)) - return 0 + return FALSE if(!has_charge(step_energy_drain)) - return 0 + return FALSE if(defence_mode) if(world.time - last_message > 20) occupant_message("Unable to move while in defence mode.") last_message = world.time - return 0 + return FALSE if(zoom_mode) if(world.time - last_message > 20) occupant_message("Unable to move while in zoom mode.") last_message = world.time - return 0 + return FALSE if(thrusters_active && has_gravity(src)) thrusters_active = FALSE @@ -364,7 +364,7 @@ dir = direction if(turnsound) playsound(src,turnsound,40,1) - return 1 + return TRUE /obj/mecha/proc/mechstep(direction) . = step(src, direction) @@ -387,25 +387,25 @@ /obj/mecha/Bump(atom/obstacle, bump_allowed) if(throwing) //high velocity mechas in your face! - var/breakthrough = 0 + var/breakthrough = FALSE if(istype(obstacle, /obj/structure/window)) qdel(obstacle) - breakthrough = 1 + breakthrough = TRUE else if(istype(obstacle, /obj/structure/grille/)) var/obj/structure/grille/G = obstacle G.obj_break() - breakthrough = 1 + breakthrough = TRUE else if(istype(obstacle, /obj/structure/table)) var/obj/structure/table/T = obstacle qdel(T) - breakthrough = 1 + breakthrough = TRUE else if(istype(obstacle, /obj/structure/rack)) new /obj/item/rack_parts(obstacle.loc) qdel(obstacle) - breakthrough = 1 + breakthrough = TRUE else if(istype(obstacle, /obj/structure/reagent_dispensers/fueltank)) obstacle.ex_act(1) @@ -421,7 +421,7 @@ L.Weaken(10 SECONDS) L.apply_effect(STUTTER, 10 SECONDS) playsound(src, pick(hit_sound), 50, 0, 0) - breakthrough = 1 + breakthrough = TRUE else if(throwing) @@ -524,7 +524,7 @@ /obj/mecha/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir) . = ..() if(!damage_amount) - return 0 + return FALSE var/booster_deflection_modifier = 1 var/booster_damage_modifier = 1 if(damage_flag == BULLET || damage_flag == LASER || damage_flag == ENERGY) @@ -547,7 +547,7 @@ if(prob(deflect_chance * booster_deflection_modifier)) visible_message("[src]'s armour deflects the attack!") log_message("Armor saved.") - return 0 + return FALSE if(.) . *= booster_damage_modifier @@ -729,7 +729,7 @@ to_chat(user, "Maintenance protocols disabled by operator.") else if(istype(W, /obj/item/stack/cable_coil)) - if(state == 3 && hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) + if(state == MECHA_OPEN_HATCH && hasInternalDamage(MECHA_INT_SHORT_CIRCUIT)) var/obj/item/stack/cable_coil/CC = W if(CC.get_amount() > 1) CC.use(2) @@ -740,7 +740,7 @@ return else if(istype(W, /obj/item/stock_parts/cell)) - if(state==4) + if(state == MECHA_BATTERY_UNSCREW) if(!cell) if(!user.drop_item()) return @@ -819,16 +819,16 @@ /obj/mecha/crowbar_act(mob/user, obj/item/I) - if(state != 2 && state != 3 && !(state == 4 && pilot_is_mmi())) + if(state != MECHA_BOLTS_UP && state != MECHA_OPEN_HATCH && !(state == MECHA_BATTERY_UNSCREW && pilot_is_mmi())) return . = TRUE if(!I.use_tool(src, user, 0, volume = I.tool_volume)) return - if(state == 2) - state = 3 + if(state == MECHA_BOLTS_UP) + state = MECHA_OPEN_HATCH to_chat(user, "You open the hatch to the power unit") - else if(state == 3) - state = 2 + else if(state == MECHA_OPEN_HATCH) + state = MECHA_BOLTS_UP to_chat(user, "You close the hatch to the power unit") else // Since having maint protocols available is controllable by the MMI, I see this as a consensual way to remove an MMI without destroying the mech @@ -841,7 +841,7 @@ /obj/mecha/screwdriver_act(mob/user, obj/item/I) if(user.a_intent == INTENT_HARM) return - if(!(state==3 && cell) && !(state==4 && cell)) + if(!(state == MECHA_OPEN_HATCH && cell) && !(state == MECHA_BATTERY_UNSCREW && cell)) return . = TRUE if(!I.use_tool(src, user, 0, volume = I.tool_volume)) @@ -849,27 +849,27 @@ if(hasInternalDamage(MECHA_INT_TEMP_CONTROL)) clearInternalDamage(MECHA_INT_TEMP_CONTROL) to_chat(user, "You repair the damaged temperature controller.") - else if(state==3 && cell) + else if(state == MECHA_OPEN_HATCH && cell) cell.forceMove(loc) cell = null - state = 4 + state = MECHA_BATTERY_UNSCREW to_chat(user, "You unscrew and pry out the powercell.") log_message("Powercell removed") - else if(state==4 && cell) - state=3 + else if(state == MECHA_BATTERY_UNSCREW && cell) + state = MECHA_OPEN_HATCH to_chat(user, "You screw the cell in place.") /obj/mecha/wrench_act(mob/user, obj/item/I) - if(state != 1 && state != 2) + if(state != MECHA_MAINT_ON && state != MECHA_BOLTS_UP) return . = TRUE if(!I.use_tool(src, user, 0, volume = I.tool_volume)) return - if(state==1) - state = 2 + if(state == MECHA_MAINT_ON) + state = MECHA_BOLTS_UP to_chat(user, "You undo the securing bolts.") else - state = 1 + state = MECHA_MAINT_ON to_chat(user, "You tighten the securing bolts.") /obj/mecha/welder_act(mob/user, obj/item/I) @@ -884,7 +884,7 @@ if(repairing) to_chat(user, "[src] is currently being repaired!") return - if(state == 0) // If maint protocols are not active, the state is zero + if(state == MECHA_MAINT_OFF) // If maint protocols are not active, the state is zero to_chat(user, "[src] can not be repaired without maintenance protocols active!") return WELDER_ATTEMPT_REPAIR_MESSAGE @@ -902,7 +902,7 @@ /obj/mecha/mech_melee_attack(obj/mecha/M) if(!has_charge(melee_energy_drain)) - return 0 + return FALSE use_power(melee_energy_drain) if(M.damtype == BRUTE || M.damtype == BURN) add_attack_logs(M.occupant, src, "Mecha-attacked with [M] ([uppertext(M.occupant.a_intent)]) ([uppertext(M.damtype)])") @@ -1068,11 +1068,11 @@ /obj/mecha/proc/connect(obj/machinery/atmospherics/unary/portables_connector/new_port) //Make sure not already connected to something else if(connected_port || !istype(new_port) || new_port.connected_device) - return 0 + return FALSE //Make sure are close enough for a valid connection if(new_port.loc != loc) - return 0 + return FALSE //Perform the connection connected_port = new_port @@ -1088,14 +1088,14 @@ /obj/mecha/proc/disconnect() if(!connected_port) - return 0 + return FALSE connected_port.connected_device = null connected_port = null log_message("Disconnected from gas port.") if(occupant) occupant.clear_alert("mechaport_d") - return 1 + return TRUE /obj/mecha/portableConnectorReturnAir() return internal_tank.return_air() @@ -1137,9 +1137,9 @@ if(dna) if(ishuman(user)) if(user.dna.unique_enzymes == dna) - passed = 1 + passed = TRUE else if(operation_allowed(user)) - passed = 1 + passed = TRUE if(!passed) to_chat(user, "Access denied.") log_append_to_last("Permission denied.") @@ -1213,7 +1213,7 @@ to_chat(user, "Access denied. [name] is secured with an ID lock.") return FALSE - if(do_after(user, 40, target = src)) + if(do_after(user, 4 SECONDS, target = src)) if(!occupant) return mmi_moved_inside(mmi_as_oc,user) else @@ -1261,8 +1261,8 @@ var/mob/living/brain/brain = occupant mob_container = brain.container if(istype(mob_container, /obj/item/mmi)) - return 1 - return 0 + return TRUE + return FALSE /obj/mecha/proc/pilot_mmi_hud(mob/living/brain/pilot) return @@ -1349,34 +1349,34 @@ return 0 for(var/ID in list(H.get_active_hand(), H.wear_id, H.belt, H.wear_pda)) if(check_access(ID, operation_req_access)) - return 1 - return 0 + return TRUE + return FALSE /obj/mecha/proc/internals_access_allowed(mob/living/carbon/human/H) for(var/atom/ID in list(H.get_active_hand(), H.wear_id, H.belt, H.wear_pda)) if(check_access(ID, internals_req_access)) - return 1 - return 0 + return TRUE + return FALSE /obj/mecha/check_access(obj/item/card/id/I, list/access_list) if(!istype(access_list)) - return 1 + return TRUE if(!length(access_list)) //no requirements - return 1 + return TRUE I = I?.GetID() if(!istype(I) || !I.access) //not ID or no access - return 0 + return FALSE if(access_list==operation_req_access) for(var/req in access_list) if(!(req in I.access)) //doesn't have this access - return 0 + return FALSE else if(access_list==internals_req_access) for(var/req in access_list) if(req in I.access) - return 1 - return 1 + return TRUE + return TRUE /////////////////////// ///// MARK: Power stuff @@ -1398,16 +1398,16 @@ cell.use(amount) if(occupant) update_cell() - return 1 - return 0 + return TRUE + return FALSE /obj/mecha/proc/give_power(amount) if(!isnull(get_charge())) cell.give(amount) if(occupant) update_cell() - return 1 - return 0 + return TRUE + return FALSE /obj/mecha/proc/update_cell() if(cell) diff --git a/code/game/mecha/mecha_topic.dm b/code/game/mecha/mecha_topic.dm index afdee42432d..c41573b8b44 100644 --- a/code/game/mecha/mecha_topic.dm +++ b/code/game/mecha/mecha_topic.dm @@ -327,19 +327,19 @@ if(!in_range(src, usr)) return var/mob/user = afilter.getMob("user") if(user) - if(state==0) - state = 1 + if(state == MECHA_MAINT_OFF) + state = MECHA_MAINT_ON to_chat(user, "The securing bolts are now exposed.") if(occupant) occupant.throw_alert("locked", /atom/movable/screen/alert/mech_maintenance) - else if(state==1) - state = 0 + else if(state == MECHA_MAINT_ON) + state = MECHA_MAINT_OFF to_chat(user, "The securing bolts are now hidden.") if(occupant) occupant.clear_alert("locked") output_maintenance_dialog(afilter.getObj("id_card"),user) return - if(href_list["set_internal_tank_valve"] && state >=1) + if(href_list["set_internal_tank_valve"] && state >= MECHA_MAINT_ON) if(!in_range(src, usr)) return var/mob/user = afilter.getMob("user") if(user) diff --git a/code/game/mecha/medical/odysseus.dm b/code/game/mecha/medical/odysseus.dm index 05d1d5c38ce..e8995cfd47c 100644 --- a/code/game/mecha/medical/odysseus.dm +++ b/code/game/mecha/medical/odysseus.dm @@ -1,5 +1,5 @@ /obj/mecha/medical/odysseus - desc = "These exosuits are developed and produced by Vey-Med. (© All rights reserved)." + desc = "These exosuits are developed and produced by DeForest Medical Corporation, for rescue operations." name = "Odysseus" icon_state = "odysseus" initial_icon = "odysseus" @@ -44,3 +44,12 @@ builtin_hud_user = 0 . = ..() + +/obj/mecha/medical/odysseus/examine_more(mob/user) + . = ..() + . += "The Odysseus is a relatively fast, lightweight, and easy-to-maintain exosuit developed by DeForest Medical Corporation. \ + Initially designed for patient rescue and care within hostile environments, it has seen semi-widespread use throughout the sector, usually by larger corporations and military groups who value its ability to get in and out of even the most rugged disaster zones." + . += "" + . += "DeForest has seen modest success from the Odysseus, with only minor complaints arising from its sluggish pace and lack of armor or defensive capabilities. \ + Despite these flaws, it has found a home amid Nanotrasen medical teams, where Paramedics find solid uses for it and its varied equipment loadout. \ + As with all station-side mechs, Nanotrasen has purchased the license to produce the Odysseus in their facilities." diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm index c1d333e8c4a..e894342853e 100644 --- a/code/game/mecha/working/ripley.dm +++ b/code/game/mecha/working/ripley.dm @@ -120,6 +120,16 @@ else if(drake_hides == DRAKE_HIDES_COVERED_SLIGHT) . += occupant ? "ripley-d" : "ripley-d-open" +/obj/mecha/working/ripley/examine_more(mob/user) + . = ..() + . += "The Ripley is a robust, venerable utility exosuit originally produced by Hephaestus Industries. \ + It now sees widespread use in and around the Orion sector, being one of the most pervasive mechs ever produced. \ + Shortly after initial production, Hephaestus licensed production rights for the Ripley to other corporations, earning royalties as the exosuit grew more popular." + . += "" + . += "Depending on the configuration, the Ripley can be used for many purposes, including mining, construction, and even goods transport. \ + To this day, it remains one of the most valuable mechs ever produced, and Hephaestus enjoys a substantial profit from sales of this aging but rugged design. \ + As with all station-side mechs, Nanotrasen has purchased the license to make the Ripley in their facilities." + /obj/mecha/working/ripley/firefighter desc = "A standard APLU chassis that was refitted with additional thermal protection and a cistern." name = "APLU \"Firefighter\"" @@ -133,6 +143,15 @@ max_equip = 5 // More armor, less tools wreckage = /obj/structure/mecha_wreckage/ripley/firefighter +/obj/mecha/working/ripley/firefighter/examine_more(mob/user) + ..() + . = list() + . += "Based on the venerable Ripley chassis, designed initially by Hephaestus Industries, the Firefighter is a retrofit created by Nanotrasen as their mining operations expanded, and a robust, fireproof exosuit was needed. \ + Adapted to fit heat-resistant shielding, the Firefighter became a popular mech for mining teams in dangerous environments." + . += "" + . += "Since Nanotrasen's expansion into Epsilon Eridani and their mining operations on Lavaland, the Firefighter has grown more popular among seasoned miners looking for a safer, armored way to mine in even the hottest of biomes. \ + Additionally, it has seen some use among atmospherics crews and is admired for its ability to control even the toughest of plasmafires while protecting its pilot." + /obj/mecha/working/ripley/deathripley desc = "OH SHIT IT'S THE DEATHSQUAD WE'RE ALL GONNA DIE" name = "DEATH-RIPLEY" @@ -155,6 +174,16 @@ ME.attach(src) return +/obj/mecha/working/ripley/deathripley/examine_more(mob/user) + ..() + . = list() + . += "A functioning, well-made collectable for the popular Nanotrasen-Funded holovid show, 'Deathsquad'. \ + A retrofitted and repainted Ripley chassis, the Death Ripley was created and used by the leader of the Deathsquad, Master Sergeant Killjoy, during the climactic battle with the Spider Queen “Xerxes” at the end of Season 4. \ + The mech bears the signature mark of the team's engineer, Corporal Ironhead, who assisted Killjoy in its construction." + . += "" + . += "Replicas such as this are sought-after collectibles among the biggest fans of Deathsquad. \ + An altercation even occurred where an individual dressed in a poorly-made Killjoy costume attempted to kill a collector to gain a Death Ripley, who was later sent to a mental institution after screaming, “THE DEATHSQUAD IS REAL." + /obj/mecha/working/ripley/mining desc = "An old, dusty mining ripley." name = "APLU \"Miner\"" diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm index f07d0243c18..1dd7548fd4f 100644 --- a/code/game/objects/effects/effect_system/effects_foam.dm +++ b/code/game/objects/effects/effect_system/effects_foam.dm @@ -177,7 +177,7 @@ var/metal = MFOAM_ALUMINUM /obj/structure/foamedmetal/Initialize() - ..() + . = ..() air_update_turf(1) /obj/structure/foamedmetal/Destroy() diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 5118c56e628..eb19e9b1395 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -253,8 +253,8 @@ blocks_emissive = FALSE /obj/item/flashlight/flare/glowstick/Initialize() + . = ..() light_color = color - ..() /obj/item/flashlight/flare/glowstick/update_icon_state() if(!fuel) diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index dbb4ecb723a..518ec0bc614 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -26,8 +26,8 @@ ..() internal_channels.Cut() -/obj/item/radio/headset/Initialize() - ..() +/obj/item/radio/headset/Initialize(mapload) + . = ..() if(ks1type) keyslot1 = new ks1type(src) diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index d8ff1d46d74..f2eb9da5007 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -174,6 +174,11 @@ else return ..() +/obj/item/radio/intercom/AltClick(mob/user) + . = ..() + if(broadcasting) + investigate_log("had its hotmic toggled on via hotkey by [key_name(user)].", INVESTIGATE_HOTMIC) ///Allows us to track who spams all these on if they do. + /obj/item/radio/intercom/crowbar_act(mob/user, obj/item/I) if(buildstage != 1) return @@ -245,7 +250,7 @@ underlays += emissive_appearance(icon, "intercom_lightmask") /obj/item/radio/intercom/proc/update_operating_status(on = TRUE) - if(!loc) // We init a few radios in nullspace to prevent them from needing power. + if(!loc) // We init a few radios in nullspace to prevent them from needing power. return var/area/current_area = get_area(src) if(on) diff --git a/code/game/objects/items/devices/radio/radio_objects.dm b/code/game/objects/items/devices/radio/radio_objects.dm index a26c5a126fa..f64a7fbb450 100644 --- a/code/game/objects/items/devices/radio/radio_objects.dm +++ b/code/game/objects/items/devices/radio/radio_objects.dm @@ -107,9 +107,8 @@ GLOBAL_LIST_EMPTY(deadsay_radio_systems) follow_target = null return ..() - -/obj/item/radio/Initialize() - ..() +/obj/item/radio/Initialize(mapload) + . = ..() if(frequency < RADIO_LOW_FREQ || frequency > RADIO_HIGH_FREQ) frequency = sanitize_frequency(frequency, RADIO_LOW_FREQ, RADIO_HIGH_FREQ) set_frequency(frequency) @@ -131,6 +130,14 @@ GLOBAL_LIST_EMPTY(deadsay_radio_systems) return ui_interact(user) +/obj/item/radio/AltClick(mob/user) + if(user.stat || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) || !Adjacent(user) || !istype(user)) + return + + ToggleBroadcast() + to_chat(user, "You [broadcasting ? "enable" : "disable"] [src]'s hotmic!") + add_fingerprint(user) + /obj/item/radio/ui_state(mob/user) return GLOB.default_state @@ -252,6 +259,8 @@ GLOBAL_LIST_EMPTY(deadsay_radio_systems) /obj/item/radio/proc/ToggleBroadcast() broadcasting = !broadcasting && !(wires.is_cut(WIRE_RADIO_TRANSMIT) || wires.is_cut(WIRE_RADIO_SIGNAL)) + if(broadcasting) + playsound(src, 'sound/items/radio_common.ogg', rand(4, 16) * 5, SOUND_RANGE_SET(3)) /obj/item/radio/proc/ToggleReception() listening = !listening && !(wires.is_cut(WIRE_RADIO_RECEIVER) || wires.is_cut(WIRE_RADIO_SIGNAL)) @@ -534,6 +543,7 @@ GLOBAL_LIST_EMPTY(deadsay_radio_systems) /obj/item/radio/examine(mob/user) . = ..() + . += "Alt-Click to toggle [src]'s hotmic!" if(in_range(src, user) || loc == user) if(b_stat) . += "\the [src] can be attached and modified!" diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 054dfa99020..5b040e8a28e 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -208,10 +208,10 @@ SLIME SCANNER continue msgs += "Warning: [D.form] detected\nName: [D.name].\nType: [D.spread_text].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure_text]" if(H.undergoing_cardiac_arrest()) - var/obj/item/organ/internal/heart/heart = H.get_int_organ(/obj/item/organ/internal/heart) - if(heart && !(heart.status & ORGAN_DEAD)) + var/datum/organ/heart/heart = H.get_int_organ_datum(ORGAN_DATUM_HEART) + if(heart && !(heart.linked_organ.status & ORGAN_DEAD)) msgs += "The patient's heart has stopped.\nPossible Cure: Electric Shock" - else if(heart && (heart.status & ORGAN_DEAD)) + else if(heart && (heart.linked_organ.status & ORGAN_DEAD)) msgs += "Subject's heart is necrotic." else if(!heart) msgs += "Subject has no heart." diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm index 53d367f3552..6c53d139848 100644 --- a/code/game/objects/items/stacks/nanopaste.dm +++ b/code/game/objects/items/stacks/nanopaste.dm @@ -18,7 +18,7 @@ if(R.getBruteLoss() || R.getFireLoss()) R.heal_overall_damage(15, 15) use(1) - user.visible_message("\The [user] applied some [src] at [R]'s damaged areas.",\ + user.visible_message("[user] applies some [src] at [R]'s damaged areas.",\ "You apply some [src] at [R]'s damaged areas.") else to_chat(user, "All [R]'s systems are nominal.") @@ -32,6 +32,28 @@ else to_chat(user, "[src] won't work on that.") +/obj/item/stack/nanopaste/afterattack(atom/A, mob/user, proximity_flag) + if(!ismecha(A) || user.a_intent == INTENT_HARM || !proximity_flag) + return + var/obj/mecha/mecha = A + if((mecha.obj_integrity >= mecha.max_integrity) && !mecha.internal_damage) + to_chat(user, "[mecha] is at full integrity!") + return + if(mecha.state == MECHA_MAINT_OFF) + to_chat(user, "[mecha] cannot be repaired without maintenance protocols active!") + return + if(mecha.repairing) + to_chat(user, "[mecha] is currently being repaired!") + return + if(mecha.internal_damage & MECHA_INT_TANK_BREACH) + mecha.clearInternalDamage(MECHA_INT_TANK_BREACH) + user.visible_message("[user] repairs the damaged air tank.", "You repair the damaged air tank.") + else if(mecha.obj_integrity < mecha.max_integrity) + mecha.obj_integrity += min(20, mecha.max_integrity - mecha.obj_integrity) + use(1) + user.visible_message("[user] applies some [src] to [mecha]'s damaged areas.",\ + "You apply some [src] to [mecha]'s damaged areas.") + /obj/item/stack/nanopaste/proc/robotic_limb_repair(mob/user, obj/item/organ/external/external_limb, mob/living/carbon/human/H) if(!external_limb.get_damage()) to_chat(user, "Nothing to fix here.") diff --git a/code/game/objects/items/tools/welder.dm b/code/game/objects/items/tools/welder.dm index 239d13fd9a7..afb690efa6e 100644 --- a/code/game/objects/items/tools/welder.dm +++ b/code/game/objects/items/tools/welder.dm @@ -35,7 +35,7 @@ var/progress_flash_divisor = 10 //Length of time between each "eye flash" /obj/item/weldingtool/Initialize(mapload) - ..() + . = ..() create_reagents(maximum_fuel) reagents.add_reagent("fuel", maximum_fuel) update_icon() @@ -149,7 +149,7 @@ /obj/item/weldingtool/attack(mob/living/carbon/M, mob/living/carbon/user) // For lighting other people's cigarettes. var/obj/item/clothing/mask/cigarette/cig = M?.wear_mask - if(!istype(cig) || user.zone_selected != "mouth" || !tool_enabled) + if(!istype(cig) || user.zone_selected != "mouth" || !tool_enabled) return ..() if(M == user) diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm index e3e6b5d0b43..f9a3c96d3dd 100644 --- a/code/game/objects/items/trash.dm +++ b/code/game/objects/items/trash.dm @@ -38,8 +38,9 @@ icon_state = "twimsts" /obj/item/trash/popcorn - name = "Popcorn" + name = "popcorn" icon_state = "popcorn" + gender = PLURAL /obj/item/trash/sosjerky name = "Scaredy's Private Reserve Beef Jerky" diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm index 481ca66e692..2431ae640c0 100644 --- a/code/game/objects/items/weapons/RCD.dm +++ b/code/game/objects/items/weapons/RCD.dm @@ -204,6 +204,13 @@ for(var/obj/structure/grille/grill_to_destroy in act_on) qdel(grill_to_destroy) +/datum/rcd_act/remove_user + mode = MODE_DECON + cost = 5 + start_message = "Deconstructing user..." + delay = 5 SECONDS + start_effect_type = /obj/effect/temp_visual/rcd_effect/reverse + /obj/item/rcd name = "rapid-construction-device (RCD)" desc = "A device used to rapidly build and deconstruct walls, floors and airlocks." @@ -243,6 +250,7 @@ var/door_name = "Airlock" /// If the glass airlock is polarized. var/electrochromic = FALSE + /// If the airlock will be created with glass so it can be seen through. var/airlock_glass = FALSE /// If this is TRUE, any airlocks that gets built will require only ONE of the checked accesses. If FALSE, it will require ALL of them. var/one_access = TRUE @@ -331,6 +339,32 @@ GLOB.rcd_list -= src return ..() +/obj/item/rcd/suicide_act(mob/living/user) + user.Immobilize(10 SECONDS) // You cannot move. + flags |= NODROP // You cannot drop. You commit to die. + var/turf/suicide_tile = get_turf(src) + if(mode == MODE_DECON) + user.visible_message("[user] points [src] at [user.p_their()] chest and pulls the trigger. It looks like [user.p_theyre()] trying to commit suicide!") + var/datum/rcd_act/remove_user/act = new() + if(!act.try_act(suicide_tile, src, user)) + flags &= ~NODROP + return SHAME + user.visible_message("[user] deconstructs [user.p_themselves()] with [src]!") + for(var/obj/item/W in user) // Do not delete all their stuff. + user.unEquip(W) // Dump everything on the floor instead. + flags &= ~NODROP // NODROP must be removed so the RCD doesn't get dusted along with them. Having this come after the unequipping puts the RCD on top of the pile of stuff. + user.dust() // (held items fall to the floor when dusting). + return OBLITERATION + + user.visible_message("[user] puts the barrel of [src] into [user.p_their()] mouth and pulls the trigger. It looks like [user.p_theyre()] trying to commit suicide!") + if(!afterattack(suicide_tile, user, TRUE)) + flags &= ~NODROP + return SHAME + user.visible_message("[user] explodes as [src] builds a structure inside [user.p_them()]!") + flags &= ~NODROP + user.gib() + return OBLITERATION + /** * Creates and returns a base64 icon of the given `airlock_type`. * diff --git a/code/game/objects/items/weapons/bio_chips/bio_chip_adrenalin.dm b/code/game/objects/items/weapons/bio_chips/bio_chip_adrenalin.dm index 67e06aad599..b4a3fa9bb00 100644 --- a/code/game/objects/items/weapons/bio_chips/bio_chip_adrenalin.dm +++ b/code/game/objects/items/weapons/bio_chips/bio_chip_adrenalin.dm @@ -19,7 +19,7 @@ SEND_SIGNAL(imp_in, COMSIG_LIVING_CLEAR_STUNS) imp_in.reagents.add_reagent("synaptizine", 10) - imp_in.reagents.add_reagent("omnizine", 10) + imp_in.reagents.add_reagent("omnizine_no_addiction", 10) imp_in.reagents.add_reagent("stimulative_agent", 10) if(!uses) qdel(src) diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index cc9c370b973..6f3f3baa23c 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -1034,7 +1034,7 @@ name = "Free Golem ID" desc = "A card used to claim mining points and buy gear. Use it to mark it as yours." icon_state = "research" - access = list(ACCESS_FREE_GOLEMS, ACCESS_ROBOTICS, ACCESS_CLOWN, ACCESS_MIME) //access to robots/mechs + access = list(ACCESS_FREE_GOLEMS, ACCESS_ROBOTICS, ACCESS_CLOWN, ACCESS_MIME, ACCESS_XENOBIOLOGY) //access to robots/mechs var/registered = FALSE /obj/item/card/id/golem/attack_self(mob/user as mob) diff --git a/code/game/objects/items/weapons/cigs.dm b/code/game/objects/items/weapons/cigs.dm index efd1ea57792..718851cda55 100644 --- a/code/game/objects/items/weapons/cigs.dm +++ b/code/game/objects/items/weapons/cigs.dm @@ -1,3 +1,5 @@ +#define REAGENT_TIME_RATIO 2.5 + /* CONTAINS: CIGARETTES @@ -502,7 +504,7 @@ LIGHTERS ARE IN LIGHTERS.DM return smoke() -/obj/item/clothing/mask/cigarette/pipe/attack_self(mob/user) //Refills the pipe. Can be changed to an attackby later, if loose tobacco is added to vendors or something. +/obj/item/clothing/mask/cigarette/pipe/attack_self(mob/user) // Extinguishes the pipe. if(lit) user.visible_message("[user] puts out [src].") lit = FALSE @@ -510,17 +512,27 @@ LIGHTERS ARE IN LIGHTERS.DM item_state = icon_off STOP_PROCESSING(SSobj, src) return - if(smoketime <= 0) - to_chat(user, "You refill the pipe with tobacco.") - reagents.add_reagent("nicotine", chem_volume) - smoketime = initial(smoketime) - first_puff = TRUE /obj/item/clothing/mask/cigarette/pipe/try_light(obj/item/cigar, obj/item/lighting_item) if(can_light_fancy(lighting_item)) return ..() +// Refill or light the pipe /obj/item/clothing/mask/cigarette/pipe/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/food/snacks/grown)) + var/obj/item/food/snacks/grown/O = I + if(O.dry) + if(reagents.total_volume == reagents.maximum_volume) + to_chat(user, "[src] is full!") + return + O.reagents.trans_to(src, chem_volume) + to_chat(user, "You stuff the [O.name] into the pipe.") + smoketime = max(reagents.total_volume * REAGENT_TIME_RATIO, smoketime) + qdel(O) + else + to_chat(user, "You need to dry this first!") + return + if(!is_type_in_typecache(I, things_that_light)) return if(can_light_fancy(I)) @@ -535,8 +547,9 @@ LIGHTERS ARE IN LIGHTERS.DM item_state = "cobpipeoff" icon_on = "cobpipeon" //Note - these are in masks.dmi icon_off = "cobpipeoff" - smoketime = 800 - chem_volume = 40 + smoketime = 0 //there is nothing to smoke initially + chem_volume = 160 + list_reagents = list() /////////// //ROLLING// @@ -569,3 +582,5 @@ LIGHTERS ARE IN LIGHTERS.DM to_chat(user, "You need to dry this first!") else ..() + +#undef REAGENT_TIME_RATIO diff --git a/code/game/objects/items/weapons/dna_injector.dm b/code/game/objects/items/weapons/dna_injector.dm index b2e1014bbb2..7958cd9dca8 100644 --- a/code/game/objects/items/weapons/dna_injector.dm +++ b/code/game/objects/items/weapons/dna_injector.dm @@ -20,8 +20,13 @@ var/value = 0 var/forcedmutation = FALSE //Will it give the mutation, guaranteed? -/obj/item/dnainjector/Initialize() +/obj/item/dnainjector/Initialize(mapload) . = ..() + + var/init_block = GetInitBlock() + if(init_block) + block = init_block + if(datatype && block) buf = new buf.dna = new @@ -29,6 +34,10 @@ buf.dna.ResetSE() SetValue(value) +// Override this with a var reference to do setup +/obj/item/dnainjector/proc/GetInitBlock() + return null + /obj/item/dnainjector/Destroy() QDEL_NULL(buf) return ..() @@ -157,9 +166,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/hulkmut/Initialize() - block = GLOB.hulkblock - ..() +/obj/item/dnainjector/hulkmut/GetInitBlock() + return GLOB.hulkblock /obj/item/dnainjector/antihulk name = "DNA-Injector (Anti-Hulk)" @@ -168,9 +176,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antihulk/Initialize() - block = GLOB.hulkblock - ..() +/obj/item/dnainjector/antihulk/GetInitBlock() + return GLOB.hulkblock /obj/item/dnainjector/firemut name = "DNA-Injector (Fire)" @@ -179,9 +186,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/firemut/Initialize() - block = GLOB.fireblock - ..() +/obj/item/dnainjector/firemut/GetInitBlock() + return GLOB.fireblock /obj/item/dnainjector/antifire name = "DNA-Injector (Anti-Fire)" @@ -190,9 +196,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antifire/Initialize() - block = GLOB.fireblock - ..() +/obj/item/dnainjector/antifire/GetInitBlock() + return GLOB.fireblock /obj/item/dnainjector/telemut name = "DNA-Injector (Tele.)" @@ -201,9 +206,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/telemut/Initialize() - block = GLOB.teleblock - ..() +/obj/item/dnainjector/telemut/GetInitBlock() + return GLOB.teleblock /obj/item/dnainjector/telemut/darkbundle name = "DNA injector" @@ -216,9 +220,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antitele/Initialize() - block = GLOB.teleblock - ..() +/obj/item/dnainjector/antitele/GetInitBlock() + return GLOB.teleblock /obj/item/dnainjector/nobreath name = "DNA-Injector (Breathless)" @@ -227,9 +230,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/nobreath/Initialize() - block = GLOB.breathlessblock - ..() +/obj/item/dnainjector/nobreath/GetInitBlock() + return GLOB.breathlessblock /obj/item/dnainjector/antinobreath name = "DNA-Injector (Anti-Breathless)" @@ -238,9 +240,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antinobreath/Initialize() - block = GLOB.breathlessblock - ..() +/obj/item/dnainjector/antinobreath/GetInitBlock() + return GLOB.breathlessblock /obj/item/dnainjector/remoteview name = "DNA-Injector (Remote View)" @@ -249,9 +250,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/remoteview/Initialize() - block = GLOB.remoteviewblock - ..() +/obj/item/dnainjector/remoteview/GetInitBlock() + return GLOB.remoteviewblock /obj/item/dnainjector/antiremoteview name = "DNA-Injector (Anti-Remote View)" @@ -260,9 +260,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antiremoteview/Initialize() - block = GLOB.remoteviewblock - ..() +/obj/item/dnainjector/antiremoteview/GetInitBlock() + return GLOB.remoteviewblock /obj/item/dnainjector/regenerate name = "DNA-Injector (Regeneration)" @@ -271,9 +270,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/regenerate/Initialize() - block = GLOB.regenerateblock - ..() +/obj/item/dnainjector/regenerate/GetInitBlock() + return GLOB.regenerateblock /obj/item/dnainjector/antiregenerate name = "DNA-Injector (Anti-Regeneration)" @@ -282,9 +280,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antiregenerate/Initialize() - block = GLOB.regenerateblock - ..() +/obj/item/dnainjector/antiregenerate/GetInitBlock() + return GLOB.regenerateblock /obj/item/dnainjector/morph name = "DNA-Injector (Morph)" @@ -293,9 +290,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/morph/Initialize() - block = GLOB.morphblock - ..() +/obj/item/dnainjector/morph/GetInitBlock() + return GLOB.morphblock /obj/item/dnainjector/antimorph name = "DNA-Injector (Anti-Morph)" @@ -304,9 +300,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antimorph/Initialize() - block = GLOB.morphblock - ..() +/obj/item/dnainjector/antimorph/GetInitBlock() + return GLOB.morphblock /obj/item/dnainjector/noprints name = "DNA-Injector (No Prints)" @@ -315,9 +310,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/noprints/Initialize() - block = GLOB.noprintsblock - ..() +/obj/item/dnainjector/noprints/GetInitBlock() + return GLOB.noprintsblock /obj/item/dnainjector/antinoprints name = "DNA-Injector (Anti-No Prints)" @@ -326,9 +320,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antinoprints/Initialize() - block = GLOB.noprintsblock - ..() +/obj/item/dnainjector/antinoprints/GetInitBlock() + return GLOB.noprintsblock /obj/item/dnainjector/insulation name = "DNA-Injector (Shock Immunity)" @@ -337,9 +330,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/insulation/Initialize() - block = GLOB.shockimmunityblock - ..() +/obj/item/dnainjector/insulation/GetInitBlock() + return GLOB.shockimmunityblock /obj/item/dnainjector/antiinsulation name = "DNA-Injector (Anti-Shock Immunity)" @@ -348,9 +340,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antiinsulation/Initialize() - block = GLOB.shockimmunityblock - ..() +/obj/item/dnainjector/antiinsulation/GetInitBlock() + return GLOB.shockimmunityblock /obj/item/dnainjector/midgit name = "DNA-Injector (Small Size)" @@ -359,9 +350,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/midgit/Initialize() - block = GLOB.smallsizeblock - ..() +/obj/item/dnainjector/midgit/GetInitBlock() + return GLOB.smallsizeblock /obj/item/dnainjector/antimidgit name = "DNA-Injector (Anti-Small Size)" @@ -370,9 +360,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antimidgit/Initialize() - block = GLOB.smallsizeblock - ..() +/obj/item/dnainjector/antimidgit/GetInitBlock() + return GLOB.smallsizeblock /obj/item/dnainjector/eatmut name = "DNA-Injector (Matter Eater)" @@ -381,9 +370,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/eatmut/Initialize() - block = GLOB.eatblock - return ..() +/obj/item/dnainjector/eatmut/GetInitBlock() + return GLOB.eatblock /obj/item/dnainjector/antieat name = "DNA-Injector (Anti-Matter Eater)" @@ -392,9 +380,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antieat/Initialize() - block = GLOB.eatblock - return ..() +/obj/item/dnainjector/antieat/GetInitBlock() + return GLOB.eatblock ///////////////////////////////////// /obj/item/dnainjector/antiglasses @@ -404,9 +391,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antiglasses/Initialize() - block = GLOB.glassesblock - ..() +/obj/item/dnainjector/antiglasses/GetInitBlock() + return GLOB.glassesblock /obj/item/dnainjector/glassesmut name = "DNA-Injector (Glasses)" @@ -415,9 +401,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/glassesmut/Initialize() - block = GLOB.glassesblock - ..() +/obj/item/dnainjector/glassesmut/GetInitBlock() + return GLOB.glassesblock /obj/item/dnainjector/epimut name = "DNA-Injector (Epi.)" @@ -426,9 +411,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/epimut/Initialize() - block = GLOB.epilepsyblock - ..() +/obj/item/dnainjector/epimut/GetInitBlock() + return GLOB.epilepsyblock /obj/item/dnainjector/antiepi name = "DNA-Injector (Anti-Epi.)" @@ -437,9 +421,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antiepi/Initialize() - block = GLOB.epilepsyblock - ..() +/obj/item/dnainjector/antiepi/GetInitBlock() + return GLOB.epilepsyblock /obj/item/dnainjector/anticough name = "DNA-Injector (Anti-Cough)" @@ -448,9 +431,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/anticough/Initialize() - block = GLOB.coughblock - ..() +/obj/item/dnainjector/anticough/GetInitBlock() + return GLOB.coughblock /obj/item/dnainjector/coughmut name = "DNA-Injector (Cough)" @@ -459,9 +441,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/coughmut/Initialize() - block = GLOB.coughblock - ..() +/obj/item/dnainjector/coughmut/GetInitBlock() + return GLOB.coughblock /obj/item/dnainjector/clumsymut name = "DNA-Injector (Clumsy)" @@ -470,9 +451,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/clumsymut/Initialize() - block = GLOB.clumsyblock - ..() +/obj/item/dnainjector/clumsymut/GetInitBlock() + return GLOB.clumsyblock /obj/item/dnainjector/anticlumsy name = "DNA-Injector (Anti-Clumy)" @@ -481,9 +461,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/anticlumsy/Initialize() - block = GLOB.clumsyblock - ..() +/obj/item/dnainjector/anticlumsy/GetInitBlock() + return GLOB.clumsyblock /obj/item/dnainjector/antitour name = "DNA-Injector (Anti-Tour.)" @@ -492,9 +471,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antitour/Initialize() - block = GLOB.twitchblock - ..() +/obj/item/dnainjector/antitour/GetInitBlock() + return GLOB.twitchblock /obj/item/dnainjector/tourmut name = "DNA-Injector (Tour.)" @@ -503,9 +481,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/tourmut/Initialize() - block = GLOB.twitchblock - ..() +/obj/item/dnainjector/tourmut/GetInitBlock() + return GLOB.twitchblock /obj/item/dnainjector/stuttmut name = "DNA-Injector (Stutt.)" @@ -514,9 +491,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/stuttmut/Initialize() - block = GLOB.nervousblock - ..() +/obj/item/dnainjector/stuttmut/GetInitBlock() + return GLOB.nervousblock /obj/item/dnainjector/antistutt @@ -526,9 +502,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antistutt/Initialize() - block = GLOB.nervousblock - ..() +/obj/item/dnainjector/antistutt/GetInitBlock() + return GLOB.nervousblock /obj/item/dnainjector/blindmut name = "DNA-Injector (Blind)" @@ -537,9 +512,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/blindmut/Initialize() - block = GLOB.blindblock - ..() +/obj/item/dnainjector/blindmut/GetInitBlock() + return GLOB.blindblock /obj/item/dnainjector/antiblind name = "DNA-Injector (Anti-Blind)" @@ -548,9 +522,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antiblind/Initialize() - block = GLOB.blindblock - ..() +/obj/item/dnainjector/antiblind/GetInitBlock() + return GLOB.blindblock /obj/item/dnainjector/deafmut name = "DNA-Injector (Deaf)" @@ -559,9 +532,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/deafmut/Initialize() - block = GLOB.deafblock - ..() +/obj/item/dnainjector/deafmut/GetInitBlock() + return GLOB.deafblock /obj/item/dnainjector/antideaf name = "DNA-Injector (Anti-Deaf)" @@ -570,9 +542,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antideaf/Initialize() - block = GLOB.deafblock - ..() +/obj/item/dnainjector/antideaf/GetInitBlock() + return GLOB.deafblock /obj/item/dnainjector/hallucination name = "DNA-Injector (Halluctination)" @@ -581,9 +552,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/hallucination/Initialize() - block = GLOB.hallucinationblock - ..() +/obj/item/dnainjector/hallucination/GetInitBlock() + return GLOB.hallucinationblock /obj/item/dnainjector/antihallucination name = "DNA-Injector (Anti-Hallucination)" @@ -592,9 +562,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/antihallucination/Initialize() - block = GLOB.hallucinationblock - ..() +/obj/item/dnainjector/antihallucination/GetInitBlock() + return GLOB.hallucinationblock /obj/item/dnainjector/h2m name = "DNA-Injector (Human > Monkey)" @@ -603,9 +572,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/h2m/Initialize() - block = GLOB.monkeyblock - ..() +/obj/item/dnainjector/h2m/GetInitBlock() + return GLOB.monkeyblock /obj/item/dnainjector/m2h name = "DNA-Injector (Monkey > Human)" @@ -614,9 +582,8 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/m2h/Initialize() - block = GLOB.monkeyblock - ..() +/obj/item/dnainjector/m2h/GetInitBlock() + return GLOB.monkeyblock /obj/item/dnainjector/comic @@ -626,9 +593,8 @@ value = 0xFFF forcedmutation = TRUE -/obj/item/dnainjector/comic/Initialize() - block = GLOB.comicblock - ..() +/obj/item/dnainjector/comic/GetInitBlock() + return GLOB.comicblock /obj/item/dnainjector/anticomic name = "DNA-Injector (Ant-Comic)" @@ -637,6 +603,5 @@ value = 0x001 forcedmutation = TRUE -/obj/item/dnainjector/anticomic/Initialize() - block = GLOB.comicblock - ..() +/obj/item/dnainjector/anticomic/GetInitBlock() + return GLOB.comicblock diff --git a/code/game/objects/items/weapons/storage/storage_base.dm b/code/game/objects/items/weapons/storage/storage_base.dm index cfb1b6015dc..ea3e086b3d6 100644 --- a/code/game/objects/items/weapons/storage/storage_base.dm +++ b/code/game/objects/items/weapons/storage/storage_base.dm @@ -199,12 +199,9 @@ orient2hud(user) // this only needs to happen to make .contents show properly as screen objects. if(user.s_active) user.s_active.hide_from(user) // If there's already an interface open, close it. - user.client.screen -= boxes - user.client.screen -= closer - user.client.screen -= contents - user.client.screen += boxes - user.client.screen += closer - user.client.screen += contents + user.client.screen |= boxes + user.client.screen |= closer + user.client.screen |= contents user.s_active = src LAZYDISTINCTADD(mobs_viewing, user) @@ -245,6 +242,9 @@ update_viewers() /obj/item/storage/proc/open(mob/user) + if(isobserver(user)) + show_to(user) + return if(use_sound && isliving(user)) playsound(loc, use_sound, 50, TRUE, -5) @@ -459,6 +459,10 @@ if(user) if(user.client && user.s_active != src) user.client.screen -= I + if(length(user.observers)) + for(var/mob/observer in user.observers) + if(observer.client && observer.s_active != src) + observer.client.screen -= I I.dropped(user, TRUE) add_fingerprint(user) diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index 460a227057d..629a85c2f09 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -565,7 +565,7 @@ origin_tech = "combat=4;bluespace=4;plasmatech=7" /obj/item/singularityhammer/Initialize(mapload) - ..() + . = ..() AddComponent(/datum/component/two_handed, \ force_wielded = 40, \ force_unwielded = force, \ @@ -634,7 +634,7 @@ origin_tech = "combat=4;powerstorage=7" /obj/item/mjollnir/Initialize(mapload) - ..() + . = ..() AddComponent(/datum/component/two_handed, \ force_wielded = 25, \ force_unwielded = force, \ diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index fd6d679e4e2..47e9c6ffdfd 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -237,7 +237,7 @@ /obj/structure/flora/ausbushes/ppflowers/Initialize(mapload) . = ..() - icon_state = "ppflowers_[rand(1, 4)]" + icon_state = "ppflowers_[rand(1, 3)]" /obj/structure/flora/ausbushes/sparsegrass icon_state = "sparsegrass_1" diff --git a/code/game/objects/structures/noticeboard.dm b/code/game/objects/structures/noticeboard.dm index eeb179d870d..83317b9d430 100644 --- a/code/game/objects/structures/noticeboard.dm +++ b/code/game/objects/structures/noticeboard.dm @@ -8,7 +8,7 @@ w_class = WEIGHT_CLASS_BULKY /obj/item/mounted/noticeboard/do_build(turf/on_wall, mob/user) - new /obj/structure/noticeboard(get_turf(user), get_dir(on_wall, user), building = TRUE) + new /obj/structure/noticeboard(get_turf(user), get_dir(on_wall, user), TRUE) qdel(src) /obj/structure/noticeboard @@ -21,21 +21,21 @@ max_integrity = 150 var/notices = 0 -/obj/structure/noticeboard/New(turf/loc, direction, building = FALSE) +/obj/structure/noticeboard/Initialize(mapload, direction, building = FALSE) . = ..() + if(building) setDir(direction) set_pixel_offsets_from_dir(-32, 32, -30, 30) update_icon(UPDATE_ICON_STATE) -/obj/structure/noticeboard/Initialize() - . = ..() for(var/obj/item/paper in loc) if(notices >= MAX_NOTICES) break if(istype(paper, /obj/item/paper)) paper.loc = src notices++ + update_icon(UPDATE_ICON_STATE) /obj/structure/noticeboard/update_icon_state() diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm index d3399770979..45159cb37c4 100644 --- a/code/game/objects/structures/plasticflaps.dm +++ b/code/game/objects/structures/plasticflaps.dm @@ -100,8 +100,8 @@ desc = "Heavy duty, airtight, plastic flaps." /obj/structure/plasticflaps/mining/Initialize() + . = ..() air_update_turf(TRUE) - ..() /obj/structure/plasticflaps/mining/Destroy() var/turf/T = get_turf(src) diff --git a/code/game/turfs/simulated/floor/misc_floor.dm b/code/game/turfs/simulated/floor/misc_floor.dm index 01452e74990..ba176cd0c8d 100644 --- a/code/game/turfs/simulated/floor/misc_floor.dm +++ b/code/game/turfs/simulated/floor/misc_floor.dm @@ -192,8 +192,10 @@ return if(!. && isliving(A)) - sleep(2 DECISECONDS) - new /obj/effect/temp_visual/ratvar/floor(src) + addtimer(CALLBACK(src, PROC_REF(spawn_visual)), 0.2 SECONDS, TIMER_DELETE_ME) + +/turf/simulated/floor/clockwork/proc/spawn_visual() + new /obj/effect/temp_visual/ratvar/floor(src) /turf/simulated/floor/clockwork/Destroy() if(uses_overlay && realappearence) diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index 61b11391ba6..050beadb770 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -246,8 +246,10 @@ return if(!. && isliving(A)) - sleep(2 DECISECONDS) - new /obj/effect/temp_visual/cult/turf/open/floor(src) + addtimer(CALLBACK(src, PROC_REF(spawn_visual)), 0.2 SECONDS, TIMER_DELETE_ME) + +/turf/simulated/floor/engine/cult/proc/spawn_visual() + new /obj/effect/temp_visual/cult/turf/open/floor(src) /turf/simulated/floor/engine/cult/narsie_act() return diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index d8465c69431..17b4c5e637f 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -581,27 +581,6 @@ /turf/AllowDrop() return TRUE -/** - * Returns adjacent turfs to this turf that are reachable, in all cardinal directions - * - * Arguments: - * * caller: The movable, if one exists, being used for mobility checks to see what tiles it can reach - * * ID: An ID card that decides if we can gain access to doors that would otherwise block a turf - * * simulated_only: Do we only worry about turfs with simulated atmos, most notably things that aren't space? - * * no_id: When true, doors with public access will count as impassible -*/ -/turf/proc/reachableAdjacentTurfs(caller, ID, simulated_only, no_id = FALSE) - var/static/space_type_cache = typecacheof(/turf/space) - . = list() - - for(var/iter_dir in GLOB.cardinal) - var/turf/turf_to_check = get_step(src, iter_dir) - if(!turf_to_check || (simulated_only && space_type_cache[turf_to_check.type])) - continue - if(turf_to_check.density || LinkBlockedWithAccess(turf_to_check, caller, ID, no_id = no_id)) - continue - . += turf_to_check - // Makes an image of up to 20 things on a turf + the turf /turf/proc/photograph(limit = 20) var/image/I = new() diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index baf89390823..b1f28b70a9a 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -12,6 +12,8 @@ GLOBAL_LIST_INIT(admin_verbs_admin, list( /client/proc/invisimin, /*allows our mob to go invisible/visible*/ /datum/admins/proc/announce, /*priority announce something to all clients.*/ /client/proc/admin_ghost, /*allows us to ghost/reenter body at will*/ + /client/proc/admin_observe, /*allows us to freely observe mobs */ + /client/proc/admin_observe_target, /*and gives it to us on right click*/ /client/proc/toggle_view_range, /*changes how far we can see*/ /client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/ /client/proc/cmd_admin_pm_panel, /*admin-pm list*/ @@ -170,7 +172,8 @@ GLOBAL_LIST_INIT(admin_verbs_debug, list( /client/proc/force_verb_bypass, /client/proc/show_gc_queues, /client/proc/debug_global_variables, - /client/proc/profile_code + /client/proc/profile_code, + /client/proc/debug_atom_init )) GLOBAL_LIST_INIT(admin_verbs_possess, list( /proc/possess, @@ -196,13 +199,17 @@ GLOBAL_LIST_INIT(admin_verbs_mod, list( /client/proc/dsay, /datum/admins/proc/show_player_panel, /client/proc/ban_panel, - /client/proc/debug_variables /*allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify*/ + /client/proc/debug_variables, /*allows us to -see- the variables of any instance in the game. +VAREDIT needed to modify*/ + /client/proc/admin_observe, + /client/proc/admin_observe_target, )) GLOBAL_LIST_INIT(admin_verbs_mentor, list( /client/proc/cmd_admin_pm_context, /*right-click adminPM interface*/ /client/proc/cmd_admin_pm_panel, /*admin-pm list*/ /client/proc/cmd_admin_pm_by_key_panel, /*admin-pm list by key*/ /client/proc/openMentorTicketUI, + /client/proc/admin_observe, /* Allow mentors to observe as well, though they face some limitations */ + /client/proc/admin_observe_target, /client/proc/cmd_mentor_say /* mentor say*/ // cmd_mentor_say is added/removed by the toggle_mentor_chat verb )) @@ -339,13 +346,22 @@ GLOBAL_LIST_INIT(view_runtimes_verbs, list( to_chat(src, "All of your adminverbs are now visible.") SSblackbox.record_feedback("tally", "admin_verb", 1, "Show Admin Verbs") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! -/client/proc/admin_ghost() - set category = "Admin" - set name = "Aghost" +/client/proc/mentor_ghost() + var/is_mentor = check_rights(R_MENTOR, FALSE) + var/is_full_admin = check_rights(R_ADMIN|R_MOD, FALSE) - if(!check_rights(R_ADMIN|R_MOD)) + if(!is_mentor && !is_full_admin) + to_chat(src, "You aren't allowed to use this!") return + // mentors are allowed only if they have the observe trait, which is given on observe. + // they should also not be given this proc. + if(!is_full_admin && (is_mentor && !HAS_MIND_TRAIT(mob, TRAIT_MENTOR_OBSERVING) || !is_mentor)) + return + + do_aghost() + +/client/proc/do_aghost() if(isobserver(mob)) //re-enter var/mob/dead/observer/ghost = mob @@ -372,6 +388,134 @@ GLOBAL_LIST_INIT(view_runtimes_verbs, list( // TODO: SStgui.on_transfer() to move windows from old and new SSblackbox.record_feedback("tally", "admin_verb", 1, "Aghost") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +/client/proc/admin_ghost() + set category = "Admin" + set name = "Aghost" + + if(!check_rights(R_ADMIN|R_MOD)) + return + + do_aghost() + +/// Allow an admin to observe someone. +/// mentors are allowed to use this verb while living, but with some stipulations: +/// if they attempt to do anything that would stop their orbit, they will immediately be returned to their body. +/client/proc/admin_observe() + set name = "Aobserve" + set category = "Admin" + if(!check_rights(R_ADMIN|R_MOD|R_MENTOR)) + return + + if(isnewplayer(mob)) + to_chat(src, "You cannot aobserve while in the lobby. Please join or observe first.") + return + + var/mob/target + + target = tgui_input_list(mob, "Select a mob to observe", "Aobserve", GLOB.player_list) + if(isnull(target)) + return + if(target == src) + to_chat(src, "You can't observe yourself!") + return + + if(isobserver(target)) + to_chat(src, "[target] is a ghost, and cannot be observed.") + return + + if(isnewplayer(target)) + to_chat(src, "[target] is in the lobby, and cannot be observed.") + return + + admin_observe_target(target) + +/client/proc/cleanup_admin_observe(mob/dead/observer/ghost) + if(!istype(ghost) || !ghost.mob_observed) + return FALSE + + // un-follow them + ghost.cleanup_observe() + // if it's a mentor, make sure they go back to their body. + if(HAS_TRAIT(mob.mind, TRAIT_MENTOR_OBSERVING)) + // handler will handle removing the trait + mob.stop_orbit() + log_admin("[key_name(src)] has de-activated Aobserve") + SSblackbox.record_feedback("tally", "admin_verb", 1, "Aobserve") + return TRUE + +/// targeted form of admin_observe: this should only appear in the right-click menu. +/client/proc/admin_observe_target(mob/target as mob in GLOB.mob_list) + set name = "\[Admin\] Aobserve" + set category = null + + if(!check_rights(R_ADMIN|R_MOD|R_MENTOR, mob)) + return + + var/full_admin = check_rights(R_ADMIN|R_MOD, FALSE, mob) + + if(isnewplayer(mob)) + to_chat(src, "You cannot aobserve while in the lobby. Please join or observe first.") + return + + if(isnewplayer(target)) + to_chat(src, "[target] is currently in the lobby.") + return + + if(isobserver(target)) + to_chat(src, "You can't observe a ghost.") + return + + if(cleanup_admin_observe(mob)) + return + + if(isnull(target) || target == src) + // let the default one find the target if there isn't one + admin_observe() + return + + // observers don't need to ghost, so we don't need to worry about adding any traits + if(isobserver(mob)) + var/mob/dead/observer/ghost = mob + SSblackbox.record_feedback("tally", "admin_verb", 1, "Aobserve") + ghost.do_observe(target) + return + + log_admin("[key_name(src)] has Aobserved out of their body to follow [target]") + do_aghost() + var/mob/dead/observer/ghost = mob + + if(!full_admin) + // if they're a me and they're alive, add the MENTOR_OBSERVINGtrait to ensure that they can only go back to their body. + // we need to handle this here because when you aghost, your mob gets set to the ghost. Oops! + ADD_TRAIT(mob.mind, TRAIT_MENTOR_OBSERVING, MENTOR_OBSERVING) + RegisterSignal(ghost, COMSIG_ATOM_ORBITER_STOP, PROC_REF(on_mentor_observe_end), override = TRUE) + to_chat(src, "You have temporarily observed [target], either move or observe again to un-observe.") + log_admin("[key_name(src)] has mobserved out of their body to follow [target].") + else + log_admin("[key_name(src)] is aobserving [target].") + + + ghost.do_observe(target) + +/client/proc/on_mentor_observe_end(atom/movable/us, atom/movable/orbited) + SIGNAL_HANDLER // COMSIG_ATOM_ORBITER_STOP + if(!isobserver(mob)) + log_and_message_admins("A mentor somehow managed to end observing while not being a ghost. Please investigate and notify coders.") + return + var/mob/dead/observer/ghost = mob + + // just to be safe + ghost.cleanup_observe() + + REMOVE_TRAIT(mob.mind, TRAIT_MENTOR_OBSERVING, MENTOR_OBSERVING) + UnregisterSignal(mob, COMSIG_ATOM_ORBITER_STOP) + + if(!ghost.reenter_corpse()) + // tell everyone since this is kinda nasty. + log_debug("Mentor [key_name_mentor(src)] was unable to re-enter their body after mentor observing.") + log_and_message_admins("[key_name_mentor(src)] was unable to re-enter their body after mentor observing.") + to_chat(src, "Unable to return you to your body after mentor ghosting. If your body still exists, please contact a coder, and you should probably ahelp.") + /client/proc/invisimin() set name = "Invisimin" set category = "Admin" diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index ca98106ea1b..3b33c728713 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -86,7 +86,8 @@ body += "PM - " body += "SM - " body += "FLW - " - body += "ALERT" + body += "ALERT - " + body += "OBS" if(eyeUID) body += "|EYE" body += "
" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index cdbce0a63d8..ba2d9b6432e 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1613,6 +1613,17 @@ show_player_panel(H) //H.regenerate_icons() + else if(href_list["adminobserve"]) + if(!check_rights(R_ADMIN|R_MOD|R_MENTOR)) + return + var/client/C = usr.client + var/mob/M = locateUID(href_list["adminobserve"]) + + if(!ismob(M)) + to_chat(usr, "This can only be used on instances of type /mob") + return + C.admin_observe_target(M) + else if(href_list["adminplayeropts"]) var/mob/M = locateUID(href_list["adminplayeropts"]) @@ -3586,3 +3597,5 @@ var/mob/dead/observer/O = target if(O.mind && O.mind.current) . += "|[ADMIN_FLW(O.mind.current,"BDY")]" + else if(ismob(target)) + . += "|[ADMIN_OBS(target, "OBS")]" diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index 1ee1e1ad547..f45f123f57d 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -86,28 +86,6 @@ if(alert("That player has been PM'd in the last [config.simultaneous_pm_warning_timeout / 10] seconds by: [C.ckey_last_pm]","Simultaneous PMs warning","Continue","Cancel") == "Cancel") return*/ - //get message text, limit it's length.and clean/escape html - if(!msg) - set_typing(C, TRUE) - msg = clean_input("Message:", "Private message to [holder ? key_name(C, FALSE) : key_name_hidden(C, FALSE)]", null, src) - set_typing(C, FALSE) - - if(!msg) - return - if(!C) - if(holder) - to_chat(src, "Error: Admin-PM: Client not found.") - else - adminhelp(msg) //admin we are replying to has vanished, adminhelp instead - return - - if(handle_spam_prevention(msg, MUTE_ADMINHELP, OOC_COOLDOWN)) - return - - // Let high-rank admins use advanced pencode. - if(check_rights(R_SERVER|R_DEBUG, 0)) - msg = admin_pencode_to_html(msg) - var/send_span var/receive_span var/send_pm_type = " " @@ -127,6 +105,41 @@ message_type = MESSAGE_TYPE_ADMINPM tickets_system = SStickets + //Check if the mob being PM'd has any open tickets. + var/list/tickets = tickets_system.checkForTicket(C, ticket_id) + if(!length(tickets)) + // If we didn't find a specific ticket by the target mob, we check for + // tickets by the source mob. + if(message_type == MESSAGE_TYPE_MENTORPM) + if(check_rights(R_ADMIN|R_MOD|R_MENTOR, 0, C.mob)) + tickets = SSmentor_tickets.checkForTicket(src) + else + if(check_rights(R_ADMIN|R_MOD, 0, C.mob)) + tickets = SStickets.checkForTicket(src) + + //get message text, limit it's length.and clean/escape html + if(!msg) + set_typing(C, TRUE) + tickets_system.refresh_tickets(tickets) + msg = clean_input("Message:", "Private message to [holder ? key_name(C, FALSE) : key_name_hidden(C, FALSE)]", null, src) + set_typing(C, FALSE) + + if(!msg) + tickets_system.refresh_tickets(tickets) + return + if(!C) + if(holder) + to_chat(src, "Error: Admin-PM: Client not found.") + else + adminhelp(msg) //admin we are replying to has vanished, adminhelp instead + return + + if(handle_spam_prevention(msg, MUTE_ADMINHELP, OOC_COOLDOWN)) + return + + // Let high-rank admins use advanced pencode. + if(check_rights(R_SERVER|R_DEBUG, 0)) + msg = admin_pencode_to_html(msg) if(holder) //PMs sent from admins and mods display their rank @@ -165,6 +178,7 @@ var/ping_link = check_rights(R_ADMIN, 0, mob) ? "(PING)" : "" var/ticket_link var/alert_link = check_rights(R_ADMIN, FALSE, mob) ? "(ALERT)" : "" + var/observe_link = check_rights(R_MENTOR, FALSE, mob) ? "([ADMIN_OBS(C, "OBS")])" : "" if(ticket_id != -1) if(message_type == MESSAGE_TYPE_MENTORPM) ticket_link = "(TICKET)" @@ -177,7 +191,7 @@ receive_window_link = ticket_link else if(message_type == MESSAGE_TYPE_ADMINPM && check_rights(R_ADMIN, 0, C.mob)) receive_window_link = ticket_link - receive_message = "[type] from-[receive_pm_type] [C.holder ? key_name(src, TRUE, type, ticket_id = ticket_id) : key_name_hidden(src, TRUE, type, ticket_id = ticket_id)]:

[emoji_msg][C.holder ? "
[ping_link] [receive_window_link] [alert_link]" : ""]
" + receive_message = "[type] from-[receive_pm_type] [C.holder ? key_name(src, TRUE, type, ticket_id = ticket_id) : key_name_hidden(src, TRUE, type, ticket_id = ticket_id)]:

[emoji_msg][C.holder ? "
[ping_link] [receive_window_link] [alert_link] [observe_link]" : ""]
" if(message_type == MESSAGE_TYPE_MENTORPM) receive_message = chat_box_mhelp(receive_message) else @@ -189,7 +203,7 @@ send_window_link = ticket_link else if(message_type == MESSAGE_TYPE_ADMINPM && check_rights(R_ADMIN, 0, mob)) send_window_link = ticket_link - var/send_message = "[send_pm_type][type] to-[holder ? key_name(C, TRUE, type, ticket_id = ticket_id) : key_name_hidden(C, TRUE, type, ticket_id = ticket_id)]:

[emoji_msg]

[ping_link] [send_window_link] [alert_link]" + var/send_message = "[send_pm_type][type] to-[holder ? key_name(C, TRUE, type, ticket_id = ticket_id) : key_name_hidden(C, TRUE, type, ticket_id = ticket_id)]:

[emoji_msg]

[ping_link] [send_window_link] [alert_link] [observe_link]" if(message_type == MESSAGE_TYPE_MENTORPM) send_message = chat_box_mhelp(send_message) else @@ -198,9 +212,9 @@ var/third_party_message if(message_type == MESSAGE_TYPE_MENTORPM) - third_party_message = chat_box_mhelp("[type]: [key_name(src, TRUE, type, ticket_id = ticket_id)]->[key_name(C, TRUE, type, ticket_id = ticket_id)]:

[emoji_msg]
[ping_link] [ticket_link] [alert_link]
") + third_party_message = chat_box_mhelp("[type]: [key_name(src, TRUE, type, ticket_id = ticket_id)]->[key_name(C, TRUE, type, ticket_id = ticket_id)]:

[emoji_msg]
[ping_link] [ticket_link] [alert_link] [observe_link]
") else - third_party_message = chat_box_ahelp("[type]: [key_name(src, TRUE, type, ticket_id = ticket_id)]->[key_name(C, TRUE, type, ticket_id = ticket_id)]:

[emoji_msg]
[ping_link] [ticket_link] [alert_link]
") + third_party_message = chat_box_ahelp("[type]: [key_name(src, TRUE, type, ticket_id = ticket_id)]->[key_name(C, TRUE, type, ticket_id = ticket_id)]:

[emoji_msg]
[ping_link] [ticket_link] [alert_link] [observe_link]
") //play the recieving admin the adminhelp sound (if they have them enabled) //non-admins always hear the sound, as they cannot toggle it @@ -224,22 +238,6 @@ if(check_rights(R_ADMIN|R_MOD, 0, X.mob)) to_chat(X, third_party_message, MESSAGE_TYPE_ADMINPM) - //Check if the mob being PM'd has any open tickets. - var/list/tickets = tickets_system.checkForTicket(C, ticket_id) - - if(length(tickets)) - tickets_system.addResponse(tickets, src, msg) - return - - // If we didn't find a specific ticket by the target mob, we check for - // tickets by the source mob. - if(message_type == MESSAGE_TYPE_MENTORPM) - if(check_rights(R_ADMIN|R_MOD|R_MENTOR, 0, C.mob)) - tickets = SSmentor_tickets.checkForTicket(src) - else - if(check_rights(R_ADMIN|R_MOD, 0, C.mob)) - tickets = SStickets.checkForTicket(src) - if(length(tickets)) tickets_system.addResponse(tickets, src, msg) @@ -288,7 +286,8 @@ return var/datum/pm_convo/convo = target.pm_tracker.pms[key] if(!convo) - return + convo = new /datum/pm_convo(src) + target.pm_tracker.pms[key] = convo convo.typing = value if(target.pm_tracker.open && target.pm_tracker.current_title == key) target.pm_tracker.show_ui(target.mob) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 47529556d96..f3ae480e707 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -928,7 +928,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention) return to_chat(src, "You can now right click to use inspect on browsers.") - winset(src, "", "browser-options=find,devtools") + winset(src, "", "browser-options=byondstorage,find,devtools") /client/proc/visualise_active_turfs() set category = "Debug" diff --git a/code/modules/antagonists/changeling/powers/contort_body.dm b/code/modules/antagonists/changeling/powers/contort_body.dm index 8d8e611ee85..fb6fa8252d7 100644 --- a/code/modules/antagonists/changeling/powers/contort_body.dm +++ b/code/modules/antagonists/changeling/powers/contort_body.dm @@ -8,20 +8,27 @@ category = /datum/changeling_power_category/utility /datum/action/changeling/contort_body/Remove(mob/M) - REMOVE_TRAIT(M, TRAIT_CONTORTED_BODY, CHANGELING_TRAIT) + deactivate() ..() /datum/action/changeling/contort_body/sting_action(mob/living/user) if(HAS_TRAIT_FROM(user, TRAIT_CONTORTED_BODY, CHANGELING_TRAIT)) - REMOVE_TRAIT(user, TRAIT_CONTORTED_BODY, CHANGELING_TRAIT) - to_chat(user, "Our body stiffens and returns to form.") - if(IS_HORIZONTAL(user)) - user.layer = initial(user.layer) - else - ADD_TRAIT(user, TRAIT_CONTORTED_BODY, CHANGELING_TRAIT) - to_chat(user, "We contort our form to allow us to fit in and under things we normally wouldn't be able to.") - if(IS_HORIZONTAL(user)) - user.layer = TURF_LAYER + 0.2 + deactivate(user) + return TRUE + + ADD_TRAIT(user, TRAIT_CONTORTED_BODY, CHANGELING_TRAIT) + RegisterSignal(user, COMSIG_MOB_DEATH, PROC_REF(deactivate)) + to_chat(user, "We contort our form to allow us to fit in and under things we normally wouldn't be able to.") + if(IS_HORIZONTAL(user)) + user.layer = TURF_LAYER + 0.2 SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("[name]")) return TRUE + +/datum/action/changeling/contort_body/proc/deactivate(mob/living/user) + REMOVE_TRAIT(user, TRAIT_CONTORTED_BODY, CHANGELING_TRAIT) + UnregisterSignal(user, COMSIG_MOB_DEATH) + if(IS_HORIZONTAL(user)) + user.layer = initial(user.layer) + to_chat(user, "Our body stiffens and returns to form.") + SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("[name]")) diff --git a/code/modules/antagonists/changeling/powers/summon_spiders.dm b/code/modules/antagonists/changeling/powers/summon_spiders.dm index abbd67db1b4..b9e0b3e4852 100644 --- a/code/modules/antagonists/changeling/powers/summon_spiders.dm +++ b/code/modules/antagonists/changeling/powers/summon_spiders.dm @@ -5,18 +5,17 @@ /datum/action/changeling/spiders name = "Spread Infestation" - desc = "Our form divides, creating an aggressive arachnid which will regard us as a friend. Costs 45 chemicals." - helptext = "The spiders are thoughtless creatures, but will not attack their creators. Requires at least 7 stored DNA. Their orders can be changed via remote hivemind (Alt+Shift click)." + desc = "Our form divides, creating an aggressive arachnid which will regard us as a friend. Costs 30 chemicals." + helptext = "The spiders are thoughtless creatures, but will not attack their creators. Their orders can be changed via remote hivemind (Alt+Shift click)." button_icon_state = "spread_infestation" - chemical_cost = 45 + chemical_cost = 30 dna_cost = 4 - req_dna = 7 /// This var keeps track of the changeling's spider count var/spider_counter = 0 /// Checks if changeling is already spawning a spider var/is_operating = FALSE power_type = CHANGELING_PURCHASABLE_POWER - category = /datum/changeling_power_category/utility + category = /datum/changeling_power_category/offence /// Makes a spider. Good for setting traps and combat. /datum/action/changeling/spiders/sting_action(mob/user) diff --git a/code/modules/atmospherics/machinery/components/binary_devices/binary_atmos_base.dm b/code/modules/atmospherics/machinery/components/binary_devices/binary_atmos_base.dm index 9ea2faff551..bff72287926 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/binary_atmos_base.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/binary_atmos_base.dm @@ -153,7 +153,3 @@ to_release.merge(air2.remove(shared_loss)) T.assume_air(to_release) air_update_turf(1) - -/obj/machinery/atmospherics/binary/process_atmos() - ..() - return parent1 && parent2 diff --git a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm index f485d115db3..41f09473a33 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm @@ -39,7 +39,6 @@ add_underlay(T, node2, dir) /obj/machinery/atmospherics/binary/passive_gate/process_atmos() - ..() if(!on) return 0 diff --git a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm index 3171bcf40da..5d335eab813 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm @@ -72,7 +72,6 @@ Thus, the two variables affect pump operation are set in New(): add_underlay(T, node2, dir) /obj/machinery/atmospherics/binary/pump/process_atmos() - ..() if((stat & (NOPOWER|BROKEN)) || !on) return 0 diff --git a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm index 4dbcc32e463..cce6166a223 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm @@ -68,7 +68,6 @@ Thus, the two variables affect pump operation are set in New(): add_underlay(T, node2, dir) /obj/machinery/atmospherics/binary/volume_pump/process_atmos() - ..() if((stat & (NOPOWER|BROKEN)) || !on) return 0 diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm index e90edf7cb6e..2588b232fd7 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm @@ -94,7 +94,6 @@ update_icon() /obj/machinery/atmospherics/trinary/filter/process_atmos() - ..() if(!on) return FALSE diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm index 12d84586b9c..6a714ae8262 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm @@ -79,7 +79,6 @@ air3.volume = 300 /obj/machinery/atmospherics/trinary/mixer/process_atmos() - ..() if(!on) return 0 diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/trinary_base.dm b/code/modules/atmospherics/machinery/components/trinary_devices/trinary_base.dm index f39509482c8..afb1c014e53 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/trinary_base.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/trinary_base.dm @@ -210,7 +210,3 @@ to_release.merge(air3.remove(shared_loss)) T.assume_air(to_release) air_update_turf(1) - -/obj/machinery/atmospherics/trinary/process_atmos() - ..() - return parent1 && parent2 && parent3 diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index 0fac7c4668c..a8e75f02e4a 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -178,7 +178,6 @@ return TRUE /obj/machinery/atmospherics/unary/cryo_cell/process_atmos() - ..() if(!node || !on) return diff --git a/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm b/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm index 15ef6b5437c..865dfc0baea 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm @@ -29,7 +29,6 @@ ..() /obj/machinery/atmospherics/unary/heat_exchanger/process_atmos() - ..() if(!partner) return 0 diff --git a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm index d800dc799bb..e7c6b839bd6 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm @@ -54,8 +54,6 @@ GLOBAL_LIST_EMPTY(air_injectors) update_icon() /obj/machinery/atmospherics/unary/outlet_injector/process_atmos() - ..() - injecting = FALSE if(!on || stat & NOPOWER) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/oxygen_generator.dm b/code/modules/atmospherics/machinery/components/unary_devices/oxygen_generator.dm index c043e75ff00..5b8b3e33ae8 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/oxygen_generator.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/oxygen_generator.dm @@ -25,7 +25,6 @@ air_contents.volume = 50 /obj/machinery/atmospherics/unary/oxygen_generator/process_atmos() - ..() if(!on) return 0 diff --git a/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm b/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm index 4468f0a662f..1381b56d71e 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm @@ -20,7 +20,6 @@ air_contents.volume = volume /obj/machinery/atmospherics/unary/passive_vent/process_atmos() - ..() if(!node) return 0 diff --git a/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm b/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm index b0e22bc8874..c3cfc1990b3 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm @@ -28,7 +28,6 @@ add_underlay(T, node, dir) /obj/machinery/atmospherics/unary/portables_connector/process_atmos() - ..() if(!connected_device) return 0 parent.update = 1 diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermal_plate.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermal_plate.dm index 9d145894e52..633f40704ba 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/thermal_plate.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/thermal_plate.dm @@ -18,8 +18,6 @@ icon_state = "[prefix]off" /obj/machinery/atmospherics/unary/thermal_plate/process_atmos() - ..() - var/datum/gas_mixture/environment = loc.return_air() //Get processable air sample and thermal info from environment diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm index f3ae2426a67..03039a7212d 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm @@ -93,7 +93,6 @@ /obj/machinery/atmospherics/unary/thermomachine/process_atmos() - ..() if(!on) return diff --git a/code/modules/atmospherics/machinery/components/unary_devices/unary_base.dm b/code/modules/atmospherics/machinery/components/unary_devices/unary_base.dm index 785c7538e7e..a6d766a3c47 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/unary_base.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/unary_base.dm @@ -99,7 +99,3 @@ var/datum/gas_mixture/to_release = air_contents.remove(lost) T.assume_air(to_release) air_update_turf(1) - -/obj/machinery/atmospherics/unary/process_atmos() - ..() - return parent diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm index cfa4bc99f71..7ec85af2152 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm @@ -110,7 +110,6 @@ update_underlays() /obj/machinery/atmospherics/unary/vent_pump/process_atmos() - ..() if(stat & (NOPOWER|BROKEN)) return FALSE var/turf/T = loc diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm index 7a61e3e142d..bc283f68098 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm @@ -100,8 +100,6 @@ check_turfs() /obj/machinery/atmospherics/unary/vent_scrubber/process_atmos() - ..() - if(widenet) check_turfs() diff --git a/code/modules/atmospherics/machinery/datum_pipeline.dm b/code/modules/atmospherics/machinery/datum_pipeline.dm index d5e091a5e1e..7a9fbf70f38 100644 --- a/code/modules/atmospherics/machinery/datum_pipeline.dm +++ b/code/modules/atmospherics/machinery/datum_pipeline.dm @@ -76,6 +76,7 @@ other_airs |= G /datum/pipeline/proc/addMember(obj/machinery/atmospherics/A, obj/machinery/atmospherics/N) + update = TRUE if(istype(A, /obj/machinery/atmospherics/pipe)) var/obj/machinery/atmospherics/pipe/P = A P.parent = src diff --git a/code/modules/atmospherics/machinery/other/meter.dm b/code/modules/atmospherics/machinery/other/meter.dm index a2cef4fc3f5..1d8b54b8111 100644 --- a/code/modules/atmospherics/machinery/other/meter.dm +++ b/code/modules/atmospherics/machinery/other/meter.dm @@ -27,15 +27,6 @@ GLOBAL_LIST_EMPTY(gas_meters) return ..() /obj/machinery/atmospherics/meter/process_atmos() - if(!target || (stat & (BROKEN|NOPOWER))) - update_icon(UPDATE_ICON_STATE) - return - - var/datum/gas_mixture/environment = target.return_air() - if(!environment) - update_icon(UPDATE_ICON_STATE) - return - update_icon(UPDATE_ICON_STATE) /obj/machinery/atmospherics/meter/update_icon_state() diff --git a/code/modules/atmospherics/machinery/pipes/manifold.dm b/code/modules/atmospherics/machinery/pipes/manifold.dm index 46f9f70323c..c8a59b5784c 100644 --- a/code/modules/atmospherics/machinery/pipes/manifold.dm +++ b/code/modules/atmospherics/machinery/pipes/manifold.dm @@ -70,12 +70,6 @@ /obj/machinery/atmospherics/pipe/manifold/pipeline_expansion() return list(node1, node2, node3) -/obj/machinery/atmospherics/pipe/manifold/process_atmos() - if(!parent) - ..() - else - . = PROCESS_KILL - /obj/machinery/atmospherics/pipe/manifold/Destroy() . = ..() diff --git a/code/modules/atmospherics/machinery/pipes/manifold4w.dm b/code/modules/atmospherics/machinery/pipes/manifold4w.dm index 3d547129f5f..000a6fb2190 100644 --- a/code/modules/atmospherics/machinery/pipes/manifold4w.dm +++ b/code/modules/atmospherics/machinery/pipes/manifold4w.dm @@ -28,12 +28,6 @@ /obj/machinery/atmospherics/pipe/manifold4w/pipeline_expansion() return list(node1, node2, node3, node4) -/obj/machinery/atmospherics/pipe/manifold4w/process_atmos() - if(!parent) - ..() - else - . = PROCESS_KILL - /obj/machinery/atmospherics/pipe/manifold4w/Destroy() . = ..() diff --git a/code/modules/awaymissions/loot.dm b/code/modules/awaymissions/loot.dm index faaeff82e9a..a0a1b472b71 100644 --- a/code/modules/awaymissions/loot.dm +++ b/code/modules/awaymissions/loot.dm @@ -22,4 +22,5 @@ continue new loot_path(get_turf(src)) - qdel(src) + + return INITIALIZE_HINT_QDEL diff --git a/code/modules/awaymissions/map_rng.dm b/code/modules/awaymissions/map_rng.dm deleted file mode 100644 index 598b46687f8..00000000000 --- a/code/modules/awaymissions/map_rng.dm +++ /dev/null @@ -1,51 +0,0 @@ -/obj/effect/landmark/map_loader - name = "map loader" - icon = 'icons/mob/screen_gen.dmi' - icon_state = "x2" - invisibility = 101 - anchored = TRUE - density = FALSE - opacity = FALSE - var/template_name = null - var/datum/map_template/template = null - var/centered = 1 - var/loaded = 0 - -/obj/effect/landmark/map_loader/New(turf/loc, tname) - ..() - - if(tname) - template_name = tname - if(template_name) - template = GLOB.map_templates[template_name] - -/obj/effect/landmark/map_loader/Initialize() - . = ..() - if(template) - load(template) - -/obj/effect/landmark/map_loader/set_tag() - return - -/obj/effect/landmark/map_loader/proc/load(datum/map_template/t) - if(!t) - return - if(loaded) // I wanna be super sure this loads only once - return - loaded = 1 - var/turf/pos = get_turf(src) - // Hop to nullspace so we don't get re-initialized by the map we're loading - loc = null - t.load(pos, centered = centered) - t.loaded++ - qdel(src) - -/obj/effect/landmark/map_loader/random - var/template_list = "" - -/obj/effect/landmark/map_loader/random/Initialize() - ..() - if(template_list) - template_name = safepick(splittext(template_list, ";")) - template = GLOB.map_templates[template_name] - load(template) diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 28575df9f21..73c0d726df4 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -257,6 +257,10 @@ //CONNECT// /////////// /client/New(TopicData) + // TODO: Remove with 516 + if(byond_version >= 516) // Enable 516 compat browser storage mechanisms + winset(src, "", "browser-options=byondstorage") + var/tdata = TopicData //save this for later use // Instantiate stat panel stat_panel = new(src, "statbrowser") @@ -1168,6 +1172,14 @@ else src << link(GLOB.configuration.system.region_map[choice]) +/client/proc/set_eye(new_eye) + if(new_eye == eye) + return + eye = new_eye + +/client/proc/clear_screen() + for(var/object in screen) + screen -= object /client/verb/reload_graphics() set category = "Special Verbs" diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index 490290d28db..b70aa66502e 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -120,7 +120,6 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 return ..() /obj/effect/immovablerod/smite/Move() - var/atom/oldloc = loc . = ..() if(get_turf(src) == get_turf(end)) // our exit condition: get outta there kowalski diff --git a/code/modules/events/prison_break.dm b/code/modules/events/prison_break.dm index 637dd3a254c..097961d2158 100644 --- a/code/modules/events/prison_break.dm +++ b/code/modules/events/prison_break.dm @@ -1,5 +1,5 @@ /datum/event/prison_break - startWhen = 5 + startWhen = 40 announceWhen = 75 var/releaseWhen = 60 @@ -37,7 +37,7 @@ /datum/event/prison_break/announce(false_alarm) if(length(areas) || false_alarm) - GLOB.minor_announcement.Announce("[pick("Gr3y.T1d3 virus","Malignant trojan")] detected in [station_name()] [(eventDept == "Security")? "imprisonment":"containment"] subroutines. Secure any compromised areas immediately. Station AI involvement is recommended.", "[eventDept] Alert") + GLOB.minor_announcement.Announce("[pick("Gr3y.T1d3 virus", "S.E.L.F program", "Malignant trojan", "Runtime error", "Cybersun worm", "[pick("Castle", "Felix", "Fractal", "Paradox", "Rubiks", "Portcullis", "Hammer", "Lockpick", "Faust", "Dream")][pick(" 2.0","")] Daemon")] detected in [station_name()] [(eventDept == "Security")? "imprisonment":"containment"] subroutines. Secure any compromised areas immediately. Station AI involvement is recommended.", "[eventDept] Alert") /datum/event/prison_break/start() for(var/area/A in world) @@ -46,12 +46,9 @@ if(areas && length(areas) > 0) var/my_department = "[station_name()] firewall subroutines" - var/rc_message = "An unknown malicious program has been detected in the [english_list(areaName)] lighting and airlock control systems at [station_time_timestamp()]. Systems will be fully compromised within approximately three minutes. Direct intervention is required immediately.
" + var/rc_message = "An unknown malicious program has been detected in the [english_list(areaName)] lighting and airlock control systems at [station_time_timestamp()]. Systems will be fully compromised within approximately one minute. Direct intervention is required immediately.
" for(var/obj/machinery/message_server/MS in GLOB.machines) MS.send_rc_message("Engineering", my_department, rc_message, "", "", 2) - for(var/mob/living/silicon/ai/A in GLOB.player_list) - to_chat(A, "Malicious program detected in the [english_list(areaName)] lighting and airlock control systems by [my_department].") - else stack_trace("Could not initiate grey-tide. Unable to find suitable containment area.") kill() diff --git a/code/modules/food_and_drinks/food/foods/misc_food.dm b/code/modules/food_and_drinks/food/foods/misc_food.dm index 7d5b6bcf6b0..ae9e946f60e 100644 --- a/code/modules/food_and_drinks/food/foods/misc_food.dm +++ b/code/modules/food_and_drinks/food/foods/misc_food.dm @@ -283,6 +283,7 @@ name = "popcorn" desc = "Now let's find some cinema." icon_state = "popcorn" + gender = PLURAL trash = /obj/item/trash/popcorn var/unpopped = 0 filling_color = "#FFFAD4" diff --git a/code/modules/food_and_drinks/kitchen_machinery/kitchen_machine.dm b/code/modules/food_and_drinks/kitchen_machinery/kitchen_machine.dm index 2058df28982..09e60e96ff3 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/kitchen_machine.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/kitchen_machine.dm @@ -440,6 +440,19 @@ if(dat) . += "It contains:
[dat]" + if(!HAS_MIND_TRAIT(user, TRAIT_KNOWS_COOKING_RECIPES)) + return + + if(locate(/obj/item/mixing_bowl) in contents) + . += "You can't see inside the mixing bowl, you're not sure what it would do." + return + + var/list/recipes = choose_recipes() + if(length(recipes) == 1 && recipes[1][2] != RECIPE_FAIL) + var/datum/recipe/recipe = recipes[1][2] + var/obj/item/result = recipe.result + . += "Your expert chef knowledge tells you that this would make \a [initial(result.name)]." + /obj/machinery/kitchen_machine/attack_hand(mob/user) if(stat & (BROKEN|NOPOWER) || panel_open || !anchored) return diff --git a/code/modules/library/book.dm b/code/modules/library/book.dm index 5fb95c5811d..02316f5a95c 100644 --- a/code/modules/library/book.dm +++ b/code/modules/library/book.dm @@ -361,7 +361,7 @@ /obj/item/book/random/Initialize() ..() - var/list/books = GLOB.library_catalog.get_random_book(amount) + var/list/books = GLOB.library_catalog.get_random_book(amount, FALSE) for(var/datum/cachedbook/book as anything in books) new /obj/item/book(loc, book, TRUE, FALSE) return INITIALIZE_HINT_QDEL diff --git a/code/modules/library/library_catalog.dm b/code/modules/library/library_catalog.dm index 6e351833ee9..84f097eeea8 100644 --- a/code/modules/library/library_catalog.dm +++ b/code/modules/library/library_catalog.dm @@ -309,13 +309,13 @@ * Arguments: * * datum/library_user_data/search_terms - datum with parameters for what we want to query our DB for */ -/datum/library_catalog/proc/get_total_books(datum/library_user_data/search_terms) +/datum/library_catalog/proc/get_total_books(datum/library_user_data/search_terms, async = TRUE) var/list/search_query = build_search_query(search_terms) var/sql = "SELECT COUNT(id) FROM library" + search_query[1] var/list/sql_params = search_query[2] var/datum/db_query/count_query = SSdbcore.NewQuery(sql, sql_params) - if(!count_query.warn_execute()) + if(!count_query.warn_execute(async)) qdel(count_query) return diff --git a/code/modules/library/library_computer.dm b/code/modules/library/library_computer.dm index 9e9741d1c78..02412fd6a04 100644 --- a/code/modules/library/library_computer.dm +++ b/code/modules/library/library_computer.dm @@ -558,13 +558,13 @@ book_data["categories"] += book_category.description //we're displaying the cats onlys, so we don't need the ids cached_booklist += list(book_data) - num_pages = getmaxpages() + num_pages = getmaxpages(async) archive_page_num = clamp(archive_page_num, 1, num_pages) ///Returns the amount of pages we will need to hold all the book our DB has found -/obj/machinery/computer/library/proc/getmaxpages() +/obj/machinery/computer/library/proc/getmaxpages(async = TRUE) //if get_total_books doesn't return anything, just set pages to 1 so we don't break stuff - var/book_count = max(1, GLOB.library_catalog.get_total_books(user_data)) + var/book_count = max(1, GLOB.library_catalog.get_total_books(user_data, async)) var/page_count = round(book_count / LIBRARY_BOOKS_PER_PAGE) //Since 'round' gets the floor value it's likely there will be 1 page more than //the page count amount (almost guaranteed), we check for a remainder because of this diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index b0abf709371..f003c6ecfc2 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -66,7 +66,7 @@ /obj/effect/mapping_helpers/Initialize(mapload) ..() - return late ? INITIALIZE_HINT_LATELOAD : qdel(src) // INITIALIZE_HINT_QDEL <-- Doesn't work + return late ? INITIALIZE_HINT_LATELOAD : INITIALIZE_HINT_QDEL /obj/effect/mapping_helpers/no_lava icon_state = "no_lava" diff --git a/code/modules/maze_generation/maze_generator.dm b/code/modules/maze_generation/maze_generator.dm index 04b72a6aca4..447017b4aa4 100644 --- a/code/modules/maze_generation/maze_generator.dm +++ b/code/modules/maze_generation/maze_generator.dm @@ -64,7 +64,6 @@ LOG_MAZE_PROGRESS(calculate_loot_spots(), "Loot Spot Calculation") LOG_MAZE_PROGRESS(apply_loot_modules(), "Loot Modules") log_debug("\[MAZE] Generation of maze at [x],[y],[z] complete within [stop_watch(total_time)]s") - qdel(src) /obj/effect/mazegen/generator/proc/generate_path() // Setup our turf list diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm index 49f7bbec1f1..94afc18e880 100644 --- a/code/modules/mining/equipment/survival_pod.dm +++ b/code/modules/mining/equipment/survival_pod.dm @@ -263,7 +263,7 @@ var/buildstackamount = 5 /obj/structure/fans/Initialize(loc) - ..() + . = ..() air_update_turf(1) /obj/structure/fans/Destroy() diff --git a/code/modules/mob/dead/observer/observer_base.dm b/code/modules/mob/dead/observer/observer_base.dm index 1cecdbfa03e..1a96a63de3e 100644 --- a/code/modules/mob/dead/observer/observer_base.dm +++ b/code/modules/mob/dead/observer/observer_base.dm @@ -20,6 +20,8 @@ GLOBAL_DATUM_INIT(ghost_crew_monitor, /datum/ui_module/crew_monitor/ghost, new) move_resist = INFINITY // don't get pushed around invisibility = INVISIBILITY_OBSERVER blocks_emissive = FALSE // Ghosts are transparent, duh + hud_type = /datum/hud/ghost + speaks_ooc = TRUE var/can_reenter_corpse var/bootime = FALSE var/started_as_observer //This variable is set to 1 when you enter the game as an observer. @@ -41,8 +43,8 @@ GLOBAL_DATUM_INIT(ghost_crew_monitor, /datum/ui_module/crew_monitor/ghost, new) var/datum/orbit_menu/orbit_menu /// The "color" their runechat would have had var/alive_runechat_color = "#FFFFFF" - hud_type = /datum/hud/ghost - speaks_ooc = TRUE + /// UID of the mob which we are currently observing + var/mob_observed /mob/dead/observer/New(mob/body=null, flags=1) set_invisibility(GLOB.observer_default_invisibility) @@ -120,6 +122,8 @@ GLOBAL_DATUM_INIT(ghost_crew_monitor, /datum/ui_module/crew_monitor/ghost, new) if(seerads) STOP_PROCESSING(SSobj, src) remove_observer_verbs() + if(mob_observed) + cleanup_observe() return ..() /mob/dead/observer/examine(mob/user) @@ -184,25 +188,37 @@ Works together with spawning an observer, noted above. return 1 /mob/proc/ghostize(flags = GHOST_CAN_REENTER, user_color, ghost_name) - if(key) - if(player_logged) //if they have disconnected we want to remove their SSD overlay - overlays -= image('icons/effects/effects.dmi', icon_state = "zzz_glow") - if(GLOB.non_respawnable_keys[ckey]) - flags &= ~GHOST_CAN_REENTER - var/mob/dead/observer/ghost = new(src, flags) //Transfer safety to observer spawning proc. - ghost.timeofdeath = src.timeofdeath //BS12 EDIT - if(ghost.can_reenter_corpse) - ADD_TRAIT(ghost, TRAIT_RESPAWNABLE, GHOSTED) - else - GLOB.non_respawnable_keys[ckey] = 1 - if(user_color) - add_atom_colour(user_color, ADMIN_COLOUR_PRIORITY) - ghost.color = user_color - if(ghost_name) - ghost.name = ghost_name - ghost.key = key - ghost.client?.init_verbs() - return ghost + if(!key) + return + if(player_logged) // if they have disconnected we want to remove their SSD overlay + overlays -= image('icons/effects/effects.dmi', icon_state = "zzz_glow") + if(GLOB.non_respawnable_keys[ckey]) + flags &= ~GHOST_CAN_REENTER + var/mob/dead/observer/ghost = new(src, flags) // Transfer safety to observer spawning proc. + ghost.timeofdeath = src.timeofdeath // BS12 EDIT + if(ghost.can_reenter_corpse) + ADD_TRAIT(ghost, TRAIT_RESPAWNABLE, GHOSTED) + else + GLOB.non_respawnable_keys[ckey] = 1 + + // mods, mentors, and the like will have admin observe anyway, so this is moot + if(((key in GLOB.antag_hud_users) || (key in GLOB.roundstart_observer_keys)) && !check_rights(R_MOD | R_ADMIN | R_MENTOR, FALSE, src)) + ghost.verbs |= /mob/dead/observer/proc/do_observe + ghost.verbs |= /mob/dead/observer/proc/observe + if(user_color) + add_atom_colour(user_color, ADMIN_COLOUR_PRIORITY) + ghost.color = user_color + if(ghost_name) + ghost.name = ghost_name + ghost.key = key + + ghost.client?.init_verbs() + + for(var/mob/dead/observer/obs in observers) + obs.cleanup_observe() + + + return ghost /* This is the proc mobs get to turn into a ghost. Forked from ghostize due to compatibility issues. @@ -492,52 +508,67 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp GLOB.ghost_crew_monitor.ui_interact(src) /mob/dead/observer/proc/add_observer_verbs() - verbs.Add(/mob/dead/observer/proc/ManualFollow) + verbs.Add( + /mob/dead/observer/proc/ManualFollow, + ) /mob/dead/observer/proc/remove_observer_verbs() - verbs.Remove(/mob/dead/observer/proc/ManualFollow) + verbs.Remove( + /mob/dead/observer/proc/ManualFollow, + // these might not necessarily be here, but we want to make sure they're gonezo anyway + /mob/dead/observer/proc/observe, + /mob/dead/observer/proc/do_observe + ) -// This is the ghost's follow verb with an argument +// This is the ghost's follow verb with an argument. +// We need to do the usr check on this verb itself, but the logic follows. /mob/dead/observer/proc/ManualFollow(atom/movable/target) set name = "\[Observer\] Orbit" set desc = "Orbits the specified movable atom." set category = null - if(!target || !isobserver(usr)) + // this usr check is apparently necessary for security + if(!isobserver(usr)) return + return do_manual_follow(target) + +// We need to check usr when calling the verb, but we still want this logic to be accessible elsewhere +/mob/dead/observer/proc/do_manual_follow(atom/movable/target) if(!get_turf(target)) return - if(target != src) - if(src in target.get_orbiters()) - return + if(!target || target == src) + return - var/icon/I = icon(target.icon,target.icon_state,target.dir) + if(src in target.get_orbiters()) + return - var/orbitsize = (I.Width()+I.Height())*0.5 + var/icon/I = icon(target.icon, target.icon_state, target.dir) - if(orbitsize == 0) - orbitsize = 40 + var/orbitsize = (I.Width() + I.Height())*0.5 - orbitsize -= (orbitsize/world.icon_size)*(world.icon_size*0.25) + if(orbitsize == 0) + orbitsize = 40 - var/rot_seg + orbitsize -= (orbitsize/world.icon_size)*(world.icon_size*0.25) - switch(ghost_orbit) - if(GHOST_ORBIT_TRIANGLE) - rot_seg = 3 - if(GHOST_ORBIT_SQUARE) - rot_seg = 4 - if(GHOST_ORBIT_PENTAGON) - rot_seg = 5 - if(GHOST_ORBIT_HEXAGON) - rot_seg = 6 - else //Circular - rot_seg = 36 //360/10 bby, smooth enough aproximation of a circle + var/rot_seg - to_chat(src, "Now following [target].") - orbit(target,orbitsize, FALSE, 20, rot_seg) + switch(ghost_orbit) + if(GHOST_ORBIT_TRIANGLE) + rot_seg = 3 + if(GHOST_ORBIT_SQUARE) + rot_seg = 4 + if(GHOST_ORBIT_PENTAGON) + rot_seg = 5 + if(GHOST_ORBIT_HEXAGON) + rot_seg = 6 + else // Circular + rot_seg = 36 // 360/10 bby, smooth enough aproximation of a circle + + to_chat(src, "Now following [target].") + orbit(target, orbitsize, FALSE, 20, rot_seg) /mob/dead/observer/orbit(atom/A, radius = 10, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, pre_rotation = TRUE, lock_in_orbit = FALSE, force_move = FALSE, orbit_layer = GHOST_LAYER) setDir(2)//reset dir so the right directional sprites show up @@ -825,5 +856,101 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp /mob/dead/observer/get_runechat_color() return alive_runechat_color +/mob/dead/observer/proc/observe() + set name = "Observe" + set desc = "Observe a mob." + set category = "Ghost" + + var/list/possible_targets = list() + for(var/mob/living/L in GLOB.player_list) + if(!L.mind) + continue + possible_targets.Add(L) + + if(!length(possible_targets)) + to_chat(src, "There's nobody for you to observe!") + return + + var/mob/target = tgui_input_list(usr, "Please, select a player!", "Observe", possible_targets) + if(!istype(target) || QDELETED(target)) + return + do_observe(target) + +/mob/dead/observer/proc/do_observe(mob/mob_eye) + set name = "\[Observer\] Observe" + set desc = "Observe the target mob." + set category = null + + if(isnewplayer(mob_eye)) + to_chat(src, "You can't observe someone in the lobby.") + return + + if(isobserver(mob_eye)) + to_chat(src, "You can't observe a ghost.") + return + + if(!mob_eye.mind) + to_chat(src, "You can only observe mobs that have been or are being inhabited by a player!") + return + + if(mob_eye == src) + to_chat(src, "You can't observe yourself!") + return + + if(mob_observed) + // clean up first + stop_orbit() + cleanup_observe() + + // Istype so we filter out points of interest that are not mobs + if(client && ismob(mob_eye)) + // follow the mob so they're technically right there for visible messages n stuff + // call the sub-proc since the base one checks for usr + do_manual_follow(mob_eye) + client.set_eye(mob_eye) + add_attack_logs(src, mob_eye, "observed", ATKLOG_ALMOSTALL) + client.perspective = EYE_PERSPECTIVE + if(mob_eye.hud_used) + client.clear_screen() + LAZYOR(mob_eye.observers, src) + mob_eye.hud_used?.show_hud(mob_eye.hud_used.hud_version, src) + mob_observed = mob_eye.UID() + + + // mentor observing grants you this trait, and provides its own signal handler for this + if(!HAS_MIND_TRAIT(src, TRAIT_MENTOR_OBSERVING)) + RegisterSignal(src, COMSIG_ATOM_ORBITER_STOP, PROC_REF(on_observer_orbit_end), override = TRUE) + else + if(!check_rights(R_MENTOR, FALSE, src)) + log_debug("[key_name(src)] has the the mobserve trait while observing, but isn't a mentor. This is likely an error, and may result in them getting stuck") + +/// Clean up observing +/mob/dead/observer/proc/cleanup_observe() + if(isnull(mob_observed)) + return + + var/mob/target = locateUID(mob_observed) + add_attack_logs(src, target, "un-observed", ATKLOG_ALL) + mob_observed = null + reset_perspective(null) + client?.perspective = initial(client.perspective) + set_sight(initial(sight)) + UnregisterSignal(src, COMSIG_ATOM_ORBITER_STOP) + + if(s_active) + var/obj/item/storage/bag = s_active + s_active = null + bag.update_viewers(src) + + if(!QDELETED(target) && istype(target)) + hide_other_mob_action_buttons(target) + target.observers -= src + +/mob/dead/observer/proc/on_observer_orbit_end(mob/follower, atom) + SIGNAL_HANDLER // COMSIG_ATOM_ORBITER_STOP + if(HAS_MIND_TRAIT(src, TRAIT_MENTOR_OBSERVING)) + log_debug("[key_name(src)] ended up in regular cleanup_observe rather than the mentor cleanup observe despite having TRAIT_MENTOR_OBSERVING. This is likely a bug and may result in them being stuck outside of their bodies.") + cleanup_observe() + #undef GHOST_CAN_REENTER #undef GHOST_IS_OBSERVER diff --git a/code/modules/mob/dead/observer/observer_logout.dm b/code/modules/mob/dead/observer/observer_logout.dm index 64ef90683c3..d6c1b6e96fb 100644 --- a/code/modules/mob/dead/observer/observer_logout.dm +++ b/code/modules/mob/dead/observer/observer_logout.dm @@ -1,6 +1,9 @@ /mob/dead/observer/Logout() if(client) client.images -= GLOB.ghost_images + if(mob_observed && ismob(locateUID(mob_observed))) + cleanup_observe() + ..() spawn(0) if(src && !key) //we've transferred to another mob. This ghost should be deleted. diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm index f174dd227ca..203b7ae10d4 100644 --- a/code/modules/mob/living/carbon/carbon_update_icons.dm +++ b/code/modules/mob/living/carbon/carbon_update_icons.dm @@ -49,6 +49,8 @@ r_hand.screen_loc = ui_rhand client.screen += r_hand + update_observer_view(r_hand) + /mob/living/carbon/update_inv_l_hand(ignore_cuffs) if(handcuffed && !ignore_cuffs) drop_l_hand() @@ -57,6 +59,7 @@ if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) l_hand.screen_loc = ui_lhand client.screen += l_hand + update_observer_view(l_hand) /mob/living/carbon/update_inv_wear_mask() if(istype(wear_mask, /obj/item/clothing/mask)) @@ -86,3 +89,17 @@ /mob/living/carbon/proc/update_hud_back(obj/item/I) return +/mob/living/carbon/proc/update_observer_view(obj/item/worn_item, inventory) + if(!length(observers)) + return + for(var/mob/dead/observe as anything in observers) + if(observe.client && observe.client.eye == src) + if(observe.hud_used) + if(inventory && !observe.hud_used.inventory_shown) + continue + observe.client.screen += worn_item + else + observers -= observe + if(!length(observers)) + observers.Cut() + break diff --git a/code/modules/mob/living/carbon/human/human_inventory.dm b/code/modules/mob/living/carbon/human/human_inventory.dm index 3b39a48a1f0..1ee19379c31 100644 --- a/code/modules/mob/living/carbon/human/human_inventory.dm +++ b/code/modules/mob/living/carbon/human/human_inventory.dm @@ -186,6 +186,13 @@ update_inv_r_hand() I.screen_loc = null + if(client) + client.screen -= I + if(length(observers)) + for(var/mob/dead/observe as anything in observers) + if(observe.client) + observe.client.screen -= I + I.forceMove(src) I.equipped(src, slot, initial) I.layer = ABOVE_HUD_LAYER @@ -271,8 +278,8 @@ var/obj/item/clothing/head/hat = I if(hat.vision_flags || hat.see_in_dark || !isnull(hat.lighting_alpha)) update_sight() + // this calls update_inv_head() on its own head_update(I) - update_inv_head() if(SLOT_HUD_SHOES) shoes = I update_inv_shoes() diff --git a/code/modules/mob/living/carbon/human/human_life.dm b/code/modules/mob/living/carbon/human/human_life.dm index b1aa99b34b0..67ac118cb07 100644 --- a/code/modules/mob/living/carbon/human/human_life.dm +++ b/code/modules/mob/living/carbon/human/human_life.dm @@ -767,19 +767,19 @@ if(reagents.has_reagent("formaldehyde")) //embalming fluid stops decay return - if(decaytime <= 6000) //10 minutes for decaylevel1 -- stinky + if(decaytime <= 8 MINUTES) return - if(decaytime > 6000 && decaytime <= 12000)//20 minutes for decaylevel2 -- bloated and very stinky + if(decaytime > 8 MINUTES) decaylevel = 1 - if(decaytime > 12000 && decaytime <= 18000)//30 minutes for decaylevel3 -- rotting and gross + if(decaytime > 16 MINUTES) decaylevel = 2 - if(decaytime > 18000 && decaytime <= 27000)//45 minutes for decaylevel4 -- skeleton + if(decaytime > 24 MINUTES) decaylevel = 3 - if(decaytime > 27000) + if(decaytime > 45 MINUTES) decaylevel = 4 makeSkeleton() return //No puking over skeletons, they don't smell at all! diff --git a/code/modules/mob/living/carbon/human/human_mob.dm b/code/modules/mob/living/carbon/human/human_mob.dm index eade62cabf0..dc78288d967 100644 --- a/code/modules/mob/living/carbon/human/human_mob.dm +++ b/code/modules/mob/living/carbon/human/human_mob.dm @@ -1967,3 +1967,67 @@ Eyes need to have significantly high darksight to shine unless the mob has the X set category = "IC" update_flavor_text() + +/mob/living/carbon/human/proc/expert_chef_knowledge() + if(!HAS_TRAIT(mind, TRAIT_KNOWS_COOKING_RECIPES)) + return + + var/list/possible_cookware = view(1, src) + + for(var/obj/item/storage/storage in possible_cookware) + possible_cookware += storage.contents + possible_cookware -= storage + + shuffle_inplace(possible_cookware) + + var/list/available_ingredients = list() + var/list/available_reagents = list() + for(var/obj/item/item in possible_cookware) + if(item.container_type == OPENCONTAINER && item.reagents) + for(var/datum/reagent/reagent in item.reagents.reagent_list) + if(!available_reagents[reagent.id]) + available_reagents[reagent.id] = 0 + available_reagents[reagent.id] += reagent.volume + else + if(!available_ingredients[item.type]) + available_ingredients[item.type] = 0 + available_ingredients[item.type] += 1 + + var/list/possible_recipes = list() + for(var/datum/recipe/recipe_type as anything in subtypesof(/datum/recipe)) + if(!recipe_type.result) + continue + var/datum/recipe/recipe = new recipe_type() + if(recipe.check_reagents_assoc_list(available_reagents) != INGREDIENT_CHECK_FAILURE && recipe.check_items_assoc_list(available_ingredients) != INGREDIENT_CHECK_FAILURE) + if(istype(recipe, /datum/recipe/microwave)) + possible_recipes[recipe] = RECIPE_MICROWAVE + else if(istype(recipe, /datum/recipe/oven)) + possible_recipes[recipe] = RECIPE_OVEN + else if(istype(recipe, /datum/recipe/grill)) + possible_recipes[recipe] = RECIPE_GRILL + else if(istype(recipe, /datum/recipe/candy)) + possible_recipes[recipe] = RECIPE_CANDY + else + possible_recipes[recipe] = "something? This shouldn't happen, make a bug report" + + if(!length(possible_recipes)) + to_chat(src, "You can't think of anything to cook with the items around you.") + return + + var/list/message = list("You draw upon your extensive experience in space food, contemplating what you could make with the items around you...") + for(var/datum/recipe/recipe in possible_recipes) + var/list/assoc = type_list_to_counted_assoc_list(recipe.items) + var/list/ingredient_list = list() + for(var/obj/item/path_key as anything in assoc) + ingredient_list += "[assoc[path_key]] [initial(path_key.name)]\s" + + var/list/required_reagents = list() + for(var/reagent_id in recipe.reagents) + var/datum/reagent/temp = GLOB.chemical_reagents_list[reagent_id] + if(temp) + required_reagents += "[recipe.reagents[reagent_id]] unit\s of [temp.name]" + + var/obj/item/result = recipe.result + message += "\tI could make [result.gender == PLURAL ? "some" : "a"] [bicon(result)] [result.name] by using \a [possible_recipes[recipe]] with [english_list(ingredient_list)][length(required_reagents) ? ", along with [english_list(required_reagents)]" : ""]." + qdel(recipe) + to_chat(src, chat_box_examine(message.Join("
"))) diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index feaad4085f9..c1109e078d1 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -567,10 +567,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) inv.update_icon() if(w_uniform && istype(w_uniform, /obj/item/clothing/under)) - if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) - if(hud_used.inventory_shown) //if the inventory is open ... - w_uniform.screen_loc = ui_iclothing //...draw the item in the inventory screen - client.screen += w_uniform //Either way, add the item to the HUD + update_hud_uniform(w_uniform) var/t_color = w_uniform.item_color if(!t_color) @@ -644,9 +641,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) inv.update_icon() if(wear_id) - if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) - wear_id.screen_loc = ui_id - client.screen += wear_id + update_hud_id(wear_id) if(w_uniform && w_uniform:displays_id) overlays_standing[ID_LAYER] = mutable_appearance('icons/mob/mob.dmi', "id", layer = -ID_LAYER) @@ -660,10 +655,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) inv.update_icon() if(gloves) - if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) - if(hud_used.inventory_shown) //if the inventory is open ... - gloves.screen_loc = ui_gloves //...draw the item in the inventory screen - client.screen += gloves //Either way, add the item to the HUD + update_hud_gloves(gloves) var/t_state = gloves.item_state if(!t_state) t_state = gloves.icon_state @@ -702,10 +694,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) if(glasses) var/mutable_appearance/new_glasses var/obj/item/organ/external/head/head_organ = get_organ("head") - if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) - if(hud_used.inventory_shown) //if the inventory is open ... - glasses.screen_loc = ui_glasses //...draw the item in the inventory screen - client.screen += glasses //Either way, add the item to the HUD + update_hud_glasses(glasses) if(glasses.icon_override) new_glasses = mutable_appearance(glasses.icon_override, "[glasses.icon_state]", layer = -GLASSES_LAYER) @@ -744,10 +733,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) if(l_ear || r_ear) if(l_ear) - if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) - if(hud_used.inventory_shown) //if the inventory is open ... - l_ear.screen_loc = ui_l_ear //...draw the item in the inventory screen - client.screen += l_ear //Either way, add the item to the HUD + update_hud_l_ear(l_ear) var/t_type = l_ear.item_state if(!t_type) @@ -761,10 +747,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) overlays_standing[EARS_LAYER] = mutable_appearance('icons/mob/clothing/ears.dmi', "[t_type]", layer = -EARS_LAYER) if(r_ear) - if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) - if(hud_used.inventory_shown) //if the inventory is open ... - r_ear.screen_loc = ui_r_ear //...draw the item in the inventory screen - client.screen += r_ear //Either way, add the item to the HUD + update_hud_r_ear(r_ear) var/t_type = r_ear.item_state if(!t_type) @@ -786,10 +769,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) inv.update_icon() if(shoes) - if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) - if(hud_used.inventory_shown) //if the inventory is open ... - shoes.screen_loc = ui_shoes //...draw the item in the inventory screen - client.screen += shoes //Either way, add the item to the HUD + update_hud_shoes(shoes) if(!wear_suit || !(wear_suit.flags_inv & HIDESHOES)) var/mutable_appearance/standing @@ -822,9 +802,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) inv.update_icon() if(s_store) - if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) - s_store.screen_loc = ui_sstore1 - client.screen += s_store + update_hud_s_store(s_store) var/t_state = s_store.item_state if(!t_state) @@ -844,6 +822,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) inv.update_icon() if(head) + update_hud_head(head) var/mutable_appearance/standing if(head.sprite_sheets && head.sprite_sheets[dna.species.sprite_sheet_name]) standing = mutable_appearance(head.sprite_sheets[dna.species.sprite_sheet_name], "[head.icon_state]", layer = -HEAD_LAYER) @@ -877,6 +856,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) belt.screen_loc = ui_belt if(belt) + update_observer_view(belt) var/t_state = belt.item_state if(!t_state) t_state = belt.icon_state @@ -899,10 +879,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) inv.update_icon() if(wear_suit && istype(wear_suit, /obj/item/clothing/suit)) - if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) - if(hud_used.inventory_shown) //if the inventory is open ... - wear_suit.screen_loc = ui_oclothing //TODO //...draw the item in the inventory screen - client.screen += wear_suit //Either way, add the item to the HUD + update_hud_wear_suit(wear_suit) var/mutable_appearance/standing if(wear_suit.sprite_sheets && wear_suit.sprite_sheets[dna.species.sprite_sheet_name]) @@ -950,12 +927,17 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) if(hud_used.hud_version == HUD_STYLE_STANDARD) if(l_store) - client.screen += l_store l_store.screen_loc = ui_storage1 + if(hud_used.hud_shown) + client.screen += l_store + update_observer_view(l_store) if(r_store) - client.screen += r_store r_store.screen_loc = ui_storage2 + if(hud_used.hud_shown) + client.screen += r_store + r_store.screen_loc = ui_storage2 + update_observer_view(r_store) /mob/living/carbon/human/update_inv_wear_pda() if(client && hud_used) @@ -964,8 +946,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) inv.update_icon() if(wear_pda) - client.screen += wear_pda - wear_pda.screen_loc = ui_pda + update_hud_wear_pda(wear_pda) /mob/living/carbon/human/update_inv_wear_mask() ..() @@ -975,6 +956,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) if(inv) inv.update_icon() if(wear_mask && (istype(wear_mask, /obj/item/clothing/mask) || istype(wear_mask, /obj/item/clothing/accessory))) + update_hud_wear_mask(wear_mask) if(!(SLOT_HUD_WEAR_MASK in check_obscured_slots())) var/obj/item/organ/external/head/head_organ = get_organ("head") if(!istype(head_organ)) @@ -1009,6 +991,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) ..() remove_overlay(BACK_LAYER) if(back) + update_hud_back(back) //determine the icon to use var/t_state = back.item_state if(!t_state) @@ -1045,6 +1028,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) ..() remove_overlay(R_HAND_LAYER) if(r_hand) + show_hand_to_observers(r_hand, left = FALSE) var/t_state = r_hand.item_state if(!t_state) t_state = r_hand.icon_state @@ -1064,6 +1048,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) ..() remove_overlay(L_HAND_LAYER) if(l_hand) + show_hand_to_observers(l_hand, left = TRUE) var/t_state = l_hand.item_state if(!t_state) t_state = l_hand.icon_state @@ -1080,25 +1065,105 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) //human HUD updates for items in our inventory -//update whether our head item appears on our hud. -/mob/living/carbon/human/update_hud_head(obj/item/I) - if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) - if(hud_used.inventory_shown) - I.screen_loc = ui_head - client.screen += I +/mob/living/carbon/human/proc/show_hand_to_observers(obj/item/worn_item, left = TRUE) + if(client && hud_used && hud_used.hud_version != HUD_STYLE_NOHUD) + worn_item.screen_loc = ui_hand_position(left ? 1 : 2) + client.screen += worn_item + if(length(observers)) + for(var/mob/dead/observe in observers) + if(observe.client && observe.client.eye == src) + observe.client.screen += worn_item + else + observers -= observe + if(!length(observers)) + observers = null + break -//update whether our mask item appears on our hud. -/mob/living/carbon/human/update_hud_wear_mask(obj/item/I) - if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) - if(hud_used.inventory_shown) - I.screen_loc = ui_mask - client.screen += I -//update whether our back item appears on our hud. -/mob/living/carbon/human/update_hud_back(obj/item/I) - if(client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) - I.screen_loc = ui_back - client.screen += I +/mob/living/carbon/human/update_hud_wear_mask(obj/item/worn_item) + worn_item.screen_loc = ui_mask + if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item, TRUE) + + +/mob/living/carbon/human/proc/update_hud_uniform(obj/item/worn_item) + worn_item.screen_loc = ui_iclothing + if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item, TRUE) + +/mob/living/carbon/human/proc/update_hud_id(obj/item/worn_item) + worn_item.screen_loc = ui_id + if(client && hud_used?.hud_shown && hud_used.hud_version == HUD_STYLE_STANDARD) + client.screen += worn_item + update_observer_view(worn_item) + +/mob/living/carbon/human/proc/update_hud_wear_pda(obj/item/worn_item) + worn_item.screen_loc = ui_pda + if(client && hud_used?.hud_shown && hud_used.hud_version == HUD_STYLE_STANDARD) + client.screen += worn_item + update_observer_view(worn_item) + +/mob/living/carbon/human/proc/update_hud_gloves(obj/item/worn_item) + worn_item.screen_loc = ui_gloves + if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item, TRUE) + +/mob/living/carbon/human/proc/update_hud_glasses(obj/item/worn_item) + worn_item.screen_loc = ui_glasses + if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item, TRUE) + +/mob/living/carbon/human/proc/update_hud_l_ear(obj/item/worn_item) + worn_item.screen_loc = ui_l_ear + if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item, TRUE) + +/mob/living/carbon/human/proc/update_hud_r_ear(obj/item/worn_item) + worn_item.screen_loc = ui_r_ear + if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item, TRUE) + +/mob/living/carbon/human/proc/update_hud_shoes(obj/item/worn_item) + worn_item.screen_loc = ui_shoes + if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item, TRUE) + +/mob/living/carbon/human/proc/update_hud_s_store(obj/item/worn_item) + worn_item.screen_loc = ui_sstore1 + if(client && hud_used?.hud_shown && hud_used.hud_version == HUD_STYLE_STANDARD) + client.screen += worn_item + update_observer_view(worn_item, TRUE) + +/mob/living/carbon/human/proc/update_hud_wear_suit(obj/item/worn_item) + worn_item.screen_loc = ui_oclothing + if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item, TRUE) + +/mob/living/carbon/human/proc/update_hud_belt(obj/item/worn_item) + belt.screen_loc = ui_belt + if(client && hud_used?.hud_shown && hud_used.hud_version == HUD_STYLE_STANDARD) + client.screen += worn_item + update_observer_view(worn_item, TRUE) + +/mob/living/carbon/human/update_hud_head(obj/item/worn_item) + worn_item.screen_loc = ui_head + if((client && hud_used && hud_used.hud_version == HUD_STYLE_STANDARD) && (hud_used.inventory_shown && hud_used.hud_shown)) + client.screen += worn_item + update_observer_view(worn_item, TRUE) + +/mob/living/carbon/human/update_hud_back(obj/item/worn_item) + worn_item.screen_loc = ui_back + if(client && hud_used?.hud_shown && hud_used.hud_version == HUD_STYLE_STANDARD) + client.screen += worn_item + update_observer_view(worn_item, TRUE) /mob/living/carbon/human/proc/update_wing_layer() remove_overlay(WING_UNDERLIMBS_LAYER) diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index 890b5209345..23e6ba4f0ab 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -64,7 +64,7 @@ if(mind && suiciding) mind.suicided = TRUE reset_perspective(null) - hud_used?.reload_fullscreen() + reload_fullscreen() update_sight() update_action_buttons_icon() ADD_TRAIT(src, TRAIT_FLOORED, STAT_TRAIT) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 1b6ddb47b94..803d724e524 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -118,6 +118,8 @@ if(a_intent == INTENT_HELP) // Help intent doesn't mob swap a mob pulling a structure if(isstructure(M.pulling) || isstructure(pulling)) return TRUE + //Let us check if the person has riot equipment. We should not move past them or push them, unless they are on *walk* intent. This is so officers batoning on help can't me moved past. + var/riot_equipment_used = (M.r_hand?.GetComponent(/datum/component/parry) || M.l_hand?.GetComponent(/datum/component/parry)) if(!M.buckled && !M.has_buckled_mobs()) var/mob_swap @@ -125,7 +127,7 @@ if(length(M.grabbed_by) && a_intent == INTENT_GRAB) mob_swap = TRUE //restrained people act if they were on 'help' intent to prevent a person being pulled from being seperated from their puller - else if((M.restrained() || M.a_intent == INTENT_HELP) && (restrained() || a_intent == INTENT_HELP)) + else if(((M.restrained() || M.a_intent == INTENT_HELP) && !(riot_equipment_used && M.m_intent == MOVE_INTENT_RUN)) && (restrained() || a_intent == INTENT_HELP)) mob_swap = TRUE if(mob_swap) //switch our position with M @@ -156,7 +158,7 @@ if(!(M.status_flags & CANPUSH)) return TRUE //anti-riot equipment is also anti-push - if(M.r_hand?.GetComponent(/datum/component/parry) || M.l_hand?.GetComponent(/datum/component/parry)) + if(riot_equipment_used) return TRUE //Called when we bump into an obj diff --git a/code/modules/mob/living/silicon/robot/drone/maint_drone.dm b/code/modules/mob/living/silicon/robot/drone/maint_drone.dm index bb04f17de68..c1dd8d1a197 100644 --- a/code/modules/mob/living/silicon/robot/drone/maint_drone.dm +++ b/code/modules/mob/living/silicon/robot/drone/maint_drone.dm @@ -147,9 +147,12 @@ /mob/living/silicon/robot/drone/examine(mob/user) . = ..() - . += "The ever-loyal workers of Nanotrasen facilities. Known for their small and cute look, these drones seek only to repair damaged parts of the station, being lawed against hurting even a spiderling. These fine drones are programmed against interfering with any business of anyone, so they won't do anything you don't want them to." if(isAntag(user)) - . += "Clearly they're not loyal enough however, use of an emag will slave them to you for 5 minutes... until they explode in a shower of sparks." + . += "Using an emag on this drone will slave them to you for 5 minutes... until they explode in a shower of sparks." + +/mob/living/silicon/robot/drone/examine_more(mob/user)//I know examine_more is for lore but the length of this description is too much + . = ..() + . += "The ever-loyal workers of Nanotrasen facilities. Known for their small and cute look, these drones seek only to repair damaged parts of the station, being lawed against hurting even a spiderling. These fine drones are programmed against interfering with any business of anyone, so they won't do anything you don't want them to." //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/I, mob/user, params) diff --git a/code/modules/mob/living/silicon/robot/robot_inventory.dm b/code/modules/mob/living/silicon/robot/robot_inventory.dm index 29cbd551747..78bf0e04a6d 100644 --- a/code/modules/mob/living/silicon/robot/robot_inventory.dm +++ b/code/modules/mob/living/silicon/robot/robot_inventory.dm @@ -15,6 +15,7 @@ O.mouse_opacity = MOUSE_OPACITY_OPAQUE + observer_screen_update(O, add = FALSE) if(client) client.screen -= O contents -= O @@ -78,6 +79,7 @@ set_actions(O) else to_chat(src, "You need to disable a module first!") + observer_screen_update(O, add = TRUE) check_module_damage(FALSE) update_icons() @@ -250,3 +252,25 @@ hands.icon_state = "nomod" else hands.icon_state = lowertext(module.module_type) + + +/** + * Updates the observers's screens with cyborg itemss. + * Arguments + * * item_module - the item being added or removed from the screen + * * add - whether or not the item is being added, or removed. + */ +/mob/living/silicon/robot/proc/observer_screen_update(obj/item/item_module, add = TRUE) + if(!length(observers)) + return + for(var/mob/dead/observe in observers) + if(observe.client && observe.client.eye == src) + if(add) + observe.client.screen += item_module + else + observe.client.screen -= item_module + else + observers -= observe + if(!length(observers)) + observers = null + break diff --git a/code/modules/mob/living/silicon/robot/robot_mob.dm b/code/modules/mob/living/silicon/robot/robot_mob.dm index d95d0d9d294..bb700a8d976 100644 --- a/code/modules/mob/living/silicon/robot/robot_mob.dm +++ b/code/modules/mob/living/silicon/robot/robot_mob.dm @@ -27,10 +27,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( var/atom/movable/screen/lamp_button = null var/atom/movable/screen/thruster_button = null - /// Used to determine whether the robot has the module menu shown or not. - var/shown_robot_modules = FALSE - var/atom/movable/screen/robot_modules_background - // 3 Modules can be activated at any one time. var/obj/item/robot_module/module = null var/module_active = null @@ -172,11 +168,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( wires = new(src) - robot_modules_background = new() - robot_modules_background.icon_state = "block" - robot_modules_background.layer = HUD_LAYER //Objects that appear on screen are on layer 20, UI should be just below it. - robot_modules_background.plane = HUD_PLANE - ident = rand(1, 999) rename_character(null, get_default_name()) update_icons() @@ -664,9 +655,6 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( /mob/living/silicon/robot/proc/reset_module() notify_ai(2) - - shown_robot_modules = 0 - client?.screen -= robot_modules_background client?.screen -= hud_used.module_store_icon uneq_all() SStgui.close_user_uis(src) @@ -699,6 +687,8 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( status_flags |= CANPUSH + hud_used.update_robot_modules_display() + //for borg hotkeys, here module refers to borg inv slot, not core module /mob/living/silicon/robot/verb/cmd_toggle_module(module as num) set name = "Toggle Module" diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 352c05b2808..9bb5db6aea7 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -398,7 +398,7 @@ //Preload Syringes /obj/item/gun/syringemalf/Initialize(mapload) - ..() + . = ..() chambered = new /obj/item/ammo_casing/syringegun(src) process_chamber() diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm index fa3ab06c3c7..70cb9eeecfb 100644 --- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm +++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm @@ -230,7 +230,7 @@ /mob/living/simple_animal/bot/cleanbot/ui_act(action, params) if(..()) return - if(topic_denied(usr)) + if(action != "area" && topic_denied(usr)) to_chat(usr, "[src]'s interface is not responding!") return add_fingerprint(usr) diff --git a/code/modules/mob/living/stat_states.dm b/code/modules/mob/living/stat_states.dm index 551eac92d1d..0698dd7bf79 100644 --- a/code/modules/mob/living/stat_states.dm +++ b/code/modules/mob/living/stat_states.dm @@ -75,7 +75,7 @@ update_blind_effects() update_sight() updatehealth("update revive") - hud_used?.reload_fullscreen() + reload_fullscreen() SEND_SIGNAL(src, COMSIG_LIVING_REVIVE, updating) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index b89bb7ec75a..489d8edacaf 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -27,6 +27,10 @@ viewing_alternate_appearances = null LAssailant = null runechat_msg_location = null + if(length(observers)) + for(var/mob/dead/observe as anything in observers) + observe.reset_perspective(null) + return ..() /mob/Initialize(mapload) @@ -600,7 +604,7 @@ GLOBAL_LIST_INIT(slot_equipment_priority, list( \ if(.) // Allows sharing HUDs with ghosts if(hud_used) - client.screen = list() + client.clear_screen() hud_used.show_hud(hud_used.hud_version) //mob verbs are faster than object verbs. See http://www.byond.com/forum/?post=1326139&page=2#comment8198716 for why this isn't atom/verb/examine() diff --git a/code/modules/mob/mob_vars.dm b/code/modules/mob/mob_vars.dm index 9f71bc02cfe..b46a1d29f4e 100644 --- a/code/modules/mob/mob_vars.dm +++ b/code/modules/mob/mob_vars.dm @@ -207,7 +207,7 @@ var/datum/input_focus = null /// Is our mob currently suiciding? Used for suicide code along with many different revival checks var/suiciding = FALSE - /// Used for some screen objects, such as + /// Used for some screen objects var/list/screens = list() /// lazy list. contains /atom/movable/screen/alert only, On /mob so clientless mobs will throw alerts properly var/list/alerts @@ -246,7 +246,8 @@ var/next_click_modifier = 1 /// Tracks the open UIs that a mob has, used in TGUI for various things, such as updating UIs var/list/open_uis = list() - + /// List of observers currently observing us. + var/list/mob/dead/observer/observers = list() /// Does this mob speak OOC? /// Controls whether they can say some symbols. var/speaks_ooc = FALSE diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index 9e354111a88..ecd4db10155 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -182,7 +182,10 @@ var/period_human_readable = "within [GLOB.configuration.general.roundstart_observer_period] minute\s" if(GLOB.configuration.general.roundstart_observer_period == 0) period_human_readable = "before the round started" - to_chat(src, "As you observed [period_human_readable], you can freely toggle antag-hud without losing respawnability.") + to_chat(src, "As you observed [period_human_readable], you can freely toggle antag-hud without losing respawnability, and can freely observe what other players see.") + if(!check_rights(R_MOD | R_ADMIN | R_MENTOR, FALSE, src)) + // admins always get aobserve + add_verb(observer, list(/mob/dead/observer/proc/do_observe, /mob/dead/observer/proc/observe)) observer.started_as_observer = 1 close_spawn_windows() var/obj/spawn_point diff --git a/code/modules/mod/modules/module_kinesis.dm b/code/modules/mod/modules/module_kinesis.dm index c2c9242fb40..070c1122d83 100644 --- a/code/modules/mod/modules/module_kinesis.dm +++ b/code/modules/mod/modules/module_kinesis.dm @@ -161,6 +161,8 @@ return FALSE if(iseffect(target)) return FALSE + if(locate(mod.wearer) in target) + return FALSE var/atom/movable/movable_target = target if(movable_target.anchored) return FALSE @@ -168,6 +170,8 @@ return FALSE if(movable_target.move_resist >= MOVE_FORCE_OVERPOWERING) return FALSE + if(locate(mod.wearer) in movable_target.buckled_mobs) + return FALSE if(ismob(movable_target)) if(!isliving(movable_target)) return FALSE diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm index ad8101088b0..215803c13d0 100644 --- a/code/modules/paperwork/filingcabinet.dm +++ b/code/modules/paperwork/filingcabinet.dm @@ -38,7 +38,7 @@ /obj/structure/filingcabinet/Initialize(mapload) - ..() + . = ..() for(var/obj/item/I in loc) if(istype(I, /obj/item/paper) || istype(I, /obj/item/folder) || istype(I, /obj/item/photo)) I.loc = src diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 6a3d492555a..f55701150fd 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -64,7 +64,7 @@ var/pen_colour_iconstate = "pencolor" /obj/item/pen/multi/Initialize(mapload) - ..() + . = ..() update_icon() /obj/item/pen/multi/proc/select_colour(mob/user as mob) diff --git a/code/modules/power/generators/turbine.dm b/code/modules/power/generators/turbine.dm index cd8a1078922..e81f4337882 100644 --- a/code/modules/power/generators/turbine.dm +++ b/code/modules/power/generators/turbine.dm @@ -18,7 +18,7 @@ // S CT * T - Turbine // * ^ * * V * D - Doors with firedoor // **|***D**|** ^ - Fuel feed (Not vent, but a gas outlet) -// | | V - Suction vent (Like the ones in atmos +// | | V - Suction vent (Like the ones in atmos) // #define OVERDRIVE 4 @@ -407,8 +407,10 @@ /obj/machinery/computer/turbine_computer/Initialize() ..() - spawn(10) - locate_machinery() + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/computer/turbine_computer/LateInitialize() + locate_machinery() /obj/machinery/computer/turbine_computer/proc/disconnect() //this disconnects the computer from the turbine, good for resets. diff --git a/code/modules/projectiles/ammunition/energy_lens.dm b/code/modules/projectiles/ammunition/energy_lens.dm index f1b453ec833..dc73c017b47 100644 --- a/code/modules/projectiles/ammunition/energy_lens.dm +++ b/code/modules/projectiles/ammunition/energy_lens.dm @@ -179,7 +179,7 @@ click_cooldown_override = 2 variance = 15 randomspread = 1 - delay = 2 + delay = 0 /// seperate balancing for cyborg, again /obj/item/ammo_casing/energy/disabler/cyborg diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index 77f5b742d2c..0c98f70adf6 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -76,6 +76,7 @@ ammo_type = list(/obj/item/ammo_casing/energy/disabler/smg) shaded_charge = TRUE can_holster = FALSE + fire_delay = 0 /obj/item/gun/energy/disabler/smg/Initialize(mapload) . = ..() diff --git a/code/modules/projectiles/guns/medbeam.dm b/code/modules/projectiles/guns/medbeam.dm index 815ad91cb34..945960fbb94 100644 --- a/code/modules/projectiles/guns/medbeam.dm +++ b/code/modules/projectiles/guns/medbeam.dm @@ -113,6 +113,8 @@ for(var/obj/item/organ/external/E in H.bodyparts) if(prob(10)) E.mend_fracture() + E.fix_internal_bleeding() + E.fix_burn_wound() else target.adjustBruteLoss(-4) target.adjustFireLoss(-4) diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm index c1d5716c536..2199b87e1b2 100644 --- a/code/modules/projectiles/guns/projectile/automatic.dm +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -336,6 +336,7 @@ can_suppress = FALSE burst_size = 1 execution_speed = 5 SECONDS + fire_delay = 0 /obj/item/gun/projectile/automatic/lasercarbine/Initialize(mapload) . = ..() diff --git a/code/modules/projectiles/guns/projectile/saw.dm b/code/modules/projectiles/guns/projectile/saw.dm index 587e65bf083..91a9eb677bd 100644 --- a/code/modules/projectiles/guns/projectile/saw.dm +++ b/code/modules/projectiles/guns/projectile/saw.dm @@ -16,6 +16,7 @@ can_suppress = FALSE burst_size = 1 spread = 7 + fire_delay = 0 /obj/item/gun/projectile/automatic/l6_saw/Initialize(mapload) . = ..() diff --git a/code/modules/projectiles/guns/syringe_gun.dm b/code/modules/projectiles/guns/syringe_gun.dm index c930fb9efa2..091b37dd56b 100644 --- a/code/modules/projectiles/guns/syringe_gun.dm +++ b/code/modules/projectiles/guns/syringe_gun.dm @@ -15,7 +15,7 @@ var/max_syringes = 1 /obj/item/gun/syringe/Initialize() - ..() + . = ..() chambered = new /obj/item/ammo_casing/syringegun(src) /obj/item/gun/syringe/process_chamber() diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm index c20c2c4cdaa..dc628655580 100644 --- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm +++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm @@ -423,7 +423,7 @@ var/recharge_rate = 1 // Keep this as an integer /obj/item/handheld_chem_dispenser/Initialize() - ..() + . = ..() cell = new(src) dispensable_reagents = sortList(dispensable_reagents) current_reagent = pick(dispensable_reagents) diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 67d620b2e7e..5a9b01f86a1 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -1,17 +1,7 @@ #define MAX_PILL_SPRITE 20 //max icon state of the pill sprites -#define MAX_UNITS_PER_PILL 100 // Max amount of units in a pill -#define MAX_UNITS_PER_PATCH 30 // Max amount of units in a patch -#define MAX_UNITS_PER_BOTTLE 50 // Max amount of units in a bottle #define MAX_CUSTOM_NAME_LEN 64 // Max length of a custom pill/condiment/whatever -#define CHEMMASTER_PRODUCTION_MODE_PILLS 1 -#define CHEMMASTER_PRODUCTION_MODE_PATCHES 2 -#define CHEMMASTER_PRODUCTION_MODE_BOTTLES 3 -#define CHEMMASTER_MIN_PRODUCTION_MODE 1 -#define CHEMMASTER_MAX_PRODUCTION_MODE 3 -#define CHEMMASTER_MAX_PILLS 20 -#define CHEMMASTER_MAX_PATCHES 20 -#define CHEMMASTER_MAX_BOTTLES 5 +#define CUSTOM_NAME_DISABLED null #define TRANSFER_TO_DISPOSAL 0 #define TRANSFER_TO_BEAKER 1 @@ -31,15 +21,7 @@ var/mode = TRANSFER_TO_BEAKER var/condi = FALSE var/useramount = 30 // Last used amount - var/pillamount = 10 - var/patchamount = 10 - var/bottleamount = 1 - var/pillname = "" - var/patchname = "" - var/bottlename = "" - var/bottlesprite = 1 - var/production_mode = CHEMMASTER_PRODUCTION_MODE_PILLS - var/pillsprite = 1 + var/production_mode = null var/printing = FALSE var/static/list/pill_bottle_wrappers = list( COLOR_RED = "Red", @@ -53,11 +35,7 @@ COLOR_PINK = "Pink", COLOR_MAROON = "Brown" ) - var/static/list/bottle_styles = list("bottle", "small_bottle", "wide_bottle", "round_bottle", "reagent_bottle") - var/list/safe_chem_list = list("antihol", "charcoal", "epinephrine", "insulin", "teporone", "silver_sulfadiazine", "salbutamol", - "omnizine", "stimulants", "synaptizine", "potass_iodide", "oculine", "mannitol", "styptic_powder", - "spaceacillin", "salglu_solution", "sal_acid", "cryoxadone", "blood", "synthflesh", "hydrocodone", - "mitocholide", "rezadone", "menthol", "diphenhydramine", "ephedrine", "iron", "sanguine_reagent") + var/list/datum/chemical_production_mode/production_modes = list() /obj/machinery/chem_master/Initialize(mapload) . = ..() @@ -70,6 +48,22 @@ component_parts += new /obj/item/reagent_containers/glass/beaker(null) RefreshParts() update_icon() + if(condi) + var/datum/chemical_production_mode/new_mode = new /datum/chemical_production_mode/condiment_packs() + production_modes[new_mode.mode_id] = new_mode + new_mode = new /datum/chemical_production_mode/condiment_bottles() + production_modes[new_mode.mode_id] = new_mode + else + var/datum/chemical_production_mode/new_mode = new /datum/chemical_production_mode/pills() + production_modes[new_mode.mode_id] = new_mode + new_mode = new /datum/chemical_production_mode/patches() + production_modes[new_mode.mode_id] = new_mode + new_mode = new /datum/chemical_production_mode/bottles() + production_modes[new_mode.mode_id] = new_mode + if(isnull(production_mode)) + for(var/key in production_modes) + production_mode = key + break /obj/machinery/chem_master/Destroy() QDEL_NULL(beaker) @@ -225,59 +219,44 @@ spawn(50) printing = FALSE if("set_production_mode") - var/new_mode = text2num(params["mode"]) - if(isnull(new_mode)) + var/new_production_mode = params["production_mode"] + var/datum/chemical_production_mode/M = production_modes[new_production_mode] + if(isnull(M)) return - production_mode = clamp(new_mode, CHEMMASTER_MIN_PRODUCTION_MODE, CHEMMASTER_MAX_PRODUCTION_MODE) + production_mode = new_production_mode - // Pills - if("set_pills_style") + if("set_sprite_style") + var/production_mode_key = params["production_mode"] + var/datum/chemical_production_mode/M = production_modes[production_mode_key] + if(isnull(M)) + return + if(!M.sprites) + return var/new_style = text2num(params["style"]) - if(isnull(new_style)) + if(!ISINDEXSAFE(M.sprites, new_style)) + return + M.set_sprite = new_style + if("set_items_amount") + var/production_mode_key = params["production_mode"] + var/datum/chemical_production_mode/M = production_modes[production_mode_key] + if(isnull(M)) return - pillsprite = clamp(new_style, 1, MAX_PILL_SPRITE) - if("set_pills_amount") var/new_amount = text2num(params["amount"]) - if(isnull(new_amount)) + if(isnull(new_amount) || new_amount < 1 || new_amount > M.max_items_amount) + return + M.set_items_amount = new_amount + if("set_items_name") + var/production_mode_key = params["production_mode"] + var/datum/chemical_production_mode/M = production_modes[production_mode_key] + if(isnull(M)) + return + if(M.set_name == CUSTOM_NAME_DISABLED) return - pillamount = clamp(new_amount, 1, CHEMMASTER_MAX_PILLS) - if("set_pills_name") var/new_name = sanitize(params["name"]) // Allow name to be set to empty if(length(new_name) < 0 || length(new_name) > MAX_CUSTOM_NAME_LEN) return - pillname = new_name - - // Patches - if("set_patches_amount") - var/new_amount = text2num(params["amount"]) - if(isnull(new_amount)) - return - patchamount = clamp(new_amount, 1, CHEMMASTER_MAX_PATCHES) - if("set_patches_name") - var/new_name = sanitize(params["name"]) - // Allow name to be set to empty - if(length(new_name) < 0 || length(new_name) > MAX_CUSTOM_NAME_LEN) - return - patchname = new_name - - // Bottles - if("set_bottles_style") - var/new_style = text2num(params["style"]) - if(isnull(new_style)) - return - bottlesprite = clamp(new_style, 1, length(bottle_styles)) - if("set_bottles_amount") - var/new_amount = text2num(params["amount"]) - if(isnull(new_amount)) - return - bottleamount = clamp(new_amount, 1, CHEMMASTER_MAX_BOTTLES) - if("set_bottles_name") - var/new_name = sanitize(params["name"]) - // Allow name to be set to empty - if(length(new_name) < 0 || length(new_name) > MAX_CUSTOM_NAME_LEN) - return - bottlename = new_name + M.set_name = new_name // Container Customization if("clear_container_style") @@ -325,81 +304,14 @@ beaker = null reagents.clear_reagents() update_icon() - if("create_condi_bottle") - if(!condi || !reagents.total_volume) + if("create_items") + if(!reagents.total_volume) return - var/obj/item/reagent_containers/condiment/P = new(loc) - reagents.trans_to(P, 50) - if("create_pills") - var/medicine_name = pillname - var/count = pillamount - var/amount_per_pill = clamp(reagents.total_volume / count, 0, MAX_UNITS_PER_PILL) - if(length(pillname) <= 0 || isnull(pillname)) - medicine_name = "[reagents.get_master_reagent_name()] ([amount_per_pill]u)" - - if(condi || !reagents.total_volume) + var/production_mode_key = params["production_mode"] + var/datum/chemical_production_mode/M = production_modes[production_mode_key] + if(isnull(M)) return - - for(var/i in 1 to count) - if(reagents.total_volume <= 0) - to_chat(ui.user, "Not enough reagents to create these pills!") - return - - var/obj/item/reagent_containers/pill/P = new(loc) - P.name = "[medicine_name] pill" - P.pixel_x = rand(-7, 7) // Random position - P.pixel_y = rand(-7, 7) - P.icon_state = "pill[pillsprite]" - reagents.trans_to(P, amount_per_pill) - // Load the pills in the bottle if there's one loaded - if(istype(loaded_pill_bottle) && loaded_pill_bottle.can_be_inserted(P, TRUE)) - P.forceMove(loaded_pill_bottle) - if("create_patches") - if(condi || !reagents.total_volume) - return - - var/medicine_name = patchname - var/count = patchamount - var/amount_per_patch = clamp(reagents.total_volume / count, 0, MAX_UNITS_PER_PATCH) - if(length(medicine_name) <= 0 || isnull(medicine_name)) - medicine_name = "[reagents.get_master_reagent_name()] ([amount_per_patch]u)" - var/is_medical_patch = chemical_safety_check(reagents) - for(var/i in 1 to count) - if(reagents.total_volume <= 0) - to_chat(ui.user, "Not enough reagents to create these patches!") - return - - var/obj/item/reagent_containers/patch/P = new(loc) - P.name = "[medicine_name] patch" - P.pixel_x = rand(-7, 7) // random position - P.pixel_y = rand(-7, 7) - reagents.trans_to(P, amount_per_patch) - if(is_medical_patch) - P.instant_application = TRUE - P.icon_state = "bandaid_med" - // Load the patches in the bottle if there's one loaded - if(istype(loaded_pill_bottle) && loaded_pill_bottle.can_be_inserted(P, TRUE)) - P.forceMove(loaded_pill_bottle) - if("create_bottles") - if(condi || !reagents.total_volume) - return - - var/medicine_name = bottlename - var/count = bottleamount - if(length(medicine_name) <= 0 || isnull(medicine_name)) - medicine_name = reagents.get_master_reagent_name() - var/amount_per_bottle = clamp(reagents.total_volume / count, 0, MAX_UNITS_PER_BOTTLE) - for(var/i in 1 to count) - if(reagents.total_volume <= 0) - to_chat(ui.user, "Not enough reagents to create these bottles!") - return - - var/obj/item/reagent_containers/glass/bottle/reagent/P = new(loc) - P.name = "[medicine_name] bottle" - P.pixel_x = rand(-7, 7) // random position - P.pixel_y = rand(-7, 7) - P.icon_state = length(bottle_styles) && bottle_styles[bottlesprite] || "bottle" - reagents.trans_to(P, amount_per_bottle) + M.synthesize(ui.user, loc, reagents, loaded_pill_bottle) else return FALSE @@ -434,9 +346,6 @@ data["condi"] = condi data["loaded_pill_bottle"] = loaded_pill_bottle ? TRUE : FALSE if(loaded_pill_bottle) - data["loaded_pill_bottle_name"] = loaded_pill_bottle.name - data["loaded_pill_bottle_contents_len"] = length(loaded_pill_bottle.contents) - data["loaded_pill_bottle_storage_slots"] = loaded_pill_bottle.storage_slots data["loaded_pill_bottle_style"] = loaded_pill_bottle.wrapper_color data["beaker"] = beaker ? TRUE : FALSE @@ -453,11 +362,21 @@ data["beaker_reagents"] = list() data["buffer_reagents"] = list() - data["pillamount"] = pillamount - data["patchamount"] = patchamount - data["bottleamount"] = bottleamount - data["pillsprite"] = pillsprite - data["bottlesprite"] = bottlesprite + var/production_data = list() + for(var/key in production_modes) + var/datum/chemical_production_mode/M = production_modes[key] + var/mode_data = list( + "set_items_amount" = M.set_items_amount, + ) + if(M.set_name != CUSTOM_NAME_DISABLED) + mode_data["set_name"] = M.set_name + if(reagents.total_volume) + mode_data["placeholder_name"] = M.get_placeholder_name(reagents) + if(M.sprites) + mode_data["set_sprite"] = M.set_sprite + production_data[M.mode_id] = mode_data + data["production_data"] = production_data + data["mode"] = mode data["printing"] = printing @@ -466,21 +385,6 @@ data["production_mode"] = production_mode - data["pillname"] = pillname - data["patchname"] = patchname - data["bottlename"] = bottlename - - data["maxpills"] = CHEMMASTER_MAX_PILLS - data["maxpatches"] = CHEMMASTER_MAX_PATCHES - data["maxbottles"] = CHEMMASTER_MAX_BOTTLES - - if(reagents.total_volume) - var/amount_per_pill = clamp(reagents.total_volume / pillamount, 0, MAX_UNITS_PER_PILL) - data["pillplaceholdername"] = "[reagents.get_master_reagent_name()] ([amount_per_pill]u)" - var/amount_per_patch = clamp(reagents.total_volume / patchamount, 0, MAX_UNITS_PER_PATCH) - data["patchplaceholdername"] = "[reagents.get_master_reagent_name()] ([amount_per_patch]u)" - data["bottleplaceholdername"] = reagents.get_master_reagent_name() - return data /obj/machinery/chem_master/ui_static_data(mob/user) @@ -488,23 +392,26 @@ data["maxnamelength"] = MAX_CUSTOM_NAME_LEN - var/pill_styles = list() - for(var/i in 1 to MAX_PILL_SPRITE) - pill_styles += list(list( - "id" = i, - "sprite" = "pill[i]", - )) - data["pillstyles"] = pill_styles - - var/bottle_styles_with_sprite = list() - var/bottle_style_indexer = 0 - for(var/style in bottle_styles) - bottle_style_indexer++ - bottle_styles_with_sprite += list(list( - "id" = bottle_style_indexer, - "sprite" = "[style]", - )) - data["bottlestyles"] = bottle_styles_with_sprite + var/static_production_data = list() + for(var/key in production_modes) + var/datum/chemical_production_mode/M = production_modes[key] + var/mode_data = list( + "name" = M.production_name, + "icon" = M.production_icon, + "max_items_amount" = M.max_items_amount, + "max_units_per_item" = M.max_units_per_item, + ) + if(M.sprites) + var/sprites = list() + var/indexer = 0 + for(var/sprite in M.sprites) + sprites += list(list( + "id" = ++indexer, + "sprite" = sprite, + )) + mode_data["sprites"] = sprites + static_production_data[M.mode_id] = mode_data + data["static_production_data"] = static_production_data var/pill_bottle_styles[0] for(var/style in pill_bottle_wrappers) @@ -554,10 +461,6 @@ if(!reagents.total_volume) return ui_modal_input(src, id, "Please enter the amount to transfer to [mode ? "beaker" : "disposal"]:", null, arguments, useramount) - if("create_condi_pack") - if(!condi || !reagents.total_volume) - return - ui_modal_input(src, id, "Please name your new condiment pack:", null, arguments, reagents.get_master_reagent_name(), MAX_CUSTOM_NAME_LEN) else return FALSE if(UI_MODAL_ANSWER) @@ -573,16 +476,6 @@ if(!amount || !arguments["id"]) return ui_act("remove", list("id" = arguments["id"], "amount" = amount), ui, state) - if("create_condi_pack") - if(!condi || !reagents.total_volume) - return - if(!length(answer)) - answer = reagents.get_master_reagent_name() - var/obj/item/reagent_containers/condiment/pack/P = new(loc) - P.originalname = answer - P.name = "[answer] pack" - P.desc = "A small condiment pack. The label says it contains [answer]." - reagents.trans_to(P, 10) else return FALSE else @@ -600,13 +493,6 @@ else return FALSE -/obj/machinery/chem_master/proc/chemical_safety_check(datum/reagents/R) - var/all_safe = TRUE - for(var/datum/reagent/A in R.reagent_list) - if(!safe_chem_list.Find(A.id)) - all_safe = FALSE - return all_safe - /obj/machinery/chem_master/condimaster name = "\improper CondiMaster 3000" desc = "Used to remove reagents from that single beaker you're using, or create condiment packs and bottles; your choice." @@ -622,20 +508,154 @@ component_parts += new /obj/item/reagent_containers/glass/beaker(null) RefreshParts() +/datum/chemical_production_mode + var/mode_id = "" + var/production_name = "" + /// FontAwesome icon name + var/production_icon = "" + var/obj/item/reagent_containers/item_type + var/list/sprites + var/max_items_amount = 0 + var/max_units_per_item = 0 + var/name_suffix = "" + + var/set_sprite = 1 + var/set_name = "" + var/set_items_amount = 1 + var/placeholder_name = "" + +/datum/chemical_production_mode/proc/get_placeholder_name(datum/reagents/reagents) + return get_base_placeholder_name(reagents, clamp(reagents.total_volume / set_items_amount, 0, max_units_per_item)) + +/datum/chemical_production_mode/proc/get_base_placeholder_name(datum/reagents/reagents, amount_per_item) + return "[reagents.get_master_reagent_name()] ([amount_per_item]u)" + +/** + public + + Configures the icon of the specified container P. + + required data Data persistent through invocations in the same loop. + required R The reagents used to make the item P. + required P The container to configure. +*/ +/datum/chemical_production_mode/proc/configure_item(data, datum/reagents/R, obj/item/reagent_containers/P) + if(sprites) + P.icon_state = sprites[set_sprite] + +/datum/chemical_production_mode/proc/synthesize(user, location, datum/reagents/reagents, obj/item/storage/S = null) + if(!reagents.total_volume) + return + + var/medicine_name = set_name + var/count = set_items_amount + var/amount_per_item = clamp(reagents.total_volume / count, 0, max_units_per_item) + if(!isnull(medicine_name) && length(medicine_name) <= 0) + medicine_name = get_base_placeholder_name(reagents, amount_per_item) + + var/data = list() + for(var/i in 1 to count) + if(reagents.total_volume <= 0) + to_chat(user, "Not enough reagents to create these items!") + return + + var/obj/item/reagent_containers/P = new item_type(location) + if(!isnull(medicine_name)) + P.name = "[medicine_name][name_suffix]" + P.pixel_x = rand(-7, 7) // Random position + P.pixel_y = rand(-7, 7) + reagents.trans_to(P, amount_per_item) + configure_item(data, reagents, P) + + // Load the items into the bottle if there's one loaded + if(istype(S) && S.can_be_inserted(P, TRUE)) + P.forceMove(S) + +/datum/chemical_production_mode/pills + mode_id = "pills" + production_name = "Pills" + production_icon = "pills" + item_type = /obj/item/reagent_containers/pill + max_items_amount = 20 + max_units_per_item = 100 + name_suffix = " pill" + +/datum/chemical_production_mode/pills/New() + . = ..() + sprites = list() + for(var/i = 1 to MAX_PILL_SPRITE) + sprites += list("pill[i]") + +/datum/chemical_production_mode/patches + mode_id = "patches" + production_name = "Patches" + production_icon = "plus-square" + item_type = /obj/item/reagent_containers/patch + max_items_amount = 20 + max_units_per_item = 30 + name_suffix = " patch" + + var/static/list/safe_chem_list = list("antihol", "charcoal", "epinephrine", "insulin", "teporone", "silver_sulfadiazine", "salbutamol", + "omnizine", "stimulants", "synaptizine", "potass_iodide", "oculine", "mannitol", "styptic_powder", + "spaceacillin", "salglu_solution", "sal_acid", "cryoxadone", "blood", "synthflesh", "hydrocodone", + "mitocholide", "rezadone", "menthol", "diphenhydramine", "ephedrine", "iron", "sanguine_reagent") + +/datum/chemical_production_mode/patches/proc/SafetyCheck(datum/reagents/R) + for(var/datum/reagent/A in R.reagent_list) + if(!safe_chem_list.Find(A.id)) + return FALSE + return TRUE + +/datum/chemical_production_mode/patches/configure_item(data, datum/reagents/R, obj/item/reagent_containers/patch/P) + var/chemicals_is_safe = data["chemicals_is_safe"] + + if(isnull(chemicals_is_safe)) + chemicals_is_safe = SafetyCheck(R) + data["chemicals_is_safe"] = chemicals_is_safe + + if(chemicals_is_safe) + P.instant_application = TRUE + P.icon_state = "bandaid_med" + +/datum/chemical_production_mode/bottles + mode_id = "chem_bottles" + production_name = "Bottles" + production_icon = "wine-bottle" + item_type = /obj/item/reagent_containers/glass/bottle/reagent + sprites = list("bottle", "small_bottle", "wide_bottle", "round_bottle", "reagent_bottle") + max_items_amount = 5 + max_units_per_item = 50 + name_suffix = " bottle" + +/datum/chemical_production_mode/bottles/get_base_placeholder_name(datum/reagents/reagents, amount_per_item) + return reagents.get_master_reagent_name() + +/datum/chemical_production_mode/condiment_bottles + mode_id = "condi_bottles" + production_name = "Bottles" + production_icon = "wine-bottle" + item_type = /obj/item/reagent_containers/condiment + max_items_amount = 5 + max_units_per_item = 50 + + set_name = CUSTOM_NAME_DISABLED + +/datum/chemical_production_mode/condiment_packs + mode_id = "condi_packets" + production_name = "Packet" + production_icon = "bacon" + item_type = /obj/item/reagent_containers/condiment/pack + max_items_amount = 10 + max_units_per_item = 10 + name_suffix = " pack" + +/datum/chemical_production_mode/condiment_packs/get_base_placeholder_name(datum/reagents/reagents, amount_per_item) + return reagents.get_master_reagent_name() + #undef MAX_PILL_SPRITE -#undef MAX_UNITS_PER_PILL -#undef MAX_UNITS_PER_PATCH -#undef MAX_UNITS_PER_BOTTLE #undef MAX_CUSTOM_NAME_LEN -#undef CHEMMASTER_PRODUCTION_MODE_PILLS -#undef CHEMMASTER_PRODUCTION_MODE_PATCHES -#undef CHEMMASTER_PRODUCTION_MODE_BOTTLES -#undef CHEMMASTER_MIN_PRODUCTION_MODE -#undef CHEMMASTER_MAX_PRODUCTION_MODE -#undef CHEMMASTER_MAX_PILLS -#undef CHEMMASTER_MAX_PATCHES -#undef CHEMMASTER_MAX_BOTTLES +#undef CUSTOM_NAME_DISABLED #undef TRANSFER_TO_DISPOSAL #undef TRANSFER_TO_BEAKER diff --git a/code/modules/reagents/chemistry/reagents/medicine.dm b/code/modules/reagents/chemistry/reagents/medicine.dm index eac48e6f390..962320c4628 100644 --- a/code/modules/reagents/chemistry/reagents/medicine.dm +++ b/code/modules/reagents/chemistry/reagents/medicine.dm @@ -3,7 +3,7 @@ id = "medicine" taste_description = "bitterness" harmless = TRUE - goal_department = "Medbay" + goal_department = "Chemistry" /datum/reagent/medicine/on_mob_life(mob/living/M) current_cycle++ @@ -467,6 +467,13 @@ M.Weaken(6 SECONDS) return list(effect, update_flags) +/datum/reagent/medicine/omnizine/no_addict + id = "omnizine_no_addiction" + overdose_threshold = 0 + addiction_chance = 0 + addiction_chance_additional = 100 + addiction_threshold = 0 + /datum/reagent/medicine/calomel name = "Calomel" id = "calomel" @@ -914,7 +921,6 @@ return if(!M.suiciding && !HAS_TRAIT(M, TRAIT_HUSK) && !HAS_TRAIT(M, TRAIT_BADDNA)) - var/time_dead = world.time - M.timeofdeath M.visible_message("[M] seems to rise from the dead!") M.adjustCloneLoss(50) M.setOxyLoss(0) @@ -923,12 +929,12 @@ M.adjustFireLoss(rand(0, 15)) if(ishuman(M)) var/mob/living/carbon/human/H = M + var/necrosis_prob = 15 * H.decaylevel H.decaylevel = 0 - var/necrosis_prob = 40 * min((20 MINUTES), max((time_dead - (1 MINUTES)), 0)) / ((20 MINUTES) - (1 MINUTES)) for(var/obj/item/organ/O in (H.bodyparts | H.internal_organs)) // Per non-vital body part: - // 0% chance of necrosis within 1 minute of death - // 40% chance of necrosis after 20 minutes of death + // 15% * H.decaylevel (1 to 4) + // Min of 0%, Max of 60% if(prob(necrosis_prob) && !O.is_robotic() && !O.vital) // side effects may include: Organ failure O.necrotize(FALSE) diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 5745bbb9542..be196f847af 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -98,9 +98,9 @@ . = ..() if(get_dist(user, src) && user == loc) . += "[round(reagents.total_volume)] units left." - . += "Alt-Click to empty it." + . += "Alt-Shift-Click to empty it." -/obj/item/reagent_containers/spray/AltClick(mob/user) +/obj/item/reagent_containers/spray/AltShiftClick(mob/user) if(user.stat || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) || !Adjacent(user)) return if(tgui_alert(user, "Are you sure you want to empty that?", "Empty Bottle", list("Yes", "No")) != "Yes") diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index b929547aa27..5caceeec130 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -436,6 +436,17 @@ build_path = /obj/item/organ/internal/cyberimp/arm/janitorial_abductor category = list("Medical") +/datum/design/cyberimp_surgical_abductor + name = "Abductor Surgical Toolset Implant" + desc = "An alien surgical toolset, designed to be installed on the subject's arm." + id = "ci-med-abductor" + req_tech = list("materials" = 6, "magnets" = 6, "biotech" = 6, "abductor" = 3) + build_type = PROTOLATHE | MECHFAB + materials = list(MAT_METAL = 20000, MAT_SILVER = 10000, MAT_PLASMA = 9000, MAT_TITANIUM = 8000, MAT_DIAMOND = 8000) + construction_time = 20 SECONDS + build_path = /obj/item/organ/internal/cyberimp/arm/surgical_abductor + category = list("Medical") + /datum/design/cyberimp_jani_hud name = "Janitor HUD Implant" desc = "These cybernetic eye implants will display a filth HUD over everything you see. Wiggle eyes to control." diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm index ce515e4ffe2..04d8ee6a358 100644 --- a/code/modules/research/experimentor.dm +++ b/code/modules/research/experimentor.dm @@ -68,8 +68,8 @@ if(initial(tempCheck.icon_state) != null) critical_items += I -/obj/machinery/r_n_d/experimentor/Initialize(mapload) - ..() +/obj/machinery/r_n_d/experimentor/Initialize(mapload) // DIEEEEEEEEEEEEEEEEEEEEEEE + . = ..() component_parts = list() component_parts += new /obj/item/circuitboard/experimentor(src) component_parts += new /obj/item/stock_parts/scanning_module(src) diff --git a/code/modules/research/server.dm b/code/modules/research/server.dm index cceda0d9ae6..0eb7290c88d 100644 --- a/code/modules/research/server.dm +++ b/code/modules/research/server.dm @@ -161,7 +161,7 @@ server_id = -1 /obj/machinery/r_n_d/server/centcom/Initialize() - ..() + . = ..() var/list/no_id_servers = list() var/list/server_ids = list() for(var/obj/machinery/r_n_d/server/S in GLOB.machines) diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm index 36343d811fa..1a7dd0f29ba 100644 --- a/code/modules/shuttle/emergency.dm +++ b/code/modules/shuttle/emergency.dm @@ -532,7 +532,7 @@ var/target_area = /area/mine/unexplored /obj/docking_port/stationary/random/Initialize() - ..() + . = ..() var/list/turfs = get_area_turfs(target_area) var/turf/T = pick(turfs) src.loc = T diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 12776a8ccea..95089f65910 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -808,6 +808,8 @@ var/admin_controlled var/max_connect_range = 7 var/moved = FALSE //workaround for nukie shuttle, hope I find a better way to do this... + /// Do we want to search for shuttle destinations as part of Initialize (fixed) or LateInitialize (variable) + var/find_destinations_in_late_init = FALSE /obj/machinery/computer/shuttle/New(location, obj/item/circuitboard/shuttle/C) ..() @@ -817,6 +819,12 @@ /obj/machinery/computer/shuttle/Initialize(mapload) . = ..() + if(find_destinations_in_late_init && mapload) // We only care about this in mapload, if its mid round its fine + return INITIALIZE_HINT_LATELOAD + + connect() + +/obj/machinery/computer/shuttle/LateInitialize() connect() /obj/machinery/computer/shuttle/proc/connect() @@ -952,27 +960,7 @@ circuit = /obj/item/circuitboard/white_ship shuttleId = "whiteship" possible_destinations = null // Set at runtime - -/obj/machinery/computer/shuttle/white_ship/Initialize(mapload) - if(mapload) - return INITIALIZE_HINT_LATELOAD - return ..() - -// Yes. This is disgusting, but the console needs to be loaded AFTER the docking ports load. -/obj/machinery/computer/shuttle/white_ship/LateInitialize() - Initialize() - -/obj/machinery/computer/shuttle/engineering - name = "Engineering Shuttle Console" - desc = "Used to call and send the engineering shuttle." - shuttleId = "engineering" - possible_destinations = "engineering_home;engineering_away" - -/obj/machinery/computer/shuttle/science - name = "Science Shuttle Console" - desc = "Used to call and send the science shuttle." - shuttleId = "science" - possible_destinations = "science_home;science_away" + find_destinations_in_late_init = TRUE /obj/machinery/computer/shuttle/admin name = "admin shuttle console" @@ -997,6 +985,7 @@ /obj/machinery/computer/shuttle/trade name = "Freighter Console" resistance_flags = INDESTRUCTIBLE + flags = NODECONSTRUCT /obj/machinery/computer/shuttle/trade/sol req_access = list(ACCESS_TRADE_SOL) diff --git a/code/modules/shuttle/supply.dm b/code/modules/shuttle/supply.dm index 9853fc4e78b..0e529da1d8b 100644 --- a/code/modules/shuttle/supply.dm +++ b/code/modules/shuttle/supply.dm @@ -53,7 +53,7 @@ var/blocking_item = "ERR_UNKNOWN" /obj/docking_port/mobile/supply/Initialize() - ..() + . = ..() for(var/T in subtypesof(/datum/economy/simple_seller)) var/datum/economy/simple_seller/seller = new T simple_sellers += seller diff --git a/code/modules/space_management/space_level.dm b/code/modules/space_management/space_level.dm index 5512447e346..a595a626d15 100644 --- a/code/modules/space_management/space_level.dm +++ b/code/modules/space_management/space_level.dm @@ -145,7 +145,6 @@ GLOBAL_LIST_INIT(atmos_machine_typecache, typecacheof(/obj/machinery/atmospherics)) GLOBAL_LIST_INIT(cable_typecache, typecacheof(/obj/structure/cable)) -GLOBAL_LIST_INIT(maploader_typecache, typecacheof(/obj/effect/landmark/map_loader)) /datum/space_level/proc/resume_init() if(dirt_count > 0) @@ -156,12 +155,8 @@ GLOBAL_LIST_INIT(maploader_typecache, typecacheof(/obj/effect/landmark/map_loade init_list = list() var/watch = start_watch() listclearnulls(our_atoms) - var/list/late_maps = typecache_filter_list(our_atoms, GLOB.maploader_typecache) var/list/pipes = typecache_filter_list(our_atoms, GLOB.atmos_machine_typecache) var/list/cables = typecache_filter_list(our_atoms, GLOB.cable_typecache) - // If we don't carefully add dirt around the map templates, bad stuff happens - // so we separate them out here - our_atoms -= late_maps SSatoms.InitializeAtoms(our_atoms, FALSE) log_debug("Primary initialization finished in [stop_watch(watch)]s.") our_atoms.Cut() @@ -169,8 +164,6 @@ GLOBAL_LIST_INIT(maploader_typecache, typecacheof(/obj/effect/landmark/map_loade do_pipes(pipes) if(length(cables)) do_cables(cables) - if(length(late_maps)) - do_late_maps(late_maps) /datum/space_level/proc/do_pipes(list/pipes) var/watch = start_watch() @@ -189,13 +182,3 @@ GLOBAL_LIST_INIT(maploader_typecache, typecacheof(/obj/effect/landmark/map_loade SSmachines.setup_template_powernets(cables) cables.Cut() log_debug("Took [stop_watch(watch)]s") - -/datum/space_level/proc/do_late_maps(list/late_maps) - var/watch = start_watch() - log_debug("Loading map templates on z-level '[zpos]'!") - GLOB.space_manager.add_dirt(zpos) // Let's not repeatedly resume init for each template - for(var/atom/movable/AM in late_maps) - AM.Initialize() - late_maps.Cut() - GLOB.space_manager.remove_dirt(zpos) - log_debug("Took [stop_watch(watch)]s") diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm index 92923a597cc..569f121d9a8 100644 --- a/code/modules/station_goals/bsa.dm +++ b/code/modules/station_goals/bsa.dm @@ -293,7 +293,7 @@ target_all_areas = TRUE /obj/machinery/computer/bsa_control/admin/Initialize() - ..() + . = ..() if(!cannon) cannon = deploy() diff --git a/code/modules/station_goals/secondary/medical/random_bulk_medicine.dm b/code/modules/station_goals/secondary/medical/random_bulk_medicine.dm index 67f4ecba402..640e25d631a 100644 --- a/code/modules/station_goals/secondary/medical/random_bulk_medicine.dm +++ b/code/modules/station_goals/secondary/medical/random_bulk_medicine.dm @@ -1,6 +1,6 @@ /datum/station_goal/secondary/random_bulk_reagent/medchem name = "Random Bulk Medicine" - department = "Medbay" + department = "Chemistry" abstract = FALSE /datum/station_goal/secondary/random_bulk_reagent/medchem/randomize_params() diff --git a/code/modules/station_goals/secondary/medical/variety_medicine.dm b/code/modules/station_goals/secondary/medical/variety_medicine.dm index 4344004fa35..6618374912e 100644 --- a/code/modules/station_goals/secondary/medical/variety_medicine.dm +++ b/code/modules/station_goals/secondary/medical/variety_medicine.dm @@ -1,7 +1,7 @@ /datum/station_goal/secondary/variety_reagent/medchem name = "Variety of Medicine" progress_type = /datum/secondary_goal_progress/variety_reagent - department = "Medbay" + department = "Chemistry" generic_name_plural = "medicines" abstract = FALSE diff --git a/code/modules/supply/supply_console.dm b/code/modules/supply/supply_console.dm index 83f08bcdbd8..3ff104c8892 100644 --- a/code/modules/supply/supply_console.dm +++ b/code/modules/supply/supply_console.dm @@ -275,13 +275,15 @@ if(!P.can_order()) to_chat(user, "That cannot be ordered right now. Please try again later.") return - + if(P.are_you_sure_you_want_to_be_banned) + var/we_warned_you = tgui_alert(user, "[P.are_you_sure_you_want_to_be_banned]", "ARE YOU SURE?", list("Yes", "No")) + if(!we_warned_you || we_warned_you == "No") + return if(!P.singleton && params["multiple"]) var/num_input = tgui_input_number(user, "Amount", "How many crates?", max_value = MULTIPLE_CRATE_MAX, min_value = 1) if(isnull(num_input) || (!is_public && !is_authorized(user)) || ..()) // Make sure they dont walk away return amount = clamp(round(num_input), 1, MULTIPLE_CRATE_MAX) - var/reason = tgui_input_text(user, "Reason", "Why do you require this item?", encode = FALSE, timeout = 60 SECONDS) if(!reason || (!is_public && !is_authorized(user)) || ..()) return diff --git a/code/modules/supply/supply_pack.dm b/code/modules/supply/supply_pack.dm index 3a3ce13a8ed..a9f2bcaca46 100644 --- a/code/modules/supply/supply_pack.dm +++ b/code/modules/supply/supply_pack.dm @@ -43,6 +43,8 @@ var/list/announce_beacons = list() /// List of names for being done in TGUI var/list/ui_manifest = list() + /// If this variable is filled, this grants the user a special TGUI confirmation prompt about ordering this shuttle, before they can place the order. Similar to bag of holding. + var/are_you_sure_you_want_to_be_banned /datum/supply_packs/New() . = ..() diff --git a/code/modules/supply/supply_packs/pack_shuttle.dm b/code/modules/supply/supply_packs/pack_shuttle.dm index 2425a61026b..f00ef4cccf1 100644 --- a/code/modules/supply/supply_packs/pack_shuttle.dm +++ b/code/modules/supply/supply_packs/pack_shuttle.dm @@ -106,6 +106,7 @@ cost = 5000 //please don't order this for funny please sir template = /datum/map_template/shuttle/emergency/lance speed_factor = 1.5 //Don't need to slow down before docking + are_you_sure_you_want_to_be_banned = "If you are not an antagonist, and you are ordering this shuttle for no valid reason, you will be banned, or job banned. If you are an antagonist, ahelp for permision, unless you are a hijacker, or you will be antagonist banned. If you are unsure, ahelp now." /datum/supply_packs/abstract/shuttle/lance/on_order_confirm(datum/supply_order/order) . = ..() diff --git a/code/modules/surgery/encased.dm b/code/modules/surgery/encased.dm index acf72adcf95..9651704951d 100644 --- a/code/modules/surgery/encased.dm +++ b/code/modules/surgery/encased.dm @@ -11,7 +11,9 @@ allowed_tools = list( TOOL_SAW = 100, /obj/item/hatchet = 90, - /obj/item/wirecutters = 35 // silly goose + /obj/item/chainsaw = 90, // Chainsaws were actually invented to replace manual bonesaws. Obvously *these* chainsaws aren't exactly designed for that, but then again, neither is a hatchet or a set of wirecutters. + /obj/item/butcher_chainsaw = 90, + TOOL_WIRECUTTER = 35 // Silly goose! ) time = 5.4 SECONDS diff --git a/code/modules/surgery/generic.dm b/code/modules/surgery/generic.dm index 244eed75241..286535d4df9 100644 --- a/code/modules/surgery/generic.dm +++ b/code/modules/surgery/generic.dm @@ -14,11 +14,13 @@ /obj/item/kitchen/knife = 90, /obj/item/kitchen/knife/shiv = 70, /obj/item/shard = 60, + TOOL_WIRECUTTER = 35, /obj/item/scissors = 12, - /obj/item/butcher_chainsaw = 1, /obj/item/claymore = 6, /obj/item/melee/energy = 6, /obj/item/pen/edagger = 6, + /obj/item/chainsaw = 1, + /obj/item/butcher_chainsaw = 1 ) time = 1.6 SECONDS @@ -162,7 +164,8 @@ TOOL_CAUTERY = 100, /obj/item/clothing/mask/cigarette = 90, /obj/item/lighter = 60, - TOOL_WELDER = 30 + TOOL_WELDER = 30, + /obj/item/flamethrower = 1 // You make do with what ya got... ) time = 2.4 SECONDS @@ -251,11 +254,14 @@ /datum/surgery_step/generic/amputate name = "amputate limb" - allowed_tools = list( TOOL_SAW = 100, + /obj/item/chainsaw = 100, // It's pretty good at doing this outside of surgery tbh... + /obj/item/butcher_chainsaw = 100, /obj/item/hatchet = 90, - /obj/item/melee/arm_blade = 75 + /obj/item/melee/arm_blade = 75, + /obj/item/claymore = 75, + /obj/item/melee/energy = 75 ) time = 10 SECONDS diff --git a/code/modules/surgery/organs/augments_arms.dm b/code/modules/surgery/organs/augments_arms.dm index f28c4636559..ec626a19ba6 100644 --- a/code/modules/surgery/organs/augments_arms.dm +++ b/code/modules/surgery/organs/augments_arms.dm @@ -261,6 +261,17 @@ /obj/item/organ/internal/cyberimp/arm/janitorial_abductor/l parent_organ = "l_arm" +/obj/item/organ/internal/cyberimp/arm/surgical_abductor + name = "Alien Surgical Toolset implant" + desc = "An alien surgical toolset, designed to be installed on the subject's arm." + origin_tech = "materials=5;engineering=5;plasmatech=5;powerstorage=4;abductor=2" + contents = newlist(/obj/item/retractor/alien, /obj/item/hemostat/alien, /obj/item/cautery/alien, /obj/item/bonesetter/alien, /obj/item/scalpel/alien, /obj/item/circular_saw/alien, /obj/item/bonegel/alien, /obj/item/FixOVein/alien, /obj/item/surgicaldrill/alien) + action_icon = list(/datum/action/item_action/organ_action/toggle = 'icons/obj/abductor.dmi') + action_icon_state = list(/datum/action/item_action/organ_action/toggle = "belt") + +/obj/item/organ/internal/cyberimp/arm/surgical_abductor/l + parent_organ = "l_arm" + /obj/item/organ/internal/cyberimp/arm/esword name = "arm-mounted energy blade" desc = "An illegal, and highly dangerous cybernetic implant that can project a deadly blade of concentrated enregy." diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index aa542a8e91a..4f07e8a71c4 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -702,7 +702,10 @@ allowed_tools = list( TOOL_SAW = 100, /obj/item/melee/energy/sword/cyborg/saw = 100, - /obj/item/hatchet = 90 + /obj/item/hatchet = 90, + /obj/item/chainsaw/ = 90, + /obj/item/butcher_chainsaw = 90, + TOOL_WIRECUTTER = 35 ) time = 5.4 SECONDS @@ -737,12 +740,15 @@ allowed_tools = list( TOOL_SCALPEL = 100, /obj/item/kitchen/knife = 90, + /obj/item/kitchen/knife/shiv = 70, /obj/item/shard = 60, + TOOL_WIRECUTTER = 35, /obj/item/scissors = 12, - /obj/item/butcher_chainsaw = 1, /obj/item/claymore = 6, /obj/item/melee/energy = 6, - /obj/item/pen/edagger = 6 + /obj/item/pen/edagger = 6, + /obj/item/chainsaw = 1, + /obj/item/butcher_chainsaw = 1 ) time = 1.6 SECONDS @@ -829,7 +835,8 @@ TOOL_CAUTERY = 100, /obj/item/clothing/mask/cigarette = 90, /obj/item/lighter = 60, - TOOL_WELDER = 30 + TOOL_WELDER = 30, + /obj/item/flamethrower = 1 ) time = 2.4 SECONDS diff --git a/code/modules/surgery/other.dm b/code/modules/surgery/other.dm index 6743fce0a65..22da9cad876 100644 --- a/code/modules/surgery/other.dm +++ b/code/modules/surgery/other.dm @@ -186,6 +186,7 @@ allowed_tools = list( TOOL_SCALPEL = 100, /obj/item/kitchen/knife = 90, + /obj/item/kitchen/knife/shiv = 70, /obj/item/shard = 60 ) diff --git a/code/modules/tgui/modules/ghost_hud_panel.dm b/code/modules/tgui/modules/ghost_hud_panel.dm index cff69061394..2e6a6b8d58d 100644 --- a/code/modules/tgui/modules/ghost_hud_panel.dm +++ b/code/modules/tgui/modules/ghost_hud_panel.dm @@ -81,6 +81,9 @@ GLOBAL_DATUM_INIT(ghost_hud_panel, /datum/ui_module/ghost_hud_panel, new) GLOB.antag_hud_users |= ghost.ckey + if(!check_rights(R_MOD | R_ADMIN | R_MENTOR, FALSE)) + // admins always get aobserve + add_verb(ghost, list(/mob/dead/observer/proc/do_observe, /mob/dead/observer/proc/observe)) ghost.antagHUD = TRUE for(var/datum/atom_hud/antag/H in GLOB.huds) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index f1e1b6c8300..cbaa4b3043f 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -12,6 +12,7 @@ #include "config_sanity.dm" #include "crafting_lists.dm" #include "emotes.dm" +#include "init_sanity.dm" #include "log_format.dm" #include "map_templates.dm" #include "map_tests.dm" diff --git a/code/modules/unit_tests/init_sanity.dm b/code/modules/unit_tests/init_sanity.dm new file mode 100644 index 00000000000..1584179cbe7 --- /dev/null +++ b/code/modules/unit_tests/init_sanity.dm @@ -0,0 +1,11 @@ +/datum/unit_test/initialize_sanity/Run() + if(length(SSatoms.BadInitializeCalls)) + Fail("Bad Initialize() calls detected. Please read logs.") + var/list/init_failures_to_text = list( + "[BAD_INIT_QDEL_BEFORE]" = "Qdeleted Before Initialized", + "[BAD_INIT_DIDNT_INIT]" = "Did Not Initialize", + "[BAD_INIT_SLEPT]" = "Initialize() Slept", + "[BAD_INIT_NO_HINT]" = "No Initialize() Hint Returned", + ) + for(var/failure in SSatoms.BadInitializeCalls) + Fail("[failure]: [init_failures_to_text["[SSatoms.BadInitializeCalls[failure]]"]]") // You like stacked brackets? diff --git a/code/modules/world_topic/adminmsg.dm b/code/modules/world_topic/adminmsg.dm index fdbfba8a4d3..a8cfb57101d 100644 --- a/code/modules/world_topic/adminmsg.dm +++ b/code/modules/world_topic/adminmsg.dm @@ -28,12 +28,12 @@ C.last_discord_pm_time = 0 SEND_SOUND(C, sound('sound/effects/adminhelp.ogg')) - to_chat(C, message, , MESSAGE_TYPE_ADMINPM) + to_chat(C, message, MESSAGE_TYPE_ADMINPM) for(var/client/A in GLOB.admins) // GLOB.admins includes anyone with a holder datum (mentors too). This makes sure only admins see ahelps if(check_rights(R_ADMIN, FALSE, A.mob)) if(A != C) - to_chat(A, amessage, , MESSAGE_TYPE_ADMINPM) + to_chat(A, amessage, MESSAGE_TYPE_ADMINPM) return json_encode(list("success" = "Message Successful")) diff --git a/icons/mob/actions/actions.dmi b/icons/mob/actions/actions.dmi index e9b7ef94895..ed1b9f9f312 100644 Binary files a/icons/mob/actions/actions.dmi and b/icons/mob/actions/actions.dmi differ diff --git a/paradise.dme b/paradise.dme index 8f0b4deab90..ae82570d648 100644 --- a/paradise.dme +++ b/paradise.dme @@ -37,6 +37,7 @@ #include "code\__DEFINES\armour.dm" #include "code\__DEFINES\asset_defines.dm" #include "code\__DEFINES\atmospherics_defines.dm" +#include "code\__DEFINES\atom_states.dm" #include "code\__DEFINES\bio_chip_defines.dm" #include "code\__DEFINES\bitfields_defines.dm" #include "code\__DEFINES\bots.dm" @@ -555,6 +556,7 @@ #include "code\datums\spells\charge.dm" #include "code\datums\spells\charge_up.dm" #include "code\datums\spells\charge_up_bounce.dm" +#include "code\datums\spells\chef.dm" #include "code\datums\spells\cluwne.dm" #include "code\datums\spells\conjure.dm" #include "code\datums\spells\conjure_item.dm" @@ -1578,7 +1580,6 @@ #include "code\modules\atmospherics\machinery\portable\portable_pump.dm" #include "code\modules\atmospherics\machinery\portable\scrubber.dm" #include "code\modules\awaymissions\loot.dm" -#include "code\modules\awaymissions\map_rng.dm" #include "code\modules\awaymissions\mob_spawn.dm" #include "code\modules\awaymissions\zlevel_helpers.dm" #include "code\modules\awaymissions\maploader\dmm_suite.dm" diff --git a/tgui/packages/common/storage.js b/tgui/packages/common/storage.js index 7a08cbb2920..c8d181b31fa 100644 --- a/tgui/packages/common/storage.js +++ b/tgui/packages/common/storage.js @@ -6,9 +6,8 @@ * @license MIT */ -export const IMPL_MEMORY = 0; -export const IMPL_LOCAL_STORAGE = 1; -export const IMPL_INDEXED_DB = 2; +export const IMPL_HUB_STORAGE = 0; +export const IMPL_INDEXED_DB = 1; const INDEXED_DB_VERSION = 1; const INDEXED_DB_NAME = 'para-tgui'; @@ -25,69 +24,44 @@ const testGeneric = (testFn) => () => { } }; -// Localstorage can sometimes throw an error, even if DOM storage is not -// disabled in IE11 settings. -// See: https://superuser.com/questions/1080011 -// prettier-ignore -const testLocalStorage = testGeneric(() => ( - window.localStorage && window.localStorage.getItem -)); +const testHubStorage = testGeneric( + () => window.hubStorage && window.hubStorage.getItem +); +// TODO: Remove with 516 // prettier-ignore const testIndexedDb = testGeneric(() => ( (window.indexedDB || window.msIndexedDB) && (window.IDBTransaction || window.msIDBTransaction) )); -class MemoryBackend { +class HubStorageBackend { constructor() { - this.impl = IMPL_MEMORY; - this.store = {}; + this.impl = IMPL_HUB_STORAGE; } get(key) { - return this.store[key]; - } - - set(key, value) { - this.store[key] = value; - } - - remove(key) { - this.store[key] = undefined; - } - - clear() { - this.store = {}; - } -} - -class LocalStorageBackend { - constructor() { - this.impl = IMPL_LOCAL_STORAGE; - } - - get(key) { - const value = localStorage.getItem(key); + const value = window.hubStorage.getItem('paradise-' + key); if (typeof value === 'string') { return JSON.parse(value); } } set(key, value) { - localStorage.setItem(key, JSON.stringify(value)); + window.hubStorage.setItem('paradise-' + key, JSON.stringify(value)); } remove(key) { - localStorage.removeItem(key); + window.hubStorage.removeItem('paradise-' + key); } clear() { - localStorage.clear(); + window.hubStorage.clear(); } } class IndexedDbBackend { + // TODO: Remove with 516 constructor() { this.impl = IMPL_INDEXED_DB; /** @type {Promise} */ @@ -157,17 +131,18 @@ class IndexedDbBackend { class StorageProxy { constructor() { this.backendPromise = (async () => { - if (testIndexedDb()) { - try { - const backend = new IndexedDbBackend(); - await backend.dbPromise; - return backend; - } catch {} + if (Byond.TRIDENT) { + // fuckin IE users, TODO: Remove with 516 + if (testIndexedDb()) { + try { + const backend = new IndexedDbBackend(); + await backend.dbPromise; + return backend; + } catch {} + } + } else if (testHubStorage()) { + return new HubStorageBackend(); } - if (testLocalStorage()) { - return new LocalStorageBackend(); - } - return new MemoryBackend(); })(); } diff --git a/tgui/packages/tgui/interfaces/ChemMaster.js b/tgui/packages/tgui/interfaces/ChemMaster.tsx similarity index 62% rename from tgui/packages/tgui/interfaces/ChemMaster.js rename to tgui/packages/tgui/interfaces/ChemMaster.tsx index 4c504ed8671..e0ecb4eaf5a 100644 --- a/tgui/packages/tgui/interfaces/ChemMaster.js +++ b/tgui/packages/tgui/interfaces/ChemMaster.tsx @@ -1,4 +1,4 @@ -import { Component } from 'inferno'; +import { Component, InfernoNode } from 'inferno'; import { useBackend } from '../backend'; import { Box, @@ -18,15 +18,13 @@ import { modalOpen, modalRegisterBodyOverride, } from './common/ComplexModal'; -import { classes } from 'common/react'; -import { createLogger } from '../logging'; - -const logger = createLogger('ChemMaster'); +import { BooleanLike, classes } from 'common/react'; +import { BoxProps } from '../components/Box'; const transferAmounts = [1, 5, 10]; const analyzeModalBodyOverride = (modal, context) => { - const { act, data } = useBackend(context); + const { act, data } = useBackend(context); const result = modal.args.analysis; return ( @@ -72,30 +70,74 @@ const analyzeModalBodyOverride = (modal, context) => { ); }; +interface ProductionItemSprite { + id: number; + sprite: string; +} + +interface StaticProductionData { + name: string; + icon: string; + max_items_amount: number; + max_units_per_item: number; + sprites?: ProductionItemSprite[]; +} + +interface NonStaticProductionData { + set_name?: string; + set_items_amount: string; + set_sprite?: number; + placeholder_name?: string; +} + +type ProductionData = StaticProductionData & + NonStaticProductionData & { id: string }; + +enum TransferMode { + ToDisposals = 0, + ToBeaker = 1, +} + +interface ReagentData { + id: string; + name: string; + description: string; + volume: number; +} + +interface ContainerStyle { + color: string; + name: string; +} + +interface ChemMasterData { + // ui_static + maxnamelength: number; + static_production_data: Record; + containerstyles: ContainerStyle[]; + + condi: BooleanLike; + loaded_pill_bottle: BooleanLike; + loaded_pill_bottle_style?: string; + beaker: BooleanLike; + beaker_reagents: ReagentData[]; + buffer_reagents: ReagentData[]; + mode: TransferMode; + printing: BooleanLike; + modal?: unknown; + production_mode: string; + production_data: Record; +} + export const ChemMaster = (props, context) => { - const { data } = useBackend(context); - const { - condi, - beaker, - beaker_reagents = [], - buffer_reagents = [], - mode, - } = data; return ( - 0} - /> - - 0} - /> + + + @@ -103,9 +145,10 @@ export const ChemMaster = (props, context) => { ); }; -const ChemMasterBeaker = (props, context) => { - const { act } = useBackend(context); - const { beaker, beakerReagents, bufferNonEmpty } = props; +const ChemMasterBeaker = (props: {}, context) => { + const { act, data } = useBackend(context); + const { beaker, beaker_reagents, buffer_reagents } = data; + const bufferNonEmpty = buffer_reagents.length > 0; return (
{ {beaker ? ( ( - +