diff --git a/.vscode/launch.json b/.vscode/launch.json index bf3a209531db..f41cbaa49440 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,13 @@ { "version": "0.2.0", "configurations": [ + { + "type": "opendream", + "request": "launch", + "name": "OpenDream", + "preLaunchTask": "OpenDream: compile ${command:CurrentDME}", + "json_path": "${workspaceFolder}/${command:CurrentJson}" + }, { "type": "byond", "request": "launch", diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm index 9b2a6c2920b8..c011fba61655 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_surface_mining_site.dmm @@ -82,7 +82,6 @@ /turf/open/floor/wood, /area/ruin/unpowered) "s" = ( -/obj/effect/decal/cleanable/trail_holder, /turf/open/floor/wood, /area/ruin/unpowered) "t" = ( diff --git a/_maps/RandomRuins/SpaceRuins/derelict_sulaco.dmm b/_maps/RandomRuins/SpaceRuins/derelict_sulaco.dmm index 92f43ca70358..467083499b4c 100644 --- a/_maps/RandomRuins/SpaceRuins/derelict_sulaco.dmm +++ b/_maps/RandomRuins/SpaceRuins/derelict_sulaco.dmm @@ -132,7 +132,7 @@ /turf/open/floor/iron/smooth_edge, /area/ruin/space/has_grav/derelictsulaco) "eF" = ( -/obj/effect/decal/cleanable/blood/xtracks, +/obj/effect/decal/cleanable/xenoblood/xtracks, /turf/open/floor/plating/airless, /area/ruin/space) "eU" = ( @@ -165,7 +165,7 @@ /area/ruin/space/has_grav/derelictsulaco) "fI" = ( /obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/blood/xtracks{ +/obj/effect/decal/cleanable/xenoblood/xtracks{ dir = 4 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -663,7 +663,7 @@ /area/ruin/space/has_grav/derelictsulaco) "vl" = ( /obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/blood/xtracks{ +/obj/effect/decal/cleanable/xenoblood/xtracks{ dir = 4 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -708,7 +708,7 @@ /area/ruin/space/has_grav/derelictsulaco) "wR" = ( /obj/effect/mapping_helpers/burnt_floor, -/obj/effect/decal/cleanable/blood/xtracks{ +/obj/effect/decal/cleanable/xenoblood/xtracks{ dir = 4 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1017,7 +1017,7 @@ /area/ruin/space) "Ie" = ( /obj/effect/mapping_helpers/burnt_floor, -/obj/effect/decal/cleanable/blood/xtracks{ +/obj/effect/decal/cleanable/xenoblood/xtracks{ dir = 4 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1322,7 +1322,7 @@ /area/ruin/space/has_grav/derelictsulaco) "QR" = ( /obj/structure/alien/weeds, -/obj/effect/decal/cleanable/blood/xtracks{ +/obj/effect/decal/cleanable/xenoblood/xtracks{ dir = 5 }, /obj/item/trash/flare, @@ -1433,7 +1433,7 @@ /area/ruin/space/has_grav/derelictsulaco) "TL" = ( /obj/structure/alien/weeds, -/obj/effect/decal/cleanable/blood/xtracks{ +/obj/effect/decal/cleanable/xenoblood/xtracks{ dir = 4 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -1645,7 +1645,7 @@ /area/template_noop) "ZA" = ( /obj/effect/mapping_helpers/broken_floor, -/obj/effect/decal/cleanable/blood/xtracks{ +/obj/effect/decal/cleanable/xenoblood/xtracks{ dir = 4 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, diff --git a/_maps/RandomRuins/SpaceRuins/oldstation.dmm b/_maps/RandomRuins/SpaceRuins/oldstation.dmm index 90ee5333b933..8629ad254131 100644 --- a/_maps/RandomRuins/SpaceRuins/oldstation.dmm +++ b/_maps/RandomRuins/SpaceRuins/oldstation.dmm @@ -3429,7 +3429,7 @@ /obj/machinery/door/airlock/highsecurity, /obj/structure/alien/weeds, /obj/structure/cable, -/obj/effect/decal/cleanable/blood/xtracks, +/obj/effect/decal/cleanable/xenoblood/xtracks, /obj/effect/decal/cleanable/blood/tracks, /obj/effect/mapping_helpers/airlock/cyclelink_helper_multi{ cycle_id = "oldstation-aisat" @@ -4613,7 +4613,7 @@ /turf/open/floor/iron, /area/ruin/space/ancientstation/charlie/hall) "rC" = ( -/obj/effect/decal/cleanable/blood/xtracks{ +/obj/effect/decal/cleanable/xenoblood/xtracks{ dir = 8 }, /obj/effect/decal/cleanable/glass, @@ -4892,7 +4892,7 @@ }, /obj/effect/decal/cleanable/dirt, /obj/item/shard, -/obj/effect/decal/cleanable/blood/xtracks{ +/obj/effect/decal/cleanable/xenoblood/xtracks{ dir = 6 }, /obj/effect/turf_decal/tile/purple/half/contrasted, @@ -7247,7 +7247,7 @@ /turf/open/floor/plating, /area/ruin/space/ancientstation/beta/supermatter) "Np" = ( -/obj/effect/decal/cleanable/blood/xtracks{ +/obj/effect/decal/cleanable/xenoblood/xtracks{ dir = 10 }, /turf/open/floor/engine, @@ -8194,7 +8194,7 @@ /turf/open/floor/engine, /area/ruin/space/ancientstation/delta/biolab) "Wd" = ( -/obj/effect/decal/cleanable/blood/xtracks{ +/obj/effect/decal/cleanable/xenoblood/xtracks{ dir = 5 }, /turf/open/floor/engine, diff --git a/_maps/map_files/Blueshift/Blueshift.dmm b/_maps/map_files/Blueshift/Blueshift.dmm index a379281c7ee5..ca805053a4c7 100644 --- a/_maps/map_files/Blueshift/Blueshift.dmm +++ b/_maps/map_files/Blueshift/Blueshift.dmm @@ -1697,6 +1697,15 @@ }, /turf/open/floor/plating, /area/station/maintenance/department/security/prison_upper) +"arz" = ( +/obj/structure/table, +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 10 + }, +/obj/item/radio/intercom/directional/west, +/obj/item/surgery_tray, +/turf/open/floor/iron/white, +/area/station/science/robotics) "arA" = ( /turf/open/floor/iron/smooth_edge{ dir = 4 @@ -1987,19 +1996,6 @@ /obj/machinery/light/directional/east, /turf/open/floor/iron, /area/station/hallway/primary/central) -"auS" = ( -/obj/structure/table, -/obj/machinery/smartfridge/disks, -/obj/item/stack/package_wrap, -/obj/item/hand_labeler, -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/trimline/green/filled/corner{ - dir = 8 - }, -/turf/open/floor/iron/dark/corner{ - dir = 1 - }, -/area/station/service/hydroponics) "auZ" = ( /obj/item/toy/plush/pim, /turf/open/floor/plating, @@ -3950,19 +3946,6 @@ /obj/item/trash/candle, /turf/open/floor/plating, /area/station/maintenance/department/engineering/engine_aft_port) -"aOd" = ( -/obj/machinery/smartfridge/chemistry/virology/preloaded, -/obj/machinery/light/directional/east, -/obj/structure/reagent_dispensers/wall/virusfood/directional/east, -/obj/effect/turf_decal/trimline/green/filled/end{ - dir = 4 - }, -/obj/machinery/smartfridge/disks{ - pixel_x = 8; - pixel_y = 14 - }, -/turf/open/floor/iron/white, -/area/station/medical/virology) "aOe" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /turf/open/floor/iron, @@ -6305,24 +6288,6 @@ dir = 8 }, /area/station/medical/medbay/lobby) -"bmD" = ( -/obj/structure/table/glass, -/obj/machinery/light/directional/east, -/obj/item/seeds/grape{ - pixel_x = -6 - }, -/obj/item/seeds/lime{ - pixel_x = 6 - }, -/obj/item/seeds/watermelon, -/obj/item/food/grown/wheat, -/obj/item/food/grown/watermelon, -/obj/item/food/grown/banana, -/obj/item/storage/bag/plants/portaseeder, -/turf/open/floor/iron/dark/side{ - dir = 4 - }, -/area/station/service/hydroponics) "bmI" = ( /turf/open/floor/iron/stairs/right, /area/station/maintenance/port/upper) @@ -13308,6 +13273,20 @@ dir = 1 }, /area/station/security/prison) +"cAU" = ( +/obj/structure/table, +/obj/item/wrench, +/obj/item/crowbar, +/obj/item/stack/sheet/plasteel/twenty, +/obj/item/stack/sheet/iron/fifty, +/obj/item/stack/sheet/iron/fifty, +/obj/item/stack/sheet/iron/fifty, +/obj/item/stack/sheet/iron/fifty, +/obj/item/stack/sheet/iron/fifty, +/obj/item/stack/sheet/glass/fifty, +/obj/machinery/firealarm/directional/south, +/turf/open/floor/mineral/plastitanium, +/area/station/science/robotics/lab) "cAV" = ( /obj/machinery/atmospherics/pipe/smart/simple/orange/hidden{ dir = 6 @@ -15878,6 +15857,11 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/command) +"cYx" = ( +/obj/effect/turf_decal/bot_red, +/obj/machinery/autolathe, +/turf/open/floor/mineral/plastitanium, +/area/station/science/robotics/lab) "cYF" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -16928,15 +16912,6 @@ /obj/machinery/duct, /turf/open/floor/wood, /area/station/commons/dorms/room8) -"djt" = ( -/obj/structure/table, -/obj/effect/turf_decal/trimline/blue/filled/line{ - dir = 10 - }, -/obj/item/radio/intercom/directional/west, -/obj/item/surgery_tray, -/turf/open/floor/iron/white, -/area/station/science/robotics) "djv" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/command/glass{ @@ -22325,6 +22300,19 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/central) +"eoK" = ( +/obj/structure/table, +/obj/machinery/smartfridge/disks, +/obj/item/stack/package_wrap, +/obj/item/hand_labeler, +/obj/structure/disposalpipe/segment, +/obj/effect/turf_decal/trimline/green/filled/corner{ + dir = 8 + }, +/turf/open/floor/iron/dark/corner{ + dir = 1 + }, +/area/station/service/hydroponics) "eoO" = ( /obj/item/stack/sheet/iron{ amount = 10 @@ -25979,10 +25967,6 @@ dir = 4 }, /area/station/security/prison/safe) -"eWk" = ( -/obj/machinery/smartfridge/organ, -/turf/open/floor/iron/dark, -/area/station/science/robotics) "eWl" = ( /turf/closed/wall, /area/station/maintenance/disposal) @@ -28104,13 +28088,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) -"fqR" = ( -/obj/structure/extinguisher_cabinet/directional/south, -/obj/structure/bookcase/manuals/botany, -/turf/open/floor/iron/dark/side{ - dir = 4 - }, -/area/station/service/hydroponics) "fqT" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -30507,30 +30484,6 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) -"fRD" = ( -/obj/structure/table/reinforced, -/obj/item/clothing/mask/gas/sechailer{ - pixel_x = -3; - pixel_y = 3 - }, -/obj/item/clothing/mask/gas/sechailer, -/obj/item/clothing/mask/gas/sechailer{ - pixel_x = 3; - pixel_y = -3 - }, -/obj/item/flashlight/seclite, -/obj/item/flashlight/seclite, -/obj/item/flashlight/seclite, -/obj/item/key/security, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/trimline/red/line{ - dir = 4 - }, -/obj/effect/turf_decal/trimline/red/line{ - dir = 8 - }, -/turf/open/floor/iron/dark/textured, -/area/station/ai_monitored/security/armory) "fRF" = ( /obj/effect/turf_decal/stripes/white/line{ dir = 10 @@ -32446,20 +32399,6 @@ dir = 1 }, /area/station/common/night_club/changing_room) -"gme" = ( -/obj/structure/table, -/obj/item/wrench, -/obj/item/crowbar, -/obj/item/stack/sheet/plasteel/twenty, -/obj/item/stack/sheet/iron/fifty, -/obj/item/stack/sheet/iron/fifty, -/obj/item/stack/sheet/iron/fifty, -/obj/item/stack/sheet/iron/fifty, -/obj/item/stack/sheet/iron/fifty, -/obj/item/stack/sheet/glass/fifty, -/obj/machinery/firealarm/directional/south, -/turf/open/floor/mineral/plastitanium, -/area/station/science/robotics/lab) "gmf" = ( /obj/effect/turf_decal/tile/neutral, /obj/effect/turf_decal/tile/neutral{ @@ -36154,6 +36093,13 @@ /obj/structure/sign/poster/contraband/random/directional/south, /turf/open/floor/plating, /area/station/maintenance/fore/upper) +"gWH" = ( +/obj/machinery/firealarm/directional/north, +/obj/structure/bodycontainer/morgue{ + dir = 2 + }, +/turf/open/floor/iron, +/area/station/science/robotics) "gWR" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment, @@ -45877,6 +45823,21 @@ /obj/structure/bookcase/random/reference, /turf/open/floor/wood, /area/station/command/meeting_room/council) +"iUA" = ( +/obj/structure/table, +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 9 + }, +/obj/item/reagent_containers/spray/cleaner{ + pixel_x = 9; + pixel_y = 4 + }, +/obj/item/healthanalyzer{ + pixel_x = -4; + pixel_y = 4 + }, +/turf/open/floor/iron/white, +/area/station/science/robotics) "iUB" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -52185,6 +52146,33 @@ }, /turf/open/floor/iron, /area/station/science/ordnance) +"kdL" = ( +/obj/structure/table/reinforced, +/obj/item/clothing/mask/gas/sechailer{ + pixel_x = -3; + pixel_y = 3 + }, +/obj/item/clothing/mask/gas/sechailer, +/obj/item/clothing/mask/gas/sechailer{ + pixel_x = 3; + pixel_y = -3 + }, +/obj/item/flashlight/seclite, +/obj/item/flashlight/seclite, +/obj/item/flashlight/seclite, +/obj/item/key/security, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/trimline/red/line{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/red/line{ + dir = 8 + }, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/turf/open/floor/iron/dark/textured, +/area/station/ai_monitored/security/armory) "kdO" = ( /obj/machinery/light/directional/west, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -64079,6 +64067,10 @@ }, /turf/open/floor/plating, /area/station/maintenance/department/engineering/engine_aft_starboard) +"mvr" = ( +/obj/machinery/smartfridge/organ, +/turf/open/floor/iron/dark, +/area/station/science/robotics) "mvD" = ( /obj/effect/turf_decal/stripes/white/line{ dir = 6 @@ -65616,6 +65608,24 @@ /obj/structure/chair/stool, /turf/open/floor/iron, /area/station/commons/fitness/recreation) +"mKM" = ( +/obj/structure/table/glass, +/obj/machinery/light/directional/east, +/obj/item/seeds/grape{ + pixel_x = -6 + }, +/obj/item/seeds/lime{ + pixel_x = 6 + }, +/obj/item/seeds/watermelon, +/obj/item/food/grown/wheat, +/obj/item/food/grown/watermelon, +/obj/item/food/grown/banana, +/obj/item/storage/bag/plants/portaseeder, +/turf/open/floor/iron/dark/side{ + dir = 4 + }, +/area/station/service/hydroponics) "mKN" = ( /obj/effect/turf_decal/tile/neutral{ dir = 4 @@ -80727,11 +80737,6 @@ /obj/effect/spawner/random/maintenance/three, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) -"pHX" = ( -/obj/effect/turf_decal/bot_red, -/obj/machinery/autolathe, -/turf/open/floor/mineral/plastitanium, -/area/station/science/robotics/lab) "pHY" = ( /obj/effect/turf_decal/tile/neutral, /obj/structure/sign/departments/restroom/directional/south, @@ -88232,6 +88237,19 @@ }, /turf/open/floor/carpet, /area/station/commons/dorms/vacantroom) +"reP" = ( +/obj/machinery/smartfridge/chemistry/virology/preloaded, +/obj/machinery/light/directional/east, +/obj/structure/reagent_dispensers/wall/virusfood/directional/east, +/obj/effect/turf_decal/trimline/green/filled/end{ + dir = 4 + }, +/obj/machinery/smartfridge/disks{ + pixel_x = 8; + pixel_y = 14 + }, +/turf/open/floor/iron/white, +/area/station/medical/virology) "reW" = ( /obj/effect/turf_decal/delivery, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/visible, @@ -99774,13 +99792,6 @@ /obj/machinery/shower/directional/south, /turf/open/floor/iron/freezer, /area/station/commons/dorms/room3) -"tpV" = ( -/obj/machinery/firealarm/directional/north, -/obj/structure/bodycontainer/morgue{ - dir = 2 - }, -/turf/open/floor/iron, -/area/station/science/robotics) "tqc" = ( /obj/effect/decal/cleanable/oil, /obj/effect/landmark/generic_maintenance_landmark, @@ -119732,21 +119743,6 @@ "xdU" = ( /turf/open/floor/iron, /area/station/cargo/warehouse) -"xej" = ( -/obj/structure/table, -/obj/effect/turf_decal/trimline/blue/filled/line{ - dir = 9 - }, -/obj/item/reagent_containers/spray/cleaner{ - pixel_x = 9; - pixel_y = 4 - }, -/obj/item/healthanalyzer{ - pixel_x = -4; - pixel_y = 4 - }, -/turf/open/floor/iron/white, -/area/station/science/robotics) "xep" = ( /obj/effect/turf_decal/trimline/purple/filled/line, /obj/structure/cable, @@ -123293,6 +123289,13 @@ /obj/structure/closet/radiation, /turf/open/floor/iron/dark, /area/station/engineering/atmos/hfr_room) +"xOF" = ( +/obj/structure/extinguisher_cabinet/directional/south, +/obj/structure/bookcase/manuals/botany, +/turf/open/floor/iron/dark/side{ + dir = 4 + }, +/area/station/service/hydroponics) "xOQ" = ( /obj/effect/turf_decal/trimline/purple/filled/line{ dir = 4 @@ -159447,7 +159450,7 @@ xJn bqj pzw mrb -fRD +kdL uKW gkm bkG @@ -159482,7 +159485,7 @@ bBI xnF epa lHt -auS +eoK gtP vDx mHE @@ -161792,8 +161795,8 @@ fUV oKN fAR qVa -bmD -fqR +mKM +xOF mHE hwb ofS @@ -217349,8 +217352,8 @@ reb nTU aOe xot -xej -djt +iUA +arz kOu dur rxR @@ -218116,9 +218119,9 @@ eSk lKo dbR tUp -gme +cAU uor -tpV +gWH rVU mve uor @@ -218884,7 +218887,7 @@ sTk quF eNE pKE -pHX +cYx ohm mYm ndT @@ -219660,7 +219663,7 @@ kky aXQ rlz sXt -eWk +mvr vXP bDH uor @@ -237365,7 +237368,7 @@ gOT cmP viI ivX -aOd +reP tvs fnu eSa diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm index 5582f45bb067..763df1a081b2 100644 --- a/_maps/map_files/BoxStation/BoxStation.dmm +++ b/_maps/map_files/BoxStation/BoxStation.dmm @@ -3871,6 +3871,23 @@ /obj/effect/turf_decal/bot/right, /turf/open/floor/engine, /area/station/engineering/atmos/hfr_room) +"boL" = ( +/obj/effect/turf_decal/tile/red/fourcorners, +/obj/structure/rack, +/obj/item/gun/energy/disabler{ + pixel_x = -3; + pixel_y = 3 + }, +/obj/item/gun/energy/disabler, +/obj/item/gun/energy/disabler{ + pixel_x = 3; + pixel_y = -3 + }, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/turf/open/floor/iron/dark, +/area/station/ai_monitored/security/armory) "boP" = ( /obj/structure/table/wood, /turf/open/floor/wood, @@ -7329,6 +7346,25 @@ "crM" = ( /turf/closed/wall/r_wall, /area/station/security/warden) +"crP" = ( +/obj/effect/turf_decal/tile/green/half/contrasted{ + dir = 1 + }, +/obj/machinery/camera/autoname/directional/south, +/obj/item/radio/intercom/directional/south, +/obj/structure/table, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/turf/open/floor/iron/dark/side, +/area/station/service/hydroponics) "crV" = ( /obj/effect/turf_decal/trimline/purple/filled/corner{ dir = 1 @@ -11515,6 +11551,20 @@ /obj/effect/landmark/navigate_destination/atmos, /turf/open/floor/iron/dark/textured, /area/station/engineering/break_room) +"dNc" = ( +/obj/effect/turf_decal/tile/green, +/obj/structure/table, +/obj/machinery/plantgenes{ + pixel_y = 6 + }, +/obj/item/clothing/suit/apron, +/obj/item/clothing/accessory/armband/hydro, +/obj/item/wrench, +/obj/machinery/light/small/directional/west, +/turf/open/floor/iron/dark/side{ + dir = 9 + }, +/area/station/service/hydroponics) "dNr" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 4 @@ -14836,20 +14886,6 @@ /obj/structure/reagent_dispensers/watertank, /turf/open/floor/plating, /area/station/maintenance/department/security/brig) -"eVZ" = ( -/obj/effect/turf_decal/tile/green, -/obj/structure/table, -/obj/machinery/plantgenes{ - pixel_y = 6 - }, -/obj/item/clothing/suit/apron, -/obj/item/clothing/accessory/armband/hydro, -/obj/item/wrench, -/obj/machinery/light/small/directional/west, -/turf/open/floor/iron/dark/side{ - dir = 9 - }, -/area/station/service/hydroponics) "eWd" = ( /obj/effect/turf_decal/tile/dark_blue/fourcorners, /obj/structure/extinguisher_cabinet/directional/west, @@ -25458,20 +25494,6 @@ /obj/machinery/deepfryer, /turf/open/floor/iron/kitchen, /area/station/service/kitchen) -"iuI" = ( -/obj/effect/turf_decal/tile/red/fourcorners, -/obj/structure/rack, -/obj/item/gun/energy/disabler{ - pixel_x = -3; - pixel_y = 3 - }, -/obj/item/gun/energy/disabler, -/obj/item/gun/energy/disabler{ - pixel_x = 3; - pixel_y = -3 - }, -/turf/open/floor/iron/dark, -/area/station/ai_monitored/security/armory) "iuJ" = ( /obj/effect/turf_decal/tile/dark_blue/full, /obj/effect/turf_decal/bot_white, @@ -26713,24 +26735,6 @@ }, /turf/open/floor/iron/dark, /area/station/security/processing) -"iPZ" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 6 - }, -/obj/machinery/camera/directional/east{ - c_tag = "Medical - Pathology, Hallway, East"; - network = list("ss13","medbay"); - name = "medical camera" - }, -/obj/structure/table/reinforced/rglass, -/obj/item/storage/box/monkeycubes, -/obj/item/toy/figure/virologist{ - pixel_y = 13; - pixel_x = -9 - }, -/obj/machinery/smartfridge/disks, -/turf/open/floor/iron/white, -/area/station/medical/virology) "iQd" = ( /obj/effect/spawner/random/structure/table_or_rack, /obj/effect/spawner/random/maintenance, @@ -30214,6 +30218,18 @@ /obj/structure/cable, /turf/open/floor/carpet/black, /area/station/security/bitden) +"kcN" = ( +/obj/effect/turf_decal/tile/green/half/contrasted{ + dir = 1 + }, +/obj/structure/table, +/obj/item/chicken_feed{ + pixel_y = 10; + pixel_x = -5 + }, +/obj/machinery/feed_machine, +/turf/open/floor/iron/dark/side, +/area/station/service/hydroponics) "kde" = ( /obj/machinery/atmospherics/components/tank/air{ dir = 4 @@ -34622,6 +34638,22 @@ /obj/structure/closet/firecloset, /turf/open/floor/iron/dark, /area/station/hallway/primary/aft) +"lxC" = ( +/obj/structure/closet/crate/hydroponics, +/obj/item/seeds/tree, +/obj/effect/spawner/random/contraband/prison, +/obj/item/seeds/pumpkin, +/obj/item/seeds/wheat, +/obj/item/seeds/ambrosia, +/obj/item/seeds/grass, +/obj/item/seeds/carrot, +/obj/item/seeds/tomato, +/obj/item/seeds/potato, +/obj/item/seeds/garlic, +/obj/item/seeds/onion, +/obj/item/paper/guides/jobs/hydroponics, +/turf/open/floor/iron/dark, +/area/station/security/prison/garden) "lyp" = ( /obj/effect/turf_decal/siding/wood{ dir = 1 @@ -44132,18 +44164,6 @@ }, /turf/open/floor/iron/white, /area/station/medical/medbay/lobby) -"oMD" = ( -/obj/effect/turf_decal/tile/green/half/contrasted{ - dir = 1 - }, -/obj/structure/table, -/obj/item/chicken_feed{ - pixel_y = 10; - pixel_x = -5 - }, -/obj/machinery/feed_machine, -/turf/open/floor/iron/dark/side, -/area/station/service/hydroponics) "oMG" = ( /obj/effect/turf_decal/tile/green{ dir = 8 @@ -45448,13 +45468,6 @@ /obj/structure/cable, /turf/open/floor/circuit/telecomms, /area/station/tcommsat/server) -"pml" = ( -/obj/effect/turf_decal/tile/green/half/contrasted{ - dir = 1 - }, -/obj/structure/bookcase/manuals/botany, -/turf/open/floor/iron/dark/side, -/area/station/service/hydroponics) "pmr" = ( /obj/effect/turf_decal/trimline/purple/line, /obj/effect/turf_decal/trimline/purple/filled/line{ @@ -55974,18 +55987,6 @@ dir = 1 }, /area/station/commons/storage/primary) -"sQL" = ( -/obj/effect/turf_decal/trimline/blue/filled/line{ - dir = 4 - }, -/obj/structure/table, -/obj/item/healthanalyzer{ - pixel_x = -1; - pixel_y = 6 - }, -/obj/item/storage/backpack/duffelbag/med/surgery, -/turf/open/floor/iron/white, -/area/station/science/robotics/lab) "sQN" = ( /obj/machinery/power/apc/auto_name/directional/west, /obj/structure/cable, @@ -58113,23 +58114,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white, /area/station/medical/treatment_center) -"tyX" = ( -/obj/structure/closet/crate/hydroponics, -/obj/item/book/manual/botanical_lexicon, -/obj/item/seeds/tree, -/obj/effect/spawner/random/contraband/prison, -/obj/item/seeds/pumpkin, -/obj/item/seeds/wheat, -/obj/item/seeds/ambrosia, -/obj/item/seeds/grass, -/obj/item/seeds/carrot, -/obj/item/seeds/tomato, -/obj/item/seeds/potato, -/obj/item/seeds/garlic, -/obj/item/seeds/onion, -/obj/item/paper/guides/jobs/hydroponics, -/turf/open/floor/iron/dark, -/area/station/security/prison/garden) "tzc" = ( /obj/effect/spawner/random/engineering/tank, /turf/open/floor/plating, @@ -62102,6 +62086,13 @@ /obj/structure/closet/secure_closet/exile, /turf/open/floor/iron/dark/textured, /area/station/command/gateway) +"uRU" = ( +/obj/effect/turf_decal/tile/green/half/contrasted{ + dir = 1 + }, +/obj/structure/bookcase/manuals/botany, +/turf/open/floor/iron/dark/side, +/area/station/service/hydroponics) "uRW" = ( /obj/machinery/plumbing/ooze_sucker{ mapping_id = "4"; @@ -63123,6 +63114,18 @@ /obj/machinery/telecomms/server/presets/science, /turf/open/floor/circuit/green/telecomms, /area/station/tcommsat/server) +"vjd" = ( +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 4 + }, +/obj/structure/table, +/obj/item/healthanalyzer{ + pixel_x = -1; + pixel_y = 6 + }, +/obj/item/storage/backpack/duffelbag/med/surgery, +/turf/open/floor/iron/white, +/area/station/science/robotics/lab) "vje" = ( /obj/effect/turf_decal/stripes/line, /obj/effect/turf_decal/stripes/line{ @@ -63241,12 +63244,6 @@ /obj/machinery/light/small/directional/west, /turf/open/floor/iron/dark/smooth_large, /area/station/hallway/secondary/entry) -"vki" = ( -/obj/effect/turf_decal/bot_red, -/obj/machinery/status_display/ai/directional/east, -/obj/machinery/suit_storage_unit/standard_unit, -/turf/open/floor/iron/large, -/area/station/ai_monitored/command/storage/eva) "vkj" = ( /obj/structure/table/wood/fancy/black, /obj/item/flashlight/lantern{ @@ -65912,25 +65909,6 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/security/evidence) -"wbw" = ( -/obj/effect/turf_decal/tile/green/half/contrasted{ - dir = 1 - }, -/obj/machinery/camera/autoname/directional/south, -/obj/item/radio/intercom/directional/south, -/obj/structure/table, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/turf/open/floor/iron/dark/side, -/area/station/service/hydroponics) "wbA" = ( /obj/effect/turf_decal/trimline/red/filled/line{ dir = 9 @@ -68660,6 +68638,24 @@ /obj/item/aicard, /turf/open/floor/iron/dark, /area/station/command/bridge) +"wWb" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 6 + }, +/obj/machinery/camera/directional/east{ + c_tag = "Medical - Pathology, Hallway, East"; + network = list("ss13","medbay"); + name = "medical camera" + }, +/obj/structure/table/reinforced/rglass, +/obj/item/storage/box/monkeycubes, +/obj/item/toy/figure/virologist{ + pixel_y = 13; + pixel_x = -9 + }, +/obj/machinery/smartfridge/disks, +/turf/open/floor/iron/white, +/area/station/medical/virology) "wWd" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/catwalk_floor, @@ -70859,6 +70855,11 @@ }, /turf/open/floor/iron/white, /area/station/medical/exam_room) +"xLa" = ( +/obj/machinery/suit_storage_unit/standard_unit, +/obj/effect/turf_decal/bot_red, +/turf/open/floor/iron, +/area/station/ai_monitored/command/storage/eva) "xLc" = ( /obj/structure/sink/kitchen/directional/south, /turf/open/floor/iron/freezer, @@ -85746,7 +85747,7 @@ kNg jZY coj pEY -eVZ +dNc sXx fZO cvn @@ -88844,7 +88845,7 @@ xAQ tQJ ctk pAW -pml +uRU bnl cLZ fUs @@ -89101,7 +89102,7 @@ sjV fzI uQP ohF -wbw +crP bnl wgX fUs @@ -89358,7 +89359,7 @@ juc juc juc ohF -oMD +kcN bnl cLZ fUs @@ -99356,7 +99357,7 @@ nZL kOK nVk rfW -vki +xLa hZS liC rTP @@ -101093,7 +101094,7 @@ tFK mfE mfE xWj -tyX +lxC lEa wtv oER @@ -101632,7 +101633,7 @@ oRs csZ gGx dAx -iuI +boL lZV jZp jRr @@ -113758,7 +113759,7 @@ auK mxF dxk flU -sQL +vjd lpk eoA sYI @@ -115862,7 +115863,7 @@ gmy nIN lfj rzW -iPZ +wWb jRY axo hmZ diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index b0d582c657a0..415a96dcd41b 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -4016,15 +4016,6 @@ /obj/effect/spawner/random/trash/moisture_trap, /turf/open/floor/iron, /area/station/maintenance/starboard/aft) -"aUw" = ( -/obj/machinery/light/small/directional/north, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/power/smes, -/obj/structure/cable, -/turf/open/floor/plating, -/area/station/maintenance/solars/port/aft) "aUG" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/structure/disposalpipe/segment{ @@ -5786,14 +5777,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/cargo/storage) -"bqC" = ( -/obj/effect/turf_decal/bot, -/obj/structure/railing{ - dir = 1 - }, -/obj/machinery/seed_extractor, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "bqF" = ( /obj/effect/turf_decal/tile/neutral{ dir = 4 @@ -7997,6 +7980,15 @@ /obj/effect/turf_decal/bot_white, /turf/open/floor/iron/dark, /area/station/service/library) +"bQk" = ( +/obj/machinery/light/directional/north, +/obj/machinery/asteroid_magnet{ + center_y = 61; + center_x = 105; + area_size = 3 + }, +/turf/open/floor/iron/dark, +/area/station/science/explab) "bQw" = ( /obj/effect/landmark/start/hangover, /obj/effect/turf_decal/stripes/line{ @@ -8398,6 +8390,19 @@ }, /turf/open/space, /area/space/nearstation) +"bTK" = ( +/obj/effect/turf_decal/bot, +/obj/structure/railing{ + dir = 1 + }, +/obj/machinery/smartfridge, +/obj/structure/railing{ + dir = 8; + layer = 4.1; + pixel_x = -5 + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "bTN" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -12818,6 +12823,18 @@ }, /turf/open/floor/iron, /area/station/security/execution/transfer) +"cXJ" = ( +/obj/machinery/power/solar_control{ + dir = 4; + id = "aftport"; + name = "Port Quarter Solar Control" + }, +/obj/structure/cable, +/obj/effect/turf_decal/stripes/line{ + dir = 10 + }, +/turf/open/floor/plating, +/area/station/maintenance/solars/port/aft) "cXL" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/effect/turf_decal/trimline/white/warning{ @@ -15492,6 +15509,20 @@ /obj/structure/sign/warning/radiation/directional/north, /turf/open/floor/engine, /area/station/engineering/supermatter) +"dHG" = ( +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 8 + }, +/obj/effect/turf_decal/siding/green{ + dir = 8 + }, +/obj/machinery/status_display/evac/directional/east, +/obj/structure/table/glass, +/obj/item/folder/white, +/obj/item/pen/red, +/obj/machinery/smartfridge/disks, +/turf/open/floor/iron, +/area/station/medical/pathology) "dHN" = ( /obj/machinery/door/poddoor/massdriver_chapel, /obj/structure/fans/tiny, @@ -23696,6 +23727,17 @@ /obj/effect/decal/cleanable/insectguts, /turf/open/floor/circuit, /area/station/science/research/abandoned) +"fDn" = ( +/obj/effect/turf_decal/tile/blue, +/obj/effect/turf_decal/tile/green{ + dir = 8 + }, +/obj/item/radio/intercom/directional/south, +/obj/structure/table/glass, +/obj/item/food/grown/poppy/geranium, +/obj/machinery/smartfridge/disks, +/turf/open/floor/iron, +/area/station/service/hydroponics) "fDy" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/table/wood, @@ -24939,6 +24981,17 @@ /obj/effect/turf_decal/siding/wood, /turf/open/floor/wood, /area/station/service/library) +"fTH" = ( +/obj/structure/sign/painting/library_secure{ + pixel_x = 32 + }, +/obj/structure/table/wood/fancy/blue, +/obj/machinery/door/window/left/directional/west{ + name = "Hydroponics Center" + }, +/obj/structure/window/reinforced/spawner/directional/south, +/turf/open/floor/wood/tile, +/area/station/service/library/artgallery) "fTJ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -25613,6 +25666,20 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) +"gcj" = ( +/obj/machinery/door/window/left/directional/west{ + name = "Hydroponics Center" + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/atmospherics/components/binary/pump{ + dir = 8; + name = "Justice gas pump" + }, +/obj/effect/turf_decal/siding/dark_red{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/station/security/execution/education) "gco" = ( /obj/effect/turf_decal/tile/brown/anticorner/contrasted{ dir = 8 @@ -30985,6 +31052,14 @@ }, /turf/open/floor/iron, /area/station/command/teleporter) +"hpH" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/door/window/left/directional/west{ + name = "Hydroponics Center" + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "hqf" = ( /turf/closed/wall/r_wall, /area/station/security/bitden) @@ -33564,11 +33639,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/cargo/warehouse) -"hXG" = ( -/obj/structure/lattice/catwalk, -/obj/structure/marker_beacon/lime, -/turf/open/space, -/area/space/nearstation) "hXO" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -34602,6 +34672,15 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/cargo/miningoffice) +"iip" = ( +/obj/machinery/power/smes, +/obj/machinery/light/small/directional/north, +/obj/structure/cable, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/plating, +/area/station/maintenance/solars/port/aft) "iiK" = ( /obj/structure/disposalpipe/segment, /obj/effect/landmark/start/hangover, @@ -34719,16 +34798,6 @@ /obj/machinery/light/small/directional/north, /turf/open/floor/iron, /area/station/engineering/supermatter/room) -"ikv" = ( -/obj/structure/cable, -/obj/effect/turf_decal/stripes/line{ - dir = 9 - }, -/obj/machinery/power/terminal{ - dir = 4 - }, -/turf/open/floor/plating, -/area/station/maintenance/solars/port/aft) "ikx" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -35521,6 +35590,19 @@ /obj/machinery/newscaster/directional/east, /turf/open/floor/wood, /area/station/medical/psychology) +"iuc" = ( +/obj/structure/table/glass, +/obj/machinery/newscaster/directional/west, +/obj/machinery/computer/security/telescreen/entertainment/directional/north, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 9 + }, +/obj/machinery/light/small/directional/west, +/obj/item/paper_bin, +/obj/item/clothing/gloves/latex, +/obj/item/clothing/neck/stethoscope, +/turf/open/floor/iron/white, +/area/station/medical/pathology) "iud" = ( /obj/machinery/door/airlock/external{ name = "Escape Pod 4"; @@ -36858,6 +36940,19 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/fore) +"iLa" = ( +/obj/machinery/firealarm/directional/west, +/obj/structure/table, +/obj/item/storage/box/beakers, +/obj/item/storage/box/syringes{ + pixel_x = 3; + pixel_y = 4 + }, +/obj/machinery/light_switch/directional/south{ + pixel_x = 8 + }, +/turf/open/floor/iron/checker, +/area/station/service/hydroponics) "iLq" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -41024,6 +41119,23 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/purple/visible, /turf/open/floor/iron, /area/station/engineering/atmos) +"jIH" = ( +/obj/effect/mapping_helpers/airlock/cyclelink_helper{ + dir = 4 + }, +/obj/machinery/door/airlock/external{ + name = "External Airlock" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/mapping_helpers/airlock/access/any/engineering/external, +/obj/effect/mapping_helpers/airlock/access/any/science/maintenance, +/turf/open/floor/iron, +/area/station/maintenance/port/aft) "jJc" = ( /turf/closed/wall, /area/station/security/checkpoint/arrivals) @@ -43420,6 +43532,17 @@ /obj/structure/chair/stool/directional/east, /turf/open/floor/iron/dark, /area/station/service/theater) +"kjw" = ( +/obj/structure/cable, +/obj/machinery/power/terminal{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 9 + }, +/obj/item/radio/intercom/directional/north, +/turf/open/floor/plating, +/area/station/maintenance/solars/port/aft) "kjz" = ( /obj/effect/turf_decal/tile/neutral/fourcorners, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -45208,18 +45331,6 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron/dark, /area/station/security/courtroom) -"kHK" = ( -/obj/machinery/camera/directional/north{ - c_tag = "Solar - Aft Port"; - name = "solar camera" - }, -/obj/structure/cable, -/obj/effect/turf_decal/stripes/line{ - dir = 5 - }, -/obj/item/radio/intercom/directional/north, -/turf/open/floor/plating, -/area/station/maintenance/solars/port/aft) "kHV" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/shower/directional/east{ @@ -48665,6 +48776,37 @@ /obj/effect/turf_decal/stripes/line, /turf/open/floor/iron, /area/station/engineering/main) +"lzz" = ( +/obj/machinery/power/apc/auto_name/directional/south, +/obj/structure/cable, +/obj/machinery/status_display/ai/directional/east, +/obj/structure/rack, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ + pixel_y = 0 + }, +/obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ + pixel_y = 0 + }, +/obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ + pixel_y = 6 + }, +/obj/effect/turf_decal/bot, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/turf/open/floor/iron/dark, +/area/station/ai_monitored/security/armory) "lzH" = ( /obj/structure/chair{ dir = 8 @@ -48778,9 +48920,6 @@ /obj/structure/sign/poster/contraband/random/directional/north, /turf/open/floor/iron/dark/herringbone, /area/station/security/prison) -"lAS" = ( -/turf/open/space, -/area/station/cargo/mining/asteroid_magnet) "lAV" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/duct, @@ -48889,11 +49028,6 @@ /obj/machinery/computer/diseasesplicer, /turf/open/floor/iron, /area/station/medical/pathology) -"lBL" = ( -/obj/structure/lattice/catwalk, -/obj/structure/marker_beacon/lime, -/turf/open/space/basic, -/area/space/nearstation) "lBR" = ( /obj/structure/sign/nanotrasen, /turf/closed/wall/r_wall, @@ -50109,19 +50243,6 @@ /obj/machinery/atm/directional/north, /turf/open/floor/iron, /area/station/hallway/primary/fore) -"lPs" = ( -/obj/effect/turf_decal/bot, -/obj/structure/railing{ - dir = 1 - }, -/obj/machinery/biogenerator, -/obj/structure/railing{ - dir = 4; - layer = 4.1; - pixel_x = 5 - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "lPy" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/closet/firecloset, @@ -51876,20 +51997,6 @@ }, /turf/open/floor/iron, /area/station/commons/storage/tools) -"mnA" = ( -/obj/structure/table/glass, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/turf/open/floor/iron, -/area/station/service/hydroponics) "mnF" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -51950,6 +52057,20 @@ }, /turf/open/floor/iron/dark, /area/station/security/execution/education) +"mot" = ( +/obj/structure/table/glass, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/turf/open/floor/iron, +/area/station/service/hydroponics) "mou" = ( /obj/structure/disposalpipe/segment{ dir = 6 @@ -52383,6 +52504,11 @@ /obj/effect/turf_decal/tile/yellow/fourcorners, /turf/open/floor/iron, /area/station/engineering/storage) +"mtz" = ( +/obj/structure/lattice, +/obj/structure/grille, +/turf/open/space/basic, +/area/space) "mtL" = ( /obj/effect/spawner/structure/window/reinforced, /obj/machinery/status_display/evac/directional/north, @@ -55068,20 +55194,6 @@ }, /turf/open/floor/iron, /area/station/service/hydroponics) -"mZA" = ( -/obj/machinery/door/window/left/directional/west{ - name = "Hydroponics Center" - }, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/machinery/atmospherics/components/binary/pump{ - dir = 8; - name = "Justice gas pump" - }, -/obj/effect/turf_decal/siding/dark_red{ - dir = 8 - }, -/turf/open/floor/iron/dark, -/area/station/security/execution/education) "mZK" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible{ dir = 8 @@ -59752,12 +59864,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/science/research) -"oiZ" = ( -/obj/structure/disposalpipe/segment, -/obj/structure/cable, -/obj/structure/bookcase/manuals/botany, -/turf/open/floor/iron, -/area/station/service/hydroponics) "ojb" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -60567,6 +60673,12 @@ /obj/machinery/light/directional/west, /turf/open/floor/iron/dark, /area/station/ai_monitored/security/armory) +"otU" = ( +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/structure/bookcase/manuals/botany, +/turf/open/floor/iron, +/area/station/service/hydroponics) "ouc" = ( /obj/effect/turf_decal/trimline/hot_pink/filled/line, /obj/effect/turf_decal/trimline/hot_pink/line{ @@ -60736,6 +60848,10 @@ /obj/structure/sign/departments/medbay/alt/directional/south, /turf/open/floor/iron, /area/station/hallway/primary/central/aft) +"owK" = ( +/obj/structure/lattice/catwalk, +/turf/open/space/basic, +/area/space) "owO" = ( /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 4 @@ -61242,6 +61358,17 @@ /obj/machinery/firealarm/directional/east, /turf/open/floor/iron/dark, /area/station/science/breakroom) +"oDe" = ( +/obj/machinery/camera/directional/north{ + c_tag = "Solar - Aft Port"; + name = "solar camera" + }, +/obj/structure/cable, +/obj/effect/turf_decal/stripes/line{ + dir = 5 + }, +/turf/open/floor/plating, +/area/station/maintenance/solars/port/aft) "oDf" = ( /obj/effect/turf_decal/tile/brown/half/contrasted, /turf/open/floor/iron, @@ -61764,24 +61891,6 @@ }, /turf/open/floor/iron/dark, /area/station/science/explab) -"oJj" = ( -/obj/structure/railing{ - dir = 4; - layer = 4.1; - pixel_x = 5 - }, -/obj/effect/turf_decal/delivery/white{ - color = "#52B4E9" - }, -/obj/structure/railing{ - dir = 1; - pixel_x = 5 - }, -/obj/structure/reagent_dispensers/watertank/high, -/obj/item/reagent_containers/cup/watering_can, -/obj/item/reagent_containers/cup/watering_can, -/turf/open/floor/iron/dark/textured, -/area/station/service/hydroponics) "oJy" = ( /turf/closed/wall/r_wall, /area/station/science/genetics) @@ -63057,34 +63166,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/engineering/main) -"pbN" = ( -/obj/machinery/power/apc/auto_name/directional/south, -/obj/structure/cable, -/obj/machinery/status_display/ai/directional/east, -/obj/structure/rack, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ - pixel_y = 0 - }, -/obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ - pixel_y = 0 - }, -/obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ - pixel_y = 6 - }, -/obj/effect/turf_decal/bot, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/turf/open/floor/iron/dark, -/area/station/ai_monitored/security/armory) "pbP" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -66377,19 +66458,6 @@ /obj/machinery/station_map/engineering/directional/south, /turf/open/floor/iron/white, /area/station/science/lobby) -"pOB" = ( -/obj/structure/table/glass, -/obj/machinery/newscaster/directional/west, -/obj/machinery/computer/security/telescreen/entertainment/directional/north, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 9 - }, -/obj/machinery/light/small/directional/west, -/obj/item/paper_bin, -/obj/item/clothing/gloves/latex, -/obj/item/clothing/neck/stethoscope, -/turf/open/floor/iron/white, -/area/station/medical/pathology) "pOC" = ( /obj/effect/turf_decal/tile/neutral, /turf/open/floor/iron, @@ -67931,14 +67999,6 @@ }, /turf/open/floor/iron/grimy, /area/station/security/detectives_office) -"qgR" = ( -/obj/structure/table/reinforced, -/obj/structure/window/reinforced/spawner/directional/north{ - pixel_y = 2 - }, -/obj/item/healthanalyzer, -/turf/open/floor/iron, -/area/station/science/robotics/lab) "qgU" = ( /obj/structure/disposalpipe/segment, /obj/structure/cable, @@ -69328,6 +69388,19 @@ }, /turf/open/floor/iron/dark, /area/station/engineering/transit_tube) +"qzM" = ( +/obj/effect/turf_decal/bot, +/obj/structure/railing{ + dir = 1 + }, +/obj/machinery/biogenerator, +/obj/structure/railing{ + dir = 4; + layer = 4.1; + pixel_x = 5 + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "qzT" = ( /obj/machinery/light/directional/east, /obj/effect/turf_decal/stripes/line{ @@ -69589,6 +69662,14 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/grimy, /area/station/service/chapel) +"qCr" = ( +/obj/structure/table/reinforced, +/obj/structure/window/reinforced/spawner/directional/north{ + pixel_y = 2 + }, +/obj/item/healthanalyzer, +/turf/open/floor/iron, +/area/station/science/robotics/lab) "qCA" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -70626,25 +70707,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/port) -"qNQ" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/delivery/white{ - color = "#52B4E9" - }, -/obj/structure/railing{ - dir = 1; - pixel_x = -5 - }, -/obj/structure/railing{ - dir = 8; - layer = 4.1; - pixel_x = -5 - }, -/obj/machinery/composters{ - pixel_x = -1 - }, -/turf/open/floor/iron/dark/textured, -/area/station/service/hydroponics) "qNU" = ( /obj/structure/disposalpipe/segment{ dir = 6 @@ -71636,18 +71698,6 @@ /obj/effect/turf_decal/tile/neutral/full, /turf/open/floor/iron/dark/smooth_large, /area/station/service/chapel/storage) -"rcZ" = ( -/obj/structure/cable, -/obj/effect/turf_decal/stripes/line{ - dir = 10 - }, -/obj/machinery/power/solar_control{ - dir = 4; - id = "aftport"; - name = "Port Quarter Solar Control" - }, -/turf/open/floor/plating, -/area/station/maintenance/solars/port/aft) "rde" = ( /obj/machinery/space_heater/improvised_chem_heater, /obj/effect/turf_decal/siding/thinplating/dark{ @@ -72441,17 +72491,6 @@ /obj/effect/decal/cleanable/cobweb, /turf/open/floor/iron, /area/station/maintenance/port/aft) -"rlL" = ( -/obj/effect/turf_decal/tile/blue, -/obj/effect/turf_decal/tile/green{ - dir = 8 - }, -/obj/item/radio/intercom/directional/south, -/obj/structure/table/glass, -/obj/item/food/grown/poppy/geranium, -/obj/machinery/smartfridge/disks, -/turf/open/floor/iron, -/area/station/service/hydroponics) "rlQ" = ( /obj/structure/chair{ dir = 4 @@ -75960,6 +75999,24 @@ /obj/machinery/meter, /turf/open/floor/iron/dark, /area/station/engineering/atmos) +"sdS" = ( +/obj/structure/railing{ + dir = 4; + layer = 4.1; + pixel_x = 5 + }, +/obj/effect/turf_decal/delivery/white{ + color = "#52B4E9" + }, +/obj/structure/railing{ + dir = 1; + pixel_x = 5 + }, +/obj/structure/reagent_dispensers/watertank/high, +/obj/item/reagent_containers/cup/watering_can, +/obj/item/reagent_containers/cup/watering_can, +/turf/open/floor/iron/dark/textured, +/area/station/service/hydroponics) "sef" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -76715,15 +76772,6 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/station/service/hydroponics) -"soF" = ( -/obj/machinery/light/directional/north, -/obj/machinery/asteroid_magnet{ - center_y = 59; - center_x = 101; - area_size = 7 - }, -/turf/open/floor/iron/dark, -/area/station/science/explab) "soK" = ( /obj/structure/chair{ dir = 4 @@ -80900,19 +80948,6 @@ /obj/item/pen, /turf/open/floor/iron, /area/station/science/lab) -"tpr" = ( -/obj/machinery/firealarm/directional/west, -/obj/structure/table, -/obj/item/storage/box/beakers, -/obj/item/storage/box/syringes{ - pixel_x = 3; - pixel_y = 4 - }, -/obj/machinery/light_switch/directional/south{ - pixel_x = 8 - }, -/turf/open/floor/iron/checker, -/area/station/service/hydroponics) "tpE" = ( /obj/machinery/status_display/evac/directional/east, /obj/machinery/camera/directional/east{ @@ -81014,17 +81049,6 @@ /obj/machinery/vending/wardrobe/medi_wardrobe, /turf/open/floor/iron, /area/station/medical/storage) -"tqy" = ( -/obj/structure/sign/painting/library_secure{ - pixel_x = 32 - }, -/obj/structure/table/wood/fancy/blue, -/obj/machinery/door/window/left/directional/west{ - name = "Hydroponics Center" - }, -/obj/structure/window/reinforced/spawner/directional/south, -/turf/open/floor/wood/tile, -/area/station/service/library/artgallery) "tqI" = ( /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 1 @@ -86669,6 +86693,25 @@ /obj/effect/turf_decal/stripes/line, /turf/open/floor/iron, /area/station/cargo/storage) +"uHv" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/delivery/white{ + color = "#52B4E9" + }, +/obj/structure/railing{ + dir = 1; + pixel_x = -5 + }, +/obj/structure/railing{ + dir = 8; + layer = 4.1; + pixel_x = -5 + }, +/obj/machinery/composters{ + pixel_x = -1 + }, +/turf/open/floor/iron/dark/textured, +/area/station/service/hydroponics) "uHC" = ( /obj/effect/turf_decal/tile/yellow{ dir = 1 @@ -86710,14 +86753,6 @@ /obj/structure/extinguisher_cabinet/directional/south, /turf/open/floor/iron/dark, /area/station/security/lockers) -"uHW" = ( -/obj/structure/table/reinforced, -/obj/structure/sign/departments/medbay/alt/directional/south, -/obj/machinery/light/cold/directional/east, -/obj/machinery/status_display/evac/directional/east, -/obj/item/surgery_tray, -/turf/open/floor/iron, -/area/station/science/robotics/lab) "uHZ" = ( /obj/effect/turf_decal/tile/neutral{ dir = 4 @@ -88918,6 +88953,18 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron, /area/station/engineering/atmos/mix) +"vkl" = ( +/obj/effect/turf_decal/tile/green, +/obj/effect/turf_decal/tile/blue{ + dir = 4 + }, +/obj/structure/railing{ + dir = 4; + layer = 4.1; + pixel_x = 5 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "vkv" = ( /obj/effect/turf_decal/tile/neutral/anticorner/contrasted{ dir = 8 @@ -90843,6 +90890,14 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/security/checkpoint/arrivals) +"vFX" = ( +/obj/effect/turf_decal/bot, +/obj/structure/railing{ + dir = 1 + }, +/obj/machinery/seed_extractor, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "vGc" = ( /obj/effect/turf_decal/tile/yellow{ dir = 4 @@ -92155,19 +92210,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/hallway/secondary/exit/departure_lounge) -"vZo" = ( -/obj/effect/turf_decal/bot, -/obj/structure/railing{ - dir = 1 - }, -/obj/machinery/smartfridge, -/obj/structure/railing{ - dir = 8; - layer = 4.1; - pixel_x = -5 - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "vZq" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -92456,6 +92498,14 @@ "wdb" = ( /turf/open/floor/circuit/green, /area/station/science/robotics/mechbay) +"wdg" = ( +/obj/structure/table/reinforced, +/obj/structure/sign/departments/medbay/alt/directional/south, +/obj/machinery/light/cold/directional/east, +/obj/machinery/status_display/evac/directional/east, +/obj/item/surgery_tray, +/turf/open/floor/iron, +/area/station/science/robotics/lab) "wdl" = ( /obj/structure/disposalpipe/segment{ dir = 10 @@ -95762,24 +95812,6 @@ }, /turf/open/floor/iron/half, /area/station/security/range) -"wPK" = ( -/obj/effect/mapping_helpers/airlock/cyclelink_helper{ - dir = 4 - }, -/obj/machinery/door/airlock/external{ - name = "External Airlock" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/effect/mapping_helpers/airlock/access/any/engineering/external, -/obj/effect/mapping_helpers/airlock/access/any/science/maintenance, -/obj/structure/fans/tiny, -/turf/open/floor/iron, -/area/station/maintenance/port/aft) "wPN" = ( /obj/item/kirbyplants/random, /obj/effect/turf_decal/trimline/blue/filled/corner{ @@ -97700,18 +97732,6 @@ /obj/structure/sign/departments/science/directional/south, /turf/open/floor/iron, /area/station/hallway/primary/central/aft) -"xoU" = ( -/obj/effect/turf_decal/tile/green, -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/structure/railing{ - dir = 4; - layer = 4.1; - pixel_x = 5 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) "xpr" = ( /obj/effect/spawner/random/decoration/carpet, /obj/effect/spawner/random/structure/furniture_parts, @@ -97805,15 +97825,6 @@ /obj/machinery/duct, /turf/open/floor/iron/white, /area/station/medical/pathology) -"xqs" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 8 - }, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron, -/area/station/maintenance/port/aft) "xqC" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /turf/open/floor/iron, @@ -100799,14 +100810,6 @@ "yaW" = ( /turf/open/floor/circuit, /area/station/ai_monitored/turret_protected/ai_upload) -"yba" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/door/window/left/directional/west{ - name = "Hydroponics Center" - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "ybb" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -101102,20 +101105,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/engineering/supermatter/room) -"yeT" = ( -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 8 - }, -/obj/effect/turf_decal/siding/green{ - dir = 8 - }, -/obj/machinery/status_display/evac/directional/east, -/obj/structure/table/glass, -/obj/item/folder/white, -/obj/item/pen/red, -/obj/machinery/smartfridge/disks, -/turf/open/floor/iron, -/area/station/medical/pathology) "yeZ" = ( /obj/effect/turf_decal/tile/purple, /obj/effect/turf_decal/stripes/line{ @@ -101563,10 +101552,6 @@ /obj/item/pushbroom, /turf/open/floor/iron/dark, /area/station/medical/morgue) -"ykO" = ( -/obj/structure/tank_dispenser/oxygen, -/turf/open/floor/plating, -/area/station/maintenance/port/aft) "ykX" = ( /obj/structure/table/wood, /obj/item/electronics/firelock, @@ -125245,22 +125230,22 @@ aaa aad aad rWQ -lvw -lvw -lvw -lvw -lvw -lvw -lvw -lvw -lvw -lvw -lvw -lvw -lvw -lvw -lvw -lvw +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa aaa aaa aaa @@ -125500,24 +125485,24 @@ qYo qYo aaa aad -lBL -vVc -vVc -vVc -vVc -vVc -vVc -lBL -vVc -lBL -vVc -vVc -vVc -vVc -vVc -vVc -lBL -lvw +aaa +efQ +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa aaa aaa aaa @@ -125757,24 +125742,24 @@ aaa qYo aaa aad -abj -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -vVc -lvw +aad +efQ +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa aaa aaa aaa @@ -126014,24 +125999,24 @@ aaa qYo aaa aad -vVc -lAS -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -vVc -lvw +aaa +aad +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa aaa aaa aaa @@ -126271,24 +126256,24 @@ aaa qYo aaa aad -vVc -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -vVc -lvw +aaa +aad +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa aaa aaa aaa @@ -126528,42 +126513,8 @@ aaa qYo aaa aad -vVc -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -vVc -lvw -aaa -aaa aaa aad -aad -qgl -bbD -qgl -aad -qgl -bbD -qgl -aad -qgl -bbD -qgl -aad -aac aaa aaa aaa @@ -126583,6 +126534,21 @@ aaa aaa aaa aaa +aad +aad +qgl +bbD +qgl +aad +qgl +bbD +qgl +aad +qgl +bbD +qgl +aad +aac aaa aaa aaa @@ -126595,8 +126561,27 @@ aaa aaa aaa aaa -"} -(98,1,1) = {" +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +"} +(98,1,1) = {" aaa aaa aaa @@ -126780,29 +126765,29 @@ gkT nEc qYo qYo +vVc qYo -qYo -qYo +vVc aad +abj aad abj -lAS -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -vVc -lvw +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa aaa aaa aaa @@ -127037,29 +127022,29 @@ ebX nEc qYo aaa -aaa +vVc aaa qYo aaa aad -vVc -lAS -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -vVc -lvw +aaa +abj +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +efQ +efQ +aaa efQ efQ aaa @@ -127294,28 +127279,28 @@ lxM hoT qYo qYo +vVc qYo -qYo -qYo +vVc aad +abj aad -lBL -lAS -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -lBL +abj +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +aaa +efQ +qYo qYo qYo qYo @@ -127556,29 +127541,29 @@ aaa qYo aaa aad -vVc -lAS -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz -vVc -vVc -vVc +aaa +abj +owK +owK +owK +owK +owK +owK +owK +owK +owK +aaa +aaa +mtz +aaa +efQ +qYo pSj -kun -bbD -bbD +pSj +pSj +pSj +bBc +bBc bBc bBc bBc @@ -127813,15 +127798,9 @@ aaa qYo aaa aad -lBL -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz +aaa +aaa +owK bTz bTz bTz @@ -127829,11 +127808,17 @@ bTz bTz bTz bTz -lBL +owK +jUT +jUT +mtz +jUT qYo qYo pSj qYo +qYo +qYo aad aaa aaa @@ -128070,15 +128055,9 @@ aaa qYo aaa aad -vVc -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz +aaa +aaa +owK bTz bTz bTz @@ -128086,11 +128065,17 @@ bTz bTz bTz bTz -vVc -qYo +owK +aaa +aaa +mtz +aaa +efQ qYo kun qYo +aaa +aaa aac aaa qgl @@ -128327,15 +128312,9 @@ aaa qYo aaa aad -vVc -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz +aaa +aaa +owK bTz bTz bTz @@ -128343,11 +128322,17 @@ bTz bTz bTz bTz -vVc -qYo +owK +aaa +aaa +aaa +aaa +efQ qYo kun qYo +aaa +aaa aac aaa qgl @@ -128584,15 +128569,9 @@ aaa aad aaa aad -vVc -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz +aaa +aaa +owK bTz bTz bTz @@ -128600,11 +128579,17 @@ bTz bTz bTz bTz -abj -qYo +owK +aaa +aaa +aaa +aaa +aad aad bbD aad +aad +aaa aac aad qgl @@ -128841,15 +128826,9 @@ aaa aad aaa aad -vVc -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz +aaa +aaa +owK bTz bTz bTz @@ -128857,11 +128836,17 @@ bTz bTz bTz bTz -abj -qYo +owK +aaa +aaa +aaa +aaa +aad fuV ocY fuV +aad +aaa aac aaa qgl @@ -129095,18 +129080,12 @@ aad aad aad aad -aad +abj aaa -aad abj -lAS -bTz -bTz -bTz -bTz -bTz -bTz -bTz +aad +aad +owK bTz bTz bTz @@ -129114,11 +129093,17 @@ bTz bTz bTz bTz -abj -qYo +owK +aaa +mtz +aaa +aaa +aad fuV htw fuV +aad +aad aFo aaa qgl @@ -129355,15 +129340,9 @@ aaa aad aaa aad -vVc -bTz -bTz -bTz -bTz -bTz -bTz -bTz -bTz +aaa +aaa +owK bTz bTz bTz @@ -129371,12 +129350,18 @@ bTz bTz bTz bTz -vVc +owK +jUT +mtz +jUT +jUT fuV fuV jNx fuV fuV +aad +aac aaa aaa aad @@ -129609,31 +129594,31 @@ aad aad aad aad -aad +abj aaa -aad -hXG abj -vVc -vVc -vVc -vVc -vVc -lBL -vVc -lBL -vVc -vVc -vVc -vVc -vVc -vVc -lBL +abj +abj +owK +owK +owK +owK +owK +owK +owK +owK +owK +aaa +mtz +aaa +aaa dPR -ikv +kjw uWa -rcZ +cXJ dPR +aad +aac aac aac aFo @@ -129869,28 +129854,28 @@ fLf blX cUJ kzc -wPK +jIH qQM aaa +jUT aaa aaa aaa aaa aaa aaa -aaa -aaa -aaa -aaa +jUT aaa aaa aaa aaa dPR -aUw +iip jKG eZz dPR +aad +aaa aaa aaa aad @@ -130140,14 +130125,14 @@ igg igg igg igg -eqU -aaa -aaa +aad dPR -kHK +oDe dkH qXJ dPR +aad +aad qYo aaa aad @@ -130399,12 +130384,12 @@ ntA igg qQM kzc -kzc -jtV -kyA jGs +kyA +jtV kzc qQM +qQM qYo efQ qYo @@ -130642,7 +130627,7 @@ hGW hEt nRr igg -soF +bQk fBX oIX fBX @@ -130658,7 +130643,7 @@ tTg dzF dzF frM -xqs +tlV tTg oUU wjP @@ -131048,7 +131033,7 @@ lHY oYs eWt tqe -tpr +iLa csw dzq kUA @@ -131562,16 +131547,16 @@ oYs oYs qdn inS -rlL +fDn csw csw kaw iBc -mnA +mot wYd cpI soB -oiZ +otU exv cLt xJf @@ -131924,7 +131909,7 @@ aZz kui wEI oGr -ykO +uYH ejx qQM wVd @@ -132587,8 +132572,8 @@ rkM ueJ kyR jQd -qNQ -yba +uHv +hpH hAG nHW vdN @@ -132843,7 +132828,7 @@ oYs jxU ueJ cBn -vZo +bTK kDY ezw fdY @@ -133100,7 +133085,7 @@ oYs hih ueJ cBn -bqC +vFX sic bqf uvl @@ -133357,7 +133342,7 @@ oYs rkM ueJ cBn -lPs +qzM iEr uGf hiT @@ -133615,7 +133600,7 @@ lJH ueJ rID xSz -oJj +sdS qSB aze cLO @@ -133939,8 +133924,8 @@ tlN eGy liL rmV -qgR -uHW +qCr +wdg khb bPY pOx @@ -134385,7 +134370,7 @@ wkS oYs oYs tsL -xoU +vkl arQ mZy aGp @@ -136304,7 +136289,7 @@ uKl qQM qYo tgT -pOB +iuc nJb nSp hXu @@ -137086,7 +137071,7 @@ tgT xPc umi nWg -yeT +dHG tgT tgT nPp @@ -149121,7 +149106,7 @@ eLk lsJ ffP sMB -tqy +fTH hYh qMf oci @@ -156022,7 +156007,7 @@ teo teo teo pKD -pbN +lzz bLs hEF udb @@ -158816,7 +158801,7 @@ eHO eHO omd gku -mZA +gcj eHO lhq tSk diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 556bab189828..a26d174b34db 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -388,6 +388,10 @@ /obj/effect/turf_decal/tile/yellow/opposingcorners, /turf/open/floor/iron/dark, /area/station/engineering/atmos/project) +"aiN" = ( +/obj/structure/bookcase/manuals/botany, +/turf/open/floor/iron, +/area/station/service/hydroponics) "aiT" = ( /obj/structure/sign/warning/electric_shock, /turf/closed/wall/r_wall, @@ -1370,12 +1374,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/station/hallway/primary/port) -"awK" = ( -/obj/structure/table, -/obj/item/radio/intercom/directional/north, -/obj/item/razor, -/turf/open/floor/iron/dark, -/area/station/science/robotics/lab) "axc" = ( /obj/machinery/door/firedoor/heavy, /obj/machinery/door/poddoor/preopen{ @@ -2604,27 +2602,6 @@ /obj/effect/turf_decal/box, /turf/open/floor/iron/dark, /area/station/science/ordnance/office) -"aSH" = ( -/obj/effect/turf_decal/tile/red/half/contrasted, -/obj/structure/rack, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ - pixel_y = 6 - }, -/obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ - pixel_y = 0 - }, -/turf/open/floor/iron/dark/textured, -/area/station/ai_monitored/security/armory/upper) "aSS" = ( /obj/effect/turf_decal/trimline/dark_red/end, /obj/machinery/meter, @@ -4747,6 +4724,11 @@ /obj/effect/landmark/navigate_destination/kitchen, /turf/open/floor/iron/kitchen/diagonal, /area/station/service/kitchen) +"bzt" = ( +/obj/structure/table, +/obj/item/healthanalyzer, +/turf/open/floor/iron/dark, +/area/station/science/robotics/lab) "bzB" = ( /obj/structure/window/reinforced/spawner/directional/north, /obj/structure/reagent_dispensers/watertank, @@ -5911,13 +5893,6 @@ /obj/effect/landmark/blobstart, /turf/open/floor/plating, /area/station/maintenance/port/aft) -"bPE" = ( -/obj/structure/table, -/obj/item/radio/intercom/directional/east, -/obj/effect/turf_decal/tile/green/full, -/obj/machinery/smartfridge/disks, -/turf/open/floor/iron/dark/smooth_large, -/area/station/medical/pathology) "bPP" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -8839,6 +8814,30 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/commons/locker) +"cIG" = ( +/obj/effect/turf_decal/tile/red/half/contrasted, +/obj/structure/rack, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ + pixel_y = 6 + }, +/obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ + pixel_y = 0 + }, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/turf/open/floor/iron/dark/textured, +/area/station/ai_monitored/security/armory/upper) "cIH" = ( /obj/item/clothing/glasses/sunglasses, /obj/item/stack/spacecash/c10, @@ -19211,18 +19210,6 @@ /obj/structure/sign/warning/secure_area/directional/west, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/underground/explored) -"gbF" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 9 - }, -/obj/effect/turf_decal/trimline/blue/filled/warning{ - dir = 9 - }, -/obj/machinery/light/directional/north, -/obj/structure/table/glass, -/obj/machinery/smartfridge/disks, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "gbH" = ( /obj/machinery/conveyor{ id = "mining_internal" @@ -27109,12 +27096,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central) -"iII" = ( -/obj/structure/table, -/obj/machinery/light/directional/north, -/obj/item/surgery_tray, -/turf/open/floor/iron/dark, -/area/station/science/robotics/lab) "iIW" = ( /obj/structure/table, /obj/item/plant_analyzer, @@ -30854,30 +30835,6 @@ /obj/structure/stairs/east, /turf/open/floor/plating, /area/station/hallway/primary/central/fore) -"jSM" = ( -/obj/machinery/status_display/ai/directional/north, -/obj/structure/table/glass, -/obj/item/chicken_feed{ - pixel_y = 2; - pixel_x = -5 - }, -/obj/machinery/feed_machine{ - pixel_y = 1; - pixel_x = 9 - }, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/machinery/light/directional/north, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "jTf" = ( /obj/structure/railing{ dir = 1 @@ -33052,11 +33009,6 @@ }, /turf/open/floor/iron, /area/mine/laborcamp) -"kBT" = ( -/obj/structure/table, -/obj/item/healthanalyzer, -/turf/open/floor/iron/dark, -/area/station/science/robotics/lab) "kBV" = ( /obj/structure/table, /obj/item/circuitboard/machine/chem_dispenser/drinks, @@ -33997,6 +33949,18 @@ /obj/item/crowbar/red, /turf/open/floor/glass/reinforced, /area/station/science/xenobiology) +"kRn" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 9 + }, +/obj/effect/turf_decal/trimline/blue/filled/warning{ + dir = 9 + }, +/obj/machinery/light/directional/north, +/obj/structure/table/glass, +/obj/machinery/smartfridge/disks, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "kRr" = ( /obj/machinery/door/airlock/engineering{ name = "Port Quarter Solar Access" @@ -35541,6 +35505,30 @@ "lpM" = ( /turf/closed/wall/r_wall, /area/station/command/heads_quarters/captain) +"lpP" = ( +/obj/machinery/status_display/ai/directional/north, +/obj/structure/table/glass, +/obj/item/chicken_feed{ + pixel_y = 2; + pixel_x = -5 + }, +/obj/machinery/feed_machine{ + pixel_y = 1; + pixel_x = 9 + }, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/machinery/light/directional/north, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "lpW" = ( /obj/structure/disposalpipe/segment, /turf/open/floor/plating, @@ -35768,6 +35756,12 @@ }, /turf/open/floor/iron/white, /area/station/medical/treatment_center) +"luw" = ( +/obj/structure/table, +/obj/item/clothing/gloves/latex, +/obj/machinery/airalarm/directional/north, +/turf/open/floor/iron/dark, +/area/station/science/robotics/lab) "lux" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 4 @@ -44053,6 +44047,10 @@ }, /turf/open/floor/plating, /area/station/maintenance/starboard/upper) +"nXi" = ( +/mob/living/basic/goat/pete/icebox, +/turf/open/misc/asteroid/snow/coldroom, +/area/station/service/kitchen/coldroom) "nXj" = ( /obj/machinery/vending/sovietsoda, /obj/structure/cable, @@ -45129,22 +45127,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/maintenance/starboard/upper) -"ops" = ( -/obj/structure/table/glass, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/turf_decal/siding/white{ - dir = 5 - }, -/obj/item/watertank, -/obj/item/cultivator, -/obj/item/plant_analyzer, -/obj/effect/turf_decal/tile/green/opposingcorners{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue/opposingcorners, -/turf/open/floor/iron, -/area/station/service/hydroponics) "opu" = ( /obj/structure/extinguisher_cabinet/directional/south, /obj/structure/disposalpipe/segment{ @@ -54379,6 +54361,12 @@ /obj/structure/sign/poster/official/cleanliness/directional/east, /turf/open/floor/iron, /area/station/maintenance/port/fore) +"rnm" = ( +/obj/structure/table, +/obj/item/radio/intercom/directional/north, +/obj/item/razor, +/turf/open/floor/iron/dark, +/area/station/science/robotics/lab) "rns" = ( /obj/structure/table/reinforced, /obj/item/aicard, @@ -56991,6 +56979,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/cyan/visible, /turf/open/floor/engine, /area/station/engineering/supermatter/room) +"shD" = ( +/obj/structure/table, +/obj/item/radio/intercom/directional/east, +/obj/effect/turf_decal/tile/green/full, +/obj/machinery/smartfridge/disks, +/turf/open/floor/iron/dark/smooth_large, +/area/station/medical/pathology) "shE" = ( /obj/structure/closet/secure_closet/chemical, /obj/effect/turf_decal/trimline/blue/filled/line{ @@ -58081,6 +58076,12 @@ }, /turf/open/floor/plating, /area/station/ai_monitored/turret_protected/aisat/atmos) +"szh" = ( +/obj/structure/table, +/obj/machinery/light/directional/north, +/obj/item/surgery_tray, +/turf/open/floor/iron/dark, +/area/station/science/robotics/lab) "szo" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/engineering/glass{ @@ -61074,10 +61075,6 @@ /obj/structure/grille, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) -"tCs" = ( -/obj/structure/bookcase/manuals/botany, -/turf/open/floor/iron, -/area/station/service/hydroponics) "tCx" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, @@ -62087,6 +62084,22 @@ }, /turf/open/floor/iron/dark, /area/station/service/chapel) +"tSQ" = ( +/obj/structure/table/glass, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/turf_decal/siding/white{ + dir = 5 + }, +/obj/item/watertank, +/obj/item/cultivator, +/obj/item/plant_analyzer, +/obj/effect/turf_decal/tile/green/opposingcorners{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/turf/open/floor/iron, +/area/station/service/hydroponics) "tTw" = ( /obj/structure/stairs/east, /obj/structure/railing, @@ -67982,12 +67995,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/fore) -"vPE" = ( -/obj/structure/table, -/obj/item/clothing/gloves/latex, -/obj/machinery/airalarm/directional/north, -/turf/open/floor/iron/dark, -/area/station/science/robotics/lab) "vPF" = ( /obj/machinery/power/apc/auto_name/directional/north, /obj/structure/cable, @@ -69636,15 +69643,6 @@ "wqx" = ( /turf/closed/wall/r_wall, /area/station/hallway/primary/fore) -"wqE" = ( -/mob/living/basic/goat/pete{ - desc = "Not known for their pleasant disposition. This one seems a bit more hardy to the cold."; - habitable_atmos = list("min_oxy"=1,"max_oxy"=0,"min_plas"=0,"max_plas"=1,"min_co2"=0,"max_co2"=5,"min_n2"=0,"max_n2"=0); - minimum_survivable_temperature = 150; - name = "Snowy Pete" - }, -/turf/open/misc/asteroid/snow/coldroom, -/area/station/service/kitchen/coldroom) "wqI" = ( /obj/item/radio/intercom/directional/north, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ @@ -173422,7 +173420,7 @@ rcY scw xMq hmb -gbF +kRn eYX sCZ sCZ @@ -174195,14 +174193,14 @@ gAN qXz gAy rhR -ops +tSQ lEH lgA gAy bqH jtv exw -jSM +lpP rCh jTf gUF @@ -179084,7 +179082,7 @@ dEB dMS jBB mQk -wqE +nXi wMP fwB fwB @@ -182189,7 +182187,7 @@ ueE wDk jUB vjJ -bPE +shD ffe ffe ffe @@ -232490,7 +232488,7 @@ mAe stt qum diC -aSH +cIG mwJ rUb hYu @@ -241520,7 +241518,7 @@ gmW uiw hWh hGI -tCs +aiN exw exw exw @@ -248999,7 +248997,7 @@ vzX bJJ gzB uvt -vPE +luw unw xwN npD @@ -249256,7 +249254,7 @@ kBl hOY dbx uvt -awK +rnm pra wVJ mtI @@ -249513,7 +249511,7 @@ vvP mxD cgZ uvt -iII +szh pra rdb mtI @@ -249770,7 +249768,7 @@ ddk dry apM uvt -kBT +bzt pra tSc mtI diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index 854d8c081185..c77cc4d1da6e 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -490,10 +490,6 @@ }, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/rd) -"aeL" = ( -/obj/machinery/atmospherics/pipe/layer_manifold/yellow/visible, -/turf/closed/wall/rust, -/area/station/engineering/atmos) "aeS" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -982,18 +978,6 @@ /obj/machinery/light/directional/east, /turf/open/floor/carpet/black, /area/station/security/prison) -"amu" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/turf_decal/siding/yellow{ - dir = 4 - }, -/obj/effect/turf_decal/tile/yellow/half/contrasted{ - dir = 4 - }, -/obj/effect/turf_decal/tile/red, -/obj/machinery/incident_display/delam/directional/north, -/turf/open/floor/iron, -/area/station/engineering/storage_shared) "amy" = ( /obj/machinery/door/airlock/grunge{ name = "Cell 2" @@ -1545,13 +1529,6 @@ }, /turf/open/floor/stone, /area/station/science/xenobiology) -"awG" = ( -/obj/machinery/meter, -/obj/machinery/atmospherics/pipe/layer_manifold/yellow/visible{ - dir = 4 - }, -/turf/closed/wall/r_wall/rust, -/area/station/engineering/atmos) "awR" = ( /obj/structure/table/wood, /obj/machinery/firealarm/directional/north, @@ -2801,17 +2778,6 @@ /mob/living/basic/chicken, /turf/open/floor/sandy_dirt, /area/station/service/hydroponics) -"aUv" = ( -/obj/effect/decal/cleanable/blood/drip, -/obj/effect/decal/cleanable/blood/drip{ - pixel_x = 14; - pixel_y = 13 - }, -/obj/effect/landmark/start/prisoner, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/plastic, -/area/station/security/prison/shower) "aUz" = ( /obj/structure/flora/rock/pile/style_random, /turf/open/misc/asteroid/airless, @@ -3174,6 +3140,32 @@ /obj/effect/mapping_helpers/burnt_floor, /turf/open/floor/plating, /area/station/maintenance/port/lesser) +"bbJ" = ( +/obj/effect/turf_decal/bot, +/obj/item/storage/belt/utility{ + pixel_x = 5; + pixel_y = 5 + }, +/obj/item/storage/belt/utility, +/obj/item/clothing/head/utility/welding, +/obj/item/clothing/head/utility/welding, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/structure/table, +/obj/machinery/cell_charger_multi, +/obj/item/stock_parts/cell/high, +/turf/open/floor/iron/dark, +/area/station/engineering/storage_shared) "bbM" = ( /obj/structure/disposalpipe/segment{ dir = 4 @@ -3733,10 +3725,6 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron/dark, /area/station/medical/medbay/central) -"blX" = ( -/obj/machinery/atmospherics/pipe/layer_manifold/yellow/visible, -/turf/closed/wall, -/area/station/engineering/atmos) "blZ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -3978,6 +3966,14 @@ dir = 8 }, /area/station/hallway/primary/central/fore) +"bqk" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/showroomfloor, +/area/station/medical/storage) "bqo" = ( /mob/living/basic/clown{ name = "Maniac" @@ -4000,12 +3996,6 @@ }, /turf/open/floor/iron/dark, /area/station/command/bridge) -"bqY" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/plastic, -/area/station/security/prison/shower) "brg" = ( /obj/structure/rack, /obj/effect/spawner/random/techstorage/engineering_all, @@ -5775,12 +5765,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating/airless, /area/space/nearstation) -"bUO" = ( -/obj/effect/turf_decal/box/corners{ - dir = 8 - }, -/turf/open/floor/plating/airless, -/area/space/nearstation) "bVh" = ( /obj/structure/urinal/directional/west, /obj/effect/decal/remains/human, @@ -6768,6 +6752,16 @@ "chD" = ( /turf/closed/wall, /area/station/ai_monitored/turret_protected/aisat/foyer) +"chF" = ( +/obj/effect/decal/cleanable/robot_debris/limb, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/oil/streak, +/obj/effect/decal/cleanable/robot_debris/old, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/station/service/chapel/storage) "chH" = ( /obj/structure/table/reinforced, /obj/item/paper_bin{ @@ -7333,13 +7327,6 @@ "cok" = ( /turf/closed/wall/r_wall, /area/space/nearstation) -"cos" = ( -/obj/effect/turf_decal/box, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/turf/open/floor/plating/airless, -/area/space/nearstation) "cov" = ( /obj/structure/disposaloutlet{ dir = 8 @@ -7520,12 +7507,6 @@ /obj/machinery/light/small/directional/south, /turf/open/floor/plating, /area/station/service/chapel/funeral) -"crK" = ( -/obj/effect/turf_decal/box/corners{ - dir = 1 - }, -/turf/open/floor/plating/airless, -/area/space/nearstation) "crR" = ( /obj/effect/turf_decal/stripes/line, /obj/effect/decal/cleanable/dirt, @@ -8476,11 +8457,6 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron/showroomfloor, /area/station/command/heads_quarters/cmo) -"cJu" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark, -/area/station/service/chapel) "cJv" = ( /obj/effect/turf_decal/tile/brown{ dir = 4 @@ -9909,6 +9885,31 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/fore) +"djc" = ( +/obj/machinery/door/firedoor, +/obj/structure/table/reinforced, +/obj/item/toy/figure/paramedic{ + pixel_x = 10; + pixel_y = 15 + }, +/obj/machinery/door/window/left/directional/west{ + name = "Medbay Storage" + }, +/obj/effect/mapping_helpers/airlock/access/all/medical/general, +/turf/open/floor/iron/dark, +/area/station/medical/storage) +"dje" = ( +/obj/machinery/smartfridge/chemistry/virology/preloaded, +/obj/effect/turf_decal/delivery, +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 1 + }, +/obj/machinery/smartfridge/disks{ + pixel_x = -7; + pixel_y = 15 + }, +/turf/open/floor/iron/dark, +/area/station/medical/pathology) "djo" = ( /obj/machinery/atmospherics/pipe/heat_exchanging/simple/layer2{ dir = 8 @@ -10442,19 +10443,6 @@ /obj/structure/window/reinforced/spawner/directional/south, /turf/open/misc/asteroid/airless, /area/space/nearstation) -"dqn" = ( -/obj/machinery/door/firedoor, -/obj/structure/table/reinforced, -/obj/item/toy/figure/paramedic{ - pixel_x = 10; - pixel_y = 15 - }, -/obj/machinery/door/window/left/directional/west{ - name = "Medbay Storage" - }, -/obj/effect/mapping_helpers/airlock/access/all/medical/general, -/turf/open/floor/iron/dark, -/area/station/medical/storage) "dqw" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 8 @@ -11682,32 +11670,6 @@ dir = 8 }, /area/station/service/chapel) -"dKz" = ( -/obj/effect/turf_decal/bot, -/obj/item/storage/belt/utility{ - pixel_x = 5; - pixel_y = 5 - }, -/obj/item/storage/belt/utility, -/obj/item/clothing/head/utility/welding, -/obj/item/clothing/head/utility/welding, -/obj/effect/turf_decal/stripes/corner{ - dir = 8 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/structure/table, -/obj/machinery/cell_charger_multi, -/obj/item/stock_parts/cell/high, -/turf/open/floor/iron/dark, -/area/station/engineering/storage_shared) "dKJ" = ( /turf/closed/wall/r_wall/rust, /area/station/command/heads_quarters/captain/private) @@ -12429,15 +12391,6 @@ }, /turf/open/floor/iron/dark, /area/station/maintenance/port/greater) -"dVQ" = ( -/obj/structure/cable, -/obj/effect/turf_decal/trimline/hot_pink/filled/line{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark/herringbone, -/area/station/security/prison) "dWr" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /obj/effect/turf_decal/tile/red/half/contrasted{ @@ -12765,6 +12718,18 @@ }, /turf/open/floor/iron/showroomfloor, /area/station/science/genetics) +"edY" = ( +/obj/docking_port/stationary{ + dir = 4; + dwidth = 3; + height = 14; + name = "kilo arrivals"; + roundstart_template = /datum/map_template/shuttle/arrival/kilo; + shuttle_id = "arrival_stationary"; + width = 7 + }, +/turf/open/floor/plating/airless, +/area/space/nearstation) "eeb" = ( /obj/effect/turf_decal/tile/blue{ dir = 8 @@ -14760,6 +14725,13 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/cargo/storage) +"eKq" = ( +/obj/machinery/shower/directional/west, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 8 + }, +/turf/open/floor/plastic, +/area/station/security/prison/shower) "eKA" = ( /obj/machinery/atmospherics/pipe/smart/simple/cyan/visible{ dir = 4 @@ -15482,6 +15454,15 @@ /obj/item/radio/intercom/directional/west, /turf/open/floor/plating, /area/station/maintenance/starboard) +"eVC" = ( +/obj/structure/curtain, +/obj/structure/cable, +/obj/structure/sign/directions/cryo/directional/west, +/obj/machinery/door/firedoor, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark/herringbone, +/area/station/security/prison/shower) "eVP" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/stripes/corner{ @@ -16905,6 +16886,15 @@ }, /turf/open/floor/iron/dark/corner, /area/station/hallway/primary/starboard) +"fqF" = ( +/obj/structure/cable, +/obj/effect/turf_decal/trimline/hot_pink/filled/line{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark/herringbone, +/area/station/security/prison) "fqG" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -17121,23 +17111,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark/textured, /area/station/security/prison) -"fuP" = ( -/obj/structure/rack, -/obj/item/gun/energy/disabler{ - pixel_x = -3; - pixel_y = 3 - }, -/obj/item/gun/energy/disabler, -/obj/item/gun/energy/disabler{ - pixel_x = 3; - pixel_y = -3 - }, -/obj/effect/turf_decal/bot, -/obj/structure/window/reinforced/spawner/directional/south, -/obj/structure/window/reinforced/spawner/directional/west, -/obj/effect/turf_decal/tile/neutral/anticorner/contrasted, -/turf/open/floor/iron/dark/textured_large, -/area/station/ai_monitored/security/armory) "fuX" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -17462,6 +17435,12 @@ /obj/machinery/cryopod, /turf/open/floor/iron/freezer, /area/station/hallway/secondary/exit/departure_lounge) +"fyD" = ( +/obj/effect/turf_decal/box/corners{ + dir = 1 + }, +/turf/open/floor/plating/airless, +/area/space/nearstation) "fyG" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -17652,14 +17631,6 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/maintenance, /turf/open/floor/plating, /area/station/maintenance/department/cargo) -"fBl" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/growing/tray, -/obj/effect/turf_decal/trimline/green/end{ - dir = 8 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) "fBt" = ( /obj/machinery/door/airlock/grunge{ name = "Chapel Office" @@ -17872,19 +17843,6 @@ /obj/effect/turf_decal/box, /turf/open/floor/iron/dark, /area/station/security/lockers) -"fDX" = ( -/obj/effect/turf_decal/siding/blue{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue/half/contrasted{ - dir = 1 - }, -/obj/structure/disposalpipe/segment, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/showroomfloor, -/area/station/medical/storage) "fEb" = ( /obj/effect/turf_decal/tile/neutral{ dir = 8 @@ -18255,6 +18213,11 @@ /obj/machinery/nanite_chamber, /turf/open/floor/iron/dark, /area/station/science/lab) +"fKb" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/chapel) "fKf" = ( /obj/machinery/chem_heater/withbuffer{ pixel_x = 6 @@ -18856,13 +18819,6 @@ /obj/machinery/growing/tray, /turf/open/floor/grass, /area/station/service/hydroponics/garden) -"fSM" = ( -/obj/effect/decal/cleanable/dirt, -/obj/machinery/airalarm/directional/south, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark, -/area/station/service/chapel/storage) "fSS" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -21320,12 +21276,6 @@ }, /turf/open/floor/plating, /area/station/maintenance/starboard) -"gIY" = ( -/obj/structure/sign/poster/random/directional/south, -/obj/machinery/shower/directional/north, -/obj/effect/turf_decal/box/red, -/turf/open/floor/noslip, -/area/station/medical/treatment_center) "gJc" = ( /obj/structure/railing{ dir = 1 @@ -23563,6 +23513,28 @@ }, /turf/open/floor/iron/showroomfloor, /area/station/science/research) +"hsp" = ( +/obj/effect/turf_decal/siding/blue, +/obj/effect/turf_decal/tile/blue/half/contrasted, +/obj/effect/turf_decal/tile/blue{ + dir = 8 + }, +/obj/structure/table/reinforced, +/obj/machinery/door/window/right/directional/south{ + name = "First Aid Supplies"; + req_access = list("medical"); + dir = 1 + }, +/obj/item/defibrillator/loaded{ + pixel_y = 6 + }, +/obj/item/defibrillator/loaded{ + pixel_y = 3 + }, +/obj/item/defibrillator/loaded, +/obj/effect/mapping_helpers/airlock/access/all/medical/general, +/turf/open/floor/iron/showroomfloor, +/area/station/medical/storage) "hsx" = ( /obj/machinery/vending/hydroseeds{ slogan_delay = 700 @@ -23816,32 +23788,6 @@ /obj/effect/decal/cleanable/cobweb, /turf/open/floor/iron/grimy, /area/station/hallway/primary/fore) -"hxg" = ( -/obj/effect/turf_decal/siding/blue{ - dir = 5 - }, -/obj/effect/turf_decal/tile/blue/anticorner/contrasted{ - dir = 4 - }, -/obj/effect/turf_decal/tile/blue/opposingcorners, -/obj/structure/table/reinforced, -/obj/machinery/door/window/right/directional/south{ - name = "First Aid Supplies"; - req_access = list("medical") - }, -/obj/item/storage/medkit/o2{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/item/storage/medkit/o2, -/obj/item/storage/medkit/o2{ - pixel_x = -3; - pixel_y = -3 - }, -/obj/machinery/light/directional/north, -/obj/effect/mapping_helpers/airlock/access/all/medical/general, -/turf/open/floor/iron/showroomfloor, -/area/station/medical/storage) "hxi" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -24731,14 +24677,34 @@ }, /turf/open/floor/iron/dark, /area/station/service/bar/atrium) -"hJY" = ( -/obj/machinery/door/airlock/medical/glass{ - id_tag = "medbay_front_door"; - name = "Medbay Storage" +"hJX" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/half/contrasted{ + dir = 1 + }, +/obj/structure/table/reinforced, +/obj/structure/window/spawner/directional/west, +/obj/machinery/door/window/left/directional/south{ + name = "First Aid Supplies" + }, +/obj/item/storage/medkit/toxin{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/storage/medkit/toxin, +/obj/item/storage/medkit/toxin{ + pixel_x = -3; + pixel_y = -3 + }, +/obj/machinery/requests_console/directional/north{ + assistance_requestable = 1; + department = "Medbay"; + name = "Medbay Requests Console" }, /obj/effect/mapping_helpers/airlock/access/all/medical/general, -/obj/machinery/door/firedoor, -/turf/open/floor/iron/dark, +/turf/open/floor/iron/showroomfloor, /area/station/medical/storage) "hJZ" = ( /obj/effect/turf_decal/stripes/line{ @@ -25197,6 +25163,21 @@ /obj/item/clothing/mask/surgical, /turf/open/floor/plating, /area/station/maintenance/port/greater) +"hPr" = ( +/obj/structure/table, +/obj/item/paper/guides/jobs/hydroponics, +/obj/item/reagent_containers/dropper, +/obj/effect/turf_decal/tile/green{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue{ + dir = 4 + }, +/obj/effect/turf_decal/bot, +/obj/item/toy/figure/botanist, +/obj/machinery/plantgenes, +/turf/open/floor/iron, +/area/station/service/hydroponics) "hPx" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/structure/crate, @@ -26216,15 +26197,6 @@ }, /turf/open/floor/iron/dark, /area/station/hallway/primary/port) -"idV" = ( -/obj/structure/cable, -/obj/structure/barricade/wooden/crude, -/obj/machinery/door/airlock/maintenance_hatch, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark, -/area/station/service/chapel/storage) "idY" = ( /obj/machinery/door/airlock/maintenance{ name = "Morgue Maintenance" @@ -26948,22 +26920,6 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, /area/station/hallway/primary/aft) -"ipo" = ( -/obj/machinery/chem_master/condimaster{ - desc = "Used to separate out liquids - useful for purifying botanical extracts. Also dispenses condiments."; - name = "BrewMaster 2199" - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/bot, -/obj/machinery/smartfridge/disks{ - pixel_x = -4; - pixel_y = 16 - }, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "ipq" = ( /obj/structure/flora/bush/grassy/style_random, /obj/effect/turf_decal/stripes/line, @@ -29052,14 +29008,6 @@ }, /turf/open/floor/catwalk_floor/iron_dark, /area/station/service/chapel/dock) -"iSP" = ( -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/robot_debris, -/obj/effect/decal/cleanable/oil/streak, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark, -/area/station/service/chapel/storage) "iSQ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/general/visible, /turf/closed/wall/r_wall, @@ -29224,28 +29172,6 @@ }, /turf/open/floor/iron/showroomfloor, /area/station/science/research) -"iUC" = ( -/obj/effect/turf_decal/siding/blue, -/obj/effect/turf_decal/tile/blue/half/contrasted, -/obj/effect/turf_decal/tile/blue{ - dir = 8 - }, -/obj/structure/table/reinforced, -/obj/machinery/door/window/right/directional/south{ - name = "First Aid Supplies"; - req_access = list("medical"); - dir = 1 - }, -/obj/item/defibrillator/loaded{ - pixel_y = 6 - }, -/obj/item/defibrillator/loaded{ - pixel_y = 3 - }, -/obj/item/defibrillator/loaded, -/obj/effect/mapping_helpers/airlock/access/all/medical/general, -/turf/open/floor/iron/showroomfloor, -/area/station/medical/storage) "iUF" = ( /obj/effect/turf_decal/stripes/line{ dir = 9 @@ -30629,21 +30555,13 @@ "jri" = ( /turf/closed/wall, /area/station/security/execution/transfer) -"jrr" = ( -/obj/structure/table, -/obj/item/paper/guides/jobs/hydroponics, -/obj/item/reagent_containers/dropper, -/obj/effect/turf_decal/tile/green{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue{ +"jro" = ( +/obj/effect/turf_decal/box, +/obj/effect/turf_decal/stripes/line{ dir = 4 }, -/obj/effect/turf_decal/bot, -/obj/item/toy/figure/botanist, -/obj/machinery/plantgenes, -/turf/open/floor/iron, -/area/station/service/hydroponics) +/turf/open/floor/plating/airless, +/area/space/nearstation) "jrs" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -31702,13 +31620,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/wood, /area/station/maintenance/port/fore) -"jJW" = ( -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/tile/blue, -/obj/effect/turf_decal/tile/blue/anticorner/contrasted, -/obj/machinery/medipen_refiller, -/turf/open/floor/iron/showroomfloor, -/area/station/medical/medbay/lobby) "jKj" = ( /obj/machinery/door/airlock/mining{ name = "Auxiliary Base" @@ -32319,6 +32230,14 @@ /obj/machinery/deepfryer, /turf/open/floor/iron/kitchen, /area/station/security/prison/mess) +"jTI" = ( +/obj/structure/table, +/obj/item/mmi, +/obj/item/mmi, +/obj/item/mmi, +/obj/structure/window/reinforced/spawner/directional/east, +/turf/open/floor/iron/dark, +/area/station/science/robotics/lab) "jUa" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/bot, @@ -32975,6 +32894,39 @@ /obj/structure/cable, /turf/open/floor/iron/solarpanel/airless, /area/station/solars/starboard/aft) +"kgH" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/half/contrasted{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue{ + dir = 4 + }, +/obj/structure/table/reinforced, +/obj/structure/window/spawner/directional/east, +/obj/machinery/door/window/right/directional/south{ + name = "First Aid Supplies"; + req_access = list("medical") + }, +/obj/item/storage/medkit/fire{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/storage/medkit/fire, +/obj/item/storage/medkit/fire{ + pixel_x = -3; + pixel_y = -3 + }, +/obj/machinery/camera/directional/north{ + c_tag = "Medbay Central"; + name = "medical camera"; + network = list("ss13","medical") + }, +/obj/effect/mapping_helpers/airlock/access/all/medical/general, +/turf/open/floor/iron/showroomfloor, +/area/station/medical/storage) "kgY" = ( /obj/structure/table, /obj/item/storage/portable_chem_mixer, @@ -34423,6 +34375,12 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/command/gateway) +"kGF" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plastic, +/area/station/security/prison/shower) "kGI" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/event_spawn, @@ -36725,13 +36683,6 @@ /obj/effect/decal/cleanable/blood/old, /turf/open/floor/iron/cafeteria, /area/station/service/kitchen) -"luk" = ( -/obj/machinery/light/small/directional/south, -/obj/effect/decal/cleanable/oil, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark, -/area/station/service/chapel/storage) "lun" = ( /obj/effect/turf_decal/stripes/line{ dir = 1 @@ -37070,6 +37021,12 @@ /obj/effect/turf_decal/tile/yellow/opposingcorners, /turf/open/floor/iron/showroomfloor, /area/station/medical/chemistry) +"lzP" = ( +/obj/machinery/shower/directional/north, +/obj/machinery/station_map/engineering/directional/south, +/obj/effect/turf_decal/box/red, +/turf/open/floor/noslip, +/area/station/medical/treatment_center) "lzQ" = ( /obj/machinery/door/airlock/maintenance, /obj/structure/disposalpipe/segment, @@ -37321,12 +37278,6 @@ /obj/structure/cable, /turf/open/floor/plating, /area/station/maintenance/aft) -"lDK" = ( -/obj/effect/decal/remains/robot, -/obj/effect/decal/cleanable/oil/streak, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/turf/open/floor/iron/dark, -/area/station/service/chapel/storage) "lDT" = ( /obj/machinery/light_switch/directional/east, /obj/structure/cable, @@ -37809,14 +37760,6 @@ /obj/structure/sign/departments/engineering, /turf/closed/wall, /area/station/cargo/warehouse) -"lLM" = ( -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/showroomfloor, -/area/station/medical/medbay/central) "lLN" = ( /obj/structure/fans/tiny, /obj/machinery/door/poddoor/massdriver_chapel, @@ -37998,18 +37941,6 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/starboard) -"lOt" = ( -/obj/docking_port/stationary{ - dir = 4; - dwidth = 3; - height = 14; - name = "kilo arrivals"; - roundstart_template = /datum/map_template/shuttle/arrival/kilo; - shuttle_id = "arrival_stationary"; - width = 7 - }, -/turf/open/floor/plating/airless, -/area/space/nearstation) "lOA" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 @@ -38069,13 +38000,6 @@ /obj/structure/sign/poster/contraband/random/directional/south, /turf/open/floor/plating, /area/station/maintenance/starboard) -"lPU" = ( -/obj/machinery/shower/directional/west, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 8 - }, -/turf/open/floor/plastic, -/area/station/security/prison/shower) "lPV" = ( /obj/machinery/disposal/bin, /obj/structure/disposalpipe/trunk, @@ -38592,6 +38516,14 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/central/fore) +"mar" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/robot_debris, +/obj/effect/decal/cleanable/oil/streak, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/chapel/storage) "mav" = ( /obj/structure/sign/departments/security/directional/north, /obj/effect/turf_decal/tile/red/half/contrasted{ @@ -39069,6 +39001,13 @@ dir = 1 }, /area/station/hallway/primary/starboard) +"mhB" = ( +/obj/effect/decal/cleanable/dirt, +/obj/machinery/airalarm/directional/south, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/chapel/storage) "mhP" = ( /obj/effect/turf_decal/tile/purple{ dir = 1 @@ -39652,10 +39591,27 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/commons/fitness/recreation) +"mqU" = ( +/obj/effect/decal/cleanable/blood/drip, +/obj/effect/decal/cleanable/blood/drip{ + pixel_x = 14; + pixel_y = 13 + }, +/obj/effect/landmark/start/prisoner, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/plastic, +/area/station/security/prison/shower) "mqY" = ( /obj/machinery/cryopod, /turf/open/floor/iron/freezer, /area/station/hallway/secondary/exit/departure_lounge) +"mre" = ( +/obj/structure/sign/poster/random/directional/south, +/obj/machinery/shower/directional/north, +/obj/effect/turf_decal/box/red, +/turf/open/floor/noslip, +/area/station/medical/treatment_center) "mrt" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -39794,16 +39750,6 @@ }, /turf/open/floor/iron/dark, /area/station/hallway/secondary/exit/departure_lounge) -"mtk" = ( -/obj/effect/decal/cleanable/robot_debris/limb, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/oil/streak, -/obj/effect/decal/cleanable/robot_debris/old, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 4 - }, -/turf/open/floor/iron/dark, -/area/station/service/chapel/storage) "mtq" = ( /obj/effect/turf_decal/tile/purple, /obj/structure/chair/office/light, @@ -40502,45 +40448,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/maintenance/starboard/aft) -"mFm" = ( -/obj/structure/flora/bush/sparsegrass/style_random, -/obj/structure/table/glass, -/obj/item/chicken_scanner{ - pixel_x = 6 - }, -/obj/item/chicken_scanner{ - pixel_x = 6 - }, -/obj/item/chicken_scanner{ - pixel_x = 6 - }, -/obj/item/chicken_scanner{ - pixel_x = 6 - }, -/obj/item/chicken_feed{ - pixel_y = 2; - pixel_x = -5 - }, -/obj/machinery/feed_machine{ - pixel_y = 1; - pixel_x = 9 - }, -/obj/item/storage/bag/egg{ - pixel_y = 8 - }, -/obj/item/storage/bag/egg{ - pixel_y = 8 - }, -/obj/item/storage/bag/egg{ - pixel_y = 8 - }, -/obj/item/storage/bag/egg{ - pixel_y = 8 - }, -/obj/effect/turf_decal/stripes/line, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/grass, -/area/station/service/hydroponics) "mFt" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -42281,14 +42188,6 @@ }, /turf/open/misc/asteroid, /area/space/nearstation) -"nij" = ( -/obj/structure/table, -/obj/item/mmi, -/obj/item/mmi, -/obj/item/mmi, -/obj/structure/window/reinforced/spawner/directional/east, -/turf/open/floor/iron/dark, -/area/station/science/robotics/lab) "nim" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible, @@ -45132,6 +45031,10 @@ }, /turf/open/floor/iron/dark, /area/station/hallway/secondary/service) +"ohr" = ( +/obj/machinery/atmospherics/pipe/layer_manifold/yellow/visible, +/turf/closed/wall/rust, +/area/station/engineering/atmos) "ohI" = ( /obj/structure/lattice/catwalk, /obj/structure/marker_beacon/jade, @@ -46084,18 +45987,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/security/courtroom) -"oyX" = ( -/obj/structure/table, -/obj/structure/window/reinforced/spawner/directional/east, -/obj/structure/window/reinforced/spawner/directional/north{ - pixel_y = 1 - }, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 1 - }, -/obj/item/surgery_tray, -/turf/open/floor/iron/dark, -/area/station/science/robotics/lab) "oyY" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/tank_dispenser/oxygen, @@ -46186,6 +46077,13 @@ }, /turf/closed/wall, /area/station/medical/cryo) +"oAf" = ( +/obj/machinery/light/small/directional/north, +/obj/structure/sign/warning/electric_shock/directional/north, +/obj/structure/cable, +/obj/machinery/power/smes/full, +/turf/open/floor/circuit/red/telecomms, +/area/station/tcommsat/server) "oAg" = ( /obj/structure/cable, /obj/structure/lattice/catwalk, @@ -46270,6 +46168,14 @@ /obj/item/knife/combat/survival, /turf/open/floor/carpet/green, /area/station/cargo/warehouse) +"oBq" = ( +/obj/effect/turf_decal/delivery, +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 1 + }, +/obj/effect/landmark/atmospheric_sanity/ignore_area, +/turf/open/floor/iron/dark, +/area/station/cargo/warehouse) "oBt" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /obj/effect/turf_decal/stripes/line{ @@ -46506,34 +46412,6 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/carpet/green, /area/station/maintenance/port/greater) -"oFC" = ( -/obj/item/storage/box/syringes{ - pixel_y = 23; - pixel_x = -7 - }, -/obj/item/storage/box/beakers{ - pixel_x = -1; - pixel_y = 22 - }, -/obj/item/hand_labeler{ - pixel_x = 7; - pixel_y = 17 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/machinery/camera/directional/west{ - c_tag = "Hydroponcis Fore"; - name = "hydroponics camera" - }, -/obj/effect/turf_decal/bot, -/obj/structure/bookcase/manuals/botany, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "oGo" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -48064,6 +47942,15 @@ }, /turf/open/floor/engine/air, /area/station/engineering/atmos) +"pfp" = ( +/obj/structure/cable, +/obj/structure/barricade/wooden/crude, +/obj/machinery/door/airlock/maintenance_hatch, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/chapel/storage) "pfI" = ( /mob/living/basic/clown{ name = "Lost Cause"; @@ -49205,6 +49092,19 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/wood, /area/station/maintenance/starboard/fore) +"pvJ" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/half/contrasted{ + dir = 1 + }, +/obj/structure/disposalpipe/segment, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/iron/showroomfloor, +/area/station/medical/storage) "pvK" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -50078,6 +49978,15 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/atmos/pumproom) +"pKb" = ( +/obj/machinery/door/airlock/medical/glass{ + id_tag = "medbay_front_door"; + name = "Medbay Storage" + }, +/obj/effect/mapping_helpers/airlock/access/all/medical/general, +/obj/machinery/door/firedoor, +/turf/open/floor/iron/dark, +/area/station/medical/storage) "pKm" = ( /obj/effect/turf_decal/stripes/corner{ dir = 4 @@ -52730,6 +52639,10 @@ /obj/effect/turf_decal/box, /turf/open/floor/iron/showroomfloor, /area/station/medical/cryo) +"qBu" = ( +/obj/machinery/atmospherics/pipe/layer_manifold/yellow/visible, +/turf/closed/wall, +/area/station/engineering/atmos) "qBz" = ( /obj/effect/turf_decal/stripes/corner{ dir = 1 @@ -53054,6 +52967,13 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark, /area/station/maintenance/disposal/incinerator) +"qHI" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/layer_manifold/yellow/visible{ + dir = 4 + }, +/turf/closed/wall/r_wall, +/area/station/engineering/atmos) "qHN" = ( /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -53875,14 +53795,6 @@ /obj/machinery/smartfridge/food, /turf/closed/wall, /area/station/service/kitchen) -"qUH" = ( -/obj/structure/cable, -/obj/machinery/power/apc/auto_name/directional/east, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark, -/area/station/service/chapel/storage) "qUO" = ( /obj/machinery/airalarm/directional/west, /obj/effect/turf_decal/stripes/line{ @@ -54261,12 +54173,6 @@ /obj/effect/turf_decal/tile/neutral/half/contrasted, /turf/open/floor/iron/dark, /area/station/commons/fitness/recreation) -"raH" = ( -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/structure/cable, -/obj/effect/landmark/start/chief_medical_officer, -/turf/open/floor/iron/showroomfloor, -/area/station/command/heads_quarters/cmo) "raK" = ( /obj/effect/landmark/start/scientist, /obj/effect/decal/cleanable/dirt, @@ -54731,12 +54637,6 @@ "rhf" = ( /turf/open/floor/iron/stairs/old, /area/station/maintenance/port/fore) -"rhl" = ( -/obj/machinery/shower/directional/north, -/obj/machinery/station_map/engineering/directional/south, -/obj/effect/turf_decal/box/red, -/turf/open/floor/noslip, -/area/station/medical/treatment_center) "rhv" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -54908,6 +54808,22 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark/textured_large, /area/station/ai_monitored/security/armory) +"rjG" = ( +/obj/machinery/chem_master/condimaster{ + desc = "Used to separate out liquids - useful for purifying botanical extracts. Also dispenses condiments."; + name = "BrewMaster 2199" + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/bot, +/obj/machinery/smartfridge/disks{ + pixel_x = -4; + pixel_y = 16 + }, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "rjV" = ( /obj/structure/cable, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, @@ -56684,6 +56600,14 @@ }, /turf/open/floor/iron/dark, /area/station/engineering/atmos) +"rMk" = ( +/obj/machinery/shower/directional/east, +/obj/structure/cable, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 4 + }, +/turf/open/floor/plastic, +/area/station/security/prison/shower) "rMl" = ( /obj/effect/turf_decal/stripes/corner{ dir = 8 @@ -57979,6 +57903,34 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron, /area/station/service/hydroponics) +"sgl" = ( +/obj/item/storage/box/syringes{ + pixel_y = 23; + pixel_x = -7 + }, +/obj/item/storage/box/beakers{ + pixel_x = -1; + pixel_y = 22 + }, +/obj/item/hand_labeler{ + pixel_x = 7; + pixel_y = 17 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/machinery/camera/directional/west{ + c_tag = "Hydroponcis Fore"; + name = "hydroponics camera" + }, +/obj/effect/turf_decal/bot, +/obj/structure/bookcase/manuals/botany, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "sgn" = ( /obj/effect/turf_decal/tile/yellow/half/contrasted, /obj/machinery/atmospherics/pipe/smart/simple/yellow/visible{ @@ -57994,6 +57946,17 @@ }, /turf/open/floor/iron, /area/station/security/processing) +"sgJ" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/turf_decal/tile/blue/half/contrasted{ + dir = 4 + }, +/obj/effect/turf_decal/tile/blue, +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/showroomfloor, +/area/station/medical/medbay/central) "sgW" = ( /obj/structure/window/reinforced/spawner/directional/east, /mob/living/carbon/human/species/monkey, @@ -59363,15 +59326,6 @@ }, /turf/closed/wall/r_wall/rust, /area/station/engineering/atmos/pumproom) -"sDQ" = ( -/obj/structure/curtain, -/obj/structure/cable, -/obj/structure/sign/directions/cryo/directional/west, -/obj/machinery/door/firedoor, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/dark/herringbone, -/area/station/security/prison/shower) "sDW" = ( /obj/effect/turf_decal/tile/yellow/half/contrasted{ dir = 4 @@ -59871,13 +59825,6 @@ /obj/effect/turf_decal/tile/blue, /turf/open/floor/iron, /area/station/service/janitor) -"sLU" = ( -/obj/machinery/light/small/directional/north, -/obj/structure/sign/warning/electric_shock/directional/north, -/obj/structure/cable, -/obj/machinery/power/smes/full, -/turf/open/floor/circuit/red/telecomms, -/area/station/tcommsat/server) "sLW" = ( /obj/machinery/atmospherics/pipe/smart/manifold/supply/visible{ dir = 4 @@ -60830,14 +60777,6 @@ }, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/ce) -"taA" = ( -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/structure/disposalpipe/segment, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/turf/open/floor/iron/showroomfloor, -/area/station/medical/storage) "taK" = ( /obj/effect/turf_decal/tile/purple, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -61819,6 +61758,13 @@ /obj/structure/cable, /turf/open/floor/iron/showroomfloor, /area/station/security/brig) +"tqx" = ( +/obj/machinery/meter, +/obj/machinery/atmospherics/pipe/layer_manifold/yellow/visible{ + dir = 4 + }, +/turf/closed/wall/r_wall/rust, +/area/station/engineering/atmos) "tqz" = ( /turf/closed/wall/r_wall/rust, /area/station/maintenance/central) @@ -62975,14 +62921,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/showroomfloor, /area/station/commons/toilet/restrooms) -"tMu" = ( -/obj/machinery/shower/directional/east, -/obj/structure/cable, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 4 - }, -/turf/open/floor/plastic, -/area/station/security/prison/shower) "tMD" = ( /obj/structure/table, /obj/effect/turf_decal/tile/neutral/fourcorners, @@ -63465,6 +63403,26 @@ /obj/machinery/digital_clock/directional/north, /turf/open/floor/iron/dark, /area/station/hallway/primary/central/fore) +"tTI" = ( +/obj/structure/rack, +/obj/item/gun/energy/disabler{ + pixel_x = -3; + pixel_y = 3 + }, +/obj/item/gun/energy/disabler, +/obj/item/gun/energy/disabler{ + pixel_x = 3; + pixel_y = -3 + }, +/obj/effect/turf_decal/bot, +/obj/structure/window/reinforced/spawner/directional/south, +/obj/structure/window/reinforced/spawner/directional/west, +/obj/effect/turf_decal/tile/neutral/anticorner/contrasted, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/turf/open/floor/iron/dark/textured_large, +/area/station/ai_monitored/security/armory) "tUc" = ( /obj/effect/turf_decal/stripes/line, /obj/machinery/atmospherics/pipe/smart/manifold/green/visible{ @@ -63952,9 +63910,43 @@ /obj/effect/turf_decal/tile/neutral, /turf/open/floor/iron, /area/station/security/processing) +"uar" = ( +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/showroomfloor, +/area/station/medical/medbay/central) "uax" = ( /turf/closed/wall/r_wall, /area/station/security/office) +"ubg" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 5 + }, +/obj/effect/turf_decal/tile/blue/anticorner/contrasted{ + dir = 4 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners, +/obj/structure/table/reinforced, +/obj/machinery/door/window/right/directional/south{ + name = "First Aid Supplies"; + req_access = list("medical") + }, +/obj/item/storage/medkit/o2{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/item/storage/medkit/o2, +/obj/item/storage/medkit/o2{ + pixel_x = -3; + pixel_y = -3 + }, +/obj/machinery/light/directional/north, +/obj/effect/mapping_helpers/airlock/access/all/medical/general, +/turf/open/floor/iron/showroomfloor, +/area/station/medical/storage) "ubt" = ( /obj/effect/turf_decal/stripes/corner{ dir = 1 @@ -64379,6 +64371,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/engine, /area/station/ai_monitored/turret_protected/ai_upload) +"uiJ" = ( +/obj/machinery/light/small/directional/south, +/obj/effect/decal/cleanable/oil, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/chapel/storage) "uiN" = ( /obj/effect/turf_decal/siding/wood, /obj/structure/chair/stool/directional/south, @@ -64807,18 +64806,6 @@ /obj/machinery/light/directional/south, /turf/open/floor/iron/dark, /area/station/cargo/sorting) -"upb" = ( -/obj/machinery/smartfridge/chemistry/virology/preloaded, -/obj/effect/turf_decal/delivery, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 1 - }, -/obj/machinery/smartfridge/disks{ - pixel_x = -7; - pixel_y = 15 - }, -/turf/open/floor/iron/dark, -/area/station/medical/pathology) "upt" = ( /obj/machinery/light/directional/north, /obj/effect/turf_decal/tile/red/half/contrasted{ @@ -65961,39 +65948,6 @@ /obj/effect/turf_decal/box, /turf/open/floor/iron, /area/station/commons/fitness/recreation) -"uIr" = ( -/obj/effect/turf_decal/siding/blue{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue/half/contrasted{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 4 - }, -/obj/structure/table/reinforced, -/obj/structure/window/spawner/directional/east, -/obj/machinery/door/window/right/directional/south{ - name = "First Aid Supplies"; - req_access = list("medical") - }, -/obj/item/storage/medkit/fire{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/item/storage/medkit/fire, -/obj/item/storage/medkit/fire{ - pixel_x = -3; - pixel_y = -3 - }, -/obj/machinery/camera/directional/north{ - c_tag = "Medbay Central"; - name = "medical camera"; - network = list("ss13","medical") - }, -/obj/effect/mapping_helpers/airlock/access/all/medical/general, -/turf/open/floor/iron/showroomfloor, -/area/station/medical/storage) "uIs" = ( /obj/machinery/turretid{ control_area = "/area/station/ai_monitored/turret_protected/aisat_interior"; @@ -66393,14 +66347,6 @@ /obj/structure/spider/stickyweb, /turf/open/floor/iron/dark, /area/station/maintenance/port/greater) -"uQt" = ( -/obj/effect/turf_decal/delivery, -/obj/effect/turf_decal/tile/neutral/half/contrasted{ - dir = 1 - }, -/obj/effect/landmark/atmospheric_sanity/ignore_area, -/turf/open/floor/iron/dark, -/area/station/cargo/warehouse) "uQF" = ( /obj/machinery/door/poddoor/preopen{ id = "Xenolab"; @@ -66827,6 +66773,14 @@ /obj/effect/turf_decal/tile/blue, /turf/open/floor/iron, /area/station/engineering/atmos) +"uYx" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/growing/tray, +/obj/effect/turf_decal/trimline/green/end{ + dir = 8 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "uYy" = ( /obj/structure/sign/directions/evac{ dir = 4; @@ -66938,6 +66892,33 @@ }, /turf/open/floor/plating, /area/station/maintenance/disposal/incinerator) +"vaj" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 9 + }, +/obj/effect/turf_decal/tile/blue/anticorner/contrasted{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue/opposingcorners{ + dir = 1 + }, +/obj/structure/table/reinforced, +/obj/machinery/door/window/left/directional/south{ + name = "First Aid Supplies" + }, +/obj/item/storage/medkit/brute{ + pixel_x = -3; + pixel_y = -3 + }, +/obj/item/storage/medkit/brute, +/obj/item/storage/medkit/brute{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/machinery/light/directional/north, +/obj/effect/mapping_helpers/airlock/access/all/medical/general, +/turf/open/floor/iron/showroomfloor, +/area/station/medical/storage) "vam" = ( /obj/effect/turf_decal/tile/neutral{ dir = 8 @@ -67154,6 +67135,13 @@ /obj/structure/flora/grass/jungle/b/style_5, /turf/open/misc/asteroid, /area/space/nearstation) +"vdL" = ( +/obj/structure/disposalpipe/segment, +/obj/effect/turf_decal/tile/blue, +/obj/effect/turf_decal/tile/blue/anticorner/contrasted, +/obj/machinery/medipen_refiller, +/turf/open/floor/iron/showroomfloor, +/area/station/medical/medbay/lobby) "vdS" = ( /obj/structure/lattice, /obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible{ @@ -67195,6 +67183,20 @@ }, /turf/closed/wall/r_wall, /area/station/science/xenobiology) +"veG" = ( +/obj/structure/chair/office/light{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/blue/filled/line{ + dir = 1 + }, +/obj/machinery/keycard_auth/directional/north, +/obj/machinery/light_switch/directional/north{ + pixel_x = 10 + }, +/obj/effect/landmark/start/chief_medical_officer, +/turf/open/floor/iron/showroomfloor, +/area/station/command/heads_quarters/cmo) "veP" = ( /obj/machinery/door/airlock/grunge{ name = "Restrooms" @@ -67443,17 +67445,6 @@ /obj/effect/turf_decal/siding/wood, /turf/open/floor/wood, /area/station/cargo/quartermaster) -"vil" = ( -/obj/structure/disposalpipe/segment, -/obj/effect/turf_decal/tile/blue/half/contrasted{ - dir = 4 - }, -/obj/effect/turf_decal/tile/blue, -/obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/showroomfloor, -/area/station/medical/medbay/central) "vim" = ( /obj/effect/turf_decal/siding/thinplating/light/corner{ dir = 4 @@ -69707,12 +69698,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron, /area/station/security/courtroom) -"vNt" = ( -/obj/item/radio/intercom/directional/south, -/obj/effect/turf_decal/box/red, -/obj/machinery/shower/directional/north, -/turf/open/floor/noslip, -/area/station/engineering/storage_shared) "vNB" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -69890,6 +69875,12 @@ /obj/structure/sign/warning/electric_shock, /turf/closed/wall/r_wall, /area/station/maintenance/port/lesser) +"vPu" = ( +/obj/effect/decal/remains/robot, +/obj/effect/decal/cleanable/oil/streak, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/turf/open/floor/iron/dark, +/area/station/service/chapel/storage) "vPx" = ( /obj/machinery/door/window/left/directional/north{ dir = 2; @@ -70440,33 +70431,6 @@ /obj/effect/turf_decal/tile/neutral/half/contrasted, /turf/open/floor/iron/dark, /area/station/medical/surgery/aft) -"vXg" = ( -/obj/effect/turf_decal/siding/blue{ - dir = 9 - }, -/obj/effect/turf_decal/tile/blue/anticorner/contrasted{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue/opposingcorners{ - dir = 1 - }, -/obj/structure/table/reinforced, -/obj/machinery/door/window/left/directional/south{ - name = "First Aid Supplies" - }, -/obj/item/storage/medkit/brute{ - pixel_x = -3; - pixel_y = -3 - }, -/obj/item/storage/medkit/brute, -/obj/item/storage/medkit/brute{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/machinery/light/directional/north, -/obj/effect/mapping_helpers/airlock/access/all/medical/general, -/turf/open/floor/iron/showroomfloor, -/area/station/medical/storage) "vXp" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/conveyor{ @@ -71244,6 +71208,12 @@ }, /turf/open/floor/iron/dark, /area/station/service/bar/atrium) +"wiE" = ( +/obj/effect/turf_decal/box/corners{ + dir = 8 + }, +/turf/open/floor/plating/airless, +/area/space/nearstation) "wiM" = ( /obj/structure/cable, /obj/structure/table, @@ -71437,35 +71407,20 @@ dir = 1 }, /area/station/service/chapel) -"wlL" = ( -/obj/effect/turf_decal/siding/blue{ - dir = 1 +"wlC" = ( +/obj/structure/table, +/obj/structure/window/reinforced/spawner/directional/north{ + pixel_y = 1 }, -/obj/effect/turf_decal/tile/blue/half/contrasted{ +/obj/effect/turf_decal/tile/neutral/anticorner/contrasted{ dir = 1 }, -/obj/structure/table/reinforced, -/obj/structure/window/spawner/directional/west, -/obj/machinery/door/window/left/directional/south{ - name = "First Aid Supplies" - }, -/obj/item/storage/medkit/toxin{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/item/storage/medkit/toxin, -/obj/item/storage/medkit/toxin{ - pixel_x = -3; - pixel_y = -3 - }, -/obj/machinery/requests_console/directional/north{ - assistance_requestable = 1; - department = "Medbay"; - name = "Medbay Requests Console" - }, -/obj/effect/mapping_helpers/airlock/access/all/medical/general, -/turf/open/floor/iron/showroomfloor, -/area/station/medical/storage) +/obj/item/clothing/gloves/latex, +/obj/item/healthanalyzer, +/obj/item/clothing/mask/surgical, +/obj/item/clothing/suit/apron/surgical, +/turf/open/floor/iron/dark, +/area/station/science/robotics/lab) "wlO" = ( /obj/machinery/atmospherics/components/unary/portables_connector/visible/layer4, /obj/effect/decal/cleanable/dirt, @@ -72478,6 +72433,18 @@ /obj/effect/turf_decal/tile/neutral/half/contrasted, /turf/open/floor/iron/dark, /area/station/cargo/miningoffice) +"wCi" = ( +/obj/structure/table, +/obj/structure/window/reinforced/spawner/directional/east, +/obj/structure/window/reinforced/spawner/directional/north{ + pixel_y = 1 + }, +/obj/effect/turf_decal/tile/neutral/half/contrasted{ + dir = 1 + }, +/obj/item/surgery_tray, +/turf/open/floor/iron/dark, +/area/station/science/robotics/lab) "wCq" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/light/small/directional/north, @@ -72536,6 +72503,45 @@ /obj/structure/flora/rock/pile/style_random, /turf/open/misc/asteroid/lowpressure, /area/space/nearstation) +"wDQ" = ( +/obj/structure/flora/bush/sparsegrass/style_random, +/obj/structure/table/glass, +/obj/item/chicken_scanner{ + pixel_x = 6 + }, +/obj/item/chicken_scanner{ + pixel_x = 6 + }, +/obj/item/chicken_scanner{ + pixel_x = 6 + }, +/obj/item/chicken_scanner{ + pixel_x = 6 + }, +/obj/item/chicken_feed{ + pixel_y = 2; + pixel_x = -5 + }, +/obj/machinery/feed_machine{ + pixel_y = 1; + pixel_x = 9 + }, +/obj/item/storage/bag/egg{ + pixel_y = 8 + }, +/obj/item/storage/bag/egg{ + pixel_y = 8 + }, +/obj/item/storage/bag/egg{ + pixel_y = 8 + }, +/obj/item/storage/bag/egg{ + pixel_y = 8 + }, +/obj/effect/turf_decal/stripes/line, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/grass, +/area/station/service/hydroponics) "wDX" = ( /obj/effect/mapping_helpers/broken_floor, /obj/machinery/light/small/red/directional/east, @@ -72646,13 +72652,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/hallway/primary/port) -"wGd" = ( -/obj/machinery/meter, -/obj/machinery/atmospherics/pipe/layer_manifold/yellow/visible{ - dir = 4 - }, -/turf/closed/wall/r_wall, -/area/station/engineering/atmos) "wGe" = ( /obj/effect/landmark/start/assistant, /obj/effect/turf_decal/tile/neutral/half/contrasted{ @@ -73944,6 +73943,18 @@ }, /turf/open/floor/iron/showroomfloor, /area/station/medical/chemistry) +"wYT" = ( +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/siding/yellow{ + dir = 4 + }, +/obj/effect/turf_decal/tile/yellow/half/contrasted{ + dir = 4 + }, +/obj/effect/turf_decal/tile/red, +/obj/machinery/incident_display/delam/directional/north, +/turf/open/floor/iron, +/area/station/engineering/storage_shared) "wYX" = ( /obj/structure/sign/warning, /turf/closed/wall, @@ -74142,6 +74153,14 @@ /obj/effect/landmark/start/hangover, /turf/open/floor/iron/dark, /area/station/security/courtroom) +"xcC" = ( +/obj/structure/cable, +/obj/machinery/power/apc/auto_name/directional/east, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/turf/open/floor/iron/dark, +/area/station/service/chapel/storage) "xcE" = ( /obj/structure/chair/office/light{ dir = 1; @@ -75207,20 +75226,6 @@ /obj/structure/closet/emcloset/wall/directional/west, /turf/open/floor/iron/showroomfloor, /area/station/medical/medbay/central) -"xvh" = ( -/obj/structure/table, -/obj/structure/window/reinforced/spawner/directional/north{ - pixel_y = 1 - }, -/obj/effect/turf_decal/tile/neutral/anticorner/contrasted{ - dir = 1 - }, -/obj/item/clothing/gloves/latex, -/obj/item/healthanalyzer, -/obj/item/clothing/mask/surgical, -/obj/item/clothing/suit/apron/surgical, -/turf/open/floor/iron/dark, -/area/station/science/robotics/lab) "xvj" = ( /obj/structure/flora/bush/stalky/style_random, /obj/structure/flora/bush/flowers_br/style_random, @@ -75653,20 +75658,6 @@ /obj/machinery/airalarm/directional/east, /turf/open/floor/iron/dark, /area/station/engineering/main) -"xCt" = ( -/obj/structure/chair/office/light{ - dir = 8 - }, -/obj/effect/turf_decal/trimline/blue/filled/line{ - dir = 1 - }, -/obj/machinery/keycard_auth/directional/north, -/obj/machinery/light_switch/directional/north{ - pixel_x = 10 - }, -/obj/effect/landmark/start/chief_medical_officer, -/turf/open/floor/iron/showroomfloor, -/area/station/command/heads_quarters/cmo) "xCy" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -76423,6 +76414,12 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron, /area/station/hallway/primary/port) +"xQg" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/structure/cable, +/obj/effect/landmark/start/chief_medical_officer, +/turf/open/floor/iron/showroomfloor, +/area/station/command/heads_quarters/cmo) "xQj" = ( /obj/machinery/firealarm/directional/east, /obj/effect/turf_decal/tile/neutral/half/contrasted{ @@ -76817,6 +76814,12 @@ dir = 4 }, /area/station/ai_monitored/security/armory) +"xWd" = ( +/obj/item/radio/intercom/directional/south, +/obj/effect/turf_decal/box/red, +/obj/machinery/shower/directional/north, +/turf/open/floor/noslip, +/area/station/engineering/storage_shared) "xWh" = ( /obj/structure/disposalpipe/segment, /obj/effect/turf_decal/tile/neutral{ @@ -86286,7 +86289,7 @@ aaa aaa giH obO -tMu +rMk lhv twX bzX @@ -86543,10 +86546,10 @@ aaa aaa twX gaX -aUv -bqY -sDQ -dVQ +mqU +kGF +eVC +fqF lQr fSe lWx @@ -86800,7 +86803,7 @@ aaa aaa twX byh -lPU +eKq tns twX rsk @@ -92356,7 +92359,7 @@ aeU bVv bbO dIR -mtk +chF rBV pOV ogM @@ -92612,8 +92615,8 @@ aeU aeU aeU qOd -lDK -fSM +vPu +mhB pOV pOV tiv @@ -92870,7 +92873,7 @@ aeU aeU qOd xRP -luk +uiJ ecE nUf eTS @@ -93127,7 +93130,7 @@ aeU aeU bbO wno -iSP +mar pOV sOI rjV @@ -93384,11 +93387,11 @@ aeU aeU lUq bbO -qUH -idV +xcC +pfp vmZ -cJu -cJu +fKb +fKb qci wXa siH @@ -95508,7 +95511,7 @@ xyl vbD xyl lki -gIY +mre lWI vBi hpY @@ -95765,7 +95768,7 @@ hFs muA jtr wRp -rhl +lzP lWI vjh wFG @@ -96262,7 +96265,7 @@ xtt xxk msR uxn -raH +xQg dhX gHC mYS @@ -96774,7 +96777,7 @@ pVz pVP ami xxk -xCt +veG rtU rLp xak @@ -97549,7 +97552,7 @@ lFN lBU sIP eUN -vXg +vaj uxd bnG wpP @@ -97806,7 +97809,7 @@ ukO gZX czD rwr -uIr +kgH kpm hVw qtV @@ -98063,8 +98066,8 @@ jIg pdI bPb jHY -fDX -taA +pvJ +bqk iEv wFh hea @@ -98074,7 +98077,7 @@ lFJ mcM oqe moy -lLM +uar vAW vAW pqZ @@ -98331,7 +98334,7 @@ pFu kBh gWC smk -vil +sgJ eCX xgb jrs @@ -98578,10 +98581,10 @@ dkh jUU dkh qGK -wlL +hJX kpm kpm -iUC +hsp eWd mJR wPj @@ -98835,7 +98838,7 @@ vJg fwx eMB qGK -hxg +ubg oWt vED jsh @@ -98860,7 +98863,7 @@ nEr rTK jVH vrE -upb +dje pGi hRD xDc @@ -99093,8 +99096,8 @@ eby gtK qGK qGK -dqn -hJY +djc +pKb qhU qGK lHd @@ -99411,7 +99414,7 @@ swZ uNG nPD wNz -fuP +tTI bwI bwI tPO @@ -100387,7 +100390,7 @@ fkK oqD eyA eIW -jJW +vdL vss aeH xzS @@ -104293,11 +104296,11 @@ gmG gva fLZ xLM -wGd +qHI rTi fLZ xLM -awG +tqx rTi uhp xLM @@ -106874,7 +106877,7 @@ iLQ lst pWY tzF -blX +qBu eQf fOH eSl @@ -107902,7 +107905,7 @@ xAW dkD kMq tYZ -blX +qBu eQf fOH qWT @@ -108081,7 +108084,7 @@ qlC yaN efG tPD -sLU +oAf uWU nYp mLJ @@ -108930,7 +108933,7 @@ tNB cUA aal gZm -aeL +ohr eQf fOH gyn @@ -111697,9 +111700,9 @@ hat nol lox ocZ -oFC +sgl lbj -ipo +rjG wxq wxq hat @@ -112210,7 +112213,7 @@ tWg oEc rYx udF -fBl +uYx xHP yaS rbO @@ -112465,7 +112468,7 @@ dEc umq tWg oIx -jrr +hPr cAu ppH xHP @@ -112479,7 +112482,7 @@ aMe pmc oRF oRF -mFm +wDQ izo fXQ arl @@ -112972,7 +112975,7 @@ xSO vTu dRR tmf -xvh +wlC lvV bBF jdE @@ -113030,10 +113033,10 @@ kGc mPP vww kUS -amu +wYT gDu xtc -dKz +bbJ cry cry cry @@ -113290,7 +113293,7 @@ kUS whP jWL bFv -vNt +xWd cry cry cry @@ -113486,8 +113489,8 @@ lyc cWV rqJ tmf -oyX -nij +wCi +jTI bBF weL umq @@ -113679,7 +113682,7 @@ wYC tMG gUT ihD -uQt +oBq dME aaa aaa @@ -116630,7 +116633,7 @@ bPP cko cko cko -lOt +edY cko cko cko @@ -119968,13 +119971,13 @@ sMh aeu aeu bTT -bUO +wiE cko cko cko cko cko -crK +fyD bUD aeu aeu @@ -120228,7 +120231,7 @@ vJm aeZ aeZ aeZ -cos +jro aeZ aeZ aeZ diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index c9adba0773ee..e6951002b8a6 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -2419,6 +2419,27 @@ "aRI" = ( /turf/open/floor/circuit/green, /area/station/science/robotics/mechbay) +"aRM" = ( +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap, +/obj/item/hand_labeler, +/obj/structure/table/glass, +/obj/effect/turf_decal/trimline/green/filled/corner{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/machinery/requests_console/directional/west{ + department = "Hydroponics"; + name = "Hydroponics Requests Console"; + supplies_requestable = 1 + }, +/turf/open/floor/iron, +/area/station/service/hydroponics) "aRS" = ( /obj/machinery/computer/security/telescreen/ce{ dir = 1; @@ -4366,6 +4387,19 @@ }, /turf/open/floor/wood, /area/station/service/theater) +"bzO" = ( +/obj/structure/table, +/obj/machinery/plantgenes, +/obj/item/clothing/suit/apron, +/obj/item/clothing/accessory/armband/hydro, +/obj/item/wrench, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/machinery/light/directional/west, +/obj/structure/sign/poster/random/directional/west, +/turf/open/floor/iron, +/area/station/service/hydroponics) "bzV" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/security/glass{ @@ -11563,27 +11597,6 @@ "elJ" = ( /turf/closed/wall/r_wall, /area/station/science/server) -"elM" = ( -/obj/item/stack/package_wrap, -/obj/item/stack/package_wrap, -/obj/item/stack/package_wrap, -/obj/item/stack/package_wrap, -/obj/item/stack/package_wrap, -/obj/item/hand_labeler, -/obj/structure/table/glass, -/obj/effect/turf_decal/trimline/green/filled/corner{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/machinery/requests_console/directional/west{ - department = "Hydroponics"; - name = "Hydroponics Requests Console"; - supplies_requestable = 1 - }, -/turf/open/floor/iron, -/area/station/service/hydroponics) "elT" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -12529,6 +12542,24 @@ }, /turf/closed/wall/r_wall, /area/station/command/heads_quarters/captain/private) +"eDZ" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/structure/table/wood, +/obj/machinery/microwave{ + pixel_y = 6 + }, +/obj/item/food/donkpocket/berry{ + pixel_y = 18; + pixel_x = 8 + }, +/obj/item/reagent_containers/cup/glass/bottle/beer{ + pixel_y = 21; + pixel_x = -1 + }, +/turf/open/floor/wood/parquet, +/area/station/medical/pathology) "eEf" = ( /obj/machinery/camera/directional/north{ c_tag = "Bar - Backroom" @@ -20510,6 +20541,31 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/station/hallway/primary/central) +"hwO" = ( +/obj/machinery/light/directional/north, +/obj/effect/turf_decal/stripes/line, +/obj/machinery/status_display/ai/directional/north, +/obj/structure/table/glass, +/obj/item/chicken_feed{ + pixel_y = 2; + pixel_x = -5 + }, +/obj/machinery/feed_machine{ + pixel_y = 1; + pixel_x = 9 + }, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/turf/open/floor/grass, +/area/station/service/hydroponics) "hwZ" = ( /obj/structure/chair/stool/directional/north, /obj/structure/cable, @@ -25367,12 +25423,6 @@ }, /turf/open/floor/iron, /area/station/commons/fitness/recreation) -"iYO" = ( -/obj/structure/table, -/obj/effect/turf_decal/tile/purple/half/contrasted, -/obj/item/surgery_tray, -/turf/open/floor/iron/white, -/area/station/science/robotics/lab) "iYP" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -28489,28 +28539,6 @@ }, /turf/open/floor/plating, /area/station/cargo/sorting) -"kaC" = ( -/obj/machinery/light_switch/directional/east, -/obj/effect/turf_decal/tile/red/half/contrasted{ - dir = 8 - }, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/structure/rack, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/ammo_box/magazine/m35, -/obj/item/gun/ballistic/automatic/pistol/paco/no_mag, -/obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ - pixel_y = 6 - }, -/turf/open/floor/iron/dark, -/area/station/ai_monitored/security/armory) "kaF" = ( /obj/effect/turf_decal/trimline/purple/line{ dir = 1 @@ -31273,6 +31301,25 @@ /obj/effect/mapping_helpers/airlock/access/any/medical/maintenance, /turf/open/floor/plating, /area/station/maintenance/aft/greater) +"laR" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 5 + }, +/obj/machinery/smartfridge/chemistry/virology/preloaded, +/obj/item/reagent_containers/cup/bottle/synaptizine{ + pixel_y = 19; + pixel_x = -10 + }, +/obj/item/reagent_containers/cup/bottle/sugar{ + pixel_y = 17; + pixel_x = -5 + }, +/obj/machinery/smartfridge/disks{ + pixel_x = 8; + pixel_y = 15 + }, +/turf/open/floor/wood/parquet, +/area/station/medical/pathology) "laT" = ( /obj/structure/cable, /obj/effect/decal/cleanable/dirt, @@ -32907,6 +32954,31 @@ /obj/machinery/duct, /turf/open/floor/engine, /area/station/science/xenobiology) +"lFk" = ( +/obj/machinery/light_switch/directional/east, +/obj/effect/turf_decal/tile/red/half/contrasted{ + dir = 8 + }, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/structure/rack, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/ammo_box/magazine/m35, +/obj/item/gun/ballistic/automatic/pistol/paco/no_mag, +/obj/item/gun/ballistic/automatic/pistol/paco/no_mag{ + pixel_y = 6 + }, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/turf/open/floor/iron/dark, +/area/station/ai_monitored/security/armory) "lFo" = ( /obj/structure/disposalpipe/segment{ dir = 9 @@ -33579,6 +33651,15 @@ /obj/effect/spawner/random/maintenance, /turf/open/floor/plating, /area/station/maintenance/starboard/fore) +"lRO" = ( +/obj/structure/window/spawner/directional/west, +/obj/structure/table, +/obj/effect/turf_decal/tile/purple/half/contrasted, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/turf/open/floor/iron/white, +/area/station/science/robotics/lab) "lRS" = ( /obj/machinery/atmospherics/pipe/smart/simple/green/visible, /obj/effect/spawner/structure/window/reinforced, @@ -46430,6 +46511,12 @@ }, /turf/open/floor/iron/dark, /area/station/command/bridge) +"qpt" = ( +/obj/machinery/light/small/directional/south, +/obj/structure/table, +/obj/effect/turf_decal/tile/purple/anticorner/contrasted, +/turf/open/floor/iron/white, +/area/station/science/robotics/lab) "qpD" = ( /obj/structure/sign/warning/secure_area, /turf/closed/wall/r_wall, @@ -47022,15 +47109,6 @@ /obj/effect/spawner/random/trash/janitor_supplies, /turf/open/floor/plating, /area/station/maintenance/fore) -"qBr" = ( -/obj/structure/window/spawner/directional/west, -/obj/structure/table, -/obj/effect/turf_decal/tile/purple/half/contrasted, -/obj/structure/disposalpipe/segment{ - dir = 9 - }, -/turf/open/floor/iron/white, -/area/station/science/robotics/lab) "qBy" = ( /turf/closed/wall, /area/station/command/heads_quarters/hop) @@ -52205,24 +52283,6 @@ /obj/item/training_toolbox, /turf/open/floor/iron, /area/station/commons/fitness/recreation) -"soR" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 1 - }, -/obj/structure/table/wood, -/obj/machinery/microwave{ - pixel_y = 6 - }, -/obj/item/food/donkpocket/berry{ - pixel_y = 18; - pixel_x = 8 - }, -/obj/item/reagent_containers/cup/glass/bottle/beer{ - pixel_y = 21; - pixel_x = -1 - }, -/turf/open/floor/wood/parquet, -/area/station/medical/pathology) "soW" = ( /obj/structure/rack, /obj/effect/spawner/random/techstorage/security_all, @@ -53784,15 +53844,6 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron/white, /area/station/science/cytology) -"sRb" = ( -/obj/structure/table, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/machinery/status_display/ai/directional/west, -/obj/machinery/smartfridge/disks, -/turf/open/floor/iron, -/area/station/service/hydroponics) "sRf" = ( /obj/effect/turf_decal/plaque{ icon_state = "L11" @@ -61363,19 +61414,6 @@ /obj/item/tail_pin, /turf/open/space/basic, /area/space/nearstation) -"vDt" = ( -/obj/structure/table, -/obj/machinery/plantgenes, -/obj/item/clothing/suit/apron, -/obj/item/clothing/accessory/armband/hydro, -/obj/item/wrench, -/obj/effect/turf_decal/stripes/line{ - dir = 4 - }, -/obj/machinery/light/directional/west, -/obj/structure/sign/poster/random/directional/west, -/turf/open/floor/iron, -/area/station/service/hydroponics) "vDz" = ( /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 8 @@ -63133,6 +63171,12 @@ /obj/machinery/newscaster/directional/south, /turf/open/floor/wood, /area/station/service/library) +"wij" = ( +/obj/structure/table, +/obj/effect/turf_decal/tile/purple/half/contrasted, +/obj/item/surgery_tray, +/turf/open/floor/iron/white, +/area/station/science/robotics/lab) "wit" = ( /obj/machinery/atmospherics/miner/carbon_dioxide, /turf/open/floor/engine/co2, @@ -63290,18 +63334,6 @@ }, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/rd) -"wkW" = ( -/obj/effect/turf_decal/tile/green{ - dir = 8 - }, -/obj/effect/turf_decal/tile/blue{ - dir = 1 - }, -/obj/effect/turf_decal/tile/blue, -/obj/structure/extinguisher_cabinet/directional/south, -/obj/structure/bookcase/manuals/botany, -/turf/open/floor/iron, -/area/station/service/hydroponics) "wlt" = ( /obj/structure/cable, /obj/effect/turf_decal/trimline/blue/filled/warning, @@ -64437,25 +64469,6 @@ /obj/structure/sign/poster/contraband/random/directional/north, /turf/open/floor/plating, /area/station/maintenance/starboard/lesser) -"wJI" = ( -/obj/effect/turf_decal/siding/wood{ - dir = 5 - }, -/obj/machinery/smartfridge/chemistry/virology/preloaded, -/obj/item/reagent_containers/cup/bottle/synaptizine{ - pixel_y = 19; - pixel_x = -10 - }, -/obj/item/reagent_containers/cup/bottle/sugar{ - pixel_y = 17; - pixel_x = -5 - }, -/obj/machinery/smartfridge/disks{ - pixel_x = 8; - pixel_y = 15 - }, -/turf/open/floor/wood/parquet, -/area/station/medical/pathology) "wJL" = ( /turf/open/floor/iron/dark, /area/station/security/holding_cell) @@ -64469,6 +64482,15 @@ /obj/machinery/atmospherics/components/unary/cryo_cell, /turf/open/floor/iron/dark/textured, /area/station/medical/cryo) +"wKg" = ( +/obj/structure/table, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/machinery/status_display/ai/directional/west, +/obj/machinery/smartfridge/disks, +/turf/open/floor/iron, +/area/station/service/hydroponics) "wKo" = ( /obj/structure/closet/toolcloset, /obj/effect/turf_decal/tile/yellow/anticorner/contrasted{ @@ -65699,6 +65721,18 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, /area/station/maintenance/port) +"xeX" = ( +/obj/effect/turf_decal/tile/green{ + dir = 8 + }, +/obj/effect/turf_decal/tile/blue{ + dir = 1 + }, +/obj/effect/turf_decal/tile/blue, +/obj/structure/extinguisher_cabinet/directional/south, +/obj/structure/bookcase/manuals/botany, +/turf/open/floor/iron, +/area/station/service/hydroponics) "xfe" = ( /obj/effect/turf_decal/tile/neutral, /obj/structure/disposalpipe/segment, @@ -66477,31 +66511,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/main) -"xsh" = ( -/obj/machinery/light/directional/north, -/obj/effect/turf_decal/stripes/line, -/obj/machinery/status_display/ai/directional/north, -/obj/structure/table/glass, -/obj/item/chicken_feed{ - pixel_y = 2; - pixel_x = -5 - }, -/obj/machinery/feed_machine{ - pixel_y = 1; - pixel_x = 9 - }, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/turf/open/floor/grass, -/area/station/service/hydroponics) "xsn" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/effect/turf_decal/siding/purple{ @@ -68585,12 +68594,6 @@ /obj/structure/cable, /turf/open/floor/iron/white, /area/station/science/xenobiology) -"yeS" = ( -/obj/machinery/light/small/directional/south, -/obj/structure/table, -/obj/effect/turf_decal/tile/purple/anticorner/contrasted, -/turf/open/floor/iron/white, -/area/station/science/robotics/lab) "yeV" = ( /obj/structure/closet/secure_closet/hos, /obj/item/clothing/shoes/cowboy/black, @@ -84542,7 +84545,7 @@ hZL rkz mci kQK -soR +eDZ qTr dto rFY @@ -84799,7 +84802,7 @@ sKe uuE qkR kQK -wJI +laR epW rqT dmu @@ -96529,7 +96532,7 @@ sDw eew hxF daO -kaC +lFk anl vDh ewj @@ -98664,7 +98667,7 @@ noN bCc scd vjq -qBr +lRO eut dEV gwf @@ -98921,7 +98924,7 @@ wOg nJH gso nQX -iYO +wij tga kzQ gwf @@ -99178,7 +99181,7 @@ pfK wRD sUp xIM -yeS +qpt eut beZ gwf @@ -102241,13 +102244,13 @@ wYB ebC iQI tNL -elM +aRM xOU ijv hRQ -sRb +wKg lPz -vDt +bzO xor pXj kCZ @@ -102507,7 +102510,7 @@ mrC mrC mrC upT -wkW +xeX kCZ jGv tAg @@ -104295,7 +104298,7 @@ jER rMA ukv wYB -xsh +hwO lXr lav mVi diff --git a/_maps/map_files/Ouroboros/Ouroboros.dmm b/_maps/map_files/Ouroboros/Ouroboros.dmm index bafe34f6628b..c6788d420e26 100644 --- a/_maps/map_files/Ouroboros/Ouroboros.dmm +++ b/_maps/map_files/Ouroboros/Ouroboros.dmm @@ -23476,29 +23476,6 @@ dir = 8 }, /area/station/security/office) -"hag" = ( -/obj/effect/turf_decal/trimline/green/filled/warning{ - dir = 1 - }, -/obj/structure/table/glass, -/obj/item/reagent_containers/spray/plantbgone{ - pixel_x = -3; - pixel_y = 11 - }, -/obj/item/reagent_containers/spray/plantbgone{ - pixel_x = -8; - pixel_y = 7 - }, -/obj/item/hand_labeler{ - pixel_x = 4; - pixel_y = 5 - }, -/obj/item/stack/package_wrap, -/obj/item/stack/package_wrap, -/obj/item/stack/package_wrap, -/obj/item/stack/package_wrap, -/turf/open/floor/iron/dark/smooth_edge, -/area/station/service/hydroponics) "hao" = ( /obj/structure/bed, /obj/item/bedsheet/qm, @@ -28458,6 +28435,24 @@ /obj/machinery/light/warm/dim/directional/west, /turf/open/floor/carpet, /area/station/service/abandoned_gambling_den) +"ixl" = ( +/obj/structure/rack/gunrack, +/obj/effect/turf_decal/stripes/line{ + dir = 9 + }, +/obj/effect/turf_decal/bot, +/obj/machinery/requests_console/auto_name/directional/south, +/obj/effect/mapping_helpers/requests_console/assistance, +/obj/effect/mapping_helpers/requests_console/information, +/obj/machinery/camera/motion/directional/south{ + c_tag = "Security - Armory" + }, +/obj/effect/spawner/random/armory/disablers, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/turf/open/floor/engine, +/area/station/ai_monitored/security/armory) "ixo" = ( /obj/effect/turf_decal/tile/green/opposingcorners, /obj/machinery/camera/directional/east{ @@ -39210,13 +39205,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/plating, /area/station/cargo/drone_bay) -"lBs" = ( -/obj/structure/table, -/obj/item/watertank, -/obj/item/wrench, -/obj/item/crowbar, -/turf/open/floor/iron/large, -/area/station/service/hydroponics) "lBx" = ( /obj/effect/turf_decal/siding/green/end{ dir = 8 @@ -39410,21 +39398,6 @@ }, /turf/open/floor/iron/white/diagonal, /area/station/commons/toilet/auxiliary) -"lEq" = ( -/obj/structure/rack/gunrack, -/obj/effect/turf_decal/stripes/line{ - dir = 9 - }, -/obj/effect/turf_decal/bot, -/obj/machinery/requests_console/auto_name/directional/south, -/obj/effect/mapping_helpers/requests_console/assistance, -/obj/effect/mapping_helpers/requests_console/information, -/obj/machinery/camera/motion/directional/south{ - c_tag = "Security - Armory" - }, -/obj/effect/spawner/random/armory/disablers, -/turf/open/floor/engine, -/area/station/ai_monitored/security/armory) "lEB" = ( /obj/effect/turf_decal/tile/yellow/opposingcorners, /obj/structure/railing{ @@ -41183,6 +41156,19 @@ }, /turf/open/floor/plating, /area/station/maintenance/port/lesser) +"mdW" = ( +/obj/structure/table, +/obj/item/kirbyplants/organic/plant15{ + pixel_y = 12; + pixel_x = 6 + }, +/obj/structure/lattice/catwalk, +/obj/item/radio/intercom/directional/west, +/obj/machinery/light/directional/west, +/mob/living/basic/pet/bumbles, +/obj/item/chicken_feed, +/turf/open/openspace, +/area/station/service/hydroponics/upper) "mea" = ( /obj/machinery/door/firedoor, /obj/effect/mapping_helpers/airlock/access/all/medical/psychology, @@ -41788,14 +41774,6 @@ /obj/effect/turf_decal/stripes/corner, /turf/open/floor/engine, /area/station/engineering/atmos/hfr_room) -"mmM" = ( -/obj/structure/table, -/obj/item/radio/intercom/directional/north, -/obj/machinery/light/directional/north, -/obj/machinery/light_switch/directional/west, -/obj/machinery/smartfridge/disks, -/turf/open/floor/iron/large, -/area/station/service/hydroponics) "mmP" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -43918,15 +43896,6 @@ /obj/structure/cable, /turf/open/floor/wood, /area/station/commons/dorms) -"mRw" = ( -/obj/effect/turf_decal/trimline/green/filled/warning{ - dir = 1 - }, -/obj/item/radio/intercom/directional/west, -/obj/machinery/light/directional/west, -/obj/structure/bookcase/manuals/botany, -/turf/open/floor/iron/dark/smooth_edge, -/area/station/service/hydroponics) "mRD" = ( /obj/machinery/atmospherics/pipe/smart/manifold/dark/visible{ dir = 1 @@ -47015,6 +46984,13 @@ }, /turf/open/floor/iron/dark/smooth_edge, /area/station/service/hydroponics) +"nNv" = ( +/obj/structure/table, +/obj/item/watertank, +/obj/item/wrench, +/obj/item/crowbar, +/turf/open/floor/iron/large, +/area/station/service/hydroponics) "nNF" = ( /obj/machinery/requests_console/auto_name/directional/east, /obj/effect/mapping_helpers/requests_console/assistance, @@ -50484,6 +50460,14 @@ dir = 4 }, /area/station/security/office) +"oRB" = ( +/obj/structure/table, +/obj/item/radio/intercom/directional/north, +/obj/machinery/light/directional/north, +/obj/machinery/light_switch/directional/west, +/obj/machinery/smartfridge/disks, +/turf/open/floor/iron/large, +/area/station/service/hydroponics) "oRX" = ( /obj/structure/transit_tube/curved{ dir = 4 @@ -53446,6 +53430,29 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/plating, /area/station/maintenance/port/fore) +"pMb" = ( +/obj/effect/turf_decal/trimline/green/filled/warning{ + dir = 1 + }, +/obj/structure/table/glass, +/obj/item/reagent_containers/spray/plantbgone{ + pixel_x = -3; + pixel_y = 11 + }, +/obj/item/reagent_containers/spray/plantbgone{ + pixel_x = -8; + pixel_y = 7 + }, +/obj/item/hand_labeler{ + pixel_x = 4; + pixel_y = 5 + }, +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap, +/obj/item/stack/package_wrap, +/turf/open/floor/iron/dark/smooth_edge, +/area/station/service/hydroponics) "pMi" = ( /obj/structure/railing{ dir = 4 @@ -59406,6 +59413,14 @@ }, /turf/open/openspace, /area/station/science/xenobiology) +"rDH" = ( +/obj/machinery/disease2/incubator, +/obj/machinery/smartfridge/disks{ + pixel_x = -4; + pixel_y = 14 + }, +/turf/open/floor/iron/dark, +/area/station/medical/virology) "rDQ" = ( /obj/structure/cable, /obj/effect/turf_decal/stripes/line{ @@ -62829,6 +62844,15 @@ /obj/effect/spawner/random/structure/closet_maintenance, /turf/open/floor/plating, /area/station/maintenance/starboard/greater) +"sCe" = ( +/obj/effect/turf_decal/trimline/green/filled/warning{ + dir = 1 + }, +/obj/item/radio/intercom/directional/west, +/obj/machinery/light/directional/west, +/obj/structure/bookcase/manuals/botany, +/turf/open/floor/iron/dark/smooth_edge, +/area/station/service/hydroponics) "sCh" = ( /turf/open/floor/engine, /area/station/security/range) @@ -69955,19 +69979,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/hallway/secondary/exit/escape_pod) -"uKg" = ( -/obj/structure/table, -/obj/item/kirbyplants/organic/plant15{ - pixel_y = 12; - pixel_x = 6 - }, -/obj/structure/lattice/catwalk, -/obj/item/radio/intercom/directional/west, -/obj/machinery/light/directional/west, -/mob/living/basic/pet/bumbles, -/obj/item/chicken_feed, -/turf/open/openspace, -/area/station/service/hydroponics/upper) "uKn" = ( /obj/structure/disposalpipe/junction{ dir = 4 @@ -79013,14 +79024,6 @@ "xoC" = ( /turf/closed/wall, /area/station/medical/surgery/theatre) -"xoS" = ( -/obj/machinery/disease2/incubator, -/obj/machinery/smartfridge/disks{ - pixel_x = -4; - pixel_y = 14 - }, -/turf/open/floor/iron/dark, -/area/station/medical/virology) "xoT" = ( /obj/effect/spawner/random/structure/crate, /turf/open/floor/plating, @@ -106096,9 +106099,9 @@ cEu tJE hDR qxU -hag +pMb kSJ -mRw +sCe uys fWE kSJ @@ -108154,7 +108157,7 @@ rbG icp oMF dIb -mmM +oRB uKn wvO sHu @@ -108411,7 +108414,7 @@ hDR rqT xzG dIb -lBs +nNv uTy cDP pDE @@ -122002,7 +122005,7 @@ kdj hSi rXg jsY -lEq +ixl sFW sFW wbh @@ -123850,7 +123853,7 @@ kTx vLA vLA kTx -xoS +rDH tuz neS bAS @@ -171635,7 +171638,7 @@ xtO xtO xtO tag -uKg +mdW sJc jdw bQz diff --git a/_maps/map_files/Voidraptor/VoidRaptor.dmm b/_maps/map_files/Voidraptor/VoidRaptor.dmm index 381bd7d3d918..38d356feff86 100644 --- a/_maps/map_files/Voidraptor/VoidRaptor.dmm +++ b/_maps/map_files/Voidraptor/VoidRaptor.dmm @@ -5047,16 +5047,6 @@ /obj/machinery/light/directional/north, /turf/open/floor/iron/white, /area/station/medical/pathology) -"bws" = ( -/obj/structure/table, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/turf/open/floor/wood, -/area/station/service/hydroponics/upper) "bwv" = ( /obj/effect/spawner/random/structure/crate, /obj/effect/decal/cleanable/dirt, @@ -7086,15 +7076,6 @@ /obj/effect/turf_decal/box, /turf/open/floor/engine, /area/station/science/ordnance/storage) -"cfa" = ( -/obj/effect/decal/cleanable/blood/xtracks, -/obj/machinery/door/window/brigdoor/left/directional/south{ - name = "Secure Creature Pen"; - req_access = list("xenobiology") - }, -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/engine, -/area/station/science/xenobiology) "cfm" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, @@ -16281,6 +16262,24 @@ }, /turf/open/floor/wood, /area/station/commons/vacant_room/office) +"eIc" = ( +/obj/structure/table/glass, +/obj/item/paper_bin{ + pixel_x = -6; + pixel_y = 4 + }, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 8 + }, +/obj/effect/turf_decal/bot, +/obj/item/pen{ + pixel_x = -6; + pixel_y = 4 + }, +/turf/open/floor/iron/edge{ + dir = 4 + }, +/area/station/service/hydroponics) "eId" = ( /turf/closed/wall, /area/station/hallway/primary/central/fore) @@ -18261,6 +18260,30 @@ }, /turf/open/floor/iron/textured, /area/station/cargo/lobby) +"fnq" = ( +/obj/structure/table, +/obj/machinery/button/door/directional/east{ + id = "roboticssurgery"; + name = "Robotics Surgery Privacy"; + pixel_y = -4; + req_access = list("robotics") + }, +/obj/structure/window/reinforced/spawner/directional/north, +/obj/effect/turf_decal/tile/dark_red/anticorner/contrasted{ + dir = 4 + }, +/obj/item/mmi{ + pixel_y = -14 + }, +/obj/item/mmi{ + pixel_y = -10 + }, +/obj/item/mmi{ + pixel_y = -5 + }, +/obj/item/healthanalyzer, +/turf/open/floor/iron/dark/textured, +/area/station/science/robotics/lab) "fnt" = ( /obj/structure/drain, /obj/effect/turf_decal/stripes/line{ @@ -18947,16 +18970,27 @@ /obj/structure/window/reinforced/spawner/directional/north, /turf/open/floor/carpet/stellar, /area/station/service/chapel/funeral) -"fyh" = ( -/obj/structure/bookcase/manuals/botany, -/turf/open/floor/wood, -/area/station/service/hydroponics/upper) "fys" = ( /obj/effect/turf_decal/trimline/purple/filled/warning{ dir = 1 }, /turf/open/floor/iron/white/side, /area/station/science/lab) +"fyu" = ( +/obj/machinery/door/poddoor/preopen{ + id = "Xtestlab"; + name = "Test Chamber Blast Door" + }, +/obj/item/toy/toy_xeno, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/machinery/door/window/brigdoor/left/directional/north{ + name = "Secure Creature Pen"; + req_access = list("xenobiology") + }, +/turf/open/floor/engine, +/area/station/science/xenobiology) "fyy" = ( /obj/effect/mapping_helpers/airlock/abandoned, /obj/machinery/door/airlock/maintenance{ @@ -27037,6 +27071,28 @@ dir = 1 }, /area/station/security/checkpoint/engineering) +"hPg" = ( +/obj/structure/table/reinforced, +/obj/item/clothing/suit/hooded/ablative{ + pixel_y = 7 + }, +/obj/item/gun/energy/temperature/security{ + pixel_y = 5 + }, +/obj/structure/window/reinforced/spawner/directional/south, +/obj/structure/window/reinforced/spawner/directional/east{ + layer = 2.9; + pixel_x = 4 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/turf_decal/delivery, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/turf/open/floor/iron/dark/textured_large, +/area/station/ai_monitored/security/armory) "hPi" = ( /turf/open/floor/iron/textured_large, /area/station/command/cc_dock) @@ -28376,6 +28432,10 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/port) +"iju" = ( +/obj/structure/bookcase/manuals/botany, +/turf/open/floor/wood, +/area/station/service/hydroponics/upper) "ijw" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -37008,23 +37068,6 @@ /obj/effect/turf_decal/siding/green, /turf/open/floor/iron/textured, /area/station/service/hydroponics/garden/abandoned) -"kzj" = ( -/obj/structure/table/glass, -/obj/effect/turf_decal/trimline/dark_green/filled/line, -/obj/item/stack/sheet/mineral/plasma{ - amount = 5; - pixel_x = 11; - pixel_y = 0 - }, -/obj/item/stack/sheet/mineral/uranium/five{ - pixel_x = 15; - pixel_y = 0 - }, -/obj/machinery/smartfridge/disks, -/turf/open/floor/iron/white/textured_edge{ - dir = 1 - }, -/area/station/medical/pathology) "kzk" = ( /obj/structure/table/wood, /obj/effect/decal/cleanable/cobweb/cobweb2, @@ -43818,6 +43861,16 @@ }, /turf/open/floor/wood/large, /area/station/commons/fitness/recreation/entertainment) +"mpV" = ( +/obj/structure/table, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/turf/open/floor/wood, +/area/station/service/hydroponics/upper) "mqd" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/structure/closet_empty, @@ -44333,6 +44386,18 @@ }, /turf/open/floor/plating/airless, /area/station/science/ordnance/bomb) +"mzH" = ( +/obj/machinery/smartfridge, +/obj/machinery/splicer{ + pixel_y = 12; + pixel_x = -8 + }, +/obj/machinery/smartfridge/disks{ + pixel_x = 9; + pixel_y = 14 + }, +/turf/open/floor/iron/dark/textured_large, +/area/station/service/hydroponics) "mAj" = ( /obj/machinery/power/shuttle_engine/huge{ dir = 4 @@ -44928,10 +44993,6 @@ /obj/effect/turf_decal/siding/wood, /turf/open/floor/wood/large, /area/station/security/courtroom) -"mIH" = ( -/obj/effect/decal/cleanable/blood/xtracks, -/turf/open/floor/engine, -/area/station/science/xenobiology) "mII" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ dir = 10 @@ -51821,30 +51882,6 @@ dir = 4 }, /area/station/medical/surgery) -"oEc" = ( -/obj/structure/table, -/obj/machinery/button/door/directional/east{ - id = "roboticssurgery"; - name = "Robotics Surgery Privacy"; - pixel_y = -4; - req_access = list("robotics") - }, -/obj/structure/window/reinforced/spawner/directional/north, -/obj/effect/turf_decal/tile/dark_red/anticorner/contrasted{ - dir = 4 - }, -/obj/item/mmi{ - pixel_y = -14 - }, -/obj/item/mmi{ - pixel_y = -10 - }, -/obj/item/mmi{ - pixel_y = -5 - }, -/obj/item/healthanalyzer, -/turf/open/floor/iron/dark/textured, -/area/station/science/robotics/lab) "oEk" = ( /obj/machinery/airalarm/directional/east, /obj/machinery/light/small/directional/east, @@ -53813,24 +53850,6 @@ /obj/item/folder/white, /turf/open/floor/iron/dark/textured_large, /area/station/medical/morgue) -"pep" = ( -/obj/structure/table/glass, -/obj/item/paper_bin{ - pixel_x = -6; - pixel_y = 4 - }, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 8 - }, -/obj/effect/turf_decal/bot, -/obj/item/pen{ - pixel_x = -6; - pixel_y = 4 - }, -/turf/open/floor/iron/edge{ - dir = 4 - }, -/area/station/service/hydroponics) "pev" = ( /obj/effect/turf_decal/stripes/line{ dir = 8 @@ -54425,6 +54444,28 @@ /obj/machinery/airalarm/directional/north, /turf/open/floor/iron/dark/textured, /area/station/service/hydroponics/garden) +"pmi" = ( +/obj/structure/table/glass, +/obj/item/storage/box/beakers, +/obj/item/storage/box/syringes{ + pixel_x = 3; + pixel_y = 4 + }, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 4 + }, +/obj/item/clothing/accessory/armband/hydro, +/obj/structure/extinguisher_cabinet/directional/east, +/obj/machinery/camera/directional/east{ + c_tag = "Service - Hydroponics Back"; + dir = 6; + name = "service camera" + }, +/obj/effect/turf_decal/bot, +/turf/open/floor/iron/edge{ + dir = 8 + }, +/area/station/service/hydroponics) "pmk" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -59294,25 +59335,6 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/station/maintenance/port/fore) -"qBO" = ( -/obj/structure/table/reinforced, -/obj/item/clothing/suit/hooded/ablative{ - pixel_y = 7 - }, -/obj/item/gun/energy/temperature/security{ - pixel_y = 5 - }, -/obj/structure/window/reinforced/spawner/directional/south, -/obj/structure/window/reinforced/spawner/directional/east{ - layer = 2.9; - pixel_x = 4 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/effect/turf_decal/delivery, -/turf/open/floor/iron/dark/textured_large, -/area/station/ai_monitored/security/armory) "qBR" = ( /obj/structure/transit_tube, /obj/structure/lattice, @@ -61073,18 +61095,6 @@ }, /turf/open/floor/iron/textured_large, /area/station/engineering/atmos) -"qZN" = ( -/obj/machinery/smartfridge, -/obj/machinery/splicer{ - pixel_y = 12; - pixel_x = -8 - }, -/obj/machinery/smartfridge/disks{ - pixel_x = 9; - pixel_y = 14 - }, -/turf/open/floor/iron/dark/textured_large, -/area/station/service/hydroponics) "qZQ" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ dir = 1 @@ -62919,22 +62929,6 @@ /obj/effect/landmark/start/assistant, /turf/open/floor/wood/large, /area/station/service/library) -"rCy" = ( -/obj/machinery/door/poddoor/preopen{ - id = "Xtestlab"; - name = "Test Chamber Blast Door" - }, -/obj/effect/decal/cleanable/blood/xtracks, -/obj/item/toy/toy_xeno, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/obj/machinery/door/window/brigdoor/left/directional/north{ - name = "Secure Creature Pen"; - req_access = list("xenobiology") - }, -/turf/open/floor/engine, -/area/station/science/xenobiology) "rCB" = ( /obj/structure/disposalpipe/segment, /obj/machinery/door/firedoor, @@ -63954,28 +63948,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/port) -"rSW" = ( -/obj/structure/table/glass, -/obj/item/storage/box/beakers, -/obj/item/storage/box/syringes{ - pixel_x = 3; - pixel_y = 4 - }, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 4 - }, -/obj/item/clothing/accessory/armband/hydro, -/obj/structure/extinguisher_cabinet/directional/east, -/obj/machinery/camera/directional/east{ - c_tag = "Service - Hydroponics Back"; - dir = 6; - name = "service camera" - }, -/obj/effect/turf_decal/bot, -/turf/open/floor/iron/edge{ - dir = 8 - }, -/area/station/service/hydroponics) "rSX" = ( /obj/structure/table, /obj/item/reagent_containers/condiment/saltshaker{ @@ -79857,6 +79829,23 @@ /obj/machinery/firealarm/directional/east, /turf/open/floor/iron/grimy, /area/station/security/detectives_office) +"wjt" = ( +/obj/structure/table/glass, +/obj/effect/turf_decal/trimline/dark_green/filled/line, +/obj/item/stack/sheet/mineral/plasma{ + amount = 5; + pixel_x = 11; + pixel_y = 0 + }, +/obj/item/stack/sheet/mineral/uranium/five{ + pixel_x = 15; + pixel_y = 0 + }, +/obj/machinery/smartfridge/disks, +/turf/open/floor/iron/white/textured_edge{ + dir = 1 + }, +/area/station/medical/pathology) "wjA" = ( /obj/effect/turf_decal/tile/dark_red/fourcorners, /obj/effect/turf_decal/loading_area, @@ -84870,6 +84859,14 @@ dir = 4 }, /area/station/cargo/miningdock) +"xGd" = ( +/obj/machinery/door/window/brigdoor/left/directional/south{ + name = "Secure Creature Pen"; + req_access = list("xenobiology") + }, +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/engine, +/area/station/science/xenobiology) "xGe" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -104867,7 +104864,7 @@ vMv sqo bGR sqo -kzj +wjt qbX ttw ttw @@ -105303,9 +105300,9 @@ kVR jRP abP nlj -mIH -rCy -cfa +uiw +fyu +xGd sYn vBO ktF @@ -117653,7 +117650,7 @@ kJi lTr jbi rlk -oEc +fnq gKY tlq bmt @@ -122299,7 +122296,7 @@ bPZ fLp gsl hhJ -pep +eIc udR cuJ bDA @@ -123587,7 +123584,7 @@ jru qKf nGh bYk -qZN +mzH mKb fLp ePt @@ -124868,7 +124865,7 @@ rMB fLp dyf eKj -rSW +pmi rGQ jGY xsd @@ -126418,7 +126415,7 @@ cqI xiF kVo fYs -fyh +iju jpR uKN kAB @@ -126891,7 +126888,7 @@ vwn ewC ybu cDc -qBO +hPg pKY nRV iqx @@ -127189,7 +127186,7 @@ jpR muX eKx vxA -bws +mpV ykh aqi yep diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index e41f37a3398e..ba03f5ff5785 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -2526,11 +2526,6 @@ "ajF" = ( /turf/open/floor/iron, /area/station/engineering/gravity_generator) -"ajG" = ( -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/effect/landmark/start/scientist, -/turf/open/floor/iron/dark, -/area/station/science/explab) "ajI" = ( /obj/effect/spawner/structure/window, /turf/open/floor/plating, @@ -6713,10 +6708,6 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/entry) -"bax" = ( -/obj/effect/landmark/start/scientist, -/turf/open/floor/glass/reinforced, -/area/station/science/research) "bay" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -6776,6 +6767,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white, /area/station/medical/medbay/central) +"bbI" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, +/obj/effect/landmark/start/depsec/science, +/turf/open/floor/iron, +/area/station/security/checkpoint/science) "bbS" = ( /obj/machinery/light/small/directional/north, /turf/open/floor/engine/o2, @@ -7658,6 +7656,13 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/security/prison) +"brZ" = ( +/obj/structure/chair/office/light{ + dir = 1 + }, +/obj/effect/landmark/start/research_director, +/turf/open/floor/glass/reinforced, +/area/station/command/heads_quarters/rd) "bsf" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/portable_atmospherics/canister/bz, @@ -7865,16 +7870,6 @@ }, /turf/open/floor/iron, /area/station/commons/dorms) -"buM" = ( -/obj/structure/chair/office{ - dir = 1 - }, -/obj/effect/turf_decal/trimline/purple/filled/line{ - dir = 1 - }, -/obj/effect/landmark/start/roboticist, -/turf/open/floor/iron, -/area/station/science/robotics/lab) "buQ" = ( /obj/structure/closet/secure_closet/security/sec, /obj/machinery/status_display/evac/directional/east, @@ -8652,23 +8647,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/maintenance/department/security) -"bGV" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 5 - }, -/obj/structure/table, -/obj/item/stack/sheet/cardboard, -/obj/item/paper{ - default_raw_text = "buy more donk pockets"; - name = "To-Do List" - }, -/obj/item/food/donkpocket/pizza, -/obj/machinery/camera/directional/east{ - c_tag = "Medical - Virology Break Room"; - network = list("ss13","medbay") - }, -/turf/open/floor/iron/dark, -/area/station/medical/pathology) "bHb" = ( /obj/effect/turf_decal/trimline/purple/filled/corner{ dir = 8 @@ -12499,6 +12477,15 @@ "cSr" = ( /turf/closed/wall, /area/station/service/library) +"cSO" = ( +/obj/structure/table, +/obj/machinery/camera/directional/north{ + c_tag = "Service - Hydroponics" + }, +/obj/effect/turf_decal/tile/green/fourcorners, +/obj/machinery/plantgenes, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "cSR" = ( /obj/structure/table, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -12893,6 +12880,15 @@ /obj/effect/turf_decal/trimline/purple/filled/corner, /turf/open/floor/iron/white, /area/station/science/xenobiology) +"cZN" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 4 + }, +/obj/structure/table, +/obj/item/radio/intercom/directional/east, +/obj/machinery/smartfridge/disks, +/turf/open/floor/iron/dark, +/area/station/medical/pathology) "cZT" = ( /obj/structure/alien/weeds, /obj/item/clothing/mask/facehugger/dead, @@ -13270,6 +13266,10 @@ }, /turf/open/floor/catwalk_floor, /area/station/maintenance/tram/mid) +"dge" = ( +/obj/effect/landmark/start/scientist, +/turf/open/floor/iron/white, +/area/station/science/ordnance) "dgi" = ( /obj/structure/cable, /obj/structure/disposalpipe/segment{ @@ -14384,6 +14384,23 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron, /area/station/maintenance/tram/mid) +"dzj" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 5 + }, +/obj/structure/table, +/obj/item/stack/sheet/cardboard, +/obj/item/paper{ + default_raw_text = "buy more donk pockets"; + name = "To-Do List" + }, +/obj/item/food/donkpocket/pizza, +/obj/machinery/camera/directional/east{ + c_tag = "Medical - Virology Break Room"; + network = list("ss13","medbay") + }, +/turf/open/floor/iron/dark, +/area/station/medical/pathology) "dzk" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 8 @@ -14788,18 +14805,6 @@ }, /turf/open/floor/iron, /area/station/security/checkpoint/supply) -"dGd" = ( -/obj/structure/table/glass, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 6 - }, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/obj/item/storage/bag/egg, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "dGh" = ( /obj/machinery/door/airlock/maintenance_hatch{ name = "Tunnel Access Hatch" @@ -15601,6 +15606,10 @@ "dSe" = ( /turf/closed/wall, /area/station/security/prison/mess) +"dSi" = ( +/obj/effect/landmark/start/scientist, +/turf/open/floor/glass/reinforced, +/area/station/science/research) "dSo" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/cable, @@ -16046,15 +16055,6 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/maintenance, /turf/open/floor/iron/smooth, /area/station/maintenance/port/aft) -"eah" = ( -/obj/structure/chair/office{ - dir = 8 - }, -/obj/effect/turf_decal/trimline/red/filled/line, -/obj/item/radio/intercom/directional/south, -/obj/effect/landmark/start/depsec/science, -/turf/open/floor/iron, -/area/station/security/checkpoint/science) "eal" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/trash/food_packaging, @@ -17349,16 +17349,6 @@ /obj/structure/sign/clock/directional/south, /turf/open/floor/iron/dark, /area/station/security/courtroom/holding) -"etW" = ( -/obj/structure/table/glass, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/item/chicken_scanner, -/obj/effect/turf_decal/trimline/green/filled/line, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "eud" = ( /obj/structure/lattice, /obj/structure/table, @@ -18481,6 +18471,13 @@ }, /turf/open/floor/iron, /area/station/commons/fitness) +"eOE" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 1 + }, +/obj/effect/landmark/start/depsec/science, +/turf/open/floor/iron, +/area/station/security/checkpoint/science) "eON" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 8 @@ -26982,14 +26979,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark, /area/station/medical/morgue) -"hFH" = ( -/obj/structure/cable, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 8 - }, -/obj/effect/landmark/start/scientist, -/turf/open/floor/iron/cafeteria, -/area/station/science/breakroom) "hFJ" = ( /obj/machinery/duct, /obj/structure/cable, @@ -29747,13 +29736,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/catwalk_floor, /area/station/maintenance/department/medical) -"iyh" = ( -/obj/structure/chair/office, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/structure/cable, -/obj/effect/landmark/start/scientist, -/turf/open/floor/iron, -/area/station/science/lower) "iyi" = ( /obj/effect/turf_decal/stripes/end, /obj/structure/cable/multilayer/multiz, @@ -32262,6 +32244,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/circuit/green, /area/station/ai_monitored/command/nuke_storage) +"jni" = ( +/obj/structure/chair/office, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/structure/cable, +/obj/effect/landmark/start/scientist, +/turf/open/floor/iron, +/area/station/science/lower) "jnn" = ( /obj/machinery/light/neon_lining{ dir = 8 @@ -33440,10 +33429,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/hallway/primary/tram/left) -"jFW" = ( -/obj/effect/landmark/start/roboticist, -/turf/open/floor/iron/white, -/area/station/science/robotics/lab) "jGa" = ( /obj/effect/turf_decal/trimline/brown/filled/line{ dir = 1 @@ -34698,17 +34683,6 @@ /obj/effect/turf_decal/sand/plating, /turf/open/floor/plating, /area/station/security/prison/workout) -"kav" = ( -/obj/structure/table/glass, -/obj/machinery/feed_machine, -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 10 - }, -/obj/structure/disposalpipe/segment, -/obj/item/chicken_feed, -/obj/item/chicken_feed, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "kaD" = ( /obj/structure/table, /obj/effect/turf_decal/trimline/yellow/filled/line{ @@ -35792,10 +35766,6 @@ }, /turf/open/floor/iron, /area/station/engineering/atmos) -"ksh" = ( -/obj/effect/landmark/start/scientist, -/turf/open/floor/iron/white, -/area/station/science/ordnance) "ksq" = ( /obj/effect/mapping_helpers/airlock/access/all/service/general, /obj/effect/turf_decal/trimline/neutral/filled/line, @@ -36803,6 +36773,15 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/hallway/secondary/construction/engineering) +"kIW" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/landmark/start/depsec/science, +/turf/open/floor/iron, +/area/station/security/checkpoint/science) "kIZ" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -37346,6 +37325,14 @@ "kPC" = ( /turf/closed/wall/rust, /area/station/security/prison/workout) +"kPK" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 8 + }, +/obj/effect/landmark/start/scientist, +/turf/open/floor/iron/cafeteria, +/area/station/science/breakroom) "kPT" = ( /obj/vehicle/ridden/wheelchair, /obj/effect/turf_decal/bot, @@ -37618,6 +37605,17 @@ "kUo" = ( /turf/open/floor/iron/dark, /area/station/service/chapel) +"kUA" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 1 + }, +/obj/machinery/light/directional/north, +/obj/structure/sign/clock/directional/north, +/obj/structure/cable, +/obj/structure/table, +/obj/machinery/smartfridge/disks, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "kUN" = ( /obj/machinery/door/airlock/external{ autoclose = 0; @@ -41634,15 +41632,6 @@ /obj/effect/turf_decal/tile/blue/fourcorners, /turf/open/floor/iron/white, /area/station/medical/treatment_center) -"min" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 4 - }, -/obj/structure/table, -/obj/item/radio/intercom/directional/east, -/obj/machinery/smartfridge/disks, -/turf/open/floor/iron/dark, -/area/station/medical/pathology) "miE" = ( /obj/effect/turf_decal/siding/thinplating/dark, /obj/structure/chair{ @@ -41818,21 +41807,6 @@ }, /turf/open/floor/iron/white, /area/station/science/lab) -"mlS" = ( -/obj/structure/rack, -/obj/item/gun/energy/disabler{ - pixel_x = -3; - pixel_y = 3 - }, -/obj/item/gun/energy/disabler, -/obj/item/gun/energy/disabler{ - pixel_x = 3; - pixel_y = -3 - }, -/obj/structure/window/reinforced/spawner/directional/north, -/obj/structure/window/reinforced/spawner/directional/south, -/turf/open/floor/iron, -/area/station/ai_monitored/security/armory) "mlW" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/displaycase/labcage, @@ -43011,6 +42985,14 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/white, /area/station/medical/medbay/central) +"mGk" = ( +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/obj/structure/disposalpipe/segment{ + dir = 6 + }, +/obj/effect/landmark/start/roboticist, +/turf/open/floor/iron, +/area/station/science/robotics/mechbay) "mGl" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/circuit, @@ -43149,6 +43131,19 @@ /obj/effect/decal/cleanable/blood/old, /turf/open/misc/asteroid/airless, /area/station/asteroid) +"mHU" = ( +/obj/structure/chair/office{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/effect/landmark/start/scientist, +/turf/open/floor/iron/white, +/area/station/science/ordnance/office) "mHX" = ( /obj/effect/turf_decal/trimline/dark_blue/arrow_cw{ dir = 10 @@ -43218,15 +43213,6 @@ /obj/item/radio/intercom/directional/east, /turf/open/floor/iron/white, /area/station/medical/medbay/lobby) -"mJg" = ( -/obj/structure/table, -/obj/machinery/camera/directional/north{ - c_tag = "Service - Hydroponics" - }, -/obj/effect/turf_decal/tile/green/fourcorners, -/obj/machinery/plantgenes, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "mJh" = ( /obj/effect/turf_decal/trimline/purple/filled/line{ dir = 8 @@ -43630,13 +43616,6 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, /turf/open/floor/iron, /area/station/engineering/main) -"mPV" = ( -/obj/structure/chair/office/light{ - dir = 8 - }, -/obj/effect/landmark/start/scientist, -/turf/open/floor/iron/dark, -/area/station/science/ordnance/testlab) "mQa" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth, @@ -43922,12 +43901,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron/dark, /area/station/security/interrogation) -"mWe" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, -/obj/effect/turf_decal/tile/neutral/fourcorners, -/obj/effect/landmark/start/roboticist, -/turf/open/floor/iron/dark, -/area/station/science/robotics/lab) "mWj" = ( /obj/structure/table, /obj/effect/spawner/random/food_or_drink/donkpockets, @@ -44251,6 +44224,18 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/smooth, /area/station/maintenance/department/crew_quarters/dorms) +"nbW" = ( +/obj/structure/table/glass, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 6 + }, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/obj/item/storage/bag/egg, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "nca" = ( /turf/open/openspace, /area/station/security/brig) @@ -46244,15 +46229,6 @@ /obj/item/pen/fourcolor, /turf/open/floor/iron/smooth, /area/station/maintenance/starboard/lesser) -"nHu" = ( -/obj/effect/turf_decal/trimline/red/filled/line{ - dir = 4 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/effect/landmark/start/depsec/science, -/turf/open/floor/iron, -/area/station/security/checkpoint/science) "nHW" = ( /obj/effect/turf_decal/trimline/red/filled/corner{ dir = 4 @@ -47719,14 +47695,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/dark, /area/station/engineering/gravity_generator) -"oga" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/obj/structure/disposalpipe/segment{ - dir = 6 - }, -/obj/effect/landmark/start/roboticist, -/turf/open/floor/iron, -/area/station/science/robotics/mechbay) "ogp" = ( /obj/structure/table/wood, /turf/open/floor/wood/tile, @@ -49294,17 +49262,6 @@ /obj/effect/turf_decal/trimline/dark_green/filled/line, /turf/open/floor/iron/white, /area/station/science/genetics) -"oIk" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 1 - }, -/obj/machinery/light/directional/north, -/obj/structure/sign/clock/directional/north, -/obj/structure/cable, -/obj/structure/table, -/obj/machinery/smartfridge/disks, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "oIo" = ( /obj/structure/disposalpipe/sorting/mail/flip{ dir = 4 @@ -51087,6 +51044,24 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/station/hallway/secondary/service) +"ppd" = ( +/obj/structure/rack, +/obj/item/gun/energy/disabler{ + pixel_x = -3; + pixel_y = 3 + }, +/obj/item/gun/energy/disabler, +/obj/item/gun/energy/disabler{ + pixel_x = 3; + pixel_y = -3 + }, +/obj/structure/window/reinforced/spawner/directional/north, +/obj/structure/window/reinforced/spawner/directional/south, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/obj/item/gun/energy/taser, +/turf/open/floor/iron, +/area/station/ai_monitored/security/armory) "pph" = ( /obj/structure/table/glass, /obj/item/storage/box/syringes{ @@ -52552,6 +52527,16 @@ }, /turf/open/floor/iron, /area/station/security/prison) +"pJH" = ( +/obj/structure/chair/office{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/purple/filled/line{ + dir = 1 + }, +/obj/effect/landmark/start/roboticist, +/turf/open/floor/iron, +/area/station/science/robotics/lab) "pJJ" = ( /obj/structure/disposalpipe/segment, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -53839,6 +53824,13 @@ /obj/structure/cable, /turf/open/floor/iron/dark, /area/station/commons/fitness/recreation/entertainment) +"qew" = ( +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 5 + }, +/obj/structure/bookcase/manuals/botany, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "qeD" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 8 @@ -55565,6 +55557,16 @@ }, /turf/open/floor/iron, /area/station/security/execution/transfer) +"qGx" = ( +/obj/structure/table/glass, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/item/chicken_scanner, +/obj/effect/turf_decal/trimline/green/filled/line, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "qGy" = ( /obj/structure/transit_tube/crossing, /turf/open/floor/plating/airless, @@ -56403,13 +56405,6 @@ "qUB" = ( /turf/closed/wall, /area/station/hallway/secondary/exit) -"qUC" = ( -/obj/structure/chair/office/light{ - dir = 1 - }, -/obj/effect/landmark/start/research_director, -/turf/open/floor/glass/reinforced, -/area/station/command/heads_quarters/rd) "qUF" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ dir = 4 @@ -58022,6 +58017,10 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/command/nuke_storage) +"rsK" = ( +/obj/effect/landmark/start/roboticist, +/turf/open/floor/iron/white, +/area/station/science/robotics/lab) "rsL" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -59557,6 +59556,15 @@ "rUR" = ( /turf/closed/wall/r_wall, /area/station/ai_monitored/command/nuke_storage) +"rVl" = ( +/obj/structure/chair/office{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/red/filled/line, +/obj/item/radio/intercom/directional/south, +/obj/effect/landmark/start/depsec/science, +/turf/open/floor/iron, +/area/station/security/checkpoint/science) "rVp" = ( /obj/effect/turf_decal/tile/blue/opposingcorners{ dir = 1 @@ -62100,6 +62108,11 @@ }, /turf/open/floor/iron, /area/station/hallway/secondary/command) +"sLc" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/landmark/start/scientist, +/turf/open/floor/iron/dark, +/area/station/science/explab) "sLd" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -62812,13 +62825,6 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/cafeteria, /area/station/security/prison/mess) -"sVG" = ( -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 4 - }, -/obj/effect/landmark/start/depsec/science, -/turf/open/floor/iron, -/area/station/security/checkpoint/science) "sVV" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/spawner/random/engineering/material_cheap, @@ -63939,6 +63945,12 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/iron, /area/station/security/execution/transfer) +"tnU" = ( +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/landmark/start/roboticist, +/turf/open/floor/iron/dark, +/area/station/science/robotics/lab) "tnV" = ( /obj/effect/landmark/event_spawn, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ @@ -69945,6 +69957,17 @@ /obj/item/stock_parts/cell/high/empty, /turf/open/floor/iron/smooth, /area/station/maintenance/starboard/lesser) +"vhA" = ( +/obj/structure/table/glass, +/obj/machinery/feed_machine, +/obj/effect/turf_decal/trimline/green/filled/line{ + dir = 10 + }, +/obj/structure/disposalpipe/segment, +/obj/item/chicken_feed, +/obj/item/chicken_feed, +/turf/open/floor/iron/dark, +/area/station/service/hydroponics) "vhB" = ( /obj/structure/chair/office{ dir = 4 @@ -75780,13 +75803,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/engineering/atmos/pumproom) -"wUJ" = ( -/obj/effect/turf_decal/trimline/green/filled/line{ - dir = 5 - }, -/obj/structure/bookcase/manuals/botany, -/turf/open/floor/iron/dark, -/area/station/service/hydroponics) "wUL" = ( /obj/machinery/status_display/evac/directional/north, /obj/machinery/fax{ @@ -77549,19 +77565,6 @@ "xBk" = ( /turf/closed/wall, /area/station/medical/storage) -"xBC" = ( -/obj/structure/chair/office{ - dir = 1 - }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/cable, -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/effect/landmark/start/scientist, -/turf/open/floor/iron/white, -/area/station/science/ordnance/office) "xBD" = ( /obj/effect/turf_decal/trimline/yellow/filled/line{ dir = 10 @@ -78555,6 +78558,13 @@ }, /turf/open/floor/iron/dark, /area/station/medical/storage) +"xVi" = ( +/obj/structure/chair/office/light{ + dir = 8 + }, +/obj/effect/landmark/start/scientist, +/turf/open/floor/iron/dark, +/area/station/science/ordnance/testlab) "xVp" = ( /obj/structure/cable, /turf/open/floor/wood, @@ -79013,13 +79023,6 @@ }, /turf/open/floor/iron/smooth, /area/station/maintenance/starboard/lesser) -"ybW" = ( -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 1 - }, -/obj/effect/landmark/start/depsec/science, -/turf/open/floor/iron, -/area/station/security/checkpoint/science) "ybX" = ( /obj/effect/spawner/random/engineering/tracking_beacon, /obj/effect/decal/cleanable/cobweb, @@ -110952,7 +110955,7 @@ eVz jbf pKI pKI -kav +vhA jyC cDO vph @@ -111209,7 +111212,7 @@ eVz rCo xMi pzz -etW +qGx eVz wHX aqu @@ -111463,10 +111466,10 @@ nUP eVz eVz eVz -wUJ +qew jQS jQS -dGd +nbW eVz wHX mYg @@ -111985,7 +111988,7 @@ eVz wHX qoZ nUP -mJg +cSO wHX nWT adg @@ -112499,7 +112502,7 @@ nUP gcE mDy nUP -oIk +kUA nbL uLD sqF @@ -126943,7 +126946,7 @@ tiF its tiF gbu -iyh +jni pMJ iix bYZ @@ -126959,7 +126962,7 @@ nZL rin pnn ebs -hFH +kPK tYB qVr bfH @@ -128237,7 +128240,7 @@ dpd ahG gzw stC -xBC +mHU ryT rpQ vOx @@ -131586,7 +131589,7 @@ lkK aeg gPB qOo -ksh +dge jGx aej oAn @@ -131837,7 +131840,7 @@ pyG qCz wMz okA -mPV +xVi xjx gKc frV @@ -132870,7 +132873,7 @@ dWM frV frV rsQ -ajG +sLc xLN tho sQZ @@ -163890,7 +163893,7 @@ uPZ eSj dst xYC -mlS +ppd avf avg hgn @@ -181950,8 +181953,8 @@ whz rXK neX ugt -bGV -min +dzj +cZN tkh kgN ugt @@ -187080,7 +187083,7 @@ wSi moz gyP cdB -mWe +tnU mAf dzu nto @@ -187590,7 +187593,7 @@ lVi kCF soq loJ -oga +mGk aRK qoo tUT @@ -187600,7 +187603,7 @@ dzu doK uJH uJH -jFW +rsK ukS soq rsL @@ -189392,7 +189395,7 @@ bvO vnu nUy mUX -buM +pJH goK gal pdZ @@ -190947,7 +190950,7 @@ iij yaB tes byp -qUC +brZ tes cjz qKE @@ -191712,7 +191715,7 @@ cli oPf jRy odC -bax +dSi tqA rBb rrL @@ -193516,8 +193519,8 @@ rQt kvt syv qHW -ybW -eah +eOE +rVl syv aaa aaa @@ -194287,7 +194290,7 @@ aso syv syv ubR -sVG +bbI moH syv aaa @@ -194544,7 +194547,7 @@ xNT syv aKO efB -nHu +kIW uoJ syv aaa diff --git a/code/__DEFINES/DNA.dm b/code/__DEFINES/DNA.dm index ed8b47ddadd7..f343ab8f7a6c 100644 --- a/code/__DEFINES/DNA.dm +++ b/code/__DEFINES/DNA.dm @@ -40,7 +40,7 @@ #define DNA_UNI_IDENTITY_BLOCKS 7 /// This number needs to equal the total number of DNA blocks -#define DNA_FEATURE_BLOCKS 16 +#define DNA_FEATURE_BLOCKS 20 #define DNA_MUTANT_COLOR_BLOCK 1 #define DNA_ETHEREAL_COLOR_BLOCK 2 @@ -58,6 +58,10 @@ #define DNA_MUSHROOM_CAPS_BLOCK 14 #define DNA_POD_HAIR_BLOCK 15 #define DNA_MUTANT_COLOR_SECONDARY 16 +#define DNA_ARM_WINGS_BLOCK 17 // NON-MODULE CHANGE +#define DNA_AVIAN_EARS_BLOCK 18 // NON-MODULE CHANGE +#define DNA_AVIAN_TAIL_BLOCK 19 // NON-MODULE CHANGE +#define DNA_FEATHER_COLOR_BLOCK 20 // NON-MODULE CHANGE #define DNA_SEQUENCE_LENGTH 4 #define DNA_MUTATION_BLOCKS 8 @@ -66,37 +70,19 @@ #define CLONER_FRESH_CLONE "fresh" #define CLONER_MATURE_CLONE "mature" - - -//species traits for mutantraces -#define MUTCOLORS 1 -#define NOTRANSSTING 2 -#define NOZOMBIE 3 -#define NO_UNDERWEAR 4 -#define NO_DNA_COPY 5 -#define DRINKSBLOOD 6 -#define ANIME 7 -#define MUTCOLORS_SECONDARY 8 -#define SPECIES_FUR 9 -#define SKINTONES 10 - /// Use this if you want to change the race's color without the player being able to pick their own color. AKA special color shifting #define DYNCOLORS 7 #define AGENDER 8 -/// Do not draw eyes or eyeless overlay -#define NOEYESPRITES 9 ///If we have a limb-specific overlay sprite -#define HAS_MARKINGS 10 +#define HAS_MARKINGS 9 /// Do not draw blood overlay -#define NOBLOODOVERLAY 11 +#define NOBLOODOVERLAY 10 ///No augments, for monkeys in specific because they will turn into fucking freakazoids https://cdn.discordapp.com/attachments/326831214667235328/791313258912153640/102707682-fa7cad80-4294-11eb-8f13-8c689468aeb0.png -#define NOAUGMENTS 12 +#define NOAUGMENTS 11 ///will be assigned a universal vampire themed last name shared by their department. this is preferenced! -#define BLOOD_CLANS 13 +#define BLOOD_CLANS 12 -#define REVIVESBYHEALING 14 -#define NOHUSK 15 -#define NOMOUTH 16 +#define REVIVESBYHEALING 13 //organ slots #define ORGAN_SLOT_ADAMANTINE_RESONATOR "adamantine_resonator" @@ -145,6 +131,7 @@ #define ORGAN_SLOT_EXTERNAL_ANIME_BOTTOM "anime_bottom" #define ORGAN_SLOT_EXTERNAL_FLORAN_LEAVES "floran_leaves" #define ORGAN_SLOT_EXTERNAL_FLUFF "fluff" +#define ORGAN_SLOT_EXTERNAL_FEATHERS "feathers" /// Xenomorph organ slots #define ORGAN_SLOT_XENO_ACIDGLAND "acid_gland" diff --git a/code/__DEFINES/atmospherics/atmos_core.dm b/code/__DEFINES/atmospherics/atmos_core.dm index 383e34f5c831..2544e9c95950 100644 --- a/code/__DEFINES/atmospherics/atmos_core.dm +++ b/code/__DEFINES/atmospherics/atmos_core.dm @@ -29,13 +29,13 @@ /// kPa #define ONE_ATMOSPHERE 101.325 /// -270.3degC -#define TCMB 2.7 +#define TCMB CELCIUS_TO_KELVIN(-270.3 CELCIUS) /// 0degC -#define T0C 273.15 +#define T0C CELCIUS_TO_KELVIN(0 CELCIUS) /// 20degC -#define T20C 293.15 +#define T20C CELCIUS_TO_KELVIN(20 CELCIUS) /// -14C - Temperature used for kitchen cold room, medical freezer, etc. -#define COLD_ROOM_TEMP 259.15 +#define COLD_ROOM_TEMP CELCIUS_TO_KELVIN(-14 CELCIUS) /** *I feel the need to document what happens here. Basically this is used @@ -128,11 +128,11 @@ //FIRE ///Minimum temperature for fire to move to the next turf (150 °C or 433 K) -#define FIRE_MINIMUM_TEMPERATURE_TO_SPREAD (150+T0C) +#define FIRE_MINIMUM_TEMPERATURE_TO_SPREAD CELCIUS_TO_KELVIN(150 CELCIUS) ///Minimum temperature for fire to exist on a turf (100 °C or 373 K) -#define FIRE_MINIMUM_TEMPERATURE_TO_EXIST (100+T0C) +#define FIRE_MINIMUM_TEMPERATURE_TO_EXIST CELCIUS_TO_KELVIN(100 CELCIUS) ///Minimum temperature for items on fire -#define BURNING_ITEM_MINIMUM_TEMPERATURE (150+T0C) +#define BURNING_ITEM_MINIMUM_TEMPERATURE CELCIUS_TO_KELVIN(150 CELCIUS) ///Multiplier for the temperature shared to other turfs #define FIRE_SPREAD_RADIOSITY_SCALE 0.85 ///Helper for small fires to grow diff --git a/code/__DEFINES/atmospherics/atmos_mob_interaction.dm b/code/__DEFINES/atmospherics/atmos_mob_interaction.dm index 26f13bc0522c..636eb201d6bf 100644 --- a/code/__DEFINES/atmospherics/atmos_mob_interaction.dm +++ b/code/__DEFINES/atmospherics/atmos_mob_interaction.dm @@ -41,51 +41,95 @@ /// This is used in handle_temperature_damage() for humans, and in reagents that affect body temperature. Temperature damage is multiplied by this amount. #define TEMPERATURE_DAMAGE_COEFFICIENT 1.5 +// Defines the cap on fast your body normalizes to the environment +/// Max negative change in temperature during natural body temperature stabilization +#define BODYTEMP_ENVIRONMENT_COOLING_MAX -30 KELVIN // needs to be relatively high, as otherwise you will make space not deadly +/// Max positive change in temperature during natural body temperature stabilization +#define BODYTEMP_ENVIRONMENT_HEATING_MAX 20 KELVIN // should not be too high, as otherwise atmos meme fires will be extremely deadly + +/// Default maximum body temperature mobs can exist in before taking damage +#define NPC_DEFAULT_MAX_TEMP CELCIUS_TO_KELVIN(76.85 CELCIUS)// 350 KELVIN +/// Default minimum body temperature mobs can exist in before taking damage +#define NPC_DEFAULT_MIN_TEMP CELCIUS_TO_KELVIN(-23.15 CELCIUS)// 250 KELVIN + +// Helpers for temperature conversion +#define FAHRENHEIT_TO_KELVIN(x) (((x) + 459.67) * 5 / 9) +#define KELVIN_TO_FAHRENHEIT(x) (((x) * 9 / 5) - 459.67) +#define CELCIUS_TO_KELVIN(x) ((x) + 273.15) +#define KELVIN_TO_CELCIUS(x) ((x) - 273.15) +#define CELCIUS_TO_FAHRENHEIT(x) (((x) * 9 / 5) + 32) +#define FAHRENHEIT_TO_CELSIUS(x) (((x) - 32) * 5 / 9) + +// These defines do nothing but can be used to make the code more readable by indicating temperature units +#define CELCIUS * 1 +#define FAHRENHEIT * 1 +#define KELVIN * 1 + +/// Max change in temperature during natural body temperature stabilization +#define BODYTEMP_HOMEOSTASIS_COOLING_MAX (BODYTEMP_ENVIRONMENT_COOLING_MAX / 10) +/// Max change in temperature during natural body temperature stabilization +#define BODYTEMP_HOMEOSTASIS_HEATING_MAX (BODYTEMP_ENVIRONMENT_HEATING_MAX / 8) + +// These defines are DEFAULTS for most mobs +// Mobs can override these to have whatever they want +// That means in a lot of situations (namely mob code) you should not directly use these, +// and instead use the relevant mob vars UNLESS you intentionally are using defaults over reality + /// The natural temperature for a body -#define BODYTEMP_NORMAL 310.15 -/// This is the divisor which handles how much of the temperature difference between the current body temperature and 310.15K (optimal temperature) humans auto-regenerate each tick. The higher the number, the slower the recovery. This is applied each tick, so long as the mob is alive. -#define BODYTEMP_AUTORECOVERY_DIVISOR 28 -/// Minimum amount of kelvin moved toward 310K per tick. So long as abs(310.15 - bodytemp) is more than 50. -#define BODYTEMP_AUTORECOVERY_MINIMUM 3 -///Similar to the BODYTEMP_AUTORECOVERY_DIVISOR, but this is the divisor which is applied at the stage that follows autorecovery. This is the divisor which comes into play when the human's loc temperature is lower than their body temperature. Make it lower to lose bodytemp faster. -#define BODYTEMP_COLD_DIVISOR 15 -/// Similar to the BODYTEMP_AUTORECOVERY_DIVISOR, but this is the divisor which is applied at the stage that follows autorecovery. This is the divisor which comes into play when the human's loc temperature is higher than their body temperature. Make it lower to gain bodytemp faster. -#define BODYTEMP_HEAT_DIVISOR 15 -/// The maximum number of degrees that your body can cool in 1 tick, due to the environment, when in a cold area. -#define BODYTEMP_COOLING_MAX -30 -/// The maximum number of degrees that your body can heat up in 1 tick, due to the environment, when in a hot area. -#define BODYTEMP_HEATING_MAX 30 +#define BODYTEMP_NORMAL CELCIUS_TO_KELVIN(37 CELCIUS) +/// Beyond this point a mob is considered hyperthermic +#define HYPERTHERMIA (BODYTEMP_NORMAL + 10 CELCIUS) +/// Beyond this point a mob is considered hypothermic +#define HYPOTHERMIA (BODYTEMP_NORMAL - 10 CELCIUS) + /// The body temperature limit the human body can take before it starts taking damage from heat. /// This also affects how fast the body normalises it's temperature when hot. -/// 340k is about 66c, and rather high for a human. -#define BODYTEMP_HEAT_DAMAGE_LIMIT (BODYTEMP_NORMAL + 30) +#define BODYTEMP_HEAT_DAMAGE_LIMIT CELCIUS_TO_KELVIN(45 CELCIUS) /// The body temperature limit the human body can take before it starts taking damage from cold. /// This also affects how fast the body normalises it's temperature when cold. -/// 270k is about -3c, that is below freezing and would hurt over time. -#define BODYTEMP_COLD_DAMAGE_LIMIT (BODYTEMP_NORMAL - 40) -/// The body temperature limit the human body can take before it will take wound damage. -#define BODYTEMP_HEAT_WOUND_LIMIT (BODYTEMP_NORMAL + 90) // 400.5 k -/// The modifier on cold damage limit hulks get ontop of their regular limit -#define BODYTEMP_HULK_COLD_DAMAGE_LIMIT_MODIFIER 25 -/// The modifier on cold damage hulks get. -#define HULK_COLD_DAMAGE_MOD 2 +#define BODYTEMP_COLD_DAMAGE_LIMIT CELCIUS_TO_KELVIN(-0.5 CELCIUS) + +/// The maximum temperature of Lavaland +#define LAVALAND_MAX_TEMPERATURE CELCIUS_TO_KELVIN(76.85 CELCIUS)// 350 KELVIN +#define ICEBOX_MIN_TEMPERATURE CELCIUS_TO_KELVIN(-93.15 CELCIUS) + +/// A temperature limit which is above the maximum lavaland temperature +#define BODYTEMP_HEAT_LAVALAND_SAFE (LAVALAND_MAX_TEMPERATURE + 5 KELVIN) +/// A temperature limit which is above the minimum icebox temperature +#define BODYTEMP_COLD_ICEBOX_SAFE (ICEBOX_MIN_TEMPERATURE - 5 KELVIN) -// Body temperature warning icons /// The temperature the red icon is displayed. -#define BODYTEMP_HEAT_WARNING_3 (BODYTEMP_HEAT_DAMAGE_LIMIT + 360) //+700k +#define BODYTEMP_HEAT_WARNING_3 (BODYTEMP_NORMAL + 23 CELCIUS) // CELCIUS_TO_KELVIN(60 CELCIUS) /// The temperature the orange icon is displayed. -#define BODYTEMP_HEAT_WARNING_2 (BODYTEMP_HEAT_DAMAGE_LIMIT + 120) //460K +#define BODYTEMP_HEAT_WARNING_2 (BODYTEMP_NORMAL + 13 CELCIUS) // CELCIUS_TO_KELVIN(50 CELCIUS) /// The temperature the yellow icon is displayed. -#define BODYTEMP_HEAT_WARNING_1 (BODYTEMP_HEAT_DAMAGE_LIMIT) //340K +#define BODYTEMP_HEAT_WARNING_1 (BODYTEMP_NORMAL + 3 CELCIUS) // CELCIUS_TO_KELVIN(40 CELCIUS) /// The temperature the light green icon is displayed. -#define BODYTEMP_COLD_WARNING_1 (BODYTEMP_COLD_DAMAGE_LIMIT) //270k +#define BODYTEMP_COLD_WARNING_1 (BODYTEMP_NORMAL - 7 CELCIUS) // CELCIUS_TO_KELVIN(30 CELCIUS) /// The temperature the cyan icon is displayed. -#define BODYTEMP_COLD_WARNING_2 (BODYTEMP_COLD_DAMAGE_LIMIT - 70) //200k +#define BODYTEMP_COLD_WARNING_2 (BODYTEMP_NORMAL - 17 CELCIUS) // CELCIUS_TO_KELVIN(20 CELCIUS) /// The temperature the blue icon is displayed. -#define BODYTEMP_COLD_WARNING_3 (BODYTEMP_COLD_DAMAGE_LIMIT - 150) //120k +#define BODYTEMP_COLD_WARNING_3 (BODYTEMP_NORMAL - 27 CELCIUS) // CELCIUS_TO_KELVIN(10 CELCIUS) -/// Beyond this temperature, being on fire will increase body temperature by less and less -#define BODYTEMP_FIRE_TEMP_SOFTCAP 1200 +// Ok defaults over + +/// Beyond this body temperature, being on fire will increase body temperature by less and less +#define BODYTEMP_FIRE_TEMP_SOFTCAP 600 KELVIN + +/// Amount of heating applied per fire stack per tick while on fire +#define HEAT_PER_FIRE_STACK 0.075 KELVIN +/// Amount of direct damage applied per fire stack per tick while on fire +#define BURN_DAMAGE_PER_FIRE_STACK 0.1 + +/// A warm drink will increase body temperature by this much +#define WARM_DRINK 0.25 KELVIN +/// A cold drink will decrease body temperature by this much +#define COLD_DRINK -0.25 KELVIN + +/// The modifier on cold damage limit hulks get ontop of their regular limit +#define BODYTEMP_HULK_COLD_DAMAGE_LIMIT_MODIFIER 25 KELVIN +/// The modifier on cold damage hulks get. +#define HULK_COLD_DAMAGE_MOD 2 /// The amount of pressure damage someone takes is equal to (pressure / HAZARD_HIGH_PRESSURE)*PRESSURE_DAMAGE_COEFFICIENT, with the maximum of MAX_PRESSURE_DAMAGE #define PRESSURE_DAMAGE_COEFFICIENT 2 @@ -100,41 +144,41 @@ //CLOTHES /// what min_cold_protection_temperature is set to for space-helmet quality headwear. MUST NOT BE 0. -#define SPACE_HELM_MIN_TEMP_PROTECT 2.0 +#define SPACE_HELM_MIN_TEMP_PROTECT 2.0 KELVIN /// Thermal insulation works both ways /Malkevin -#define SPACE_HELM_MAX_TEMP_PROTECT 1500 +#define SPACE_HELM_MAX_TEMP_PROTECT 1500 KELVIN /// what min_cold_protection_temperature is set to for space-suit quality jumpsuits or suits. MUST NOT BE 0. -#define SPACE_SUIT_MIN_TEMP_PROTECT 2.0 +#define SPACE_SUIT_MIN_TEMP_PROTECT 2.0 KELVIN /// The min cold protection of a space suit without the heater active -#define SPACE_SUIT_MIN_TEMP_PROTECT_OFF 72 -#define SPACE_SUIT_MAX_TEMP_PROTECT 1500 +#define SPACE_SUIT_MIN_TEMP_PROTECT_OFF 72 KELVIN +#define SPACE_SUIT_MAX_TEMP_PROTECT 1500 KELVIN /// Cold protection for firesuits -#define FIRE_SUIT_MIN_TEMP_PROTECT 60 +#define FIRE_SUIT_MIN_TEMP_PROTECT 60 KELVIN /// what max_heat_protection_temperature is set to for firesuit quality suits. MUST NOT BE 0. -#define FIRE_SUIT_MAX_TEMP_PROTECT 30000 +#define FIRE_SUIT_MAX_TEMP_PROTECT 30000 KELVIN /// Cold protection for fire helmets -#define FIRE_HELM_MIN_TEMP_PROTECT 60 +#define FIRE_HELM_MIN_TEMP_PROTECT 60 KELVIN /// for fire helmet quality items (red and white hardhats) -#define FIRE_HELM_MAX_TEMP_PROTECT 30000 +#define FIRE_HELM_MAX_TEMP_PROTECT 30000 KELVIN /// what max_heat_protection_temperature is set to for firesuit quality suits and helmets. MUST NOT BE 0. -#define FIRE_IMMUNITY_MAX_TEMP_PROTECT 35000 +#define FIRE_IMMUNITY_MAX_TEMP_PROTECT 35000 KELVIN /// For normal helmets -#define HELMET_MIN_TEMP_PROTECT 160 +#define HELMET_MIN_TEMP_PROTECT 160 KELVIN /// For normal helmets -#define HELMET_MAX_TEMP_PROTECT 600 +#define HELMET_MAX_TEMP_PROTECT 600 KELVIN /// For armor -#define ARMOR_MIN_TEMP_PROTECT 160 +#define ARMOR_MIN_TEMP_PROTECT 160 KELVIN /// For armor -#define ARMOR_MAX_TEMP_PROTECT 600 +#define ARMOR_MAX_TEMP_PROTECT 600 KELVIN /// For some gloves (black and) -#define GLOVES_MIN_TEMP_PROTECT 2.0 +#define GLOVES_MIN_TEMP_PROTECT 2.0 KELVIN /// For some gloves -#define GLOVES_MAX_TEMP_PROTECT 1500 +#define GLOVES_MAX_TEMP_PROTECT 1500 KELVIN /// For gloves -#define SHOES_MIN_TEMP_PROTECT 2.0 +#define SHOES_MIN_TEMP_PROTECT 2.0 KELVIN /// For gloves -#define SHOES_MAX_TEMP_PROTECT 1500 +#define SHOES_MAX_TEMP_PROTECT 1500 KELVIN diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 25e86ab8f191..d6de977fecb6 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -273,6 +273,8 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( #define BODY_ZONE_L_LEG "l_leg" #define BODY_ZONE_R_LEG "r_leg" +#define TOTAL_BODYPART_COUNT 6 + GLOBAL_LIST_INIT(arm_zones, list(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) #define BODY_ZONE_PRECISE_EYES "eyes" diff --git a/code/__DEFINES/dcs/helpers.dm b/code/__DEFINES/dcs/helpers.dm index 75d37aebf72f..3a245951da58 100644 --- a/code/__DEFINES/dcs/helpers.dm +++ b/code/__DEFINES/dcs/helpers.dm @@ -15,7 +15,7 @@ #define AddElement(arguments...) _AddElement(list(##arguments)) /// A wrapper for _RemoveElement that allows us to pretend we're using normal named arguments #define RemoveElement(arguments...) _RemoveElement(list(##arguments)) - +#define HasElement(source, type) _HasElement(source, type) /// A wrapper for _AddComponent that allows us to pretend we're using normal named arguments #define AddComponent(arguments...) _AddComponent(list(##arguments)) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm index d2b720057c4f..132cca0816ea 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -102,10 +102,14 @@ #define COMSIG_CARBON_SANITY_UPDATE "carbon_sanity_update" ///Called when a carbon attempts to breath, before the breath has actually occured #define COMSIG_CARBON_ATTEMPT_BREATHE "carbon_attempt_breathe" - // Prevents the breath - #define COMSIG_CARBON_BLOCK_BREATH (1 << 0) -///Called when a carbon breathes, before the breath has actually occured -#define COMSIG_CARBON_PRE_BREATHE "carbon_pre_breathe" + /// Prevents the breath entirely, which means they will neither suffocate nor regain oxyloss nor decay losebreath stacks + #define BREATHE_BLOCK_BREATH (1<<0) + /// Allow the breath but prevent inake, think losebreath + #define BREATHE_SKIP_BREATH (1<<1) +/// Called when a carbon breathes out (breath (the exhale)) +#define COMSIG_CARBON_BREATH_EXHALE "carbon_breath_exhale" + /// Return if the exhale was handled, or I guess to send the exhale into the void + #define BREATHE_EXHALE_HANDLED (1<<0) ///Called when a carbon updates their mood #define COMSIG_CARBON_MOOD_UPDATE "carbon_mood_update" ///Called when a carbon attempts to eat (eating) @@ -121,10 +125,12 @@ #define COMSIG_HUMAN_DISARM_HIT "human_disarm_hit" ///Whenever EquipRanked is called, called after job is set #define COMSIG_JOB_RECEIVED "job_received" -///from /mob/living/carbon/human/proc/set_coretemperature(): (oldvalue, newvalue) -#define COMSIG_HUMAN_CORETEMP_CHANGE "human_coretemp_change" ///from /datum/species/handle_fire. Called when the human is set on fire and burning clothes and stuff #define COMSIG_HUMAN_BURNING "human_burning" + /// Return to do no burn damage + #define BURNING_HANDLED (1<<0) + /// Return to skip protection check (ie, cause damage even if wearing fireproof clothing) + #define BURNING_SKIP_PROTECTION (1<<1) ///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity, modifiers) #define COMSIG_HUMAN_EARLY_UNARMED_ATTACK "human_early_unarmed_attack" ///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity, modifiers) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index 00dbeb79632f..4fdb0479fe34 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -221,3 +221,11 @@ #define COMSIG_MOB_LOST_CHAIN_TAIL "living_detached_chain_tail" /// Sent from a 'contract chain' button on a mob chain #define COMSIG_MOB_CHAIN_CONTRACT "living_chain_contracted" + +#define COMSIG_LIVING_BODY_TEMPERATURE_CHANGE "living_body_temperature_change" + +#define COMSIG_LIVING_HOMEOSTASIS "living_homeostasis" + /// Return to do no homeostasis at all + #define HOMEOSTASIS_HANDLED (1<<0) + /// Return to not reduce hunger at all + #define HOMEOSTASIS_NO_HUNGER (1<<1) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm index 51b79ec9eb10..d5753bf6e8b5 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm @@ -11,6 +11,10 @@ #define COMSIG_MOB_MIND_INITIALIZED "mob_mind_inited" ///from base of mob/set_stat(): (new_stat, old_stat) #define COMSIG_MOB_STATCHANGE "mob_statchange" +///from base of mob/reagent_check(): (datum/reagent/chem, seconds_per_tick, times_fired) +#define COMSIG_MOB_REAGENT_CHECK "mob_reagent_check" + ///stops the reagent check call + #define COMSIG_MOB_STOP_REAGENT_CHECK (1<<0) ///from base of mob/clickon(): (atom/A, params) #define COMSIG_MOB_CLICKON "mob_clickon" ///from base of mob/MiddleClickOn(): (atom/A) diff --git a/code/__DEFINES/dcs/signals/signals_specie.dm b/code/__DEFINES/dcs/signals/signals_specie.dm index 89239cf39dbc..1ff22aed90c6 100644 --- a/code/__DEFINES/dcs/signals/signals_specie.dm +++ b/code/__DEFINES/dcs/signals/signals_specie.dm @@ -5,3 +5,6 @@ #define COMSIG_SPECIES_LOSS "species_loss" ///from datum/species/on_species_gain(): (datum/species/new_species, datum/species/old_species) called before anything is done to ensure passing of data #define COMSIG_SPECIES_GAIN_PRE "species_gain_pre" +///from datum/species/handle_chemical(): (datum/reagent/chem, mob/living/carbon/human/affected, seconds_per_tick, times_fired) +#define COMSIG_SPECIES_HANDLE_CHEMICAL "species_handle_chemicals" + // same return values as COMSIG_MOB_STOP_REAGENT_CHECK diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 7d3d5d8e7bbb..a0d08b7644e5 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -28,7 +28,7 @@ #define BLOOD_DEFICIENCY_MODIFIER 0.025 /// Temperature at which blood loss and regen stops. [/mob/living/carbon/human/proc/handle_blood] -#define BLOOD_STOP_TEMP 225 +#define BLOOD_STOP_TEMP CELCIUS_TO_KELVIN(-48.15 CELCIUS) //Sizes of mobs, used by mob/living/var/mob_size #define MOB_SIZE_TINY 0 @@ -166,22 +166,13 @@ #define HUMAN_MAX_OXYLOSS 3 #define HUMAN_CRIT_MAX_OXYLOSS (SSMOBS_DT/3) -#define HEAT_DAMAGE_LEVEL_1 1 //Amount of damage applied when your body temperature just passes the 360.15k safety point -#define HEAT_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when your body temperature passes the 400K point -#define HEAT_DAMAGE_LEVEL_3 4 //Amount of damage applied when your body temperature passes the 460K point and you are on fire +/// Damage recieved when past heat damage threshold. +/// Gets multiplied by 2x, 4x, 8x depending on how far past the threshold you are. +#define HEAT_DAMAGE 1 -#define COLD_DAMAGE_LEVEL_1 0.25 //Amount of damage applied when your body temperature just passes the 260.15k safety point -#define COLD_DAMAGE_LEVEL_2 0.75 //Amount of damage applied when your body temperature passes the 200K point -#define COLD_DAMAGE_LEVEL_3 1.5 //Amount of damage applied when your body temperature passes the 120K point - -//Note that gas heat damage is only applied once every FOUR ticks. -#define HEAT_GAS_DAMAGE_LEVEL_1 2 //Amount of damage applied when the current breath's temperature just passes the 360.15k safety point -#define HEAT_GAS_DAMAGE_LEVEL_2 4 //Amount of damage applied when the current breath's temperature passes the 400K point -#define HEAT_GAS_DAMAGE_LEVEL_3 8 //Amount of damage applied when the current breath's temperature passes the 1000K point - -#define COLD_GAS_DAMAGE_LEVEL_1 0.5 //Amount of damage applied when the current breath's temperature just passes the 260.15k safety point -#define COLD_GAS_DAMAGE_LEVEL_2 1.5 //Amount of damage applied when the current breath's temperature passes the 200K point -#define COLD_GAS_DAMAGE_LEVEL_3 3 //Amount of damage applied when the current breath's temperature passes the 120K point +/// Damage recieved when past cold damage threshold. +/// Gets multiplied by 2x, 4x, 8x depending on how far past the threshold you are. +#define COLD_DAMAGE 0.25 //Brain Damage defines #define BRAIN_DAMAGE_MILD 20 @@ -459,8 +450,19 @@ #define POCKET_STRIP_DELAY (4 SECONDS) //time taken to search somebody's pockets #define DOOR_CRUSH_DAMAGE 15 //the amount of damage that airlocks deal when they crush you -#define HUNGER_FACTOR 0.05 //factor at which mob nutrition decreases -#define ETHEREAL_CHARGE_FACTOR 0.8 //factor at which ethereal's charge decreases per second +/// Factor at which mob nutrition decreases +#define HUNGER_FACTOR 0.1 + +// These add up to 1 to roughly (VERY roughly) represent the proportion of hunger used by each system +/// What % of hunger is used by homeostasis +#define HOMEOSTASIS_HUNGER_MULTIPLIER 0.1 +/// What % of hunger is used by passive hunger +#define PASSIVE_HUNGER_MULTIPLIER 0.4 +/// What % of hunger is used by movement +#define MOVEMENT_HUNGER_MULTIPLIER 0.1 + +/// Factor at which ethereal's charge decreases per second +#define ETHEREAL_CHARGE_FACTOR 0.2 /// How much nutrition eating clothes as moth gives and drains #define CLOTHING_NUTRITION_GAIN 15 #define REAGENTS_METABOLISM 0.2 //How many units of reagent are consumed per second, by default. @@ -929,11 +931,6 @@ GLOBAL_LIST_INIT(layers_to_offset, list( #define HEALING_TOUCH_NOT_SELF "healing_touch_not_self" #define HEALING_TOUCH_SELF_ONLY "healing_touch_self_only" -/// Default minimum body temperature mobs can exist in before taking damage -#define NPC_DEFAULT_MIN_TEMP 250 -/// Default maximum body temperature mobs can exist in before taking damage -#define NPC_DEFAULT_MAX_TEMP 350 - // Flags for mobs which can't do certain things while someone is looking at them /// Flag which stops you from moving while observed #define NO_OBSERVED_MOVEMENT (1<<0) diff --git a/code/__DEFINES/sprite_accessories.dm b/code/__DEFINES/sprite_accessories.dm index 9c9471130e6f..d4cfb7ca5d57 100644 --- a/code/__DEFINES/sprite_accessories.dm +++ b/code/__DEFINES/sprite_accessories.dm @@ -7,3 +7,9 @@ #define FACIAL_HAIR_COLOR "facial_hair_color" /// Color of the sprite accessory will match the owner's (left) eye color #define EYE_COLOR "eye_color" + +#define SKIN_COLOR "skin_color" + +#define MUTANT_COLOR_SECONDARY "mutant_color_secondary" + +#define ANIME_COLOR "anime_color" diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index ab2bd38217d6..ba2feadba2c0 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -187,6 +187,7 @@ #define INIT_ORDER_MINOR_MAPPING -40 #define INIT_ORDER_PATH -50 #define INIT_ORDER_EXPLOSIONS -69 +#define INIT_ORDER_CREDITS -93 #define INIT_ORDER_REPLAYS -94 #define INIT_ORDER_HOTSPOTS -95 ///only called on oshan so just call it near the end. #define INIT_ORDER_TWITCH -96 diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 281c2ba5f246..db1506f1be9b 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -147,39 +147,44 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Species with this trait are genderless #define TRAIT_AGENDER "agender" /// Species with this trait have a blood clan mechanic -/* #define TRAIT_BLOOD_CLANS "blood_clans" */ +#define TRAIT_BLOOD_CLANS "blood_clans" +/// Species with this trait have markings (this SUCKS, remove this later in favor of bodypart overlays) +#define TRAIT_HAS_MARKINGS "has_markings" /// Species with this trait use skin tones for coloration #define TRAIT_USES_SKINTONES "uses_skintones" /// Species with this trait use mutant colors for coloration #define TRAIT_MUTANT_COLORS "mutcolors" +/// Species with this trait use mutant colors for coloration +#define TRAIT_MUTANT_COLORS_SECONDARY "mutcolors_secondary" /// Species with this trait have mutant colors that cannot be chosen by the player, nor altered ingame by external means #define TRAIT_FIXED_MUTANT_COLORS "fixed_mutcolors" /// Humans with this trait won't get bloody hands, nor bloody feet -/* #define TRAIT_NO_BLOOD_OVERLAY "no_blood_overlay" */ +#define TRAIT_NO_BLOOD_OVERLAY "no_blood_overlay" /// Humans with this trait cannot have underwear #define TRAIT_NO_UNDERWEAR "no_underwear" /// This carbon doesn't show an overlay when they have no brain -/* #define TRAIT_NO_DEBRAIN_OVERLAY "no_debrain_overlay" */ +#define TRAIT_FUR_COLORS "trait_fur_colors" /// Humans with this trait cannot get augmentation surgery #define TRAIT_NO_AUGMENTS "no_augments" /// This carbon doesn't get hungry #define TRAIT_NOHUNGER "no_hunger" /// This carbon doesn't metabolize reagents. -#define TRAIT_NOMETABOLISM "no_metabolism" /// This carbon doesn't bleed #define TRAIT_NOBLOOD "noblood" /// This just means that the carbon will always have functional liverless metabolism #define TRAIT_LIVERLESS_METABOLISM "liverless_metabolism" +/// Humans with this trait cannot be affected by changeling transformation stings +#define TRAIT_NO_TRANSFORMATION_STING "no_transformation_sting" /// This carbon can't be overdosed by chems -/* #define TRAIT_OVERDOSEIMMUNE "overdose_immune" */ +#define TRAIT_OVERDOSEIMMUNE "overdose_immune" /// Humans with this trait cannot be turned into zombies #define TRAIT_NO_ZOMBIFY "no_zombify" /// Carbons with this trait can't have their DNA copied by diseases nor changelings #define TRAIT_NO_DNA_COPY "no_dna_copy" /// Carbons with this trait cant have their dna scrambled by genetics or a disease retrovirus. -/* #define TRAIT_NO_DNA_SCRAMBLE "no_dna_scramble" */ +#define TRAIT_NO_DNA_SCRAMBLE "no_dna_scramble" /// Carbons with this trait can eat blood to regenerate their own blood volume, instead of injecting it -/* #define TRAIT_DRINKS_BLOOD "drinks_blood" */ +#define TRAIT_DRINKS_BLOOD "drinks_blood" /// Mob is immune to clone (cellular) damage #define TRAIT_NOCLONELOSS "no_cloneloss" /// Mob is immune to toxin damage @@ -196,6 +201,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_EASILY_WOUNDED "easy_limb_wound" #define TRAIT_HARDLY_WOUNDED "hard_limb_wound" #define TRAIT_NEVER_WOUNDED "never_wounded" +#define TRAIT_NO_HUSK "no_husk" /// Species with this trait have 50% extra chance of bleeding from piercing and slashing wounds /* #define TRAIT_EASYBLEED "easybleed" */ #define TRAIT_TOXINLOVER "toxinlover" @@ -543,7 +549,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /* #define TRAIT_UNHITTABLE_BY_PROJECTILES "unhittable_by_projectiles" */ /// Projectile with this trait will always hit the defined zone of a struck living mob. -/* #define TRAIT_ALWAYS_HIT_ZONE "always_hit_zone" */ +#define TRAIT_ALWAYS_HIT_ZONE "always_hit_zone" /// Mobs with this trait do care about a few grisly things, such as digging up graves. They also really do not like bringing people back to life or tending wounds, but love autopsies and amputations. #define TRAIT_MORBID "morbid" diff --git a/code/__DEFINES/traits/monkestation/declarations.dm b/code/__DEFINES/traits/monkestation/declarations.dm index 29d153abd301..2e9ea4b80104 100644 --- a/code/__DEFINES/traits/monkestation/declarations.dm +++ b/code/__DEFINES/traits/monkestation/declarations.dm @@ -131,4 +131,15 @@ /// Has an item been enchanted by a clock cult Stargazer? #define TRAIT_STARGAZED "stargazed" +#define TRAIT_FEATHERED "feathers" +#define TRAIT_NON_IMPORTANT_SHOE_BLOCK "shoe_block" +/// Skip a breath once in every x breaths (where x is ticks between breaths) +#define TRAIT_LABOURED_BREATHING "laboured_breathing" +/// Blocks losebreath from accumulating from things such as heart attacks or choking +#define TRAIT_ASSISTED_BREATHING "assisted_breathing" +/// Stops organs from decaying while dead +#define TRAIT_NO_ORGAN_DECAY "no_organ_decay" +/// Mob does not homeostasize body temperature +#define TRAIT_COLD_BLOODED "cold_blooded" + // END TRAIT DEFINES diff --git a/code/__DEFINES/wounds.dm b/code/__DEFINES/wounds.dm index 815e60d0738e..6a108858bb1f 100644 --- a/code/__DEFINES/wounds.dm +++ b/code/__DEFINES/wounds.dm @@ -48,16 +48,13 @@ GLOBAL_LIST_INIT(wound_severities_chronological, list( // ~determination second wind defines -// How much determination reagent to add each time someone gains a new wound in [/datum/wound/proc/second_wind] -#define WOUND_DETERMINATION_MODERATE 1 -#define WOUND_DETERMINATION_SEVERE 2.5 -#define WOUND_DETERMINATION_CRITICAL 5 -#define WOUND_DETERMINATION_LOSS 7.5 +// How much determination to add each time someone gains a new wound in [/datum/wound/proc/second_wind] +#define WOUND_DETERMINATION_MODERATE (5 SECONDS) +#define WOUND_DETERMINATION_SEVERE (10 SECONDS) +#define WOUND_DETERMINATION_CRITICAL (20 SECONDS) +#define WOUND_DETERMINATION_LOSS (30 SECONDS) /// the max amount of determination you can have -#define WOUND_DETERMINATION_MAX 10 - -/// While someone has determination in their system, their bleed rate is slightly reduced -#define WOUND_DETERMINATION_BLEED_MOD 0.85 +#define WOUND_DETERMINATION_MAX (1 MINUTES) /// Wounds using this competition mode will remove any wounds of a greater severity than itself in a random wound roll. In most cases, you dont want to use this. #define WOUND_COMPETITION_OVERPOWER_GREATERS "wound_submit" diff --git a/code/__DEFINES/~monkestation/blood_datums.dm b/code/__DEFINES/~monkestation/blood_datums.dm new file mode 100644 index 000000000000..e1f906a8b103 --- /dev/null +++ b/code/__DEFINES/~monkestation/blood_datums.dm @@ -0,0 +1,21 @@ +#define COMSIG_HUMAN_ON_HANDLE_BLOOD "human_on_handle_blood" + #define HANDLE_BLOOD_HANDLED (1<<0) + #define HANDLE_BLOOD_NO_NUTRITION_DRAIN (1<<1) + #define HANDLE_BLOOD_NO_EFFECTS (1<<2) + +#define COLOR_BLOOD "#c90000" + +/// Modifier used in math involving bloodiness, so the above values can be adjusted easily +#define BLOOD_PER_UNIT_MODIFIER 0.5 + +/// from /datum/status_effect/limp/proc/check_step() +#define COMSIG_CARBON_LIMPING "mob_limp_check" + #define COMPONENT_CANCEL_LIMP (1<<0) + +/// Mob can walk despite having two disabled/missing legs so long as they have two of this trait. +/// Kind of jank, refactor at a later day when I can think of a better solution. +/// Just be sure to call update_limbless_locomotion() after applying / removal +#define TRAIT_NO_LEG_AID "no_leg_aid" + +/// Updating a mob's movespeed when lacking limbs. (list/modifiers) +#define COMSIG_LIVING_LIMBLESS_MOVESPEED_UPDATE "living_get_movespeed_modifiers" diff --git a/code/__DEFINES/~monkestation/chewin.dm b/code/__DEFINES/~monkestation/chewin.dm index 980bcb76b964..75b635b5b9b4 100644 --- a/code/__DEFINES/~monkestation/chewin.dm +++ b/code/__DEFINES/~monkestation/chewin.dm @@ -64,21 +64,18 @@ #define PLATE "plate" #define CUTTING_BOARD "cutting board" #define PAN "pan" -#define POT "pot" -#define BOWL "bowl" +#define POT "cooking pot" +#define BOWL "mixing bowl" #define DF_BASKET "deep fryer basket" #define AF_BASKET "air fryer basket" #define OVEN "oven" -#define GRILL "grill" +#define GRILL "grill grate" //Stove temp settings. #define J_LO "Low" #define J_MED "Medium" #define J_HI "High" -//Just a catalog for the cooking catalog -#define CATALOG_COOKING "cooking" - //Burn times for cooking things on a stove. //Anything put on a stove for this long becomes a burned mess. #define CHEWIN_BURN_TIME_LOW 15 MINUTES diff --git a/code/__DEFINES/~monkestation/dcs/signals/signals_mob/signals_mob_main.dm b/code/__DEFINES/~monkestation/dcs/signals/signals_mob/signals_mob_main.dm index bfc0f361e4f4..969145aeec56 100644 --- a/code/__DEFINES/~monkestation/dcs/signals/signals_mob/signals_mob_main.dm +++ b/code/__DEFINES/~monkestation/dcs/signals/signals_mob/signals_mob_main.dm @@ -33,3 +33,14 @@ #define COMSIG_LIVING_TRACKER_REMOVED "tracker_removed" #define COMSIG_CLEAR_SEE "clear_see" + +/// Carbon is steppin +#define COMSIG_CARBON_STEP "carbon_step" +/// Carbon is steppin on a painful limb +#define COMSIG_CARBON_PAINED_STEP "carbon_pain_step" + /// Stop the pain from happening + #define STOP_PAIN (1<<0) + +#define COMSIG_LIVING_GIVE_ITEM_CHECK "living_give_item_check" + +#define COMSIG_LIVING_ITEM_OFFERED_PRECHECK "living_item_offer_precheck" diff --git a/code/__DEFINES/~monkestation/living.dm b/code/__DEFINES/~monkestation/living.dm index 06134c4aaffa..b79309b42d8d 100644 --- a/code/__DEFINES/~monkestation/living.dm +++ b/code/__DEFINES/~monkestation/living.dm @@ -6,3 +6,32 @@ #define COMSIG_LIVING_CAN_ALLOW_THROUGH "living_can_allow_through" /// Allow to movable atoms to pass through this living mob #define COMPONENT_LIVING_PASSABLE (1<<0) + +/// Checks if the value is "left" +/// Used primarily for hand or foot indexes +#define IS_RIGHT(value) (value % 2 == 0) +/// Checks if the value is "right" +/// Used primarily for hand or foot indexes +#define IS_LEFT(value) (value % 2 != 0) +/// Helper for picking between left or right when given a value +/// Used primarily for hand or foot indexes +#define SELECT_LEFT_OR_RIGHT(value, left, right) (IS_LEFT(value) ? left : right) + + +/// Calculates oxyloss cap +#define MAX_OXYLOSS(maxHealth) (maxHealth * 2) + +// Some source defines for pain and consciousness +// Consciousness ones are human readable because of laziness (they are shown in cause of death) +#define PAINSHOCK "neurological shock" +#define PAINCRIT "paincrit" +#define PAIN "pain" +#define HUNGER "starvation" +#define BRAIN_DAMAGE "brain damage" +#define BLOOD_LOSS "blood loss" +#define BLUNT_DAMAGE "blunt force trauma" +#define BURN_DAMAGE "severe burns" +#define OXY_DAMAGE "suffocation" +#define TOX_DAMAGE "toxic poisoning" + +#define SKIP_INTERNALS "skip_internals" diff --git a/code/__DEFINES/~monkestation/mobs.dm b/code/__DEFINES/~monkestation/mobs.dm index 9f531dc4da76..708feee16e0b 100644 --- a/code/__DEFINES/~monkestation/mobs.dm +++ b/code/__DEFINES/~monkestation/mobs.dm @@ -1,5 +1,7 @@ #define SPECIES_ARACHNIDS "arachnid" #define SPECIES_DRACONIC_SKELETON "draconic_skeleton" +#define SPECIES_WEREWOLF "werewolf" //Monkestation Addition +#define SPECIES_ORNITHID "ornithid" GLOBAL_REAL_VAR(list/voice_type2sound = list( "1" = list( diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index c6b4e280eed3..b9241abe78a7 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -52,6 +52,10 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/satyr_fluff, GLOB.satyr_fluff_list) //Monkestation Addition init_sprite_accessory_subtypes(/datum/sprite_accessory/satyr_tail, GLOB.satyr_tail_list) //Monkestation Addition init_sprite_accessory_subtypes(/datum/sprite_accessory/satyr_horns, GLOB.satyr_horns_list) //Monkestation Addition + init_sprite_accessory_subtypes(/datum/sprite_accessory/arm_wings, GLOB.arm_wings_list) //NON-MODULE CHANGE + init_sprite_accessory_subtypes(/datum/sprite_accessory/arm_wingsopen, GLOB.arm_wingsopen_list) //NON-MODULE CHANGE + init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/avian, GLOB.tails_list_avian) //NON-MODULE CHANGE + init_sprite_accessory_subtypes(/datum/sprite_accessory/plumage, GLOB.avian_ears_list) //NON-MODULE CHANGE /// Inits GLOB.species_list. Not using GLOBAL_LIST_INIT b/c it depends on GLOB.string_lists /proc/init_species_list() diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index a43a50cda5a2..19feb2cb2c0e 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -89,6 +89,10 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/moth_markings, GLOB.moth_markings_list) if(!length(GLOB.pod_hair_list)) init_sprite_accessory_subtypes(/datum/sprite_accessory/pod_hair, GLOB.pod_hair_list) + if(!length(GLOB.pod_hair_list)) + init_sprite_accessory_subtypes(/datum/sprite_accessory/pod_hair, GLOB.pod_hair_list) + if(!length(GLOB.pod_hair_list)) + init_sprite_accessory_subtypes(/datum/sprite_accessory/pod_hair, GLOB.pod_hair_list) //Monkestation Addition Start if(!length(GLOB.ethereal_horns_list)) init_sprite_accessory_subtypes(/datum/sprite_accessory/ethereal_horns, GLOB.ethereal_horns_list) @@ -126,13 +130,18 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/satyr_tail, GLOB.satyr_tail_list) if(!GLOB.satyr_horns_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/satyr_horns, GLOB.satyr_horns_list) + if(!length(GLOB.arm_wings_list)) + init_sprite_accessory_subtypes(/datum/sprite_accessory/arm_wings, GLOB.arm_wings_list) + if(!length(GLOB.arm_wingsopen_list)) + init_sprite_accessory_subtypes(/datum/sprite_accessory/arm_wingsopen, GLOB.arm_wingsopen_list) + if(!length(GLOB.tails_list_avian)) + init_sprite_accessory_subtypes(/datum/sprite_accessory/tails/avian, GLOB.tails_list_avian) + if(!length(GLOB.avian_ears_list)) + init_sprite_accessory_subtypes(/datum/sprite_accessory/plumage, GLOB.avian_ears_list) //Monkestation Addition End //For now we will always return none for tail_human and ears. | "For now" he says. return(list( - "mcolor" = "#[pick("7F","FF")][pick("7F","FF")][pick("7F","FF")]", - "mcolor_secondary" = "#[pick("7F","FF")][pick("7F","FF")][pick("7F","FF")]", - "ethcolor" = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)], "tail_cat" = "None", "tail_lizard" = "Smooth", "wings" = "None", @@ -167,6 +176,9 @@ "satyr_fluff" = pick(GLOB.satyr_fluff_list), //Monkestation Addition "satyr_tail" = pick(GLOB.satyr_tail_list), //Monkestation Addition "satyr_horns" = pick(GLOB.satyr_horns_list), //Monkestation Addition + "arm_wings" = pick(GLOB.arm_wings_list), + "ears_avian" = pick(GLOB.avian_ears_list), + "tail_avian" = pick(GLOB.tails_list_avian), )) /proc/random_hairstyle(gender) @@ -617,20 +629,6 @@ GLOBAL_LIST_EMPTY(species_list) . = pick(ais) return . -/** - * Used to get the amount of change between two body temperatures - * - * When passed the difference between two temperatures returns the amount of change to temperature to apply. - * The change rate should be kept at a low value tween 0.16 and 0.02 for optimal results. - * vars: - * * temp_diff (required) The differance between two temperatures - * * change_rate (optional)(Default: 0.06) The rate of range multiplyer - */ -/proc/get_temp_change_amount(temp_diff, change_rate = 0.06) - if(temp_diff < 0) - return -(BODYTEMP_AUTORECOVERY_DIVISOR / 2) * log(1 - (temp_diff * change_rate)) - return (BODYTEMP_AUTORECOVERY_DIVISOR / 2) * log(1 + (temp_diff * change_rate)) - #define ISADVANCEDTOOLUSER(mob) (HAS_TRAIT(mob, TRAIT_ADVANCEDTOOLUSER) && !HAS_TRAIT(mob, TRAIT_DISCOORDINATED_TOOL_USER)) /// Gets the client of the mob, allowing for mocking of the client. diff --git a/code/__HELPERS/roundend.dm b/code/__HELPERS/roundend.dm index 5c3c5334ab13..8c8200cae6e5 100644 --- a/code/__HELPERS/roundend.dm +++ b/code/__HELPERS/roundend.dm @@ -1,6 +1,7 @@ #define POPCOUNT_SURVIVORS "survivors" //Not dead at roundend #define POPCOUNT_ESCAPEES "escapees" //Not dead and on centcom/shuttles marked as escaped #define POPCOUNT_SHUTTLE_ESCAPEES "shuttle_escapees" //Emergency shuttle only. +#define POPCOUNT_ESCAPEES_HUMANONLY "human_escapees" #define PERSONAL_LAST_ROUND "personal last round" #define SERVER_LAST_ROUND "server last round" #define DISCORD_SUPPRESS_NOTIFICATIONS (1 << 12) // monke edit: discord flag for silent messages @@ -17,7 +18,10 @@ GLOBAL_LIST_INIT(round_end_images, world.file2list("data/image_urls.txt")) // MO var/list/file_data = list("escapees" = list("humans" = list(), "silicons" = list(), "others" = list(), "npcs" = list()), "abandoned" = list("humans" = list(), "silicons" = list(), "others" = list(), "npcs" = list()), "ghosts" = list(), "additional data" = list()) var/num_survivors = 0 //Count of non-brain non-camera mobs with mind that are alive var/num_escapees = 0 //Above and on centcom z + var/num_human_escapees = 0 //Above but humans only var/num_shuttle_escapees = 0 //Above and on escape shuttle + var/list/list_of_human_escapees = list() //References to all escaped humans + var/list/list_of_mobs_on_shuttle = list() var/list/area/shuttle_areas if(SSshuttle?.emergency) shuttle_areas = SSshuttle.emergency.shuttle_areas @@ -35,6 +39,8 @@ GLOBAL_LIST_INIT(round_end_images, world.file2list("data/image_urls.txt")) // MO if(M.mind) count_only = FALSE mob_data["ckey"] = M.mind.key + if(M.onCentCom()) + list_of_mobs_on_shuttle += M if(M.stat != DEAD && !isbrain(M) && !iscameramob(M)) num_survivors++ if(EMERGENCY_ESCAPED_OR_ENDGAMED && (M.onCentCom() || M.onSyndieBase())) @@ -42,6 +48,9 @@ GLOBAL_LIST_INIT(round_end_images, world.file2list("data/image_urls.txt")) // MO escape_status = "escapees" if(shuttle_areas[get_area(M)]) num_shuttle_escapees++ + if(ishuman(M)) + num_human_escapees++ + list_of_human_escapees += M if(isliving(M)) var/mob/living/L = M mob_data["location"] = get_area(L) @@ -105,7 +114,10 @@ GLOBAL_LIST_INIT(round_end_images, world.file2list("data/image_urls.txt")) // MO . = list() .[POPCOUNT_SURVIVORS] = num_survivors .[POPCOUNT_ESCAPEES] = num_escapees + .[POPCOUNT_ESCAPEES_HUMANONLY] = num_human_escapees .[POPCOUNT_SHUTTLE_ESCAPEES] = num_shuttle_escapees + .["all_mobs_on_shuttle"] = list_of_mobs_on_shuttle + .["human_escapees_list"] = list_of_human_escapees .["station_integrity"] = station_integrity /datum/controller/subsystem/ticker/proc/gather_antag_data() @@ -221,7 +233,7 @@ GLOBAL_LIST_INIT(round_end_images, world.file2list("data/image_urls.txt")) // MO C?.give_award(/datum/award/achievement/misc/speed_round, C?.mob) HandleRandomHardcoreScore(C) - var/popcount = gather_roundend_feedback() + popcount = gather_roundend_feedback() display_report(popcount) CHECK_TICK diff --git a/code/__HELPERS/~monkestation-helpers/blood_datums.dm b/code/__HELPERS/~monkestation-helpers/blood_datums.dm new file mode 100644 index 000000000000..7e74ac55592d --- /dev/null +++ b/code/__HELPERS/~monkestation-helpers/blood_datums.dm @@ -0,0 +1,13 @@ +/proc/random_human_blood_type() + var/static/list/human_blood_type_weights = list( + /datum/blood_type/crew/human/o_minus = 4, + /datum/blood_type/crew/human/o_plus = 36, + /datum/blood_type/crew/human/a_minus = 28, + /datum/blood_type/crew/human/a_plus = 3, + /datum/blood_type/crew/human/b_minus = 20, + /datum/blood_type/crew/human/b_plus = 1, + /datum/blood_type/crew/human/ab_minus = 5, + /datum/blood_type/crew/human/ab_plus = 1 + ) + + return pick_weight(human_blood_type_weights) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index fb117fadab69..4497da073e3e 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -270,6 +270,75 @@ DEFINE_BITFIELD(mob_respiration_type, list( "RESPIRATION_PLASMA" = RESPIRATION_PLASMA, )) +DEFINE_BITFIELD(liked_foodtypes, list( + "MEAT" = MEAT, + "VEGETABLES" = VEGETABLES, + "RAW" = RAW, + "JUNKFOOD" = JUNKFOOD, + "GRAIN" = GRAIN, + "FRUIT" = FRUIT, + "DAIRY" = DAIRY, + "FRIED" = FRIED, + "ALCOHOL" = ALCOHOL, + "SUGAR" = SUGAR, + "GROSS" = GROSS, + "TOXIC" = TOXIC, + "PINEAPPLE" = PINEAPPLE, + "BREAKFAST" = BREAKFAST, + "CLOTH" = CLOTH, + "NUTS" = NUTS, + "SEAFOOD" = SEAFOOD, + "ORANGES" = ORANGES, + "BUGS" = BUGS, + "GORE" = GORE, +)) + +DEFINE_BITFIELD(disliked_foodtypes, list( + "MEAT" = MEAT, + "VEGETABLES" = VEGETABLES, + "RAW" = RAW, + "JUNKFOOD" = JUNKFOOD, + "GRAIN" = GRAIN, + "FRUIT" = FRUIT, + "DAIRY" = DAIRY, + "FRIED" = FRIED, + "ALCOHOL" = ALCOHOL, + "SUGAR" = SUGAR, + "GROSS" = GROSS, + "TOXIC" = TOXIC, + "PINEAPPLE" = PINEAPPLE, + "BREAKFAST" = BREAKFAST, + "CLOTH" = CLOTH, + "NUTS" = NUTS, + "SEAFOOD" = SEAFOOD, + "ORANGES" = ORANGES, + "BUGS" = BUGS, + "GORE" = GORE, +)) + +DEFINE_BITFIELD(toxic_foodtypes, list( + "MEAT" = MEAT, + "VEGETABLES" = VEGETABLES, + "RAW" = RAW, + "JUNKFOOD" = JUNKFOOD, + "GRAIN" = GRAIN, + "FRUIT" = FRUIT, + "DAIRY" = DAIRY, + "FRIED" = FRIED, + "ALCOHOL" = ALCOHOL, + "SUGAR" = SUGAR, + "GROSS" = GROSS, + "TOXIC" = TOXIC, + "PINEAPPLE" = PINEAPPLE, + "BREAKFAST" = BREAKFAST, + "CLOTH" = CLOTH, + "NUTS" = NUTS, + "SEAFOOD" = SEAFOOD, + "ORANGES" = ORANGES, + "BUGS" = BUGS, + "GORE" = GORE, +)) + DEFINE_BITFIELD(mobility_flags, list( "MOVE" = MOBILITY_MOVE, "PICKUP" = MOBILITY_PICKUP, @@ -438,6 +507,7 @@ DEFINE_BITFIELD(organ_flags, list( "ORGAN_EDIBLE" = ORGAN_EDIBLE, "ORGAN_SYNTHETIC_EMP" = ORGAN_SYNTHETIC_EMP, "ORGAN_UNREMOVABLE" = ORGAN_UNREMOVABLE, + "ORGAN_HIDDEN" = ORGAN_HIDDEN, //Monkestation edit: BLOOD_DATUMS, how was this forgotten )) DEFINE_BITFIELD(respiration_type, list( diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 99db47cf8472..d342bf01d594 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -318,6 +318,11 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_MULTIZ_SUIT_SENSORS" = TRAIT_MULTIZ_SUIT_SENSORS, "TRAIT_MUSICIAN" = TRAIT_MUSICIAN, "TRAIT_MUTANT_COLORS" = TRAIT_MUTANT_COLORS, + "TRAIT_MUTANT_COLORS_SECONDARY" = TRAIT_MUTANT_COLORS_SECONDARY, + "TRAIT_FUR_COLORS" = TRAIT_FUR_COLORS, + "TRAIT_NO_TRANSFORMATION_STING" = TRAIT_NO_TRANSFORMATION_STING, + "TRAIT_NO_HUSK" = TRAIT_NO_HUSK, + "TRAIT_HAS_MARKINGS" = TRAIT_HAS_MARKINGS, "TRAIT_MUTE" = TRAIT_MUTE, "TRAIT_NAIVE" = TRAIT_NAIVE, "TRAIT_NANITE_MONITORING" = TRAIT_NANITE_MONITORING, @@ -341,7 +346,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NOHARDCRIT" = TRAIT_NOHARDCRIT, "TRAIT_NOHUNGER" = TRAIT_NOHUNGER, "TRAIT_NOLIMBDISABLE" = TRAIT_NOLIMBDISABLE, - "TRAIT_NOMETABOLISM" = TRAIT_NOMETABOLISM, "TRAIT_NOMOBSWAP" = TRAIT_NOMOBSWAP, "TRAIT_NOSELFIGNITION_HEAD_ONLY" = TRAIT_NOSELFIGNITION_HEAD_ONLY, "TRAIT_NOSOFTCRIT" = TRAIT_NOSOFTCRIT, @@ -508,6 +512,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_XENO_HOST" = TRAIT_XENO_HOST, "TRAIT_XENO_IMMUNE" = TRAIT_XENO_IMMUNE, "TRAIT_XRAY_VISION" = TRAIT_XRAY_VISION, + "TRAIT_COLD_BLOODED" = TRAIT_COLD_BLOODED, /* "TRAIT_ADAMANTINE_EXTRACT_ARMOR" = TRAIT_ADAMANTINE_EXTRACT_ARMOR, */ /* "TRAIT_ALWAYS_WANTED" = TRAIT_ALWAYS_WANTED, */ /* "TRAIT_ANOSMIA" = TRAIT_ANOSMIA, */ @@ -630,6 +635,11 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_T_RAY_VISIBLE" = TRAIT_T_RAY_VISIBLE, "TRAIT_UNCATCHABLE" = TRAIT_UNCATCHABLE, "TRAIT_WIELDED" = TRAIT_WIELDED, + "TRAIT_FEATHERED" = TRAIT_FEATHERED, + "TRAIT_NON_IMPORTANT_SHOE_BLOCK" = TRAIT_NON_IMPORTANT_SHOE_BLOCK, + "TRAIT_LABOURED_BREATHING" = TRAIT_LABOURED_BREATHING, + "TRAIT_ASSISTED_BREATHING" = TRAIT_ASSISTED_BREATHING, + "TRAIT_NO_ORGAN_DECAY" = TRAIT_NO_ORGAN_DECAY, /* "TRAIT_BAIT_UNCONSUMABLE" = TRAIT_BAIT_UNCONSUMABLE, */ /* "TRAIT_BAKEABLE" = TRAIT_BAKEABLE, */ /* "TRAIT_BYPASS_RANGED_ARMOR" = TRAIT_BYPASS_RANGED_ARMOR, */ @@ -708,7 +718,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( /* "TRAIT_MODPC_INTERACTING_WITH_FRAME" = TRAIT_MODPC_INTERACTING_WITH_FRAME, */ ), /obj/projectile = list( - /* "TRAIT_ALWAYS_HIT_ZONE" = TRAIT_ALWAYS_HIT_ZONE, */ + "TRAIT_ALWAYS_HIT_ZONE" = TRAIT_ALWAYS_HIT_ZONE, ), /obj/structure = list( "TRAIT_RADSTORM_IMMUNE" = TRAIT_RADSTORM_IMMUNE, diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index 302cd10c28f0..b4d62bf89221 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -57,8 +57,7 @@ thealert.icon_state = "template" // We'll set the icon to the client's ui pref in reorganize_alerts() thealert.master = new_master else - thealert.icon_state = "[initial(thealert.icon_state)][severity]" - thealert.severity = severity + thealert.set_severity(severity) alerts[category] = thealert if(client && hud_used) @@ -120,6 +119,15 @@ /atom/movable/screen/alert/MouseExited() closeToolTip(usr) +/atom/movable/screen/alert/proc/set_severity(new_val) + if(severity == new_val) + return + severity = new_val + update_appearance() + +/atom/movable/screen/alert/update_icon_state() + . = ..() + icon_state = "[base_icon_state || initial(icon_state)][severity]" //Gas alerts // Gas alerts are continuously thrown/cleared by: @@ -213,15 +221,52 @@ icon_state = "gross3" /atom/movable/screen/alert/hot - name = "Too Hot" - desc = "You're flaming hot! Get somewhere cooler and take off any insulating clothing like a fire suit." + name = "Hot" icon_state = "hot" +/atom/movable/screen/alert/hot/update_name(updates) + . = ..() + switch(severity) + if(1) + name = "Warm" + if(2) + name = "Hot" + if(3) + name = "Flaming Hot" + +/atom/movable/screen/alert/hot/update_desc(updates) + . = ..() + switch(severity) + if(1) + desc = "It's pretty warm around here. You might not want to stick around for long, but it won't hurt you unless it gets hotter." + if(2) + desc = "You're getting pretty hot. You might want to find somewhere cooler soon, or take off any insulating clothing like a fire suit." + if(3) + desc = "You're flaming hot! Get somewhere cooler and take off any insulating clothing like a fire suit." + /atom/movable/screen/alert/cold - name = "Too Cold" - desc = "You're freezing cold! Get somewhere warmer and take off any insulating clothing like a space suit." + name = "Cold" icon_state = "cold" +/atom/movable/screen/alert/cold/update_name(updates) + . = ..() + switch(severity) + if(1) + name = "Chilly" + if(2) + name = "Cold" + if(3) + name = "Freezing" + +/atom/movable/screen/alert/cold/update_desc(updates) + . = ..() + switch(severity) + if(1) + desc = "You feel pretty chilly. You might not want to stick around for long, but it won't hurt you unless it gets colder." + if(2) + desc = "You're getting pretty cold. You might want to find somewhere warmer soon, or put on some insulating clothing like a space suit or winter coat." + if(3) + desc = "You're freezing cold! Get somewhere warmer and put on some insulating clothing like a space suit or winter coat." /atom/movable/screen/alert/lowpressure name = "Low Pressure" desc = "The air around you is hazardously thin. A space suit would protect you." @@ -329,7 +374,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." * * offerer - The person giving the alert and item * * receiving - The item being given by the offerer */ -/atom/movable/screen/alert/give/proc/setup(mob/living/carbon/taker, datum/status_effect/offering/offer) +/atom/movable/screen/alert/give/proc/setup(mob/living/taker, datum/status_effect/offering/offer) src.offer = offer var/mob/living/offerer = offer.owner @@ -370,12 +415,15 @@ or shoot a gun to move around via Newton's 3rd Law of Motion." handle_transfer() /// An overrideable proc used simply to hand over the item when claimed, this is a proc so that high-fives can override them since nothing is actually transferred -/atom/movable/screen/alert/give/proc/handle_transfer() - var/mob/living/carbon/taker = owner +/atom/movable/screen/alert/give/proc/handle_transfer(visible_message = TRUE) + var/mob/living/taker = owner var/mob/living/offerer = offer.owner var/obj/item/receiving = offer.offered_item - taker.take(offerer, receiving) + if(!taker.take(offerer, receiving, visible_message)) + return FALSE + SEND_SIGNAL(offerer, COMSIG_CARBON_ITEM_GIVEN, taker, receiving) + return TRUE /atom/movable/screen/alert/give/highfive additional_desc_text = "Click this alert to slap it." diff --git a/code/_onclick/hud/credits.dm b/code/_onclick/hud/credits.dm deleted file mode 100644 index e39e1ef36d07..000000000000 --- a/code/_onclick/hud/credits.dm +++ /dev/null @@ -1,76 +0,0 @@ -#define CREDIT_ROLL_SPEED 125 -#define CREDIT_SPAWN_SPEED 10 -#define CREDIT_ANIMATE_HEIGHT (14 * world.icon_size) -#define CREDIT_EASE_DURATION 22 -#define CREDITS_PATH "[global.config.directory]/contributors.dmi" - -/client/proc/RollCredits() - set waitfor = FALSE - if(!fexists(CREDITS_PATH)) - return - var/icon/credits_icon = new(CREDITS_PATH) - LAZYINITLIST(credits) - var/list/_credits = credits - add_verb(src, /client/proc/ClearCredits) - var/static/list/credit_order_for_this_round - if(isnull(credit_order_for_this_round)) - credit_order_for_this_round = list("Thanks for playing!") + (shuffle(icon_states(credits_icon)) - "Thanks for playing!") - for(var/I in credit_order_for_this_round) - if(!credits) - return - _credits += new /atom/movable/screen/credit(null, I, src, credits_icon) - sleep(CREDIT_SPAWN_SPEED) - sleep(CREDIT_ROLL_SPEED - CREDIT_SPAWN_SPEED) - remove_verb(src, /client/proc/ClearCredits) - qdel(credits_icon) - -/client/proc/ClearCredits() - set name = "Hide Credits" - set category = "OOC" - remove_verb(src, /client/proc/ClearCredits) - QDEL_LIST(credits) - credits = null - -/atom/movable/screen/credit - mouse_opacity = MOUSE_OPACITY_TRANSPARENT - alpha = 0 - screen_loc = "12,1" - plane = SPLASHSCREEN_PLANE - var/client/parent - var/matrix/target - -/atom/movable/screen/credit/Initialize(mapload, credited, client/P, icon/I) - . = ..() - icon = I - parent = P - icon_state = credited - maptext = MAPTEXT_PIXELLARI(credited) - maptext_x = world.icon_size + 8 - maptext_y = (world.icon_size / 2) - 4 - maptext_width = world.icon_size * 3 - var/matrix/M = matrix(transform) - M.Translate(0, CREDIT_ANIMATE_HEIGHT) - animate(src, transform = M, time = CREDIT_ROLL_SPEED) - target = M - animate(src, alpha = 255, time = CREDIT_EASE_DURATION, flags = ANIMATION_PARALLEL) - addtimer(CALLBACK(src, PROC_REF(FadeOut)), CREDIT_ROLL_SPEED - CREDIT_EASE_DURATION) - QDEL_IN(src, CREDIT_ROLL_SPEED) - if(parent) - parent.screen += src - -/atom/movable/screen/credit/Destroy() - icon = null - if(parent) - parent.screen -= src - LAZYREMOVE(parent.credits, src) - parent = null - return ..() - -/atom/movable/screen/credit/proc/FadeOut() - animate(src, alpha = 0, transform = target, time = CREDIT_EASE_DURATION) - -#undef CREDIT_ANIMATE_HEIGHT -#undef CREDIT_EASE_DURATION -#undef CREDIT_ROLL_SPEED -#undef CREDIT_SPAWN_SPEED -#undef CREDITS_PATH diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 539dcb585ab2..3f149ec80769 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -334,7 +334,7 @@ send_item_attack_message(attacking_item, user) if(!attacking_item.force) return FALSE - var/damage = attacking_item.force + var/damage = attacking_item.force * user.outgoing_damage_mod if(mob_biotypes & MOB_ROBOTIC) damage *= attacking_item.demolition_mod apply_damage(damage, attacking_item.damtype) diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 5fb06027a5fc..f85392756bc5 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -234,6 +234,7 @@ GLOBAL_REAL(Master, /datum/controller/master) // Initialize subsystems. for (var/datum/controller/subsystem/subsystem in stage_sorted_subsystems[current_init_stage]) init_subsystem(subsystem) + #ifndef OPENDREAM if(world.system_type == MS_WINDOWS) var/ss_name = "[subsystem.name]" var/memory_summary = call_ext("memorystats", "get_memory_stats")() @@ -241,6 +242,7 @@ GLOBAL_REAL(Master, /datum/controller/master) var/string = "[ss_name] [memory_summary]" WRITE_FILE(file, string) + #endif CHECK_TICK current_initializing_subsystem = null diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm index 21bab011b399..1b77a8555554 100644 --- a/code/controllers/subsystem/blackbox.dm +++ b/code/controllers/subsystem/blackbox.dm @@ -4,7 +4,7 @@ SUBSYSTEM_DEF(blackbox) runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME init_order = INIT_ORDER_BLACKBOX - var/list/feedback_list = list() //list of datum/feedback_variable + var/list/datum/feedback_variable/feedback_list = list() //list of datum/feedback_variable var/list/first_death = list() //the first death of this round, assoc. vars keep track of different things var/triggertime = 0 var/sealed = FALSE //time to stop tracking stats? diff --git a/code/controllers/subsystem/dcs.dm b/code/controllers/subsystem/dcs.dm index 8e305d95699b..8dbd88e6231a 100644 --- a/code/controllers/subsystem/dcs.dm +++ b/code/controllers/subsystem/dcs.dm @@ -58,3 +58,12 @@ PROCESSING_SUBSYSTEM_DEF(dcs) fullid += named_arguments return list2params(fullid) + +/datum/controller/subsystem/processing/dcs/proc/_Has_Element(atom/checker, datum/element/element_id) + var/datum/element/eletype = elements_by_type[element_id] + if(!eletype) + return FALSE //not yet created simply return FALSE + + if(!(checker in eletype?._signal_procs)) //shitcode beware + return FALSE + return TRUE diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 6ef45699f514..ab0406609acf 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -74,6 +74,8 @@ SUBSYSTEM_DEF(ticker) ///add jobs to this that should get rewarded monkecoins, example: JOB_SECURITY_OFFICER var/list/jobs_to_reward = list(JOB_JANITOR,) + var/list/popcount + /datum/controller/subsystem/ticker/Initialize() // monkestation start: fix-lobby-music var/old_login_music = trim(file2text("data/last_round_lobby_music.txt")) diff --git a/code/datums/atmosphere/planetary.dm b/code/datums/atmosphere/planetary.dm index 3fa845b144cd..868658f04226 100644 --- a/code/datums/atmosphere/planetary.dm +++ b/code/datums/atmosphere/planetary.dm @@ -47,8 +47,8 @@ minimum_pressure = HAZARD_LOW_PRESSURE + 10 maximum_pressure = LAVALAND_EQUIPMENT_EFFECT_PRESSURE - 1 - minimum_temp = 180 - maximum_temp = 180 + minimum_temp = ICEBOX_MIN_TEMPERATURE + maximum_temp = ICEBOX_MIN_TEMPERATURE /datum/atmosphere/oshan id = OSHAN_DEFAULT_ATMOS diff --git a/code/datums/bodypart_overlays/bodypart_overlay.dm b/code/datums/bodypart_overlays/bodypart_overlay.dm index 3173296a03e8..365a9f73197e 100644 --- a/code/datums/bodypart_overlays/bodypart_overlay.dm +++ b/code/datums/bodypart_overlays/bodypart_overlay.dm @@ -8,6 +8,14 @@ ///Key of the icon states of all the sprite_datums for easy caching var/cache_key = "" + ///our color palette + var/datum/color_palette/palette + ///our palette key + var/palette_key + ///our fallback key + var/fallback_key + ///list of palette keys to colors used if the accessory says it needs multiple colors + var/list/color_keys ///Wrapper for getting the proper image, colored and everything /datum/bodypart_overlay/proc/get_overlay(layer, obj/item/bodypart/limb) diff --git a/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm b/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm index 0b52225359cb..e5abf9f742ef 100644 --- a/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm +++ b/code/datums/bodypart_overlays/mutant_bodypart_overlay.dm @@ -13,10 +13,6 @@ ///Take on the dna/preference from whoever we're gonna be inserted in var/imprint_on_next_insertion = TRUE -/datum/bodypart_overlay/mutant/get_overlay(layer, obj/item/bodypart/limb) - inherit_color(limb) // If draw_color is not set yet, go ahead and do that - return ..() - ///Completely random image and color generation (obeys what a player can choose from) /datum/bodypart_overlay/mutant/proc/randomize_appearance() randomize_sprite() @@ -53,27 +49,6 @@ /datum/bodypart_overlay/mutant/proc/get_base_icon_state() return sprite_datum.icon_state -///Get the image we need to draw on the person. Called from get_overlay() which is called from _bodyparts.dm. Limb can be null -/datum/bodypart_overlay/mutant/get_image(image_layer, obj/item/bodypart/limb) - if(!sprite_datum) - CRASH("Trying to call get_image() on [type] while it didn't have a sprite_datum. This shouldn't happen, report it as soon as possible.") - - var/gender = (limb?.limb_gender == FEMALE) ? "f" : "m" - var/list/icon_state_builder = list() - icon_state_builder += sprite_datum.gender_specific ? gender : "m" //Male is default because sprite accessories are so ancient they predate the concept of not hardcoding gender - icon_state_builder += feature_key - icon_state_builder += get_base_icon_state() - icon_state_builder += mutant_bodyparts_layertext(image_layer) - - var/finished_icon_state = icon_state_builder.Join("_") - - var/mutable_appearance/appearance = mutable_appearance(sprite_datum.icon, finished_icon_state, layer = image_layer) - - if(sprite_datum.center) - center_image(appearance, sprite_datum.dimension_x, sprite_datum.dimension_y) - - return appearance - ///Get the image we need to draw on the person. Called from get_overlay() which is called from _bodyparts.dm. Limb can be null /datum/bodypart_overlay/mutant/get_image_inner(image_layer, obj/item/bodypart/limb) if(!sprite_datum) @@ -98,10 +73,6 @@ return appearance -/datum/bodypart_overlay/mutant/color_image(image/overlay, layer, obj/item/bodypart/limb) - - overlay.color = sprite_datum.color_src ? draw_color : null - /datum/bodypart_overlay/mutant/added_to_limb(obj/item/bodypart/limb) inherit_color(limb) @@ -136,26 +107,25 @@ if(draw_color && !force) return FALSE - switch(color_source) - if(ORGAN_COLOR_OVERRIDE) - draw_color = override_color(ownerlimb.draw_color) - if(ORGAN_COLOR_INHERIT) - draw_color = ownerlimb.draw_color - if(ORGAN_COLOR_HAIR) - if(!ishuman(ownerlimb.owner)) - return - var/mob/living/carbon/human/human_owner = ownerlimb.owner - draw_color = human_owner.hair_color - if(ORGAN_COLOR_ANIME) - if(!ishuman(ownerlimb.owner)) - return - var/mob/living/carbon/human/human_owner = ownerlimb.owner - draw_color = human_owner.dna.features["animecolor"] - if(ORGAN_COLOR_MUTSECONDARY) - if(!ishuman(ownerlimb.owner)) - return - var/mob/living/carbon/human/human_owner = ownerlimb.owner - draw_color = human_owner.dna.features["mcolor_secondary"] + if(palette) + var/datum/color_palette/located = ownerlimb.owner.dna.color_palettes[palette] + draw_color = located.return_color(palette_key, fallback_key) + else + switch(color_source) + if(ORGAN_COLOR_OVERRIDE) + draw_color = override_color(ownerlimb.draw_color) + if(ORGAN_COLOR_INHERIT) + draw_color = ownerlimb.draw_color + if(ORGAN_COLOR_HAIR) + if(!ishuman(ownerlimb.owner)) + return + var/mob/living/carbon/human/human_owner = ownerlimb.owner + draw_color = human_owner.hair_color + if(ORGAN_COLOR_ANIME) + if(!ishuman(ownerlimb.owner)) + return + var/mob/living/carbon/human/human_owner = ownerlimb.owner + draw_color = human_owner.dna.features["animecolor"] return TRUE diff --git a/code/datums/components/bloodysoles.dm b/code/datums/components/bloodysoles.dm index 0d950031f229..b2e98144d536 100644 --- a/code/datums/components/bloodysoles.dm +++ b/code/datums/components/bloodysoles.dm @@ -3,35 +3,44 @@ * Component for clothing items that can pick up blood from decals and spread it around everywhere when walking, such as shoes or suits with integrated shoes. */ /datum/component/bloodysoles + /* /// The type of the last grub pool we stepped in, used to decide the type of footprints to make var/last_blood_state = BLOOD_STATE_NOT_BLOODY /// How much of each grubby type we have on our feet var/list/bloody_shoes = list(BLOOD_STATE_HUMAN = 0,BLOOD_STATE_XENO = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0) + */ //Monkestation removal: BLOOD_DATUMS + + // Monkestation Addition: BLOOD_DATUMS + /// What percentage of the bloodiness is deposited on the ground per step + var/blood_dropped_per_step = 3 + /// Bloodiness on our clothines + VAR_FINAL/total_bloodiness = 0 + // Monkestation Addition: BLOOD_DATUMS /// The ITEM_SLOT_* slot the item is equipped on, if it is. var/equipped_slot - /// The parent item but casted into atom type for easier use. - var/atom/parent_atom - /// Either the mob carrying the item, or the mob itself for the /feet component subtype - var/mob/living/carbon/wielder + VAR_FINAL/mob/living/carbon/wielder /// The world.time when we last picked up blood - var/last_pickup + VAR_FINAL/last_pickup var/footprint_sprite = FOOTPRINT_SPRITE_SHOES /datum/component/bloodysoles/Initialize() if(!isclothing(parent)) return COMPONENT_INCOMPATIBLE - parent_atom = parent RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip)) RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop)) RegisterSignal(parent, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_clean)) +/datum/component/bloodysoles/Destroy() + wielder = null + return ..() + /** * Unregisters from the wielder if necessary */ @@ -55,63 +64,52 @@ var/obj/item/parent_item = parent parent_item.update_slot_icon() - -/datum/component/bloodysoles/proc/reset_bloody_shoes() - bloody_shoes = list(BLOOD_STATE_HUMAN = 0, BLOOD_STATE_XENO = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0) - on_changed_bloody_shoes(BLOOD_STATE_NOT_BLOODY) - -///lowers bloody_shoes[index] by adjust_by -/datum/component/bloodysoles/proc/adjust_bloody_shoes(index, adjust_by) - bloody_shoes[index] = max(bloody_shoes[index] - adjust_by, 0) - on_changed_bloody_shoes() - -/datum/component/bloodysoles/proc/set_bloody_shoes(index, new_value) - bloody_shoes[index] = new_value - on_changed_bloody_shoes(index) - ///called whenever the value of bloody_soles changes -/datum/component/bloodysoles/proc/on_changed_bloody_shoes(index) - if(index && index != last_blood_state) - last_blood_state = index +/datum/component/bloodysoles/proc/change_blood_amount(some_amount) + total_bloodiness = clamp(round(total_bloodiness + some_amount, 0.1), 0, BLOOD_ITEM_MAX) if(!wielder) return - if(bloody_shoes[index] <= BLOOD_FOOTPRINTS_MIN * 2)//need twice that amount to make footprints + if(total_bloodiness <= BLOOD_FOOTPRINTS_MIN * 2)//need twice that amount to make footprints UnregisterSignal(wielder, COMSIG_MOVABLE_MOVED) else RegisterSignal(wielder, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved), override = TRUE) + update_icon() /** * Run to equally share the blood between us and a decal */ /datum/component/bloodysoles/proc/share_blood(obj/effect/decal/cleanable/pool) // Share the blood between our boots and the blood pool - var/total_bloodiness = pool.bloodiness + bloody_shoes[pool.blood_state] - - // We can however be limited by how much blood we can hold - var/new_our_bloodiness = min(BLOOD_ITEM_MAX, total_bloodiness / 2) - - set_bloody_shoes(pool.blood_state, new_our_bloodiness) - pool.bloodiness = total_bloodiness - new_our_bloodiness // Give the pool the remaining blood incase we were limited + var/new_total_bloodiness = min(BLOOD_ITEM_MAX, pool.bloodiness + total_bloodiness / 2) + if(new_total_bloodiness == total_bloodiness || new_total_bloodiness == 0) + return - if(HAS_TRAIT(wielder, TRAIT_LIGHT_STEP)) //the character is agile enough to don't mess their clothing and hands just from one blood splatter at floor - return TRUE + var/delta = new_total_bloodiness - total_bloodiness + pool.adjust_bloodiness(-1 * delta) + change_blood_amount(delta) + var/atom/parent_atom = parent parent_atom.add_blood_DNA(GET_ATOM_BLOOD_DNA(pool)) - update_icon() /** - * Find a blood decal on a turf that matches our last_blood_state + * Adds blood to an existing (or new) footprint */ -/datum/component/bloodysoles/proc/find_pool_by_blood_state(turf/turfLoc, typeFilter = null, footprint_sprite) - for(var/obj/effect/decal/cleanable/blood/pool in turfLoc) - if(pool.blood_state == last_blood_state && pool.footprint_sprite == footprint_sprite && (!typeFilter || istype(pool, typeFilter))) - return pool +/datum/component/bloodysoles/proc/add_blood_to_footprint(obj/effect/decal/cleanable/blood/footprints/footprint, bloodiness_to_add, exiting = FALSE) + var/atom/atom_parent = parent + add_parent_to_footprint(footprint) + footprint.adjust_bloodiness(bloodiness_to_add) + footprint.add_blood_DNA(GET_ATOM_BLOOD_DNA(atom_parent)) + if(exiting) + footprint.exited_dirs |= wielder.dir + else + footprint.entered_dirs |= wielder.dir + footprint.update_appearance() /** * Adds the parent type to the footprint's shoe_types var */ -/datum/component/bloodysoles/proc/add_parent_to_footprint(obj/effect/decal/cleanable/blood/footprints/FP) - FP.shoe_types |= parent.type +/datum/component/bloodysoles/proc/add_parent_to_footprint(obj/effect/decal/cleanable/blood/footprints/footprint) + footprint.shoe_types |= parent.type /** * Called when the parent item is equipped by someone @@ -130,7 +128,7 @@ equipped_slot = slot wielder = equipper - if(bloody_shoes[last_blood_state] > BLOOD_FOOTPRINTS_MIN * 2) + if(total_bloodiness > BLOOD_FOOTPRINTS_MIN * 2) RegisterSignal(wielder, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) RegisterSignal(wielder, COMSIG_STEP_ON_BLOOD, PROC_REF(on_step_blood)) @@ -149,61 +147,51 @@ * * Used to make bloody footprints on the ground */ -/datum/component/bloodysoles/proc/on_moved(datum/source, OldLoc, Dir, Forced) +/datum/component/bloodysoles/proc/on_moved(datum/source, atom/old_loc, Dir, Forced) SIGNAL_HANDLER - if(bloody_shoes[last_blood_state] == 0) + if(total_bloodiness <= 0) return if(QDELETED(wielder) || is_obscured()) return if(wielder.body_position == LYING_DOWN || !wielder.has_gravity(wielder.loc)) return - var/half_our_blood = bloody_shoes[last_blood_state] / 2 - var/footprint_sprite = wielder.get_footprint_sprite() + var/atom/parent_atom = parent + var/blood_used = round(total_bloodiness / 3, 0.01) + // Add footprints in old loc if we have enough cream - if(half_our_blood >= BLOOD_FOOTPRINTS_MIN) - var/turf/oldLocTurf = get_turf(OldLoc) - var/obj/effect/decal/cleanable/blood/footprints/oldLocFP = find_pool_by_blood_state(oldLocTurf, /obj/effect/decal/cleanable/blood/footprints, footprint_sprite) - if(oldLocFP) - // Footprints found in the tile we left, add us to it - add_parent_to_footprint(oldLocFP) - if (!(oldLocFP.exited_dirs & wielder.dir)) - oldLocFP.exited_dirs |= wielder.dir - oldLocFP.update_appearance() - else if(find_pool_by_blood_state(oldLocTurf, footprint_sprite = footprint_sprite)) - // No footprints in the tile we left, but there was some other blood pool there. Add exit footprints on it - adjust_bloody_shoes(last_blood_state, half_our_blood) - update_icon() + if(blood_used >= BLOOD_FOOTPRINTS_MIN) + var/turf/old_loc_turf = get_turf(old_loc) + var/obj/effect/decal/cleanable/blood/footprints/old_loc_prints = locate() in old_loc_turf + if(old_loc_prints) + add_blood_to_footprint(old_loc_prints, 0, TRUE) // Add no actual blood, just update sprite - oldLocFP = new(oldLocTurf, footprint_sprite) - if(!QDELETED(oldLocFP)) ///prints merged - oldLocFP.blood_state = last_blood_state - oldLocFP.exited_dirs |= wielder.dir - add_parent_to_footprint(oldLocFP) - oldLocFP.bloodiness = half_our_blood - oldLocFP.add_blood_DNA(GET_ATOM_BLOOD_DNA(parent_atom)) - oldLocFP.update_appearance() + else if(locate(/obj/effect/decal/cleanable/blood) in old_loc_turf) + // No footprints in the tile we left, but there was some other blood pool there. Add exit footprints on it + change_blood_amount(-1 * blood_used) + old_loc_prints = new(old_loc_turf) + if(!QDELETED(old_loc_prints)) // prints merged + add_blood_to_footprint(old_loc_prints, blood_used, TRUE) - half_our_blood = bloody_shoes[last_blood_state] / 2 + blood_used = round(total_bloodiness / 3, 0.01) // If we picked up the blood on this tick in on_step_blood, don't make footprints at the same place if(last_pickup && last_pickup == world.time) return // Create new footprints - if(half_our_blood >= BLOOD_FOOTPRINTS_MIN) - adjust_bloody_shoes(last_blood_state, half_our_blood) - update_icon() + if(blood_used >= BLOOD_FOOTPRINTS_MIN) + var/turf/new_loc_turf = get_turf(parent_atom) + var/obj/effect/decal/cleanable/blood/footprints/new_loc_prints = locate() in new_loc_turf + if(new_loc_prints) + add_blood_to_footprint(new_loc_prints, 0, FALSE) // Add no actual blood, just update sprite - var/obj/effect/decal/cleanable/blood/footprints/FP = new(get_turf(parent_atom), footprint_sprite) - if(!QDELETED(FP)) ///prints merged - FP.blood_state = last_blood_state - FP.entered_dirs |= wielder.dir - add_parent_to_footprint(FP) - FP.bloodiness = half_our_blood - FP.add_blood_DNA(GET_ATOM_BLOOD_DNA(parent_atom)) - FP.update_appearance() + else + change_blood_amount(-1 * blood_used) + new_loc_prints = new(new_loc_turf) + if(!QDELETED(new_loc_prints)) // prints merged + add_blood_to_footprint(new_loc_prints, blood_used, FALSE) /** @@ -214,20 +202,16 @@ /datum/component/bloodysoles/proc/on_step_blood(datum/source, obj/effect/decal/cleanable/pool) SIGNAL_HANDLER - if(QDELETED(wielder) || is_obscured()) + if(QDELETED(wielder) || is_obscured() || !wielder.has_gravity(wielder.loc)) + return + /// The character is agile enough to not mess their clothing and hands just from one blood splatter at floor + if(HAS_TRAIT(wielder, TRAIT_LIGHT_STEP)) + return + // Don't share from other feetprints, not super realistic but I think it ruins the effect a bit + if(istype(pool, /obj/effect/decal/cleanable/blood/footprints)) return - - if(istype(pool, /obj/effect/decal/cleanable/blood/footprints) && pool.blood_state == last_blood_state) - // The pool we stepped in was actually footprints with the same type - var/obj/effect/decal/cleanable/blood/footprints/pool_FP = pool - add_parent_to_footprint(pool_FP) - if((bloody_shoes[last_blood_state] / 2) >= BLOOD_FOOTPRINTS_MIN && !(pool_FP.entered_dirs & wielder.dir)) - // If our feet are bloody enough, add an entered dir - pool_FP.entered_dirs |= wielder.dir - pool_FP.update_appearance() share_blood(pool) - last_pickup = world.time /** @@ -236,10 +220,10 @@ /datum/component/bloodysoles/proc/on_clean(datum/source, clean_types) SIGNAL_HANDLER - if(!(clean_types & CLEAN_TYPE_BLOOD) || last_blood_state == BLOOD_STATE_NOT_BLOODY) + if(!(clean_types & CLEAN_TYPE_BLOOD)) return NONE - reset_bloody_shoes() + total_bloodiness = 0 update_icon() return COMPONENT_CLEANED @@ -248,12 +232,12 @@ * Like its parent but can be applied to carbon mobs instead of clothing items */ /datum/component/bloodysoles/feet + equipped_slot = ITEM_SLOT_FEET var/static/mutable_appearance/bloody_feet /datum/component/bloodysoles/feet/Initialize() if(!iscarbon(parent)) return COMPONENT_INCOMPATIBLE - parent_atom = parent wielder = parent if(footprint_sprite) src.footprint_sprite = footprint_sprite @@ -266,29 +250,26 @@ RegisterSignal(parent, COMSIG_CARBON_EQUIP_SHOECOVER, PROC_REF(equip_shoecover)) /datum/component/bloodysoles/feet/update_icon() - if(ishuman(wielder)) - var/mob/living/carbon/human/human = wielder - if(NOBLOODOVERLAY in human.dna.species.species_traits) - return - if(bloody_shoes[BLOOD_STATE_HUMAN] > 0 && !is_obscured()) - human.remove_overlay(SHOES_LAYER) - human.overlays_standing[SHOES_LAYER] = bloody_feet - human.apply_overlay(SHOES_LAYER) - else - human.update_worn_shoes() + if(!ishuman(wielder) || HAS_TRAIT(wielder, TRAIT_NO_BLOOD_OVERLAY)) + return + wielder.remove_overlay(SHOES_LAYER) + if(total_bloodiness > 0 && !is_obscured()) + bloody_feet.color = wielder.get_blood_dna_color() + wielder.overlays_standing[SHOES_LAYER] = bloody_feet + wielder.apply_overlay(SHOES_LAYER) + else + wielder.update_worn_shoes() -/datum/component/bloodysoles/feet/add_parent_to_footprint(obj/effect/decal/cleanable/blood/footprints/FP) +/datum/component/bloodysoles/feet/add_parent_to_footprint(obj/effect/decal/cleanable/blood/footprints/footprint) if(!ishuman(wielder)) - FP.species_types |= "unknown" + footprint.species_types |= "unknown" return // Find any leg of our human and add that to the footprint, instead of the default which is to just add the human type - for(var/X in wielder.bodyparts) - var/obj/item/bodypart/affecting = X - if(affecting.body_part == LEG_RIGHT || affecting.body_part == LEG_LEFT) - if(!affecting.bodypart_disabled) - FP.species_types |= affecting.limb_id - break + for(var/obj/item/bodypart/affecting as anything in wielder.bodyparts) + if(!affecting.bodypart_disabled && (affecting.body_part == LEG_RIGHT || affecting.body_part == LEG_LEFT)) + footprint.species_types |= affecting.limb_id + break /datum/component/bloodysoles/feet/is_obscured() @@ -297,16 +278,12 @@ return wielder.check_obscured_slots(TRUE) & ITEM_SLOT_FEET /datum/component/bloodysoles/feet/on_moved(datum/source, OldLoc, Dir, Forced) - if(wielder.num_legs < 2) - return - - ..() + if(wielder.num_legs >= 2) + return ..() /datum/component/bloodysoles/feet/on_step_blood(datum/source, obj/effect/decal/cleanable/pool) - if(wielder.num_legs < 2) - return - - ..() + if(wielder.num_legs >= 2) + return ..() /datum/component/bloodysoles/feet/proc/unequip_shoecover(datum/source) SIGNAL_HANDLER diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm index 55e14ac851d3..08864d934cb9 100644 --- a/code/datums/components/butchering.dm +++ b/code/datums/components/butchering.dm @@ -150,7 +150,7 @@ butcher_callback?.Invoke(butcher, meat) meat.harvest(butcher) meat.log_message("has been butchered by [key_name(butcher)]", LOG_ATTACK) - meat.gib(FALSE, FALSE, TRUE) + meat.gib(FALSE, FALSE, FALSE, TRUE) ///Enables the butchering mechanic for the mob who has equipped us. /datum/component/butchering/proc/enable_butchering(datum/source) diff --git a/code/datums/components/cleaner.dm b/code/datums/components/cleaner.dm index 874af94cc50e..eff8531afafc 100644 --- a/code/datums/components/cleaner.dm +++ b/code/datums/components/cleaner.dm @@ -96,8 +96,8 @@ ADD_TRAIT(target, TRAIT_CURRENTLY_CLEANING, REF(src)) // We need to update our planes on overlay changes RegisterSignal(target, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(cleaning_target_moved)) - var/mutable_appearance/low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, target, GAME_PLANE) - var/mutable_appearance/high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, target, ABOVE_GAME_PLANE) + var/mutable_appearance/low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, target, GAME_PLANE, appearance_flags = RESET_COLOR) // Monkestation edit BLOOD_DATUM + var/mutable_appearance/high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, target, ABOVE_GAME_PLANE, appearance_flags = RESET_COLOR) // Monkestation edit BLOOD_DATUM if(target.plane > low_bubble.plane) //check if the higher overlay is necessary target.add_overlay(high_bubble) else if(target.plane == low_bubble.plane) @@ -140,16 +140,18 @@ REMOVE_TRAIT(target, TRAIT_CURRENTLY_CLEANING, REF(src)) /datum/component/cleaner/proc/cleaning_target_moved(atom/movable/source, turf/old_turf, turf/new_turf, same_z_layer) + SIGNAL_HANDLER + if(same_z_layer) return // First, get rid of the old overlay - var/mutable_appearance/old_low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, old_turf, GAME_PLANE) - var/mutable_appearance/old_high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, old_turf, ABOVE_GAME_PLANE) + var/mutable_appearance/old_low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, old_turf, GAME_PLANE, appearance_flags = RESET_COLOR) // NON-MODULE CHANGE + var/mutable_appearance/old_high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, old_turf, ABOVE_GAME_PLANE, appearance_flags = RESET_COLOR) // NON-MODULE CHANGE source.cut_overlay(old_low_bubble) source.cut_overlay(old_high_bubble) // Now, add the new one - var/mutable_appearance/new_low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, new_turf, GAME_PLANE) - var/mutable_appearance/new_high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, new_turf, ABOVE_GAME_PLANE) + var/mutable_appearance/new_low_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, new_turf, GAME_PLANE, appearance_flags = RESET_COLOR) // NON-MODULE CHANGE + var/mutable_appearance/new_high_bubble = mutable_appearance('icons/effects/effects.dmi', "bubbles", FLOOR_CLEAN_LAYER, new_turf, ABOVE_GAME_PLANE, appearance_flags = RESET_COLOR) // NON-MODULE CHANGE source.add_overlay(new_low_bubble) source.add_overlay(new_high_bubble) diff --git a/code/datums/components/cult_ritual_item.dm b/code/datums/components/cult_ritual_item.dm index 584d9c0f5267..8d2e9fc133e0 100644 --- a/code/datums/components/cult_ritual_item.dm +++ b/code/datums/components/cult_ritual_item.dm @@ -303,7 +303,7 @@ span_cult("You [cultist.blood_volume ? "slice open your arm and ":""]begin drawing a sigil of the Geometer.") ) - if(cultist.blood_volume) + if(!HAS_TRAIT(cultist, TRAIT_NOBLOOD)) // Monkestation Edit: BLOOD_DATUM cultist.apply_damage(initial(rune_to_scribe.scribe_damage), BRUTE, pick(GLOB.arm_zones), wound_bonus = CANT_WOUND) // *cuts arm* *bone explodes* ever have one of those days? var/scribe_mod = initial(rune_to_scribe.scribe_delay) diff --git a/code/datums/components/food/edible.dm b/code/datums/components/food/edible.dm index 33de3942ec3a..a1726ca00b4e 100644 --- a/code/datums/components/food/edible.dm +++ b/code/datums/components/food/edible.dm @@ -452,7 +452,7 @@ Behavior that's still missing from this component that original food items had t stack_trace("[eater] failed to bite [owner], because [owner] had no reagents.") return FALSE if(eater.satiety > -200) - eater.satiety -= junkiness + eater.adjust_satiety(-junkiness) playsound(eater.loc,'sound/items/eatfood.ogg', rand(10,50), TRUE) if(!owner.reagents.total_volume) return @@ -511,57 +511,39 @@ Behavior that's still missing from this component that original food items had t return TRUE ///Check foodtypes to see if we should send a moodlet -/datum/component/edible/proc/checkLiked(fraction, mob/M) +/datum/component/edible/proc/checkLiked(fraction, mob/eater) if(last_check_time + 50 > world.time) return FALSE - if(!ishuman(M)) + if(!ishuman(eater)) return FALSE - var/mob/living/carbon/human/H = M + var/mob/living/carbon/human/gourmand = eater //Bruh this breakfast thing is cringe and shouldve been handled separately from food-types, remove this in the future (Actually, just kill foodtypes in general) if((foodtypes & BREAKFAST) && world.time - SSticker.round_start_time < STOP_SERVING_BREAKFAST) - H.add_mood_event("breakfast", /datum/mood_event/breakfast) + gourmand.add_mood_event("breakfast", /datum/mood_event/breakfast) last_check_time = world.time - if(HAS_TRAIT(H, TRAIT_AGEUSIA)) - if(foodtypes & H.dna.species.toxic_food) - to_chat(H, span_warning("You don't feel so good...")) - H.adjust_disgust(25 + 30 * fraction) - return // Don't care about the later checks if user has ageusia - var/food_taste_reaction if(check_liked) //Callback handling; use this as an override for special food like donuts - food_taste_reaction = check_liked.Invoke(fraction, H) + food_taste_reaction = check_liked.Invoke(fraction, gourmand) if(!food_taste_reaction) - if(foodtypes & H.dna.species.toxic_food) - food_taste_reaction = FOOD_TOXIC - else if(foodtypes & H.dna.species.disliked_food) - food_taste_reaction = FOOD_DISLIKED - else if(foodtypes & H.dna.species.liked_food) - food_taste_reaction = FOOD_LIKED - - if(HAS_TRAIT(parent, TRAIT_FOOD_SILVER)) // it's not real food - food_taste_reaction = isjellyperson(H) ? FOOD_LIKED : FOOD_TOXIC + food_taste_reaction = gourmand.get_food_taste_reaction(parent, foodtypes) switch(food_taste_reaction) if(FOOD_TOXIC) - to_chat(H,span_warning("What the hell was that thing?!")) - H.adjust_disgust(25 + 30 * fraction) - H.add_mood_event("toxic_food", /datum/mood_event/disgusting_food) + to_chat(gourmand,span_warning("What the hell was that thing?!")) + gourmand.adjust_disgust(25 + 30 * fraction) + gourmand.add_mood_event("toxic_food", /datum/mood_event/disgusting_food) if(FOOD_DISLIKED) - to_chat(H,span_notice("That didn't taste very good...")) - H.adjust_disgust(11 + 15 * fraction) - H.add_mood_event("gross_food", /datum/mood_event/gross_food) + to_chat(gourmand,span_notice("That didn't taste very good...")) + gourmand.adjust_disgust(11 + 15 * fraction) + gourmand.add_mood_event("gross_food", /datum/mood_event/gross_food) if(FOOD_LIKED) - to_chat(H,span_notice("I love this taste!")) - H.adjust_disgust(-5 + -2.5 * fraction) - H.add_mood_event("fav_food", /datum/mood_event/favorite_food) - if(istype(parent, /obj/item/food)) - var/obj/item/food/memorable_food = parent - if(memorable_food.venue_value >= FOOD_PRICE_EXOTIC) - H.add_mob_memory(/datum/memory/good_food, food = parent) + to_chat(gourmand,span_notice("I love this taste!")) + gourmand.adjust_disgust(-5 + -2.5 * fraction) + gourmand.add_mood_event("fav_food", /datum/mood_event/favorite_food) ///Delete the item when it is fully eaten /datum/component/edible/proc/On_Consume(mob/living/eater, mob/living/feeder) diff --git a/code/datums/components/rot.dm b/code/datums/components/rot.dm index 4dcb69a2e9eb..7898d252b5ca 100644 --- a/code/datums/components/rot.dm +++ b/code/datums/components/rot.dm @@ -42,20 +42,25 @@ AddComponent(/datum/component/connect_loc_behalf, parent, loc_connections) RegisterSignal(parent, COMSIG_MOVABLE_BUMP, PROC_REF(rot_react)) if(isliving(parent)) + var/mob/living/living_parent = parent RegisterSignal(parent, COMSIG_LIVING_REVIVE, PROC_REF(react_to_revive)) //mobs stop this when they come to life RegisterSignal(parent, COMSIG_LIVING_GET_PULLED, PROC_REF(rot_react_touch)) + + RegisterSignal(parent, COMSIG_LIVING_BODY_TEMPERATURE_CHANGE, PROC_REF(check_for_temperature)) + check_for_temperature(parent, living_parent.bodytemperature, living_parent.bodytemperature) if(iscarbon(parent)) var/mob/living/carbon/carbon_parent = parent - RegisterSignals(carbon_parent.reagents, list(COMSIG_REAGENTS_ADD_REAGENT, + RegisterSignals(carbon_parent.reagents, list( + COMSIG_REAGENTS_ADD_REAGENT, + COMSIG_REAGENTS_DEL_REAGENT, COMSIG_REAGENTS_REM_REAGENT, - COMSIG_REAGENTS_DEL_REAGENT), PROC_REF(check_reagent)) - RegisterSignals(parent, list(SIGNAL_ADDTRAIT(TRAIT_HUSK), SIGNAL_REMOVETRAIT(TRAIT_HUSK)), PROC_REF(check_husk_trait)) + ), PROC_REF(check_reagent)) check_reagent(carbon_parent.reagents, null) - check_husk_trait(null) - if(ishuman(parent)) - var/mob/living/carbon/human/human_parent = parent - RegisterSignal(parent, COMSIG_HUMAN_CORETEMP_CHANGE, PROC_REF(check_for_temperature)) - check_for_temperature(null, 0, human_parent.coretemperature) + + RegisterSignals(parent, list( + SIGNAL_ADDTRAIT(TRAIT_HUSK), + SIGNAL_REMOVETRAIT(TRAIT_HUSK), + ), PROC_REF(check_husk_trait)) start_up(NONE) //If nothing's blocking it, start diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm index bfdd2ce481fb..9ccf58e71431 100644 --- a/code/datums/components/tackle.dm +++ b/code/datums/components/tackle.dm @@ -367,25 +367,12 @@ var/obj/machinery/vending/darth_vendor = hit darth_vendor.tilt(user, 100) return - else if(istype(hit, /obj/structure/window)) - var/obj/structure/window/W = hit - splatWindow(user, W) - if(QDELETED(W)) - return COMPONENT_MOVABLE_IMPACT_NEVERMIND - return - var/oopsie_mod = 0 var/danger_zone = (speed - 1) * 13 // for every extra speed we have over 1, take away 13 of the safest chance danger_zone = max(min(danger_zone, 100), 1) - if(ishuman(user)) - var/mob/living/carbon/human/S = user - var/head_slot = S.get_item_by_slot(ITEM_SLOT_HEAD) - var/suit_slot = S.get_item_by_slot(ITEM_SLOT_OCLOTHING) - if(head_slot && (istype(head_slot,/obj/item/clothing/head/helmet) || istype(head_slot,/obj/item/clothing/head/utility/hardhat))) - oopsie_mod -= 6 - if(suit_slot && (istype(suit_slot,/obj/item/clothing/suit/armor/riot))) - oopsie_mod -= 6 + oopsie_mod -= floor(user.getarmor(BODY_ZONE_HEAD, MELEE) * 0.18) + oopsie_mod -= floor(user.getarmor(BODY_ZONE_CHEST, MELEE) * 0.12) if(HAS_TRAIT(user, TRAIT_CLUMSY)) oopsie_mod += 6 //honk! @@ -411,7 +398,7 @@ playsound(user, 'sound/effects/blobattack.ogg', 60, TRUE) playsound(user, 'sound/effects/splat.ogg', 70, TRUE) playsound(user, 'sound/effects/wounds/crack2.ogg', 70, TRUE) - user.emote("scream") + user.pain_emote("scream") user.gain_trauma(/datum/brain_trauma/severe/paralysis/paraplegic) // oopsie indeed! shake_camera(user, 7, 7) user.flash_act(1, TRUE, TRUE, length = 4.5) @@ -476,31 +463,6 @@ QDEL_NULL(tackle_ref) UnregisterSignal(parent, COMSIG_MOVABLE_MOVED) -///A special case for splatting for handling windows -/datum/component/tackler/proc/splatWindow(mob/living/carbon/user, obj/structure/window/W) - playsound(user, 'sound/effects/Glasshit.ogg', 140, TRUE) - - if(W.type in list(/obj/structure/window, /obj/structure/window/fulltile, /obj/structure/window/unanchored, /obj/structure/window/fulltile/unanchored)) // boring unreinforced windows - for(var/i in 1 to speed) - var/obj/item/shard/shard = new /obj/item/shard(get_turf(user)) - shard.embedding = list(embed_chance = 100, ignore_throwspeed_threshold = TRUE, impact_pain_mult=3, pain_chance=5) - shard.updateEmbedding() - user.hitby(shard, skipcatch = TRUE, hitpush = FALSE) - shard.embedding = null - shard.updateEmbedding() - W.atom_destruction() - user.stamina.adjust(-10 * speed) - user.Paralyze(3 SECONDS) - user.visible_message(span_danger("[user] smacks into [W] and shatters it, shredding [user.p_them()]self with glass!"), span_userdanger("You smacks into [W] and shatter it, shredding yourself with glass!")) - - else - user.visible_message(span_danger("[user] smacks into [W] like a bug!"), span_userdanger("You smacks into [W] like a bug!")) - user.Paralyze(1 SECONDS) - user.Knockdown(3 SECONDS) - W.take_damage(30 * speed) - user.stamina.adjust(-10 * speed) - user.adjustBruteLoss(5 * speed) - /datum/component/tackler/proc/delayedSmash(obj/structure/window/W) if(W) W.atom_destruction() diff --git a/code/datums/diseases/advance/symptoms/fever.dm b/code/datums/diseases/advance/symptoms/fever.dm index 7fd6bf70d494..77e3b3121a88 100644 --- a/code/datums/diseases/advance/symptoms/fever.dm +++ b/code/datums/diseases/advance/symptoms/fever.dm @@ -26,6 +26,7 @@ "Resistance 5" = "Increases fever intensity, fever can overheat and harm the host.", "Resistance 10" = "Further increases fever intensity.", ) + var/heat_cap = 6 KELVIN /datum/symptom/fever/Start(datum/disease/advance/A) . = ..() @@ -57,12 +58,9 @@ * * datum/disease/advance/A The disease applying the symptom */ /datum/symptom/fever/proc/set_body_temp(mob/living/M, datum/disease/advance/A) - if(unsafe) // when unsafe the fever can cause heat damage - M.add_body_temperature_change(FEVER_CHANGE, 6 * power * A.stage) - else - // Get the max amount of change allowed before going over heat damage limit, then cap the maximum allowed temperature change from a safe fever to 5 under the heat damage limit - var/change_limit = max(M.get_body_temp_heat_damage_limit() - 5 - M.get_body_temp_normal(apply_change=FALSE), 0) - M.add_body_temperature_change(FEVER_CHANGE, min(6 * power * A.stage, change_limit)) + var/mob/living/affected = M + var/new_level = affected.standard_body_temperature + (heat_cap * power * A.stage) + affected.add_homeostasis_level(type, new_level, 0.25 KELVIN * power) /// Update the body temp change based on the new stage /datum/symptom/fever/on_stage_change(datum/disease/advance/A) @@ -74,6 +72,6 @@ /datum/symptom/fever/End(datum/disease/advance/A) var/mob/living/carbon/M = A.affected_mob if(M) - M.remove_body_temperature_change(FEVER_CHANGE) + M.remove_homeostasis_level(type) #undef FEVER_CHANGE diff --git a/code/datums/dna.dm b/code/datums/dna.dm index a40c0097eb10..e6c7a51a3e39 100644 --- a/code/datums/dna.dm +++ b/code/datums/dna.dm @@ -20,7 +20,6 @@ GLOBAL_LIST_INIT(identity_block_lengths, list( * (commonly abbreviated with uf) and its blocks. Both ui and uf have a standard block length of 3 ASCII characters. */ GLOBAL_LIST_INIT(features_block_lengths, list( - "[DNA_MUTANT_COLOR_BLOCK]" = DNA_BLOCK_SIZE_COLOR, "[DNA_ETHEREAL_COLOR_BLOCK]" = DNA_BLOCK_SIZE_COLOR, )) @@ -53,7 +52,10 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) var/unique_enzymes ///Stores the hashed values of traits such as skin tones, hair style, and gender var/unique_identity - var/blood_type + /// So humans have a variety of blood types while other species do not + /// This tracks JUST human blood type. Might seem a bit bias but everyone is a human under their scales and feathers. + /// Essentially only exists so humans have their same blood type swapping from human -> non-human -> human. + var/datum/blood_type/crew/human/human_blood_type ///The type of mutant race the player is if applicable (i.e. potato-man) var/datum/species/species = new /datum/species/human ///first value is mutant color @@ -103,11 +105,12 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) return destination.dna.unique_enzymes = unique_enzymes destination.dna.unique_identity = unique_identity - destination.dna.blood_type = blood_type + destination.dna.human_blood_type = human_blood_type destination.dna.unique_features = unique_features destination.dna.features = features.Copy() destination.dna.real_name = real_name destination.dna.temporary_mutations = temporary_mutations.Copy() + destination.dna.color_palettes = color_palettes.Copy() if(transfer_SE) destination.dna.mutation_index = mutation_index destination.dna.default_mutation_genes = default_mutation_genes @@ -120,8 +123,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) new_dna.default_mutation_genes = default_mutation_genes new_dna.unique_identity = unique_identity new_dna.unique_features = unique_features - new_dna.blood_type = blood_type + new_dna.human_blood_type = human_blood_type new_dna.features = features.Copy() + new_dna.color_palettes = color_palettes.Copy() //if the new DNA has a holder, transform them immediately, otherwise save it if(new_dna.holder) new_dna.holder.set_species(species.type, icon_update = 0) @@ -194,12 +198,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) . = "" var/list/L = new /list(DNA_FEATURE_BLOCKS) - if(features["mcolor"]) - L[DNA_MUTANT_COLOR_BLOCK] = sanitize_hexcolor(features["mcolor"], include_crunch = FALSE) - if(features["mcolor_secondary"]) - L[DNA_MUTANT_COLOR_SECONDARY] = sanitize_hexcolor(features["mcolor_secondary"], include_crunch = FALSE) - if(features["ethcolor"]) - L[DNA_ETHEREAL_COLOR_BLOCK] = sanitize_hexcolor(features["ethcolor"], include_crunch = FALSE) if(features["body_markings"]) L[DNA_LIZARD_MARKINGS_BLOCK] = construct_block(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len) if(features["tail_cat"]) @@ -226,7 +224,12 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) L[DNA_MUSHROOM_CAPS_BLOCK] = construct_block(GLOB.caps_list.Find(features["caps"]), GLOB.caps_list.len) if(features["pod_hair"]) L[DNA_POD_HAIR_BLOCK] = construct_block(GLOB.pod_hair_list.Find(features["pod_hair"]), GLOB.pod_hair_list.len) - + if(features["arm_wings"]) // NON-MODULE CHANGE + L[DNA_ARM_WINGS_BLOCK] = construct_block(GLOB.arm_wings_list.Find(features["arm_wings"]), GLOB.arm_wings_list.len) + if(features["tail_avian"]) // NON-MODULE CHANGE + L[DNA_AVIAN_TAIL_BLOCK] = construct_block(GLOB.tails_list_avian.Find(features["tail_avian"]), GLOB.tails_list_avian.len) + if(features["ears_avian"]) // NON-MODULE CHANGE + L[DNA_AVIAN_EARS_BLOCK] = construct_block(GLOB.avian_ears_list.Find(features["ears_avian"]), GLOB.avian_ears_list.len) for(var/blocknum in 1 to DNA_FEATURE_BLOCKS) . += L[blocknum] || random_string(GET_UI_BLOCK_LEN(blocknum), GLOB.hex_characters) @@ -330,12 +333,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(!ishuman(holder)) CRASH("Non-human mobs shouldn't have DNA") switch(blocknumber) - if(DNA_MUTANT_COLOR_BLOCK) - set_uni_feature_block(blocknumber, sanitize_hexcolor(features["mcolor"], include_crunch = FALSE)) - if(DNA_MUTANT_COLOR_SECONDARY) - set_uni_feature_block(blocknumber, sanitize_hexcolor(features["mcolor_secondary"], include_crunch = FALSE)) - if(DNA_ETHEREAL_COLOR_BLOCK) - set_uni_feature_block(blocknumber, sanitize_hexcolor(features["ethcolor"], include_crunch = FALSE)) if(DNA_LIZARD_MARKINGS_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.body_markings_list.Find(features["body_markings"]), GLOB.body_markings_list.len)) if(DNA_TAIL_BLOCK) @@ -360,7 +357,12 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) set_uni_feature_block(blocknumber, construct_block(GLOB.caps_list.Find(features["caps"]), GLOB.caps_list.len)) if(DNA_POD_HAIR_BLOCK) set_uni_feature_block(blocknumber, construct_block(GLOB.pod_hair_list.Find(features["pod_hair"]), GLOB.pod_hair_list.len)) - + if(DNA_ARM_WINGS_BLOCK) // NON-MODULE CHANGE + set_uni_feature_block(blocknumber, construct_block(GLOB.arm_wings_list.Find(features["arm_wings"]), GLOB.arm_wings_list.len)) + if(DNA_AVIAN_TAIL_BLOCK) // NON-MODULE CHANGE + set_uni_feature_block(blocknumber, construct_block(GLOB.tails_list_avian.Find(features["tail_avian"]), GLOB.tails_list_avian.len)) + if(DNA_AVIAN_EARS_BLOCK) // NON-MODULE CHANGE + set_uni_feature_block(blocknumber, construct_block(GLOB.avian_ears_list.Find(features["ears_avian"]), GLOB.avian_ears_list.len)) //Please use add_mutation or activate_mutation instead /datum/dna/proc/force_give(datum/mutation/human/human_mutation) if(holder && human_mutation) @@ -393,7 +395,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) && real_name == target_dna.real_name \ && species.type == target_dna.species.type \ && compare_list(features, target_dna.features) \ - && blood_type == target_dna.blood_type \ + && human_blood_type == target_dna.human_blood_type \ ) return TRUE @@ -431,9 +433,9 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) unique_enzymes = generate_unique_enzymes() unique_features = generate_unique_features() -/datum/dna/proc/initialize_dna(newblood_type, skip_index = FALSE) +/datum/dna/proc/initialize_dna(newblood_type = random_human_blood_type(), skip_index = FALSE) if(newblood_type) - blood_type = newblood_type + human_blood_type = newblood_type unique_enzymes = generate_unique_enzymes() unique_identity = generate_unique_identity() if(!skip_index) //I hate this @@ -543,7 +545,7 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) dna.generate_unique_enzymes() if(newblood_type) - dna.blood_type = newblood_type + dna.human_blood_type = newblood_type if(unique_identity) dna.unique_identity = unique_identity @@ -576,6 +578,11 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) if(!has_dna()) return + //Always plural gender if agender + if(HAS_TRAIT(src, TRAIT_AGENDER)) + gender = PLURAL + return + switch(deconstruct_block(get_uni_identity_block(dna.unique_identity, DNA_GENDER_BLOCK), 3)) if(G_MALE) gender = MALE @@ -601,12 +608,6 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) else hairstyle = GLOB.hairstyles_list[deconstruct_block(get_uni_identity_block(structure, DNA_HAIRSTYLE_BLOCK), GLOB.hairstyles_list.len)] var/features = dna.unique_features - if(dna.features["mcolor"]) - dna.features["mcolor"] = sanitize_hexcolor(get_uni_feature_block(features, DNA_MUTANT_COLOR_BLOCK)) - if(dna.features["mcolor_secondary"]) - dna.features["mcolor_secondary"] = sanitize_hexcolor(get_uni_feature_block(features, DNA_MUTANT_COLOR_SECONDARY)) - if(dna.features["ethcolor"]) - dna.features["ethcolor"] = sanitize_hexcolor(get_uni_feature_block(features, DNA_ETHEREAL_COLOR_BLOCK)) if(dna.features["body_markings"]) dna.features["body_markings"] = GLOB.body_markings_list[deconstruct_block(get_uni_feature_block(features, DNA_LIZARD_MARKINGS_BLOCK), GLOB.body_markings_list.len)] if(dna.features["snout"]) @@ -637,6 +638,12 @@ GLOBAL_LIST_INIT(total_uf_len_by_block, populate_total_uf_len_by_block()) dna.features["caps"] = GLOB.caps_list[deconstruct_block(get_uni_feature_block(features, DNA_MUSHROOM_CAPS_BLOCK), GLOB.caps_list.len)] if(dna.features["pod_hair"]) dna.features["pod_hair"] = GLOB.pod_hair_list[deconstruct_block(get_uni_feature_block(features, DNA_POD_HAIR_BLOCK), GLOB.pod_hair_list.len)] + if(dna.features["arm_wings"]) // NON-MODULE CHANGE + dna.features["arm_wings"] = GLOB.arm_wings_list[deconstruct_block(get_uni_feature_block(features, DNA_ARM_WINGS_BLOCK), GLOB.arm_wings_list.len)] + if(dna.features["tail_avian"]) // NON-MODULE CHANGE + dna.features["tail_avian"] = GLOB.tails_list_avian[deconstruct_block(get_uni_feature_block(features, DNA_AVIAN_TAIL_BLOCK), GLOB.tails_list_avian.len)] + if(dna.features["ears_avian"]) // NON-MODULE CHANGE + dna.features["ears_avian"] = GLOB.avian_ears_list[deconstruct_block(get_uni_feature_block(features, DNA_AVIAN_EARS_BLOCK), GLOB.avian_ears_list.len)] for(var/obj/item/organ/external/external_organ in organs) external_organ.mutate_feature(features, src) diff --git a/code/datums/elements/_element.dm b/code/datums/elements/_element.dm index ee1d5a9af9ac..7a6703d86195 100644 --- a/code/datums/elements/_element.dm +++ b/code/datums/elements/_element.dm @@ -57,6 +57,10 @@ if(ele.Attach(arglist(arguments)) == ELEMENT_INCOMPATIBLE) CRASH("Incompatible element [ele.type] was assigned to a [type]! args: [json_encode(args)]") +/// Finds the element and checks if the source is currently part of the element +/datum/proc/_HasElement(datum/source, datum/element/type) + return SSdcs._Has_Element(source, type) + /** * Finds the singleton for the element type given and detaches it from src * You only need additional arguments beyond the type if you're using [ELEMENT_BESPOKE] diff --git a/code/datums/elements/basic_body_temp_sensitive.dm b/code/datums/elements/basic_body_temp_sensitive.dm deleted file mode 100644 index 8e11ed92575e..000000000000 --- a/code/datums/elements/basic_body_temp_sensitive.dm +++ /dev/null @@ -1,71 +0,0 @@ -/** - * When attached to a basic mob, it gives it the ability to be hurt by cold/hot body temperatures - */ -/datum/element/basic_body_temp_sensitive - element_flags = ELEMENT_BESPOKE - argument_hash_start_idx = 2 - - ///Min body temp - var/min_body_temp = 250 - ///Max body temp - var/max_body_temp = 350 - ////Damage when below min temp - var/cold_damage = 1 - ///Damage when above max temp - var/heat_damage = 1 - -/datum/element/basic_body_temp_sensitive/Attach(datum/target, min_body_temp, max_body_temp, cold_damage, heat_damage) - . = ..() - if(!isbasicmob(target)) - return ELEMENT_INCOMPATIBLE - - if(isnum(min_body_temp)) - src.min_body_temp = min_body_temp - - if(isnum(max_body_temp)) - src.max_body_temp = max_body_temp - - if(isnum(cold_damage)) - src.cold_damage = cold_damage - - if(isnum(heat_damage)) - src.heat_damage = heat_damage - - RegisterSignal(target, COMSIG_LIVING_LIFE, PROC_REF(on_life)) - -/datum/element/basic_body_temp_sensitive/Detach(datum/source) - if(source) - UnregisterSignal(source, COMSIG_LIVING_LIFE) - return ..() - - -/datum/element/basic_body_temp_sensitive/proc/on_life(datum/target, seconds_per_tick, times_fired) - SIGNAL_HANDLER - - var/mob/living/basic/basic_mob = target - var/gave_alert = FALSE - - if(basic_mob.bodytemperature < min_body_temp) - basic_mob.adjust_health(cold_damage * seconds_per_tick) - switch(cold_damage) - if(1 to 5) - basic_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 1) - if(5 to 10) - basic_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 2) - if(10 to INFINITY) - basic_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 3) - gave_alert = TRUE - - else if(basic_mob.bodytemperature > max_body_temp) - basic_mob.adjust_health(heat_damage * seconds_per_tick) - switch(heat_damage) - if(1 to 5) - basic_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 1) - if(5 to 10) - basic_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 2) - if(10 to INFINITY) - basic_mob.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 3) - gave_alert = TRUE - - if(!gave_alert) - basic_mob.clear_alert(ALERT_TEMPERATURE) diff --git a/code/datums/elements/decals/blood.dm b/code/datums/elements/decals/blood.dm index 889ebb12904b..cd679b80003d 100644 --- a/code/datums/elements/decals/blood.dm +++ b/code/datums/elements/decals/blood.dm @@ -38,6 +38,10 @@ blood_splatter_appearances[index] = pic return TRUE +/datum/element/decal/blood/apply_overlay(obj/item/source, list/overlay_list) + pic.color = source.get_blood_dna_color() || COLOR_BLOOD + return ..() + /datum/element/decal/blood/proc/get_examine_name(datum/source, mob/user, list/override) SIGNAL_HANDLER diff --git a/code/datums/elements/footstep.dm b/code/datums/elements/footstep.dm index f3e5176d0972..1bc10f91bd4d 100644 --- a/code/datums/elements/footstep.dm +++ b/code/datums/elements/footstep.dm @@ -146,8 +146,14 @@ footstep_sounds[shoestep_type][3] + e_range + range_adjustment, falloff_distance = 1, vary = sound_vary, mixer_channel = CHANNEL_SOUND_FOOTSTEPS) else var/barefoot_type = prepared_steps[FOOTSTEP_MOB_BAREFOOT] - if(source.dna.species.special_step_sounds) - heard_clients = playsound(source.loc, pick(source.dna.species.special_step_sounds), 50, TRUE, falloff_distance = 1, vary = sound_vary) + var/leg_num = source.step_leg + source.step_leg++ + if(source.step_leg > source.usable_legs) + source.step_leg = 1 + var/bodypart_slot = leg_num == 2 ? BODY_ZONE_L_LEG : BODY_ZONE_R_LEG + var/obj/item/bodypart/leg/gotten = source.get_bodypart(bodypart_slot) + if(gotten?.step_sounds) + heard_clients = playsound(source.loc, pick(gotten.step_sounds), 50, TRUE, falloff_distance = 1, vary = sound_vary) else var/static/list/bare_footstep_sounds = GLOB.barefootstep diff --git a/code/datums/interactions/intents.dm b/code/datums/interactions/intents.dm index 493bff0f4dde..93076a7395c5 100644 --- a/code/datums/interactions/intents.dm +++ b/code/datums/interactions/intents.dm @@ -10,7 +10,6 @@ if(LAZYACCESS(modifiers, RIGHT_CLICK)) M.istate = ISTATE_SECONDARY - return switch (intent) if (INTENT_DISARM) diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm index efa76ca24cd7..452048b3c231 100644 --- a/code/datums/martial/krav_maga.dm +++ b/code/datums/martial/krav_maga.dm @@ -183,9 +183,7 @@ desc = "These gloves can teach you to perform Krav Maga using nanochips." icon_state = "fightgloves" greyscale_colors = "#c41e0d" - cold_protection = HANDS min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE @@ -196,9 +194,7 @@ greyscale_colors = "#2f2e31" siemens_coefficient = 0 strip_delay = 80 - cold_protection = HANDS min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE armor_type = /datum/armor/krav_maga_combatglovesplus diff --git a/code/datums/martial/sleeping_carp.dm b/code/datums/martial/sleeping_carp.dm index df8369a707e1..ccaf1ae6caf8 100644 --- a/code/datums/martial/sleeping_carp.dm +++ b/code/datums/martial/sleeping_carp.dm @@ -162,7 +162,7 @@ /datum/martial_art/the_sleeping_carp/proc/can_deflect(mob/living/carp_user) if(!COOLDOWN_FINISHED(src, block_cooldown)) - if(prob(70)) + if(prob(50)) return FALSE if(!can_use(carp_user)) return FALSE @@ -191,7 +191,7 @@ ) COOLDOWN_START(src, block_cooldown, 3 SECONDS) playsound(carp_user, pick('sound/weapons/bulletflyby.ogg', 'sound/weapons/bulletflyby2.ogg', 'sound/weapons/bulletflyby3.ogg'), vol = 75, vary = TRUE) - carp_user.stamina?.adjust(-50) + carp_user.stamina?.adjust(-15) hitting_projectile.firer = carp_user hitting_projectile.set_angle(rand(0, 360))//SHING return COMPONENT_BULLET_PIERCED diff --git a/code/datums/mood.dm b/code/datums/mood.dm index 9cce6e98a8f3..14817b4d52e9 100644 --- a/code/datums/mood.dm +++ b/code/datums/mood.dm @@ -316,6 +316,41 @@ /// Prints the users mood, sanity, and moodies to chat /datum/mood/proc/print_mood(mob/user) var/msg = "[span_info("My current mental status:")]\n" + + if(!HAS_TRAIT(src, TRAIT_NOHUNGER)) + msg += span_notice("My hunger: ") + var/nutrition = mob_parent.nutrition + switch(nutrition) + if(NUTRITION_LEVEL_FULL to INFINITY) + msg += span_info("I'm completely stuffed!\n") + if(NUTRITION_LEVEL_WELL_FED to NUTRITION_LEVEL_FULL) + msg += span_info("I'm well fed!\n") + if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED) + msg += span_info("I'm not hungry.\n") + if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED) + msg += span_info("I could use a bite to eat.\n") + if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY) + msg += span_warning("I feel quite hungry.\n") + if(0 to NUTRITION_LEVEL_STARVING) + msg += span_boldwarning("I'm starving!\n") + + var/drunkness = mob_parent.get_timed_status_effect_duration(/datum/status_effect/inebriated) + if(drunkness >= 1) + msg += span_notice("My current drunkenness: ") + switch(drunkness) + if(1 to 10) + msg += span_info("I'm feeling a little tipsy.\n") + if(11 to 21) + msg += span_info("I'm feeling a bit drunk.\n") + if(21 to 41) + msg += span_info("I'm feeling quite drunk.\n") + if(41 to 61) + msg += span_info("I'm feeling very drunk.\n") + if(61 to 81) + msg += span_warning("I'm feeling like a mess.\n") + if(81 to INFINITY) + msg += span_boldwarning("I'm completely wasted.\n") + msg += span_notice("My current sanity: ") //Long term switch(sanity) if(SANITY_GREAT to INFINITY) @@ -356,6 +391,7 @@ if(mood_events.len) for(var/category in mood_events) var/datum/mood_event/event = mood_events[category] + msg += "• " switch(event.mood_change) if(-INFINITY to MOOD_SAD2) msg += span_boldwarning(event.description + "\n") @@ -370,7 +406,10 @@ if(MOOD_HAPPY2 to INFINITY) msg += span_boldnicegreen(event.description + "\n") else - msg += "[span_grey("I don't have much of a reaction to anything right now.")]\n" + msg += "• [span_grey("I don't have much of a reaction to anything right now.")]\n" + + if(LAZYLEN(mob_parent.quirks)) + msg += span_notice("You have these quirks: [mob_parent.get_quirk_string(FALSE, CAT_QUIRK_ALL)].") to_chat(user, examine_block(msg)) /// Updates the mob's moodies, if the area provides a mood bonus diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm index c22e940c990b..962c26c4936e 100644 --- a/code/datums/mood_events/generic_negative_events.dm +++ b/code/datums/mood_events/generic_negative_events.dm @@ -19,13 +19,29 @@ mood_change = -1 timeout = 2 MINUTES +/datum/mood_event/chilly + description = "I'm feeling a bit chilly." + mood_change = -2 + /datum/mood_event/cold - description = "It's way too cold in here." - mood_change = -5 + description = "It's way too cold." + mood_change = -3 + +/datum/mood_event/freezing + description = "It's freezing cold!" + mood_change = -6 + +/datum/mood_event/warm + description = "I'm feeling a bit warm." + mood_change = -2 /datum/mood_event/hot - description = "It's getting hot in here." - mood_change = -5 + description = "It's way too hot." + mood_change = -3 + +/datum/mood_event/overhot + description = "It's scorching hot!" + mood_change = -6 /datum/mood_event/creampie description = "I've been creamed. Tastes like pie flavor." diff --git a/code/datums/mutations/hulk.dm b/code/datums/mutations/hulk.dm index c1b42564f593..c306ab7c4dfa 100644 --- a/code/datums/mutations/hulk.dm +++ b/code/datums/mutations/hulk.dm @@ -15,7 +15,6 @@ var/list/mutation_traits = list( TRAIT_CHUNKYFINGERS, TRAIT_HULK, - TRAIT_IGNOREDAMAGESLOWDOWN, TRAIT_PUSHIMMUNE, TRAIT_STUNIMMUNE, ) @@ -29,9 +28,13 @@ part.variable_color = "#00aa00" owner.update_body_parts() owner.add_mood_event("hulk", /datum/mood_event/hulk) + owner.physiology?.cold_mod *= HULK_COLD_DAMAGE_MOD + owner.bodytemp_cold_damage_limit += BODYTEMP_HULK_COLD_DAMAGE_LIMIT_MODIFIER RegisterSignal(owner, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(on_attack_hand)) RegisterSignal(owner, COMSIG_MOB_SAY, PROC_REF(handle_speech)) RegisterSignal(owner, COMSIG_MOB_CLICKON, PROC_REF(check_swing)) + RegisterSignal(owner, COMSIG_MOB_STATCHANGE, PROC_REF(statchange)) + owner.add_movespeed_mod_immunities("hulk", /datum/movespeed_modifier/damage_slowdown) /datum/mutation/human/hulk/proc/on_attack_hand(mob/living/carbon/human/source, atom/target, proximity, modifiers) SIGNAL_HANDLER @@ -77,8 +80,9 @@ owner.cause_wound_of_type_and_severity(WOUND_BLUNT, arm, severity, wound_source = "hulk smashing") -/datum/mutation/human/hulk/on_life(seconds_per_tick, times_fired) - if(owner.health < owner.crit_threshold) +/datum/mutation/human/hulk/proc/statchange(mob/living/carbon/human/owner, stat, old_stat) + SIGNAL_HANDLER + if(stat >= UNCONSCIOUS) on_losing(owner) to_chat(owner, span_danger("You suddenly feel very weak.")) qdel(src) @@ -91,9 +95,13 @@ part.variable_color = null owner.update_body_parts() owner.clear_mood_event("hulk") + owner.physiology?.cold_mod /= HULK_COLD_DAMAGE_MOD + owner.bodytemp_cold_damage_limit -= BODYTEMP_HULK_COLD_DAMAGE_LIMIT_MODIFIER UnregisterSignal(owner, COMSIG_HUMAN_EARLY_UNARMED_ATTACK) UnregisterSignal(owner, COMSIG_MOB_SAY) UnregisterSignal(owner, COMSIG_MOB_CLICKON) + UnregisterSignal(owner, COMSIG_MOB_STATCHANGE) + owner.remove_movespeed_mod_immunities("hulk", /datum/movespeed_modifier/damage_slowdown) /datum/mutation/human/hulk/proc/handle_speech(datum/source, list/speech_args) SIGNAL_HANDLER @@ -264,6 +272,7 @@ log_combat(the_hulk, yeeted_person, "has thrown by tail") /datum/mutation/human/hulk/wizardly + name = "Hulk (Magic)" species_allowed = null //yes skeleton/lizard hulk - note that species that dont have skintone changing (like skellies) get custom handling health_req = 0 instability = 0 @@ -271,7 +280,6 @@ /// List of traits to add/remove when someone gets this mutation. mutation_traits = list( TRAIT_HULK, - TRAIT_IGNOREDAMAGESLOWDOWN, TRAIT_PUSHIMMUNE, TRAIT_STUNIMMUNE, ) // no chunk diff --git a/code/datums/quirks/_quirk.dm b/code/datums/quirks/_quirk.dm index 2b55f0932f04..3c18ddad816d 100644 --- a/code/datums/quirks/_quirk.dm +++ b/code/datums/quirks/_quirk.dm @@ -32,7 +32,7 @@ /// A list of items people can receive from mail who have this quirk enabled /// The base weight for the each quirk's mail goodies list to be selected is 5 /// then the item selected is determined by pick(selected_quirk.mail_goodies) - var/mail_goodies = list() + var/list/mail_goodies = list() //Monkestation Edit BLOOD_DATUM: Why? this is already a list all this does is mess confuse us. /datum/quirk/Destroy() if(quirk_holder) @@ -147,7 +147,7 @@ /// Otherwise, it runs once on the next COMSIG_MOB_LOGIN. /datum/quirk/proc/post_add() return - + /// return additional data that should be remembered by cloning /datum/quirk/proc/clone_data() return @@ -155,7 +155,7 @@ /// create the quirk from clone data /datum/quirk/proc/on_clone(data) return - + /// Subtype quirk that has some bonus logic to spawn items for the player. /datum/quirk/item_quirk /// Lazylist of strings describing where all the quirk items have been spawned. diff --git a/code/datums/quirks/negative_quirks.dm b/code/datums/quirks/negative_quirks.dm index a2528c8c9d92..f10307b0fae2 100644 --- a/code/datums/quirks/negative_quirks.dm +++ b/code/datums/quirks/negative_quirks.dm @@ -69,31 +69,43 @@ var/min_blood = BLOOD_VOLUME_SAFE - 25 // just barely survivable without treatment /datum/quirk/blooddeficiency/post_add() - if(!ishuman(quirk_holder)) - return + update_mail() - // for making sure the roundstart species has the right blood pack sent to them - var/mob/living/carbon/human/carbon_target = quirk_holder - carbon_target.dna.species.update_quirk_mail_goodies(carbon_target, src) - -/** - * Makes the mob lose blood from having the blood deficiency quirk, if possible - * - * Arguments: - * * seconds_per_tick - */ -/datum/quirk/blooddeficiency/proc/lose_blood(seconds_per_tick) - if(quirk_holder.stat == DEAD) +/datum/quirk/blooddeficiency/add(client/client_source) + . = ..() + RegisterSignal(quirk_holder, COMSIG_HUMAN_ON_HANDLE_BLOOD, PROC_REF(lose_blood)) + RegisterSignal(quirk_holder, COMSIG_SPECIES_GAIN, PROC_REF(update_mail)) + +/datum/quirk/blooddeficiency/remove() + . = ..() + UnregisterSignal(quirk_holder, COMSIG_HUMAN_ON_HANDLE_BLOOD) + UnregisterSignal(quirk_holder, COMSIG_SPECIES_GAIN) + +/datum/quirk/blooddeficiency/proc/lose_blood(mob/living/carbon/human/draining, seconds_per_tick, times_fired) + SIGNAL_HANDLER + if(quirk_holder.stat == DEAD || quirk_holder.blood_volume <= min_blood) return - var/mob/living/carbon/human/carbon_target = quirk_holder - if(HAS_TRAIT(carbon_target, TRAIT_NOBLOOD) && isnull(carbon_target.dna.species.exotic_blood)) //can't lose blood if your species doesn't have any + // Ensures that we don't reduce total blood volume below min_blood. + draining.blood_volume = max(min_blood, draining.blood_volume - draining.dna.species.blood_deficiency_drain_rate * seconds_per_tick) + +/datum/quirk/blooddeficiency/proc/update_mail(datum/source, datum/species/new_species, datum/species/old_species) + SIGNAL_HANDLER + + mail_goodies.Cut() + + var/datum/blood_type/new_type = quirk_holder.get_blood_type() + if(isnull(new_type)) return - if (carbon_target.blood_volume <= min_blood) + if(istype(new_type, /datum/blood_type/crew/human)) + mail_goodies += /obj/item/reagent_containers/blood/o_minus return - // Ensures that we don't reduce total blood volume below min_blood. - carbon_target.blood_volume = max(min_blood, carbon_target.blood_volume - carbon_target.dna.species.blood_deficiency_drain_rate * seconds_per_tick) + + for(var/obj/item/reagent_containers/blood/blood_bag as anything in typesof(/obj/item/reagent_containers/blood)) + if(initial(blood_bag.blood_type) == new_type.type) + mail_goodies += blood_bag + break /datum/quirk/item_quirk/blindness name = "Blind" @@ -862,7 +874,7 @@ quirk_holder.mind.remove_addiction_points(addiction_type, MAX_ADDICTION_POINTS) /datum/quirk/item_quirk/junkie/process(seconds_per_tick) - if(HAS_TRAIT(quirk_holder, TRAIT_NOMETABOLISM)) + if(HAS_TRAIT(quirk_holder, TRAIT_LIVERLESS_METABOLISM)) return var/mob/living/carbon/human/human_holder = quirk_holder if(world.time > next_process) diff --git a/code/datums/quirks/neutral_quirks.dm b/code/datums/quirks/neutral_quirks.dm index 4bc4c2168ab0..126af15ec8be 100644 --- a/code/datums/quirks/neutral_quirks.dm +++ b/code/datums/quirks/neutral_quirks.dm @@ -68,26 +68,18 @@ mail_goodies = list(/obj/effect/spawner/random/food_or_drink/salad) /datum/quirk/vegetarian/add(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - var/datum/species/species = human_holder.dna.species - species.liked_food &= ~MEAT - species.disliked_food |= MEAT - RegisterSignal(human_holder, COMSIG_SPECIES_GAIN, PROC_REF(on_species_gain)) - -/datum/quirk/vegetarian/proc/on_species_gain(datum/source, datum/species/new_species, datum/species/old_species) - SIGNAL_HANDLER - new_species.liked_food &= ~MEAT - new_species.disliked_food |= MEAT + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.liked_foodtypes &= ~MEAT + tongue.disliked_foodtypes |= MEAT /datum/quirk/vegetarian/remove() - var/mob/living/carbon/human/human_holder = quirk_holder - - var/datum/species/species = human_holder.dna.species - if(initial(species.liked_food) & MEAT) - species.liked_food |= MEAT - if(!(initial(species.disliked_food) & MEAT)) - species.disliked_food &= ~MEAT - UnregisterSignal(human_holder, COMSIG_SPECIES_GAIN) + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.liked_foodtypes = initial(tongue.liked_foodtypes) + tongue.disliked_foodtypes = initial(tongue.disliked_foodtypes) /datum/quirk/snob name = "Snob" @@ -111,20 +103,16 @@ mail_goodies = list(/obj/item/food/pizzaslice/pineapple) /datum/quirk/pineapple_liker/add(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - var/datum/species/species = human_holder.dna.species - species.liked_food |= PINEAPPLE - RegisterSignal(human_holder, COMSIG_SPECIES_GAIN, PROC_REF(on_species_gain)) - -/datum/quirk/pineapple_liker/proc/on_species_gain(datum/source, datum/species/new_species, datum/species/old_species) - SIGNAL_HANDLER - new_species.liked_food |= PINEAPPLE + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.liked_foodtypes |= PINEAPPLE /datum/quirk/pineapple_liker/remove() - var/mob/living/carbon/human/human_holder = quirk_holder - var/datum/species/species = human_holder.dna.species - species.liked_food &= ~PINEAPPLE - UnregisterSignal(human_holder, COMSIG_SPECIES_GAIN) + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.liked_foodtypes = initial(tongue.liked_foodtypes) /datum/quirk/pineapple_hater name = "Ananas Aversion" @@ -143,20 +131,16 @@ ) /datum/quirk/pineapple_hater/add(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - var/datum/species/species = human_holder.dna.species - species.disliked_food |= PINEAPPLE - RegisterSignal(human_holder, COMSIG_SPECIES_GAIN, PROC_REF(on_species_gain)) - -/datum/quirk/pineapple_hater/proc/on_species_gain(datum/source, datum/species/new_species, datum/species/old_species) - SIGNAL_HANDLER - new_species.disliked_food |= PINEAPPLE + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.disliked_foodtypes |= PINEAPPLE /datum/quirk/pineapple_hater/remove() - var/mob/living/carbon/human/human_holder = quirk_holder - var/datum/species/species = human_holder.dna.species - species.disliked_food &= ~PINEAPPLE - UnregisterSignal(human_holder, COMSIG_SPECIES_GAIN) + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.disliked_foodtypes = initial(tongue.disliked_foodtypes) /datum/quirk/deviant_tastes name = "Deviant Tastes" @@ -169,25 +153,19 @@ mail_goodies = list(/obj/item/food/urinalcake, /obj/item/food/badrecipe) // Mhhhmmm yummy /datum/quirk/deviant_tastes/add(client/client_source) - var/mob/living/carbon/human/human_holder = quirk_holder - var/datum/species/species = human_holder.dna.species - var/liked = species.liked_food - species.liked_food = species.disliked_food - species.disliked_food = liked - RegisterSignal(human_holder, COMSIG_SPECIES_GAIN, PROC_REF(on_species_gain)) - -/datum/quirk/deviant_tastes/proc/on_species_gain(datum/source, datum/species/new_species, datum/species/old_species) - SIGNAL_HANDLER - var/liked = new_species.liked_food - new_species.liked_food = new_species.disliked_food - new_species.disliked_food = liked + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + var/liked_foodtypes = tongue.liked_foodtypes + tongue.liked_foodtypes = tongue.disliked_foodtypes + tongue.disliked_foodtypes = liked_foodtypes /datum/quirk/deviant_tastes/remove() - var/mob/living/carbon/human/human_holder = quirk_holder - var/datum/species/species = human_holder.dna.species - species.liked_food = initial(species.liked_food) - species.disliked_food = initial(species.disliked_food) - UnregisterSignal(human_holder, COMSIG_SPECIES_GAIN) + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.liked_foodtypes = initial(tongue.liked_foodtypes) + tongue.disliked_foodtypes = initial(tongue.disliked_foodtypes) /datum/quirk/heterochromatic name = "Heterochromatic" @@ -410,27 +388,22 @@ var/gaming_withdrawal_timer = TIMER_ID_NULL /datum/quirk/gamer/add(client/client_source) - // Gamer diet - var/mob/living/carbon/human/human_holder = quirk_holder - var/datum/species/species = human_holder.dna.species - species.liked_food = JUNKFOOD - RegisterSignal(human_holder, COMSIG_SPECIES_GAIN, PROC_REF(on_species_gain)) - RegisterSignal(human_holder, COMSIG_MOB_WON_VIDEOGAME, PROC_REF(won_game)) - RegisterSignal(human_holder, COMSIG_MOB_LOST_VIDEOGAME, PROC_REF(lost_game)) - RegisterSignal(human_holder, COMSIG_MOB_PLAYED_VIDEOGAME, PROC_REF(gamed)) - -/datum/quirk/gamer/proc/on_species_gain(datum/source, datum/species/new_species, datum/species/old_species) - SIGNAL_HANDLER - new_species.liked_food = JUNKFOOD + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(tongue) + // Gamer diet + tongue.liked_foodtypes = JUNKFOOD + RegisterSignal(quirk_holder, COMSIG_MOB_WON_VIDEOGAME, PROC_REF(won_game)) + RegisterSignal(quirk_holder, COMSIG_MOB_LOST_VIDEOGAME, PROC_REF(lost_game)) + RegisterSignal(quirk_holder, COMSIG_MOB_PLAYED_VIDEOGAME, PROC_REF(gamed)) /datum/quirk/gamer/remove() - var/mob/living/carbon/human/human_holder = quirk_holder - var/datum/species/species = human_holder.dna.species - species.liked_food = initial(species.liked_food) - UnregisterSignal(human_holder, COMSIG_SPECIES_GAIN) - UnregisterSignal(human_holder, COMSIG_MOB_WON_VIDEOGAME) - UnregisterSignal(human_holder, COMSIG_MOB_LOST_VIDEOGAME) - UnregisterSignal(human_holder, COMSIG_MOB_PLAYED_VIDEOGAME) + var/obj/item/organ/internal/tongue/tongue = quirk_holder.get_organ_slot(ORGAN_SLOT_TONGUE) + if(tongue) + tongue.liked_foodtypes = initial(tongue.liked_foodtypes) + UnregisterSignal(quirk_holder, COMSIG_MOB_WON_VIDEOGAME) + UnregisterSignal(quirk_holder, COMSIG_MOB_LOST_VIDEOGAME) + UnregisterSignal(quirk_holder, COMSIG_MOB_PLAYED_VIDEOGAME) + /datum/quirk/gamer/add_unique(client/client_source) // The gamer starts off quelled diff --git a/code/datums/records/manifest.dm b/code/datums/records/manifest.dm index 3bd91072ab8f..786d94ef0f9c 100644 --- a/code/datums/records/manifest.dm +++ b/code/datums/records/manifest.dm @@ -113,7 +113,7 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new) var/datum/record/locked/lockfile = new( age = person.age, - blood_type = person.dna.blood_type, + blood_type = "[person.get_blood_type() || "None"]", character_appearance = character_appearance, dna_string = person.dna.unique_enzymes, fingerprint = md5(person.dna.unique_identity), @@ -130,7 +130,7 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new) var/datum/record/crew/crewfile = new ( age = person.age, - blood_type = person.dna.blood_type, + blood_type = "[person.get_blood_type() || "None"]", character_appearance = character_appearance, dna_string = person.dna.unique_enzymes, fingerprint = md5(person.dna.unique_identity), diff --git a/code/datums/status_effects/_status_effect_helpers.dm b/code/datums/status_effects/_status_effect_helpers.dm index 0ee952200610..144a972da621 100644 --- a/code/datums/status_effects/_status_effect_helpers.dm +++ b/code/datums/status_effects/_status_effect_helpers.dm @@ -56,7 +56,7 @@ . = FALSE for(var/datum/status_effect/existing_effect as anything in status_effects) - if(existing_effect.id == initial(removed_effect.id) && existing_effect.before_remove(arguments)) + if(existing_effect.id == initial(removed_effect.id) && existing_effect.before_remove(arglist(arguments))) qdel(existing_effect) . = TRUE diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm index 2e9714fb2959..ee06eee43f13 100644 --- a/code/datums/status_effects/buffs.dm +++ b/code/datums/status_effects/buffs.dm @@ -335,11 +335,7 @@ ADD_TRAIT(owner, TRAIT_IGNOREDAMAGESLOWDOWN, STATUS_EFFECT_TRAIT) owner.adjustBruteLoss(-25) owner.adjustFireLoss(-25) - owner.fully_heal(HEAL_CC_STATUS) - owner.bodytemperature = owner.get_body_temp_normal() - if(ishuman(owner)) - var/mob/living/carbon/human/humi = owner - humi.set_coretemperature(humi.get_body_temp_normal()) + owner.fully_heal(HEAL_CC_STATUS|HEAL_TEMP) return TRUE /datum/status_effect/regenerative_core/on_remove() @@ -480,7 +476,7 @@ owner.adjustFireLoss(-2 * seconds_per_tick, updating_health = FALSE) owner.adjustOxyLoss(-4 * seconds_per_tick, updating_health = FALSE) owner.stamina.adjust(4 * seconds_per_tick) - owner.adjust_bodytemperature(BODYTEMP_NORMAL, 0, BODYTEMP_NORMAL) //Won't save you from the void of space, but it will stop you from freezing or suffocating in low pressure + owner.adjust_bodytemperature(INFINITY, max_temp = owner.standard_body_temperature) //Won't save you from the void of space, but it will stop you from freezing or suffocating in low pressure /atom/movable/screen/alert/status_effect/nest_sustenance diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index 4fe68d281eae..aa0be7f3120e 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -138,14 +138,19 @@ ADD_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id)) RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_SLEEPIMMUNE), PROC_REF(on_owner_insomniac)) RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_SLEEPIMMUNE), PROC_REF(on_owner_sleepy)) + RegisterSignal(owner, COMSIG_LIVING_DEATH, PROC_REF(on_owner_death)) /datum/status_effect/incapacitating/sleeping/on_remove() - UnregisterSignal(owner, list(SIGNAL_ADDTRAIT(TRAIT_SLEEPIMMUNE), SIGNAL_REMOVETRAIT(TRAIT_SLEEPIMMUNE))) + UnregisterSignal(owner, list(SIGNAL_ADDTRAIT(TRAIT_SLEEPIMMUNE), SIGNAL_REMOVETRAIT(TRAIT_SLEEPIMMUNE), COMSIG_LIVING_DEATH)) if(!HAS_TRAIT(owner, TRAIT_SLEEPIMMUNE)) REMOVE_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id)) tick_interval = initial(tick_interval) return ..() +/datum/status_effect/incapacitating/sleeping/proc/on_owner_death(mob/living/source) + SIGNAL_HANDLER + qdel(src) + ///If the mob is sleeping and gain the TRAIT_SLEEPIMMUNE we remove the TRAIT_KNOCKEDOUT and stop the tick() from happening /datum/status_effect/incapacitating/sleeping/proc/on_owner_insomniac(mob/living/source) SIGNAL_HANDLER @@ -365,11 +370,10 @@ /datum/status_effect/stacking/saw_bleed/threshold_cross_effect() owner.adjustBruteLoss(bleed_damage) - var/turf/T = get_turf(owner) - new /obj/effect/temp_visual/bleed/explode(T) + new /obj/effect/temp_visual/bleed/explode(owner.loc) for(var/d in GLOB.alldirs) - new /obj/effect/temp_visual/dir_setting/bloodsplatter(T, d) - playsound(T, SFX_DESECRATION, 100, TRUE, -1) + owner.do_splatter_effect(d) + playsound(owner, SFX_DESECRATION, 100, TRUE, -1) /datum/status_effect/stacking/saw_bleed/bloodletting id = "bloodletting" diff --git a/code/datums/status_effects/debuffs/fire_stacks.dm b/code/datums/status_effects/debuffs/fire_stacks.dm index f2c014578adc..d00d0c348439 100644 --- a/code/datums/status_effects/debuffs/fire_stacks.dm +++ b/code/datums/status_effects/debuffs/fire_stacks.dm @@ -189,36 +189,6 @@ var/turf/location = get_turf(owner) location.hotspot_expose(700, 25 * seconds_per_tick, TRUE) -/** - * Used to deal damage to humans and count their protection. - * - * Arguments: - * - seconds_per_tick - * - times_fired - * - no_protection: When set to TRUE, fire will ignore any possible fire protection - * - */ - -/datum/status_effect/fire_handler/fire_stacks/proc/harm_human(seconds_per_tick, times_fired, no_protection = FALSE) - var/mob/living/carbon/human/victim = owner - var/thermal_protection = victim.get_thermal_protection() - - if(!no_protection) - if(thermal_protection >= FIRE_IMMUNITY_MAX_TEMP_PROTECT) - return - if(thermal_protection >= FIRE_SUIT_MAX_TEMP_PROTECT) - victim.adjust_bodytemperature(5.5 * seconds_per_tick) - return - - var/amount_to_heat = (BODYTEMP_HEATING_MAX + (stacks * 12)) * 0.5 * seconds_per_tick - if(owner.bodytemperature > BODYTEMP_FIRE_TEMP_SOFTCAP) - // Apply dimishing returns upon temp beyond the soft cap - amount_to_heat = amount_to_heat ** (BODYTEMP_FIRE_TEMP_SOFTCAP / owner.bodytemperature) - - victim.adjust_bodytemperature(amount_to_heat) - victim.add_mood_event("on_fire", /datum/mood_event/on_fire) - victim.add_mob_memory(/datum/memory/was_burning) - /** * Handles mob ignition, should be the only way to set on_fire to TRUE * diff --git a/code/datums/status_effects/debuffs/strandling.dm b/code/datums/status_effects/debuffs/strandling.dm index 5465171df820..5fbf37e6f6f2 100644 --- a/code/datums/status_effects/debuffs/strandling.dm +++ b/code/datums/status_effects/debuffs/strandling.dm @@ -10,25 +10,22 @@ var/time_to_remove = 3.5 SECONDS /datum/status_effect/strandling/on_apply() - RegisterSignal(owner, COMSIG_CARBON_PRE_BREATHE, PROC_REF(on_breathe)) + RegisterSignal(owner, COMSIG_CARBON_ATTEMPT_BREATHE, PROC_REF(on_breathe)) RegisterSignal(owner, COMSIG_ATOM_TOOL_ACT(TOOL_WIRECUTTER), PROC_REF(on_cut)) RegisterSignal(owner, COMSIG_CARBON_PRE_MISC_HELP, PROC_REF(on_self_check)) return TRUE /datum/status_effect/strandling/on_remove() - UnregisterSignal(owner, list(COMSIG_CARBON_PRE_BREATHE, COMSIG_ATOM_TOOL_ACT(TOOL_WIRECUTTER), COMSIG_CARBON_PRE_MISC_HELP)) + UnregisterSignal(owner, list(COMSIG_CARBON_ATTEMPT_BREATHE, COMSIG_ATOM_TOOL_ACT(TOOL_WIRECUTTER), COMSIG_CARBON_PRE_MISC_HELP)) /datum/status_effect/strandling/get_examine_text() return span_warning("[owner.p_they(TRUE)] seem[owner.p_s()] to be being choked by some durathread strands. You may be able to cut them off.") -/// Signal proc for [COMSIG_CARBON_PRE_BREATHE], causes losebreath whenever we're trying to breathe +/// Signal proc for [COMSIG_CARBON_ATTEMPT_BREATHE], causes losebreath whenever we're trying to breathe /datum/status_effect/strandling/proc/on_breathe(mob/living/source) SIGNAL_HANDLER - if(source.get_organ_slot(ORGAN_SLOT_BREATHING_TUBE)) - return - - source.losebreath++ + return HAS_TRAIT(owner, TRAIT_ASSISTED_BREATHING) ? NONE : BREATHE_SKIP_BREATH /// Signal proc for [COMSIG_ATOM_TOOL_ACT] with [TOOL_WIRECUTTER], allowing wirecutters to remove the effect (from others / themself) /datum/status_effect/strandling/proc/on_cut(mob/living/source, mob/user, obj/item/tool) diff --git a/code/datums/status_effects/gas.dm b/code/datums/status_effects/gas.dm index cfa282732058..bf0822d879f8 100644 --- a/code/datums/status_effects/gas.dm +++ b/code/datums/status_effects/gas.dm @@ -24,7 +24,7 @@ /datum/status_effect/freon/tick() - if(can_melt && owner.bodytemperature >= owner.get_body_temp_normal()) + if(can_melt && owner.bodytemperature >= owner.standard_body_temperature - 2 KELVIN) qdel(src) /datum/status_effect/freon/proc/owner_resist() @@ -43,7 +43,7 @@ if(!owner.stat) to_chat(owner, span_notice("The cube melts!")) owner.cut_overlay(cube) - owner.adjust_bodytemperature(100) + owner.adjust_bodytemperature(50 KELVIN, max_temp = owner.standard_body_temperature - 5 KELVIN) UnregisterSignal(owner, COMSIG_LIVING_RESIST) REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id)) return ..() diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index b9428e2d250b..c3d684560c26 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -163,7 +163,7 @@ /// The type of alert given to people when offered, in case you need to override some behavior (like for high-fives) var/give_alert_type = /atom/movable/screen/alert/give -/datum/status_effect/offering/on_creation(mob/living/new_owner, obj/item/offer, give_alert_override, mob/living/carbon/offered) +/datum/status_effect/offering/on_creation(mob/living/new_owner, obj/item/offer, give_alert_override, mob/living/offered) . = ..() if(!.) return @@ -171,11 +171,11 @@ if(give_alert_override) give_alert_type = give_alert_override - if(offered && is_taker_elligible(offered)) + if(offered && is_taker_elligible(offered, offer)) register_candidate(offered) else - for(var/mob/living/carbon/possible_taker in orange(1, owner)) - if(!is_taker_elligible(possible_taker)) + for(var/mob/living/possible_taker in orange(1, owner)) + if(!is_taker_elligible(possible_taker, offer)) continue register_candidate(possible_taker) @@ -202,6 +202,7 @@ LAZYADD(possible_takers, possible_candidate) RegisterSignal(possible_candidate, COMSIG_MOVABLE_MOVED, PROC_REF(check_taker_in_range)) G.setup(possible_candidate, src) + SEND_SIGNAL(possible_candidate, COMSIG_LIVING_GIVE_ITEM_CHECK, G, offered_item) /// Remove the alert and signals for the specified carbon mob. Automatically removes the status effect when we lost the last taker /datum/status_effect/offering/proc/remove_candidate(mob/living/carbon/removed_candidate) @@ -239,8 +240,8 @@ * * Returns `TRUE` if the taker is valid as a target for the offering. */ -/datum/status_effect/offering/proc/is_taker_elligible(mob/living/carbon/taker) - return owner.CanReach(taker) && !IS_DEAD_OR_INCAP(taker) && additional_taker_check(taker) +/datum/status_effect/offering/proc/is_taker_elligible(mob/living/carbon/taker, obj/item/offer) + return (owner.CanReach(taker) && !IS_DEAD_OR_INCAP(taker) && additional_taker_check(taker)) || SEND_SIGNAL(taker, COMSIG_LIVING_ITEM_OFFERED_PRECHECK, offer) /** * Additional checks added to `CanReach()` and `IS_DEAD_OR_INCAP()` in `is_taker_elligible()`. diff --git a/code/datums/status_effects/stacking_effect.dm b/code/datums/status_effects/stacking_effect.dm index 9896ef5ec707..9a682000eb78 100644 --- a/code/datums/status_effects/stacking_effect.dm +++ b/code/datums/status_effects/stacking_effect.dm @@ -86,8 +86,11 @@ /datum/status_effect/stacking/proc/add_stacks(stacks_added) if(stacks_added > 0 && !can_gain_stacks()) return FALSE - owner.cut_overlay(status_overlay) - owner.underlays -= status_underlay + if(status_overlay) + owner.cut_overlay(status_overlay) + if(status_underlay) + owner.underlays -= status_underlay + stacks += stacks_added if(stacks > 0) if(stacks >= stack_threshold && !threshold_crossed) //threshold_crossed check prevents threshold effect from occuring if changing from above threshold to still above threshold @@ -98,13 +101,15 @@ else if(stacks < stack_threshold && threshold_crossed) threshold_crossed = FALSE //resets threshold effect if we fall below threshold so threshold effect can trigger again on_threshold_drop() - if(stacks_added > 0) - tick_interval += delay_before_decay //refreshes time until decay + if((stacks_added > 0) && delay_before_decay) + tick_interval = world.time + delay_before_decay //refreshes time until decay stacks = min(stacks, max_stacks) - status_overlay.icon_state = "[overlay_state][stacks]" - status_underlay.icon_state = "[underlay_state][stacks]" - owner.add_overlay(status_overlay) - owner.underlays += status_underlay + if(status_overlay) + status_overlay.icon_state = "[overlay_state][stacks]" + owner.add_overlay(status_overlay) + if(status_underlay) + status_underlay.icon_state = "[underlay_state][stacks]" + owner.underlays += status_underlay else fadeout_effect() qdel(src) //deletes status if stacks fall under one @@ -117,23 +122,34 @@ /datum/status_effect/stacking/on_apply() if(!can_have_status()) return FALSE - status_overlay = mutable_appearance(overlay_file, "[overlay_state][stacks]") - status_underlay = mutable_appearance(underlay_file, "[underlay_state][stacks]") - var/icon/I = icon(owner.icon, owner.icon_state, owner.dir) - var/icon_height = I.Height() - status_overlay.pixel_x = -owner.pixel_x - status_overlay.pixel_y = FLOOR(icon_height * 0.25, 1) - status_overlay.transform = matrix() * (icon_height/world.icon_size) //scale the status's overlay size based on the target's icon size - status_underlay.pixel_x = -owner.pixel_x - status_underlay.transform = matrix() * (icon_height/world.icon_size) * 3 - status_underlay.alpha = 40 - owner.add_overlay(status_overlay) - owner.underlays += status_underlay - return ..() - -/datum/status_effect/stacking/Destroy() - if(owner) + if(overlay_file || underlay_file) + if(overlay_file) + status_overlay = mutable_appearance(overlay_file, "[overlay_state][stacks]") + if(underlay_file) + status_underlay = mutable_appearance(underlay_file, "[underlay_state][stacks]") + + var/icon/I = icon(owner.icon, owner.icon_state, owner.dir) + var/icon_height = I.Height() + + if(status_overlay) + status_overlay.pixel_x = -owner.pixel_x + status_overlay.pixel_y = FLOOR(icon_height * 0.25, 1) + status_overlay.transform = matrix() * (icon_height/world.icon_size) //scale the status's overlay size based on the target's icon size + owner.add_overlay(status_overlay) + + if(status_underlay) + status_underlay.pixel_x = -owner.pixel_x + status_underlay.transform = matrix() * (icon_height/world.icon_size) * 3 + status_underlay.alpha = 40 + owner.underlays += status_underlay + + return TRUE + +/datum/status_effect/stacking/on_remove() + if(QDELETED(owner)) + return + if(status_overlay) owner.cut_overlay(status_overlay) + QDEL_NULL(status_overlay) + if(status_underlay) owner.underlays -= status_underlay - QDEL_NULL(status_overlay) - return ..() diff --git a/code/datums/status_effects/wound_effects.dm b/code/datums/status_effects/wound_effects.dm index 8965d22ad197..baec06c7c048 100644 --- a/code/datums/status_effects/wound_effects.dm +++ b/code/datums/status_effects/wound_effects.dm @@ -1,29 +1,102 @@ // The shattered remnants of your broken limbs fill you with determination! -/atom/movable/screen/alert/status_effect/determined +/atom/movable/screen/alert/determined name = "Determined" desc = "The serious wounds you've sustained have put your body into fight-or-flight mode! Now's the time to look for an exit!" icon_state = "wounded" +/// While someone has determination in their system, their bleed rate is slightly reduced +#define WOUND_DETERMINATION_BLEED_MOD 0.85 + /datum/status_effect/determined id = "determined" - alert_type = /atom/movable/screen/alert/status_effect/determined remove_on_fullheal = TRUE + tick_interval = 2 SECONDS + alert_type = null + status_type = STATUS_EFFECT_REFRESH + /// World.time when the status effect was applied + var/start_time = 0 + +/datum/status_effect/determined/on_creation(mob/living/new_owner, set_duration = 5 SECONDS) + src.duration = min(WOUND_DETERMINATION_MAX, set_duration) + start_time = world.time + return ..() + +/datum/status_effect/determined/refresh(mob/living/new_owner, set_duration = 5 SECONDS) + duration = min(duration + set_duration, start_time + WOUND_DETERMINATION_MAX) + if(set_duration >= WOUND_DETERMINATION_SEVERE) + owner.throw_alert(id, /atom/movable/screen/alert/determined) /datum/status_effect/determined/on_apply() - . = ..() - owner.visible_message(span_danger("[owner]'s body tenses up noticeably, gritting against [owner.p_their()] pain!"), span_notice("Your senses sharpen as your body tenses up from the wounds you've sustained!"), \ - vision_distance=COMBAT_MESSAGE_RANGE) + if(owner.stat == DEAD) + return FALSE + owner.visible_message( + span_danger("[owner]'s body tenses up noticeably, gritting against [owner.p_their()] pain!"), + span_boldnotice("Your senses sharpen as your body tenses up from the wounds you've sustained!"), + vision_distance = COMBAT_MESSAGE_RANGE, + ) if(ishuman(owner)) var/mob/living/carbon/human/human_owner = owner human_owner.physiology.bleed_mod *= WOUND_DETERMINATION_BLEED_MOD + human_owner.set_pain_mod(id, 0.625) // 0.625 * 0.8 = 0.5 = numbness + ADD_TRAIT(owner, TRAIT_NO_PAIN_EFFECTS, TRAIT_STATUS_EFFECT(id)) + ADD_TRAIT(owner, TRAIT_ABATES_SHOCK, TRAIT_STATUS_EFFECT(id)) + if(duration >= WOUND_DETERMINATION_SEVERE) + owner.throw_alert(id, /atom/movable/screen/alert/determined) + return TRUE /datum/status_effect/determined/on_remove() - owner.visible_message(span_danger("[owner]'s body slackens noticeably!"), span_warning("Your adrenaline rush dies off, and the pain from your wounds come aching back in..."), vision_distance=COMBAT_MESSAGE_RANGE) + if(QDELING(owner)) + return + if(ishuman(owner)) var/mob/living/carbon/human/human_owner = owner human_owner.physiology.bleed_mod /= WOUND_DETERMINATION_BLEED_MOD - return ..() + human_owner.unset_pain_mod(id) + REMOVE_TRAIT(owner, TRAIT_NO_PAIN_EFFECTS, TRAIT_STATUS_EFFECT(id)) + REMOVE_TRAIT(owner, TRAIT_ABATES_SHOCK, TRAIT_STATUS_EFFECT(id)) + owner.clear_alert(id) + owner.apply_status_effect(/datum/status_effect/determination_crash) + +/datum/status_effect/determined/tick(seconds_between_ticks) + if(HAS_TRAIT(owner, TRAIT_STASIS) || owner.stat == DEAD || !iscarbon(owner)) + return + + var/mob/living/carbon/carbowner = owner + for(var/datum/wound/wound as anything in carbowner.all_wounds) + wound.limb?.heal_damage(0.2 * seconds_between_ticks, 0.2 * seconds_between_ticks) + +#undef WOUND_DETERMINATION_BLEED_MOD + +/datum/status_effect/determination_crash + id = "determination_crash" + alert_type = null + remove_on_fullheal = TRUE + tick_interval = -1 + duration = 10 SECONDS + +/datum/status_effect/determination_crash/on_apply() + if(owner.stat == DEAD) + return FALSE + + owner.visible_message( + span_danger("[owner]'s body slackens noticeably!"), + span_boldwarning("Your adrenaline rush dies off, and the pain from your wounds come aching back in..."), + vision_distance = COMBAT_MESSAGE_RANGE, + ) + owner.add_movespeed_modifier(/datum/movespeed_modifier/determination_crash) + owner.add_actionspeed_modifier(/datum/actionspeed_modifier/determination_crash) + return TRUE + +/datum/status_effect/determination_crash/on_remove() + owner.remove_movespeed_modifier(/datum/movespeed_modifier/determination_crash) + owner.remove_actionspeed_modifier(/datum/actionspeed_modifier/determination_crash) + +/datum/movespeed_modifier/determination_crash + multiplicative_slowdown = 0.1 + +/datum/actionspeed_modifier/determination_crash + multiplicative_slowdown = 0.1 /datum/status_effect/limp id = "limp" @@ -71,8 +144,11 @@ if(!owner.client || owner.body_position == LYING_DOWN || !owner.has_gravity() || (owner.movement_type & FLYING) || forced || owner.buckled) return + if(SEND_SIGNAL(owner, COMSIG_CARBON_LIMPING, (next_leg || right || left)) & COMPONENT_CANCEL_LIMP) + return + // less limping while we have determination still - var/determined_mod = owner.has_status_effect(/datum/status_effect/determined) ? 0.5 : 1 + var/determined_mod = owner.can_feel_pain(TRUE) ? 1 : 0.5 if(next_leg == left) if(prob(limp_chance_left * determined_mod)) @@ -187,6 +263,8 @@ /datum/status_effect/wound/blunt/bone // blunt +/datum/status_effect/wound/blunt/bone/rib_break + id = "rib_break" /datum/status_effect/wound/blunt/bone/moderate id = "disjoint" /datum/status_effect/wound/blunt/bone/severe diff --git a/code/datums/voice_of_god_command.dm b/code/datums/voice_of_god_command.dm index 69f077ddd82b..2018f290f97f 100644 --- a/code/datums/voice_of_god_command.dm +++ b/code/datums/voice_of_god_command.dm @@ -225,7 +225,7 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands()) /datum/voice_of_god_command/hot/execute(list/listeners, mob/living/user, power_multiplier = 1, message) for(var/mob/living/target as anything in listeners) - target.adjust_bodytemperature(50 * power_multiplier) + target.adjust_bodytemperature(5 KELVIN * power_multiplier) /// This command cools the listeners down like freezing water. /datum/voice_of_god_command/cold @@ -234,7 +234,7 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands()) /datum/voice_of_god_command/cold/execute(list/listeners, mob/living/user, power_multiplier = 1, message) for(var/mob/living/target as anything in listeners) - target.adjust_bodytemperature(-50 * power_multiplier) + target.adjust_bodytemperature(-7.5 KELVIN * power_multiplier) /// This command throws the listeners away from the user. /datum/voice_of_god_command/repulse diff --git a/code/datums/weather/weather_types/ash_storm.dm b/code/datums/weather/weather_types/ash_storm.dm index 1a5bd69d2a04..e10e39505bc0 100644 --- a/code/datums/weather/weather_types/ash_storm.dm +++ b/code/datums/weather/weather_types/ash_storm.dm @@ -66,7 +66,7 @@ if(!. || !ishuman(mob_to_check)) return var/mob/living/carbon/human/human_to_check = mob_to_check - if(human_to_check.get_thermal_protection() >= FIRE_IMMUNITY_MAX_TEMP_PROTECT) + if(human_to_check.get_insulation(FIRE_IMMUNITY_MAX_TEMP_PROTECT) >= 0.9) //potentially broken return FALSE /datum/weather/ash_storm/weather_act(mob/living/victim) diff --git a/code/datums/weather/weather_types/void_storm.dm b/code/datums/weather/weather_types/void_storm.dm index becfa9859a81..13dbd09cb523 100644 --- a/code/datums/weather/weather_types/void_storm.dm +++ b/code/datums/weather/weather_types/void_storm.dm @@ -36,7 +36,7 @@ victim.adjustFireLoss(1) victim.adjustOxyLoss(rand(1, 3)) victim.adjust_eye_blur(rand(0 SECONDS, 2 SECONDS)) - victim.adjust_bodytemperature(-30 * TEMPERATURE_DAMAGE_COEFFICIENT) + victim.adjust_bodytemperature(-4 KELVIN) // Goes through former_impacted_areas and sets the overlay of each back to the telegraph overlay, to indicate the ascended heretic is no longer in that area. /datum/weather/void_storm/update_areas() diff --git a/code/datums/wounds/_wound_static_data.dm b/code/datums/wounds/_wound_static_data.dm index f996bb258c79..15aa2dd7afa7 100644 --- a/code/datums/wounds/_wound_static_data.dm +++ b/code/datums/wounds/_wound_static_data.dm @@ -86,7 +86,14 @@ * if we have a biotype mismatch, if the limb isnt in a viable zone, or if theres any duplicate wound types. * TRUE otherwise. */ -/datum/wound_pregen_data/proc/can_be_applied_to(obj/item/bodypart/limb, list/suggested_wounding_types = required_wounding_types, datum/wound/old_wound, random_roll = FALSE, duplicates_allowed = src.duplicates_allowed, care_about_existing_wounds = TRUE) +/datum/wound_pregen_data/proc/can_be_applied_to( + obj/item/bodypart/limb, + list/suggested_wounding_types = required_wounding_types, + datum/wound/old_wound, + random_roll = FALSE, + duplicates_allowed = src.duplicates_allowed, + care_about_existing_wounds = TRUE, +) SHOULD_BE_PURE(TRUE) if (!istype(limb) || !limb.owner) diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm index 6a52753eef99..53f50fddb0e4 100644 --- a/code/datums/wounds/_wounds.dm +++ b/code/datums/wounds/_wounds.dm @@ -19,10 +19,14 @@ /datum/wound /// What it's named var/name = "Wound" + /// Optional, what is the wound named when someone is checking themselves (IE, no scanner - just with their eyes and hands) + var/undiagnosed_name /// The description shown on the scanners var/desc = "" /// The basic treatment suggested by health analyzers var/treat_text = "" + /// Even more basic treatment + var/treat_text_short = "" /// What the limb looks like on a cursory examine var/examine_desc = "is badly hurt" @@ -112,6 +116,11 @@ /// The actionspeed modifier we will use in case we are on the arms and have a interaction penalty. Qdelled on destroy. var/datum/actionspeed_modifier/wound_interaction_inefficiency/actionspeed_mod + /// If we did the gel + surgical tape healing method for fractures, how many ticks does it take to heal by default + var/regen_ticks_needed + /// Our current counter for gel + surgical tape regeneration + var/regen_ticks_current + /datum/wound/New() . = ..() @@ -204,7 +213,7 @@ if(severity == WOUND_SEVERITY_TRIVIAL) return - if(!silent && !demoted) + if(!silent && !demoted && occur_text) var/msg = span_danger("[victim]'s [limb.plaintext_zone] [occur_text]!") var/vis_dist = COMBAT_MESSAGE_RANGE @@ -440,13 +449,13 @@ /datum/wound/proc/second_wind() switch(severity) if(WOUND_SEVERITY_MODERATE) - victim.reagents.add_reagent(/datum/reagent/determination, WOUND_DETERMINATION_MODERATE) + victim.apply_status_effect(/datum/status_effect/determined, WOUND_DETERMINATION_MODERATE) if(WOUND_SEVERITY_SEVERE) - victim.reagents.add_reagent(/datum/reagent/determination, WOUND_DETERMINATION_SEVERE) + victim.apply_status_effect(/datum/status_effect/determined, WOUND_DETERMINATION_SEVERE) if(WOUND_SEVERITY_CRITICAL) - victim.reagents.add_reagent(/datum/reagent/determination, WOUND_DETERMINATION_CRITICAL) + victim.apply_status_effect(/datum/status_effect/determined, WOUND_DETERMINATION_CRITICAL) if(WOUND_SEVERITY_LOSS) - victim.reagents.add_reagent(/datum/reagent/determination, WOUND_DETERMINATION_LOSS) + victim.apply_status_effect(/datum/status_effect/determined, WOUND_DETERMINATION_LOSS) /** * try_treating() is an intercept run from [/mob/living/carbon/proc/attackby] right after surgeries but before anything else. Return TRUE here if the item is something that is relevant to treatment to take over the interaction. @@ -515,7 +524,13 @@ /// If var/processing is TRUE, this is run on each life tick /datum/wound/proc/handle_process(seconds_per_tick, times_fired) - return + SHOULD_CALL_PARENT(TRUE) + if(regen_ticks_current > regen_ticks_needed) + if(!victim || !limb) + qdel(src) + return + to_chat(victim, span_green("Your [limb.plaintext_zone] has recovered from its [undiagnosed_name || name]!")) + remove_wound() /// For use in do_after callback checks /datum/wound/proc/still_exists() @@ -592,7 +607,7 @@ */ /datum/wound/proc/get_examine_description(mob/user) . = get_wound_description(user) - if(HAS_TRAIT(src, TRAIT_WOUND_SCANNED)) + if(. && HAS_TRAIT(src, TRAIT_WOUND_SCANNED)) . += span_notice("\nThere is a holo-image next to the wound that seems to contain indications for treatment.") return . @@ -601,15 +616,29 @@ var/desc if ((wound_flags & ACCEPTS_GAUZE) && limb.current_gauze) - var/sling_condition = get_gauze_condition() - desc = "[victim.p_Their()] [limb.plaintext_zone] is [sling_condition] fastened in a sling of [limb.current_gauze.name]" - else + desc = "[victim.p_Their()] [limb.plaintext_zone] is [get_gauze_condition()] fastened in a sling of [limb.current_gauze.name]" + else if(examine_desc) desc = "[victim.p_Their()] [limb.plaintext_zone] [examine_desc]" + if(!desc) + return + desc = modify_desc_before_span(desc, user) return get_desc_intensity(desc) +/datum/wound/proc/get_self_check_description(mob/user) + // future todo : medical doctors can self-diagnose / don't use [undiagnosed_name] + switch(severity) + if(WOUND_SEVERITY_TRIVIAL) + return span_danger("It's suffering [a_or_from] [lowertext(undiagnosed_name || name)].") + if(WOUND_SEVERITY_MODERATE) + return span_warning("It's suffering [a_or_from] [lowertext(undiagnosed_name || name)].") + if(WOUND_SEVERITY_SEVERE) + return span_boldwarning("It's suffering [a_or_from] [lowertext(undiagnosed_name || name)]!") + if(WOUND_SEVERITY_CRITICAL) + return span_boldwarning("It's suffering [a_or_from] [lowertext(undiagnosed_name || name)]!!") + /// A hook proc used to modify desc before it is spanned via [get_desc_intensity]. Useful for inserting spans yourself. /datum/wound/proc/modify_desc_before_span(desc, mob/user) return desc @@ -637,10 +666,17 @@ return "[desc]." /datum/wound/proc/get_scanner_description(mob/user) - return "Type: [name]\nSeverity: [severity_text(simple = FALSE)]\nDescription: [desc]\nRecommended Treatment: [treat_text]" + return "Type: [name]\n\ + Severity: [severity_text(simple = FALSE)]\n\ + Description: [desc]\n\ + Recommended Treatment: [treat_text]" /datum/wound/proc/get_simple_scanner_description(mob/user) - return "[name] detected!\nRisk: [severity_text(simple = TRUE)]\nDescription: [simple_desc ? simple_desc : desc]\nTreatment Guide: [simple_treat_text]\nHomemade Remedies: [homemade_treat_text]" + return "[name] detected!\n\ + Risk: [severity_text(simple = TRUE)]\n\ + Description: [simple_desc ? simple_desc : desc]\n\ + Treatment Guide: [simple_treat_text]\n\ + Homemade Remedies: [homemade_treat_text]" /datum/wound/proc/severity_text(simple = FALSE) switch(severity) @@ -653,11 +689,6 @@ if(WOUND_SEVERITY_CRITICAL) return "Critical" + (simple ? "!!!" : "") -/// Returns TRUE if our limb is the head or chest, FALSE otherwise. -/// Essential in the sense of "we cannot live without it". -/datum/wound/proc/limb_essential() - return (limb.body_zone == BODY_ZONE_HEAD || limb.body_zone == BODY_ZONE_CHEST) - /// Getter proc for our scar_keyword, in case we might have some custom scar gen logic. /datum/wound/proc/get_scar_keyword(obj/item/bodypart/scarred_limb, add_to_scars) return scar_keyword diff --git a/code/datums/wounds/blunt.dm b/code/datums/wounds/blunt.dm index 219b7dd8805c..e3a9538a8c57 100644 --- a/code/datums/wounds/blunt.dm +++ b/code/datums/wounds/blunt.dm @@ -1,3 +1,11 @@ /datum/wound/blunt name = "Blunt Wound" + undiagnosed_name = "Painful Bruising" sound_effect = 'sound/effects/wounds/crack1.ogg' + +/datum/wound/blunt/wound_injury(datum/wound/old_wound, attack_direction) + if(!old_wound && limb.current_gauze && (wound_flags & ACCEPTS_GAUZE)) + // oops your bone injury knocked off your gauze, gotta re-apply it + limb.remove_gauze(limb.drop_location()) + + return ..() diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index 1b63e5a4a2a4..cc53993907c2 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -22,10 +22,6 @@ var/gelled /// Have we been taped? var/taped - /// If we did the gel + surgical tape healing method for fractures, how many ticks does it take to heal by default - var/regen_ticks_needed - /// Our current counter for gel + surgical tape regeneration - var/regen_ticks_current /// If we suffer severe head booboos, we can get brain traumas tied to them var/datum/brain_trauma/active_trauma /// What brain trauma group, if any, we can draw from for head wounds @@ -36,6 +32,8 @@ var/trauma_cycle_cooldown /// If this is a chest wound and this is set, we have this chance to cough up blood when hit in the chest var/internal_bleeding_chance = 0 + /// Counts which tick we're on for footsteps + var/footstep_counter = 0 /* Overwriting of base procs @@ -53,7 +51,12 @@ I = victim.get_inactive_held_item() if(I && victim.dropItemToGround(I)) - victim.visible_message(span_danger("[victim] drops [I] in shock!"), span_warning("The force on your [limb.plaintext_zone] causes you to drop [I]!"), vision_distance=COMBAT_MESSAGE_RANGE) + victim.visible_message( + span_danger("[victim] drops [I] in shock!"), + span_boldwarning("The force on your [limb.plaintext_zone] causes you to drop [I]!"), + vision_distance = COMBAT_MESSAGE_RANGE, + + ) update_inefficiencies() return ..() @@ -62,8 +65,14 @@ if (victim) UnregisterSignal(victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK) + UnregisterSignal(victim, COMSIG_MOB_ITEM_ATTACK) + UnregisterSignal(victim, COMSIG_CARBON_STEP) + UnregisterSignal(victim, COMSIG_CARBON_ATTEMPT_BREATHE) if (new_victim) RegisterSignal(new_victim, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, PROC_REF(attack_with_hurt_hand)) + RegisterSignal(new_victim, COMSIG_MOB_ITEM_ATTACK, PROC_REF(weapon_attack_with_hurt_hand)) + RegisterSignal(new_victim, COMSIG_CARBON_STEP, PROC_REF(carbon_step)) + RegisterSignal(new_victim, COMSIG_CARBON_ATTEMPT_BREATHE, PROC_REF(breath)) return ..() @@ -103,62 +112,134 @@ if(prob(33)) to_chat(victim, span_danger("You feel a sharp pain in your body as your bones are reforming!")) - if(regen_ticks_current > regen_ticks_needed) - if(!victim || !limb) - qdel(src) - return - to_chat(victim, span_green("Your [limb.plaintext_zone] has recovered from its [name]!")) - remove_wound() - /// If we're a human who's punching something with a broken arm, we might hurt ourselves doing so -/datum/wound/blunt/bone/proc/attack_with_hurt_hand(mob/M, atom/target, proximity) +/datum/wound/blunt/bone/proc/attack_with_hurt_hand(datum/source, atom/target, proximity) + if(!proximity || severity <= WOUND_SEVERITY_MODERATE) + return NONE + if(limb.body_zone != BODY_ZONE_CHEST && victim.get_active_hand() != limb) + return NONE + var/weapon = victim.get_active_held_item() + if(!weapon && ((victim.istate & ISTATE_HARM)|| !ismob(target))) + return NONE + + // With a severe or critical wound, you have a 15% or 30% chance to proc pain on hit + if(!prob((severity - 1) * 15)) + return NONE + + var/painless = !victim.can_feel_pain() || victim.has_status_effect(/datum/status_effect/determined) + // And you have a 70% or 50% chance to actually land the blow, respectively + if(prob(70 - 20 * (severity - 1))) + to_chat(victim, span_userdanger("The fracture in your [limb.plaintext_zone] [painless ? "jostles uncomfortably" : "shoots with pain"] as you strike [target]!")) + victim.apply_damage(8, BRUTE, limb) + return NONE + + victim.visible_message( + span_danger("[victim] weakly strikes [target] with [victim.p_their()] broken [limb.plaintext_zone], recoiling from pain!"), + span_userdanger("You [weapon ? "weakly" : "fail"] to strike [target] as the fracture in your [limb.plaintext_zone] [painless ? "jostles uncomfortably" : "lights up in unbearable pain"]!"), + vision_distance = COMBAT_MESSAGE_RANGE, + + ) + victim.Stun(0.5 SECONDS) + victim.apply_damage(10, BRUTE, limb) + victim.pain_emote(pick("wince", "grimace", "flinch")) + return COMPONENT_CANCEL_ATTACK_CHAIN + +/datum/wound/blunt/bone/proc/weapon_attack_with_hurt_hand(datum/source, mob/target, mob/user, params) SIGNAL_HANDLER - if(victim.get_active_hand() != limb || !(victim.istate & ISTATE_HARM) || !ismob(target) || severity <= WOUND_SEVERITY_MODERATE) + return attack_with_hurt_hand(source, target, TRUE) + +/datum/wound/blunt/bone/proc/carbon_step(datum/source) + SIGNAL_HANDLER + + if(limb.body_zone != BODY_ZONE_L_LEG && limb.body_zone != BODY_ZONE_R_LEG) + return + if(victim.body_position == LYING_DOWN || victim.buckled) // wheelchair = fine, being pulled = not fine + return + if(victim.has_status_effect(/datum/status_effect/determined)) return - // With a severe or critical wound, you have a 15% or 30% chance to proc pain on hit - if(prob((severity - 1) * 15)) - // And you have a 70% or 50% chance to actually land the blow, respectively - if(prob(70 - 20 * (severity - 1))) - to_chat(victim, span_userdanger("The fracture in your [limb.plaintext_zone] shoots with pain as you strike [target]!")) - limb.receive_damage(brute=rand(1,5)) - else - victim.visible_message(span_danger("[victim] weakly strikes [target] with [victim.p_their()] broken [limb.plaintext_zone], recoiling from pain!"), \ - span_userdanger("You fail to strike [target] as the fracture in your [limb.plaintext_zone] lights up in unbearable pain!"), vision_distance=COMBAT_MESSAGE_RANGE) - INVOKE_ASYNC(victim, TYPE_PROC_REF(/mob, emote), "scream") - victim.Stun(0.5 SECONDS) - limb.receive_damage(brute=rand(3,7)) - return COMPONENT_CANCEL_ATTACK_CHAIN + footstep_counter += 1 + if(footstep_counter >= 8) + footstep_counter = 1 + if((limb.current_gauze ? limb.current_gauze.splint_factor : 1) <= 0.75 || !victim.can_feel_pain()) + return + if(limb.body_zone == SELECT_LEFT_OR_RIGHT(footstep_counter, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)) + return + var/mod = 1 + switch(victim.m_intent) + if(MOVE_INTENT_RUN) + mod = 1.5 + if(MOVE_INTENT_WALK) + mod = 1 + if(MOVE_INTENT_SPRINT) + mod = 2 + if(!prob(severity * mod * 20)) + return + if(SEND_SIGNAL(victim, COMSIG_CARBON_PAINED_STEP, limb, footstep_counter) & STOP_PAIN) + return + + to_chat(victim, span_danger("Your [limb.plaintext_zone] [pick("aches", "pangs", "stings")] as you take a step!")) + victim.sharp_pain(limb.body_zone, severity * 6, BRUTE, 10 SECONDS) -/datum/wound/blunt/bone/receive_damage(wounding_type, wounding_dmg, wound_bonus) - if(!victim || wounding_dmg < WOUND_MINIMUM_DAMAGE) + +/datum/wound/blunt/bone/proc/breath(...) + SIGNAL_HANDLER + + if(limb.body_zone != BODY_ZONE_CHEST) + return NONE + if(!victim.can_feel_pain() || (limb.current_gauze && limb.current_gauze.splint_factor <= 0.75)) + return NONE + var/pain_prob = min(75, 20 * severity * (victim.body_position == LYING_DOWN ? 1.5 : 1)) + if(!prob(pain_prob)) + return NONE + to_chat(victim, span_danger("You wince as you take a deep breath, feeling the pain in your ribs!")) + var/breath_prob = min(50, 15 * severity * (victim.body_position == LYING_DOWN ? 1.2 : 1)) + if(prob(breath_prob)) + victim.pain_emote("gasp") + . = BREATHE_SKIP_BREATH + else + victim.pain_emote("wince") + . = NONE + victim.sharp_pain(BODY_ZONE_CHEST, rand(5, 10), BRUTE, 10 SECONDS) + return . + +/datum/wound/blunt/bone/receive_damage(wounding_type, wounding_dmg, wound_bonus, attack_direction, damage_source) + if(victim.stat == DEAD || wounding_dmg < WOUND_MINIMUM_DAMAGE || wounding_type == WOUND_BURN) return - if(ishuman(victim)) - var/mob/living/carbon/human/human_victim = victim - if(HAS_TRAIT(human_victim, TRAIT_NOBLOOD)) - return - - if(limb.body_zone == BODY_ZONE_CHEST && victim.blood_volume && prob(internal_bleeding_chance + wounding_dmg)) - var/blood_bled = rand(1, wounding_dmg * (severity == WOUND_SEVERITY_CRITICAL ? 2 : 1.5)) // 12 brute toolbox can cause up to 18/24 bleeding with a severe/critical chest wound - switch(blood_bled) - if(1 to 6) - victim.bleed(blood_bled, TRUE) - if(7 to 13) - victim.visible_message("A thin stream of blood drips from [victim]'s mouth from the blow to [victim.p_their()] chest.", span_danger("You cough up a bit of blood from the blow to your chest."), vision_distance=COMBAT_MESSAGE_RANGE) - victim.bleed(blood_bled, TRUE) - if(14 to 19) - victim.visible_message("Blood spews out of [victim]'s mouth from the blow to [victim.p_their()] chest!", span_danger("You spit out a string of blood from the blow to your chest!"), vision_distance=COMBAT_MESSAGE_RANGE) - new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir, COLOR_DARK_RED) - victim.bleed(blood_bled) - victim.blood_particles(amount = 1) - if(20 to INFINITY) - victim.visible_message(span_danger("Blood spurts out of [victim]'s mouth from the blow to [victim.p_their()] chest!"), span_danger("You choke up on a spray of blood from the blow to your chest!"), vision_distance=COMBAT_MESSAGE_RANGE) - victim.bleed(blood_bled) - new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir, COLOR_DARK_RED) - victim.add_splatter_floor(get_step(victim.loc, victim.dir)) - victim.blood_particles(amount = 3) + if(limb.body_zone != BODY_ZONE_CHEST || !limb.can_bleed() || !prob(internal_bleeding_chance)) + return + if(limb.current_gauze?.splint_factor) + wounding_dmg *= (1 - limb.current_gauze.splint_factor) + var/blood_bled = sqrt(wounding_dmg) * (severity * 0.75) * pick(0.75, 1, 1.25) // melbert todo : push upstream + switch(blood_bled) + if(7 to 13) + victim.visible_message( + span_smalldanger("A thin stream of blood drips from [victim]'s mouth from the blow to [victim.p_their()] chest."), + span_danger("You cough up a bit of blood from the blow to your chest."), + vision_distance = COMBAT_MESSAGE_RANGE, + + ) + if(14 to 19) + victim.visible_message( + span_smalldanger("Blood spews out of [victim]'s mouth from the blow to [victim.p_their()] chest!"), + span_danger("You spit out a string of blood from the blow to your chest!"), + vision_distance = COMBAT_MESSAGE_RANGE, + + ) + if(20 to INFINITY) + victim.visible_message( + span_danger("Blood spurts out of [victim]'s mouth from the blow to [victim.p_their()] chest!"), + span_bolddanger("You choke up on a spray of blood from the blow to your chest!"), + vision_distance = COMBAT_MESSAGE_RANGE, + + ) + victim.bleed(blood_bled, TRUE) + if(blood_bled >= 14) + victim.do_splatter_effect(attack_direction) + victim.add_splatter_floor(get_step(victim.loc, victim.dir)) + victim.blood_particles(amount = 1 * round(blood_bled / 14, 1)) /datum/wound/blunt/bone/modify_desc_before_span(desc) . = ..() @@ -181,11 +262,54 @@ return ..() +/datum/wound_pregen_data/bone/rib_break + abstract = FALSE + wound_path_to_generate = /datum/wound/blunt/bone/rib_break + required_limb_biostate = BIO_BONE + threshold_minimum = 20 + viable_zones = list(BODY_ZONE_CHEST) + +/datum/wound/blunt/bone/rib_break + // You may notice higher severity bone wounds are fractures on their own + // So this one seems a bit out of place, seeing as it's a generic "rib fracture" when more specific ones exist + // This is here as the chest has no moderate wound (as it's not jointed, and can't dislocate) + // Flavor wise imagine it as one rib being broken rather than multiple + name = "Fractured Rib" + desc = "One of the patient's ribs has been fractured, causing sharp pain and difficulty breathing." + treat_text = "Repair surgically. In the event of an emergency, \ + one can also apply bone gel and surgical tape to the affected area to fix over time." + treat_text_short = "Repair surgically, or apply bone gel and surgical tape." + occur_text = "cracks and bruises" + examine_desc = "" + + severity = WOUND_SEVERITY_MODERATE + threshold_penalty = 20 + treatable_by = list(/obj/item/stack/sticky_tape/surgical, /obj/item/stack/medical/bone_gel) + status_effect_type = /datum/status_effect/wound/blunt/bone/rib_break + scar_keyword = "dislocate" + internal_bleeding_chance = 25 + wound_flags = (ACCEPTS_GAUZE | MANGLES_INTERIOR) + regen_ticks_needed = 180 // ticks every 2 seconds, 360 seconds, so roughly 6 minutes default + + simple_treat_text = "Bandaging the wound will reduce its impact until treated \ + surgically or via bone gel and surgical tape." + homemade_treat_text = "Bone gel and surgical tape may be applied directly to the wound, \ + though this is quite difficult for most people to do so individually \ + unless they've dosed themselves with one or more painkillers." + +/datum/wound/blunt/bone/rib_break/get_self_check_description(mob/user) + if(locate(/datum/wound/bleed_internal) in limb.wounds) + return null + return span_warning("It feels tense to the touch.") // same as IB! + /// Joint Dislocation (Moderate Blunt) /datum/wound/blunt/bone/moderate name = "Joint Dislocation" + undiagnosed_name = "Dislocation" desc = "Patient's limb has been unset from socket, causing pain and reduced motor function." - treat_text = "Recommended application of bonesetter to affected limb, though manual relocation by applying an aggressive grab to the patient and helpfully interacting with afflicted limb may suffice." + treat_text = "Apply Bonesetter to the affected limb. \ + Manual relocation by via an aggressive grab and a tight hug to the affected limb may also suffice." + treat_text_short = "Apply Bonesetter, or manually relocate the limb." examine_desc = "is awkwardly janked out of place" occur_text = "janks violently and becomes unseated" severity = WOUND_SEVERITY_MODERATE @@ -197,9 +321,12 @@ status_effect_type = /datum/status_effect/wound/blunt/bone/moderate scar_keyword = "dislocate" - simple_desc = "Patient's bone has been dislocated, causing limping or reduced dexterity." - simple_treat_text = "Bandaging the wound will reduce its impact until treated with a bonesetter. Most commonly, it is treated by aggressively grabbing someone and helpfully wrenching the limb in place, though there's room for malfeasance when doing this." - homemade_treat_text = "Besides bandaging and wrenching, bone setters can be printed in lathes and utilized on oneself at the cost of great pain. As a last resort, crushing the patient with a firelock has sometimes been noted to fix their dislocated limb." + simple_treat_text = "Bandaging the wound will reduce its impact until treated with a bonesetter. \ + Most commonly, it is treated by aggressively grabbing someone and helpfully wrenching the limb in place, \ + though there's room for malfeasance when doing this." + homemade_treat_text = "Besides bandaging and wrenching, bone setters \ + can be printed in lathes and utilized on oneself at the cost of great pain. \ + As a last resort, crushing the patient with a firelock has sometimes been noted to fix their dislocated limb." /datum/wound_pregen_data/bone/dislocate abstract = FALSE @@ -224,6 +351,9 @@ return ..() +/datum/wound/blunt/bone/moderate/get_self_check_description(mob/user) + return span_warning("It feels dislocated!") + /// Getting smushed in an airlock/firelock is a last-ditch attempt to try relocating your limb /datum/wound/blunt/bone/moderate/proc/door_crush() SIGNAL_HANDLER @@ -236,7 +366,7 @@ return FALSE if(user.grab_state == GRAB_PASSIVE) - to_chat(user, span_warning("You must have [victim] in an aggressive grab to manipulate [victim.p_their()] [lowertext(name)]!")) + to_chat(user, span_warning("You must have [victim] in an aggressive grab to manipulate [victim.p_their()] [lowertext(undiagnosed_name || name)]!")) return TRUE if(user.grab_state >= GRAB_AGGRESSIVE) @@ -258,13 +388,13 @@ if(prob(65)) user.visible_message(span_danger("[user] snaps [victim]'s dislocated [limb.plaintext_zone] back into place!"), span_notice("You snap [victim]'s dislocated [limb.plaintext_zone] back into place!"), ignored_mobs=victim) to_chat(victim, span_userdanger("[user] snaps your dislocated [limb.plaintext_zone] back into place!")) - victim.emote("scream") - limb.receive_damage(brute=20, wound_bonus=CANT_WOUND) + user.pain_emote("scream") + user.apply_damage(20, BRUTE, limb, wound_bonus = CANT_WOUND) qdel(src) else user.visible_message(span_danger("[user] wrenches [victim]'s dislocated [limb.plaintext_zone] around painfully!"), span_danger("You wrench [victim]'s dislocated [limb.plaintext_zone] around painfully!"), ignored_mobs=victim) to_chat(victim, span_userdanger("[user] wrenches your dislocated [limb.plaintext_zone] around painfully!")) - limb.receive_damage(brute=10, wound_bonus=CANT_WOUND) + user.apply_damage(10, BRUTE, limb, wound_bonus = CANT_WOUND) chiropractice(user) /// If someone is snapping our dislocated joint into a fracture by hand with an aggro grab and harm or disarm intent @@ -277,12 +407,12 @@ if(prob(65)) user.visible_message(span_danger("[user] snaps [victim]'s dislocated [limb.plaintext_zone] with a sickening crack!"), span_danger("You snap [victim]'s dislocated [limb.plaintext_zone] with a sickening crack!"), ignored_mobs=victim) to_chat(victim, span_userdanger("[user] snaps your dislocated [limb.plaintext_zone] with a sickening crack!")) - victim.emote("scream") - limb.receive_damage(brute=25, wound_bonus=30) + user.pain_emote("scream") + user.apply_damage(25, BRUTE, limb, wound_bonus = 30) else user.visible_message(span_danger("[user] wrenches [victim]'s dislocated [limb.plaintext_zone] around painfully!"), span_danger("You wrench [victim]'s dislocated [limb.plaintext_zone] around painfully!"), ignored_mobs=victim) to_chat(victim, span_userdanger("[user] wrenches your dislocated [limb.plaintext_zone] around painfully!")) - limb.receive_damage(brute=10, wound_bonus=CANT_WOUND) + user.apply_damage(10, BRUTE, limb, wound_bonus = CANT_WOUND) malpractice(user) @@ -308,7 +438,7 @@ user.visible_message(span_danger("[user] finishes resetting [victim]'s [limb.plaintext_zone]!"), span_nicegreen("You finish resetting [victim]'s [limb.plaintext_zone]!"), ignored_mobs=victim) to_chat(victim, span_userdanger("[user] resets your [limb.plaintext_zone]!")) - victim.emote("scream") + victim.pain_emote("scream") qdel(src) /* @@ -318,7 +448,9 @@ /datum/wound/blunt/bone/severe name = "Hairline Fracture" desc = "Patient's bone has suffered a crack in the foundation, causing serious pain and reduced limb functionality." - treat_text = "Recommended light surgical application of bone gel, though a sling of medical gauze will prevent worsening situation." + treat_text = "Repair surgically. In the event of an emergency, an application of bone gel over the affected area will fix over time. \ + A splint or sling of medical gauze can also be used to prevent the fracture from worsening." + treat_text_short = "Repair surgically, or apply bone gel. A splint or gauze sling can also be used." examine_desc = "appears grotesquely swollen, jagged bumps hinting at chips in the bone" occur_text = "sprays chips of bone and develops a nasty looking bruise" @@ -336,9 +468,11 @@ wound_flags = (ACCEPTS_GAUZE | MANGLES_INTERIOR) regen_ticks_needed = 120 // ticks every 2 seconds, 240 seconds, so roughly 4 minutes default - simple_desc = "Patient's bone has cracked in the middle, drastically reducing limb functionality." - simple_treat_text = "Bandaging the wound will reduce its impact until surgically treated with bone gel and surgical tape." - homemade_treat_text = "Bone gel and surgical tape may be applied directly to the wound, though this is quite difficult for most people to do so individually unless they've dosed themselves with one or more painkillers (Morphine and Miner's Salve have been known to help)" + simple_treat_text = "Bandaging the wound will reduce its impact until treated \ + surgically or via bone gel and surgical tape." + homemade_treat_text = "Bone gel and surgical tape may be applied directly to the wound, \ + though this is quite difficult for most people to do so individually \ + unless they've dosed themselves with one or more painkillers." /datum/wound_pregen_data/bone/hairline @@ -351,8 +485,12 @@ /// Compound Fracture (Critical Blunt) /datum/wound/blunt/bone/critical name = "Compound Fracture" - desc = "Patient's bones have suffered multiple gruesome fractures, causing significant pain and near uselessness of limb." - treat_text = "Immediate binding of affected limb, followed by surgical intervention ASAP." + undiagnosed_name = "Compound Fracture" // you can tell it's a compound fracture at a glance because of a skin breakage + desc = "Patient's bones have suffered multiple fractures, \ + couped with a break in the skin, causing significant pain and near uselessness of limb." + treat_text = "Immediately bind the affected limb with gauze or a splint. Repair surgically. \ + In the event of an emergency, bone gel and surgical tape can be applied to the affected area to fix over a long period of time." + treat_text_short = "Repair surgically, or apply bone gel and surgical tape. A splint or gauze sling should also be used." examine_desc = "is thoroughly pulped and cracked, exposing shards of bone to open air" occur_text = "cracks apart, exposing broken bones to open air" @@ -372,9 +510,12 @@ wound_flags = (ACCEPTS_GAUZE | MANGLES_INTERIOR) regen_ticks_needed = 240 // ticks every 2 seconds, 480 seconds, so roughly 8 minutes default - simple_desc = "Patient's bones have effectively shattered completely, causing total immobilization of the limb." - simple_treat_text = "Bandaging the wound will slightly reduce its impact until surgically treated with bone gel and surgical tape." - homemade_treat_text = "Although this is extremely difficult and slow to function, Bone gel and surgical tape may be applied directly to the wound, though this is nigh-impossible for most people to do so individually unless they've dosed themselves with one or more painkillers (Morphine and Miner's Salve have been known to help)" + simple_treat_text = "Bandaging the wound will slightly reduce its impact until treated \ + surgically or via bone gel and surgical tape." + homemade_treat_text = "Although this is extremely difficult and slow to function, \ + Bone gel and surgical tape may be applied directly to the wound, \ + though this is nigh-impossible for most people to do so individually \ + unless they've dosed themselves with one or more painkillers." /datum/wound_pregen_data/bone/compound abstract = FALSE @@ -406,13 +547,14 @@ return TRUE I.use(1) - victim.emote("scream") + victim.pain_emote("scream") if(user != victim) user.visible_message(span_notice("[user] finishes applying [I] to [victim]'s [limb.plaintext_zone], emitting a fizzing noise!"), span_notice("You finish applying [I] to [victim]'s [limb.plaintext_zone]!"), ignored_mobs=victim) to_chat(victim, span_userdanger("[user] finishes applying [I] to your [limb.plaintext_zone], and you can feel the bones exploding with pain as they begin melting and reforming!")) else if(!HAS_TRAIT(victim, TRAIT_ANALGESIA)) - if(prob(25 + (20 * (severity - 2)) - min(victim.get_drunk_amount(), 10))) // 25%/45% chance to fail self-applying with severe and critical wounds, modded by drunkenness + var/painkiller_bonus = 50 * (1 - (victim.pain_controller?.pain_modifier || 1)) + if(prob(25 + (20 * (severity - 2)) - painkiller_bonus)) // 25%/45% chance to fail self-applying with severe and critical wounds, modded by drunkenness victim.visible_message(span_danger("[victim] fails to finish applying [I] to [victim.p_their()] [limb.plaintext_zone], passing out from the pain!"), span_notice("You pass out from the pain of applying [I] to your [limb.plaintext_zone] before you can finish!")) victim.AdjustUnconscious(5 SECONDS) return TRUE @@ -485,21 +627,16 @@ . += "
" if(severity > WOUND_SEVERITY_MODERATE) - if((limb.biological_state & BIO_BONE) && !(limb.biological_state & BIO_FLESH)) - if(!gelled) - . += "Recommended Treatment: Apply bone gel directly to injured limb. Creatures of pure bone don't seem to mind bone gel application nearly as much as fleshed individuals. Surgical tape will also be unnecessary.\n" - else - . += "[span_notice("Note: Bone regeneration in effect. Bone is [round(regen_ticks_current*100/regen_ticks_needed)]% regenerated.")]\n" - else - if(!gelled) - . += "Alternative Treatment: Apply bone gel directly to injured limb, then apply surgical tape to begin bone regeneration. This is both excruciatingly painful and slow, and only recommended in dire circumstances.\n" - else if(!taped) - . += "[span_notice("Continue Alternative Treatment: Apply surgical tape directly to injured limb to begin bone regeneration. Note, this is both excruciatingly painful and slow, though sleep or laying down will speed recovery.")]\n" - else - . += "[span_notice("Note: Bone regeneration in effect. Bone is [round(regen_ticks_current*100/regen_ticks_needed)]% regenerated.")]\n" + if(!gelled) + . += "Recommended Treatment: \ + Operate where possible. In the event of emergency, apply bone gel directly to injured limb. \ + Creatures of pure bone don't seem to mind bone gel application nearly as much as fleshed individuals. \ + Surgical tape will also be unnecessary.\n" if(limb.body_zone == BODY_ZONE_HEAD) - . += "Cranial Trauma Detected: Patient will suffer random bouts of [severity == WOUND_SEVERITY_SEVERE ? "mild" : "severe"] brain traumas until bone is repaired." - else if(limb.body_zone == BODY_ZONE_CHEST && victim.blood_volume) - . += "Ribcage Trauma Detected: Further trauma to chest is likely to worsen internal bleeding until bone is repaired." + . += "Cranial Trauma Detected: \ + Patient will suffer random bouts of [severity == WOUND_SEVERITY_SEVERE ? "mild" : "severe"] brain traumas until bone is repaired." + else if(limb.body_zone == BODY_ZONE_CHEST && !HAS_TRAIT(victim, TRAIT_NOBLOOD)) + . += "Ribcage Trauma Detected: \ + Further trauma to chest is likely to worsen internal bleeding until bone is repaired." . += "
" diff --git a/code/datums/wounds/burns.dm b/code/datums/wounds/burns.dm index 483b47cce1fa..f5cc3c9a3231 100644 --- a/code/datums/wounds/burns.dm +++ b/code/datums/wounds/burns.dm @@ -6,9 +6,19 @@ // TODO: well, a lot really, but specifically I want to add potential fusing of clothing/equipment on the affected area, and limb infections, though those may go in body part code /datum/wound/burn name = "Burn Wound" + undiagnosed_name = "Burns" a_or_from = "from" sound_effect = 'sound/effects/wounds/sizzle1.ogg' +/datum/wound/burn/wound_injury(datum/wound/old_wound, attack_direction) + if(!old_wound && limb.current_gauze && (wound_flags & ACCEPTS_GAUZE)) + qdel(limb.remove_gauze()) + // oops your existing gauze got burned, need a new one now + var/obj/effect/decal/cleanable/ash/ash = new(limb.drop_location()) + ash.desc += " It looks like it used to be some kind of bandage." + + return ..() + /datum/wound/burn/flesh name = "Burn (Flesh) Wound" a_or_from = "from" @@ -35,6 +45,11 @@ /// Once we reach infestation beyond WOUND_INFESTATION_SEPSIS, we get this many warnings before the limb is completely paralyzed (you'd have to ignore a really bad burn for a really long time for this to happen) var/strikes_to_lose_limb = 3 +/datum/wound/burn/flesh/severity_text(simple = FALSE) + if(infestation > WOUND_INFECTION_MODERATE) + return "Infected, [..()]" + return ..() + /datum/wound/burn/flesh/handle_process(seconds_per_tick, times_fired) if (!victim || HAS_TRAIT(victim, TRAIT_STASIS)) @@ -278,7 +293,8 @@ /datum/wound/burn/flesh/moderate name = "Second Degree Burns" desc = "Patient is suffering considerable burns with mild skin penetration, weakening limb integrity and increased burning sensations." - treat_text = "Recommended application of topical ointment or regenerative mesh to affected region." + treat_text = "Apply topical ointment or regenerative mesh to the wound." + treat_text_short = "Apply healing aid such as regenerative mesh." examine_desc = "is badly burned and breaking out in blisters" occur_text = "breaks out with violent red burns" severity = WOUND_SEVERITY_MODERATE @@ -302,7 +318,10 @@ /datum/wound/burn/flesh/severe name = "Third Degree Burns" desc = "Patient is suffering extreme burns with full skin penetration, creating serious risk of infection and greatly reduced limb integrity." - treat_text = "Recommended immediate disinfection and excision of any infected skin, followed by bandaging and ointment." + treat_text = "Swiftly apply healing aids such as Synthflesh or regenerative mesh to the wound. \ + Disinfect the wound and surgically debride any infected skin, and wrap in clean gauze / use ointment to prevent further infection. \ + If the limb has locked up, it must be amputated, augmented or treated with cryogenics." + treat_text_short = "Apply healing aid such as regenerative mesh or Synthflesh and disinfect / debride." examine_desc = "appears seriously charred, with aggressive red splotches" occur_text = "chars rapidly, exposing ruined tissue and spreading angry red burns" severity = WOUND_SEVERITY_SEVERE @@ -328,7 +347,10 @@ /datum/wound/burn/flesh/critical name = "Catastrophic Burns" desc = "Patient is suffering near complete loss of tissue and significantly charred muscle and bone, creating life-threatening risk of infection and negligible limb integrity." - treat_text = "Immediate surgical debriding of any infected skin, followed by potent tissue regeneration formula and bandaging." + treat_text = "Immediately apply healing aids such as Synthflesh or regenerative mesh to the wound. \ + Disinfect the wound and surgically debride any infected skin, and wrap in clean gauze / use ointment to prevent further infection. \ + If the limb has locked up, it must be amputated, augmented or treated with cryogenics." + treat_text_short = "Apply healing aid such as regenerative mesh or Synthflesh and disinfect / debride." examine_desc = "is a ruined mess of blanched bone, melted fat, and charred tissue" occur_text = "vaporizes as flesh, bone, and fat melt together in a horrifying mess" severity = WOUND_SEVERITY_CRITICAL diff --git a/code/datums/wounds/loss.dm b/code/datums/wounds/loss.dm index bcad804eba68..d8d0aad5e80e 100644 --- a/code/datums/wounds/loss.dm +++ b/code/datums/wounds/loss.dm @@ -48,7 +48,7 @@ set_limb(dismembered_part) second_wind() log_wound(victim, src) - if(dismembered_part.can_bleed() && wounding_type != WOUND_BURN && victim.blood_volume) + if(dismembered_part.can_bleed() && wounding_type != WOUND_BURN) victim.spray_blood(attack_direction, severity) victim.blood_particles(amount = rand(3, 6), angle = 0, min_deviation = 0, max_deviation = 360) dismembered_part.dismember(wounding_type == WOUND_BURN ? BURN : BRUTE, wounding_type = wounding_type) diff --git a/code/datums/wounds/pierce.dm b/code/datums/wounds/pierce.dm index 4deb88361768..0ef431efafd6 100644 --- a/code/datums/wounds/pierce.dm +++ b/code/datums/wounds/pierce.dm @@ -3,6 +3,13 @@ Piercing wounds */ /datum/wound/pierce + undiagnosed_name = "Bleeding Wound" + +/datum/wound/pierce/wound_injury(datum/wound/old_wound, attack_direction) + if(!old_wound && limb.current_gauze && (wound_flags & ACCEPTS_GAUZE)) + // oops your existing gauze got penetrated through! need a new one now + limb.seep_gauze(initial(limb.current_gauze.absorption_capacity) * 0.8) + return ..() /datum/wound/pierce/bleed name = "Piercing Wound" @@ -34,28 +41,45 @@ return ..() -/datum/wound/pierce/bleed/receive_damage(wounding_type, wounding_dmg, wound_bonus) - if(QDELETED(victim) || victim.stat == DEAD || (wounding_dmg < 5) || !limb.can_bleed() || !victim.blood_volume || !prob(internal_bleeding_chance + wounding_dmg)) +/datum/wound/pierce/bleed/receive_damage(wounding_type, wounding_dmg, wound_bonus, attack_direction, damage_source) + if(victim.stat == DEAD || (wounding_dmg < WOUND_MINIMUM_DAMAGE) || wounding_type == WOUND_BURN) + return + if(!limb.can_bleed() || !prob(internal_bleeding_chance)) return + if(limb.body_zone != BODY_ZONE_CHEST) + wounding_dmg *= 0.5 if(limb.current_gauze?.splint_factor) wounding_dmg *= (1 - limb.current_gauze.splint_factor) - var/blood_bled = rand(1, wounding_dmg * internal_bleeding_coefficient) // 12 brute toolbox can cause up to 15/18/21 bloodloss on mod/sev/crit + var/blood_bled = sqrt(wounding_dmg) * internal_bleeding_coefficient * pick(0.75, 1, 1.25, 1.5) switch(blood_bled) - if(1 to 6) - victim.bleed(blood_bled, TRUE) if(7 to 13) - victim.visible_message("Blood droplets fly from the hole in [victim]'s [limb.plaintext_zone].", span_danger("You cough up a bit of blood from the blow to your [limb.plaintext_zone]."), vision_distance=COMBAT_MESSAGE_RANGE) - victim.bleed(blood_bled, TRUE) + victim.visible_message( + span_smalldanger("Blood droplets fly from the hole in [victim]'s [limb.plaintext_zone]."), + span_danger("You cough up a bit of blood from the blow to your [limb.plaintext_zone]."), + vision_distance = COMBAT_MESSAGE_RANGE, + + ) if(14 to 19) - victim.visible_message("A small stream of blood spurts from the hole in [victim]'s [limb.plaintext_zone]!", span_danger("You spit out a string of blood from the blow to your [limb.plaintext_zone]!"), vision_distance=COMBAT_MESSAGE_RANGE) - new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir, COLOR_DARK_RED) - victim.bleed(blood_bled) + victim.visible_message( + span_smalldanger("A small stream of blood spurts from the hole in [victim]'s [limb.plaintext_zone]!"), + span_danger("You spit out a string of blood from the blow to your [limb.plaintext_zone]!"), + vision_distance = COMBAT_MESSAGE_RANGE, + + ) + if(20 to INFINITY) - victim.visible_message(span_danger("A spray of blood streams from the gash in [victim]'s [limb.plaintext_zone]!"), span_danger("You choke up on a spray of blood from the blow to your [limb.plaintext_zone]!"), vision_distance=COMBAT_MESSAGE_RANGE) - victim.bleed(blood_bled) - new /obj/effect/temp_visual/dir_setting/bloodsplatter(victim.loc, victim.dir, COLOR_DARK_RED) + victim.visible_message( + span_danger("A spray of blood streams from the gash in [victim]'s [limb.plaintext_zone]!"), + span_bolddanger("You choke up on a spray of blood from the blow to your [limb.plaintext_zone]!"), + vision_distance = COMBAT_MESSAGE_RANGE, + + ) victim.add_splatter_floor(get_step(victim.loc, victim.dir)) + victim.bleed(blood_bled, TRUE) + if(blood_bled >= 14) + victim.do_splatter_effect(attack_direction) + /datum/wound/pierce/bleed/get_bleed_rate_of_change() //basically if a species doesn't bleed, the wound is stagnant and will not heal on it's own (nor get worse) if(!limb.can_bleed()) @@ -67,23 +91,25 @@ return BLOOD_FLOW_STEADY /datum/wound/pierce/bleed/handle_process(seconds_per_tick, times_fired) + . = ..() if (QDELETED(victim) || HAS_TRAIT(victim, TRAIT_STASIS)) return set_blood_flow(min(blood_flow, WOUND_SLASH_MAX_BLOODFLOW)) if(limb.can_bleed()) - if(victim.bodytemperature < (BODYTEMP_NORMAL - 10)) + if(!HAS_TRAIT(victim, TRAIT_RESISTCOLD) && victim.get_skin_temperature() < victim.bodytemp_cold_damage_limit) adjust_blood_flow(-0.1 * seconds_per_tick) if(SPT_PROB(2.5, seconds_per_tick)) - to_chat(victim, span_notice("You feel the [lowertext(name)] in your [limb.plaintext_zone] firming up from the cold!")) + to_chat(victim, span_notice("You feel the [lowertext(undiagnosed_name || name)] in your [limb.plaintext_zone] firming up from the cold!")) if(HAS_TRAIT(victim, TRAIT_BLOODY_MESS)) adjust_blood_flow(0.25 * seconds_per_tick) // old heparin used to just add +2 bleed stacks per tick, this adds 0.5 bleed flow to all open cuts which is probably even stronger as long as you can cut them first if(limb.current_gauze) - adjust_blood_flow(-limb.current_gauze.absorption_rate * gauzed_clot_rate * seconds_per_tick) - limb.current_gauze.absorption_capacity -= limb.current_gauze.absorption_rate * seconds_per_tick + var/amt_blocking = limb.current_gauze.absorption_rate * seconds_per_tick + adjust_blood_flow(-1 * amt_blocking * gauzed_clot_rate) + limb.seep_gauze(amt_blocking) if(blood_flow <= 0) qdel(src) @@ -153,14 +179,15 @@ else user.visible_message(span_danger("[user] begins cauterizing [victim]'s [limb.plaintext_zone] with [I]..."), span_warning("You begin cauterizing [user == victim ? "your" : "[victim]'s"] [limb.plaintext_zone] with [I]...")) + playsound(user, 'sound/surgery/cautery1.ogg', 75, TRUE) if(!do_after(user, treatment_delay, target = victim, extra_checks = CALLBACK(src, PROC_REF(still_exists)))) return TRUE + playsound(user, 'sound/surgery/cautery2.ogg', 75, TRUE) + var/bleeding_wording = (!limb.can_bleed() ? "holes" : "bleeding") user.visible_message(span_green("[user] cauterizes some of the [bleeding_wording] on [victim]."), span_green("You cauterize some of the [bleeding_wording] on [victim].")) - limb.receive_damage(burn = 2 + severity, wound_bonus = CANT_WOUND) - if(prob(30)) - victim.emote("scream") + victim.apply_damage(2 + severity, BURN, limb, wound_bonus = CANT_WOUND) var/blood_cauterized = (0.6 / (self_penalty_mult * improv_penalty_mult)) adjust_blood_flow(-blood_cauterized) @@ -176,21 +203,16 @@ wound_series = WOUND_SERIES_FLESH_PUNCTURE_BLEED -/datum/wound_pregen_data/flesh_pierce - abstract = TRUE - - required_limb_biostate = (BIO_FLESH) - required_wounding_types = list(WOUND_PIERCE) - - wound_series = WOUND_SERIES_FLESH_PUNCTURE_BLEED - /datum/wound/pierce/get_limb_examine_description() return span_warning("The flesh on this limb appears badly perforated.") /datum/wound/pierce/bleed/moderate name = "Minor Skin Breakage" desc = "Patient's skin has been broken open, causing severe bruising and minor internal bleeding in affected area." - treat_text = "Treat affected site with bandaging or exposure to extreme cold. In dire cases, brief exposure to vacuum may suffice." // space is cold in ss13, so it's like an ice pack! + treat_text = "Apply bandaging or suturing to the wound, make use of blood clotting agents, \ + cauterization, or in extreme circumstances, exposure to extreme cold or vaccuum. \ + Follow with food and a rest period." + treat_text_short = "Apply bandaging or suturing." examine_desc = "has a small, circular hole, gently bleeding" occur_text = "spurts out a thin stream of blood" sound_effect = 'sound/effects/wounds/pierce1.ogg' @@ -221,7 +243,10 @@ /datum/wound/pierce/bleed/severe name = "Open Puncture" desc = "Patient's internal tissue is penetrated, causing sizeable internal bleeding and reduced limb stability." - treat_text = "Repair punctures in skin by suture or cautery, extreme cold may also work." + treat_text = "Swiftly apply bandaging or suturing to the wound, make use of blood clotting agents or saline-glucose, \ + cauterization, or in extreme circumstances, exposure to extreme cold or vaccuum. \ + Follow with iron supplements and a rest period." + treat_text_short = "Apply bandaging, suturing, clotting agents, or cauterization." examine_desc = "is pierced clear through, with bits of tissue obscuring the open hole" occur_text = "looses a violent spray of blood, revealing a pierced wound" sound_effect = 'sound/effects/wounds/pierce2.ogg' @@ -251,7 +276,10 @@ /datum/wound/pierce/bleed/critical name = "Ruptured Cavity" desc = "Patient's internal tissue and circulatory system is shredded, causing significant internal bleeding and damage to internal organs." - treat_text = "Surgical repair of puncture wound, followed by supervised resanguination." + treat_text = "Immediately apply bandaging or suturing to the wound, make use of blood clotting agents or saline-glucose, \ + cauterization, or in extreme circumstances, exposure to extreme cold or vaccuum. \ + Follow with supervised resanguination." + treat_text_short = "Apply bandaging, suturing, clotting agents, or cauterization." examine_desc = "is ripped clear through, barely held together by exposed bone" occur_text = "blasts apart, sending chunks of viscera flying in all directions" sound_effect = 'sound/effects/wounds/pierce3.ogg' diff --git a/code/datums/wounds/slash.dm b/code/datums/wounds/slash.dm index b0edc7f25074..ea2145c2db21 100644 --- a/code/datums/wounds/slash.dm +++ b/code/datums/wounds/slash.dm @@ -5,8 +5,15 @@ /datum/wound/slash name = "Slashing (Cut) Wound" + undiagnosed_name = "Cut" sound_effect = 'sound/weapons/slice.ogg' +/datum/wound/slash/wound_injury(datum/wound/old_wound, attack_direction) + if(!old_wound && limb.current_gauze && (wound_flags & ACCEPTS_GAUZE)) + // oops your existing gauze got cut through! need a new one now + limb.seep_gauze(initial(limb.current_gauze.absorption_capacity) * 0.8) + return ..() + /datum/wound_pregen_data/flesh_slash abstract = TRUE @@ -134,7 +141,7 @@ return BLOOD_FLOW_INCREASING /datum/wound/slash/flesh/handle_process(seconds_per_tick, times_fired) - + . = ..() if (!victim || HAS_TRAIT(victim, TRAIT_STASIS)) return @@ -317,7 +324,9 @@ /datum/wound/slash/flesh/moderate name = "Rough Abrasion" desc = "Patient's skin has been badly scraped, generating moderate blood loss." - treat_text = "Application of clean bandages or first-aid grade sutures, followed by food and rest." + treat_text = "Apply bandaging or suturing to the wound. \ + Follow up with food and a rest period." + treat_text_short = "Apply bandaging or suturing." examine_desc = "has an open cut" occur_text = "is cut open, slowly leaking blood" sound_effect = 'sound/effects/wounds/blood1.ogg' @@ -346,7 +355,10 @@ /datum/wound/slash/flesh/severe name = "Open Laceration" desc = "Patient's skin is ripped clean open, allowing significant blood loss." - treat_text = "Speedy application of first-aid grade sutures and clean bandages, followed by vitals monitoring to ensure recovery." + treat_text = "Swiftly apply bandaging or suturing to the wound, \ + or make use of blood clotting agents or cauterization. \ + Follow up with iron supplements or saline-glucose and a rest period." + treat_text_short = "Apply bandaging, suturing, clotting agents, or cauterization." examine_desc = "has a severe cut" occur_text = "is ripped open, veins spurting blood" sound_effect = 'sound/effects/wounds/blood2.ogg' @@ -376,7 +388,10 @@ /datum/wound/slash/flesh/critical name = "Weeping Avulsion" desc = "Patient's skin is completely torn open, along with significant loss of tissue. Extreme blood loss will lead to quick death without intervention." - treat_text = "Immediate bandaging and either suturing or cauterization, followed by supervised resanguination." + treat_text = "Immediately apply bandaging or suturing to the wound, \ + or make use of blood clotting agents or cauterization. \ + Follow up supervised resanguination." + treat_text_short = "Apply bandaging, suturing, clotting agents, or cauterization." examine_desc = "is carved down to the bone, spraying blood wildly" occur_text = "is torn open, spraying blood wildly" sound_effect = 'sound/effects/wounds/blood3.ogg' diff --git a/code/game/atom_defense.dm b/code/game/atom_defense.dm index ea9b8994bc78..43422bf2fcba 100644 --- a/code/game/atom_defense.dm +++ b/code/game/atom_defense.dm @@ -58,6 +58,11 @@ SHOULD_BE_PURE(TRUE) return atom_integrity +/// Similar to get_integrity, but returns the percentage as [0-1] instead. +/atom/proc/get_integrity_percentage() + SHOULD_BE_PURE(TRUE) + return round(atom_integrity / max_integrity, 0.01) + ///returns the damage value of the attack after processing the atom's various armor protections /atom/proc/run_atom_armor(damage_amount, damage_type, damage_flag = 0, attack_dir, armour_penetration = 0) if(!uses_integrity) @@ -131,6 +136,10 @@ /// A cut-out proc for [/atom/proc/bullet_act] so living mobs can have their own armor behavior checks without causing issues with needing their own on_hit call /atom/proc/check_projectile_armor(def_zone, obj/projectile/impacting_projectile, is_silent) - if(uses_integrity) - return clamp(PENETRATE_ARMOUR(get_armor_rating(impacting_projectile.armor_flag), impacting_projectile.armour_penetration), 0, 100) - return 0 + if(!uses_integrity) + return 0 + + . = clamp(PENETRATE_ARMOUR(get_armor_rating(impacting_projectile.armor_flag), impacting_projectile.armour_penetration), 0, 100) + if(impacting_projectile.grazing) + . += 50 + return . diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 95ba030e198a..d95c5ad012af 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1042,20 +1042,19 @@ ///returns the mob's dna info as a list, to be inserted in an object's blood_DNA list /mob/living/proc/get_blood_dna_list() - if(get_blood_id() != /datum/reagent/blood) - return - return list("ANIMAL DNA" = "Y-") + var/datum/blood_type/blood = get_blood_type() + if(!isnull(blood)) + return list("UNKNOWN DNA" = blood.type) + return null ///Get the mobs dna list /mob/living/carbon/get_blood_dna_list() - if(get_blood_id() != /datum/reagent/blood) - return - var/list/blood_dna = list() - if(dna) - blood_dna[dna.unique_enzymes] = dna.blood_type - else - blood_dna["UNKNOWN DNA"] = "X*" - return blood_dna + if(isnull(dna)) // Xenos + return ..() + var/datum/blood_type/blood = get_blood_type() + if(isnull(blood)) // Skeletons? + return null + return list("[dna.unique_enzymes]" = blood.type) /mob/living/carbon/alien/get_blood_dna_list() return list("UNKNOWN DNA" = "X*") diff --git a/code/game/machinery/computer/dna_console.dm b/code/game/machinery/computer/dna_console.dm index 932444e63a8f..bd28bed8a6dd 100644 --- a/code/game/machinery/computer/dna_console.dm +++ b/code/game/machinery/computer/dna_console.dm @@ -1229,7 +1229,7 @@ "UE"=scanner_occupant.dna.unique_enzymes, "UF"=scanner_occupant.dna.unique_features, "name"=scanner_occupant.real_name, - "blood_type"=scanner_occupant.dna.blood_type) + "blood_type"="[GLOB.blood_types[scanner_occupant.dna.human_blood_type]]") return @@ -1719,7 +1719,7 @@ scanner_occupant.real_name = buffer_slot["name"] scanner_occupant.name = buffer_slot["name"] scanner_occupant.dna.unique_enzymes = buffer_slot["UE"] - scanner_occupant.dna.blood_type = buffer_slot["blood_type"] + scanner_occupant.dna.human_blood_type = blood_name_to_blood_type(buffer_slot["blood_type"]) scanner_occupant.apply_status_effect(/datum/status_effect/genetic_damage, damage_increase) scanner_occupant.domutcheck() return TRUE @@ -1737,7 +1737,7 @@ scanner_occupant.real_name = buffer_slot["name"] scanner_occupant.name = buffer_slot["name"] scanner_occupant.dna.unique_enzymes = buffer_slot["UE"] - scanner_occupant.dna.blood_type = buffer_slot["blood_type"] + scanner_occupant.dna.human_blood_type = blood_name_to_blood_type(buffer_slot["blood_type"]) scanner_occupant.apply_status_effect(/datum/status_effect/genetic_damage, damage_increase) scanner_occupant.domutcheck() return TRUE diff --git a/code/game/machinery/computer/operating_computer.dm b/code/game/machinery/computer/operating_computer.dm index 093c96bf57ec..83692a8af26a 100644 --- a/code/game/machinery/computer/operating_computer.dm +++ b/code/game/machinery/computer/operating_computer.dm @@ -138,12 +138,7 @@ data["patient"]["health"] = patient.health // check here to see if the patient has standard blood reagent, or special blood (like how ethereals bleed liquid electricity) to show the proper name in the computer - var/blood_id = patient.get_blood_id() - if(blood_id == /datum/reagent/blood) - data["patient"]["blood_type"] = patient.dna?.blood_type - else - var/datum/reagent/special_blood = GLOB.chemical_reagents_list[blood_id] - data["patient"]["blood_type"] = special_blood ? special_blood.name : blood_id + data["patient"]["blood_type"] = "[patient.get_blood_type() || "None"]" data["patient"]["maxHealth"] = patient.maxHealth data["patient"]["minHealth"] = HEALTH_THRESHOLD_DEAD diff --git a/code/game/machinery/computer/records/medical.dm b/code/game/machinery/computer/records/medical.dm index 53c3256dc217..2e18e22ee460 100644 --- a/code/game/machinery/computer/records/medical.dm +++ b/code/game/machinery/computer/records/medical.dm @@ -140,7 +140,7 @@ return FALSE target.age = 18 - target.blood_type = pick(list("A+", "A-", "B+", "B-", "O+", "O-", "AB+", "AB-")) + target.blood_type = "[GLOB.blood_types[random_human_blood_type()]]" target.dna_string = "Unknown" target.gender = "Unknown" target.major_disabilities = "" diff --git a/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm b/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm index 74d028d22c6f..1b915b22653d 100644 --- a/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/fly_organs.dm @@ -37,6 +37,9 @@ icon = 'icons/obj/medical/organs/fly_organs.dmi' say_mod = "buzzes" taste_sensitivity = 25 // you eat vomit, this is a mercy + liked_foodtypes = GROSS | GORE // nasty ass + disliked_foodtypes = NONE + toxic_foodtypes = NONE // these fucks eat vomit, i am sure they can handle drinking bleach or whatever too modifies_speech = TRUE languages_native = list(/datum/language/buzzwords) diff --git a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm index ff9a96b7f397..5d088da77889 100644 --- a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm +++ b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm @@ -43,51 +43,13 @@ greyscale_config = /datum/greyscale_config/mutant_organ greyscale_colors = RAT_COLORS /// Multiplier of [physiology.hunger_mod]. - var/hunger_mod = 10 + hunger_modifier = 10 /obj/item/organ/internal/stomach/rat/Initialize(mapload) . = ..() AddElement(/datum/element/organ_set_bonus, /datum/status_effect/organ_set_bonus/rat) AddElement(/datum/element/noticable_organ, "mouth is drooling excessively.", BODY_ZONE_PRECISE_MOUTH) -/obj/item/organ/internal/stomach/rat/on_insert(mob/living/carbon/receiver) - . = ..() - if(!ishuman(receiver)) - return - var/mob/living/carbon/human/human_holder = receiver - if(!human_holder.can_mutate()) - return - var/datum/species/species = human_holder.dna.species - //mmm, cheese. doesn't especially like anything else - species.liked_food = DAIRY - //but a rat can eat anything without issue - species.disliked_food = NONE - species.toxic_food = NONE - if(human_holder.physiology) - human_holder.physiology.hunger_mod *= hunger_mod - RegisterSignal(human_holder, COMSIG_SPECIES_GAIN, PROC_REF(on_species_gain)) - -/obj/item/organ/internal/stomach/rat/proc/on_species_gain(datum/source, datum/species/new_species, datum/species/old_species) - SIGNAL_HANDLER - new_species.liked_food = DAIRY - new_species.disliked_food = NONE - new_species.toxic_food = NONE - -/obj/item/organ/internal/stomach/rat/on_remove(mob/living/carbon/stomach_owner) - . = ..() - if(!ishuman(stomach_owner)) - return - var/mob/living/carbon/human/human_holder = stomach_owner - if(!human_holder.can_mutate()) - return - var/datum/species/species = human_holder.dna.species - species.liked_food = initial(species.liked_food) - species.disliked_food = initial(species.disliked_food) - species.toxic_food = initial(species.toxic_food) - if(human_holder.physiology) - human_holder.physiology.hunger_mod /= hunger_mod - UnregisterSignal(stomach_owner, COMSIG_SPECIES_GAIN) - /// makes you smaller, walk over tables, and take 1.5x damage /obj/item/organ/internal/heart/rat name = "mutated rat-heart" @@ -126,13 +88,15 @@ /obj/item/organ/internal/tongue/rat name = "mutated rat-tongue" desc = "Rat DNA infused into what was once a normal tongue." - say_mod = "squeaks" - modifies_speech = TRUE - icon = 'icons/obj/medical/organs/infuser_organs.dmi' icon_state = "tongue" + say_mod = "squeaks" + modifies_speech = TRUE greyscale_config = /datum/greyscale_config/mutant_organ greyscale_colors = RAT_COLORS + liked_foodtypes = DAIRY //mmm, cheese. doesn't especially like anything else + disliked_foodtypes = NONE //but a rat can eat anything without issue + toxic_foodtypes = NONE /obj/item/organ/internal/tongue/rat/Initialize(mapload) . = ..() diff --git a/code/game/machinery/medical_kiosk.dm b/code/game/machinery/medical_kiosk.dm index f92fd03cd04a..c41ca6bfdf72 100644 --- a/code/game/machinery/medical_kiosk.dm +++ b/code/game/machinery/medical_kiosk.dm @@ -211,7 +211,7 @@ var/bleed_status = "Patient is not currently bleeding." var/blood_status = " Patient either has no blood, or does not require it to function." var/blood_percent = round((patient.blood_volume / BLOOD_VOLUME_NORMAL)*100) - var/blood_type = patient.dna.blood_type + var/blood_type = "[patient.get_blood_type() || "None"]" var/blood_warning = " " for(var/thing in patient.diseases) //Disease Information diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index 79141c5598da..682b8ad66f40 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -466,7 +466,7 @@ DEFINE_BITFIELD(turret_flags, list( else if(iscarbon(A)) var/mob/living/carbon/C = A //If not emagged, only target carbons that can use items - if(mode != TURRET_LETHAL && (C.stat || C.handcuffed || !(C.mobility_flags & MOBILITY_USE))) + if(mode != TURRET_LETHAL && (!(C.mobility_flags & MOBILITY_USE) || HAS_TRAIT(C, TRAIT_INCAPACITATED))) continue //If emagged, target all but dead carbons diff --git a/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm b/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm index 781fd0d5a471..e9378797509b 100644 --- a/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm +++ b/code/game/objects/effects/anomalies/anomalies_pyroclastic.dm @@ -30,8 +30,7 @@ var/new_colour = pick(/datum/slime_color/red, /datum/slime_color/orange) var/mob/living/basic/slime/pyro = new(tile, new_colour) ADD_TRAIT(pyro, TRAIT_SLIME_RABID, "pyro") - pyro.maximum_survivable_temperature = INFINITY - pyro.apply_temperature_requirements() + pyro.bodytemp_heat_damage_limit = INFINITY var/mob/chosen_one = SSpolling.poll_ghosts_for_target(check_jobban = ROLE_SENTIENCE, poll_time = 10 SECONDS, checked_target = pyro, ignore_category = POLL_IGNORE_PYROSLIME, alert_pic = pyro, role_name_text = "pyroclastic anomaly slime") if(isnull(chosen_one)) diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index 260354cb7cac..35f3d3c872a0 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -53,6 +53,8 @@ COMSIG_ATOM_ENTERED = PROC_REF(on_entered), ) AddElement(/datum/element/connect_loc, loc_connections) + if(bloodiness) + update_appearance() /obj/effect/decal/cleanable/Destroy() var/turf/T = get_turf(src) @@ -97,7 +99,7 @@ //This is on /cleanable because fuck this ancient mess /obj/effect/decal/cleanable/proc/on_entered(datum/source, atom/movable/AM) SIGNAL_HANDLER - if(iscarbon(AM) && blood_state && bloodiness >= 40) + if(iscarbon(AM) && bloodiness >= 40) SEND_SIGNAL(AM, COMSIG_STEP_ON_BLOOD, src) update_appearance() @@ -112,27 +114,35 @@ * Checks if this decal is a valid decal that can be blood crawled in. */ /obj/effect/decal/cleanable/proc/can_bloodcrawl_in() - if((blood_state != BLOOD_STATE_OIL) && (blood_state != BLOOD_STATE_NOT_BLOODY)) - return bloodiness - - return FALSE - -/** - * Gets the color associated with the any blood present on this decal. If there is no blood, returns null. - */ -/obj/effect/decal/cleanable/proc/get_blood_color() - switch(blood_state) - if(BLOOD_STATE_HUMAN) - return rgb(149, 10, 10) - if(BLOOD_STATE_XENO) - return rgb(43, 186, 0) - if(BLOOD_STATE_OIL) - return rgb(22, 22, 22) - - return null + return decal_reagent == /datum/reagent/blood /obj/effect/decal/cleanable/proc/handle_merge_decal(obj/effect/decal/cleanable/merger) if(!merger) return if(merger.reagents && reagents) reagents.trans_to(merger, reagents.total_volume) + +/// Increments or decrements the bloodiness value +/obj/effect/decal/cleanable/proc/adjust_bloodiness(by_amount) + if(by_amount == 0) + return FALSE + if(QDELING(src)) + return FALSE + + bloodiness = clamp((bloodiness + by_amount), 0, BLOOD_POOL_MAX) + update_appearance() + return TRUE + +/// Called before attempting to scoop up reagents from this decal to only load reagents when necessary +/obj/effect/decal/cleanable/proc/lazy_init_reagents() + return + +#ifdef TESTING +/obj/effect/decal/cleanable/update_overlays() + . = ..() + if(bloodiness) + var/mutable_appearance/blah_text = new() + blah_text.maptext = MAPTEXT_TINY_UNICODE("[bloodiness]") + blah_text.appearance_flags |= (KEEP_APART|RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM) + . += blah_text +#endif diff --git a/code/game/objects/effects/decals/cleanable/aliens.dm b/code/game/objects/effects/decals/cleanable/aliens.dm index 6da917e8aab9..8083249d742d 100644 --- a/code/game/objects/effects/decals/cleanable/aliens.dm +++ b/code/game/objects/effects/decals/cleanable/aliens.dm @@ -7,13 +7,14 @@ icon_state = "xfloor1" random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7") bloodiness = BLOOD_AMOUNT_PER_DECAL - blood_state = BLOOD_STATE_XENO beauty = -250 clean_type = CLEAN_TYPE_BLOOD + decal_reagent = /datum/blood_type/xenomorph::reagent_type + reagent_amount = 15 /obj/effect/decal/cleanable/xenoblood/Initialize(mapload) . = ..() - add_blood_DNA(list("UNKNOWN DNA" = "X*")) + add_blood_DNA(list("UNKNOWN DNA" = /datum/blood_type/xenomorph)) /obj/effect/decal/cleanable/xenoblood/xsplatter random_icon_states = list("xgibbl1", "xgibbl2", "xgibbl3", "xgibbl4", "xgibbl5") @@ -100,10 +101,6 @@ icon_state = "xgiblarvatorso" random_icon_states = list("xgiblarvahead", "xgiblarvatorso") -/obj/effect/decal/cleanable/blood/xtracks +/obj/effect/decal/cleanable/xenoblood/xtracks icon_state = "xtracks" random_icon_states = null - -/obj/effect/decal/cleanable/blood/xtracks/Initialize(mapload) - . = ..() - add_blood_DNA(list("Unknown DNA" = "X*")) diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm index 08715536511e..0d8f4e26bb9d 100644 --- a/code/game/objects/effects/decals/cleanable/humans.dm +++ b/code/game/objects/effects/decals/cleanable/humans.dm @@ -1,6 +1,6 @@ /obj/effect/decal/cleanable/blood name = "blood" - desc = "It's red and gooey. Perhaps it's the chef's cooking?" + desc = "It's weird and gooey. Perhaps it's the chef's cooking?" icon = 'icons/effects/blood.dmi' icon_state = "floor1" random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7") @@ -8,64 +8,156 @@ bloodiness = BLOOD_AMOUNT_PER_DECAL beauty = -100 clean_type = CLEAN_TYPE_BLOOD - var/should_dry = TRUE - var/dryname = "dried blood" //when the blood lasts long enough, it becomes dry and gets a new name - var/drydesc = "Looks like it's been here a while. Eew." //as above - var/drytime = 0 + decal_reagent = /datum/reagent/blood + bloodiness = BLOOD_AMOUNT_PER_DECAL + color = COLOR_BLOOD + appearance_flags = parent_type::appearance_flags | KEEP_TOGETHER + /// Can this blood dry out? + var/can_dry = TRUE + /// Is this blood dried out? + var/dried = FALSE + + /// The "base name" of the blood, IE the "pool of" in "pool of blood" + var/base_name = "pool of" + /// When dried, this is prefixed to the name + var/dry_prefix = "dried" + /// When dried, this becomes the desc of the blood + var/dry_desc = "Looks like it's been here a while. Eew." + + /// How long it takes to dry out + var/drying_time = 5 MINUTES + /// The process to drying out, recorded in deciseconds + var/drying_progress = 0 + /// Color matrix applied to dried blood via filter to make it look dried + var/static/list/blood_dry_filter_matrix = list( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + -0.5, -0.75, -0.75, 0, + ) var/count = 0 var/footprint_sprite = null + var/glows = FALSE + var/handles_unique = FALSE -/obj/effect/decal/cleanable/blood/Initialize(mapload) +/obj/effect/decal/cleanable/blood/Initialize(mapload, blood_color = COLOR_BLOOD) . = ..() - if(!should_dry) - return - if(bloodiness) - start_drying() - else - dry() - -/obj/effect/decal/cleanable/blood/process() - if(world.time > drytime) - dry() + START_PROCESSING(SSblood_drying, src) + if(color && can_dry && !dried) + update_blood_drying_effect() /obj/effect/decal/cleanable/blood/Destroy() - STOP_PROCESSING(SSobj, src) + STOP_PROCESSING(SSblood_drying, src) return ..() -/obj/effect/decal/cleanable/blood/proc/get_timer() - drytime = world.time + 3 MINUTES +/obj/effect/decal/cleanable/blood/on_entered(datum/source, atom/movable/AM) + if(dried) + return + return ..() -/obj/effect/decal/cleanable/blood/proc/start_drying() - get_timer() - START_PROCESSING(SSobj, src) +#define DRY_FILTER_KEY "dry_effect" + +/obj/effect/decal/cleanable/blood/update_overlays() + . = ..() + if(glows && !handles_unique) + . += emissive_appearance(icon, icon_state, src) + +/obj/effect/decal/cleanable/blood/proc/update_blood_drying_effect() + if(!can_dry) + remove_filter(DRY_FILTER_KEY) // I GUESS + return + + var/existing_filter = get_filter(DRY_FILTER_KEY) + if(dried) + if(existing_filter) + animate(existing_filter) // just stop existing animations and force it to the end state + return + add_filter(DRY_FILTER_KEY, 2, color_matrix_filter(blood_dry_filter_matrix)) + return + + if(existing_filter) + remove_filter(DRY_FILTER_KEY) + + add_filter(DRY_FILTER_KEY, 2, color_matrix_filter()) + transition_filter(DRY_FILTER_KEY, color_matrix_filter(blood_dry_filter_matrix), drying_time - drying_progress) + +#undef DRY_FILTER_KEY + +/obj/effect/decal/cleanable/blood/proc/get_blood_string() + var/list/all_dna = GET_ATOM_BLOOD_DNA(src) + var/list/all_blood_names = list() + for(var/dna_sample in all_dna) + var/datum/blood_type/blood = GLOB.blood_types[all_dna[dna_sample]] + if(!blood) + all_blood_names |= "blood" + continue + all_blood_names |= lowertext(initial(blood.reagent_type.name)) + return english_list(all_blood_names, nothing_text = "blood") + +/obj/effect/decal/cleanable/blood/process(seconds_per_tick) + if(dried || !can_dry) + return PROCESS_KILL + + adjust_bloodiness(-0.4 * BLOOD_PER_UNIT_MODIFIER * seconds_per_tick) + drying_progress += (seconds_per_tick * 1 SECONDS) + if(drying_progress >= drying_time + SSblood_drying.wait) // Do it next tick when we're done + dry() + +/obj/effect/decal/cleanable/blood/update_name(updates) + . = ..() + name = initial(name) + if(base_name) + name = "[base_name] [get_blood_string()]" + if(dried && dry_prefix) + name = "[dry_prefix] [name]" + +/obj/effect/decal/cleanable/blood/update_desc(updates) + . = ..() + desc = initial(desc) + if(dried && dry_desc) + desc = dry_desc ///This is what actually "dries" the blood. Returns true if it's all out of blood to dry, and false otherwise /obj/effect/decal/cleanable/blood/proc/dry() - if(bloodiness > 20) - bloodiness -= BLOOD_AMOUNT_PER_DECAL - get_timer() + dried = TRUE + reagents?.clear_reagents() + update_appearance() + update_blood_drying_effect() + STOP_PROCESSING(SSblood_drying, src) + return TRUE + +/obj/effect/decal/cleanable/blood/lazy_init_reagents() + var/list/all_dna = GET_ATOM_BLOOD_DNA(src) + var/list/reagents_to_add = list() + for(var/dna_sample in all_dna) + var/datum/blood_type/blood = GLOB.blood_types[all_dna[dna_sample]] + reagents_to_add += blood.reagent_type + + var/num_reagents = length(reagents_to_add) + for(var/reagent_type in reagents_to_add) + reagents.add_reagent(reagent_type, round((bloodiness * 0.2 * BLOOD_PER_UNIT_MODIFIER) / num_reagents, CHEMICAL_VOLUME_ROUNDING)) + +/obj/effect/decal/cleanable/blood/replace_decal(obj/effect/decal/cleanable/blood/merger) + if(merger.dried) // New blood will lie on dry blood return FALSE - else - name = dryname - desc = drydesc - bloodiness = 0 - color = COLOR_GRAY //not all blood splatters have their own sprites... It still looks pretty nice - STOP_PROCESSING(SSobj, src) - return TRUE - -/obj/effect/decal/cleanable/blood/replace_decal(obj/effect/decal/cleanable/blood/C) - C.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) - if (bloodiness) - C.bloodiness = min((C.bloodiness + bloodiness), BLOOD_AMOUNT_PER_DECAL) return ..() +/obj/effect/decal/cleanable/blood/handle_merge_decal(obj/effect/decal/cleanable/blood/merger) + . = ..() + merger.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) + merger.adjust_bloodiness(bloodiness) + merger.drying_progress -= (bloodiness * BLOOD_PER_UNIT_MODIFIER) // goes negative = takes longer to dry + merger.update_blood_drying_effect() + /obj/effect/decal/cleanable/blood/old bloodiness = 0 icon_state = "floor1-old" /obj/effect/decal/cleanable/blood/old/Initialize(mapload, list/datum/disease/diseases) - add_blood_DNA(list("Non-human DNA" = random_blood_type())) // Needs to happen before ..() + add_blood_DNA(list("UNKNOWN DNA" = random_human_blood_type())) . = ..() + dry() /obj/effect/decal/cleanable/blood/splatter icon_state = "gibbl1" @@ -83,19 +175,18 @@ desc = "They look like tracks left by wheels." random_icon_states = null beauty = -50 - dryname = "dried tracks" - drydesc = "Some old bloody tracks left by wheels. Machines are evil, perhaps." + base_name = "" + dry_desc = "Some old bloody tracks left by wheels. Machines are evil, perhaps." -/obj/effect/decal/cleanable/trail_holder //not a child of blood on purpose - name = "blood" - icon = 'icons/effects/blood.dmi' +/obj/effect/decal/cleanable/blood/trail_holder + name = "trail of blood" desc = "Your instincts say you shouldn't be following these." beauty = -50 + icon_state = null + random_icon_states = null + base_name = "trail of" var/list/existing_dirs = list() -/obj/effect/decal/cleanable/trail_holder/can_bloodcrawl_in() - return TRUE - /obj/effect/decal/cleanable/blood/gibs name = "gibs" desc = "They look bloody and gruesome." @@ -107,8 +198,9 @@ mergeable_decal = FALSE turf_loc_check = FALSE - dryname = "rotting gibs" - drydesc = "They look bloody and gruesome while some terrible smell fills the air." + base_name = "" + dry_prefix = "rotting" + dry_desc = "They look bloody and gruesome while some terrible smell fills the air." decal_reagent = /datum/reagent/consumable/liquidgibs reagent_amount = 5 ///Information about the diseases our streaking spawns @@ -122,6 +214,10 @@ LAZYNULL(streak_diseases) return ..() + +/obj/effect/decal/cleanable/blood/gibs/get_blood_string() + return "" + /obj/effect/decal/cleanable/blood/gibs/replace_decal(obj/effect/decal/cleanable/C) return FALSE //Never fail to place us @@ -203,29 +299,25 @@ desc = "Space Jesus, why didn't anyone clean this up? They smell terrible." icon_state = "gib1-old" bloodiness = 0 - should_dry = FALSE - dryname = "old rotting gibs" - drydesc = "Space Jesus, why didn't anyone clean this up? They smell terrible." + dry_prefix = "" + dry_desc = "" /obj/effect/decal/cleanable/blood/gibs/old/Initialize(mapload, list/datum/disease/diseases) + add_blood_DNA(list("UNKNOWN DNA" = random_human_blood_type())) . = ..() - setDir(pick(1,2,4,8)) - add_blood_DNA(list("Non-human DNA" = random_blood_type())) + setDir(pick(GLOB.cardinals)) AddElement(/datum/element/swabable, CELL_LINE_TABLE_SLUDGE, CELL_VIRUS_TABLE_GENERIC, rand(2,4), 10) dry() /obj/effect/decal/cleanable/blood/drip name = "drips of blood" - desc = "It's red." + desc = "A spattering." icon_state = "drip5" //using drip5 since the others tend to blend in with pipes & wires. random_icon_states = list("drip1","drip2","drip3","drip4","drip5") - bloodiness = 0 - var/drips = 1 - dryname = "drips of blood" - drydesc = "It's red." - -/obj/effect/decal/cleanable/blood/drip/can_bloodcrawl_in() - return TRUE + bloodiness = BLOOD_AMOUNT_PER_DECAL * 0.2 * BLOOD_PER_UNIT_MODIFIER + base_name = "drips of" + dry_desc = "A dried spattering." + drying_time = 1 MINUTES //BLOODY FOOTPRINTS @@ -235,7 +327,10 @@ icon = 'icons/effects/footprints.dmi' icon_state = "blood_shoes_enter" random_icon_states = null - blood_state = BLOOD_STATE_HUMAN //the icon state to load images from + bloodiness = 0 // set based on the bloodiness of the foot + base_name = "" + dry_desc = "HMM... SOMEONE WAS HERE!" + handles_unique = TRUE var/entered_dirs = 0 var/exited_dirs = 0 @@ -245,9 +340,6 @@ /// List of species that have made footprints here. var/list/species_types = list() - dryname = "dried footprints" - drydesc = "HMM... SOMEONE WAS HERE!" - /obj/effect/decal/cleanable/blood/footprints/Initialize(mapload, footprint_sprite) src.footprint_sprite = footprint_sprite . = ..() @@ -256,6 +348,10 @@ entered_dirs |= dir //Keep the same appearance as in the map editor update_appearance(mapload ? (ALL) : (UPDATE_NAME | UPDATE_DESC)) + +/obj/effect/decal/cleanable/blood/footprints/get_blood_string() + return "" + //Rotate all of the footprint directions too /obj/effect/decal/cleanable/blood/footprints/setDir(newdir) if(dir == newdir) @@ -276,24 +372,13 @@ update_appearance() return ..() -/obj/effect/decal/cleanable/blood/footprints/update_name(updates) - switch(footprint_sprite) - if(FOOTPRINT_SPRITE_CLAWS) - name = "clawprints" - if(FOOTPRINT_SPRITE_SHOES) - name = "footprints" - if(FOOTPRINT_SPRITE_PAWS) - name = "pawprints" - dryname = "dried [name]" - return ..() - /obj/effect/decal/cleanable/blood/footprints/update_desc(updates) desc = "WHOSE [uppertext(name)] ARE THESE?" return ..() /obj/effect/decal/cleanable/blood/footprints/update_icon() . = ..() - alpha = min(BLOODY_FOOTPRINT_BASE_ALPHA + (255 - BLOODY_FOOTPRINT_BASE_ALPHA) * bloodiness / (BLOOD_ITEM_MAX / 2), 255) + alpha = min(BLOODY_FOOTPRINT_BASE_ALPHA + (255 - BLOODY_FOOTPRINT_BASE_ALPHA) * bloodiness / ((BLOOD_ITEM_MAX * BLOOD_PER_UNIT_MODIFIER) / 2), 255) //Cache of bloody footprint images //Key: @@ -303,17 +388,23 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) /obj/effect/decal/cleanable/blood/footprints/update_overlays() . = ..() + var/icon_state_to_use = "blood" + if(SPECIES_MONKEY in species_types) + icon_state_to_use += "paw" + else if(BODYPART_ID_DIGITIGRADE in species_types) + icon_state_to_use += "claw" + for(var/Ddir in GLOB.cardinals) if(entered_dirs & Ddir) - var/image/bloodstep_overlay = GLOB.bloody_footprints_cache["entered-[footprint_sprite]-[blood_state]-[Ddir]"] + var/image/bloodstep_overlay = GLOB.bloody_footprints_cache["entered-[icon_state_to_use]-[Ddir]"] if(!bloodstep_overlay) - GLOB.bloody_footprints_cache["entered-[footprint_sprite]-[blood_state]-[Ddir]"] = bloodstep_overlay = image(icon, "[blood_state]_[footprint_sprite]_enter", dir = Ddir) + GLOB.bloody_footprints_cache["entered-[icon_state_to_use]-[Ddir]"] = bloodstep_overlay = image(icon, "[icon_state_to_use]1", dir = Ddir) . += bloodstep_overlay if(exited_dirs & Ddir) - var/image/bloodstep_overlay = GLOB.bloody_footprints_cache["exited-[footprint_sprite]-[blood_state]-[Ddir]"] + var/image/bloodstep_overlay = GLOB.bloody_footprints_cache["exited-[icon_state_to_use]-[Ddir]"] if(!bloodstep_overlay) - GLOB.bloody_footprints_cache["exited-[footprint_sprite]-[blood_state]-[Ddir]"] = bloodstep_overlay = image(icon, "[blood_state]_[footprint_sprite]_exit", dir = Ddir) + GLOB.bloody_footprints_cache["exited-[icon_state_to_use]-[Ddir]"] = bloodstep_overlay = image(icon, "[icon_state_to_use]2", dir = Ddir) . += bloodstep_overlay @@ -340,21 +431,15 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) else . += "[icon2html('icons/mob/species/human/bodyparts.dmi', user, "[species]_l_leg")] Some [species] feet." -/obj/effect/decal/cleanable/blood/footprints/replace_decal(obj/effect/decal/cleanable/blood/blood_decal) - if(blood_state != blood_decal.blood_state || footprint_sprite != blood_decal.footprint_sprite) //We only replace footprints of the same type as us - return FALSE - return ..() - -/obj/effect/decal/cleanable/blood/footprints/can_bloodcrawl_in() - if((blood_state != BLOOD_STATE_OIL) && (blood_state != BLOOD_STATE_NOT_BLOODY)) - return TRUE - return FALSE - /obj/effect/decal/cleanable/blood/hitsplatter name = "blood splatter" pass_flags = PASSTABLE | PASSGRILLE icon_state = "hitsplatter1" random_icon_states = list("hitsplatter1", "hitsplatter2", "hitsplatter3") + + base_name = "" + can_dry = FALSE // No point + /// The turf we just came from, so we can back up when we hit a wall var/turf/prev_loc /// The cached info about the blood @@ -368,8 +453,10 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) /// Type of squirt decals we should try to create when moving var/line_type = /obj/effect/decal/cleanable/blood/line -/obj/effect/decal/cleanable/blood/hitsplatter/Initialize(mapload, splatter_strength) +/obj/effect/decal/cleanable/blood/hitsplatter/Initialize(mapload, splatter_strength, blood_color = COLOR_BLOOD) . = ..() + color = blood_color + blood_dna_info = GET_ATOM_BLOOD_DNA(src) prev_loc = loc //Just so we are sure prev_loc exists if(splatter_strength) src.splatter_strength = splatter_strength @@ -377,6 +464,8 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) /obj/effect/decal/cleanable/blood/hitsplatter/Destroy() if(isturf(loc) && !skip) playsound(src, 'sound/effects/wounds/splatter.ogg', 60, TRUE, -1) + if(!length(blood_dna_info)) + blood_dna_info = GET_ATOM_BLOOD_DNA(src) if(blood_dna_info) loc.add_blood_DNA(blood_dna_info) return ..() @@ -419,9 +508,11 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) if(line_type && isturf(loc)) var/obj/effect/decal/cleanable/line = locate(line_type) in loc if(line) + line.color = color line.add_blood_DNA(blood_dna_info) else line = new line_type(loc, get_dir(prev_loc, loc)) + line.color = color line.add_blood_DNA(blood_dna_info) line.alpha = 0 animate(line, alpha = initial(line.alpha), time = 2) @@ -454,6 +545,8 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) var/obj/effect/decal/cleanable/blood/splatter/over_window/final_splatter = new(prev_loc) final_splatter.pixel_x = (dir == EAST ? 32 : (dir == WEST ? -32 : 0)) final_splatter.pixel_y = (dir == NORTH ? 32 : (dir == SOUTH ? -32 : 0)) + final_splatter.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) + final_splatter.add_blood_DNA(blood_dna_info) else // This will only happen if prev_loc is not even a turf, which is highly unlikely. abstract_move(bumped_atom) qdel(src) @@ -463,6 +556,8 @@ GLOBAL_LIST_EMPTY(bloody_footprints_cache) if(!the_window.fulltile) return var/obj/effect/decal/cleanable/blood/splatter/over_window/final_splatter = new + final_splatter.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) + final_splatter.add_blood_DNA(blood_dna_info) final_splatter.forceMove(the_window) the_window.vis_contents += final_splatter the_window.bloodied = TRUE diff --git a/code/game/objects/effects/decals/cleanable/robots.dm b/code/game/objects/effects/decals/cleanable/robots.dm index d3af1e2846b0..4ba60142f57e 100644 --- a/code/game/objects/effects/decals/cleanable/robots.dm +++ b/code/game/objects/effects/decals/cleanable/robots.dm @@ -7,7 +7,6 @@ icon_state = "gib1" layer = LOW_OBJ_LAYER random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7") - blood_state = BLOOD_STATE_OIL bloodiness = BLOOD_AMOUNT_PER_DECAL mergeable_decal = FALSE beauty = -50 @@ -16,6 +15,7 @@ /obj/effect/decal/cleanable/robot_debris/Initialize(mapload) . = ..() RegisterSignal(src, COMSIG_MOVABLE_PIPE_EJECTING, PROC_REF(on_pipe_eject)) + add_blood_DNA(list("UNKNOWN DNA" = /datum/blood_type/oil)) /obj/effect/decal/cleanable/robot_debris/proc/streak(list/directions, mapload=FALSE) var/direction = pick(directions) @@ -76,29 +76,16 @@ icon = 'icons/mob/silicon/robots.dmi' icon_state = "floor1" random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7") - blood_state = BLOOD_STATE_OIL - bloodiness = BLOOD_AMOUNT_PER_DECAL + bloodiness = BLOOD_AMOUNT_PER_DECAL * 2 beauty = -100 clean_type = CLEAN_TYPE_BLOOD decal_reagent = /datum/reagent/fuel/oil reagent_amount = 30 -/obj/effect/decal/cleanable/oil/attackby(obj/item/I, mob/living/user) - var/attacked_by_hot_thing = I.get_temperature() - if(attacked_by_hot_thing) - user.visible_message(span_warning("[user] tries to ignite [src] with [I]!"), span_warning("You try to ignite [src] with [I].")) - log_combat(user, src, (attacked_by_hot_thing < 480) ? "tried to ignite" : "ignited", I) - fire_act(attacked_by_hot_thing) - return - return ..() - -/obj/effect/decal/cleanable/oil/fire_act(exposed_temperature, exposed_volume) - if(exposed_temperature < 480) - return - visible_message(span_danger("[src] catches fire!")) - var/turf/T = get_turf(src) - qdel(src) - new /obj/effect/hotspot(T) +/obj/effect/decal/cleanable/oil/Initialize(mapload, list/datum/disease/diseases) + . = ..() + AddElement(/datum/element/easy_ignite) + add_blood_DNA(list("UNKNOWN DNA" = /datum/blood_type/oil)) /obj/effect/decal/cleanable/oil/streak icon_state = "streak1" diff --git a/code/game/objects/effects/spawners/gibspawner.dm b/code/game/objects/effects/spawners/gibspawner.dm index 86dd2bac70bf..20ca27dbdd16 100644 --- a/code/game/objects/effects/spawners/gibspawner.dm +++ b/code/game/objects/effects/spawners/gibspawner.dm @@ -39,7 +39,7 @@ dna_to_add = temp_mob.get_blood_dna_list() qdel(temp_mob) else - dna_to_add = list("Non-human DNA" = random_blood_type()) //else, generate a random bloodtype for it. + dna_to_add = list("UNKNOWN DNA" = random_human_blood_type()) //else, generate a random bloodtype for it. for(var/i in 1 to gibtypes.len) diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm index d03cfea3f178..168a3f9b0883 100644 --- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm +++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm @@ -73,9 +73,6 @@ target_pixel_y = 8 animate(src, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = duration) -/obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter - splatter_type = "xsplatter" - /obj/effect/temp_visual/dir_setting/speedbike_trail name = "speedbike trails" icon_state = "ion_fade" diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index ce8694270287..cd2ee2766e41 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -110,13 +110,11 @@ ///Whether spessmen with an ID with an age below AGE_MINOR (20 by default) can buy this item var/age_restricted = FALSE - ///flags which determine which body parts are protected from heat. [See here][HEAD] - var/heat_protection = 0 - ///flags which determine which body parts are protected from cold. [See here][HEAD] - var/cold_protection = 0 - ///Set this variable to determine up to which temperature (IN KELVIN) the item protects against heat damage. Keep at null to disable protection. Only protects areas set by heat_protection flags + /// Set this variable to determine up to which temperature (IN KELVIN) the item protects against heat damage. + /// Keep at null to disable protection. var/max_heat_protection_temperature - ///Set this variable to determine down to which temperature (IN KELVIN) the item protects against cold damage. 0 is NOT an acceptable number due to if(varname) tests!! Keep at null to disable protection. Only protects areas set by cold_protection flags + /// Set this variable to determine down to which temperature (IN KELVIN) the item protects against cold damage. + /// Keep at null to disable protection. var/min_cold_protection_temperature ///list of /datum/action's that this item has. diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index e65fcf02d60d..5ea51789a3c3 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -937,12 +937,8 @@ CIGARETTE PACKETS ARE IN FANCY.DM var/mob/living/carbon/human/human_user = user if(!istype(human_user) || HAS_TRAIT(human_user, TRAIT_RESISTHEAT) || HAS_TRAIT(human_user, TRAIT_RESISTHEATHANDS)) hand_protected = TRUE - else if(!istype(human_user.gloves, /obj/item/clothing/gloves)) - hand_protected = FALSE else - var/obj/item/clothing/gloves/gloves = human_user.gloves - if(gloves.max_heat_protection_temperature) - hand_protected = (gloves.max_heat_protection_temperature > 360) + hand_protected = human_user.gloves?.max_heat_protection_temperature > 360 if(hand_protected || prob(75)) user.visible_message( diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm index f5ef78a60c98..2ac05c111337 100644 --- a/code/game/objects/items/devices/chameleonproj.dm +++ b/code/game/objects/items/devices/chameleonproj.dm @@ -152,22 +152,10 @@ if(!isturf(loc) || isspaceturf(loc) || !direction) return //No magical movement! Trust me, this bad boy can do things like leap out of pipes if you're not careful - if(can_move < world.time) - var/amount - switch(user.bodytemperature) - if(300 to INFINITY) - amount = 10 - if(295 to 300) - amount = 13 - if(280 to 295) - amount = 16 - if(260 to 280) - amount = 20 - else - amount = 25 - - can_move = world.time + amount - try_step_multiz(direction) + if(can_move >= world.time) + return + can_move = world.time + 2 + (user.cached_multiplicative_slowdown * 4) // Fake movement speed calculating based on the mob's move speed + try_step_multiz(direction) return /obj/effect/dummy/chameleon/Destroy() diff --git a/code/game/objects/items/devices/scanners/health_analyzer.dm b/code/game/objects/items/devices/scanners/health_analyzer.dm index 1d18aefec183..0113ff4d393b 100644 --- a/code/game/objects/items/devices/scanners/health_analyzer.dm +++ b/code/game/objects/items/devices/scanners/health_analyzer.dm @@ -270,51 +270,62 @@ if(ishuman(target)) var/mob/living/carbon/human/humantarget = target - // Organ damage, missing organs - if(humantarget.organs && humantarget.organs.len) - var/render = FALSE - var/toReport = "Organs:\ - \ - \ - [advanced ? "" : ""]\ - " - - for(var/obj/item/organ/organ as anything in humantarget.organs) - var/status = organ.get_status_text() - if (status != "") + var/render = FALSE + var/toReport = "Organ status:\ + \ +
Organ:DmgStatus
\ + \ + \ + [advanced ? "" : ""]\ + \ + " + + var/list/missing_organs = list() + if(!humantarget.get_organ_slot(ORGAN_SLOT_BRAIN)) + missing_organs[ORGAN_SLOT_BRAIN] = "Brain" + if(!humantarget.needs_heart() && !humantarget.get_organ_slot(ORGAN_SLOT_HEART)) + missing_organs[ORGAN_SLOT_HEART] = "Heart" + if(!HAS_TRAIT_FROM(humantarget, TRAIT_NOBREATH, SPECIES_TRAIT) && !isnull(humantarget.dna.species.mutantlungs) && !humantarget.get_organ_slot(ORGAN_SLOT_LUNGS)) + missing_organs[ORGAN_SLOT_LUNGS] = "Lungs" + if(!HAS_TRAIT_FROM(humantarget, TRAIT_LIVERLESS_METABOLISM, SPECIES_TRAIT) && !isnull(humantarget.dna.species.mutantliver) && !humantarget.get_organ_slot(ORGAN_SLOT_LIVER)) + missing_organs[ORGAN_SLOT_LIVER] = "Liver" + if(!HAS_TRAIT_FROM(humantarget, TRAIT_NOHUNGER, SPECIES_TRAIT) && !isnull(humantarget.dna.species.mutantstomach) && !humantarget.get_organ_slot(ORGAN_SLOT_STOMACH)) + missing_organs[ORGAN_SLOT_STOMACH] ="Stomach" + if(!isnull(humantarget.dna.species.mutanttongue) && !humantarget.get_organ_slot(ORGAN_SLOT_TONGUE)) + missing_organs[ORGAN_SLOT_TONGUE] = "Tongue" + if(!isnull(humantarget.dna.species.mutantears) && !humantarget.get_organ_slot(ORGAN_SLOT_EARS)) + missing_organs[ORGAN_SLOT_EARS] = "Ears" + if(!isnull(humantarget.dna.species.mutantears) && !humantarget.get_organ_slot(ORGAN_SLOT_EYES)) + missing_organs[ORGAN_SLOT_EYES] = "Eyes" + + // Follow same order as in the organ_process_order so it's consistent across all humans + for(var/sorted_slot in GLOB.organ_process_order) + var/obj/item/organ/organ = humantarget.get_organ_slot(sorted_slot) + if(isnull(organ)) + if(missing_organs[sorted_slot]) render = TRUE - toReport += "\ - [advanced ? "" : ""]\ - " - - var/datum/species/the_dudes_species = humantarget.dna.species - var/missing_organs = list() - if(!humantarget.get_organ_slot(ORGAN_SLOT_BRAIN)) - missing_organs += "brain" - if(!HAS_TRAIT(humantarget, TRAIT_NOBLOOD) && !humantarget.get_organ_slot(ORGAN_SLOT_HEART)) - missing_organs += "heart" - if(!(TRAIT_NOBREATH in the_dudes_species.inherent_traits) && !humantarget.get_organ_slot(ORGAN_SLOT_LUNGS)) - missing_organs += "lungs" - if(!(TRAIT_NOMETABOLISM in the_dudes_species.inherent_traits) && !humantarget.get_organ_slot(ORGAN_SLOT_LIVER)) - missing_organs += "liver" - if(the_dudes_species.mutantstomach && !humantarget.get_organ_slot(ORGAN_SLOT_STOMACH)) - missing_organs += "stomach" - if(the_dudes_species.mutanttongue && !humantarget.get_organ_slot(ORGAN_SLOT_TONGUE)) - missing_organs += "tongue" - if(!humantarget.get_organ_slot(ORGAN_SLOT_EARS)) - missing_organs += "ears" - if(!humantarget.get_organ_slot(ORGAN_SLOT_EYES)) - missing_organs += "eyes" - - if(length(missing_organs)) + toReport += "\ + [advanced ? "" : ""]\ + " + continue + if(mode != SCANNER_VERBOSE && !organ.show_on_condensed_scans()) + continue + var/status = organ.get_status_text(advanced, tochat) + var/appendix = organ.get_status_appendix(advanced, tochat) + if(status || appendix) + status ||= "OK" // otherwise flawless organs have no status reported by default render = TRUE - for(var/organ in missing_organs) - toReport += "\ - [advanced ? "" : ""]\ - " - - if(render) - render_list += toReport + "
Organ:DmgStatus
[organ.name]:[CEILING(organ.damage,1)][status]
[missing_organs[sorted_slot]]:-Missing
[organ]:["-"]["Missing"]
" // tables do not need extra linebreak + toReport += "\ + [capitalize(organ.name)]:\ + [advanced ? "[organ.damage > 0 ? ceil(organ.damage) : "0"]" : ""]\ + [status]\ + " + if(appendix) + toReport += "↳ [appendix]" + + if(render) + render_list += "
" + render_list += toReport + "
" // tables do not need extra linebreak //Genetic stability if(advanced && humantarget.has_dna()) @@ -335,18 +346,19 @@ || istype(humantarget.get_organ_slot(ORGAN_SLOT_EXTERNAL_WINGS), /obj/item/organ/external/wings/functional) render_list += "Species: [targetspecies.name][mutant ? "-derived mutant" : ""]\n" - var/core_temperature_message = "Core temperature: [round(humantarget.coretemperature-T0C, 0.1)] °C ([round(humantarget.coretemperature*1.8-459.67,0.1)] °F)" - if(humantarget.coretemperature >= humantarget.get_body_temp_heat_damage_limit()) - render_list += "☼ [core_temperature_message] ☼\n" - else if(humantarget.coretemperature <= humantarget.get_body_temp_cold_damage_limit()) - render_list += "❄ [core_temperature_message] ❄\n" - else - render_list += "[core_temperature_message]\n" + var/skin_temp = target.get_skin_temperature() + var/skin_temperature_message = "Skin temperature: [round(KELVIN_TO_CELCIUS(skin_temp), 0.1)] °C ([round(KELVIN_TO_FAHRENHEIT(skin_temp), 0.1)] °F)" + if(skin_temp >= target.bodytemp_heat_damage_limit) + render_list += "☼ [skin_temperature_message] ☼\n" + else if(skin_temp <= target.bodytemp_cold_damage_limit) + render_list += "❄ [skin_temperature_message] ❄\n" + else + render_list += "[skin_temperature_message]\n" - var/body_temperature_message = "Body temperature: [round(target.bodytemperature-T0C, 0.1)] °C ([round(target.bodytemperature*1.8-459.67,0.1)] °F)" - if(target.bodytemperature >= target.get_body_temp_heat_damage_limit()) + var/body_temperature_message = "Body temperature: [round(KELVIN_TO_CELCIUS(target.bodytemperature), 0.1)] °C ([round(KELVIN_TO_FAHRENHEIT(target.bodytemperature), 0.1)] °F)" + if(target.bodytemperature >= target.bodytemp_heat_damage_limit) render_list += "☼ [body_temperature_message] ☼\n" - else if(target.bodytemperature <= target.get_body_temp_cold_damage_limit()) + else if(target.bodytemperature <= target.bodytemp_cold_damage_limit) render_list += "❄ [body_temperature_message] ❄\n" else render_list += "[body_temperature_message]\n" @@ -379,23 +391,20 @@ " // divs do not need extra linebreak */ // Blood Level - if(target.has_dna()) - var/mob/living/carbon/carbontarget = target - var/blood_id = carbontarget.get_blood_id() - if(blood_id) - if(carbontarget.is_bleeding()) + // NON-MODULE CHANGE + if(target.has_dna() && target.get_blood_type()) + if(iscarbon(target)) + var/mob/living/carbon/bleeder = target + if(bleeder.is_bleeding()) render_list += "Subject is bleeding!\n" - var/blood_percent = round((carbontarget.blood_volume / BLOOD_VOLUME_NORMAL) * 100) - var/blood_type = carbontarget.dna.blood_type - if(blood_id != /datum/reagent/blood) // special blood substance - var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id] - blood_type = R ? R.name : blood_id - if(carbontarget.blood_volume <= BLOOD_VOLUME_SAFE && carbontarget.blood_volume > BLOOD_VOLUME_OKAY) - render_list += "Blood level: LOW [blood_percent] %, [carbontarget.blood_volume] cl, [span_info("type: [blood_type]")]\n" - else if(carbontarget.blood_volume <= BLOOD_VOLUME_OKAY) - render_list += "Blood level: CRITICAL [blood_percent] %, [carbontarget.blood_volume] cl, [span_info("type: [blood_type]")]\n" - else - render_list += "Blood level: [blood_percent] %, [carbontarget.blood_volume] cl, type: [blood_type]\n" + var/blood_percent = round((target.blood_volume / BLOOD_VOLUME_NORMAL) * 100) + var/blood_type = "[target.get_blood_type() || "None"]" + if(target.blood_volume <= BLOOD_VOLUME_SAFE && target.blood_volume > BLOOD_VOLUME_OKAY) + render_list += "Blood level: LOW [blood_percent] %, [target.blood_volume] cl, [span_info("type: [blood_type]")]\n" + else if(target.blood_volume <= BLOOD_VOLUME_OKAY) + render_list += "Blood level: CRITICAL [blood_percent] %, [target.blood_volume] cl, [span_info("type: [blood_type]")]\n" + else + render_list += "Blood level: [blood_percent] %, [target.blood_volume] cl, type: [blood_type]\n" // Cybernetics if(iscarbon(target)) @@ -510,11 +519,9 @@ var/render_list = "" var/advised = FALSE - for(var/limb in patient.get_wounded_bodyparts()) - var/obj/item/bodypart/wounded_part = limb - render_list += "Warning: Physical trauma[LAZYLEN(wounded_part.wounds) > 1? "s" : ""] detected in [wounded_part.name]" - for(var/limb_wound in wounded_part.wounds) - var/datum/wound/current_wound = limb_wound + for(var/obj/item/bodypart/wounded_part as anything in patient.get_wounded_bodyparts()) + render_list += "Warning: Physical trauma[LAZYLEN(wounded_part.wounds) > 1? "s" : ""] detected in [wounded_part.plaintext_zone]" + for(var/datum/wound/current_wound as anything in wounded_part.wounds) render_list += "
[simple_scan ? current_wound.get_simple_scanner_description() : current_wound.get_scanner_description()]
\n" if (scanner.give_wound_treatment_bonus) ADD_TRAIT(current_wound, TRAIT_WOUND_SCANNED, ANALYZER_TRAIT) diff --git a/code/game/objects/items/dna_injector.dm b/code/game/objects/items/dna_injector.dm index 9bf31fa4158b..2b4b24787326 100644 --- a/code/game/objects/items/dna_injector.dm +++ b/code/game/objects/items/dna_injector.dm @@ -57,7 +57,7 @@ target.real_name = fields["name"] target.dna.unique_enzymes = fields["UE"] target.name = target.real_name - target.dna.blood_type = fields["blood_type"] + target.dna.human_blood_type = blood_name_to_blood_type(fields["blood_type"]) if(fields["UI"]) //UI+UE target.dna.unique_identity = merge_text(target.dna.unique_identity, fields["UI"]) if(fields["UF"]) @@ -131,11 +131,11 @@ if(!target.dna.previous["UE"]) target.dna.previous["UE"] = target.dna.unique_enzymes if(!target.dna.previous["blood_type"]) - target.dna.previous["blood_type"] = target.dna.blood_type + target.dna.previous["blood_type"] = "[initial(target.dna.human_blood_type.name)]" target.real_name = fields["name"] target.dna.unique_enzymes = fields["UE"] target.name = target.real_name - target.dna.blood_type = fields["blood_type"] + target.dna.human_blood_type = blood_name_to_blood_type(fields["blood_type"]) target.dna.temporary_mutations[UE_CHANGED] = endtime if(fields["UI"]) //UI+UE if(!target.dna.previous["UI"]) diff --git a/code/game/objects/items/food/pastries.dm b/code/game/objects/items/food/pastries.dm index 94babd0cf901..aa88a9448bd4 100644 --- a/code/game/objects/items/food/pastries.dm +++ b/code/game/objects/items/food/pastries.dm @@ -45,10 +45,10 @@ /obj/item/food/muffin/moffin/examine(mob/user) . = ..() - if(!ishuman(user)) + if(!isliving(user)) return - var/mob/living/carbon/human/moffin_observer = user - if(moffin_observer.dna.species.liked_food & CLOTH) + var/mob/living/moffin_observer = user + if(moffin_observer.get_liked_foodtypes() & CLOTH) . += span_nicegreen("Ooh! It's even got bits of clothes on it! Yummy!") else . += span_warning("You're not too sure what's on top though...") diff --git a/code/game/objects/items/grenades/syndieminibomb.dm b/code/game/objects/items/grenades/syndieminibomb.dm index f7d63e2ed9fe..0044e996eb5e 100644 --- a/code/game/objects/items/grenades/syndieminibomb.dm +++ b/code/game/objects/items/grenades/syndieminibomb.dm @@ -60,7 +60,7 @@ var/rad_range = 4 var/rad_threshold = RAD_EXTREME_INSULATION var/stamina_damage = 30 - var/temp_adjust = -230 + var/temp_adjust = 230 /obj/item/grenade/gluon/detonate(mob/living/lanced_by) . = ..() @@ -74,5 +74,5 @@ floor.MakeSlippery(TURF_WET_PERMAFROST, 6 MINUTES) for(var/mob/living/carbon/victim in floor) victim.stamina.adjust(-stamina_damage) - victim.adjust_bodytemperature(temp_adjust) + victim.adjust_bodytemperature(victim.bodytemperature - temp_adjust, use_insulation = TRUE) qdel(src) diff --git a/code/game/objects/items/implants/implant_explosive.dm b/code/game/objects/items/implants/implant_explosive.dm index 528da0a40de6..9c3706355ee6 100644 --- a/code/game/objects/items/implants/implant_explosive.dm +++ b/code/game/objects/items/implants/implant_explosive.dm @@ -58,7 +58,7 @@ explosion(src, devastation_range = heavy, heavy_impact_range = medium, light_impact_range = weak, flame_range = weak, flash_range = weak, explosion_cause = src) if(imp_in) imp_in.investigate_log("has been gibbed by an explosive implant.", INVESTIGATE_DEATHS) - imp_in.gib(TRUE) + imp_in.gib(TRUE, safe_gib = FALSE) qdel(src) return timed_explosion() diff --git a/code/game/objects/items/melee/baton.dm b/code/game/objects/items/melee/baton.dm index d06b0067de24..e17e1af4fc55 100644 --- a/code/game/objects/items/melee/baton.dm +++ b/code/game/objects/items/melee/baton.dm @@ -136,7 +136,7 @@ if(!chunky_finger_usable && ishuman(user)) var/mob/living/carbon/human/potential_chunky_finger_human = user - if(potential_chunky_finger_human.check_chunky_fingers() && user.is_holding(src) && !HAS_MIND_TRAIT(user, TRAIT_CHUNKYFINGERS_IGNORE_BATON)) + if(user.is_holding(src) && HAS_TRAIT(potential_chunky_finger_human, TRAIT_CHUNKYFINGERS) && !HAS_MIND_TRAIT(user, TRAIT_CHUNKYFINGERS_IGNORE_BATON)) balloon_alert(potential_chunky_finger_human, "fingers are too big!") return BATON_ATTACK_DONE diff --git a/code/game/objects/items/pillow.dm b/code/game/objects/items/pillow.dm index 4bd54aa2e541..a6582d47fb22 100644 --- a/code/game/objects/items/pillow.dm +++ b/code/game/objects/items/pillow.dm @@ -124,7 +124,7 @@ name = "pillow suit" desc = "Part man, part pillow. All CARNAGE!" body_parts_covered = CHEST|GROIN|ARMS|LEGS|FEET - cold_protection = CHEST|GROIN|ARMS|LEGS //a pillow suit must be hella warm + //a pillow suit must be hella warm allowed = list(/obj/item/pillow) //moar pillow carnage icon = 'icons/obj/pillow.dmi' worn_icon = 'icons/mob/clothing/suits/pillow.dmi' diff --git a/code/game/objects/items/religion.dm b/code/game/objects/items/religion.dm index beda3ca18a39..037c0aeeee37 100644 --- a/code/game/objects/items/religion.dm +++ b/code/game/objects/items/religion.dm @@ -360,9 +360,9 @@ icon_state = "crusader" desc = "They're like gloves, but made of metal." siemens_coefficient = 0 - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT /obj/item/clothing/gloves/plate/red @@ -378,9 +378,9 @@ w_class = WEIGHT_CLASS_NORMAL armor_type = /datum/armor/shoes_plate clothing_traits = list(TRAIT_NO_SLIP_WATER) - cold_protection = FEET + min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT - heat_protection = FEET + max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT /datum/armor/shoes_plate diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 41e2b77399fb..376dc4a72400 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -15,6 +15,8 @@ cost = 250 source = /datum/robot_energy_storage/medical merge_type = /obj/item/stack/medical + /// Sound played when heal doafter begins + var/heal_sound /// How long it takes to apply it to yourself var/self_delay = 5 SECONDS /// How long it takes to apply it to someone else @@ -62,6 +64,8 @@ /obj/item/stack/medical/proc/try_heal(mob/living/patient, mob/user, silent = FALSE) if(!patient.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE)) return + if(heal_sound) + playsound(patient, heal_sound, 33, FALSE) if(patient == user) if(!silent) user.visible_message(span_notice("[user] starts to apply [src] on [user.p_them()]self..."), span_notice("You begin applying [src] on yourself...")) @@ -162,6 +166,48 @@ splint_factor = 0.7 burn_cleanliness_bonus = 0.35 merge_type = /obj/item/stack/medical/gauze + /// tracks how many times we've been scrubbed thoroughly + var/times_cleaned = 0 + +/obj/item/stack/medical/gauze/update_name(updates) + . = ..() + var/base_cap = initial(absorption_capacity) + if(!base_cap) + return + + if(absorption_capacity <= 0) + name = "used [initial(name)]" + else if(absorption_capacity <= base_cap * 0.2) + name = "dirty [initial(name)]" + else if(absorption_capacity <= base_cap * 0.8) + name = "worn [initial(name)]" + else + name = initial(name) + +/obj/item/stack/medical/gauze/can_merge(obj/item/stack/medical/gauze/check, inhand) + . = ..() + if(!.) + return . + // need to be in +- 0.5 dirtiness of each other + // otherwise you can merge a completely used bandage with a brand new one, which would magically unuse it + if(check.absorption_capacity < absorption_capacity - 0.25 || check.absorption_capacity > absorption_capacity + 0.25) + return FALSE + return . + +/obj/item/stack/medical/gauze/wash(clean_types) + . = ..() + if(.) + return . + if(!(clean_types & CLEAN_TYPE_HARD_DECAL)) // gotta scrub realllly hard to clean gauze + return . + times_cleaned += 1 + var/clean_to = initial(absorption_capacity) * (3 / (times_cleaned + 3)) + if(absorption_capacity < clean_to) + absorption_capacity = clean_to + update_appearance(UPDATE_NAME) + . = TRUE + + return . // gauze is only relevant for wounds, which are handled in the wounds themselves /obj/item/stack/medical/gauze/try_heal(mob/living/patient, mob/user, silent) @@ -170,40 +216,62 @@ var/obj/item/bodypart/limb = patient.get_bodypart(check_zone(user.zone_selected)) if(!limb) - patient.balloon_alert(user, "missing limb!") - return - if(!LAZYLEN(limb.wounds)) - patient.balloon_alert(user, "no wounds!") // good problem to have imo - return - - var/gauzeable_wound = FALSE - var/datum/wound/woundies - for(var/i in limb.wounds) - woundies = i - if(woundies.wound_flags & ACCEPTS_GAUZE) - gauzeable_wound = TRUE - break - if(!gauzeable_wound) - patient.balloon_alert(user, "can't heal those!") + patient.balloon_alert(user, "no limb!") return if(limb.current_gauze && (limb.current_gauze.absorption_capacity * 1.2 > absorption_capacity)) // ignore if our new wrap is < 20% better than the current one, so someone doesn't bandage it 5 times in a row patient.balloon_alert(user, pick("already bandaged!", "bandage is clean!")) // good enough return - if(HAS_TRAIT(woundies, TRAIT_WOUND_SCANNED)) + var/boosted = FALSE + if(LAZYLEN(limb.wounds)) + for(var/datum/wound/wound as anything in limb.wounds) + if(HAS_TRAIT(wound, TRAIT_WOUND_SCANNED)) + boosted = TRUE + break + else + // gives you extra time so you realize you're not treating a wound + treatment_delay *= 2 + + var/whose = user == patient ? "your" : "[patient]'s" + var/theirs = user == patient ? patient.p_their() : "[patient]'s" + var/wrap_or_replace = limb.current_gauze ? "replacing [limb.current_gauze] on" : "wrapping" + var/with_what = limb.current_gauze?.type == type ? "more of [src]" : src + if(boosted) treatment_delay *= 0.5 - if(user == patient) - to_chat(user, span_notice("You keep in mind the indications from the holo-image about your injury, and expertly begin wrapping your wounds with [src].")) - else - user.visible_message(span_warning("[user] begins expertly wrapping the wounds on [patient]'s [limb.plaintext_zone] with [src]..."), span_warning("You begin quickly wrapping the wounds on [patient]'s [limb.plaintext_zone] with [src], keeping the holo-image indications in mind...")) + user.visible_message( + span_notice("[user] begins expertly [wrap_or_replace] [theirs] [limb.plaintext_zone] with [with_what]."), + span_notice("You begin quickly [wrap_or_replace] [whose] [limb.plaintext_zone] with [with_what], keeping the holo-image indications in mind..."), + ) else - user.visible_message(span_warning("[user] begins wrapping the wounds on [patient]'s [limb.plaintext_zone] with [src]..."), span_warning("You begin wrapping the wounds on [user == patient ? "your" : "[patient]'s"] [limb.plaintext_zone] with [src]...")) + user.visible_message( + span_notice("[user] begins [wrap_or_replace] [theirs] [limb.plaintext_zone] with [with_what]."), + span_notice("You begin [wrap_or_replace] [whose] [limb.plaintext_zone] with [with_what]..."), + ) + user.balloon_alert(user, "applying gauze...") + if(user != patient) + user.balloon_alert(patient, "applying gauze...") + + playsound(patient, pick( + 'monkestation/sound/items/rip1.ogg', + 'monkestation/sound/items/rip2.ogg', + 'monkestation/sound/items/rip3.ogg', + 'monkestation/sound/items/rip4.ogg', + ), 33) if(!do_after(user, treatment_delay, target = patient)) + user.balloon_alert(user, "interrupted!") return - - user.visible_message("[user] applies [src] to [patient]'s [limb.plaintext_zone].", "You bandage the wounds on [user == patient ? "your" : "[patient]'s"] [limb.plaintext_zone].") + if(limb.current_gauze && (limb.current_gauze.absorption_capacity * 1.2 > absorption_capacity)) // double check for sanity + return + user.balloon_alert(user, "gauze applied") + if(user != patient) + user.balloon_alert(patient, "gauze applied") + + user.visible_message( + span_infoplain(span_green("[user] applies [src] to [theirs] [limb.plaintext_zone].")), + span_infoplain(span_green("You [limb.current_gauze?.type == type ? "replace" : "bandage"] the wounds on [whose] [limb.plaintext_zone].")), + ) limb.apply_gauze(src) /obj/item/stack/medical/gauze/twelve @@ -266,6 +334,7 @@ stop_bleeding = 0.6 grind_results = list(/datum/reagent/medicine/antipathogenic/spaceacillin = 2) merge_type = /obj/item/stack/medical/suture + heal_sound = 'monkestation/sound/items/snip.ogg' /obj/item/stack/medical/suture/emergency name = "emergency suture" diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 517a05a58ee7..32bb9ef266a4 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -338,6 +338,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \ new/datum/stack_recipe("ore box", /obj/structure/ore_box, 4, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_CONTAINERS),\ new/datum/stack_recipe("wooden crate", /obj/structure/closet/crate/wooden, 6, time = 5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_FURNITURE),\ new/datum/stack_recipe("baseball bat", /obj/item/melee/baseball_bat, 5, time = 1.5 SECONDS, check_density = FALSE, category = CAT_WEAPON_MELEE),\ + new/datum/stack_recipe("wooden crutch", /obj/item/cane/crutch/wood, 5, time = 1.5 SECONDS, check_density = FALSE, category = CAT_WEAPON_MELEE),\ new/datum/stack_recipe("loom", /obj/structure/loom, 10, time = 1.5 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, category = CAT_TOOLS), \ new/datum/stack_recipe("mortar", /obj/item/reagent_containers/cup/mortar, 3, category = CAT_CHEMISTRY), \ new/datum/stack_recipe("firebrand", /obj/item/match/firebrand, 2, time = 10 SECONDS, category = CAT_TOOLS), \ diff --git a/code/game/objects/items/storage/holsters.dm b/code/game/objects/items/storage/holsters.dm index 75f1e8b500b0..3c8fdb54e80c 100644 --- a/code/game/objects/items/storage/holsters.dm +++ b/code/game/objects/items/storage/holsters.dm @@ -26,6 +26,7 @@ /obj/item/gun/ballistic/revolver, /obj/item/gun/energy/e_gun/mini, /obj/item/gun/energy/disabler, + /obj/item/gun/energy/taser, /obj/item/gun/energy/dueling, /obj/item/food/grown/banana, /obj/item/gun/energy/laser/thermal, @@ -45,6 +46,7 @@ atom_storage.set_holdable(list( /obj/item/gun/energy/e_gun/mini, /obj/item/gun/energy/disabler, + /obj/item/gun/energy/taser, /obj/item/gun/energy/dueling, /obj/item/food/grown/banana, /obj/item/gun/energy/laser/thermal, @@ -102,6 +104,7 @@ /obj/item/ammo_box/magazine/toy/pistol, /obj/item/gun/energy/e_gun/mini, /obj/item/gun/energy/disabler, + /obj/item/gun/energy/taser, /obj/item/gun/energy/dueling, /obj/item/gun/energy/laser/thermal, /obj/item/gun/energy/laser/captain, @@ -179,6 +182,7 @@ /obj/item/gun/energy/recharge/ebow, /obj/item/gun/energy/e_gun/mini, /obj/item/gun/energy/disabler, + /obj/item/gun/energy/taser, /obj/item/gun/energy/dueling, /obj/item/gun/energy/laser/captain, /obj/item/gun/energy/e_gun/hos, diff --git a/code/game/objects/items/storage/medkit.dm b/code/game/objects/items/storage/medkit.dm index 9b5c734a3a95..2c83e9dfc054 100644 --- a/code/game/objects/items/storage/medkit.dm +++ b/code/game/objects/items/storage/medkit.dm @@ -717,7 +717,7 @@ user.visible_message(span_suicide("[user] is beating [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")) return BRUTELOSS user.visible_message(span_suicide("[user] is putting [user.p_their()] head inside the [src], it looks like [user.p_theyre()] trying to commit suicide!")) - user.adjust_bodytemperature(-300) + user.adjust_bodytemperature(-INFINITY, min_temp = CELCIUS_TO_KELVIN(10 CELCIUS)) user.apply_status_effect(/datum/status_effect/freon) return FIRELOSS diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index 5e0e5b1c4092..90d2e616de9a 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -493,6 +493,21 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 custom_materials = list(/datum/material/iron= SMALL_MATERIAL_AMOUNT * 0.5) attack_verb_continuous = list("bludgeons", "whacks", "disciplines", "thrashes") attack_verb_simple = list("bludgeon", "whack", "discipline", "thrash") + /// Only exists so the white cane doesn't spawn with its "effects" while unextended + var/start_with_effects = TRUE + +/obj/item/cane/Initialize(mapload) + . = ..() + if(start_with_effects) + add_effects() + +/obj/item/cane/proc/add_effects() + ADD_TRAIT(src, TRAIT_BLIND_TOOL, INNATE_TRAIT) + AddComponent(/datum/component/limbless_aid) + +/obj/item/cane/proc/remove_effects() + REMOVE_TRAIT(src, TRAIT_BLIND_TOOL, INNATE_TRAIT) + qdel(GetComponent(/datum/component/limbless_aid)) /obj/item/cane/white name = "white cane" @@ -504,6 +519,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 force = 1 w_class = WEIGHT_CLASS_SMALL custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 6) + start_with_effects = FALSE /obj/item/cane/white/Initialize(mapload) . = ..() @@ -527,6 +543,11 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 /obj/item/cane/white/proc/on_transform(obj/item/source, mob/user, active) SIGNAL_HANDLER + if(active) + add_effects() + else + remove_effects() + if(user) balloon_alert(user, active ? "extended" : "collapsed") playsound(src, 'sound/weapons/batonextend.ogg', 50, TRUE) diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 66f7b9b07e90..cf51a4c983ae 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -1,7 +1,85 @@ /obj/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) - ..() - take_damage(AM.throwforce, BRUTE, MELEE, 1, get_dir(src, AM)) + . = ..() + if(QDELETED(src)) + return + hit_by_damage(AM, throwingdatum) + +/obj/proc/hit_by_damage(atom/movable/hitting_us, datum/thrownthing/throwingdatum) + var/base_dam = hitting_us.throwforce + if(isliving(hitting_us)) + var/mob/living/living_mob = hitting_us + var/speed_bonus = throwingdatum.speed - living_mob.throw_speed + if(speed_bonus > 0) + base_dam += (5 * speed_bonus) + base_dam += (5 * max(0, living_mob.mob_size - 1)) + if(isitem(hitting_us)) + var/obj/item/hit_item = hitting_us + base_dam += (5 * max(0, hit_item.w_class - 2)) + + // no armor penetration + take_damage(base_dam, BRUTE, MELEE, TRUE, get_dir(src, hitting_us), 0) + +/obj/structure/window/Initialize(mapload, direct) + . = ..() + +/obj/structure/window/Cross(atom/movable/crossed_atom) + . = ..() + if(.) + return . + if(!isliving(crossed_atom) || QDELETED(crossed_atom.throwing)) + return . + if(anchored && get_integrity_percentage() > 0.5) + return . + + var/turf/old_loc = loc + + take_damage(INFINITY, BRUTE, MELEE, TRUE, get_dir(src, crossed_atom), 0) + + if(!QDELETED(src)) + return . + + var/mob/living/defenestrated = crossed_atom + var/has_grille = locate(/obj/structure/grille) in old_loc + var/list/obj/item/shards = list() + for(var/obj/item/shard/shard in old_loc) + shards += shard + + for(var/zone in shuffle(BODY_ZONES_ALL)) + var/obj/item/bodypart/part = defenestrated.get_bodypart(zone) + if(!part) + continue + if(has_grille && prob(66)) + continue + + defenestrated.apply_damage(10, BRUTE, part, blocked = min(90, defenestrated.getarmor(part, MELEE)), sharpness = SHARP_POINTY, wound_bonus = 4, bare_wound_bonus = 8, attacking_item = (length(shards) ? shards[1] : "glass")) + if(prob(25 * length(shards)) && shards[1].tryEmbed(part, TRUE)) + shards -= shards[1] + + if(has_grille) + defenestrated.Paralyze(1 SECONDS) + defenestrated.Knockdown(2 SECONDS) + defenestrated.visible_message( + span_danger("[defenestrated] is thrown against [src], shattering it!"), + span_userdanger("You are thrown against [src], shattering it!"), + ) + + else + defenestrated.Paralyze(3 SECONDS) + defenestrated.Knockdown(6 SECONDS) + defenestrated.visible_message( + span_danger("[defenestrated] is thrown clean through [src]!"), + span_userdanger("You are thrown clean through [src]!"), + ) + + return TRUE + +/obj/structure/window/hit_by_damage(atom/movable/hitting_us, datum/thrownthing/throwingdatum) + if(reinf || !isliving(hitting_us)) + return ..() + + // take a lot of damage from being hit with a mob - so we can defenestrate + take_damage(max_integrity * min(0.75, (get_armor_rating(MELEE) / 100)), BRUTE, MELEE, TRUE, get_dir(src, hitting_us), 0) /obj/ex_act(severity, target) if(resistance_flags & INDESTRUCTIBLE) @@ -41,12 +119,26 @@ ) if(hitting_projectile.suppressed != SUPPRESSED_VERY) visible_message( - span_danger("[src] is hit by \a [hitting_projectile][damage_sustained ? "" : ", without leaving a mark"]!"), + span_danger("[src] is hit by \a [hitting_projectile.generic_name || hitting_projectile][damage_sustained ? "" : ", without leaving a mark"]!"), vision_distance = COMBAT_MESSAGE_RANGE, ) return damage_sustained > 0 ? BULLET_ACT_HIT : BULLET_ACT_BLOCK +/obj/structure/window/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit) + // don't smack the window and its grille same turf, ever + for(var/obj/structure/grille/grille in loc) + hitting_projectile.impacted[grille] = TRUE + + . = ..() + if(QDELETED(hitting_projectile) || . != BULLET_ACT_HIT) + return . + if(QDELETED(src) && prob(80)) + // right through the window! + return BULLET_ACT_FORCE_PIERCE + return . + + /obj/attack_hulk(mob/living/carbon/human/user) ..() if(density) diff --git a/code/game/objects/structures/dresser.dm b/code/game/objects/structures/dresser.dm index fcc62fb834f6..67e1c896bd25 100644 --- a/code/game/objects/structures/dresser.dm +++ b/code/game/objects/structures/dresser.dm @@ -31,8 +31,8 @@ return var/mob/living/carbon/human/dressing_human = user - if(dressing_human.dna && dressing_human.dna.species && (NO_UNDERWEAR in dressing_human.dna.species.species_traits)) - to_chat(user, span_warning("You are not capable of wearing underwear.")) + if(HAS_TRAIT(dressing_human, TRAIT_NO_UNDERWEAR)) + to_chat(dressing_human, span_warning("You are not capable of wearing underwear.")) return var/choice = tgui_input_list(user, "Underwear, Undershirt, or Socks?", "Changing", list("Underwear","Underwear Color","Undershirt","Socks", "Socks Color")) //MONKESTATION EDIT diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index b046313eff72..1ca03747f56a 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -212,22 +212,22 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror, 28) var/datum/species/newrace = selectable_races[racechoice] amazed_human.set_species(newrace, icon_update = FALSE) - if(amazed_human.dna.species.use_skintones) + if(HAS_TRAIT(amazed_human, TRAIT_USES_SKINTONES)) var/new_s_tone = tgui_input_list(user, "Choose your skin tone", "Race change", GLOB.skin_tones) if(new_s_tone) amazed_human.skin_tone = new_s_tone amazed_human.dna.update_ui_block(DNA_SKIN_TONE_BLOCK) - if(MUTCOLORS in amazed_human.dna.species.species_traits) - var/new_mutantcolor = tgui_color_picker(user, "Choose your skin color:", "Race change", amazed_human.dna.features["mcolor"]) + else if(HAS_TRAIT(amazed_human, TRAIT_MUTANT_COLORS) && !HAS_TRAIT(amazed_human, TRAIT_FIXED_MUTANT_COLORS)) + var/datum/color_palette/generic_colors/palette = amazed_human.dna.color_palettes[/datum/color_palette/generic_colors] + var/new_mutantcolor = tgui_color_picker(user, "Choose your skin color:", "Race change", palette.mutant_color) if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) return TRUE if(new_mutantcolor) var/temp_hsv = RGBtoHSV(new_mutantcolor) if(ReadHSV(temp_hsv)[3] >= ReadHSV("#7F7F7F")[3]) // mutantcolors must be bright - amazed_human.dna.features["mcolor"] = sanitize_hexcolor(new_mutantcolor) - amazed_human.dna.update_uf_block(DNA_MUTANT_COLOR_BLOCK) + palette.mutant_color = sanitize_hexcolor(new_mutantcolor) else to_chat(amazed_human, span_notice("Invalid color. Your color is not bright enough.")) diff --git a/code/game/objects/structures/shower.dm b/code/game/objects/structures/shower.dm index 8607ff3c6edf..8f2dd88e944d 100644 --- a/code/game/objects/structures/shower.dm +++ b/code/game/objects/structures/shower.dm @@ -328,17 +328,17 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/shower, (-16)) qdel(src) /obj/machinery/shower/proc/check_heat(mob/living/L) - var/mob/living/carbon/C = L - if(current_temperature == SHOWER_FREEZING) - if(iscarbon(L)) - C.adjust_bodytemperature(-80, 80) - to_chat(L, span_warning("[src] is freezing!")) + if(L.bodytemperature >= L.standard_body_temperature - 1 KELVIN) + to_chat(L, span_warning("[src] is freezing!")) + + L.adjust_bodytemperature(-0.5 KELVIN, min_temp = CELCIUS_TO_KELVIN(30)) + else if(current_temperature == SHOWER_BOILING) - if(iscarbon(L)) - C.adjust_bodytemperature(35, 0, 500) - L.adjustFireLoss(5) - to_chat(L, span_danger("[src] is searing!")) + if(L.bodytemperature <= L.standard_body_temperature + 1 KELVIN) + to_chat(L, span_warning("[src] is [pick("scalding", "searing")]!")) + L.adjust_bodytemperature(0.5 KELVIN, max_temp = CELCIUS_TO_KELVIN(40)) + L.apply_damage(6, BURN, spread_damage = TRUE) /obj/structure/showerframe diff --git a/code/game/objects/structures/traps.dm b/code/game/objects/structures/traps.dm index 9078bf10085f..a702aecdda51 100644 --- a/code/game/objects/structures/traps.dm +++ b/code/game/objects/structures/traps.dm @@ -202,7 +202,7 @@ /obj/structure/trap/chill/trap_effect(mob/living/victim) to_chat(victim, span_bolddanger("You're frozen solid!")) victim.Paralyze(2 SECONDS) - victim.adjust_bodytemperature(-300) + victim.adjust_bodytemperature(-T0C, use_insulation = TRUE) victim.apply_status_effect(/datum/status_effect/freon) diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm index 793447312b94..cafd9556fc4a 100644 --- a/code/game/turfs/closed/walls.dm +++ b/code/game/turfs/closed/walls.dm @@ -63,20 +63,29 @@ ADD_TRAIT(src, TRAIT_UNDENSE, LEANING_TRAIT) ADD_TRAIT(src, TRAIT_EXPANDED_FOV, LEANING_TRAIT) + ADD_TRAIT(src, TRAIT_NO_LEG_AID, LEANING_TRAIT) visible_message(span_notice("[src] leans against \the [wall]!"), \ span_notice("You lean against \the [wall]!")) - RegisterSignals(src, list(COMSIG_MOB_CLIENT_PRE_MOVE, COMSIG_HUMAN_DISARM_HIT, COMSIG_LIVING_GET_PULLED, COMSIG_MOVABLE_TELEPORTING, COMSIG_ATOM_DIR_CHANGE), PROC_REF(stop_leaning)) + RegisterSignals(src, list(COMSIG_MOB_CLIENT_PRE_MOVE, COMSIG_HUMAN_DISARM_HIT, COMSIG_LIVING_GET_PULLED, COMSIG_MOVABLE_TELEPORTING, COMSIG_LIVING_RESIST), PROC_REF(stop_leaning)) + RegisterSignal(src, COMSIG_ATOM_DIR_CHANGE, PROC_REF(stop_leaning_dir)) update_fov() is_leaning = TRUE + update_limbless_locomotion() + +/mob/living/carbon/proc/stop_leaning_dir(datum/source, old_dir, new_dir) + SIGNAL_HANDLER + if(new_dir != old_dir) + stop_leaning() /mob/living/carbon/proc/stop_leaning() SIGNAL_HANDLER - UnregisterSignal(src, list(COMSIG_MOB_CLIENT_PRE_MOVE, COMSIG_HUMAN_DISARM_HIT, COMSIG_LIVING_GET_PULLED, COMSIG_MOVABLE_TELEPORTING, COMSIG_ATOM_DIR_CHANGE)) + UnregisterSignal(src, list(COMSIG_MOB_CLIENT_PRE_MOVE, COMSIG_HUMAN_DISARM_HIT, COMSIG_LIVING_GET_PULLED, COMSIG_MOVABLE_TELEPORTING, COMSIG_ATOM_DIR_CHANGE, COMSIG_LIVING_RESIST)) is_leaning = FALSE pixel_y = base_pixel_y + body_position_pixel_x_offset pixel_x = base_pixel_y + body_position_pixel_y_offset REMOVE_TRAIT(src, TRAIT_UNDENSE, LEANING_TRAIT) REMOVE_TRAIT(src, TRAIT_EXPANDED_FOV, LEANING_TRAIT) + REMOVE_TRAIT(src, TRAIT_NO_LEG_AID, LEANING_TRAIT) update_fov() /turf/closed/wall/Initialize(mapload) diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index 5210e90425cd..e2303cae2ca8 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -200,13 +200,13 @@ air_update_turf(FALSE, FALSE) /turf/open/proc/freeze_turf() - for(var/obj/I in contents) - if(!HAS_TRAIT(I, TRAIT_FROZEN) && !(I.resistance_flags & FREEZE_PROOF)) - I.AddElement(/datum/element/frozen) + for(var/obj/iced in contents) + if(!HAS_TRAIT(iced, TRAIT_FROZEN) && !(iced.resistance_flags & FREEZE_PROOF)) + iced.AddElement(/datum/element/frozen) - for(var/mob/living/L in contents) - if(L.bodytemperature <= 50) - L.apply_status_effect(/datum/status_effect/freon) + for(var/mob/living/freezer in src) + if(freezer.bodytemperature <= CELCIUS_TO_KELVIN(25 CELCIUS)) + freezer.apply_status_effect(/datum/status_effect/freon) MakeSlippery(TURF_WET_PERMAFROST, 50) return TRUE diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index 77fe81fdb7e9..8ca8d01352a9 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -26,8 +26,10 @@ human.eye_color_left = random_eye_color human.eye_color_right = random_eye_color - human.dna.blood_type = random_blood_type() - human.dna.features["mcolor"] = "#[random_color()]" + human.dna.human_blood_type = random_human_blood_type() + var/datum/color_palette/generic_colors/palette = human.dna.color_palettes[/datum/color_palette/generic_colors] + palette.mutant_color = "#[random_color()]" + palette.mutant_color_secondary = "#[random_color()]" human.dna.species.randomize_active_underwear_only(human) for(var/datum/species/species_path as anything in subtypesof(/datum/species)) diff --git a/code/modules/admin/permissionedit.dm b/code/modules/admin/permissionedit.dm index 5b6ca946c771..6d705789de63 100644 --- a/code/modules/admin/permissionedit.dm +++ b/code/modules/admin/permissionedit.dm @@ -222,7 +222,7 @@ . = ckey(admin_key) if(!.) return FALSE - if(!admin_ckey && (. in (GLOB.admin_datums+GLOB.deadmins))) + if(!admin_ckey && (. in (GLOB.admin_datums + GLOB.deadmins))) to_chat(usr, span_danger("[admin_key] is already an admin."), confidential = TRUE) return FALSE if(use_db) diff --git a/code/modules/admin/verbs/list_exposer.dm b/code/modules/admin/verbs/list_exposer.dm index 851bd901c1e5..c2c48963051e 100644 --- a/code/modules/admin/verbs/list_exposer.dm +++ b/code/modules/admin/verbs/list_exposer.dm @@ -33,7 +33,7 @@ for(var/entry in GLOB.human_list) var/mob/living/carbon/human/subject = entry if(subject.ckey) - data += "[subject][subject.dna.unique_enzymes][subject.dna.blood_type]" + data += "[subject][subject.dna.unique_enzymes][subject.get_blood_type()]" data += "" usr << browse(data, "window=DNA;size=440x410") diff --git a/code/modules/antagonists/abductor/equipment/glands/blood.dm b/code/modules/antagonists/abductor/equipment/glands/blood.dm index 40c2b3c4d726..8a6b43a7baf2 100644 --- a/code/modules/antagonists/abductor/equipment/glands/blood.dm +++ b/code/modules/antagonists/abductor/equipment/glands/blood.dm @@ -15,4 +15,4 @@ var/mob/living/carbon/human/H = owner var/datum/species/species = H.dna.species to_chat(H, span_warning("You feel your blood heat up for a moment.")) - species.exotic_blood = get_random_reagent_id() + species.exotic_bloodtype = pick(subtypesof(/datum/blood_type)) diff --git a/code/modules/antagonists/abductor/equipment/glands/heal.dm b/code/modules/antagonists/abductor/equipment/glands/heal.dm index 9be6245d91f0..90b6e9865a9c 100644 --- a/code/modules/antagonists/abductor/equipment/glands/heal.dm +++ b/code/modules/antagonists/abductor/equipment/glands/heal.dm @@ -27,7 +27,7 @@ return var/obj/item/organ/internal/liver/liver = owner.get_organ_slot(ORGAN_SLOT_LIVER) - if((!liver && !HAS_TRAIT(owner, TRAIT_NOMETABOLISM)) || (liver && ((liver.damage > liver.high_threshold) || (liver.organ_flags & ORGAN_SYNTHETIC)))) + if((!liver && !HAS_TRAIT(owner, TRAIT_LIVERLESS_METABOLISM)) || (liver && ((liver.damage > liver.high_threshold) || (liver.organ_flags & ORGAN_SYNTHETIC)))) replace_liver(liver) return diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm index 4aef0a99229f..4bcc1f2090d7 100644 --- a/code/modules/antagonists/brother/brother.dm +++ b/code/modules/antagonists/brother/brother.dm @@ -113,8 +113,9 @@ /datum/antagonist/brother/get_base_preview_icon() var/mob/living/carbon/human/dummy/consistent/brother1 = new var/mob/living/carbon/human/dummy/consistent/brother2 = new + var/datum/color_palette/generic_colors/located = brother1.dna.color_palettes[/datum/color_palette/generic_colors] - brother1.dna.features["ethcolor"] = GLOB.color_list_ethereal["Faint Red"] + located.ethereal_color = GLOB.color_list_ethereal["Faint Red"] brother1.set_species(/datum/species/ethereal) brother2.dna.features["moth_antennae"] = "Plain" @@ -123,11 +124,15 @@ brother2.set_species(/datum/species/moth) var/icon/brother1_icon = render_preview_outfit(/datum/outfit/job/quartermaster, brother1) - brother1_icon.Blend(icon('icons/effects/blood.dmi', "maskblood"), ICON_OVERLAY) + var/icon/blood1_icon = icon('icons/effects/blood.dmi', "maskblood") + blood1_icon.Blend(COLOR_BLOOD, ICON_MULTIPLY) + brother1_icon.Blend(blood1_icon, ICON_OVERLAY) brother1_icon.Shift(WEST, 8) var/icon/brother2_icon = render_preview_outfit(/datum/outfit/job/scientist/consistent, brother2) - brother2_icon.Blend(icon('icons/effects/blood.dmi', "uniformblood"), ICON_OVERLAY) + var/icon/blood2_icon = icon('icons/effects/blood.dmi', "uniformblood") + blood2_icon.Blend(COLOR_BLOOD, ICON_MULTIPLY) + brother2_icon.Blend(blood2_icon, ICON_OVERLAY) brother2_icon.Shift(EAST, 8) var/icon/final_icon = brother1_icon diff --git a/code/modules/antagonists/changeling/changeling.dm b/code/modules/antagonists/changeling/changeling.dm index 11b913d4f8b1..33ed63b4ac7b 100644 --- a/code/modules/antagonists/changeling/changeling.dm +++ b/code/modules/antagonists/changeling/changeling.dm @@ -489,7 +489,7 @@ if(verbose) to_chat(user, span_warning("We already have this DNA in storage!")) return FALSE - if(NO_DNA_COPY in target.dna.species?.species_traits) + if(HAS_TRAIT(target, TRAIT_NO_DNA_COPY)) if(verbose) to_chat(user, span_warning("[target] is not compatible with our biology.")) return FALSE diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm index 92ae8dae9f9f..77f3a8fe6db5 100644 --- a/code/modules/antagonists/changeling/powers/mutations.dm +++ b/code/modules/antagonists/changeling/powers/mutations.dm @@ -543,8 +543,8 @@ body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS armor_type = /datum/armor/armor_changeling flags_inv = HIDEJUMPSUIT - cold_protection = 0 - heat_protection = 0 + max_heat_protection_temperature = null + min_cold_protection_temperature = null resistance_flags = FLAMMABLE //MONKESTATION ADDITION /datum/armor/armor_changeling diff --git a/code/modules/antagonists/changeling/powers/void_adaption.dm b/code/modules/antagonists/changeling/powers/void_adaption.dm index 76c0eeffc972..0bf4fc902b1f 100644 --- a/code/modules/antagonists/changeling/powers/void_adaption.dm +++ b/code/modules/antagonists/changeling/powers/void_adaption.dm @@ -34,11 +34,11 @@ var/datum/gas_mixture/environment = void_adapted.loc.return_air() if (!isnull(environment)) - var/vulnerable_temperature = void_adapted.get_body_temp_cold_damage_limit() + var/vulnerable_temperature = void_adapted.bodytemp_cold_damage_limit var/affected_temperature = environment.return_temperature() if (ishuman(void_adapted)) var/mob/living/carbon/human/special_boy = void_adapted - var/cold_protection = special_boy.get_cold_protection(affected_temperature) + var/cold_protection = special_boy.get_insulation(affected_temperature) vulnerable_temperature *= (1 - cold_protection) var/affected_pressure = special_boy.calculate_affecting_pressure(environment.return_pressure()) diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm index 2f72953f4a05..6c29f56dad53 100644 --- a/code/modules/antagonists/cult/blood_magic.dm +++ b/code/modules/antagonists/cult/blood_magic.dm @@ -762,30 +762,25 @@ uses = 0 playsound(get_turf(M), 'sound/magic/staff_healing.ogg', 25) user.Beam(M, icon_state="sendbeam", time = 1 SECONDS) - if(istype(target, /obj/effect/decal/cleanable/blood)) + if(istype(target, /obj/effect/decal/cleanable/blood) || isturf(target)) blood_draw(target, user) ..() /obj/item/melee/blood_magic/manipulator/proc/blood_draw(atom/target, mob/living/carbon/human/user) - var/temp = 0 - var/turf/T = get_turf(target) - if(T) - for(var/obj/effect/decal/cleanable/blood/B in view(T, 2)) - if(B.blood_state == BLOOD_STATE_HUMAN) - if(B.bloodiness == 100) //Bonus for "pristine" bloodpools, also to prevent cheese with footprint spam - temp += 30 - else - temp += max((B.bloodiness**2)/800,1) - new /obj/effect/temp_visual/cult/turf/floor(get_turf(B)) - qdel(B) - for(var/obj/effect/decal/cleanable/trail_holder/TH in view(T, 2)) - qdel(TH) - if(temp) - user.Beam(T,icon_state="drainbeam", time = 15) + var/blood_to_gain = 0 + var/turf/our_turf = get_turf(target) + if(our_turf) + for(var/obj/effect/decal/cleanable/blood/blood_around_us in range(our_turf,2)) + if(blood_around_us.decal_reagent == /datum/reagent/blood) + blood_to_gain += max(blood_around_us.bloodiness * 0.12 * BLOOD_PER_UNIT_MODIFIER, 1) + new /obj/effect/temp_visual/cult/turf/floor(get_turf(blood_around_us)) + qdel(blood_around_us) + if(blood_to_gain) + user.Beam(our_turf,icon_state="drainbeam", time = 15) new /obj/effect/temp_visual/cult/sparks(get_turf(user)) - playsound(T, 'sound/magic/enter_blood.ogg', 50) - to_chat(user, span_cultitalic("Your blood rite has gained [round(temp)] charge\s from blood sources around you!")) - uses += max(1, round(temp)) + playsound(our_turf, 'sound/magic/enter_blood.ogg', 50) + to_chat(user, span_cultitalic("Your blood rite has gained [round(blood_to_gain)] charge\s from blood sources around you!")) + uses += max(1, round(blood_to_gain)) /obj/item/melee/blood_magic/manipulator/attack_self(mob/living/user) if(IS_CULTIST(user)) diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index 4094842d5d1e..97c90bba4945 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -182,9 +182,9 @@ Striking a noncultist, however, will tear their flesh."} flags_inv = HIDEFACE|HIDEHAIR|HIDEEARS flags_cover = HEADCOVERSEYES armor_type = /datum/armor/hooded_cult_hoodie - cold_protection = HEAD + min_cold_protection_temperature = HELMET_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = HELMET_MAX_TEMP_PROTECT /datum/armor/hooded_cult_hoodie @@ -208,9 +208,9 @@ Striking a noncultist, however, will tear their flesh."} allowed = list(/obj/item/tome, /obj/item/melee/cultblade) armor_type = /datum/armor/hooded_cultrobes flags_inv = HIDEJUMPSUIT - cold_protection = CHEST|GROIN|LEGS|ARMS + min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT - heat_protection = CHEST|GROIN|LEGS|ARMS + max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT hoodtype = /obj/item/clothing/head/hooded/cult_hoodie diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm index 7a03bace1050..6faf49021266 100644 --- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm +++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm @@ -20,10 +20,12 @@ /datum/status_effect/unholy_determination/on_apply() owner.add_traits(list(TRAIT_COAGULATING, TRAIT_NOCRITDAMAGE, TRAIT_NOSOFTCRIT), type) + owner.add_homeostasis_level(id, owner.standard_body_temperature, 10 KELVIN) return TRUE /datum/status_effect/unholy_determination/on_remove() owner.remove_traits(list(TRAIT_COAGULATING, TRAIT_NOCRITDAMAGE, TRAIT_NOSOFTCRIT), type) + owner.remove_homeostasis_level(id) /datum/status_effect/unholy_determination/tick() // The amount we heal of each damage type per tick. If we're missing legs we heal better because we can't dodge. @@ -49,7 +51,6 @@ playsound(owner, pick(GLOB.creepy_ambience), 50, TRUE) adjust_all_damages(healing_amount) - adjust_temperature() adjust_bleed_wounds() /* @@ -65,28 +66,11 @@ owner.adjustBruteLoss(-amount, FALSE) owner.adjustFireLoss(-amount) -/* - * Adjust the owner's temperature up or down to standard body temperatures. - */ -/datum/status_effect/unholy_determination/proc/adjust_temperature() - var/target_temp = owner.get_body_temp_normal(apply_change = FALSE) - if(owner.bodytemperature > target_temp) - owner.adjust_bodytemperature(-50 * TEMPERATURE_DAMAGE_COEFFICIENT, target_temp) - else if(owner.bodytemperature < (target_temp + 1)) - owner.adjust_bodytemperature(50 * TEMPERATURE_DAMAGE_COEFFICIENT, target_temp) - - if(ishuman(owner)) - var/mob/living/carbon/human/human_owner = owner - if(human_owner.coretemperature > target_temp) - human_owner.adjust_coretemperature(-50 * TEMPERATURE_DAMAGE_COEFFICIENT, target_temp) - else if(human_owner.coretemperature < (target_temp + 1)) - human_owner.adjust_coretemperature(50 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, target_temp) - /* * Slow and stop any blood loss the owner's experiencing. */ /datum/status_effect/unholy_determination/proc/adjust_bleed_wounds() - if(!iscarbon(owner) || !owner.blood_volume) + if(HAS_TRAIT(owner, TRAIT_NOBLOOD)) return if(owner.blood_volume < BLOOD_VOLUME_NORMAL) diff --git a/code/modules/antagonists/heretic/status_effects/debuffs.dm b/code/modules/antagonists/heretic/status_effects/debuffs.dm index 761af62876f6..1088f846525f 100644 --- a/code/modules/antagonists/heretic/status_effects/debuffs.dm +++ b/code/modules/antagonists/heretic/status_effects/debuffs.dm @@ -6,7 +6,7 @@ status_type = STATUS_EFFECT_REPLACE tick_interval = 0.5 SECONDS /// The amount the victim's body temperature changes each tick() in kelvin. Multiplied by TEMPERATURE_DAMAGE_COEFFICIENT. - var/cooling_per_tick = -14 + var/cooling_per_tick = -1 KELVIN /atom/movable/screen/alert/status_effect/void_chill name = "Void Chill" @@ -23,11 +23,11 @@ owner.remove_movespeed_modifier(/datum/movespeed_modifier/void_chill, update = TRUE) /datum/status_effect/void_chill/tick() - owner.adjust_bodytemperature(cooling_per_tick * TEMPERATURE_DAMAGE_COEFFICIENT) + owner.adjust_bodytemperature(cooling_per_tick) /datum/status_effect/void_chill/major duration = 10 SECONDS - cooling_per_tick = -20 + cooling_per_tick = -4 KELVIN /datum/status_effect/void_chill/lasting id = "lasting_void_chill" diff --git a/code/modules/antagonists/nightmare/nightmare_species.dm b/code/modules/antagonists/nightmare/nightmare_species.dm index 619d5bb79456..c2acb7703750 100644 --- a/code/modules/antagonists/nightmare/nightmare_species.dm +++ b/code/modules/antagonists/nightmare/nightmare_species.dm @@ -8,12 +8,10 @@ burnmod = 1.5 changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE no_equip_flags = ITEM_SLOT_MASK | ITEM_SLOT_OCLOTHING | ITEM_SLOT_GLOVES | ITEM_SLOT_FEET | ITEM_SLOT_ICLOTHING | ITEM_SLOT_SUITSTORE - species_traits = list( - NO_UNDERWEAR, - NO_DNA_COPY, - NOTRANSSTING, - ) inherent_traits = list( + TRAIT_NO_UNDERWEAR, + TRAIT_NO_DNA_COPY, + TRAIT_NO_TRANSFORMATION_STING, TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, TRAIT_RESISTCOLD, diff --git a/code/modules/antagonists/obsessed/obsessed.dm b/code/modules/antagonists/obsessed/obsessed.dm index a079f95cfa0e..f9de1b689141 100644 --- a/code/modules/antagonists/obsessed/obsessed.dm +++ b/code/modules/antagonists/obsessed/obsessed.dm @@ -42,7 +42,9 @@ victim_dummy.update_body_parts() var/icon/obsessed_icon = render_preview_outfit(preview_outfit) - obsessed_icon.Blend(icon('icons/effects/blood.dmi', "uniformblood"), ICON_OVERLAY) + var/icon/blood_icon = icon('icons/effects/blood.dmi', "uniformblood") + blood_icon.Blend(COLOR_BLOOD, ICON_MULTIPLY) + obsessed_icon.Blend(blood_icon, ICON_OVERLAY) var/icon/final_icon = finish_preview_icon(obsessed_icon) diff --git a/code/modules/assembly/igniter.dm b/code/modules/assembly/igniter.dm index 061de2a5f920..d2125499e6ce 100644 --- a/code/modules/assembly/igniter.dm +++ b/code/modules/assembly/igniter.dm @@ -1,5 +1,4 @@ #define EXPOSED_VOLUME 1000 -#define ROOM_TEMP 293 #define MIN_FREEZE_TEMP 50 #define MAX_FREEZE_TEMP 1000000 @@ -68,10 +67,9 @@ var/turf/location = get_turf(loc) if(location) var/datum/gas_mixture/enviro = location.return_air() - enviro.temperature = clamp(min(ROOM_TEMP, enviro.temperature*0.85),MIN_FREEZE_TEMP,MAX_FREEZE_TEMP) + enviro.temperature = clamp(min(T20C, enviro.temperature*0.85),MIN_FREEZE_TEMP,MAX_FREEZE_TEMP) sparks.start() #undef EXPOSED_VOLUME -#undef ROOM_TEMP #undef MIN_FREEZE_TEMP #undef MAX_FREEZE_TEMP diff --git a/code/modules/atmospherics/machinery/air_alarm/air_alarm_thresholds.dm b/code/modules/atmospherics/machinery/air_alarm/air_alarm_thresholds.dm index cfe74f13c346..50e31fda1162 100644 --- a/code/modules/atmospherics/machinery/air_alarm/air_alarm_thresholds.dm +++ b/code/modules/atmospherics/machinery/air_alarm/air_alarm_thresholds.dm @@ -93,10 +93,10 @@ hazard_max = HAZARD_HIGH_PRESSURE /datum/tlv/temperature - warning_min = BODYTEMP_COLD_WARNING_1+10 - hazard_min = BODYTEMP_COLD_WARNING_1 - warning_max = BODYTEMP_HEAT_WARNING_1-27 - hazard_max = BODYTEMP_HEAT_WARNING_1 + warning_min = BODYTEMP_COLD_DAMAGE_LIMIT - 10 CELCIUS // some leeway as most humans sit comfortable above area temp + hazard_min = BODYTEMP_COLD_DAMAGE_LIMIT - 40 CELCIUS + warning_max = BODYTEMP_HEAT_DAMAGE_LIMIT + 5 CELCIUS // same + hazard_max = BODYTEMP_HEAT_DAMAGE_LIMIT + 20 CELCIUS /datum/tlv/cold_room_pressure warning_min = ONE_ATMOSPHERE * 0.9 diff --git a/code/modules/atmospherics/machinery/components/gas_recipe_machines/crystallizer_items.dm b/code/modules/atmospherics/machinery/components/gas_recipe_machines/crystallizer_items.dm index d1ac81975c55..72d21d042c2f 100644 --- a/code/modules/atmospherics/machinery/components/gas_recipe_machines/crystallizer_items.dm +++ b/code/modules/atmospherics/machinery/components/gas_recipe_machines/crystallizer_items.dm @@ -33,7 +33,6 @@ worn_item.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) worn_item.add_atom_colour("#00fff7", FIXED_COLOUR_PRIORITY) worn_item.min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT - worn_item.cold_protection = worn_item.body_parts_covered worn_item.clothing_flags |= STOPSPRESSUREDAMAGE uses-- if(!uses) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index af1f78552796..6b7b27ad2ce7 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -113,6 +113,7 @@ var/patient_dead = FALSE fair_market_price = 10 payment_department = ACCOUNT_MED + var/adjusted_occupant = FALSE /datum/armor/unary_cryo_cell @@ -145,7 +146,19 @@ SET_PLANE(occupant_vis, PLANE_TO_TRUE(occupant_vis.plane), new_turf) /obj/machinery/atmospherics/components/unary/cryo_cell/set_occupant(atom/movable/new_occupant) + if(occupant && isnull(new_occupant)) + REMOVE_TRAIT(occupant, TRAIT_ASSISTED_BREATHING, REF(src)) + if(isliving(occupant) && adjusted_occupant) + adjusted_occupant = FALSE + var/mob/living/living = occupant + living.bodytemp_cold_damage_limit += 270 KELVIN . = ..() + if(occupant && on) + ADD_TRAIT(occupant, TRAIT_ASSISTED_BREATHING, REF(src)) + if(isliving(occupant) && !adjusted_occupant) + adjusted_occupant = TRUE + var/mob/living/living = occupant + living.bodytemp_cold_damage_limit -= 270 KELVIN update_appearance() /obj/machinery/atmospherics/components/unary/cryo_cell/on_construction(mob/user) @@ -259,6 +272,21 @@ else update_use_power(IDLE_POWER_USE) update_appearance() + if(occupant) + ADD_TRAIT(occupant, TRAIT_ASSISTED_BREATHING, REF(src)) + else + REMOVE_TRAIT(occupant, TRAIT_ASSISTED_BREATHING, REF(src)) + + if(on) + if(isliving(occupant) && !adjusted_occupant) + adjusted_occupant = TRUE + var/mob/living/living = occupant + living.bodytemp_cold_damage_limit -= 270 KELVIN + else + if(isliving(occupant) && adjusted_occupant) + adjusted_occupant = FALSE + var/mob/living/living = occupant + living.bodytemp_cold_damage_limit += 270 KELVIN /obj/machinery/atmospherics/components/unary/cryo_cell/on_set_is_operational(old_value) if(old_value) //Turned off @@ -360,7 +388,7 @@ if(ishuman(mob_occupant)) var/mob/living/carbon/human/H = mob_occupant - cold_protection = H.get_cold_protection(air1.temperature) + cold_protection = H.get_insulation(air1.temperature) if(abs(temperature_delta) > 1) var/air_heat_capacity = air1.heat_capacity() @@ -370,11 +398,6 @@ mob_occupant.adjust_bodytemperature(heat / heat_capacity, TCMB) air1.temperature = clamp(air1.temperature - heat / air_heat_capacity, TCMB, MAX_TEMPERATURE) - //lets have the core temp match the body temp in humans - if(ishuman(mob_occupant)) - var/mob/living/carbon/human/humi = mob_occupant - humi.adjust_coretemperature(humi.bodytemperature - humi.coretemperature) - air1.garbage_collect() @@ -392,7 +415,7 @@ return air1.remove(air1.total_moles() * breath_percentage) /obj/machinery/atmospherics/components/unary/cryo_cell/assume_air(datum/gas_mixture/giver) - airs[1].merge(giver) + return airs[1].merge(giver) /obj/machinery/atmospherics/components/unary/cryo_cell/relaymove(mob/living/user, direction) if(message_cooldown <= world.time) diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm index fd43e315527b..f25838b8fa65 100644 --- a/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm +++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm @@ -44,7 +44,7 @@ //Best guess-estimate of the total bodytemperature of all the mobs, since they share the same environment it's ~ok~ to guess like this var/avg_temp = (pipe_air.temperature * hc + (heat_source.bodytemperature * buckled_mobs.len) * 3500) / (hc + (buckled_mobs ? buckled_mobs.len * 3500 : 0)) for(var/mob/living/buckled_mob as anything in buckled_mobs) - buckled_mob.bodytemperature = avg_temp + buckled_mob.adjust_bodytemperature(avg_temp - heat_source.bodytemperature) pipe_air.temperature = avg_temp /obj/machinery/atmospherics/pipe/heat_exchanging/process(seconds_per_tick) diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm index 73da55ad2fe3..8c62a873ffea 100644 --- a/code/modules/awaymissions/mission_code/snowdin.dm +++ b/code/modules/awaymissions/mission_code/snowdin.dm @@ -376,7 +376,7 @@ name = "insulated tactical turtleneck" desc = "A nondescript and slightly suspicious-looking turtleneck with digital camouflage cargo pants. The interior has been padded with special insulation for both warmth and protection." armor_type = /datum/armor/syndicate_coldres - cold_protection = CHEST|GROIN|ARMS|LEGS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT /datum/armor/syndicate_coldres diff --git a/code/modules/cargo/gondolapod.dm b/code/modules/cargo/gondolapod.dm index f3dca7a3dca1..16da87d45c5b 100644 --- a/code/modules/cargo/gondolapod.dm +++ b/code/modules/cargo/gondolapod.dm @@ -18,8 +18,8 @@ loot = list(/obj/effect/decal/cleanable/blood/gibs, /obj/item/stack/sheet/animalhide/gondola = 2, /obj/item/food/meat/slab/gondola = 2) //Gondolas aren't affected by cold. atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 - maxbodytemp = 1500 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 1500 maxHealth = 200 health = 200 del_on_death = TRUE diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 0dfff4d73fe8..fe32f251f9bb 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -87,6 +87,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) /// If set to TRUE, will update character_profiles on the next ui_data tick. var/tainted_character_profiles = FALSE + ///have we finished loading + var/loaded = FALSE /datum/preferences/Destroy(force) QDEL_NULL(character_preview_view) @@ -121,6 +123,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/loaded_preferences_successfully = load_preferences() if(loaded_preferences_successfully) if(load_character()) + loaded = TRUE return //we couldn't load character data so just randomize the character appearance + name randomise_appearance_prefs() //let's create a random character then - rather than a fat, bald and naked man. @@ -129,8 +132,14 @@ GLOBAL_LIST_EMPTY(preferences_datums) parent.set_macros() if(!loaded_preferences_successfully) + if(load_preferences()) + if(load_character()) + loaded = TRUE + return + message_admins("[parent]'s prefs failed to load twice! Their keybindings and tokens may have been lost please check on this.") save_preferences() save_character() //let's save this new random character so it doesn't keep generating new ones. + loaded = TRUE /datum/preferences/ui_interact(mob/user, datum/tgui/ui) // There used to be code here that readded the preview view if you "rejoined" @@ -290,7 +299,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) default_value || COLOR_WHITE, ) - if (!new_color) + if (!new_color && !requested_preference.allows_nulls) return FALSE if (!update_preference(requested_preference, new_color)) @@ -477,11 +486,15 @@ GLOBAL_LIST_EMPTY(preferences_datums) /// Applies the given preferences to a human mob. /datum/preferences/proc/apply_prefs_to(mob/living/carbon/human/character, icon_updates = TRUE) character.dna.features = list() + character.dna.apply_color_palettes(src) + var/species_type = read_preference(/datum/preference/choiced/species) + var/datum/species/species = new species_type for (var/datum/preference/preference as anything in get_preferences_in_priority_order()) if (preference.savefile_identifier != PREFERENCE_CHARACTER) continue - + if(preference.relevant_inherent_trait && !(preference.relevant_inherent_trait in species.inherent_traits)) + continue preference.apply_to_human(character, read_preference(preference.type)) character.dna.real_name = character.real_name diff --git a/code/modules/client/preferences/_preference.dm b/code/modules/client/preferences/_preference.dm index e6f260d9a2f6..c952c22f96ac 100644 --- a/code/modules/client/preferences/_preference.dm +++ b/code/modules/client/preferences/_preference.dm @@ -101,9 +101,9 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key()) /// will show the feature as selectable. var/relevant_mutant_bodypart = null - /// If the selected species has this in its /datum/species/species_traits, + /// If the selected species has this in its /datum/species/inherent_traits, /// will show the feature as selectable. - var/relevant_species_trait = null + var/relevant_inherent_trait = null /// If the selected species has this in its /datum/species/var/external_organs, /// will show the feature as selectable. @@ -113,6 +113,11 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key()) /// will show the feature as selectable. --species nuking var/relevant_head_flag = null + ///do we allow null inputs + var/allows_nulls = FALSE + ///are we defaulted to null + var/default_null = FALSE + /// Called on the saved input when retrieving. /// Also called by the value sent from the user through UI. Do not trust it. /// Input is the value inside the savefile, output is to tell other code @@ -206,6 +211,8 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key()) /datum/preference/proc/apply_to_human(mob/living/carbon/human/target, value) SHOULD_NOT_SLEEP(TRUE) SHOULD_CALL_PARENT(FALSE) + if(istype(src, /datum/preference/color)) + return //colors are handled through a palette datum CRASH("`apply_to_human()` was not implemented for [type]!") /// Returns which savefile to use for a given savefile identifier @@ -317,7 +324,12 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key()) SHOULD_CALL_PARENT(TRUE) SHOULD_NOT_SLEEP(TRUE) - if (!isnull(relevant_mutant_bodypart) || !isnull(relevant_species_trait) || !isnull(relevant_external_organ)) + if ( \ + !isnull(relevant_mutant_bodypart) \ + || !isnull(relevant_inherent_trait) \ + || !isnull(relevant_external_organ) \ + || !isnull(relevant_head_flag) \ + ) var/species_type = preferences.read_preference(/datum/preference/choiced/species) var/datum/species/species = new species_type @@ -434,16 +446,24 @@ GLOBAL_LIST_INIT(preference_entries_by_key, init_preference_entries_by_key()) abstract_type = /datum/preference/color /datum/preference/color/deserialize(input, datum/preferences/preferences) - return sanitize_hexcolor(input) + if(!allows_nulls || input) + return sanitize_hexcolor(input) + return null /datum/preference/color/create_default_value() + if(default_null) + return null return random_color() /datum/preference/color/serialize(input) - return sanitize_hexcolor(input) + if(!allows_nulls || input) + return sanitize_hexcolor(input) + return null /datum/preference/color/is_valid(value) - return findtext(value, GLOB.is_color) + if(!allows_nulls || value) + return findtext(value, GLOB.is_color) + return TRUE /// Takes an assoc list of names to /datum/sprite_accessory and returns a value /// fit for `/datum/preference/init_possible_values()` diff --git a/code/modules/client/preferences/clothing.dm b/code/modules/client/preferences/clothing.dm index c1bb5f4c3105..057987c871fb 100644 --- a/code/modules/client/preferences/clothing.dm +++ b/code/modules/client/preferences/clothing.dm @@ -92,7 +92,7 @@ var/species_type = preferences.read_preference(/datum/preference/choiced/species) var/datum/species/species = new species_type - return !(NO_UNDERWEAR in species.species_traits) + return !(TRAIT_NO_UNDERWEAR in species.inherent_traits) /datum/preference/choiced/socks/compile_constant_data() var/list/data = ..() @@ -136,6 +136,14 @@ /datum/preference/choiced/undershirt/apply_to_human(mob/living/carbon/human/target, value) target.undershirt = value +/datum/preference/choiced/undershirt/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE + + var/species_type = preferences.read_preference(/datum/preference/choiced/species) + var/datum/species/species = new species_type + return !(TRAIT_NO_UNDERWEAR in species.inherent_traits) + /// Underwear preference /datum/preference/choiced/underwear savefile_key = "underwear" @@ -156,7 +164,7 @@ var/species_type = preferences.read_preference(/datum/preference/choiced/species) var/datum/species/species = new species_type - return !(NO_UNDERWEAR in species.species_traits) + return !(TRAIT_NO_UNDERWEAR in species.inherent_traits) /datum/preference/choiced/underwear/compile_constant_data() var/list/data = ..() diff --git a/code/modules/client/preferences/skin_tone.dm b/code/modules/client/preferences/skin_tone.dm index 571dfc66b3b1..d2359f8ce694 100644 --- a/code/modules/client/preferences/skin_tone.dm +++ b/code/modules/client/preferences/skin_tone.dm @@ -1,7 +1,8 @@ /datum/preference/choiced/skin_tone - category = PREFERENCE_CATEGORY_SECONDARY_FEATURES - savefile_identifier = PREFERENCE_CHARACTER savefile_key = "skin_tone" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_SECONDARY_FEATURES + relevant_inherent_trait = TRAIT_USES_SKINTONES /datum/preference/choiced/skin_tone/init_possible_values() return GLOB.skin_tones @@ -26,12 +27,4 @@ return data /datum/preference/choiced/skin_tone/apply_to_human(mob/living/carbon/human/target, value) - if(target.dna.species.use_skintones) - target.skin_tone = value - -/datum/preference/choiced/skin_tone/is_accessible(datum/preferences/preferences) - if (!..(preferences)) - return FALSE - - var/datum/species/species_type = preferences.read_preference(/datum/preference/choiced/species) - return initial(species_type.use_skintones) + target.skin_tone = value diff --git a/code/modules/client/preferences/species.dm b/code/modules/client/preferences/species.dm index 1aae0e58dbbc..9e4923d2b11d 100644 --- a/code/modules/client/preferences/species.dm +++ b/code/modules/client/preferences/species.dm @@ -39,8 +39,9 @@ data[species_id] = list() data[species_id]["name"] = species.name data[species_id]["desc"] = species.get_species_description() + data[species_id]["lore"] = species.get_species_lore() data[species_id]["icon"] = sanitize_css_class_name(species.name) - data[species_id]["use_skintones"] = species.use_skintones + data[species_id]["use_skintones"] = (TRAIT_USES_SKINTONES in species.inherent_traits) data[species_id]["sexes"] = species.sexes data[species_id]["enabled_features"] = species.get_features() data[species_id]["perks"] = species.get_species_perks() diff --git a/code/modules/client/preferences/species_features/ethereal.dm b/code/modules/client/preferences/species_features/ethereal.dm index 56fe50895894..23db386c8de4 100644 --- a/code/modules/client/preferences/species_features/ethereal.dm +++ b/code/modules/client/preferences/species_features/ethereal.dm @@ -30,4 +30,4 @@ return values /datum/preference/choiced/ethereal_color/apply_to_human(mob/living/carbon/human/target, value) - target.dna.features["ethcolor"] = GLOB.color_list_ethereal[value] + return diff --git a/code/modules/client/preferences/species_features/mutants.dm b/code/modules/client/preferences/species_features/mutants.dm index 44cefd7ef877..eee8b54e6b61 100644 --- a/code/modules/client/preferences/species_features/mutants.dm +++ b/code/modules/client/preferences/species_features/mutants.dm @@ -2,14 +2,19 @@ savefile_key = "feature_mcolor" savefile_identifier = PREFERENCE_CHARACTER category = PREFERENCE_CATEGORY_SECONDARY_FEATURES - relevant_species_trait = MUTCOLORS + relevant_inherent_trait = TRAIT_MUTANT_COLORS + +/datum/preference/color/mutant_color/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE + + var/species_type = preferences.read_preference(/datum/preference/choiced/species) + var/datum/species/species = new species_type + return !(TRAIT_FIXED_MUTANT_COLORS in species.inherent_traits) /datum/preference/color/mutant_color/create_default_value() return sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]") -/datum/preference/color/mutant_color/apply_to_human(mob/living/carbon/human/target, value) - target.dna.features["mcolor"] = value - /datum/preference/color/mutant_color/is_valid(value) if (!..(value)) return FALSE diff --git a/code/modules/client/preferences/species_features/vampire.dm b/code/modules/client/preferences/species_features/vampire.dm index 1b05c2c3e12b..710dd37a1f28 100644 --- a/code/modules/client/preferences/species_features/vampire.dm +++ b/code/modules/client/preferences/species_features/vampire.dm @@ -5,7 +5,7 @@ priority = PREFERENCE_PRIORITY_NAME_MODIFICATIONS //this will be overwritten by names otherwise main_feature_name = "Vampire status" should_generate_icons = TRUE - relevant_species_trait = BLOOD_CLANS + relevant_inherent_trait = TRAIT_BLOOD_CLANS /datum/preference/choiced/vampire_status/create_default_value() return "Inoculated" //eh, have em try out the mechanic first @@ -22,7 +22,7 @@ GLOBAL_LIST_EMPTY(vampire_houses) /datum/preference/choiced/vampire_status/apply_to_human(mob/living/carbon/human/target, value) - if (!(relevant_species_trait in target.dna?.species.species_traits)) + if(!HAS_TRAIT(target, TRAIT_BLOOD_CLANS)) return if(value != "Inoculated") diff --git a/code/modules/client/preferences/underwear_color.dm b/code/modules/client/preferences/underwear_color.dm index a005145d1735..3603729910a3 100644 --- a/code/modules/client/preferences/underwear_color.dm +++ b/code/modules/client/preferences/underwear_color.dm @@ -12,4 +12,4 @@ var/species_type = preferences.read_preference(/datum/preference/choiced/species) var/datum/species/species = new species_type - return !(NO_UNDERWEAR in species.species_traits) + return !(TRAIT_NO_UNDERWEAR in species.inherent_traits) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 9afe600c4cdd..c9aebeb0f5a4 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -43,6 +43,9 @@ /// How many zones (body parts, not precise) we have disabled so far, for naming purposes var/zones_disabled + /// If supplied, this is what overlay is used when applying blood effects when worn + var/blood_overlay_type = "" + /// A lazily initiated "food" version of the clothing for moths. // This intentionally does not use the edible component, for a few reasons. // 1. Effectively everything that wants something edible, from now and into the future, @@ -591,3 +594,20 @@ BLIND // can't see anything /obj/item/clothing/remove_fantasy_bonuses(bonus) set_armor(get_armor().generate_new_with_modifiers(list(ARMOR_ALL = -bonus))) return ..() + +/obj/item/clothing/proc/appears_bloody() + return GET_ATOM_BLOOD_DNA_LENGTH(src) && can_be_bloody && !(item_flags & NO_BLOOD_ON_ITEM) + +/obj/item/clothing/worn_overlays(mutable_appearance/standing, isinhands, icon_file) + . = ..() + if(isinhands) + return + + if(blood_overlay_type && appears_bloody()) + var/mutable_appearance/blood_overlay + if(clothing_flags & LARGE_WORN_ICON) + blood_overlay = mutable_appearance('icons/effects/64x64.dmi', "[blood_overlay_type]blood_large") + else + blood_overlay = mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood") + blood_overlay.color = get_blood_dna_color() + . += blood_overlay diff --git a/code/modules/clothing/gloves/_gloves.dm b/code/modules/clothing/gloves/_gloves.dm index 3f5503ca0eed..ec842866a6e6 100644 --- a/code/modules/clothing/gloves/_gloves.dm +++ b/code/modules/clothing/gloves/_gloves.dm @@ -16,6 +16,7 @@ attack_verb_simple = list("challenge") strip_delay = 20 equip_delay_other = 40 + blood_overlay_type = "glove" // Path variable. If defined, will produced the type through interaction with wirecutters. var/cut_type = null /// Used for handling bloody gloves leaving behind bloodstains on objects. Will be decremented whenever a bloodstain is left behind, and be incremented when the gloves become bloody. @@ -41,13 +42,11 @@ /obj/item/clothing/gloves/worn_overlays(mutable_appearance/standing, isinhands = FALSE) . = ..() - if(!isinhands) + if(isinhands) return if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedgloves") - if(GET_ATOM_BLOOD_DNA_LENGTH(src)) - . += mutable_appearance('icons/effects/blood.dmi', "bloodyhands") /obj/item/clothing/gloves/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED) ..() diff --git a/code/modules/clothing/gloves/bone.dm b/code/modules/clothing/gloves/bone.dm index 2c75e642ff61..526913241d77 100644 --- a/code/modules/clothing/gloves/bone.dm +++ b/code/modules/clothing/gloves/bone.dm @@ -6,7 +6,7 @@ strip_delay = 40 equip_delay_other = 20 body_parts_covered = ARMS - cold_protection = ARMS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE diff --git a/code/modules/clothing/gloves/botany.dm b/code/modules/clothing/gloves/botany.dm index af94a6b7bb13..a3d09c8512be 100644 --- a/code/modules/clothing/gloves/botany.dm +++ b/code/modules/clothing/gloves/botany.dm @@ -4,9 +4,9 @@ icon_state = "leather" inhand_icon_state = null greyscale_colors = null - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE clothing_traits = list(TRAIT_PLANT_SAFE) diff --git a/code/modules/clothing/gloves/color.dm b/code/modules/clothing/gloves/color.dm index 6f302279531f..67f6172c1d15 100644 --- a/code/modules/clothing/gloves/color.dm +++ b/code/modules/clothing/gloves/color.dm @@ -3,9 +3,9 @@ name = "black gloves" icon_state = "black" greyscale_colors = "#2f2e31" - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE cut_type = /obj/item/clothing/gloves/fingerless @@ -17,7 +17,7 @@ greyscale_colors = "#2f2e31" strip_delay = 40 equip_delay_other = 20 - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT custom_price = PAYCHECK_CREW * 1.5 undyeable = TRUE @@ -82,7 +82,7 @@ name = "\proper Endotherm gloves" desc = "A pair of thick grey gloves, lined to protect the wearer from freezing cold." w_class = WEIGHT_CLASS_NORMAL - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT resistance_flags = NONE clothing_flags = THICKMATERIAL diff --git a/code/modules/clothing/gloves/combat.dm b/code/modules/clothing/gloves/combat.dm index e69813272d74..0ab32158c89f 100644 --- a/code/modules/clothing/gloves/combat.dm +++ b/code/modules/clothing/gloves/combat.dm @@ -5,9 +5,9 @@ greyscale_colors = "#2f2e31" siemens_coefficient = 0 strip_delay = 80 - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE armor_type = /datum/armor/gloves_combat diff --git a/code/modules/clothing/gloves/insulated.dm b/code/modules/clothing/gloves/insulated.dm index 89f33963af5d..2585c30278f8 100644 --- a/code/modules/clothing/gloves/insulated.dm +++ b/code/modules/clothing/gloves/insulated.dm @@ -114,8 +114,8 @@ inhand_icon_state = null greyscale_colors = null siemens_coefficient = 0 - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE diff --git a/code/modules/clothing/gloves/plasmaman.dm b/code/modules/clothing/gloves/plasmaman.dm index 0ca552773ec2..a5976df47a81 100644 --- a/code/modules/clothing/gloves/plasmaman.dm +++ b/code/modules/clothing/gloves/plasmaman.dm @@ -3,9 +3,9 @@ name = "plasma envirogloves" icon_state = "plasmaman" greyscale_colors = "#913b00" - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE armor_type = /datum/armor/color_plasmaman diff --git a/code/modules/clothing/gloves/special.dm b/code/modules/clothing/gloves/special.dm index 6ba1797ac02f..2c23539ee598 100644 --- a/code/modules/clothing/gloves/special.dm +++ b/code/modules/clothing/gloves/special.dm @@ -81,9 +81,9 @@ inhand_icon_state = null greyscale_colors = null siemens_coefficient = 0 - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT strip_delay = 60 armor_type = /datum/armor/captain_gloves @@ -139,9 +139,9 @@ name = "atmospheric extrication gloves" desc = "Heavy duty gloves for firefighters. These are thick, non-flammable and let you carry people faster." icon_state = "atmos" - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT resistance_flags = FIRE_PROOF siemens_coefficient = 0.3 diff --git a/code/modules/clothing/gloves/tacklers.dm b/code/modules/clothing/gloves/tacklers.dm index 888ecac39ee7..8b205c29b5d0 100644 --- a/code/modules/clothing/gloves/tacklers.dm +++ b/code/modules/clothing/gloves/tacklers.dm @@ -3,7 +3,7 @@ desc = "Special gloves that manipulate the blood vessels in the wearer's hands, granting them the ability to launch headfirst into walls." icon_state = "tackle" inhand_icon_state = null - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT resistance_flags = NONE custom_premium_price = PAYCHECK_COMMAND * 3.5 @@ -68,9 +68,9 @@ tackle_range = 5 skill_mod = 2 - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE diff --git a/code/modules/clothing/head/_head.dm b/code/modules/clothing/head/_head.dm index a67d65b5139d..7693776c7abc 100644 --- a/code/modules/clothing/head/_head.dm +++ b/code/modules/clothing/head/_head.dm @@ -6,6 +6,7 @@ righthand_file = 'icons/mob/inhands/clothing/hats_righthand.dmi' body_parts_covered = HEAD slot_flags = ITEM_SLOT_HEAD + blood_overlay_type = "helmetblood" ///Special throw_impact for hats to frisbee hats at people to place them on their heads/attempt to de-hat them. /obj/item/clothing/head/throw_impact(atom/hit_atom, datum/thrownthing/thrownthing) @@ -64,12 +65,6 @@ if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedhelmet") - if(GET_ATOM_BLOOD_DNA_LENGTH(src)) - if(clothing_flags & LARGE_WORN_ICON) - . += mutable_appearance('icons/effects/64x64.dmi', "helmetblood_large") - else - . += mutable_appearance('icons/effects/blood.dmi', "helmetblood") - if(!(flags_inv & HIDEHAIR)) if(ismob(loc)) diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index 6d9105e51ff9..4d767bfc89e1 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -74,9 +74,9 @@ dog_fashion = null name = "firefighter helmet" clothing_flags = STOPSPRESSUREDAMAGE | PLASMAMAN_HELMET_EXEMPT - heat_protection = HEAD + max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT - cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT /obj/item/clothing/head/utility/hardhat/red/upgraded @@ -94,9 +94,9 @@ inhand_icon_state = null hat_type = "white" clothing_flags = STOPSPRESSUREDAMAGE | PLASMAMAN_HELMET_EXEMPT - heat_protection = HEAD + max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT - cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT dog_fashion = /datum/dog_fashion/head @@ -167,9 +167,9 @@ light_outer_range = 4 //Boss always takes the best stuff hat_type = "white" clothing_flags = STOPSPRESSUREDAMAGE | PLASMAMAN_HELMET_EXEMPT - heat_protection = HEAD + max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT - cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT /obj/item/clothing/head/utility/hardhat/welding/dblue @@ -185,9 +185,9 @@ name = "atmospheric firefighter helmet" desc = "A firefighter's helmet, able to keep the user cool in any situation. Comes with a light and a welding visor." clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | BLOCK_GAS_SMOKE_EFFECT | PLASMAMAN_HELMET_EXEMPT | HEADINTERNALS - heat_protection = HEAD + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF visor_flags_cover = NONE diff --git a/code/modules/clothing/head/hat.dm b/code/modules/clothing/head/hat.dm index 1bb3cae11d7b..408723b2d888 100644 --- a/code/modules/clothing/head/hat.dm +++ b/code/modules/clothing/head/hat.dm @@ -168,7 +168,7 @@ desc = "On the first day of christmas my employer gave to me!" icon_state = "santahatnorm" inhand_icon_state = "that" - cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT dog_fashion = /datum/dog_fashion/head/santa @@ -272,7 +272,7 @@ icon_state = "ushankadown" inhand_icon_state = null flags_inv = HIDEEARS|HIDEHAIR - cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT dog_fashion = /datum/dog_fashion/head/ushanka var/earflaps = TRUE diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index edbb193532d2..658e67407279 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -6,9 +6,9 @@ icon_state = "helmet" inhand_icon_state = "helmet" armor_type = /datum/armor/head_helmet - cold_protection = HEAD + min_cold_protection_temperature = HELMET_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = HELMET_MAX_TEMP_PROTECT strip_delay = 60 clothing_flags = SNUG_FIT | PLASMAMAN_HELMET_EXEMPT @@ -250,9 +250,9 @@ icon_state = "swatsyndie" inhand_icon_state = "swatsyndie_helmet" armor_type = /datum/armor/helmet_swat - cold_protection = HEAD + min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = SPACE_HELM_MAX_TEMP_PROTECT clothing_flags = STOPSPRESSUREDAMAGE | PLASMAMAN_HELMET_EXEMPT strip_delay = 80 @@ -277,9 +277,9 @@ icon_state = "swat" inhand_icon_state = "swat_helmet" clothing_flags = PLASMAMAN_HELMET_EXEMPT | SNUG_FIT //monkestation edit - cold_protection = HEAD + min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = SPACE_HELM_MAX_TEMP_PROTECT flags_cover = HEADCOVERSEYES | PEPPERPROOF //monkestation edit @@ -294,9 +294,9 @@ icon_state = "thunderdome" inhand_icon_state = "thunderdome_helmet" armor_type = /datum/armor/helmet_thunderdome - cold_protection = HEAD + min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = SPACE_HELM_MAX_TEMP_PROTECT strip_delay = 80 dog_fashion = null @@ -312,8 +312,8 @@ acid = 90 /obj/item/clothing/head/helmet/thunderdome/holosuit - cold_protection = null - heat_protection = null + max_heat_protection_temperature = null + min_cold_protection_temperature = null armor_type = /datum/armor/thunderdome_holosuit /datum/armor/thunderdome_holosuit @@ -510,7 +510,7 @@ icon_state = "rus_ushanka" inhand_icon_state = "rus_ushanka" body_parts_covered = HEAD - cold_protection = HEAD + min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT armor_type = /datum/armor/helmet_rus_ushanka diff --git a/code/modules/clothing/head/moth.dm b/code/modules/clothing/head/moth.dm index d91d58208c68..04ba774b5319 100644 --- a/code/modules/clothing/head/moth.dm +++ b/code/modules/clothing/head/moth.dm @@ -4,7 +4,7 @@ icon_state = "mothcap" icon = 'icons/obj/clothing/head/moth.dmi' worn_icon = 'icons/mob/clothing/head/moth.dmi' - cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT flags_cover = HEADCOVERSEYES flags_inv = HIDEHAIR diff --git a/code/modules/clothing/masks/_masks.dm b/code/modules/clothing/masks/_masks.dm index df868a09db20..e760afdc616a 100644 --- a/code/modules/clothing/masks/_masks.dm +++ b/code/modules/clothing/masks/_masks.dm @@ -7,6 +7,7 @@ slot_flags = ITEM_SLOT_MASK strip_delay = 40 equip_delay_other = 40 + blood_overlay_type = "mask" supports_variations_flags = CLOTHING_SNOUTED_VARIATION var/modifies_speech = FALSE var/mask_adjusted = FALSE @@ -55,8 +56,9 @@ if(body_parts_covered & HEAD) if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask") - if(GET_ATOM_BLOOD_DNA_LENGTH(src)) - . += mutable_appearance('icons/effects/blood.dmi', "maskblood") + +/obj/item/clothing/mask/appears_bloody() + return ..() && (body_parts_covered & HEAD) /obj/item/clothing/mask/update_clothes_damaged_state(damaged_state = CLOTHING_DAMAGED) ..() diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index d4d5379c6e3c..8431673288a6 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -5,6 +5,7 @@ slot_flags = ITEM_SLOT_NECK strip_delay = 40 equip_delay_other = 40 + blood_overlay_type = "mask" /obj/item/clothing/neck/worn_overlays(mutable_appearance/standing, isinhands = FALSE) . = ..() @@ -14,8 +15,9 @@ if(body_parts_covered & HEAD) if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedmask") - if(GET_ATOM_BLOOD_DNA_LENGTH(src)) - . += mutable_appearance('icons/effects/blood.dmi', "maskblood") + +/obj/item/clothing/neck/appears_bloody() + return ..() && (body_parts_covered & HEAD) /obj/item/clothing/neck/bowtie name = "bow tie" diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm index d69460e6a1ce..ec9025e177f3 100644 --- a/code/modules/clothing/shoes/_shoes.dm +++ b/code/modules/clothing/shoes/_shoes.dm @@ -13,6 +13,7 @@ armor_type = /datum/armor/clothing_shoes slowdown = SHOES_SLOWDOWN strip_delay = 1 SECONDS + blood_overlay_type = "shoe" var/offset = 0 var/equipped_before_drop = FALSE ///Whether these shoes have laces that can be tied/untied @@ -53,11 +54,6 @@ if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damagedshoe") - if(GET_ATOM_BLOOD_DNA_LENGTH(src)) - if(clothing_flags & LARGE_WORN_ICON) - . += mutable_appearance('icons/effects/64x64.dmi', "shoeblood_large") - else - . += mutable_appearance('icons/effects/blood.dmi', "shoeblood") /obj/item/clothing/shoes/examine(mob/user) . = ..() diff --git a/code/modules/clothing/shoes/boots.dm b/code/modules/clothing/shoes/boots.dm index 4b7c16292f76..4a73682e3a1a 100644 --- a/code/modules/clothing/shoes/boots.dm +++ b/code/modules/clothing/shoes/boots.dm @@ -75,9 +75,9 @@ icon_state = "winterboots" inhand_icon_state = null armor_type = /datum/armor/shoes_winterboots - cold_protection = FEET|LEGS + min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT - heat_protection = FEET|LEGS + max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT lace_time = 8 SECONDS diff --git a/code/modules/clothing/shoes/cult.dm b/code/modules/clothing/shoes/cult.dm index 80d03d3a09e2..a3e93631f04d 100644 --- a/code/modules/clothing/shoes/cult.dm +++ b/code/modules/clothing/shoes/cult.dm @@ -3,9 +3,9 @@ desc = "A pair of boots worn by the followers of Nar'Sie." icon_state = "cult" inhand_icon_state = null - cold_protection = FEET + min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT - heat_protection = FEET + max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT lace_time = 10 SECONDS diff --git a/code/modules/clothing/shoes/sneakers.dm b/code/modules/clothing/shoes/sneakers.dm index 954925ffad5b..9600d4206b73 100644 --- a/code/modules/clothing/shoes/sneakers.dm +++ b/code/modules/clothing/shoes/sneakers.dm @@ -22,9 +22,9 @@ desc = "A pair of black shoes." custom_price = PAYCHECK_CREW - cold_protection = FEET + min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT - heat_protection = FEET + max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT /obj/item/clothing/shoes/sneakers/brown diff --git a/code/modules/clothing/spacesuits/_spacesuits.dm b/code/modules/clothing/spacesuits/_spacesuits.dm index 32b50115c65c..2c2f141c6be4 100644 --- a/code/modules/clothing/spacesuits/_spacesuits.dm +++ b/code/modules/clothing/spacesuits/_spacesuits.dm @@ -13,9 +13,9 @@ armor_type = /datum/armor/helmet_space flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT clothing_traits = list(TRAIT_SNOWSTORM_IMMUNE) - cold_protection = HEAD + min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = SPACE_HELM_MAX_TEMP_PROTECT flash_protect = FLASH_PROTECTION_WELDER strip_delay = 50 @@ -49,9 +49,9 @@ slowdown = 1 armor_type = /datum/armor/suit_space flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT - cold_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT_OFF - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT strip_delay = 80 equip_delay_other = 80 @@ -121,7 +121,10 @@ // If we got here, it means thermals are on, the cell is in and the cell has // just had enough charge subtracted from it to power the thermal regulator - user.adjust_bodytemperature(get_temp_change_amount((temperature_setting - user.bodytemperature), 0.08 * seconds_per_tick)) + if(user.bodytemperature < temperature_setting) + user.adjust_bodytemperature((temperature_setting - user.bodytemperature) * 0.08 * seconds_per_tick, max_temp = temperature_setting) + else if(user.bodytemperature > temperature_setting) + user.adjust_bodytemperature((temperature_setting - user.bodytemperature) * 0.08 * seconds_per_tick, min_temp = temperature_setting) update_hud_icon(user) // Clean up the cell on destroy @@ -290,12 +293,12 @@ /obj/item/clothing/head/helmet/space/suicide_act(mob/living/carbon/user) var/datum/gas_mixture/environment = user.loc.return_air() - if(HAS_TRAIT(user, TRAIT_RESISTCOLD) || !environment || environment.return_temperature() >= user.get_body_temp_cold_damage_limit()) + if(HAS_TRAIT(user, TRAIT_RESISTCOLD) || !environment || environment.return_temperature() >= user.bodytemp_cold_damage_limit) user.visible_message(span_suicide("[user] is beating [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")) return BRUTELOSS user.say("You want proof? I'll give you proof! Here's proof of what'll happen to you if you stay here with your stuff!", forced = "space helmet suicide") user.visible_message(span_suicide("[user] is removing [user.p_their()] helmet to make a point! Yo, holy shit, [user.p_they()] dead!")) //the use of p_they() instead of p_their() here is intentional - user.adjust_bodytemperature(-300) + user.adjust_bodytemperature(-INFINITY, min_temp = CELCIUS_TO_KELVIN(-225 CELCIUS)) user.apply_status_effect(/datum/status_effect/freon) if(!ishuman(user)) return FIRELOSS diff --git a/code/modules/clothing/suits/_suits.dm b/code/modules/clothing/suits/_suits.dm index 0e9efa5b3fb9..8630f573f31e 100644 --- a/code/modules/clothing/suits/_suits.dm +++ b/code/modules/clothing/suits/_suits.dm @@ -14,7 +14,7 @@ drop_sound = 'sound/items/handling/cloth_drop.ogg' pickup_sound = 'sound/items/handling/cloth_pickup.ogg' slot_flags = ITEM_SLOT_OCLOTHING - var/blood_overlay_type = "suit" + blood_overlay_type = "suit" limb_integrity = 0 // disabled for most exo-suits var/suittoggled = FALSE // sec duster toggling and more supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION @@ -30,8 +30,6 @@ if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damaged[blood_overlay_type]") - if(GET_ATOM_BLOOD_DNA_LENGTH(src)) - . += mutable_appearance('icons/effects/blood.dmi', "[blood_overlay_type]blood") var/mob/living/carbon/human/wearer = loc if(!ishuman(wearer) || !wearer.w_uniform) diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 0e8b74b4b107..709bbb594f97 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -3,9 +3,9 @@ worn_icon = 'icons/mob/clothing/suits/armor.dmi' allowed = null body_parts_covered = CHEST - cold_protection = CHEST|GROIN + min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT - heat_protection = CHEST|GROIN + max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT strip_delay = 60 equip_delay_other = 40 @@ -71,9 +71,9 @@ clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS armor_type = /datum/armor/vest_marine - cold_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT_OFF - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + resistance_flags = FIRE_PROOF | ACID_PROOF /datum/armor/vest_marine @@ -146,8 +146,8 @@ inhand_icon_state = "greatcoat" body_parts_covered = CHEST|GROIN|ARMS|LEGS armor_type = /datum/armor/armor_hos - cold_protection = CHEST|GROIN|LEGS|ARMS - heat_protection = CHEST|GROIN|LEGS|ARMS + + strip_delay = 80 /datum/armor/armor_hos @@ -193,8 +193,8 @@ icon_state = "warden_alt" inhand_icon_state = "armor" body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS|HANDS - heat_protection = CHEST|GROIN|ARMS|HANDS + + strip_delay = 70 resistance_flags = FLAMMABLE dog_fashion = null @@ -210,8 +210,8 @@ icon_state = "leathercoat-sec" inhand_icon_state = "hostrench" body_parts_covered = CHEST|GROIN|ARMS|LEGS - cold_protection = CHEST|GROIN|LEGS|ARMS - heat_protection = CHEST|GROIN|LEGS|ARMS + + dog_fashion = null /obj/item/clothing/suit/armor/vest/capcarapace @@ -256,8 +256,8 @@ icon_state = "riot" inhand_icon_state = "swat_suit" body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + + armor_type = /datum/armor/armor_riot clothing_flags = BLOCKS_SHOVE_KNOCKDOWN strip_delay = 80 @@ -318,8 +318,8 @@ inhand_icon_state = "armor_reflec" blood_overlay_type = "armor" body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS - heat_protection = CHEST|GROIN|ARMS + + armor_type = /datum/armor/armor_laserproof resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF var/hit_reflect_chance = 50 @@ -358,9 +358,9 @@ strip_delay = 120 resistance_flags = FIRE_PROOF | ACID_PROOF clothing_flags = THICKMATERIAL - cold_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT_OFF - heat_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT slowdown = 0.5 //monkestation edit, 0.7 to 0.5 body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS @@ -404,8 +404,8 @@ body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT clothing_flags = THICKMATERIAL - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + + armor_type = /datum/armor/armor_tdome /datum/armor/armor_tdome @@ -433,8 +433,8 @@ /obj/item/clothing/suit/armor/tdome/holosuit name = "thunderdome suit" armor_type = /datum/armor/tdome_holosuit - cold_protection = null - heat_protection = null + max_heat_protection_temperature = null + min_cold_protection_temperature = null /datum/armor/tdome_holosuit melee = 10 @@ -527,7 +527,7 @@ icon_state = "rus_coat" inhand_icon_state = null body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT armor_type = /datum/armor/vest_russian_coat dog_fashion = null @@ -551,8 +551,8 @@ material_flags = MATERIAL_EFFECTS | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS//Can change color and add prefix armor_type = /datum/armor/armor_elder_atmosian body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + + /obj/item/clothing/suit/armor/elder_atmosian/Initialize(mapload) . = ..() @@ -607,7 +607,7 @@ icon_state = "militia" inhand_icon_state = "b_suit" body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT armor_type = /datum/armor/coat_militia diff --git a/code/modules/clothing/suits/costume.dm b/code/modules/clothing/suits/costume.dm index eb99688de85e..7d1f5f52e462 100644 --- a/code/modules/clothing/suits/costume.dm +++ b/code/modules/clothing/suits/costume.dm @@ -246,7 +246,7 @@ worn_icon = 'icons/mob/clothing/suits/costume.dmi' inhand_icon_state = "labcoat" body_parts_covered = CHEST|GROIN|ARMS|LEGS|FEET - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT //Space carp like space, so you should too allowed = list(/obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/gun/ballistic/rifle/boltaction/harpoon) hoodtype = /obj/item/clothing/head/hooded/carp_hood @@ -258,7 +258,7 @@ worn_icon = 'icons/mob/clothing/head/costume.dmi' icon_state = "carp_casual" body_parts_covered = HEAD - cold_protection = HEAD + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT flags_inv = HIDEHAIR|HIDEEARS @@ -280,9 +280,9 @@ armor_type = /datum/armor/carp_costume_spaceproof allowed = list(/obj/item/tank/internals, /obj/item/gun/ballistic/rifle/boltaction/harpoon) //I'm giving you a hint here flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT clothing_flags = STOPSPRESSUREDAMAGE|THICKMATERIAL body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS @@ -302,7 +302,7 @@ armor_type = /datum/armor/carp_hood_spaceproof flags_inv = HIDEEARS|HIDEHAIR|HIDEFACIALHAIR //facial hair will clip with the helm, this'll need a dynamic_fhair_suffix at some point. min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = SPACE_HELM_MAX_TEMP_PROTECT clothing_flags = STOPSPRESSUREDAMAGE|THICKMATERIAL|SNUG_FIT|PLASMAMAN_HELMET_EXEMPT body_parts_covered = HEAD @@ -333,7 +333,7 @@ worn_icon = 'icons/mob/clothing/suits/costume.dmi' inhand_icon_state = "labcoat" body_parts_covered = CHEST|GROIN|ARMS|LEGS|FEET - //cold_protection = CHEST|GROIN|ARMS + // //min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT allowed = list() hoodtype = /obj/item/clothing/head/hooded/ian_hood @@ -346,7 +346,7 @@ worn_icon = 'icons/mob/clothing/head/costume.dmi' icon_state = "ian" body_parts_covered = HEAD - //cold_protection = HEAD + // //min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT flags_inv = HIDEHAIR|HIDEEARS diff --git a/code/modules/clothing/suits/jacket.dm b/code/modules/clothing/suits/jacket.dm index ae2cb14caa2c..4b8db2052995 100644 --- a/code/modules/clothing/suits/jacket.dm +++ b/code/modules/clothing/suits/jacket.dm @@ -12,7 +12,7 @@ /obj/item/storage/belt/holster, ) body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT species_exception = list(/datum/species/golem) @@ -41,7 +41,7 @@ desc = "Rated 10 out of 10 in Cosmo for best coat brand." icon_state = "fancy_coat" body_parts_covered = CHEST|GROIN|LEGS|ARMS - cold_protection = CHEST|GROIN|LEGS|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON greyscale_config = /datum/greyscale_config/fancy_coat @@ -87,7 +87,7 @@ icon_state = "puffervest" inhand_icon_state = "armor" body_parts_covered = CHEST|GROIN - cold_protection = CHEST|GROIN + armor_type = /datum/armor/puffer_vest /datum/armor/puffer_vest diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm index a9da4854937a..cf7aed8ec995 100644 --- a/code/modules/clothing/suits/jobs.dm +++ b/code/modules/clothing/suits/jobs.dm @@ -106,8 +106,8 @@ blood_overlay_type = "coat" body_parts_covered = CHEST|GROIN|ARMS armor_type = /datum/armor/jacket_det_suit - cold_protection = CHEST|GROIN|ARMS - heat_protection = CHEST|GROIN|ARMS + + /datum/armor/jacket_det_suit melee = 25 @@ -293,8 +293,8 @@ /obj/item/tank/internals, ) armor_type = /datum/armor/jacket_curator - cold_protection = CHEST|ARMS - heat_protection = CHEST|ARMS + + //Robotocist /datum/armor/jacket_curator diff --git a/code/modules/clothing/suits/moth.dm b/code/modules/clothing/suits/moth.dm index a3e789daa245..65b9572a0ebf 100644 --- a/code/modules/clothing/suits/moth.dm +++ b/code/modules/clothing/suits/moth.dm @@ -27,6 +27,6 @@ greyscale_config_worn = /datum/greyscale_config/mothcoat_winter_worn greyscale_colors = "#557979#795e55" body_parts_covered = CHEST|GROIN|ARMS|LEGS - cold_protection = CHEST|GROIN|ARMS|LEGS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm index c867349f6564..7e3cd62ac77d 100644 --- a/code/modules/clothing/suits/utility.dm +++ b/code/modules/clothing/suits/utility.dm @@ -31,9 +31,9 @@ armor_type = /datum/armor/utility_fire flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT strip_delay = 60 equip_delay_other = 60 @@ -57,8 +57,8 @@ /obj/item/clothing/suit/utility/fire/firefighter icon_state = "firesuit" inhand_icon_state = "firefighter" - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS + + body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS /obj/item/clothing/suit/utility/fire/heavy @@ -74,8 +74,8 @@ icon_state = "atmos_firesuit" inhand_icon_state = "firefighter_atmos" max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS + + body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS flags_inv = HIDESHOES|HIDEJUMPSUIT @@ -90,9 +90,9 @@ armor_type = /datum/armor/utility_bomb_hood flags_inv = HIDEFACE|HIDEMASK|HIDEEARS|HIDEEYES|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT - cold_protection = HEAD + min_cold_protection_temperature = HELMET_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = HELMET_MAX_TEMP_PROTECT strip_delay = 70 equip_delay_other = 70 @@ -119,9 +119,9 @@ slowdown = 2 armor_type = /datum/armor/utility_bomb_suit flags_inv = HIDEJUMPSUIT - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT strip_delay = 70 equip_delay_other = 70 diff --git a/code/modules/clothing/suits/wintercoats.dm b/code/modules/clothing/suits/wintercoats.dm index d4461b8812f1..51a85dbac59d 100644 --- a/code/modules/clothing/suits/wintercoats.dm +++ b/code/modules/clothing/suits/wintercoats.dm @@ -7,7 +7,7 @@ worn_icon = 'icons/mob/clothing/suits/wintercoat.dmi' inhand_icon_state = "coatwinter" body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT allowed = list() armor_type = /datum/armor/hooded_wintercoat @@ -36,7 +36,7 @@ icon_state = "hood_winter" worn_icon = 'icons/mob/clothing/head/winterhood.dmi' body_parts_covered = HEAD - cold_protection = HEAD + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT flags_inv = HIDEHAIR|HIDEEARS armor_type = /datum/armor/hooded_winterhood diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 9b6b70f9dd7c..2e5cae08d5da 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -11,6 +11,7 @@ drop_sound = 'sound/items/handling/cloth_drop.ogg' pickup_sound = 'sound/items/handling/cloth_pickup.ogg' limb_integrity = 30 + blood_overlay_type = "uniform" /// Has this undersuit been freshly laundered and, as such, imparts a mood bonus for wearing var/freshly_laundered = FALSE @@ -88,8 +89,6 @@ if(damaged_clothes) . += mutable_appearance('icons/effects/item_damage.dmi', "damageduniform") - if(GET_ATOM_BLOOD_DNA_LENGTH(src)) - . += mutable_appearance('icons/effects/blood.dmi', "uniformblood") if(accessory_overlay) . += accessory_overlay diff --git a/code/modules/clothing/under/costume.dm b/code/modules/clothing/under/costume.dm index 16ad9ba6e9eb..5e54cd640a11 100644 --- a/code/modules/clothing/under/costume.dm +++ b/code/modules/clothing/under/costume.dm @@ -228,7 +228,7 @@ icon_state = "red_mech_suit" inhand_icon_state = null body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + female_sprite_flags = NO_FEMALE_UNIFORM alternate_worn_layer = GLOVES_LAYER //covers hands but gloves can go over it. This is how these things work in my head. can_adjust = FALSE diff --git a/code/modules/clothing/under/jobs/civilian/curator.dm b/code/modules/clothing/under/jobs/civilian/curator.dm index 1e459604e205..315c27675d6a 100644 --- a/code/modules/clothing/under/jobs/civilian/curator.dm +++ b/code/modules/clothing/under/jobs/civilian/curator.dm @@ -41,9 +41,9 @@ w_class = WEIGHT_CLASS_BULKY armor_type = /datum/armor/curator_nasa body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - cold_protection = CHEST | GROIN | LEGS | ARMS //Needs gloves and shoes with cold protection to be fully protected. + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT can_adjust = FALSE resistance_flags = NONE diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 68749df3ed0b..fc3a0ce814af 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -50,9 +50,9 @@ desc = "A cybernetically enhanced jumpsuit used for administrative duties." body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS armor_type = /datum/armor/misc_adminsuit - cold_protection = CHEST | GROIN | LEGS | FEET | ARMS | HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT can_adjust = FALSE resistance_flags = FIRE_PROOF | ACID_PROOF diff --git a/code/modules/detectivework/scanner.dm b/code/modules/detectivework/scanner.dm index 47734b398ab8..7da9153548ad 100644 --- a/code/modules/detectivework/scanner.dm +++ b/code/modules/detectivework/scanner.dm @@ -169,7 +169,7 @@ for(var/bloodtype in blood) LAZYADD(det_data[DETSCAN_CATEGORY_BLOOD], \ - "Type: [blood[bloodtype]] DNA (UE): [bloodtype]") + "Type: [GLOB.blood_types[blood[bloodtype]]] DNA (UE): [bloodtype]") // sends it off to be modified by the items SEND_SIGNAL(scanned_atom, COMSIG_DETECTIVE_SCANNED, user, det_data) diff --git a/code/modules/food_and_drinks/pizzabox.dm b/code/modules/food_and_drinks/pizzabox.dm index 7c0b9b346d36..eb98bd58f39e 100644 --- a/code/modules/food_and_drinks/pizzabox.dm +++ b/code/modules/food_and_drinks/pizzabox.dm @@ -382,14 +382,14 @@ if(pizza.type != pizza_preferences[nommer.ckey]) QDEL_NULL(pizza) else - pizza.foodtypes = nommer.dna.species.liked_food //make sure it's our favourite + pizza.foodtypes = nommer.get_liked_foodtypes() //make sure it's our favourite return var/obj/item/food/pizza/favourite_pizza_type = pizza_preferences[nommer.ckey] pizza = new favourite_pizza_type boxtag_set = FALSE update_appearance() //update our boxtag to match our new pizza - pizza.foodtypes = nommer.dna.species.liked_food //it's our favorite! + pizza.foodtypes = nommer.get_liked_foodtypes() //it's our favorite! ///screentips for pizzaboxes /obj/item/pizzabox/add_context(atom/source, list/context, obj/item/held_item, mob/user) diff --git a/code/modules/forensics/forensics_helpers.dm b/code/modules/forensics/forensics_helpers.dm index 081d6f25d4f1..90624dc7491b 100644 --- a/code/modules/forensics/forensics_helpers.dm +++ b/code/modules/forensics/forensics_helpers.dm @@ -67,13 +67,14 @@ return FALSE /obj/add_blood_DNA(list/blood_DNA_to_add) - . = ..() if (isnull(blood_DNA_to_add)) - return . + return FALSE if (forensics) forensics.inherit_new(blood_DNA = blood_DNA_to_add) else forensics = new(src, blood_DNA = blood_DNA_to_add) + cached_blood_dna_color = null + update_appearance() return TRUE /obj/item/add_blood_DNA(list/blood_DNA_to_add) @@ -82,8 +83,10 @@ return ..() /obj/item/clothing/gloves/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) - transfer_blood = rand(2, 4) - return ..() + . = ..() + if(.) + transfer_blood = rand(2, 4) + return . /turf/add_blood_DNA(list/blood_dna, list/datum/disease/diseases) var/obj/effect/decal/cleanable/blood/splatter/blood_splatter = locate() in src @@ -109,6 +112,7 @@ forensics = new(src) forensics.inherit_new(blood_DNA = blood_DNA_to_add) blood_in_hands = rand(2, 4) + cached_blood_dna_color = null update_worn_gloves() return TRUE diff --git a/code/modules/hydroponics/grown/replicapod.dm b/code/modules/hydroponics/grown/replicapod.dm index be51fe2d9e98..5a2c84b026af 100644 --- a/code/modules/hydroponics/grown/replicapod.dm +++ b/code/modules/hydroponics/grown/replicapod.dm @@ -191,8 +191,9 @@ podman.ckey = ckey_holder podman.gender = blood_gender podman.faction |= factions - if(!features["mcolor"]) - features["mcolor"] = "#59CE00" + var/datum/color_palette/generic_colors/palette = podman.dna.color_palettes[/datum/color_palette/generic_colors] + if(!palette.mutant_color) + palette.mutant_color = "#59CE00" if(!features["pod_hair"]) features["pod_hair"] = pick(GLOB.pod_hair_list) @@ -208,6 +209,6 @@ most_plentiful_reagent.Cut() most_plentiful_reagent[reagent] = reagents_add[reagent] - podman.dna.species.exotic_blood = most_plentiful_reagent[1] + //podman.dna.species.exotic_blood = most_plentiful_reagent[1] //Monkestation edit BLOOD_DATUM: This needs to be looked into investigate_log("[key_name(mind)] cloned as a podman via [src] in [parent]", INVESTIGATE_BOTANY) return result diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm index 0da6d6a811a4..84b2ee49b7ab 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seeds.dm @@ -342,7 +342,7 @@ var/amount = max(1, round((edible_vol)*(potency/100) * reagent_overflow_mod, 1)) //the plant will always have at least 1u of each of the reagents in its reagent production traits var/list/data if(rid == /datum/reagent/blood) // Hack to make blood in plants always O- - data = list("blood_type" = "O-") + data = list("blood_type" = /datum/blood_type/crew/human/o_minus) if(istype(grown_edible) && (rid == /datum/reagent/consumable/nutriment || rid == /datum/reagent/consumable/nutriment/vitamin)) data = grown_edible.tastes // apple tastes of apple. T.reagents.add_reagent(rid, amount, data) diff --git a/code/modules/hydroponics/unique_plant_genes.dm b/code/modules/hydroponics/unique_plant_genes.dm index 938ecadb78d8..f2c318faa81f 100644 --- a/code/modules/hydroponics/unique_plant_genes.dm +++ b/code/modules/hydroponics/unique_plant_genes.dm @@ -303,8 +303,8 @@ stop_backfire_effect() return - our_mob.adjust_bodytemperature(7.5 * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick) - if(SPT_PROB(5, seconds_per_tick)) + our_mob.adjust_bodytemperature(0.5 KELVIN * seconds_per_tick) + if(!HAS_TRAIT(our_mob, TRAIT_RESISTHEAT) && SPT_PROB(5, seconds_per_tick)) to_chat(our_mob, span_warning("Your hand holding [our_plant] burns!")) /// Bluespace Tomato squashing on the user on backfire @@ -433,7 +433,7 @@ var/obj/item/seeds/our_seed = our_plant.get_plant_seed() var/mob/living/spawned_mob = new killer_plant(our_plant.drop_location()) var/health_mid_point = 150 - var/health_max_value = 40 + var/health_max_value = 40 spawned_mob.maxHealth += qp_sigmoid(health_mid_point, health_max_value, our_seed.endurance) spawned_mob.health = spawned_mob.maxHealth if(ishostile(spawned_mob)) diff --git a/code/modules/instruments/songs/_song.dm b/code/modules/instruments/songs/_song.dm index 3067bc8a426f..7922a4d35833 100644 --- a/code/modules/instruments/songs/_song.dm +++ b/code/modules/instruments/songs/_song.dm @@ -123,6 +123,8 @@ var/cached_exponential_dropoff = 1.045 ///////////////////////////////////////////////////////////////////////// var/mixing_channel = CHANNEL_INSTRUMENTS + ///care about distance? + var/cares_about_distance = TRUE /datum/song/New(atom/parent, list/instrument_ids, new_range) SSinstruments.on_song_new(src) diff --git a/code/modules/instruments/songs/editor.dm b/code/modules/instruments/songs/editor.dm index ffa64a6098b2..68a649fc58fb 100644 --- a/code/modules/instruments/songs/editor.dm +++ b/code/modules/instruments/songs/editor.dm @@ -115,10 +115,11 @@ updateDialog(usr) // make sure updates when complete /datum/song/Topic(href, href_list) - if(!usr.can_perform_action(parent, ALLOW_RESTING)) - usr << browse(null, "window=instrument") - usr.unset_machine() - return + if(cares_about_distance) + if(!usr.can_perform_action(parent, ALLOW_RESTING)) + usr << browse(null, "window=instrument") + usr.unset_machine() + return parent.add_fingerprint(usr) @@ -131,7 +132,7 @@ var/t = "" do t = html_encode(input(usr, "Please paste the entire song, formatted:", text("[]", name), t) as message) - if(!in_range(parent, usr)) + if(!in_range(parent, usr) && cares_about_distance) return if(length_char(t) >= MUSIC_MAXLINES * MUSIC_MAXLINECHARS) @@ -158,7 +159,7 @@ else if(href_list["newline"]) var/newline = tgui_input_text(usr, "Enter your line ", parent.name) - if(!newline || !in_range(parent, usr)) + if(!newline || (!in_range(parent, usr) && cares_about_distance)) return if(lines.len > MUSIC_MAXLINES) return @@ -175,7 +176,7 @@ else if(href_list["modifyline"]) var/num = round(text2num(href_list["modifyline"]),1) var/content = tgui_input_text(usr, "Enter your line ", parent.name, lines[num], MUSIC_MAXLINECHARS) - if(!content || !in_range(parent, usr)) + if(!content || (!in_range(parent, usr) && cares_about_distance)) return if(num > lines.len || num < 1) return diff --git a/code/modules/jobs/job_types/chaplain/chaplain_costumes.dm b/code/modules/jobs/job_types/chaplain/chaplain_costumes.dm index c0751b2e3d1b..669a038bbfa8 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain_costumes.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_costumes.dm @@ -7,8 +7,8 @@ /obj/item/clothing/suit/chaplainsuit/armor body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + + armor_type = /datum/armor/chaplainsuit_armor clothing_flags = BLOCKS_SHOVE_KNOCKDOWN strip_delay = 80 diff --git a/code/modules/jobs/job_types/chaplain/chaplain_divine_archer.dm b/code/modules/jobs/job_types/chaplain/chaplain_divine_archer.dm index 48bdf25a22f2..d88fb2f35906 100644 --- a/code/modules/jobs/job_types/chaplain/chaplain_divine_archer.dm +++ b/code/modules/jobs/job_types/chaplain/chaplain_divine_archer.dm @@ -17,8 +17,8 @@ icon_state = "archercoat" inhand_icon_state = "archercoat" body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + + armor_type = /datum/armor/chaplainsuit_armor_weaker clothing_flags = BLOCKS_SHOVE_KNOCKDOWN strip_delay = 80 diff --git a/code/modules/jobs/job_types/warden.dm b/code/modules/jobs/job_types/warden.dm index 62e7dc9e2058..6c7db7059193 100644 --- a/code/modules/jobs/job_types/warden.dm +++ b/code/modules/jobs/job_types/warden.dm @@ -10,9 +10,9 @@ spawn_positions = 1 supervisors = SUPERVISOR_HOS minimal_player_age = 7 - exp_requirements = 300 + exp_requirements = 600 //monkestation edit changed warden to require 10 hours as sec instead of 5 hours as crew exp_required_type = EXP_TYPE_CREW - exp_granted_type = EXP_TYPE_CREW + exp_required_type_department = EXP_TYPE_SECURITY config_tag = "WARDEN" outfit = /datum/outfit/job/warden @@ -49,7 +49,7 @@ id_trim = /datum/id_trim/job/warden uniform = /obj/item/clothing/under/rank/security/warden suit = /obj/item/clothing/suit/armor/vest/warden/alt - suit_store = /obj/item/gun/energy/disabler + suit_store = /obj/item/gun/energy/taser backpack_contents = list( /obj/item/evidencebag = 1, ) diff --git a/code/modules/mapfluff/ruins/icemoonruin_code/wrath.dm b/code/modules/mapfluff/ruins/icemoonruin_code/wrath.dm index f5db91dad016..ae25cf6f2f4b 100644 --- a/code/modules/mapfluff/ruins/icemoonruin_code/wrath.dm +++ b/code/modules/mapfluff/ruins/icemoonruin_code/wrath.dm @@ -3,9 +3,9 @@ desc = "These gloves allow the user to rip apart bodies with precision and ease." icon_state = "black" greyscale_colors = "#2f2e31" - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT /obj/item/clothing/gloves/butchering/Initialize(mapload) diff --git a/code/modules/mining/equipment/explorer_gear.dm b/code/modules/mining/equipment/explorer_gear.dm index 65b80f0196d0..82cb1c63b97c 100644 --- a/code/modules/mining/equipment/explorer_gear.dm +++ b/code/modules/mining/equipment/explorer_gear.dm @@ -7,9 +7,9 @@ worn_icon = 'icons/mob/clothing/suits/utility.dmi' inhand_icon_state = null body_parts_covered = CHEST|GROIN|LEGS|ARMS - cold_protection = CHEST|GROIN|LEGS|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT - heat_protection = CHEST|GROIN|LEGS|ARMS + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT hoodtype = /obj/item/clothing/head/hooded/explorer armor_type = /datum/armor/hooded_explorer @@ -43,9 +43,9 @@ icon_state = "explorer" body_parts_covered = HEAD flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS - cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT armor_type = /datum/armor/hooded_explorer resistance_flags = FIRE_PROOF @@ -198,9 +198,9 @@ armor_type = /datum/armor/cloak_drake hoodtype = /obj/item/clothing/head/hooded/cloakhood/drake body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT resistance_flags = FIRE_PROOF | ACID_PROOF transparent_protection = HIDEGLOVES|HIDESUITSTORAGE|HIDEJUMPSUIT|HIDESHOES @@ -223,9 +223,9 @@ desc = "The skull of a dragon." armor_type = /datum/armor/cloakhood_drake clothing_flags = SNUG_FIT - cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT resistance_flags = FIRE_PROOF | ACID_PROOF @@ -256,9 +256,9 @@ armor_type = /datum/armor/cloak_godslayer clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL hoodtype = /obj/item/clothing/head/hooded/cloakhood/godslayer - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS resistance_flags = FIRE_PROOF | ACID_PROOF | FREEZE_PROOF @@ -289,9 +289,9 @@ desc = "The horns and skull of a wendigo, held together by the remaining icey energy of a demonic miner." armor_type = /datum/armor/cloakhood_godslayer clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SNUG_FIT - cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT flash_protect = FLASH_PROTECTION_WELDER flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF diff --git a/code/modules/mining/lavaland/megafauna_loot.dm b/code/modules/mining/lavaland/megafauna_loot.dm index bd4ee168cb7d..a6c30b990a8e 100644 --- a/code/modules/mining/lavaland/megafauna_loot.dm +++ b/code/modules/mining/lavaland/megafauna_loot.dm @@ -255,9 +255,9 @@ icon_state = "hostile_env" hoodtype = /obj/item/clothing/head/hooded/hostile_environment armor_type = /datum/armor/hooded_hostile_environment - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS clothing_flags = THICKMATERIAL @@ -300,9 +300,9 @@ icon_state = "hostile_env" w_class = WEIGHT_CLASS_NORMAL armor_type = /datum/armor/hooded_hostile_environment - cold_protection = HEAD + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT clothing_flags = SNUG_FIT|THICKMATERIAL resistance_flags = FIRE_PROOF|LAVA_PROOF|ACID_PROOF @@ -735,8 +735,9 @@ switch(random) if(1) to_chat(user, span_danger("Your appearance morphs to that of a very small humanoid ash dragon! You get to look like a freak without the cool abilities.")) + var/datum/color_palette/generic_colors/located = consumer.dna.color_palettes[/datum/color_palette/generic_colors] + located.mutant_color = "#A02720" consumer.dna.features = list( - "mcolor" = "#A02720", "tail_lizard" = "Dark Tiger", "tail_human" = "None", "snout" = "Sharp", diff --git a/code/modules/mining/lavaland/tendril_loot.dm b/code/modules/mining/lavaland/tendril_loot.dm index 723d5300425f..1475b2caf3fb 100644 --- a/code/modules/mining/lavaland/tendril_loot.dm +++ b/code/modules/mining/lavaland/tendril_loot.dm @@ -543,7 +543,7 @@ if(!ishuman(exposed_mob) || exposed_mob.stat == DEAD) return var/mob/living/carbon/human/exposed_human = exposed_mob - if(!HAS_TRAIT(exposed_human, TRAIT_CAN_USE_FLIGHT_POTION) || reac_volume < 5 || !exposed_human.dna) + if(reac_volume < 5 || !exposed_human.dna) if((methods & INGEST) && show_message) to_chat(exposed_human, span_notice("You feel nothing but a terrible aftertaste.")) return @@ -560,7 +560,8 @@ exposed_human.emote("scream") /datum/reagent/flightpotion/proc/get_wing_choice(mob/living/carbon/human/needs_wings) - var/list/wing_types = needs_wings.dna.species.wing_types.Copy() + var/obj/item/bodypart/chest/chest = needs_wings.get_bodypart(BODY_ZONE_CHEST) + var/list/wing_types = chest.wing_types.Copy() if(wing_types.len == 1 || !needs_wings.client) return wing_types[1] var/list/radial_wings = list() @@ -615,9 +616,9 @@ toolspeed = 0.1 strip_delay = 40 equip_delay_other = 20 - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = LAVA_PROOF | FIRE_PROOF //they are from lavaland after all armor_type = /datum/armor/gloves_gauntlets @@ -664,9 +665,9 @@ worn_icon = 'icons/mob/clothing/suits/armor.dmi' hoodtype = /obj/item/clothing/head/hooded/berserker armor_type = /datum/armor/hooded_berserker - cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS resistance_flags = FIRE_PROOF @@ -711,9 +712,9 @@ worn_icon = 'icons/mob/clothing/head/helmet.dmi' armor_type = /datum/armor/hooded_berserker actions_types = list(/datum/action/item_action/berserk_mode) - cold_protection = HEAD + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT resistance_flags = FIRE_PROOF clothing_flags = SNUG_FIT|THICKMATERIAL diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 18a4e63e6eda..11c84bb06776 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -285,9 +285,11 @@ if(QDELETED(src) || !client) return // Disconnected while checking for the appearance ban. if(!isAI(spawning_mob)) // Unfortunately there's still snowflake AI code out there. - mind.original_character_slot_index = client.prefs.default_slot - mind.transfer_to(spawning_mob) //won't transfer key since the mind is not active - mind.set_original_character(spawning_mob) + // transfer_to sets mind to null + var/datum/mind/preserved_mind = mind + preserved_mind.original_character_slot_index = client.prefs.default_slot + preserved_mind.transfer_to(spawning_mob) //won't transfer key since the mind is not active + preserved_mind.set_original_character(spawning_mob) client.init_verbs() . = spawning_mob new_character = . diff --git a/code/modules/mob/dead/new_player/sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories.dm index 08608f33a042..1426e4648449 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories.dm @@ -81,6 +81,11 @@ /// Should this sprite block emissives? var/em_block = FALSE + var/datum/color_palette/palette + var/palette_key + var/fallback_key + var/list/layers + /datum/sprite_accessory/blank name = "None" icon_state = "None" @@ -1780,7 +1785,8 @@ MONKESTATION EDIT name = "Cat" icon = 'icons/mob/species/human/cat_features.dmi' icon_state = "default" - color_src = HAIR_COLOR + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /datum/sprite_accessory/tails/monkey name = "Monkey" @@ -1891,15 +1897,17 @@ MONKESTATION EDIT name = "Cat" icon_state = "cat" hasinner = TRUE - color_src = HAIR_COLOR + palette = /datum/color_palette/generic_colors + palette_key = HAIR_COLOR /datum/sprite_accessory/ears/fox icon = 'icons/mob/species/human/fox_features.dmi' name = "Fox" icon_state = "fox" hasinner = TRUE - color_src = HAIR_COLOR locked = TRUE + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /datum/sprite_accessory/wings/none name = "None" @@ -2092,8 +2100,9 @@ MONKESTATION EDIT /datum/sprite_accessory/caps icon = 'icons/mob/species/mush_cap.dmi' - color_src = HAIR_COLOR em_block = TRUE + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /datum/sprite_accessory/caps/round name = "Round" diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index d6a9075abf80..3e8254563d6c 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -187,7 +187,7 @@ return FALSE //nonliving mobs don't have hands /mob/living/put_in_hand_check(obj/item/I) - if(istype(I) && (((mobility_flags & MOBILITY_PICKUP) || ((stat >= SOFT_CRIT && (stat != DEAD && stat != UNCONSCIOUS)))) || (I.item_flags & ABSTRACT)) \ + if(istype(I) && (((mobility_flags & MOBILITY_PICKUP) || ((stat >= SOFT_CRIT && (stat != DEAD && stat != UNCONSCIOUS && stat != HARD_CRIT)))) || (I.item_flags & ABSTRACT)) \ && !(SEND_SIGNAL(src, COMSIG_LIVING_TRY_PUT_IN_HAND, I) & COMPONENT_LIVING_CANT_PUT_IN_HAND)) return TRUE return FALSE diff --git a/code/modules/mob/living/basic/basic.dm b/code/modules/mob/living/basic/basic.dm index 299a2c2856bc..c26c94456ff8 100644 --- a/code/modules/mob/living/basic/basic.dm +++ b/code/modules/mob/living/basic/basic.dm @@ -91,10 +91,8 @@ ///This damage is taken when atmos doesn't fit all the requirements above. Set to 0 to avoid adding the atmos_requirements element. var/unsuitable_atmos_damage = 1 - ///Minimal body temperature without receiving damage - var/minimum_survivable_temperature = NPC_DEFAULT_MIN_TEMP - ///Maximal body temperature without receiving damage - var/maximum_survivable_temperature = NPC_DEFAULT_MAX_TEMP + bodytemp_cold_damage_limit = NPC_DEFAULT_MIN_TEMP + bodytemp_heat_damage_limit = NPC_DEFAULT_MAX_TEMP ///This damage is taken when the body temp is too cold. Set both this and unsuitable_heat_damage to 0 to avoid adding the basic_body_temp_sensitive element. var/unsuitable_cold_damage = 1 ///This damage is taken when the body temp is too hot. Set both this and unsuitable_cold_damage to 0 to avoid adding the basic_body_temp_sensitive element. @@ -120,7 +118,6 @@ speak_emote = string_list(speak_emote) apply_atmos_requirements() - apply_temperature_requirements() /// Ensures this mob can take atmospheric damage if it's supposed to /mob/living/basic/proc/apply_atmos_requirements() @@ -130,12 +127,36 @@ habitable_atmos = string_assoc_list(habitable_atmos) AddElement(/datum/element/atmos_requirements, habitable_atmos, unsuitable_atmos_damage) -/// Ensures this mob can take temperature damage if it's supposed to -/mob/living/basic/proc/apply_temperature_requirements() - if(unsuitable_cold_damage == 0 && unsuitable_heat_damage == 0) - return - AddElement(/datum/element/basic_body_temp_sensitive, minimum_survivable_temperature, maximum_survivable_temperature, unsuitable_cold_damage, unsuitable_heat_damage) +/mob/living/basic/body_temperature_damage(datum/gas_mixture/environment, seconds_per_tick, times_fired) + if((bodytemperature < bodytemp_cold_damage_limit) && unsuitable_cold_damage) + adjust_health(unsuitable_cold_damage * seconds_per_tick) + + if((bodytemperature > bodytemp_heat_damage_limit) && unsuitable_heat_damage) + adjust_health(unsuitable_heat_damage * seconds_per_tick) + +/mob/living/basic/body_temperature_alerts() + if((bodytemperature < bodytemp_cold_damage_limit) && unsuitable_cold_damage) + switch(unsuitable_cold_damage) + if(1 to 5) + throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 1) + if(5 to 10) + throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 2) + if(10 to INFINITY) + throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 3) + . = TRUE + + if((bodytemperature > bodytemp_heat_damage_limit) && unsuitable_heat_damage) + switch(unsuitable_heat_damage) + if(1 to 5) + throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 1) + if(5 to 10) + throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 2) + if(10 to INFINITY) + throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 3) + . = TRUE + if(!.) + clear_alert(ALERT_TEMPERATURE) /mob/living/basic/Life(seconds_per_tick = SSMOBS_DT, times_fired) . = ..() @@ -155,7 +176,7 @@ health = 0 look_dead() -/mob/living/basic/gib() +/mob/living/basic/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) if(butcher_results || guaranteed_butcher_results) var/list/butcher_loot = list() if(butcher_results) @@ -228,17 +249,11 @@ if(NAMEOF(src, habitable_atmos), NAMEOF(src, unsuitable_atmos_damage)) RemoveElement(/datum/element/atmos_requirements, habitable_atmos, unsuitable_atmos_damage) . = TRUE - if(NAMEOF(src, minimum_survivable_temperature), NAMEOF(src, maximum_survivable_temperature), NAMEOF(src, unsuitable_cold_damage), NAMEOF(src, unsuitable_heat_damage)) - RemoveElement(/datum/element/basic_body_temp_sensitive, minimum_survivable_temperature, maximum_survivable_temperature, unsuitable_cold_damage, unsuitable_heat_damage) - . = TRUE - . = ..() switch(vname) if(NAMEOF(src, habitable_atmos), NAMEOF(src, unsuitable_atmos_damage)) apply_atmos_requirements() - if(NAMEOF(src, minimum_survivable_temperature), NAMEOF(src, maximum_survivable_temperature), NAMEOF(src, unsuitable_cold_damage), NAMEOF(src, unsuitable_heat_damage)) - apply_temperature_requirements() if(NAMEOF(src, speed)) datum_flags |= DF_VAR_EDITED set_varspeed(vval) @@ -276,9 +291,6 @@ /mob/living/basic/on_stamina_update() set_varspeed(initial(speed) + (staminaloss * 0.06)) -/mob/living/basic/on_fire_stack(seconds_per_tick, times_fired, datum/status_effect/fire_handler/fire_stacks/fire_handler) - adjust_bodytemperature((maximum_survivable_temperature + (fire_handler.stacks * 12)) * 0.5 * seconds_per_tick) - /mob/living/basic/get_fire_overlay(stacks, on_fire) var/fire_icon = "generic_fire" if(!GLOB.fire_appearances[fire_icon]) @@ -306,9 +318,3 @@ SET_PLANE(held, ABOVE_HUD_PLANE, our_turf) held.screen_loc = ui_hand_position(index) client.screen |= held - -/mob/living/basic/get_body_temp_heat_damage_limit() - return maximum_survivable_temperature - -/mob/living/basic/get_body_temp_cold_damage_limit() - return minimum_survivable_temperature diff --git a/code/modules/mob/living/basic/basic_defense.dm b/code/modules/mob/living/basic/basic_defense.dm index 27ff06b8bd41..e4b51033dfcd 100644 --- a/code/modules/mob/living/basic/basic_defense.dm +++ b/code/modules/mob/living/basic/basic_defense.dm @@ -128,7 +128,7 @@ return TRUE /mob/living/basic/check_projectile_armor(def_zone, obj/projectile/impacting_projectile, is_silent) - return 0 + return impacting_projectile.grazing ? 50 : 0 /mob/living/basic/ex_act(severity, target, origin) . = ..() diff --git a/code/modules/mob/living/basic/blob_minions/blob_mob.dm b/code/modules/mob/living/basic/blob_minions/blob_mob.dm index 31eebb9394cb..2465b83e6786 100644 --- a/code/modules/mob/living/basic/blob_minions/blob_mob.dm +++ b/code/modules/mob/living/basic/blob_minions/blob_mob.dm @@ -11,8 +11,8 @@ bubble_icon = "blob" speak_emote = null habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = 0 - maximum_survivable_temperature = INFINITY + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = INFINITY lighting_cutoff_red = 20 lighting_cutoff_green = 40 lighting_cutoff_blue = 30 diff --git a/code/modules/mob/living/basic/bots/_bots.dm b/code/modules/mob/living/basic/bots/_bots.dm index 26cf415c11d7..44724c980ab5 100644 --- a/code/modules/mob/living/basic/bots/_bots.dm +++ b/code/modules/mob/living/basic/bots/_bots.dm @@ -19,8 +19,8 @@ GLOBAL_LIST_INIT(command_strings, list( damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD, DIAG_BATT_HUD, DIAG_PATH_HUD = HUD_LIST_LIST) - maximum_survivable_temperature = INFINITY - minimum_survivable_temperature = 0 + bodytemp_heat_damage_limit = INFINITY + bodytemp_cold_damage_limit = -1 has_unlimited_silicon_privilege = TRUE sentience_type = SENTIENCE_ARTIFICIAL status_flags = NONE //no default canpush diff --git a/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm b/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm index 5da570369f17..2cdf99b9d2ed 100644 --- a/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm +++ b/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm @@ -98,9 +98,7 @@ )) ///blood we can clean var/static/list/cleanable_blood = typecacheof(list( - /obj/effect/decal/cleanable/xenoblood, /obj/effect/decal/cleanable/blood, - /obj/effect/decal/cleanable/trail_holder, )) ///pests we hunt var/static/list/huntable_pests = typecacheof(list( diff --git a/code/modules/mob/living/basic/clown/clown.dm b/code/modules/mob/living/basic/clown/clown.dm index ff5410fd0593..b65f43b18afc 100644 --- a/code/modules/mob/living/basic/clown/clown.dm +++ b/code/modules/mob/living/basic/clown/clown.dm @@ -23,8 +23,8 @@ basic_mob_flags = DEL_ON_DEATH initial_language_holder = /datum/language_holder/clown habitable_atmos = list("min_oxy" = 5, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 1, "min_co2" = 0, "max_co2" = 5, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = T0C - maximum_survivable_temperature = (T0C + 100) + bodytemp_cold_damage_limit = T0C + bodytemp_heat_damage_limit = (T0C + 100) unsuitable_atmos_damage = 10 unsuitable_heat_damage = 15 faction = list(FACTION_CLOWN) diff --git a/code/modules/mob/living/basic/cult/constructs/_construct.dm b/code/modules/mob/living/basic/cult/constructs/_construct.dm index 1cb7a68cb7da..162c6fe39df5 100644 --- a/code/modules/mob/living/basic/cult/constructs/_construct.dm +++ b/code/modules/mob/living/basic/cult/constructs/_construct.dm @@ -6,8 +6,8 @@ mob_biotypes = MOB_MINERAL faction = list(FACTION_CULT) unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 - maximum_survivable_temperature = INFINITY + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = INFINITY damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) pressure_resistance = 100 speed = 0 diff --git a/code/modules/mob/living/basic/drone/_drone.dm b/code/modules/mob/living/basic/drone/_drone.dm index 27c328617c4d..061ca478bc42 100644 --- a/code/modules/mob/living/basic/drone/_drone.dm +++ b/code/modules/mob/living/basic/drone/_drone.dm @@ -262,7 +262,7 @@ alert_drones(DRONE_NET_DISCONNECT) -/mob/living/basic/drone/gib() +/mob/living/basic/drone/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) dust() /mob/living/basic/drone/examine(mob/user) diff --git a/code/modules/mob/living/basic/farm_animals/goat/_goat.dm b/code/modules/mob/living/basic/farm_animals/goat/_goat.dm index 9c7046cccf7d..ea4e0f21c836 100644 --- a/code/modules/mob/living/basic/farm_animals/goat/_goat.dm +++ b/code/modules/mob/living/basic/farm_animals/goat/_goat.dm @@ -38,7 +38,7 @@ melee_damage_upper = 2 environment_smash = ENVIRONMENT_SMASH_NONE - minimum_survivable_temperature = COLD_ROOM_TEMP - 75 // enough so that they can survive the cold room spawn with plenty of room for comfort + bodytemp_cold_damage_limit = COLD_ROOM_TEMP - 75 // enough so that they can survive the cold room spawn with plenty of room for comfort blood_volume = BLOOD_VOLUME_NORMAL diff --git a/code/modules/mob/living/basic/farm_animals/goat/goat_subtypes.dm b/code/modules/mob/living/basic/farm_animals/goat/goat_subtypes.dm index 19d50fb38097..848c3789c7ad 100644 --- a/code/modules/mob/living/basic/farm_animals/goat/goat_subtypes.dm +++ b/code/modules/mob/living/basic/farm_animals/goat/goat_subtypes.dm @@ -10,3 +10,18 @@ /mob/living/basic/goat/pete/add_udder() return //no thank you + +/mob/living/basic/goat/pete/icebox + name = "Snowy Pete" + desc = parent_type::desc + " This one seems a bit more hardy to the cold." + bodytemp_cold_damage_limit = ICEBOX_MIN_TEMPERATURE - 5 KELVIN + habitable_atmos = list( + "min_oxy" = 1, + "max_oxy"= 0, + "min_plas" = 0, + "max_plas" = 1, + "min_co2" = 0, + "max_co2" = 5, + "min_n2" = 0, + "max_n2" = 0, + ) diff --git a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm index 637f5b283b81..ef0467871e50 100644 --- a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm +++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm @@ -95,7 +95,7 @@ else target.throw_at(get_edge_target_turf(target, dir), range = rand(1, 2), speed = 7, thrower = src) -/mob/living/basic/gorilla/gib() +/mob/living/basic/gorilla/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) var/mob/living/brain/gorilla_brain = new(drop_location()) gorilla_brain.name = real_name gorilla_brain.real_name = real_name diff --git a/code/modules/mob/living/basic/farm_animals/rabbit.dm b/code/modules/mob/living/basic/farm_animals/rabbit.dm index 992a127e05f4..faaf13225096 100644 --- a/code/modules/mob/living/basic/farm_animals/rabbit.dm +++ b/code/modules/mob/living/basic/farm_animals/rabbit.dm @@ -102,8 +102,8 @@ icon_prefix = "space_rabbit" ai_controller = /datum/ai_controller/basic_controller/rabbit/easter/space unsuitable_atmos_damage = 0 // Zero because we are meant to survive in space. - minimum_survivable_temperature = 0 // Minimum Allowable Body Temp, zero because we are meant to survive in space and we have a fucking RABBIT SPACE MASK. - maximum_survivable_temperature = 1500 // Maximum Allowable Body Temp, 1500 because we might overheat and die in said RABBIT SPACE MASK. + bodytemp_cold_damage_limit = -1 // Minimum Allowable Body Temp, zero because we are meant to survive in space and we have a fucking RABBIT SPACE MASK. + bodytemp_heat_damage_limit = 1500 // Maximum Allowable Body Temp, 1500 because we might overheat and die in said RABBIT SPACE MASK. unsuitable_cold_damage = 0 // Zero because we are meant to survive in space. /datum/ai_controller/basic_controller/rabbit/easter/space diff --git a/code/modules/mob/living/basic/guardian/guardian.dm b/code/modules/mob/living/basic/guardian/guardian.dm index c84e9bca4525..40296207db3b 100644 --- a/code/modules/mob/living/basic/guardian/guardian.dm +++ b/code/modules/mob/living/basic/guardian/guardian.dm @@ -196,7 +196,7 @@ return TRUE -/mob/living/basic/guardian/gib() +/mob/living/basic/guardian/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) death(TRUE) /mob/living/basic/guardian/dust(just_ash, drop_items, force) diff --git a/code/modules/mob/living/basic/guardian/guardian_types/gaseous.dm b/code/modules/mob/living/basic/guardian/guardian_types/gaseous.dm index 1471a0976396..8cf9566b78f1 100644 --- a/code/modules/mob/living/basic/guardian/guardian_types/gaseous.dm +++ b/code/modules/mob/living/basic/guardian/guardian_types/gaseous.dm @@ -13,7 +13,7 @@ /// Ability we use to select gases var/datum/action/cooldown/mob_cooldown/expel_gas/gas /// Rate of temperature stabilization per second. - var/temp_stabilization_rate = 0.1 + var/temp_stabilization_rate = 1 KELVIN /mob/living/basic/guardian/gaseous/Initialize(mapload, theme) . = ..() @@ -34,11 +34,12 @@ if (QDELETED(src)) return RegisterSignal(summoner, COMSIG_LIVING_IGNITED, PROC_REF(on_summoner_ignited)) - RegisterSignal(summoner, COMSIG_LIVING_LIFE, PROC_REF(on_summoner_life)) + summoner.add_homeostasis_level(REF(src), summoner.standard_body_temperature, temp_stabilization_rate) /mob/living/basic/guardian/gaseous/cut_summoner(different_person) if (!isnull(summoner)) - UnregisterSignal(summoner, list(COMSIG_LIVING_IGNITED, COMSIG_LIVING_LIFE)) + UnregisterSignal(summoner, COMSIG_LIVING_IGNITED) + summoner.remove_homeostasis_level(REF(src)) return ..() /// Prevent our summoner from being on fire @@ -47,11 +48,6 @@ source.extinguish_mob() source.set_fire_stacks(0, remove_wet_stacks = FALSE) -/// Maintain our summoner at a stable body temperature -/mob/living/basic/guardian/gaseous/proc/on_summoner_life(mob/living/source, seconds_per_tick, times_fired) - SIGNAL_HANDLER - source.adjust_bodytemperature(get_temp_change_amount((summoner.get_body_temp_normal() - summoner.bodytemperature), temp_stabilization_rate * seconds_per_tick)) - /mob/living/basic/guardian/gaseous/melee_attack(atom/target, list/modifiers, ignore_cooldown) . = ..() if(!. || !isliving(target)) diff --git a/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid.dm b/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid.dm index bb109fdde61a..7c37a4009ce8 100644 --- a/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid.dm +++ b/code/modules/mob/living/basic/jungle/mega_arachnid/mega_arachnid.dm @@ -20,8 +20,8 @@ faction = list(FACTION_JUNGLE) obj_damage = 30 environment_smash = ENVIRONMENT_SMASH_WALLS - minimum_survivable_temperature = T0C - maximum_survivable_temperature = T0C + 450 + bodytemp_cold_damage_limit = T0C + bodytemp_heat_damage_limit = T0C + 450 status_flags = NONE lighting_cutoff_red = 5 lighting_cutoff_green = 20 diff --git a/code/modules/mob/living/basic/jungle/seedling/seedling.dm b/code/modules/mob/living/basic/jungle/seedling/seedling.dm index 0968ef6bc5b8..2727caa5461b 100644 --- a/code/modules/mob/living/basic/jungle/seedling/seedling.dm +++ b/code/modules/mob/living/basic/jungle/seedling/seedling.dm @@ -14,8 +14,8 @@ icon_living = "seedling" icon_dead = "seedling_dead" habitable_atmos = list("min_oxy" = 2, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = 0 - maximum_survivable_temperature = 450 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 450 mob_biotypes = MOB_ORGANIC | MOB_PLANT maxHealth = 100 health = 100 diff --git a/code/modules/mob/living/basic/jungle/venus_human_trap.dm b/code/modules/mob/living/basic/jungle/venus_human_trap.dm index c679153ba7f2..897f84871f02 100644 --- a/code/modules/mob/living/basic/jungle/venus_human_trap.dm +++ b/code/modules/mob/living/basic/jungle/venus_human_trap.dm @@ -139,7 +139,7 @@ obj_damage = 60 melee_damage_lower = 10 melee_damage_upper = 20 - minimum_survivable_temperature = 100 + bodytemp_cold_damage_limit = 100 istate = ISTATE_HARM|ISTATE_BLOCKING basic_mob_flags = DEL_ON_DEATH death_message = "collapses into bits of plant matter." diff --git a/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm b/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm index ea8267b74fb5..497a6e4e66e0 100644 --- a/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm +++ b/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm @@ -84,8 +84,8 @@ mob_biotypes = MOB_ORGANIC|MOB_BEAST faction = list(FACTION_MINING) unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 - maximum_survivable_temperature = INFINITY + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = INFINITY speed = 1.5 maxHealth = 1 health = 1 diff --git a/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm b/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm index e066bac6a704..9b787caa12c8 100644 --- a/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm +++ b/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm @@ -13,8 +13,8 @@ mob_biotypes = MOB_ORGANIC|MOB_BEAST faction = list(FACTION_MINING) unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 - maximum_survivable_temperature = INFINITY + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = INFINITY friendly_verb_continuous = "chatters near" friendly_verb_simple = "chatter near" maxHealth = 1 diff --git a/code/modules/mob/living/basic/lavaland/mining.dm b/code/modules/mob/living/basic/lavaland/mining.dm index 825f36bed6b4..fac8cf66ee5e 100644 --- a/code/modules/mob/living/basic/lavaland/mining.dm +++ b/code/modules/mob/living/basic/lavaland/mining.dm @@ -6,8 +6,8 @@ mob_biotypes = MOB_ORGANIC|MOB_BEAST faction = list(FACTION_MINING) unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 - maximum_survivable_temperature = INFINITY + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = INFINITY // Pale purple, should be red enough to see stuff on lavaland lighting_cutoff_red = 25 lighting_cutoff_green = 15 diff --git a/code/modules/mob/living/basic/minebots/minebot.dm b/code/modules/mob/living/basic/minebots/minebot.dm index 6457239bdce8..b5de01f103fa 100644 --- a/code/modules/mob/living/basic/minebots/minebot.dm +++ b/code/modules/mob/living/basic/minebots/minebot.dm @@ -9,7 +9,7 @@ status_flags = CANSTUN|CANKNOCKDOWN|CANPUSH mouse_opacity = MOUSE_OPACITY_ICON habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = 0 + bodytemp_cold_damage_limit = -1 health = 125 maxHealth = 125 melee_damage_lower = 15 diff --git a/code/modules/mob/living/basic/pets/dog/corgi.dm b/code/modules/mob/living/basic/pets/dog/corgi.dm index ae0615da7188..48950bfa208c 100644 --- a/code/modules/mob/living/basic/pets/dog/corgi.dm +++ b/code/modules/mob/living/basic/pets/dog/corgi.dm @@ -75,7 +75,7 @@ update_appearance(UPDATE_OVERLAYS) return ..() -/mob/living/basic/pet/dog/corgi/gib() +/mob/living/basic/pet/dog/corgi/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) undress_dog() if(access_card) access_card.forceMove(drop_location()) @@ -574,8 +574,8 @@ can_be_shaved = FALSE held_state = "void_puppy" unsuitable_atmos_damage = 0 - minimum_survivable_temperature = TCMB - maximum_survivable_temperature = T0C + 40 + bodytemp_cold_damage_limit = TCMB + bodytemp_heat_damage_limit = T0C + 40 /mob/living/basic/pet/dog/corgi/puppy/void/Initialize(mapload) . = ..() diff --git a/code/modules/mob/living/basic/pets/pet.dm b/code/modules/mob/living/basic/pets/pet.dm index 6e8c87059e57..6940513250f8 100644 --- a/code/modules/mob/living/basic/pets/pet.dm +++ b/code/modules/mob/living/basic/pets/pet.dm @@ -54,7 +54,7 @@ . += mutable_appearance(icon, "[collar_icon_state][stat_tag]collar") . += mutable_appearance(icon, "[collar_icon_state][stat_tag]tag") -/mob/living/basic/pet/gib() +/mob/living/basic/pet/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) remove_collar(drop_location(), update_visuals = FALSE) return ..() diff --git a/code/modules/mob/living/basic/space_fauna/ant.dm b/code/modules/mob/living/basic/space_fauna/ant.dm index 27aa66cb0521..1e244345f309 100644 --- a/code/modules/mob/living/basic/space_fauna/ant.dm +++ b/code/modules/mob/living/basic/space_fauna/ant.dm @@ -30,8 +30,8 @@ health = 100 maxHealth = 100 light_outer_range = 1.5 // Bioluminescence! - minimum_survivable_temperature = T20C - 100 - maximum_survivable_temperature = T20C + 120 + bodytemp_cold_damage_limit = T20C - 100 + bodytemp_heat_damage_limit = T20C + 120 light_color = "#d43229" // The ants that comprise the giant ant still glow red despite the sludge. ai_controller = /datum/ai_controller/basic_controller/ant diff --git a/code/modules/mob/living/basic/space_fauna/bear/_bear.dm b/code/modules/mob/living/basic/space_fauna/bear/_bear.dm index cc34f271caca..5995844362a0 100644 --- a/code/modules/mob/living/basic/space_fauna/bear/_bear.dm +++ b/code/modules/mob/living/basic/space_fauna/bear/_bear.dm @@ -34,8 +34,8 @@ faction = list(FACTION_RUSSIAN) habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = TCMB - maximum_survivable_temperature = T0C + 1500 + bodytemp_cold_damage_limit = TCMB + bodytemp_heat_damage_limit = T0C + 1500 ai_controller = /datum/ai_controller/basic_controller/bear /// is the bear wearing a armor? var/armored = FALSE diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp.dm b/code/modules/mob/living/basic/space_fauna/carp/carp.dm index b889305f811e..8e077ec4e8f4 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp.dm @@ -42,8 +42,8 @@ greyscale_config = /datum/greyscale_config/carp ai_controller = /datum/ai_controller/basic_controller/carp habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = 0 - maximum_survivable_temperature = 1500 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 1500 /// Cytology cells you can swab from this creature var/cell_line = CELL_LINE_TABLE_CARP diff --git a/code/modules/mob/living/basic/space_fauna/demon/demon.dm b/code/modules/mob/living/basic/space_fauna/demon/demon.dm index ece0e9d4ee72..b2956424aa20 100644 --- a/code/modules/mob/living/basic/space_fauna/demon/demon.dm +++ b/code/modules/mob/living/basic/space_fauna/demon/demon.dm @@ -36,8 +36,8 @@ death_sound = 'sound/magic/demon_dies.ogg' habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = T0C - 25 //Weak to cold - maximum_survivable_temperature = INFINITY + bodytemp_cold_damage_limit = T0C - 25 //Weak to cold + bodytemp_heat_damage_limit = INFINITY basic_mob_flags = DEL_ON_DEATH diff --git a/code/modules/mob/living/basic/space_fauna/demon/demon_items.dm b/code/modules/mob/living/basic/space_fauna/demon/demon_items.dm index 8cdd7a6cf53f..804aba100d8b 100644 --- a/code/modules/mob/living/basic/space_fauna/demon/demon_items.dm +++ b/code/modules/mob/living/basic/space_fauna/demon/demon_items.dm @@ -54,3 +54,9 @@ icon = 'icons/obj/medical/organs/organs.dmi' icon_state = "innards" random_icon_states = null + base_name = "" + can_dry = FALSE + +/obj/effect/decal/cleanable/blood/innards/Initialize(mapload, list/datum/disease/diseases) + . = ..() + add_blood_DNA(list("DEMON BLOOD" = /datum/blood_type/animal)) diff --git a/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm b/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm index e52eb09ac0b7..4d606df4a54e 100644 --- a/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm +++ b/code/modules/mob/living/basic/space_fauna/demon/demon_subtypes.dm @@ -8,7 +8,7 @@ icon_state = "slaughter_demon" icon_living = "slaughter_demon" - minimum_survivable_temperature = TCMB + bodytemp_cold_damage_limit = TCMB // slaughter demons are specifically intended to have low melee damage, but as they hit and build up their killstreak // their wound bonuses grow and grow higher. this is how they're able to efficiently kill and slaughter their victims. diff --git a/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm b/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm index 51fd2162baa6..ecf19bb392a4 100644 --- a/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm +++ b/code/modules/mob/living/basic/space_fauna/eyeball/_eyeball.dm @@ -31,8 +31,8 @@ speak_emote = list("telepathically cries") habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = T0C - maximum_survivable_temperature = T0C + 1500 + bodytemp_cold_damage_limit = T0C + bodytemp_heat_damage_limit = T0C + 1500 sight = SEE_SELF|SEE_MOBS|SEE_OBJS|SEE_TURFS lighting_cutoff_red = 40 diff --git a/code/modules/mob/living/basic/space_fauna/garden_gnome.dm b/code/modules/mob/living/basic/space_fauna/garden_gnome.dm index 40debc7622bc..485d74ab0c8d 100644 --- a/code/modules/mob/living/basic/space_fauna/garden_gnome.dm +++ b/code/modules/mob/living/basic/space_fauna/garden_gnome.dm @@ -22,8 +22,8 @@ speak_emote = list("announces") unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 - maximum_survivable_temperature = 500 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 500 faction = list(FACTION_GNOME) mob_size = MOB_SIZE_SMALL diff --git a/code/modules/mob/living/basic/space_fauna/hivebot/_hivebot.dm b/code/modules/mob/living/basic/space_fauna/hivebot/_hivebot.dm index 66191f7ccd96..855145200f4f 100644 --- a/code/modules/mob/living/basic/space_fauna/hivebot/_hivebot.dm +++ b/code/modules/mob/living/basic/space_fauna/hivebot/_hivebot.dm @@ -30,7 +30,7 @@ death_message = "blows apart!" habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = TCMB + bodytemp_cold_damage_limit = TCMB ai_controller = /datum/ai_controller/basic_controller/hivebot ///does this type do range attacks? var/ranged_attacker = FALSE diff --git a/code/modules/mob/living/basic/space_fauna/killer_tomato.dm b/code/modules/mob/living/basic/space_fauna/killer_tomato.dm index c859289b56d7..5f11453e2857 100644 --- a/code/modules/mob/living/basic/space_fauna/killer_tomato.dm +++ b/code/modules/mob/living/basic/space_fauna/killer_tomato.dm @@ -30,8 +30,8 @@ faction = list(FACTION_PLANTS) habitable_atmos = list("min_oxy" = 5, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = T0C - 130 - maximum_survivable_temperature = T0C + 230 + bodytemp_cold_damage_limit = T0C - 130 + bodytemp_heat_damage_limit = T0C + 230 gold_core_spawnable = HOSTILE_SPAWN ai_controller = /datum/ai_controller/basic_controller/killer_tomato diff --git a/code/modules/mob/living/basic/space_fauna/lightgeist.dm b/code/modules/mob/living/basic/space_fauna/lightgeist.dm index 7fa070ea8a76..fe83090c8c75 100644 --- a/code/modules/mob/living/basic/space_fauna/lightgeist.dm +++ b/code/modules/mob/living/basic/space_fauna/lightgeist.dm @@ -38,8 +38,8 @@ light_outer_range = 4 faction = list(FACTION_NEUTRAL) unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 - maximum_survivable_temperature = 1500 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 1500 obj_damage = 0 environment_smash = ENVIRONMENT_SMASH_NONE diff --git a/code/modules/mob/living/basic/space_fauna/meteor_heart/meteor_heart.dm b/code/modules/mob/living/basic/space_fauna/meteor_heart/meteor_heart.dm index 7aa8efc2ecf2..8b18f51e80c2 100644 --- a/code/modules/mob/living/basic/space_fauna/meteor_heart/meteor_heart.dm +++ b/code/modules/mob/living/basic/space_fauna/meteor_heart/meteor_heart.dm @@ -21,8 +21,8 @@ faction = list() ai_controller = /datum/ai_controller/basic_controller/meteor_heart habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = 0 - maximum_survivable_temperature = 1500 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 1500 istate = ISTATE_HARM | ISTATE_BLOCKING move_resist = INFINITY // This mob IS the floor /// Action which sends a line of spikes chasing a player diff --git a/code/modules/mob/living/basic/space_fauna/morph.dm b/code/modules/mob/living/basic/space_fauna/morph.dm index 40d9a8802219..542f24b55df2 100644 --- a/code/modules/mob/living/basic/space_fauna/morph.dm +++ b/code/modules/mob/living/basic/space_fauna/morph.dm @@ -16,7 +16,7 @@ maxHealth = 150 health = 150 habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = TCMB + bodytemp_cold_damage_limit = TCMB obj_damage = 50 melee_damage_lower = 20 diff --git a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm index b3c6935c92ef..4e8e6319640b 100644 --- a/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm +++ b/code/modules/mob/living/basic/space_fauna/revenant/_revenant.dm @@ -34,8 +34,8 @@ unsuitable_atmos_damage = 0 damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) //I don't know how you'd apply those, but revenants no-sell them anyway. habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = 0 - maximum_survivable_temperature = INFINITY + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = INFINITY status_flags = NONE density = FALSE @@ -256,7 +256,7 @@ /mob/living/basic/revenant/dust(just_ash, drop_items, force) death() -/mob/living/basic/revenant/gib() +/mob/living/basic/revenant/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) death() /mob/living/basic/revenant/can_perform_action(atom/movable/target, action_bitflags) diff --git a/code/modules/mob/living/basic/space_fauna/robot_customer.dm b/code/modules/mob/living/basic/space_fauna/robot_customer.dm index e084e11f403c..e5c4a7dd0ead 100644 --- a/code/modules/mob/living/basic/space_fauna/robot_customer.dm +++ b/code/modules/mob/living/basic/space_fauna/robot_customer.dm @@ -15,8 +15,8 @@ sentience_type = SENTIENCE_ARTIFICIAL unsuitable_atmos_damage = 0 - minimum_survivable_temperature = TCMB - maximum_survivable_temperature = T0C + 1000 + bodytemp_cold_damage_limit = TCMB + bodytemp_heat_damage_limit = T0C + 1000 ai_controller = /datum/ai_controller/robot_customer diff --git a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spiders.dm b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spiders.dm index 92e27c4e3415..cb0340939573 100644 --- a/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spiders.dm +++ b/code/modules/mob/living/basic/space_fauna/spider/giant_spider/giant_spiders.dm @@ -386,8 +386,8 @@ /mob/living/basic/spider/giant/ice name = "giant ice spider" habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = 0 - maximum_survivable_temperature = 1500 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 1500 color = rgb(114,228,250) gold_core_spawnable = NO_SPAWN menu_description = "Versatile ice spider variant for frontline combat with high health and damage. Immune to temperature damage." @@ -400,8 +400,8 @@ /mob/living/basic/spider/giant/nurse/ice name = "giant ice spider" habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = 0 - maximum_survivable_temperature = 1500 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 1500 poison_type = /datum/reagent/consumable/frostoil color = rgb(114,228,250) menu_description = "Support ice spider variant specializing in healing their brethren and placing webbings very swiftly, but has very low amount of health and deals low damage. Immune to temperature damage." @@ -414,8 +414,8 @@ /mob/living/basic/spider/giant/hunter/ice name = "giant ice spider" habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = 0 - maximum_survivable_temperature = 1500 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 1500 poison_type = /datum/reagent/consumable/frostoil color = rgb(114,228,250) gold_core_spawnable = NO_SPAWN diff --git a/code/modules/mob/living/basic/space_fauna/statue/statue.dm b/code/modules/mob/living/basic/space_fauna/statue/statue.dm index f906044cdab6..7e56808c7cdf 100644 --- a/code/modules/mob/living/basic/space_fauna/statue/statue.dm +++ b/code/modules/mob/living/basic/space_fauna/statue/statue.dm @@ -89,7 +89,7 @@ // Turn to dust when gibbed -/mob/living/basic/statue/gib() +/mob/living/basic/statue/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) dust() // Statue powers diff --git a/code/modules/mob/living/basic/space_fauna/supermatter_spider.dm b/code/modules/mob/living/basic/space_fauna/supermatter_spider.dm index 02fd9ed1bcf1..d4b1a79ffece 100644 --- a/code/modules/mob/living/basic/space_fauna/supermatter_spider.dm +++ b/code/modules/mob/living/basic/space_fauna/supermatter_spider.dm @@ -20,8 +20,8 @@ maxHealth = 10 health = 10 - minimum_survivable_temperature = TCMB - maximum_survivable_temperature = T0C + 1250 + bodytemp_cold_damage_limit = TCMB + bodytemp_heat_damage_limit = T0C + 1250 habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) death_message = "falls to the ground, its shard dulling to a miserable grey!" diff --git a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_fugu.dm b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_fugu.dm index d963bdf41016..0c01693190f9 100644 --- a/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_fugu.dm +++ b/code/modules/mob/living/basic/space_fauna/wumborian_fugu/wumborian_fugu.dm @@ -42,8 +42,8 @@ lighting_cutoff_green = 10 lighting_cutoff_blue = 40 habitable_atmos = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = 0 - maximum_survivable_temperature = INFINITY + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = INFINITY ai_controller = /datum/ai_controller/basic_controller/wumborian_fugu /// Ability used by the mob to become large, dangerous, and invulnerable var/datum/action/cooldown/fugu_expand/expand diff --git a/code/modules/mob/living/basic/tree.dm b/code/modules/mob/living/basic/tree.dm index 5d20a877e9f7..23a34a7c1264 100644 --- a/code/modules/mob/living/basic/tree.dm +++ b/code/modules/mob/living/basic/tree.dm @@ -36,8 +36,8 @@ habitable_atmos = list("min_oxy" = 2, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) unsuitable_atmos_damage = 2.5 - minimum_survivable_temperature = 0 - maximum_survivable_temperature = 1200 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 1200 death_message = "is hacked into pieces!" diff --git a/code/modules/mob/living/basic/trooper/syndicate.dm b/code/modules/mob/living/basic/trooper/syndicate.dm index 2c6923a63f9a..f838e7650603 100644 --- a/code/modules/mob/living/basic/trooper/syndicate.dm +++ b/code/modules/mob/living/basic/trooper/syndicate.dm @@ -15,7 +15,7 @@ health = 170 loot = list(/obj/effect/gibspawner/human) unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 + bodytemp_cold_damage_limit = -1 mob_spawner = /obj/effect/mob_spawn/corpse/human/syndicatecommando /mob/living/basic/trooper/syndicate/space/Initialize(mapload) @@ -51,7 +51,7 @@ maxHealth = 170 health = 170 unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 + bodytemp_cold_damage_limit = -1 mob_spawner = /obj/effect/mob_spawn/corpse/human/syndicatecommando /mob/living/basic/trooper/syndicate/melee/space/Initialize(mapload) @@ -84,7 +84,7 @@ maxHealth = 170 health = 170 unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 + bodytemp_cold_damage_limit = -1 projectile_deflect_chance = 50 mob_spawner = /obj/effect/mob_spawn/corpse/human/syndicatecommando @@ -135,7 +135,7 @@ maxHealth = 170 health = 170 unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 + bodytemp_cold_damage_limit = -1 mob_spawner = /obj/effect/mob_spawn/corpse/human/syndicatecommando /mob/living/basic/trooper/syndicate/ranged/space/Initialize(mapload) @@ -167,7 +167,7 @@ maxHealth = 170 health = 170 unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 + bodytemp_cold_damage_limit = -1 mob_spawner = /obj/effect/mob_spawn/corpse/human/syndicatecommando /mob/living/basic/trooper/syndicate/ranged/smg/space/Initialize(mapload) @@ -193,7 +193,7 @@ maxHealth = 170 health = 170 unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 + bodytemp_cold_damage_limit = -1 speed = 1 mob_spawner = /obj/effect/mob_spawn/corpse/human/syndicatecommando @@ -220,8 +220,8 @@ mob_biotypes = MOB_ROBOTIC basic_mob_flags = DEL_ON_DEATH unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 - maximum_survivable_temperature = 700 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 700 unsuitable_cold_damage = 0 health = 25 maxHealth = 25 diff --git a/code/modules/mob/living/basic/vermin/cockroach.dm b/code/modules/mob/living/basic/vermin/cockroach.dm index 51652ae179ae..275c09243462 100644 --- a/code/modules/mob/living/basic/vermin/cockroach.dm +++ b/code/modules/mob/living/basic/vermin/cockroach.dm @@ -28,8 +28,8 @@ faction = list(FACTION_HOSTILE, FACTION_MAINT_CREATURES) unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 270 - maximum_survivable_temperature = INFINITY + bodytemp_cold_damage_limit = 270 + bodytemp_heat_damage_limit = INFINITY ai_controller = /datum/ai_controller/basic_controller/cockroach diff --git a/code/modules/mob/living/basic/vermin/lizard.dm b/code/modules/mob/living/basic/vermin/lizard.dm index 780ed6ee981e..350fca5c0046 100644 --- a/code/modules/mob/living/basic/vermin/lizard.dm +++ b/code/modules/mob/living/basic/vermin/lizard.dm @@ -71,8 +71,8 @@ icon_state = "lizard_space" icon_living = "lizard_space" unsuitable_atmos_damage = 0 - minimum_survivable_temperature = TCMB - maximum_survivable_temperature = T0C + 40 + bodytemp_cold_damage_limit = TCMB + bodytemp_heat_damage_limit = T0C + 40 /// Janitor's pet lizard. /mob/living/basic/lizard/wags_his_tail diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm index 4cccc6c6ba63..945ef89af5c0 100644 --- a/code/modules/mob/living/blood.dm +++ b/code/modules/mob/living/blood.dm @@ -7,46 +7,53 @@ // Takes care blood loss and regeneration /mob/living/carbon/human/handle_blood(seconds_per_tick, times_fired) - if(HAS_TRAIT(src, TRAIT_NOBLOOD) || (HAS_TRAIT(src, TRAIT_FAKEDEATH))) + if(HAS_TRAIT(src, TRAIT_NOBLOOD) || HAS_TRAIT(src, TRAIT_FAKEDEATH)) return - if(bodytemperature < BLOOD_STOP_TEMP || (HAS_TRAIT(src, TRAIT_HUSK))) //cold or husked people do not pump the blood. + if(bodytemperature < BLOOD_STOP_TEMP || HAS_TRAIT(src, TRAIT_HUSK)) //cold or husked people do not pump the blood. return - //Blood regeneration if there is some space - if(blood_volume < BLOOD_VOLUME_NORMAL && !HAS_TRAIT(src, TRAIT_NOHUNGER)) - var/nutrition_ratio = 0 - switch(nutrition) - if(0 to NUTRITION_LEVEL_STARVING) - nutrition_ratio = 0.2 - if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY) - nutrition_ratio = 0.4 - if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED) - nutrition_ratio = 0.6 - if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED) - nutrition_ratio = 0.8 - else - nutrition_ratio = 1 - if(satiety > 80) - nutrition_ratio *= 1.25 - adjust_nutrition(-nutrition_ratio * HUNGER_FACTOR * seconds_per_tick) - blood_volume = min(blood_volume + (BLOOD_REGEN_FACTOR * nutrition_ratio * seconds_per_tick), BLOOD_VOLUME_NORMAL) - - // we call lose_blood() here rather than quirk/process() to make sure that the blood loss happens in sync with life() - if(HAS_TRAIT(src, TRAIT_BLOOD_DEFICIENCY)) - var/datum/quirk/blooddeficiency/blooddeficiency = get_quirk(/datum/quirk/blooddeficiency) - if(!isnull(blooddeficiency)) - blooddeficiency.lose_blood(seconds_per_tick) + var/sigreturn = SEND_SIGNAL(src, COMSIG_HUMAN_ON_HANDLE_BLOOD, seconds_per_tick, times_fired) + if(sigreturn & HANDLE_BLOOD_HANDLED) + return + + if(!(sigreturn & HANDLE_BLOOD_NO_NUTRITION_DRAIN)) + if(blood_volume < BLOOD_VOLUME_NORMAL && !HAS_TRAIT(src, TRAIT_NOHUNGER)) + var/nutrition_ratio = 0 + switch(nutrition) + if(0 to NUTRITION_LEVEL_STARVING) + nutrition_ratio = 0.2 + if(NUTRITION_LEVEL_STARVING to NUTRITION_LEVEL_HUNGRY) + nutrition_ratio = 0.4 + if(NUTRITION_LEVEL_HUNGRY to NUTRITION_LEVEL_FED) + nutrition_ratio = 0.6 + if(NUTRITION_LEVEL_FED to NUTRITION_LEVEL_WELL_FED) + nutrition_ratio = 0.8 + else + nutrition_ratio = 1 + if(satiety > 80) + nutrition_ratio *= 1.25 + adjust_nutrition(-nutrition_ratio * HUNGER_FACTOR * seconds_per_tick) + blood_volume = min(blood_volume + (BLOOD_REGEN_FACTOR * nutrition_ratio * seconds_per_tick), BLOOD_VOLUME_NORMAL) + + // // we call lose_blood() here rather than quirk/process() to make sure that the blood loss happens in sync with life() + // if(HAS_TRAIT(src, TRAIT_BLOOD_DEFICIENCY)) + // var/datum/quirk/blooddeficiency/blooddeficiency = get_quirk(/datum/quirk/blooddeficiency) + // if(!isnull(blooddeficiency)) + // blooddeficiency.lose_blood(seconds_per_tick) //Effects of bloodloss - var/word = pick("dizzy","woozy","faint") - if(!HAS_TRAIT(src, TRAIT_NO_BLOODLOSS_DAMAGE)) //monkestation addition + if(!(sigreturn & HANDLE_BLOOD_NO_EFFECTS)) + var/word = pick("dizzy","woozy","faint") switch(blood_volume) - if(BLOOD_VOLUME_EXCESS to BLOOD_VOLUME_MAX_LETHAL) + if(BLOOD_VOLUME_MAX_LETHAL to INFINITY) if(SPT_PROB(7.5, seconds_per_tick)) to_chat(src, span_userdanger("Blood starts to tear your skin apart. You're going to burst!")) investigate_log("has been gibbed by having too much blood.", INVESTIGATE_DEATHS) inflate_gib() + if(BLOOD_VOLUME_EXCESS to BLOOD_VOLUME_MAX_LETHAL) + if(SPT_PROB(5, seconds_per_tick)) + to_chat(src, span_warning("You feel your skin swelling.")) if(BLOOD_VOLUME_MAXIMUM to BLOOD_VOLUME_EXCESS) if(SPT_PROB(5, seconds_per_tick)) to_chat(src, span_warning("You feel terribly bloated.")) @@ -93,7 +100,7 @@ //Makes a blood drop, leaking amt units of blood from the mob /mob/living/carbon/proc/bleed(amt, no_visual = FALSE) - if(!blood_volume || (status_flags & GODMODE) || HAS_TRAIT(src, TRAIT_NOBLOOD)) + if((status_flags & GODMODE) || HAS_TRAIT(src, TRAIT_NOBLOOD)) return blood_volume = max(blood_volume - amt, 0) @@ -107,7 +114,7 @@ /// A helper to see how much blood we're losing per tick /mob/living/carbon/proc/get_bleed_rate() - if(!blood_volume || HAS_TRAIT(src, TRAIT_NOBLOOD)) + if(HAS_TRAIT(src, TRAIT_NOBLOOD)) return 0 var/bleed_amt = 0 for(var/X in bodyparts) @@ -116,7 +123,8 @@ return bleed_amt /mob/living/carbon/human/get_bleed_rate() - return ..() * physiology.bleed_mod + . = ..() + . *= physiology.bleed_mod /** * bleed_warn() is used to for carbons with an active client to occasionally receive messages warning them about their bleeding status (if applicable) @@ -126,7 +134,7 @@ * * forced- */ /mob/living/carbon/proc/bleed_warn(bleed_amt = 0, forced = FALSE) - if(!blood_volume || !client) + if(!client || HAS_TRAIT(src, TRAIT_NOBLOOD)) return if(!COOLDOWN_FINISHED(src, bleeding_message_cd) && !forced) return @@ -177,10 +185,6 @@ to_chat(src, span_warning("[bleeding_severity][rate_of_change]")) COOLDOWN_START(src, bleeding_message_cd, next_cooldown) -/mob/living/carbon/human/bleed_warn(bleed_amt = 0, forced = FALSE) - if(!HAS_TRAIT(src, TRAIT_NOBLOOD)) - return ..() - /mob/living/proc/restore_blood() blood_volume = initial(blood_volume) @@ -196,7 +200,8 @@ //Gets blood from mob to a container or other mob, preserving all data in it. /mob/living/proc/transfer_blood_to(atom/movable/AM, amount, forced) - if(!blood_volume || !AM.reagents) + var/datum/blood_type/blood = get_blood_type() + if(isnull(blood) || !AM.reagents) return FALSE if(blood_volume < BLOOD_VOLUME_BAD && !forced) return FALSE @@ -204,35 +209,12 @@ if(blood_volume < amount) amount = blood_volume - var/blood_id = get_blood_id() - if(!blood_id) - return FALSE - blood_volume -= amount - var/list/blood_data = get_blood_data(blood_id) - - if(iscarbon(AM)) - var/mob/living/carbon/C = AM - if(blood_id == C.get_blood_id())//both mobs have the same blood substance - if(blood_id == /datum/reagent/blood) //normal blood - if(blood_data["viruses"]) - for(var/thing in blood_data["viruses"]) - var/datum/disease/advanced/D = thing - if((D.spread_flags & DISEASE_SPREAD_SPECIAL) || (D.spread_flags & DISEASE_SPREAD_NON_CONTAGIOUS)) - continue - C.infect_disease(D, TRUE, "Infected [key_name(C)] (Infected Blood 100% Infection)") - if(!(blood_data["blood_type"] in get_safe_blood(C.dna.blood_type))) - C.reagents.add_reagent(/datum/reagent/toxin, amount * 0.5) - return TRUE - - C.blood_volume = min(C.blood_volume + round(amount, 0.1), BLOOD_VOLUME_MAX_LETHAL) - return TRUE - - AM.reagents.add_reagent(blood_id, amount, blood_data, bodytemperature) + AM.reagents.add_reagent(blood.reagent_type, amount, blood.get_blood_data(src), bodytemperature) return TRUE - +/* /mob/living/proc/get_blood_data(blood_id) return @@ -276,129 +258,46 @@ var/datum/quirk/T = V blood_data["quirks"] += T.type return blood_data +*/ -//get the id of the substance this mob use as blood. -/mob/proc/get_blood_id() - return +/mob/living/proc/get_blood_type() + RETURN_TYPE(/datum/blood_type) + if(HAS_TRAIT(src, TRAIT_NOBLOOD)) + return null + return GLOB.blood_types[/datum/blood_type/animal] -/mob/living/simple_animal/get_blood_id() - if(blood_volume) - return /datum/reagent/blood +/mob/living/silicon/get_blood_type() + return GLOB.blood_types[/datum/blood_type/oil] -/mob/living/carbon/human/get_blood_id() - if(HAS_TRAIT(src, TRAIT_HUSK)) - return - if(check_holidays(APRIL_FOOLS) && is_clown_job(mind?.assigned_role)) - return /datum/reagent/colorful_reagent - if(dna.species.exotic_blood) - return dna.species.exotic_blood - else if(HAS_TRAIT(src, TRAIT_NOBLOOD)) - return - return /datum/reagent/blood +/mob/living/simple_animal/bot/get_blood_type() + return GLOB.blood_types[/datum/blood_type/oil] -// This is has more potential uses, and is probably faster than the old proc. -/proc/get_safe_blood(bloodtype) - . = list() - if(!bloodtype) - return - - var/static/list/bloodtypes_safe = list( - "A-" = list("A-", "O-"), - "A+" = list("A-", "A+", "O-", "O+"), - "B-" = list("B-", "O-"), - "B+" = list("B-", "B+", "O-", "O+"), - "AB-" = list("A-", "B-", "O-", "AB-"), - "AB+" = list("A-", "A+", "B-", "B+", "O-", "O+", "AB-", "AB+"), - "O-" = list("O-"), - "O+" = list("O-", "O+"), - "L" = list("L"), - "U" = list("A-", "A+", "B-", "B+", "O-", "O+", "AB-", "AB+", "L", "U") - ) - - var/safe = bloodtypes_safe[bloodtype] - if(safe) - . = safe +/mob/living/basic/bot/get_blood_type() + return GLOB.blood_types[/datum/blood_type/oil] -//to add a splatter of blood or other mob liquid. -/mob/living/proc/add_splatter_floor(turf/splattered, small_drip) - if((get_blood_id() != /datum/reagent/blood) || HAS_TRAIT(src, TRAIT_NOBLOOD)) - return - if(!splattered) - splattered = get_turf(src) - if(isclosedturf(splattered) || (isgroundlessturf(splattered) && !GET_TURF_BELOW(splattered))) - return +/mob/living/carbon/alien/get_blood_type() + if(HAS_TRAIT(src, TRAIT_HUSK) || HAS_TRAIT(src, TRAIT_NOBLOOD)) + return null + return GLOB.blood_types[/datum/blood_type/xenomorph] - var/datum/reagent/blood_type = get_blood_id() - var/list/temp_blood_DNA - if(small_drip) - if(!QDELETED(splattered.liquids)) - var/list/blood_drop = list(get_blood_id() = 0.1) - splattered.add_liquid_list(blood_drop, FALSE, 300) - return - // Only a certain number of drips (or one large splatter) can be on a given turf. - var/obj/effect/decal/cleanable/blood/drip/drop = locate() in splattered - if(drop) - if(drop.drips < 5) - splattered?.pollute_turf(/datum/pollutant/metallic_scent, 5) - drop.drips++ - drop.add_overlay(pick(drop.random_icon_states)) - drop.transfer_mob_blood_dna(src) - return - else - temp_blood_DNA = GET_ATOM_BLOOD_DNA(drop) //we transfer the dna from the drip to the splatter - qdel(drop)//the drip is replaced by a bigger splatter - else - splattered?.pollute_turf(/datum/pollutant/metallic_scent, 5) - drop = new(splattered, get_static_viruses()) - drop.transfer_mob_blood_dna(src) - return +/mob/living/carbon/human/get_blood_type() + if(HAS_TRAIT(src, TRAIT_HUSK) || isnull(dna) || HAS_TRAIT(src, TRAIT_NOBLOOD)) + return null + if(check_holidays(APRIL_FOOLS) && is_clown_job(mind?.assigned_role)) + return GLOB.blood_types[/datum/blood_type/clown] + if(dna.species.exotic_bloodtype) + return GLOB.blood_types[dna.species.exotic_bloodtype] + return GLOB.blood_types[dna.human_blood_type] +//to add a splatter of blood or other mob liquid. +/mob/living/proc/add_splatter_floor(turf/blood_turf = get_turf(src), small_drip) // Create a bit of metallic pollution, as that's how blood smells - splattered.pollute_turf(/datum/pollutant/metallic_scent, 30) + blood_turf?.pollute_turf(/datum/pollutant/metallic_scent, 30) // TODO Move to blood_datum + return get_blood_type()?.make_blood_splatter(src, blood_turf, small_drip) - // Find a blood decal or create a new one. - var/obj/effect/decal/cleanable/blood/B = locate() in splattered - if(!B) - B = new /obj/effect/decal/cleanable/blood/splatter(splattered, get_static_viruses()) - if(QDELETED(B)) //Give it up - return - B.bloodiness = min((B.bloodiness + BLOOD_AMOUNT_PER_DECAL), BLOOD_POOL_MAX) - B.transfer_mob_blood_dna(src) //give blood info to the blood decal. - if(temp_blood_DNA) - B.add_blood_DNA(temp_blood_DNA) - - if(B.count < 10 ) - if(blood_type) - B.color = initial(blood_type.color) - B.count ++ - B.transfer_mob_blood_dna(src) - B.transfer_mob_blood_dna(src) //give blood info to the blood decal. - if(temp_blood_DNA) - B.add_blood_DNA(temp_blood_DNA) - - if(B.count > 9) - qdel(B) - var/list/blood_large = list(get_blood_id() = 20) - splattered.add_liquid_list(blood_large, FALSE, 300) - -/mob/living/carbon/human/add_splatter_floor(turf/T, small_drip) - if(!HAS_TRAIT(src, TRAIT_NOBLOOD)) - ..() - -/mob/living/carbon/alien/add_splatter_floor(turf/T, small_drip) - if(!T) - T = get_turf(src) - var/obj/effect/decal/cleanable/xenoblood/B = locate() in T.contents - if(!B) - B = new(T) - B.add_blood_DNA(list("UNKNOWN DNA" = "X*")) - -/mob/living/silicon/robot/add_splatter_floor(turf/T, small_drip) - if(!T) - T = get_turf(src) - var/obj/effect/decal/cleanable/oil/B = locate() in T.contents - if(!B) - B = new(T) +/mob/living/proc/do_splatter_effect(splat_dir = pick(GLOB.cardinals)) + var/obj/effect/temp_visual/dir_setting/bloodsplatter/splatter = new(get_turf(src), splat_dir, get_blood_type()?.color) + splatter.color = get_blood_type()?.color /** * This proc is a helper for spraying blood for things like slashing/piercing wounds and dismemberment. @@ -410,10 +309,12 @@ * * splatter_strength: How many tiles it can go, and how many items it can pass over and dirty */ /mob/living/proc/spray_blood(splatter_direction, splatter_strength = 3) - if(!isturf(loc) || !blood_volume || HAS_TRAIT(src, TRAIT_NOBLOOD)) + if(QDELETED(src) || !isturf(loc) || QDELING(loc) || !blood_volume || HAS_TRAIT(src, TRAIT_NOBLOOD)) return var/obj/effect/decal/cleanable/blood/hitsplatter/our_splatter = new(loc) - our_splatter.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) + if(QDELETED(our_splatter)) + return + our_splatter.add_mob_blood(src) var/turf/targ = get_ranged_target_turf(src, splatter_direction, splatter_strength) our_splatter.fly_towards(targ, splatter_strength) @@ -421,11 +322,14 @@ * Helper proc for throwing blood particles around, similar to the spray_blood proc. */ /mob/living/proc/blood_particles(amount = rand(1, 3), angle = rand(0,360), min_deviation = -30, max_deviation = 30, min_pixel_z = 0, max_pixel_z = 6) - if(QDELETED(src) || QDELETED(loc) || !isturf(loc) || !blood_volume || HAS_TRAIT(src, TRAIT_NOBLOOD)) + if(QDELETED(src) || !isturf(loc) || QDELING(loc) || !blood_volume || HAS_TRAIT(src, TRAIT_NOBLOOD)) return for(var/i in 1 to amount) var/obj/effect/decal/cleanable/blood/particle/droplet = new(loc) - droplet.add_blood_DNA(GET_ATOM_BLOOD_DNA(src)) + if(QDELETED(droplet)) // if they're deleting upon init, let's not waste any more time, any others will prolly just do the same thing + return + droplet.color = get_blood_type()?.color + droplet.add_mob_blood(src) droplet.pixel_z = rand(min_pixel_z, max_pixel_z) droplet.start_movement(angle + rand(min_deviation, max_deviation)) diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm index 3dc911e206f9..3b4b834e67d9 100644 --- a/code/modules/mob/living/brain/brain.dm +++ b/code/modules/mob/living/brain/brain.dm @@ -10,7 +10,7 @@ /mob/living/brain/Initialize(mapload) . = ..() create_dna(src) - stored_dna.initialize_dna(random_blood_type()) + stored_dna.initialize_dna() if(isturf(loc)) //not spawned in an MMI or brain organ (most likely adminspawned) var/obj/item/organ/internal/brain/OB = new(loc) //we create a new brain organ for it. OB.brainmob = src diff --git a/code/modules/mob/living/brain/death.dm b/code/modules/mob/living/brain/death.dm index 60487aa0c359..6de222060c82 100644 --- a/code/modules/mob/living/brain/death.dm +++ b/code/modules/mob/living/brain/death.dm @@ -11,7 +11,7 @@ return ..() -/mob/living/brain/gib() +/mob/living/brain/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) if(container) qdel(container)//Gets rid of the MMI if there is one if(loc) diff --git a/code/modules/mob/living/carbon/alien/adult/life.dm b/code/modules/mob/living/carbon/alien/adult/life.dm deleted file mode 100644 index 8aeb32ed657f..000000000000 --- a/code/modules/mob/living/carbon/alien/adult/life.dm +++ /dev/null @@ -1,18 +0,0 @@ - - -/mob/living/carbon/alien/adult/proc/adjust_body_temperature(current, loc_temp, boost) - var/temperature = current - var/difference = abs(current-loc_temp) //get difference - var/increments// = difference/10 //find how many increments apart they are - if(difference > 50) - increments = difference/5 - else - increments = difference/10 - var/change = increments*boost // Get the amount to change by (x per increment) - var/temp_change - if(current < loc_temp) - temperature = min(loc_temp, temperature+change) - else if(current > loc_temp) - temperature = max(loc_temp, temperature-change) - temp_change = (temperature - current) - return temp_change diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm index 44d0d4322f8b..497223b575ad 100644 --- a/code/modules/mob/living/carbon/alien/alien.dm +++ b/code/modules/mob/living/carbon/alien/alien.dm @@ -13,7 +13,8 @@ status_flags = CANUNCONSCIOUS|CANPUSH - heat_protection = 0.5 // minor heat insulation + temperature_insulation = 0.5 // minor heat insulation + bodytemp_heat_damage_limit = CELCIUS_TO_KELVIN(85 CELCIUS) var/leaping = FALSE gib_type = /obj/effect/decal/cleanable/xenoblood/xgibs @@ -45,30 +46,12 @@ /mob/living/carbon/alien/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null) // beepsky won't hunt aliums return -10 -/mob/living/carbon/alien/handle_environment(datum/gas_mixture/environment, seconds_per_tick, times_fired) - // Run base mob body temperature proc before taking damage - // this balances body temp to the environment and natural stabilization - . = ..() - - if(bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT) - //Body temperature is too hot. +/mob/living/carbon/alien/body_temperature_alerts() + if(bodytemperature > bodytemp_heat_damage_limit) throw_alert(ALERT_XENO_FIRE, /atom/movable/screen/alert/alien_fire) - switch(bodytemperature) - if(360 to 400) - apply_damage(HEAT_DAMAGE_LEVEL_1 * seconds_per_tick, BURN) - if(400 to 460) - apply_damage(HEAT_DAMAGE_LEVEL_2 * seconds_per_tick, BURN) - if(460 to INFINITY) - if(on_fire) - apply_damage(HEAT_DAMAGE_LEVEL_3 * seconds_per_tick, BURN) - else - apply_damage(HEAT_DAMAGE_LEVEL_2 * seconds_per_tick, BURN) else clear_alert(ALERT_XENO_FIRE) -/mob/living/carbon/alien/reagent_check(datum/reagent/R, seconds_per_tick, times_fired) //can metabolize all reagents - return FALSE - /mob/living/carbon/alien/getTrail() if(getBruteLoss() < 200) return pick (list("xltrails_1", "xltrails2")) diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm index c7c65f4d684c..4172767adb3c 100644 --- a/code/modules/mob/living/carbon/alien/alien_defense.dm +++ b/code/modules/mob/living/carbon/alien/alien_defense.dm @@ -117,6 +117,3 @@ In all, this is a lot like the monkey code. /N /mob/living/carbon/alien/acid_act(acidpwr, acid_volume) return FALSE//aliens are immune to acid. - -/mob/living/carbon/alien/on_fire_stack(seconds_per_tick, times_fired, datum/status_effect/fire_handler/fire_stacks/fire_handler) - adjust_bodytemperature((BODYTEMP_HEATING_MAX + (fire_handler.stacks * 12)) * 0.5 * seconds_per_tick) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 0dcd336ffe1e..16141c8a59a6 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -78,8 +78,10 @@ take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5) victim.Paralyze(2 SECONDS) Paralyze(2 SECONDS) - visible_message(span_danger("[src] crashes into [victim][extra_speed ? " really hard" : ""], knocking them both over!"),\ - span_userdanger("You violently crash into [victim][extra_speed ? " extra hard" : ""]!")) + visible_message( + span_danger("[src] crashes into [hit_atom][extra_speed ? " really hard" : ""]!"), + span_userdanger("You[extra_speed ? " violently" : ""] crash into [hit_atom][extra_speed ? " extra hard" : ""]!"), + ) playsound(src,'sound/weapons/punch1.ogg',50,TRUE) log_combat(src, victim, "crashed into") @@ -185,6 +187,14 @@ SEND_SIGNAL(src, COMSIG_CARBON_EMBED_RIP, I, L) return + if(href_list["gauze_limb"]) + var/obj/item/bodypart/gauzed = locate(href_list["gauze_limb"]) in bodyparts + if(isnull(gauzed?.current_gauze)) + return + // rest of the sanity is handled in the proc itself + gauzed.help_remove_gauze(usr) + return + if(href_list["show_paper_note"]) var/obj/item/paper/paper_note = locate(href_list["show_paper_note"]) if(!paper_note) @@ -884,7 +894,7 @@ return FALSE // And we can't heal them if they're missing their liver - if(!HAS_TRAIT(src, TRAIT_NOMETABOLISM) && !isnull(dna?.species.mutantliver) && !get_organ_slot(ORGAN_SLOT_LIVER)) + if(!HAS_TRAIT(src, TRAIT_LIVERLESS_METABOLISM) && !isnull(dna?.species.mutantliver) && !get_organ_slot(ORGAN_SLOT_LIVER)) return FALSE return ..() @@ -993,6 +1003,7 @@ var/obj/item/bodypart/bodypart_instance = new real_body_part_path() bodypart_instance.set_owner(src) bodyparts.Remove(bodypart_path) + bodypart_instance.check_adding_composition(src) add_bodypart(bodypart_instance) switch(bodypart_instance.body_part) if(ARM_LEFT) @@ -1039,6 +1050,13 @@ set_usable_hands(usable_hands - 1) +///Updates the bodypart speed modifier based on our bodyparts. +/mob/living/carbon/proc/update_bodypart_speed_modifier() + var/final_modification = 0 + for(var/obj/item/bodypart/bodypart as anything in bodyparts) + final_modification += bodypart.speed_modifier + add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/bodypart, TRUE, final_modification) + /mob/living/carbon/proc/create_internal_organs() for(var/obj/item/organ/internal/internal_organ in organs) internal_organ.Insert(src) @@ -1224,12 +1242,16 @@ /// if any of our bodyparts are bleeding /mob/living/carbon/proc/is_bleeding() + if(HAS_TRAIT(src, TRAIT_NOBLOOD)) + return FALSE for(var/obj/item/bodypart/part as anything in bodyparts) if(part.get_modified_bleed_rate()) return TRUE /// get our total bleedrate /mob/living/carbon/proc/get_total_bleed_rate() + if(HAS_TRAIT(src, TRAIT_NOBLOOD)) + return 0 var/total_bleed_rate = 0 for(var/obj/item/bodypart/part as anything in bodyparts) total_bleed_rate += part.get_modified_bleed_rate() diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 4add45bea149..ab3f27f479b1 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -140,15 +140,13 @@ var/exterior_ready_to_dismember = (!has_exterior || ((mangled_state & BODYPART_MANGLED_EXTERIOR))) var/interior_ready_to_dismember = (!has_interior || ((mangled_state & BODYPART_MANGLED_INTERIOR))) - var/dismemberable = ((hit_bodypart.dismemberable_by_wound()) || hit_bodypart.dismemberable_by_total_damage()) + var/dismemberable = hit_bodypart.dismemberable_by_wound() || hit_bodypart.dismemberable_by_total_damage() if (dismemberable) - extra_wound_details = ", threatening to sever it entirely" - else if((has_interior && (has_exterior && exterior_ready_to_dismember) && I.get_sharpness())) - var/bone_text = hit_bodypart.get_internal_description() - extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] through to the [bone_text]" - else if(has_exterior && ((has_interior && interior_ready_to_dismember) && I.get_sharpness())) - var/tissue_text = hit_bodypart.get_external_description() - extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] at the remaining [tissue_text]" + extra_wound_details = hit_bodypart.get_soon_dismember_message() + else if(has_interior && (has_exterior && exterior_ready_to_dismember) && I.get_sharpness()) + extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] through to the [hit_bodypart.get_internal_description()]" + else if(has_exterior && (has_interior && interior_ready_to_dismember) && I.get_sharpness()) + extra_wound_details = ", [I.get_sharpness() == SHARP_EDGED ? "slicing" : "piercing"] at the remaining [hit_bodypart.get_external_description()]" var/message_hit_area = "" if(hit_area) @@ -167,6 +165,18 @@ to_chat(user, span_danger("[attack_message_attacker]")) return TRUE +/mob/living/carbon/attack_animal(mob/living/simple_animal/user, list/modifiers) + . = ..() + if(. <= 0) + return + if(user.wound_bonus != CANT_WOUND) + return + // Snowflake mcsnowflake but mobs which can't wound should still capable of causing IB + var/obj/item/bodypart/affecting = get_bodypart(user.zone_selected) || get_bodypart(BODY_ZONE_CHEST) + var/ib_prob = . + rand(-10, 40) - getarmor(affecting, WOUND) + if(ib_prob < 45) + return + affecting.force_wound_upwards(/datum/wound/bleed_internal, wound_source = user) /mob/living/carbon/attack_drone(mob/living/basic/drone/user) return //so we don't call the carbon's attack_hand(). @@ -520,14 +530,14 @@ add_mood_event("hug", /datum/mood_event/bad_touch_bear_hug) // Let people know if they hugged someone really warm or really cold - if(helper.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT || helper.has_status_effect(/datum/status_effect/bloodsucker_sol)) // monkestation edit: bloodsucker sol + if(helper.bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT && !HAS_TRAIT(src, TRAIT_RESISTHEAT)) to_chat(src, span_warning("It feels like [helper] is over heating as [helper.p_they()] hug[helper.p_s()] you.")) - else if(helper.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT) + else if(helper.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !HAS_TRAIT(src, TRAIT_RESISTCOLD)) to_chat(src, span_warning("It feels like [helper] is freezing as [helper.p_they()] hug[helper.p_s()] you.")) - if(bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT || has_status_effect(/datum/status_effect/bloodsucker_sol)) // monkestation edit: bloodsucker sol + if(bodytemperature > BODYTEMP_HEAT_DAMAGE_LIMIT && !HAS_TRAIT(src, TRAIT_RESISTHEAT)) to_chat(helper, span_warning("It feels like [src] is over heating as you hug [p_them()].")) - else if(bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT) + else if(bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT && !HAS_TRAIT(src, TRAIT_RESISTCOLD)) to_chat(helper, span_warning("It feels like [src] is freezing as you hug [p_them()].")) if(HAS_TRAIT(helper, TRAIT_FRIENDLY)) diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index af129ce55802..3bafd1b07cb5 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -88,11 +88,6 @@ /// This number is also reset to 0 every tick of carbon Life(). Pain. var/damageoverlaytemp = 0 - /// Protection (insulation) from the heat, Value 0-1 corresponding to the percentage of protection - var/heat_protection = 0 // No heat protection - /// Protection (insulation) from the cold, Value 0-1 corresponding to the percentage of protection - var/cold_protection = 0 // No cold protection - /// Timer id of any transformation var/transformation_timer diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm index b6e0615ab77f..5e3d48a57583 100644 --- a/code/modules/mob/living/carbon/carbon_movement.dm +++ b/code/modules/mob/living/carbon/carbon_movement.dm @@ -15,21 +15,8 @@ adjust_nutrition(-(HUNGER_FACTOR) * 0.05) if(m_intent == MOVE_INTENT_RUN) adjust_nutrition(-(HUNGER_FACTOR) * 0.1) - - -/mob/living/carbon/set_usable_legs(new_value) - . = ..() - if(isnull(.)) - return - if(. == 0) - if(usable_legs != 0) //From having no usable legs to having some. - REMOVE_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) - REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) - else if(usable_legs == 0 && !(movement_type & (FLYING | FLOATING))) //From having usable legs to no longer having them. - ADD_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) - if(!usable_hands) - ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) - + if(!moving_diagonally) + SEND_SIGNAL(src, COMSIG_CARBON_STEP, NewLoc, direct) /mob/living/carbon/set_usable_hands(new_value) . = ..() @@ -37,32 +24,17 @@ return if(. == 0) REMOVE_TRAIT(src, TRAIT_HANDS_BLOCKED, LACKING_MANIPULATION_APPENDAGES_TRAIT) - if(usable_hands != 0) //From having no usable hands to having some. - REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) else if(usable_hands == 0 && default_num_hands > 0) //From having usable hands to no longer having them. ADD_TRAIT(src, TRAIT_HANDS_BLOCKED, LACKING_MANIPULATION_APPENDAGES_TRAIT) - if(!usable_legs && !(movement_type & (FLYING | FLOATING))) - ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) /mob/living/carbon/on_movement_type_flag_enabled(datum/source, flag, old_movement_type) . = ..() if(movement_type & (FLYING | FLOATING) && !(old_movement_type & (FLYING | FLOATING))) - remove_movespeed_modifier(/datum/movespeed_modifier/limbless) - remove_traits(list(TRAIT_FLOORED, TRAIT_IMMOBILIZED), LACKING_LOCOMOTION_APPENDAGES_TRAIT) + update_limbless_locomotion() + update_limbless_movespeed_mod() /mob/living/carbon/on_movement_type_flag_disabled(datum/source, flag, old_movement_type) . = ..() if(old_movement_type & (FLYING | FLOATING) && !(movement_type & (FLYING | FLOATING))) - var/limbless_slowdown = 0 - if(usable_legs < default_num_legs) - limbless_slowdown += (default_num_legs - usable_legs) * 3 - if(!usable_legs) - ADD_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) - if(usable_hands < default_num_hands) - limbless_slowdown += (default_num_hands - usable_hands) * 3 - if(!usable_hands) - ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) - if(limbless_slowdown) - add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/limbless, multiplicative_slowdown = limbless_slowdown) - else - remove_movespeed_modifier(/datum/movespeed_modifier/limbless) + update_limbless_locomotion() + update_limbless_movespeed_mod() diff --git a/code/modules/mob/living/carbon/carbon_update_icons.dm b/code/modules/mob/living/carbon/carbon_update_icons.dm index 2485d23eabef..38422a58979b 100644 --- a/code/modules/mob/living/carbon/carbon_update_icons.dm +++ b/code/modules/mob/living/carbon/carbon_update_icons.dm @@ -277,13 +277,13 @@ return hands /mob/living/carbon/get_fire_overlay(stacks, on_fire) - var/fire_icon = "[dna?.species.fire_overlay || "human"]_[stacks > MOB_BIG_FIRE_STACK_THRESHOLD ? "big_fire" : "small_fire"]" + var/fire_icon = "[dna?.species?.fire_overlay || "human"]_[stacks > MOB_BIG_FIRE_STACK_THRESHOLD ? "big_fire" : "small_fire"]" if(!GLOB.fire_appearances[fire_icon]) GLOB.fire_appearances[fire_icon] = mutable_appearance( - 'icons/mob/effects/onfire.dmi', - fire_icon, - -HIGHEST_LAYER, + icon = dna?.species?.fire_dmi || 'icons/mob/effects/onfire.dmi', + icon_state = fire_icon, + layer = -HIGHEST_LAYER, appearance_flags = RESET_COLOR, ) @@ -294,14 +294,12 @@ var/mutable_appearance/damage_overlay for(var/obj/item/bodypart/iter_part as anything in bodyparts) - if(!iter_part.dmg_overlay_type) + var/list/part_overlays = iter_part.get_bodypart_damage_state() + if(!LAZYLEN(part_overlays)) continue - if(isnull(damage_overlay) && (iter_part.brutestate || iter_part.burnstate)) - damage_overlay = mutable_appearance('icons/mob/effects/dam_mob.dmi', "blank", -DAMAGE_LAYER, appearance_flags = KEEP_TOGETHER) - if(iter_part.brutestate) - damage_overlay.add_overlay("[iter_part.dmg_overlay_type]_[iter_part.body_zone]_[iter_part.brutestate]0") //we're adding icon_states of the base image as overlays - if(iter_part.burnstate) - damage_overlay.add_overlay("[iter_part.dmg_overlay_type]_[iter_part.body_zone]_0[iter_part.burnstate]") + + damage_overlay ||= mutable_appearance(layer = -DAMAGE_LAYER) + damage_overlay.overlays += part_overlays if(isnull(damage_overlay)) return diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm index ba629ae60144..e192ff2d4046 100644 --- a/code/modules/mob/living/carbon/death.dm +++ b/code/modules/mob/living/carbon/death.dm @@ -24,17 +24,17 @@ M.Scale(1.8, 1.2) animate(src, time = 40, transform = M, easing = SINE_EASING) -/mob/living/carbon/gib(no_brain, no_organs, no_bodyparts, safe_gib = FALSE) +/mob/living/carbon/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) add_memory_in_range(src, 7, /datum/memory/witness_gib, protagonist = src) - // if(safe_gib) // If you want to keep all the mob's items and not have them deleted MONKESTATION EDIT - for(var/obj/item/W in src) - dropItemToGround(W, violent = TRUE) - if(prob(50)) - step(W, pick(GLOB.alldirs)) - var/atom/Tsec = drop_location() - for(var/mob/M in src) - M.forceMove(Tsec) - visible_message(span_danger("[M] bursts out of [src]!")) + if(safe_gib) // If you want to keep all the mob's items and not have them deleted MONKESTATION EDIT + for(var/obj/item/W in src) + dropItemToGround(W, violent = TRUE) + if(prob(50)) + step(W, pick(GLOB.alldirs)) + var/atom/Tsec = drop_location() + for(var/mob/M in src) + M.forceMove(Tsec) + visible_message(span_danger("[M] bursts out of [src]!")) return ..() /mob/living/carbon/spill_organs(no_brain, no_organs, no_bodyparts) @@ -45,27 +45,27 @@ if(no_brain || !istype(organ, /obj/item/organ/internal/brain)) qdel(organ) else //we're going to drop all bodyparts except chest, so the only organs that needs spilling are those inside it. - for(var/obj/item/organ/organs as anything in organs) - if(no_brain && istype(organs, /obj/item/organ/internal/brain)) - qdel(organs) //so the brain isn't transfered to the head when the head drops. + for(var/obj/item/organ/organ as anything in organs) + if(no_brain && istype(organ, /obj/item/organ/internal/brain)) + qdel(organ) //so the brain isn't transfered to the head when the head drops. continue - var/org_zone = check_zone(organs.zone) //both groin and chest organs. + var/org_zone = check_zone(organ.zone) //both groin and chest organs. if(org_zone != BODY_ZONE_CHEST) continue - organs.Remove(src) - organs.forceMove(Tsec) - organs.fly_away(Tsec, horizontal_multiplier = 2, vertical_multiplier = 1.2) + organs.Remove(organ) + organ.forceMove(Tsec) + organ.fly_away(Tsec, horizontal_multiplier = 2, vertical_multiplier = 1.2) else - for(var/obj/item/organ/organs as anything in organs) - if(no_brain && istype(organs, /obj/item/organ/internal/brain)) - qdel(organs) + for(var/obj/item/organ/organ as anything in organs) + if(no_brain && istype(organ, /obj/item/organ/internal/brain)) + qdel(organ) continue - if(no_organs && !istype(organs, /obj/item/organ/internal/brain)) - qdel(organs) + if(no_organs && !istype(organ, /obj/item/organ/internal/brain)) + qdel(organ) continue - organs.Remove(src) - organs.forceMove(Tsec) - organs.fly_away(Tsec, horizontal_multiplier = 2, vertical_multiplier = 1.2) + organs.Remove(organ) + organ.forceMove(Tsec) + organ.fly_away(Tsec, horizontal_multiplier = 2, vertical_multiplier = 1.2) /// Launches all bodyparts away from the mob. skip_head will keep the head attached. /mob/living/carbon/spread_bodyparts(skip_head = FALSE, skip_organ = FALSE, violent = FALSE) diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index 5e1ebeaf8d03..586058cc7891 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -36,25 +36,30 @@ var/list/msg = list("") var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) var/list/disabled = list() - for(var/X in bodyparts) - var/obj/item/bodypart/BP = X - if(BP.bodypart_disabled) - disabled += BP - missing -= BP.body_zone - for(var/obj/item/I in BP.embedded_objects) - if(I.isEmbedHarmless()) - msg += "[t_He] [t_has] [icon2html(I, user)] \a [I] stuck to [t_his] [BP.name]!\n" - else - msg += "[t_He] [t_has] [icon2html(I, user)] \a [I] embedded in [t_his] [BP.name]!\n" - for(var/i in BP.wounds) - var/datum/wound/W = i - msg += "[W.get_examine_description(user)]\n" - - for(var/X in disabled) - var/obj/item/bodypart/BP = X + var/adjacent = user.Adjacent(src) + for(var/obj/item/bodypart/body_part as anything in bodyparts) + if(body_part.bodypart_disabled) + disabled += body_part + missing -= body_part.body_zone + for(var/obj/item/leftover in body_part.embedded_objects) + var/stuck_or_embedded = "embedded in" + if(leftover.isEmbedHarmless()) + stuck_or_embedded = "stuck to" + msg += "[t_He] [t_has] [icon2html(leftover, user)] \a [leftover] [stuck_or_embedded] [t_his] [body_part.plaintext_zone]!\n" + + if(body_part.current_gauze) + var/gauze_href = body_part.current_gauze.name + if(adjacent && isliving(user)) // only shows the href if we're adjacent + gauze_href = "[gauze_href]" + msg += span_notice("There is some [icon2html(body_part.current_gauze, user)] [gauze_href] wrapped around [t_his] [body_part.plaintext_zone].\n") + + for(var/datum/wound/iter_wound as anything in body_part.wounds) + msg += "[iter_wound.get_examine_description(user)]\n" + + for(var/obj/item/bodypart/body_part as anything in disabled) var/damage_text - damage_text = (BP.brute_dam >= BP.burn_dam) ? BP.heavy_brute_msg : BP.heavy_burn_msg - msg += "[capitalize(t_his)] [BP.name] is [damage_text]!\n" + damage_text = (body_part.brute_dam >= body_part.burn_dam) ? body_part.heavy_brute_msg : body_part.heavy_burn_msg + msg += "[capitalize(t_his)] [body_part.name] is [damage_text]!\n" for(var/t in missing) if(t == BODY_ZONE_HEAD) diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index a979550ce806..d3de62aaeea9 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -63,24 +63,14 @@ GLOBAL_LIST_EMPTY(features_by_species) var/examine_limb_id ///Never, Optional, or Forced digi legs? var/digitigrade_customization = DIGITIGRADE_NEVER - ///Does the species use skintones or not? As of now only used by humans. - var/use_skintones = FALSE - ///If your race bleeds something other than bog standard blood, change this to reagent id. For example, ethereals bleed liquid electricity. - var/datum/reagent/exotic_blood - ///If your race uses a non standard bloodtype (A+, O-, AB-, etc). For example, lizards have L type blood. - var/exotic_bloodtype = "" + /// If your race uses a non standard bloodtype (typepath) + var/datum/blood_type/exotic_bloodtype ///The rate at which blood is passively drained by having the blood deficiency quirk. Some races such as slimepeople can regen their blood at different rates so this is to account for that var/blood_deficiency_drain_rate = BLOOD_REGEN_FACTOR + BLOOD_DEFICIENCY_MODIFIER // slightly above the regen rate so it slowly drains instead of regenerates. ///What the species drops when gibbed by a gibber machine. var/meat = /obj/item/food/meat/slab/human ///What skin the species drops when gibbed by a gibber machine. var/skinned_type - ///Bitfield for food types that the species likes, giving them a mood boost. Lizards like meat, for example. - var/liked_food = NONE - ///Bitfield for food types that the species dislikes, giving them disgust. Humans hate raw food, for example. - var/disliked_food = GROSS - ///Bitfield for food types that the species absolutely hates, giving them even more disgust than disliked food. Meat is "toxic" to moths, for example. - var/toxic_food = TOXIC ///flags for inventory slots the race can't equip stuff to. Golems cannot wear jumpsuits, for example. var/no_equip_flags ///What languages this species can understand and say. Use a [language holder datum][/datum/language_holder] in this var. @@ -110,8 +100,6 @@ GLOBAL_LIST_EMPTY(features_by_species) ///List of external organs to generate like horns, frills, wings, etc. list(typepath of organ = "Round Beautiful BDSM Snout"). Still WIP var/list/external_organs = list() - ///Multiplier for the race's speed. Positive numbers make it move slower, negative numbers make it move faster. - var/speedmod = 0 ///Percentage modifier for overall defense of the race, or less defense, if it's negative. var/armor = 0 ///multiplier for brute damage @@ -121,22 +109,24 @@ GLOBAL_LIST_EMPTY(features_by_species) //Used for metabolizing reagents. We're going to assume you're a meatbag unless you say otherwise. var/reagent_tag = PROCESS_ORGANIC - //Dictates which wing icons are allowed for a given species. If count is >1 a radial menu is used to choose between all icons in list - var/list/wing_types = list(/obj/item/organ/external/wings/functional/angel) + // Do not READ these temperature related properties, use the living level ones instead + // These are deprecated and only exist to set in [/proc/on_species_gain] /// The natural temperature for a body - var/bodytemp_normal = BODYTEMP_NORMAL - /// Minimum amount of kelvin moved toward normal body temperature per tick. - var/bodytemp_autorecovery_min = BODYTEMP_AUTORECOVERY_MINIMUM + VAR_PROTECTED/bodytemp_normal = /mob/living/carbon/human::standard_body_temperature + /// Modifier to how fast/slow the body normalizes its temperature to the environment. + VAR_PROTECTED/temperature_normalization_speed = /mob/living/carbon/human::temperature_normalization_speed + /// Modifier to how fast/slow the body normalizes its temperature to standard temp + VAR_PROTECTED/temperature_homeostasis_speed = /mob/living/carbon/human::temperature_homeostasis_speed /// The body temperature limit the body can take before it starts taking damage from heat. - var/bodytemp_heat_damage_limit = BODYTEMP_HEAT_DAMAGE_LIMIT + VAR_PROTECTED/bodytemp_heat_damage_limit = /mob/living/carbon/human::bodytemp_heat_damage_limit /// The body temperature limit the body can take before it starts taking damage from cold. - var/bodytemp_cold_damage_limit = BODYTEMP_COLD_DAMAGE_LIMIT + VAR_PROTECTED/bodytemp_cold_damage_limit = /mob/living/carbon/human::bodytemp_cold_damage_limit /// The icon_state of the fire overlay added when sufficently ablaze and standing. see onfire.dmi - var/fire_overlay = "human" + var/fire_overlay + /// The icon of the fire overlay added when sufficently ablaze + var/fire_dmi - ///Species-only traits. Can be found in [code/__DEFINES/DNA.dm] - var/list/species_traits = list() ///Generic traits tied to having the species. var/list/inherent_traits = list() /// List of biotypes the mob belongs to. Used by diseases. @@ -148,8 +138,6 @@ GLOBAL_LIST_EMPTY(features_by_species) ///What gas does this species breathe? Used by suffocation screen alerts, most of actual gas breathing is handled by mutantlungs. See [life.dm][code/modules/mob/living/carbon/human/life.dm] var/breathid = "o2" - ///are we a furry little guy? - var/uses_fur = FALSE ///What anim to use for dusting var/dust_anim = "dust-h" ///What anim to use for gibbing @@ -202,7 +190,7 @@ GLOBAL_LIST_EMPTY(features_by_species) var/payday_modifier = 1.0 ///Base electrocution coefficient. Basically a multiplier for damage from electrocutions. var/siemens_coeff = 1 - ///To use MUTCOLOR with a fixed color that's independent of the mcolor feature in DNA. + ///To use TRAIT_MUTANT_COLORS with a fixed color that's independent of the mcolor feature in DNA. var/fixed_mut_color = "" ///A fixed hair color that's independent of the mcolor feature in DNA. var/fixed_hair_color = "" @@ -210,8 +198,6 @@ GLOBAL_LIST_EMPTY(features_by_species) var/inert_mutation = /datum/mutation/human/dwarfism ///Used to set the mob's death_sound upon species change var/death_sound - ///Sounds to override barefeet walking - var/list/special_step_sounds ///Special sound for grabbing var/grab_sound /// A path to an outfit that is important for species life e.g. plasmaman outfit @@ -223,9 +209,6 @@ GLOBAL_LIST_EMPTY(features_by_species) ///Unique cookie given by admins through prayers var/species_cookie = /obj/item/food/cookie - ///For custom overrides for species ass images - var/icon/ass_image - /// List of family heirlooms this species can get with the family heirloom quirk. List of types. var/list/family_heirlooms @@ -257,6 +240,8 @@ GLOBAL_LIST_EMPTY(features_by_species) var/list/custom_worn_icons = list() ///Override of the eyes icon file, used for Vox and maybe more in the future - The future is now, with Teshari using it too var/eyes_icon + ///our color palette + var/datum/color_palette/color_palette /////////// // PROCS // @@ -264,8 +249,6 @@ GLOBAL_LIST_EMPTY(features_by_species) /datum/species/New() - wing_types = string_list(wing_types) - if(!plural_form) plural_form = "[name]\s" @@ -517,12 +500,14 @@ GLOBAL_LIST_EMPTY(features_by_species) * * old_species - The species that the carbon used to be before becoming this race, used for regenerating organs. * * pref_load - Preferences to be loaded from character setup, loads in preferred mutant things like bodyparts, digilegs, skin color, etc. */ -/datum/species/proc/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) +/datum/species/proc/on_species_gain(mob/living/carbon/human/C, datum/species/old_species, pref_load) SHOULD_CALL_PARENT(TRUE) // Drop the items the new species can't wear SEND_SIGNAL(C, COMSIG_SPECIES_GAIN_PRE, src, old_species) - if((AGENDER in species_traits)) - C.gender = PLURAL + + if(C.dna.species.exotic_bloodtype) + C.dna.human_blood_type = exotic_bloodtype + if(C.hud_used) C.hud_used.update_locked_slots() @@ -531,6 +516,15 @@ GLOBAL_LIST_EMPTY(features_by_species) C.mob_biotypes = inherent_biotypes C.mob_respiration_type = inherent_respiration_type + C.standard_body_temperature = src.bodytemp_normal + C.bodytemperature = src.bodytemp_normal + C.bodytemp_heat_damage_limit = src.bodytemp_heat_damage_limit + C.bodytemp_cold_damage_limit = src.bodytemp_cold_damage_limit + C.temperature_normalization_speed = src.temperature_normalization_speed + C.temperature_homeostasis_speed = src.temperature_homeostasis_speed + + C.physiology?.cold_mod *= coldmod + C.physiology?.heat_mod *= heatmod if (old_species.type != type) replace_body(C, src) @@ -539,14 +533,6 @@ GLOBAL_LIST_EMPTY(features_by_species) INVOKE_ASYNC(src, PROC_REF(worn_items_fit_body_check), C, TRUE) - //Assigns exotic blood type if the species has one - if(exotic_bloodtype && C.dna.blood_type != exotic_bloodtype) - C.dna.blood_type = exotic_bloodtype - //Otherwise, check if the previous species had an exotic bloodtype and we do not have one and assign a random blood type - //(why the fuck is blood type not tied to a fucking DNA block?) - else if(old_species.exotic_bloodtype && !exotic_bloodtype) - C.dna.blood_type = random_blood_type() - if(ishuman(C)) var/mob/living/carbon/human/human = C for(var/obj/item/organ/external/organ_path as anything in external_organs) @@ -554,10 +540,6 @@ GLOBAL_LIST_EMPTY(features_by_species) var/obj/item/organ/external/new_organ = SSwardrobe.provide_type(organ_path) new_organ.Insert(human, special=TRUE, drop_if_replaced=FALSE) - if(NOMOUTH in species_traits) - for(var/obj/item/bodypart/head/head in C.bodyparts) - head.mouth = FALSE - if(length(inherent_traits)) C.add_traits(inherent_traits, SPECIES_TRAIT) @@ -568,7 +550,7 @@ GLOBAL_LIST_EMPTY(features_by_species) if(TRAIT_TOXIMMUNE in inherent_traits) C.setToxLoss(0, TRUE, TRUE) - if(TRAIT_NOMETABOLISM in inherent_traits) + if(TRAIT_LIVERLESS_METABOLISM in inherent_traits) C.reagents.end_metabolization(C, keep_liverless = TRUE) if(TRAIT_GENELESS in inherent_traits) @@ -578,7 +560,6 @@ GLOBAL_LIST_EMPTY(features_by_species) for(var/i in inherent_factions) C.faction += i //Using +=/-= for this in case you also gain the faction from a different source. - C.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/species, multiplicative_slowdown=speedmod) C.maxHealth = C.maxHealth * maxhealthmod SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species) @@ -598,10 +579,7 @@ GLOBAL_LIST_EMPTY(features_by_species) /datum/species/proc/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load) SHOULD_CALL_PARENT(TRUE) if(C.dna.species.exotic_bloodtype) - C.dna.blood_type = random_blood_type() - if(NOMOUTH in species_traits) - for(var/obj/item/bodypart/head/head in C.bodyparts) - head.mouth = TRUE + C.dna.human_blood_type = random_human_blood_type() for(var/X in inherent_traits) REMOVE_TRAIT(C, X, SPECIES_TRAIT) for(var/obj/item/organ/external/organ in C.organs) @@ -624,50 +602,15 @@ GLOBAL_LIST_EMPTY(features_by_species) clear_tail_moodlets(C) - C.remove_movespeed_modifier(/datum/movespeed_modifier/species) + if(coldmod) + C.physiology?.cold_mod /= coldmod + if(heatmod) + C.physiology?.heat_mod /= heatmod + C.maxHealth = C.maxHealth / maxhealthmod SEND_SIGNAL(C, COMSIG_SPECIES_LOSS, src) -/** - * Proc called when mail goodies need to be updated for this species. - * - * Updates the mail goodies if that is required. e.g. for the blood deficiency quirk, which sends bloodbags to quirk holders, update the sent bloodpack to match the species' exotic blood. - * This is currently only used for the blood deficiency quirk but more can be added as needed. - * Arguments: - * * mob/living/carbon/human/recipient - the mob receiving the mail goodies - */ -/datum/species/proc/update_mail_goodies(mob/living/carbon/human/recipient) - update_quirk_mail_goodies(recipient, recipient.get_quirk(/datum/quirk/blooddeficiency)) - -/** - * Updates the mail goodies of a specific quirk. - * - * Updates the mail goodies belonging to a specific quirk. - * Add implementation as needed for each individual species. The base species proc should give the species the 'default' version of whatever mail goodies are required. - * Arguments: - * * mob/living/carbon/human/recipient - the mob receiving the mail goodies - * * datum/quirk/quirk - the quirk to update the mail goodies of. Use get_quirk(datum/quirk/some_quirk) to get the actual mob's quirk to pass. - * * list/mail_goodies - a list of mail goodies. Generally speaking you should not be using this argument on the initial function call. You should instead add to the species' implementation of this proc. - */ -/datum/species/proc/update_quirk_mail_goodies(mob/living/carbon/human/recipient, datum/quirk/quirk, list/mail_goodies) - if(isnull(quirk)) - return - if(length(mail_goodies)) - quirk.mail_goodies = mail_goodies - return - if(istype(quirk, /datum/quirk/blooddeficiency)) - if(HAS_TRAIT(recipient, TRAIT_NOBLOOD) && isnull(recipient.dna.species.exotic_blood)) // no blood packs should be sent in this case (like if a mob transforms into a plasmaman) - quirk.mail_goodies = list() - return - - - // The default case if no species implementation exists. Set quirk's mail_goodies to initial. - var/datum/quirk/readable_quirk = new quirk.type - quirk.mail_goodies = readable_quirk.mail_goodies - qdel(readable_quirk) // We have to do it this way because initial will not work on lists in this version of DM - return - /** * Handles the body of a human * @@ -697,7 +640,7 @@ GLOBAL_LIST_EMPTY(features_by_species) standing += eye_overlay // organic body markings - if(HAS_MARKINGS in species_traits) + if(HAS_TRAIT(species_human, TRAIT_HAS_MARKINGS)) var/obj/item/bodypart/chest/chest = species_human.get_bodypart(BODY_ZONE_CHEST) var/obj/item/bodypart/arm/right/right_arm = species_human.get_bodypart(BODY_ZONE_R_ARM) var/obj/item/bodypart/arm/left/left_arm = species_human.get_bodypart(BODY_ZONE_L_ARM) @@ -735,7 +678,7 @@ GLOBAL_LIST_EMPTY(features_by_species) standing += markings_l_leg_overlay //Underwear, Undershirts & Socks - if(!(NO_UNDERWEAR in species_traits)) + if(!HAS_TRAIT(species_human, TRAIT_NO_UNDERWEAR)) if(species_human.underwear && !(src.bodytype & BODYTYPE_DIGITIGRADE)) //MONKESTATION EDIT var/datum/sprite_accessory/underwear/underwear = GLOB.underwear_list[species_human.underwear] var/mutable_appearance/underwear_overlay @@ -856,32 +799,26 @@ GLOBAL_LIST_EMPTY(features_by_species) if(!(HAS_TRAIT(source, TRAIT_HUSK))) if(!forced_colour) - switch(accessory.color_src) - if(SKINTONES) - accessory_overlay.color = skintone2hex(source.skin_tone) - if(MUTCOLORS) - if(fixed_mut_color) - accessory_overlay.color = fixed_mut_color - else - accessory_overlay.color = source.dna.features["mcolor"] - if(MUTCOLORS_SECONDARY) - if(fixed_mut_color) - accessory_overlay.color = fixed_mut_color - else - accessory_overlay.color = source.dna.features["mcolor_secondary"] - if(HAIR_COLOR) + if(accessory.palette) + var/key = accessory.palette_key + var/datum/color_palette/located = source.dna.color_palettes[accessory.palette] + if(accessory.palette_key == HAIR_COLOR) if(hair_color == "mutcolor") - accessory_overlay.color = source.dna.features["mcolor"] - else if(hair_color == "fixedmutcolor") - accessory_overlay.color = fixed_mut_color - else - accessory_overlay.color = source.hair_color - if(FACIAL_HAIR_COLOR) - accessory_overlay.color = source.facial_hair_color - if(EYE_COLOR) - accessory_overlay.color = source.eye_color_left - if(ANIME) - accessory_overlay.color = source.dna.features["animecolor"] + key = MUTANT_COLOR + if(!located) + accessory_overlay.color = initial(accessory.palette.default_color) + else + accessory_overlay.color = located.return_color(key, accessory.fallback_key) + else + switch(accessory.color_src) + if(SKIN_COLOR) + accessory_overlay.color = skintone2hex(source.skin_tone) + if(FACIAL_HAIR_COLOR) + accessory_overlay.color = source.facial_hair_color + if(EYE_COLOR) + accessory_overlay.color = source.eye_color_left + if(ANIME_COLOR) + accessory_overlay.color = source.dna.features["animecolor"] else accessory_overlay.color = forced_colour standing += accessory_overlay @@ -955,7 +892,10 @@ GLOBAL_LIST_EMPTY(features_by_species) return /datum/species/proc/spec_life(mob/living/carbon/human/H, seconds_per_tick, times_fired) - if(HAS_TRAIT(H, TRAIT_NOBREATH)) + SHOULD_CALL_PARENT(TRUE) + if(H.stat == DEAD) + return + if(HAS_TRAIT(H, TRAIT_NOBREATH) && (H.health < H.crit_threshold) && !HAS_TRAIT(H, TRAIT_NOCRITDAMAGE)) H.setOxyLoss(0) H.losebreath = 0 @@ -1137,18 +1077,26 @@ GLOBAL_LIST_EMPTY(features_by_species) * Return True to not run the normal metabolism effects. * NOTE: If you return TRUE, that reagent will not be removed liike normal! You must handle it manually. */ -/datum/species/proc/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) +/datum/species/proc/handle_chemical(datum/reagent/chem, mob/living/carbon/human/affected, seconds_per_tick, times_fired) SHOULD_CALL_PARENT(TRUE) - if(chem.type == exotic_blood) - H.blood_volume = min(H.blood_volume + round(chem.volume, 0.1), BLOOD_VOLUME_MAXIMUM) - H.reagents.del_reagent(chem.type) - return TRUE + // Cringe but blood handles this on its own + // This also has problems of its own but that's better fixed later I think + if(!istype(chem, /datum/reagent/blood)) + var/datum/blood_type/blood = affected.get_blood_type() + if(chem.type == blood?.reagent_type) + affected.blood_volume = min(affected.blood_volume + round(chem.volume, 0.1), BLOOD_VOLUME_MAXIMUM) + affected.reagents.del_reagent(chem.type) + return TRUE + if(chem.type == blood?.restoration_chem && affected.blood_volume < BLOOD_VOLUME_NORMAL) + affected.blood_volume += 0.25 * seconds_per_tick + affected.reagents.remove_reagent(chem.type, chem.metabolization_rate * seconds_per_tick) + return TRUE //This handles dumping unprocessable reagents. var/dump_reagent = TRUE - if((chem.process_flags & SYNTHETIC) && (H.dna.species.reagent_tag & PROCESS_SYNTHETIC)) //SYNTHETIC-oriented reagents require PROCESS_SYNTHETIC + if((chem.process_flags & SYNTHETIC) && (affected.dna.species.reagent_tag & PROCESS_SYNTHETIC)) //SYNTHETIC-oriented reagents require PROCESS_SYNTHETIC dump_reagent = FALSE - if((chem.process_flags & ORGANIC) && (H.dna.species.reagent_tag & PROCESS_ORGANIC)) //ORGANIC-oriented reagents require PROCESS_ORGANIC + if((chem.process_flags & ORGANIC) && (affected.dna.species.reagent_tag & PROCESS_ORGANIC)) //ORGANIC-oriented reagents require PROCESS_ORGANIC dump_reagent = FALSE if(dump_reagent) chem.holder.remove_reagent(chem.type, chem.metabolization_rate) @@ -1156,8 +1104,9 @@ GLOBAL_LIST_EMPTY(features_by_species) if(!chem.overdosed && chem.overdose_threshold && chem.volume >= chem.overdose_threshold) chem.overdosed = TRUE - chem.overdose_start(H) - H.log_message("has started overdosing on [chem.name] at [chem.volume] units.", LOG_GAME) + chem.overdose_start(affected) + affected.log_message("has started overdosing on [chem.name] at [chem.volume] units.", LOG_GAME) + return SEND_SIGNAL(affected, COMSIG_SPECIES_HANDLE_CHEMICAL, chem, affected, seconds_per_tick, times_fired) /** * Equip the outfit required for life. Replaces items currently worn. @@ -1508,326 +1457,6 @@ GLOBAL_LIST_EMPTY(features_by_species) return TRUE -////////////////////////// -// ENVIRONMENT HANDLERS // -////////////////////////// - -/** - * Environment handler for species - * - * vars: - * * environment (required) The environment gas mix - * * humi (required)(type: /mob/living/carbon/human) The mob we will target - */ -/datum/species/proc/handle_environment(mob/living/carbon/human/humi, datum/gas_mixture/environment, seconds_per_tick, times_fired) - handle_environment_pressure(humi, environment, seconds_per_tick, times_fired) - -/** - * Body temperature handler for species - * - * These procs manage body temp, bamage, and alerts - * Some of these will still fire when not alive to balance body temp to the room temp. - * vars: - * * humi (required)(type: /mob/living/carbon/human) The mob we will target - */ -/datum/species/proc/handle_body_temperature(mob/living/carbon/human/humi, seconds_per_tick, times_fired) - //when in a cryo unit we suspend all natural body regulation - if(istype(humi.loc, /obj/machinery/atmospherics/components/unary/cryo_cell)) - return - - //Only stabilise core temp when alive and not in statis - if(humi.stat < DEAD && !HAS_TRAIT(humi, TRAIT_STASIS)) - body_temperature_core(humi, seconds_per_tick, times_fired) - - //These do run in statis - body_temperature_skin(humi, seconds_per_tick, times_fired) - body_temperature_alerts(humi, seconds_per_tick, times_fired) - - //Do not cause more damage in statis - if(!HAS_TRAIT(humi, TRAIT_STASIS)) - body_temperature_damage(humi, seconds_per_tick, times_fired) - -/** - * Used to stabilize the core temperature back to normal on living mobs - * - * The metabolisim heats up the core of the mob trying to keep it at the normal body temp - * vars: - * * humi (required) The mob we will stabilize - */ -/datum/species/proc/body_temperature_core(mob/living/carbon/human/humi, seconds_per_tick, times_fired) - var/natural_change = get_temp_change_amount(humi.get_body_temp_normal() - humi.coretemperature, 0.06 * seconds_per_tick) - humi.adjust_coretemperature(humi.metabolism_efficiency * natural_change) - -/** - * Used to normalize the skin temperature on living mobs - * - * The core temp effects the skin, then the enviroment effects the skin, then we refect that back to the core. - * This happens even when dead so bodies revert to room temp over time. - * vars: - * * humi (required) The mob we will targeting - * - seconds_per_tick: The amount of time that is considered as elapsing - * - times_fired: The number of times SSmobs has fired - */ -/datum/species/proc/body_temperature_skin(mob/living/carbon/human/humi, seconds_per_tick, times_fired) - - // change the core based on the skin temp - var/skin_core_diff = humi.bodytemperature - humi.coretemperature - // change rate of 0.04 per second to be slightly below area to skin change rate and still have a solid curve - var/skin_core_change = get_temp_change_amount(skin_core_diff, 0.04 * seconds_per_tick) - - humi.adjust_coretemperature(skin_core_change) - - // get the enviroment details of where the mob is standing - var/datum/gas_mixture/environment = humi.loc.return_air() - if(!environment) // if there is no environment (nullspace) drop out here. - return - - // Get the temperature of the environment for area - var/area_temp = humi.get_temperature(environment) - - // Get the insulation value based on the area's temp - var/thermal_protection = humi.get_insulation_protection(area_temp) - - // Changes to the skin temperature based on the area - var/area_skin_diff = area_temp - humi.bodytemperature - if(!humi.on_fire || area_skin_diff > 0) - // change rate of 0.05 as area temp has large impact on the surface - var/area_skin_change = get_temp_change_amount(area_skin_diff, 0.05 * seconds_per_tick) - - // We need to apply the thermal protection of the clothing when applying area to surface change - // If the core bodytemp goes over the normal body temp you are overheating and becom sweaty - // This will cause the insulation value of any clothing to reduced in effect (70% normal rating) - // we add 10 degree over normal body temp before triggering as thick insulation raises body temp - if(humi.get_body_temp_normal(apply_change=FALSE) + 10 < humi.coretemperature) - // we are overheating and sweaty insulation is not as good reducing thermal protection - area_skin_change = (1 - (thermal_protection * 0.7)) * area_skin_change - else - area_skin_change = (1 - thermal_protection) * area_skin_change - - humi.adjust_bodytemperature(area_skin_change) - - // Core to skin temp transfer, when not on fire - if(!humi.on_fire) - // Get the changes to the skin from the core temp - var/core_skin_diff = humi.coretemperature - humi.bodytemperature - // change rate of 0.045 to reflect temp back to the skin at the slight higher rate then core to skin - var/core_skin_change = (1 + thermal_protection) * get_temp_change_amount(core_skin_diff, 0.045 * seconds_per_tick) - - // We do not want to over shoot after using protection - if(core_skin_diff > 0) - core_skin_change = min(core_skin_change, core_skin_diff) - else - core_skin_change = max(core_skin_change, core_skin_diff) - - humi.adjust_bodytemperature(core_skin_change) - - -/** - * Used to set alerts and debuffs based on body temperature - * vars: - * * humi (required) The mob we will targeting - */ -/datum/species/proc/body_temperature_alerts(mob/living/carbon/human/humi) - var/old_bodytemp = humi.old_bodytemperature - var/bodytemp = humi.bodytemperature - // Body temperature is too hot, and we do not have resist traits - if(bodytemp > bodytemp_heat_damage_limit && !HAS_TRAIT(humi, TRAIT_RESISTHEAT)) - // Clear cold mood and apply hot mood - humi.clear_mood_event("cold") - humi.add_mood_event("hot", /datum/mood_event/hot) - - //Remove any slowdown from the cold. - humi.remove_movespeed_modifier(/datum/movespeed_modifier/cold) - // display alerts based on how hot it is - // Can't be a switch due to http://www.byond.com/forum/post/2750423 - if(bodytemp in bodytemp_heat_damage_limit to BODYTEMP_HEAT_WARNING_2) - humi.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 1) - else if(bodytemp in BODYTEMP_HEAT_WARNING_2 to BODYTEMP_HEAT_WARNING_3) - humi.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 2) - else - humi.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 3) - - // Body temperature is too cold, and we do not have resist traits - else if(bodytemp < bodytemp_cold_damage_limit && !HAS_TRAIT(humi, TRAIT_RESISTCOLD)) - // clear any hot moods and apply cold mood - humi.clear_mood_event("hot") - humi.add_mood_event("cold", /datum/mood_event/cold) - // Apply cold slow down - humi.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/cold, multiplicative_slowdown = ((bodytemp_cold_damage_limit - humi.bodytemperature) / COLD_SLOWDOWN_FACTOR)) - // Display alerts based how cold it is - // Can't be a switch due to http://www.byond.com/forum/post/2750423 - if(bodytemp in BODYTEMP_COLD_WARNING_2 to bodytemp_cold_damage_limit) - humi.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 1) - else if(bodytemp in BODYTEMP_COLD_WARNING_3 to BODYTEMP_COLD_WARNING_2) - humi.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 2) - else - humi.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 3) - - // We are not to hot or cold, remove status and moods - // Optimization here, we check these things based off the old temperature to avoid unneeded work - // We're not perfect about this, because it'd just add more work to the base case, and resistances are rare - else if (old_bodytemp > bodytemp_heat_damage_limit || old_bodytemp < bodytemp_cold_damage_limit) - humi.clear_alert(ALERT_TEMPERATURE) - humi.remove_movespeed_modifier(/datum/movespeed_modifier/cold) - humi.clear_mood_event("cold") - humi.clear_mood_event("hot") - - // Store the old bodytemp for future checking - humi.old_bodytemperature = bodytemp - -/** - * Used to apply wounds and damage based on core/body temp - * vars: - * * humi (required) The mob we will targeting - */ -/datum/species/proc/body_temperature_damage(mob/living/carbon/human/humi, seconds_per_tick, times_fired) - - //If the body temp is above the wound limit start adding exposure stacks - if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT) - humi.heat_exposure_stacks = min(humi.heat_exposure_stacks + (0.5 * seconds_per_tick), 40) - else //When below the wound limit, reduce the exposure stacks fast. - humi.heat_exposure_stacks = max(humi.heat_exposure_stacks - (2 * seconds_per_tick), 0) - - //when exposure stacks are greater then 10 + rand20 try to apply wounds and reset stacks - if(humi.heat_exposure_stacks > (10 + rand(0, 20))) - apply_burn_wounds(humi, seconds_per_tick, times_fired) - humi.heat_exposure_stacks = 0 - - // Body temperature is too hot, and we do not have resist traits - // Apply some burn damage to the body - if(humi.coretemperature > bodytemp_heat_damage_limit && !HAS_TRAIT(humi, TRAIT_RESISTHEAT)) - var/firemodifier = humi.fire_stacks / 50 - if (!humi.on_fire) // We are not on fire, reduce the modifier - firemodifier = min(firemodifier, 0) - - // this can go below 5 at log 2.5 - var/burn_damage = max(log(2 - firemodifier, (humi.coretemperature - humi.get_body_temp_normal(apply_change=FALSE))) - 5, 0) - - // Apply species and physiology modifiers to heat damage - burn_damage = burn_damage * heatmod * humi.physiology.heat_mod * 0.5 * seconds_per_tick - - // 40% for level 3 damage on humans to scream in pain - if (humi.stat < UNCONSCIOUS && (prob(burn_damage) * 10) / 4) - humi.emote("scream") - - // Apply the damage to all body parts - humi.apply_damage(burn_damage, BURN, spread_damage = TRUE) - - // Apply some burn / brute damage to the body (Dependent if the person is hulk or not) - var/is_hulk = HAS_TRAIT(humi, TRAIT_HULK) - - var/cold_damage_limit = bodytemp_cold_damage_limit + (is_hulk ? BODYTEMP_HULK_COLD_DAMAGE_LIMIT_MODIFIER : 0) - - if(humi.coretemperature < cold_damage_limit && !HAS_TRAIT(humi, TRAIT_RESISTCOLD)) - var/damage_type = is_hulk ? BRUTE : BURN // Why? - var/damage_mod = coldmod * humi.physiology.cold_mod * (is_hulk ? HULK_COLD_DAMAGE_MOD : 1) - // Can't be a switch due to http://www.byond.com/forum/post/2750423 - if(humi.coretemperature in 201 to cold_damage_limit) - humi.apply_damage(COLD_DAMAGE_LEVEL_1 * damage_mod * seconds_per_tick, damage_type) - else if(humi.coretemperature in 120 to 200) - humi.apply_damage(COLD_DAMAGE_LEVEL_2 * damage_mod * seconds_per_tick, damage_type) - else - humi.apply_damage(COLD_DAMAGE_LEVEL_3 * damage_mod * seconds_per_tick, damage_type) - -/** - * Used to apply burn wounds on random limbs - * - * This is called from body_temperature_damage when exposure to extream heat adds up and causes a wound. - * The wounds will increase in severity as the temperature increases. - * vars: - * * humi (required) The mob we will targeting - */ -/datum/species/proc/apply_burn_wounds(mob/living/carbon/human/humi, seconds_per_tick, times_fired) - // If we are resistant to heat exit - if(HAS_TRAIT(humi, TRAIT_RESISTHEAT)) - return - - // If our body temp is to low for a wound exit - if(humi.bodytemperature < BODYTEMP_HEAT_WOUND_LIMIT) - return - - // Lets pick a random body part and check for an existing burn - var/obj/item/bodypart/bodypart = pick(humi.bodyparts) - var/datum/wound/existing_burn - for (var/datum/wound/iterated_wound as anything in bodypart.wounds) - var/datum/wound_pregen_data/pregen_data = iterated_wound.get_pregen_data() - if (pregen_data.wound_series in GLOB.wounding_types_to_series[WOUND_BURN]) - existing_burn = iterated_wound - break - // If we have an existing burn try to upgrade it - var/severity - if(existing_burn) - switch(existing_burn.severity) - if(WOUND_SEVERITY_MODERATE) - if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT + 400) // 800k - severity = WOUND_SEVERITY_SEVERE - if(WOUND_SEVERITY_SEVERE) - if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT + 2800) // 3200k - severity = WOUND_SEVERITY_CRITICAL - else // If we have no burn apply the lowest level burn - severity = WOUND_SEVERITY_MODERATE - - humi.cause_wound_of_type_and_severity(WOUND_BURN, bodypart, severity, wound_source = "hot temperatures") - - // always take some burn damage - var/burn_damage = HEAT_DAMAGE_LEVEL_1 - if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT + 400) - burn_damage = HEAT_DAMAGE_LEVEL_2 - if(humi.bodytemperature > BODYTEMP_HEAT_WOUND_LIMIT + 2800) - burn_damage = HEAT_DAMAGE_LEVEL_3 - - humi.apply_damage(burn_damage * seconds_per_tick, BURN, bodypart) - -/// Handle the air pressure of the environment -/datum/species/proc/handle_environment_pressure(mob/living/carbon/human/H, datum/gas_mixture/environment, seconds_per_tick, times_fired) - var/pressure = environment.return_pressure() - var/adjusted_pressure = H.calculate_affecting_pressure(pressure) - - // Set alerts and apply damage based on the amount of pressure - switch(adjusted_pressure) - // Very high pressure, show an alert and take damage - if(HAZARD_HIGH_PRESSURE to INFINITY) - if(HAS_TRAIT(H, TRAIT_RESISTHIGHPRESSURE)) - H.clear_alert(ALERT_PRESSURE) - else - var/pressure_damage = min(((adjusted_pressure / HAZARD_HIGH_PRESSURE) - 1) * PRESSURE_DAMAGE_COEFFICIENT, MAX_HIGH_PRESSURE_DAMAGE) * H.physiology.pressure_mod * H.physiology.brute_mod * seconds_per_tick - H.adjustBruteLoss(pressure_damage, required_bodytype = BODYTYPE_ORGANIC) - H.throw_alert(ALERT_PRESSURE, /atom/movable/screen/alert/highpressure, 2) - - // High pressure, show an alert - if(WARNING_HIGH_PRESSURE to HAZARD_HIGH_PRESSURE) - H.throw_alert(ALERT_PRESSURE, /atom/movable/screen/alert/highpressure, 1) - - // No pressure issues here clear pressure alerts - if(WARNING_LOW_PRESSURE to WARNING_HIGH_PRESSURE) - H.clear_alert(ALERT_PRESSURE) - - // Low pressure here, show an alert - if(HAZARD_LOW_PRESSURE to WARNING_LOW_PRESSURE) - // We have low pressure resit trait, clear alerts - if(HAS_TRAIT(H, TRAIT_RESISTLOWPRESSURE)) - H.clear_alert(ALERT_PRESSURE) - else - H.throw_alert(ALERT_PRESSURE, /atom/movable/screen/alert/lowpressure, 1) - - // Very low pressure, show an alert and take damage - else - // We have low pressure resit trait, clear alerts - if(HAS_TRAIT(H, TRAIT_RESISTLOWPRESSURE)) - H.clear_alert(ALERT_PRESSURE) - else - var/pressure_damage = LOW_PRESSURE_DAMAGE * H.physiology.pressure_mod * H.physiology.brute_mod * seconds_per_tick - H.adjustBruteLoss(pressure_damage, required_bodytype = BODYTYPE_ORGANIC) - H.throw_alert(ALERT_PRESSURE, /atom/movable/screen/alert/lowpressure, 2) - - -////////// -// FIRE // -////////// - -/datum/species/proc/handle_fire(mob/living/carbon/human/H, seconds_per_tick, times_fired, no_protection = FALSE) - return no_protection - //////////// // Stun // //////////// @@ -1877,7 +1506,7 @@ GLOBAL_LIST_EMPTY(features_by_species) if ( \ (preference.relevant_mutant_bodypart in mutant_bodyparts) \ - || (preference.relevant_species_trait in species_traits) \ + || (preference.relevant_inherent_trait in inherent_traits) \ || (preference.relevant_external_organ in external_organs) \ || (preference.relevant_head_flag && check_head_flags(preference.relevant_head_flag)) \ ) @@ -1897,10 +1526,6 @@ GLOBAL_LIST_EMPTY(features_by_species) /datum/species/proc/prepare_human_for_preview(mob/living/carbon/human/human) return -/// Returns the species's scream sound. -/datum/species/proc/get_scream_sound(mob/living/carbon/human/human) - return - /datum/species/proc/get_types_to_preload() var/list/to_store = list() to_store += mutant_organs @@ -1947,6 +1572,12 @@ GLOBAL_LIST_EMPTY(features_by_species) stack_trace("Species [name] ([type]) did not have a description set, and is a selectable roundstart race! Override get_species_description.") return "No species description set, file a bug report!" +/datum/species/proc/get_species_lore() + SHOULD_CALL_PARENT(FALSE) + RETURN_TYPE(/list) + + return list("No species lore set!") + /** * Translate the species liked foods from bitfields into strings * and returns it in the form of an associated list. @@ -1954,21 +1585,16 @@ GLOBAL_LIST_EMPTY(features_by_species) * Returns a list, or null if they have no diet. */ /datum/species/proc/get_species_diet() - if(TRAIT_NOHUNGER in inherent_traits) + if((TRAIT_NOHUNGER in inherent_traits) || !mutanttongue) return null - var/list/food_flags = FOOD_FLAGS + var/static/list/food_flags = FOOD_FLAGS + var/obj/item/organ/internal/tongue/fake_tongue = mutanttongue - if(HAS_TRAIT(src, TRAIT_FLESH_DESIRE)) - return list( - "liked_food" = bitfield_to_list(GORE | MEAT, food_flags), - "disliked_food" = null, - "toxic_food" = bitfield_to_list(VEGETABLES | DAIRY | FRUIT | FRIED, food_flags), - ) return list( - "liked_food" = bitfield_to_list(liked_food, food_flags), - "disliked_food" = bitfield_to_list(disliked_food, food_flags), - "toxic_food" = bitfield_to_list(toxic_food, food_flags), + "liked_food" = bitfield_to_list(initial(fake_tongue.liked_foodtypes), food_flags), + "disliked_food" = bitfield_to_list(initial(fake_tongue.disliked_foodtypes), food_flags), + "toxic_food" = bitfield_to_list(initial(fake_tongue.toxic_foodtypes), food_flags), ) /** @@ -2158,35 +1784,32 @@ GLOBAL_LIST_EMPTY(features_by_species) SPECIES_PERK_DESC = "[plural_form] do not have blood.", )) - // Otherwise, check if their exotic blood is a valid typepath - else if(ispath(exotic_blood)) - to_add += list(list( - SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK, - SPECIES_PERK_ICON = "tint", - SPECIES_PERK_NAME = initial(exotic_blood.name), - SPECIES_PERK_DESC = "[name] blood is [initial(exotic_blood.name)], which can make recieving medical treatment harder.", - )) - // Otherwise otherwise, see if they have an exotic bloodtype set else if(exotic_bloodtype) to_add += list(list( SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK, SPECIES_PERK_ICON = "tint", - SPECIES_PERK_NAME = "Exotic Blood", - SPECIES_PERK_DESC = "[plural_form] have \"[exotic_bloodtype]\" type blood, which can make recieving medical treatment harder.", + SPECIES_PERK_NAME = initial(exotic_bloodtype.name), + SPECIES_PERK_DESC = "[name] blood is [initial(exotic_bloodtype.name)], which can make recieving medical treatment", )) return to_add /** - * Adds adds any perks related to the species' inherent_traits list. + * Adds adds any perks related to the species' inherent_traits list or override body traits. * * Returns a list containing perks, or an empty list. */ /datum/species/proc/create_pref_traits_perks() var/list/to_add = list() - - if(TRAIT_LIMBATTACHMENT in inherent_traits) + var/list/trait_list = list() + trait_list |= inherent_traits.Copy() + for(var/type in bodypart_overrides) + var/obj/item/bodypart/bodypart = bodypart_overrides[type] + var/obj/item/bodypart/new_bodypart = new bodypart + trait_list |= new_bodypart.bodypart_traits.Copy() + + if(TRAIT_LIMBATTACHMENT in trait_list) to_add += list(list( SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK, SPECIES_PERK_ICON = "user-plus", @@ -2195,7 +1818,7 @@ GLOBAL_LIST_EMPTY(features_by_species) require surgery to restore. Simply pick it up and pop it back in, champ!", )) - if(TRAIT_EASYDISMEMBER in inherent_traits) + if(TRAIT_EASYDISMEMBER in trait_list) to_add += list(list( SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, SPECIES_PERK_ICON = "user-times", @@ -2203,7 +1826,7 @@ GLOBAL_LIST_EMPTY(features_by_species) SPECIES_PERK_DESC = "[plural_form] limbs are not secured well, and as such they are easily dismembered.", )) - if(TRAIT_EASILY_WOUNDED in inherent_traits) + if(TRAIT_EASILY_WOUNDED in trait_list) to_add += list(list( SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, SPECIES_PERK_ICON = "user-times", @@ -2211,7 +1834,7 @@ GLOBAL_LIST_EMPTY(features_by_species) SPECIES_PERK_DESC = "[plural_form] skin is very weak and fragile. They are much easier to apply serious wounds to.", )) - if(TRAIT_TOXINLOVER in inherent_traits) + if(TRAIT_TOXINLOVER in trait_list) to_add += list(list( SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK, SPECIES_PERK_ICON = "syringe", diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index 656684c4e15f..da1a93ed6802 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -21,7 +21,7 @@ GLOBAL_LIST_EMPTY(dead_players_during_shift) else new /obj/effect/decal/remains/human(loc) -/mob/living/carbon/human/death(gibbed) +/mob/living/carbon/human/death(gibbed, cause_of_death = get_cause_of_death()) if(stat == DEAD) return stop_sound_channel(CHANNEL_HEARTBEAT) @@ -49,6 +49,67 @@ GLOBAL_LIST_EMPTY(dead_players_during_shift) to_chat(src, span_warning("You have died. Barring complete bodyloss, you can in most cases be revived by other players. If you do not wish to be brought back, use the \"Do Not Resuscitate\" verb in the ghost tab.")) to_chat(src, span_greentext("You can no longer recall who was responsible for your death.")) // MONKESTATION EDIT: making an explicit request that someone review DA RULEZ. + var/death_block = "" + death_block += span_danger("
You have succumbed to [cause_of_death].
") + death_block += "
" + death_block += span_danger("Barring complete bodyloss, you can (in most cases) be revived by other players. \ + If you do not wish to be brought back, use the \"Do Not Resuscitate\" verb in the ghost tab.") + to_chat(src, examine_block(death_block)) + +/mob/living/carbon/human/proc/get_cause_of_death(probable_cause) + switch(probable_cause) + // This should all be refactored later it's a bit of a mess ngl + if(null, "revival_sickess", "anesthetics") + return "unknown causes" + + if(OXY_DAMAGE) + var/obj/item/organ/internal/lungs/lungs = get_organ_slot(ORGAN_SLOT_LUNGS) + if(isnull(lungs) || (lungs.organ_flags & ORGAN_FAILING)) + return "lung failure" + + if(!HAS_TRAIT(src, TRAIT_NOBLOOD) && blood_volume < BLOOD_VOLUME_BAD) + return BLOOD_LOSS + + if(TOX_DAMAGE) + var/obj/item/organ/internal/liver/liver = get_organ_slot(ORGAN_SLOT_LIVER) + if(isnull(liver) || (liver.organ_flags & ORGAN_FAILING)) + return "liver failure" + + var/datum/reagent/toxin/most_toxic + for(var/datum/reagent/toxin/poison in reagents?.reagent_list) + if(!most_toxic || most_toxic.toxpwr < poison.toxpwr) + most_toxic = poison + + if(most_toxic) + return "[lowertext(most_toxic.name)] poisoning" + + if("heart_attack") + return "cardiac arrest" + + if("drunk") + var/datum/reagent/consumable/ethanol/most_alcohol + for(var/datum/reagent/consumable/ethanol/alcohol in reagents?.reagent_list) + if(!most_alcohol || most_alcohol.boozepwr < alcohol.boozepwr) + most_alcohol = alcohol + + if(most_alcohol) + return "alcohol poisoning ([lowertext(most_alcohol.name)])" + + return "alcohol poisoning" + + if("thermia") + if(bodytemperature < standard_body_temperature) + return "hypothermia" + return "hyperthermia" + + else + if(findtext(probable_cause, "disease")) + return "disease" + if(findtext(probable_cause, "addiction")) + return "addiction" + + return probable_cause + /mob/living/carbon/human/proc/reagents_readout() var/readout = "Blood:" for(var/datum/reagent/reagent in reagents?.reagent_list) diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index fb6762f4863f..dbf438919b50 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -94,14 +94,11 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) return /proc/create_consistent_human_dna(mob/living/carbon/human/target) - target.dna.initialize_dna(skip_index = TRUE) + target.dna.initialize_dna(/datum/blood_type/crew/human/o_plus, skip_index = TRUE) target.dna.features["body_markings"] = "None" target.dna.features["ears"] = "None" - target.dna.features["ethcolor"] = COLOR_WHITE target.dna.features["frills"] = "None" target.dna.features["horns"] = "None" - target.dna.features["mcolor"] = COLOR_VIBRANT_LIME - target.dna.features["mcolor_secondary"] = COLOR_VIBRANT_LIME target.dna.features["moth_antennae"] = "Plain" target.dna.features["moth_markings"] = "None" target.dna.features["moth_wings"] = "Plain" @@ -126,6 +123,14 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) target.dna.features["satyr_fluff"] = "Normal" //Monkestation Addition target.dna.features["satyr_tail"] = "Short" //Monkestation Addition target.dna.features["satyr_horns"] = "Back" //Monkestation Addition + target.dna.features["arm_wings"] = "Monochrome" //Monkestation Addition + target.dna.features["ears_avian"] = "Hermes" //Monkestation Addition + target.dna.features["tail_avian"] = "Eagle" //Monkestation Addition + + var/datum/color_palette/generic_colors/palette = target.dna.color_palettes[/datum/color_palette/generic_colors] + palette.mutant_color = COLOR_VIBRANT_LIME + palette.mutant_color_secondary = COLOR_VIBRANT_LIME + palette.ethereal_color = COLOR_WHITE /// Provides a dummy that is consistently bald, white, naked, etc. /mob/living/carbon/human/dummy/consistent diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index d490bdf8cd1e..fba7f888a17f 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -136,6 +136,7 @@ var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) var/list/disabled = list() + var/adjacent = user.Adjacent(src) for(var/X in bodyparts) var/obj/item/bodypart/body_part = X if(body_part.bodypart_disabled) @@ -147,6 +148,12 @@ else msg += "[t_He] [t_has] [icon2html(I, user)] \a [I] embedded in [t_his] [body_part.name]!\n" + if(body_part.current_gauze) + var/gauze_href = body_part.current_gauze.name + if(adjacent && isliving(user)) // only shows the href if we're adjacent + gauze_href = "[gauze_href]" + msg += span_notice("There is some [icon2html(body_part.current_gauze, user)] [gauze_href] wrapped around [t_his] [body_part.plaintext_zone].\n") + for(var/i in body_part.wounds) var/datum/wound/iter_wound = i msg += "[iter_wound.get_examine_description(user)]\n" @@ -242,7 +249,7 @@ msg += "[t_He] look[p_s()] extremely disgusted.\n" var/apparent_blood_volume = blood_volume - if((dna.species.use_skintones)&& skin_tone == "albino") + if(HAS_TRAIT(src, TRAIT_USES_SKINTONES) && (skin_tone == "albino")) apparent_blood_volume -= 150 // enough to knock you down one tier if(isethereal(src))//Monkestation Changes Start: if(appears_dead) @@ -334,9 +341,9 @@ msg += "[t_He] appear[p_s()] to be staring off into space.\n" if (HAS_TRAIT(src, TRAIT_DEAF)) msg += "[t_He] appear[p_s()] to not be responding to noises.\n" - if (bodytemperature > dna.species.bodytemp_heat_damage_limit) + if (bodytemperature > bodytemp_heat_damage_limit) msg += "[t_He] [t_is] flushed and wheezing.\n" - if (bodytemperature < dna.species.bodytemp_cold_damage_limit) + if (bodytemperature < bodytemp_cold_damage_limit) msg += "[t_He] [t_is] shivering.\n" msg += "
" diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index c67ff29b4e13..423d1b817c38 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -48,6 +48,8 @@ become_blind(NO_EYES) // Mobs cannot taste anything without a tongue; the tongue organ removes this on Insert ADD_TRAIT(src, TRAIT_AGEUSIA, NO_TONGUE_TRAIT) + // No lungs until you get lungs + apply_status_effect(/datum/status_effect/lungless) /mob/living/carbon/human/proc/setup_human_dna() //initialize dna. for spawned humans; overwritten by other code @@ -713,11 +715,6 @@ for(var/datum/mutation/human/existing_mutation in dna.mutations) if(existing_mutation.quality != POSITIVE) dna.remove_mutation(existing_mutation.name) - - if(heal_flags & HEAL_TEMP) - set_coretemperature(get_body_temp_normal(apply_change = FALSE)) - heat_exposure_stacks = 0 - return ..() /mob/living/carbon/human/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, vomit_type = VOMIT_TOXIC, harm = TRUE, force = FALSE, purge_ratio = 0.1) @@ -898,24 +895,30 @@ return ..() + +/mob/living/carbon/human/reagent_check(datum/reagent/chem, seconds_per_tick, times_fired) + . = ..() + if(. & COMSIG_MOB_STOP_REAGENT_CHECK) + return + return dna.species.handle_chemical(chem, src, seconds_per_tick, times_fired) + /mob/living/carbon/human/updatehealth() . = ..() dna?.species.spec_updatehealth(src) - if(HAS_TRAIT(src, TRAIT_IGNOREDAMAGESLOWDOWN)) - remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown) - remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying) - return + update_damage_movespeed() + +/mob/living/carbon/human/proc/update_damage_movespeed() var/health_deficiency = max((maxHealth - health), staminaloss) if(health_deficiency >= 40) add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown, TRUE, multiplicative_slowdown = health_deficiency / 75) add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying, TRUE, multiplicative_slowdown = health_deficiency / 25) - else + else if(LAZYACCESS(movespeed_modification, "[/datum/movespeed_modifier/damage_slowdown]")) remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown) remove_movespeed_modifier(/datum/movespeed_modifier/damage_slowdown_flying) /mob/living/carbon/human/pre_stamina_change(diff as num, forced) if(diff < 0) //Taking damage, not healing - return diff * physiology.stamina_mod + return diff * physiology.stamina_mod * physiology.temp_stamina_mod return diff /mob/living/carbon/human/adjust_nutrition(change) //Honestly FUCK the oldcoders for putting nutrition on /mob someone else can move it up because holy hell I'd have to fix SO many typechecks @@ -928,16 +931,6 @@ return FALSE return ..() -/mob/living/carbon/human/is_bleeding() - if(HAS_TRAIT(src, TRAIT_NOBLOOD)) - return FALSE - return ..() - -/mob/living/carbon/human/get_total_bleed_rate() - if(HAS_TRAIT(src, TRAIT_NOBLOOD)) - return FALSE - return ..() - /mob/living/carbon/human/get_exp_list(minutes) . = ..() diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index a51504d92cd9..8b91fd1e1ebd 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -900,9 +900,19 @@ burning.fire_act((stacks * 25 * seconds_per_tick)) //damage taken is reduced to 2% of this value by fire_act() /mob/living/carbon/human/on_fire_stack(seconds_per_tick, times_fired, datum/status_effect/fire_handler/fire_stacks/fire_handler) - SEND_SIGNAL(src, COMSIG_HUMAN_BURNING) - burn_clothing(seconds_per_tick, times_fired, fire_handler.stacks) - var/no_protection = FALSE - if(dna && dna.species) - no_protection = dna.species.handle_fire(src, seconds_per_tick, times_fired, no_protection) - fire_handler.harm_human(seconds_per_tick, times_fired, no_protection) + var/sigreturn = SEND_SIGNAL(src, COMSIG_HUMAN_BURNING) + if(sigreturn & BURNING_HANDLED) + return 0 + + burn_clothing(seconds_per_tick, fire_handler.stacks) + if(!(sigreturn & BURNING_SKIP_PROTECTION)) + if(get_insulation(FIRE_IMMUNITY_MAX_TEMP_PROTECT) >= 0.9) + return 0 + if(get_insulation(FIRE_SUIT_MAX_TEMP_PROTECT) >= 0.9) + return adjust_bodytemperature(HEAT_PER_FIRE_STACK * 0.2 * fire_handler.stacks * seconds_per_tick) + + . = ..() + if(. && !HAS_TRAIT(src, TRAIT_RESISTHEAT)) + add_mood_event("on_fire", /datum/mood_event/on_fire) + add_mob_memory(/datum/memory/was_burning) + return . diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 13db05913a0e..352d54dfa933 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -13,6 +13,9 @@ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID can_be_shoved_into = TRUE + bodytemp_cold_damage_limit = BODYTEMP_COLD_DAMAGE_LIMIT + bodytemp_heat_damage_limit = BODYTEMP_HEAT_DAMAGE_LIMIT + //Hair colour and style var/hair_color = "#000000" var/hairstyle = "Bald" @@ -80,12 +83,6 @@ /// How many "units of blood" we have on our hands var/blood_in_hands = 0 - /// The core temperature of the human compaired to the skin temp of the body - var/coretemperature = BODYTEMP_NORMAL - - ///Exposure to damaging heat levels increases stacks, stacks clean over time when temperatures are lower. Stack is consumed to add a wound. - var/heat_exposure_stacks = 0 - /// When an braindead player has their equipment fiddled with, we log that info here for when they come back so they know who took their ID while they were DC'd for 30 seconds var/list/afk_thefts diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index de565725dbb6..df3f8a716b7e 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -110,25 +110,16 @@ //Check inventory slots return (wear_id?.GetID() || belt?.GetID()) -/mob/living/carbon/human/reagent_check(datum/reagent/R, seconds_per_tick, times_fired) - return dna.species.handle_chemicals(R, src, seconds_per_tick, times_fired) - // if it returns 0, it will run the usual on_mob_life for that reagent. otherwise, it will stop after running handle_chemicals for the species. - /mob/living/carbon/human/can_use_guns(obj/item/G) . = ..() if(G.trigger_guard == TRIGGER_GUARD_NORMAL) - if(check_chunky_fingers()) + if(HAS_TRAIT(src, TRAIT_CHUNKYFINGERS)) balloon_alert(src, "fingers are too big!") return FALSE if(HAS_TRAIT(src, TRAIT_NOGUNS)) to_chat(src, span_warning("You can't bring yourself to use a ranged weapon!")) return FALSE -/mob/living/carbon/human/proc/check_chunky_fingers() - if(HAS_TRAIT_NOT_FROM(src, TRAIT_CHUNKYFINGERS, RIGHT_ARM_TRAIT) && HAS_TRAIT_NOT_FROM(src, TRAIT_CHUNKYFINGERS, LEFT_ARM_TRAIT)) - return TRUE - return (active_hand_index % 2) ? HAS_TRAIT_FROM(src, TRAIT_CHUNKYFINGERS, LEFT_ARM_TRAIT) : HAS_TRAIT_FROM(src, TRAIT_CHUNKYFINGERS, RIGHT_ARM_TRAIT) - /mob/living/carbon/human/get_policy_keywords() . = ..() . += "[dna.species.type]" 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 ec7f482ae1d9..c3ee8c1eda32 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -177,7 +177,8 @@ There are several things that need to be remembered: if(isnull(gloves)) if(blood_in_hands && num_hands > 0) // When byond gives us filters that respect dirs we can just use an alpha mask for this but until then, two icons weeeee - var/mutable_appearance/hands_combined = mutable_appearance(layer = -GLOVES_LAYER, appearance_flags = KEEP_TOGETHER) + var/mutable_appearance/hands_combined = mutable_appearance(layer = -GLOVES_LAYER) + hands_combined.color = get_blood_dna_color() if(has_left_hand(check_disabled = FALSE)) hands_combined.overlays += mutable_appearance('icons/effects/blood.dmi', "bloodyhands_left") if(has_right_hand(check_disabled = FALSE)) diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index dba314b18424..dd773b11ffeb 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -1,7 +1,9 @@ /mob/living/carbon/human/can_equip(obj/item/equip_target, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, ignore_equipped = FALSE) if(SEND_SIGNAL(src, COMSIG_HUMAN_EQUIPPING_ITEM, equip_target, slot) == COMPONENT_BLOCK_EQUIP) return FALSE - + if((slot & ITEM_SLOT_FEET) && HAS_TRAIT(src, TRAIT_NON_IMPORTANT_SHOE_BLOCK)) + if(!istype(equip_target, /obj/item/clothing/shoes/mod)) + return FALSE return dna.species.can_equip(equip_target, slot, disable_warning, src, bypass_equip_delay_self, ignore_equipped) /mob/living/carbon/human/get_item_by_slot(slot_id) diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 6ed3dd274433..9f9a27e6adcf 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -1,22 +1,7 @@ - -//NOTE: Breathing happens once per FOUR TICKS, unless the last breath fails. In which case it happens once per ONE TICK! So oxyloss healing is done once per 4 ticks while oxyloss damage is applied once per tick! - -// bitflags for the percentual amount of protection a piece of clothing which covers the body part offers. -// Used with human/proc/get_heat_protection() and human/proc/get_cold_protection() -// The values here should add up to 1. -// Hands and feet have 2.5%, arms and legs 7.5%, each of the torso parts has 15% and the head has 30% -#define THERMAL_PROTECTION_HEAD 0.3 -#define THERMAL_PROTECTION_CHEST 0.15 -#define THERMAL_PROTECTION_GROIN 0.15 -#define THERMAL_PROTECTION_LEG_LEFT 0.075 -#define THERMAL_PROTECTION_LEG_RIGHT 0.075 -#define THERMAL_PROTECTION_FOOT_LEFT 0.025 -#define THERMAL_PROTECTION_FOOT_RIGHT 0.025 -#define THERMAL_PROTECTION_ARM_LEFT 0.075 -#define THERMAL_PROTECTION_ARM_RIGHT 0.075 -#define THERMAL_PROTECTION_HAND_LEFT 0.025 -#define THERMAL_PROTECTION_HAND_RIGHT 0.025 +// NOTE: Breathing happens once per FOUR TICKS, unless the last breath fails. +// In which case it happens once per ONE TICK! +// So oxyloss healing is done once per 4 ticks while oxyloss damage is applied once per tick! /mob/living/carbon/human/Life(seconds_per_tick = SSMOBS_DT, times_fired) if(HAS_TRAIT(src, TRAIT_NO_TRANSFORM)) @@ -26,9 +11,6 @@ if(QDELETED(src)) return FALSE - //Body temperature stability and damage - dna.species.handle_body_temperature(src, seconds_per_tick, times_fired) - if(!HAS_TRAIT(src, TRAIT_STASIS)) if(.) //not dead @@ -71,210 +53,25 @@ return (occupied_space.contents_pressure_protection * ONE_ATMOSPHERE + (1 - occupied_space.contents_pressure_protection) * pressure) return pressure -/mob/living/carbon/human/breathe() - if(!HAS_TRAIT(src, TRAIT_NOBREATH)) - return ..() - -/mob/living/carbon/human/check_breath(datum/gas_mixture/breath) - var/L = get_organ_slot(ORGAN_SLOT_LUNGS) +/mob/living/carbon/human/check_breath(datum/gas_mixture/breath, skip_breath = FALSE) + var/obj/item/organ/internal/lungs/human_lungs = get_organ_slot(ORGAN_SLOT_LUNGS) + if(human_lungs) + return human_lungs.check_breath(breath, src, skip_breath) - if(!L) - if(health >= crit_threshold) - adjustOxyLoss(HUMAN_MAX_OXYLOSS + 1) - else if(!HAS_TRAIT(src, TRAIT_NOCRITDAMAGE)) - adjustOxyLoss(HUMAN_CRIT_MAX_OXYLOSS) + failed_last_breath = TRUE - failed_last_breath = TRUE + var/datum/species/human_species = dna.species - var/datum/species/S = dna.species - - if(S.breathid == "o2") + switch(human_species.breathid) + if("o2") throw_alert(ALERT_NOT_ENOUGH_OXYGEN, /atom/movable/screen/alert/not_enough_oxy) - else if(S.breathid == "plas") + if("plas") throw_alert(ALERT_NOT_ENOUGH_PLASMA, /atom/movable/screen/alert/not_enough_plas) - else if(S.breathid == "co2") + if("co2") throw_alert(ALERT_NOT_ENOUGH_CO2, /atom/movable/screen/alert/not_enough_co2) - else if(S.breathid == "n2") + if("n2") throw_alert(ALERT_NOT_ENOUGH_NITRO, /atom/movable/screen/alert/not_enough_nitro) - - return FALSE - else - if(istype(L, /obj/item/organ/internal/lungs)) - var/obj/item/organ/internal/lungs/lun = L - lun.check_breath(breath,src) - -/// Environment handlers for species -/mob/living/carbon/human/handle_environment(datum/gas_mixture/environment, seconds_per_tick, times_fired) - // If we are in a cryo bed do not process life functions - if(istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell)) - return - - dna.species.handle_environment(src, environment, seconds_per_tick, times_fired) - -/** - * Adjust the core temperature of a mob - * - * vars: - * * amount The amount of degrees to change body temperature by - * * min_temp (optional) The minimum body temperature after adjustment - * * max_temp (optional) The maximum body temperature after adjustment - */ -/mob/living/carbon/human/proc/adjust_coretemperature(amount, min_temp=0, max_temp=INFINITY) - set_coretemperature(clamp(coretemperature + amount, min_temp, max_temp)) - -/mob/living/carbon/human/proc/set_coretemperature(value) - SEND_SIGNAL(src, COMSIG_HUMAN_CORETEMP_CHANGE, coretemperature, value) - coretemperature = value - -/** - * get_body_temperature Returns the body temperature with any modifications applied - * - * This applies the result from proc/get_body_temp_normal_change() against the bodytemp_normal - * for the species and returns the result - * - * arguments: - * * apply_change (optional) Default True This applies the changes to body temperature normal - */ -/mob/living/carbon/human/get_body_temp_normal(apply_change=TRUE) - if(!apply_change) - return dna.species.bodytemp_normal - return dna.species.bodytemp_normal + get_body_temp_normal_change() - -/mob/living/carbon/human/get_body_temp_heat_damage_limit() - return dna.species.bodytemp_heat_damage_limit - -/mob/living/carbon/human/get_body_temp_cold_damage_limit() - return dna.species.bodytemp_cold_damage_limit - -/mob/living/carbon/human/proc/get_thermal_protection() - var/thermal_protection = 0 //Simple check to estimate how protected we are against multiple temperatures - if(wear_suit) - if((wear_suit.heat_protection & CHEST) && (wear_suit.max_heat_protection_temperature >= FIRE_SUIT_MAX_TEMP_PROTECT)) - thermal_protection += (wear_suit.max_heat_protection_temperature * 0.7) - if(head) - if((head.heat_protection & HEAD) && (head.max_heat_protection_temperature >= FIRE_HELM_MAX_TEMP_PROTECT)) - thermal_protection += (head.max_heat_protection_temperature * THERMAL_PROTECTION_HEAD) - thermal_protection = round(thermal_protection) - return thermal_protection - -//END FIRE CODE - -//This proc returns a number made up of the flags for body parts which you are protected on. (such as HEAD, CHEST, GROIN, etc. See setup.dm for the full list) -/mob/living/carbon/human/proc/get_heat_protection_flags(temperature) //Temperature is the temperature you're being exposed to. - var/thermal_protection_flags = 0 - //Handle normal clothing - if(head) - if(head.max_heat_protection_temperature && head.max_heat_protection_temperature >= temperature) - thermal_protection_flags |= head.heat_protection - if(wear_suit) - if(wear_suit.max_heat_protection_temperature && wear_suit.max_heat_protection_temperature >= temperature) - thermal_protection_flags |= wear_suit.heat_protection - if(w_uniform) - if(w_uniform.max_heat_protection_temperature && w_uniform.max_heat_protection_temperature >= temperature) - thermal_protection_flags |= w_uniform.heat_protection - if(shoes) - if(shoes.max_heat_protection_temperature && shoes.max_heat_protection_temperature >= temperature) - thermal_protection_flags |= shoes.heat_protection - if(gloves) - if(gloves.max_heat_protection_temperature && gloves.max_heat_protection_temperature >= temperature) - thermal_protection_flags |= gloves.heat_protection - if(wear_mask) - if(wear_mask.max_heat_protection_temperature && wear_mask.max_heat_protection_temperature >= temperature) - thermal_protection_flags |= wear_mask.heat_protection - - return thermal_protection_flags - -/mob/living/carbon/human/get_heat_protection(temperature) - var/thermal_protection_flags = get_heat_protection_flags(temperature) - var/thermal_protection = heat_protection - - // Apply clothing items protection - if(thermal_protection_flags) - if(thermal_protection_flags & HEAD) - thermal_protection += THERMAL_PROTECTION_HEAD - if(thermal_protection_flags & CHEST) - thermal_protection += THERMAL_PROTECTION_CHEST - if(thermal_protection_flags & GROIN) - thermal_protection += THERMAL_PROTECTION_GROIN - if(thermal_protection_flags & LEG_LEFT) - thermal_protection += THERMAL_PROTECTION_LEG_LEFT - if(thermal_protection_flags & LEG_RIGHT) - thermal_protection += THERMAL_PROTECTION_LEG_RIGHT - if(thermal_protection_flags & FOOT_LEFT) - thermal_protection += THERMAL_PROTECTION_FOOT_LEFT - if(thermal_protection_flags & FOOT_RIGHT) - thermal_protection += THERMAL_PROTECTION_FOOT_RIGHT - if(thermal_protection_flags & ARM_LEFT) - thermal_protection += THERMAL_PROTECTION_ARM_LEFT - if(thermal_protection_flags & ARM_RIGHT) - thermal_protection += THERMAL_PROTECTION_ARM_RIGHT - if(thermal_protection_flags & HAND_LEFT) - thermal_protection += THERMAL_PROTECTION_HAND_LEFT - if(thermal_protection_flags & HAND_RIGHT) - thermal_protection += THERMAL_PROTECTION_HAND_RIGHT - - return min(1, thermal_protection) - -//See proc/get_heat_protection_flags(temperature) for the description of this proc. -/mob/living/carbon/human/proc/get_cold_protection_flags(temperature) - var/thermal_protection_flags = 0 - //Handle normal clothing - - if(head) - if(head.min_cold_protection_temperature && head.min_cold_protection_temperature <= temperature) - thermal_protection_flags |= head.cold_protection - if(wear_suit) - if(wear_suit.min_cold_protection_temperature && wear_suit.min_cold_protection_temperature <= temperature) - thermal_protection_flags |= wear_suit.cold_protection - if(w_uniform) - if(w_uniform.min_cold_protection_temperature && w_uniform.min_cold_protection_temperature <= temperature) - thermal_protection_flags |= w_uniform.cold_protection - if(shoes) - if(shoes.min_cold_protection_temperature && shoes.min_cold_protection_temperature <= temperature) - thermal_protection_flags |= shoes.cold_protection - if(gloves) - if(gloves.min_cold_protection_temperature && gloves.min_cold_protection_temperature <= temperature) - thermal_protection_flags |= gloves.cold_protection - if(wear_mask) - if(wear_mask.min_cold_protection_temperature && wear_mask.min_cold_protection_temperature <= temperature) - thermal_protection_flags |= wear_mask.cold_protection - - return thermal_protection_flags - -/mob/living/carbon/human/get_cold_protection(temperature) - // There is an occasional bug where the temperature is miscalculated in areas with small amounts of gas. - // This is necessary to ensure that does not affect this calculation. - // Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K. - temperature = max(temperature, 2.7) - var/thermal_protection_flags = get_cold_protection_flags(temperature) - var/thermal_protection = cold_protection - - // Apply clothing items protection - if(thermal_protection_flags) - if(thermal_protection_flags & HEAD) - thermal_protection += THERMAL_PROTECTION_HEAD - if(thermal_protection_flags & CHEST) - thermal_protection += THERMAL_PROTECTION_CHEST - if(thermal_protection_flags & GROIN) - thermal_protection += THERMAL_PROTECTION_GROIN - if(thermal_protection_flags & LEG_LEFT) - thermal_protection += THERMAL_PROTECTION_LEG_LEFT - if(thermal_protection_flags & LEG_RIGHT) - thermal_protection += THERMAL_PROTECTION_LEG_RIGHT - if(thermal_protection_flags & FOOT_LEFT) - thermal_protection += THERMAL_PROTECTION_FOOT_LEFT - if(thermal_protection_flags & FOOT_RIGHT) - thermal_protection += THERMAL_PROTECTION_FOOT_RIGHT - if(thermal_protection_flags & ARM_LEFT) - thermal_protection += THERMAL_PROTECTION_ARM_LEFT - if(thermal_protection_flags & ARM_RIGHT) - thermal_protection += THERMAL_PROTECTION_ARM_RIGHT - if(thermal_protection_flags & HAND_LEFT) - thermal_protection += THERMAL_PROTECTION_HAND_LEFT - if(thermal_protection_flags & HAND_RIGHT) - thermal_protection += THERMAL_PROTECTION_HAND_RIGHT - - return min(1, thermal_protection) + return FALSE /mob/living/carbon/human/handle_random_events(seconds_per_tick, times_fired) //Puke if toxloss is too high @@ -314,14 +111,3 @@ // Tissues die without blood circulation adjustBruteLoss(1 * seconds_per_tick) -#undef THERMAL_PROTECTION_HEAD -#undef THERMAL_PROTECTION_CHEST -#undef THERMAL_PROTECTION_GROIN -#undef THERMAL_PROTECTION_LEG_LEFT -#undef THERMAL_PROTECTION_LEG_RIGHT -#undef THERMAL_PROTECTION_FOOT_LEFT -#undef THERMAL_PROTECTION_FOOT_RIGHT -#undef THERMAL_PROTECTION_ARM_LEFT -#undef THERMAL_PROTECTION_ARM_RIGHT -#undef THERMAL_PROTECTION_HAND_LEFT -#undef THERMAL_PROTECTION_HAND_RIGHT diff --git a/code/modules/mob/living/carbon/human/species_types/abductors.dm b/code/modules/mob/living/carbon/human/species_types/abductors.dm index 7987df7b7fef..910e75df43da 100644 --- a/code/modules/mob/living/carbon/human/species_types/abductors.dm +++ b/code/modules/mob/living/carbon/human/species_types/abductors.dm @@ -2,24 +2,20 @@ name = "Abductor" id = SPECIES_ABDUCTOR sexes = FALSE - species_traits = list( - NO_UNDERWEAR, - ) inherent_traits = list( + TRAIT_NO_UNDERWEAR, TRAIT_NOBREATH, TRAIT_NOHUNGER, TRAIT_VIRUSIMMUNE, TRAIT_NOBLOOD, TRAIT_NODISMEMBER, TRAIT_NEVER_WOUNDED, - TRAIT_CHUNKYFINGERS_IGNORE_BATON, ) mutanttongue = /obj/item/organ/internal/tongue/abductor mutantstomach = null mutantheart = null mutantlungs = null changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT - ass_image = 'icons/ass/assgrey.png' bodypart_overrides = list( BODY_ZONE_HEAD = /obj/item/bodypart/head/abductor, diff --git a/code/modules/mob/living/carbon/human/species_types/android.dm b/code/modules/mob/living/carbon/human/species_types/android.dm index 99a3a852fc7a..b93500f0f52c 100644 --- a/code/modules/mob/living/carbon/human/species_types/android.dm +++ b/code/modules/mob/living/carbon/human/species_types/android.dm @@ -1,16 +1,12 @@ /datum/species/android name = "Android" id = SPECIES_ANDROID - species_traits = list( - NO_DNA_COPY, - NOTRANSSTING, - NO_UNDERWEAR, - NOHUSK, - ) inherent_traits = list( - TRAIT_CAN_USE_FLIGHT_POTION, + TRAIT_NO_UNDERWEAR, + TRAIT_NO_DNA_COPY, + TRAIT_NO_TRANSFORMATION_STING, + TRAIT_NO_HUSK, TRAIT_GENELESS, - TRAIT_LIMBATTACHMENT, TRAIT_NOBREATH, TRAIT_NOCLONELOSS, TRAIT_NOFIRE, @@ -49,11 +45,8 @@ mutantears = /obj/item/organ/internal/ears/cybernetic mutantbutt = /obj/item/organ/internal/butt/cyber species_language_holder = /datum/language_holder/synthetic - wing_types = list(/obj/item/organ/external/wings/functional/robotic) changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT reagent_tag = PROCESS_SYNTHETIC // They don't HAVE a liver, but if they did, they'd have synthetic chem processing. - special_step_sounds = list('sound/effects/servostep.ogg') - bodypart_overrides = list( diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm index 5e1d4530228f..f37821843706 100644 --- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm +++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm @@ -1,14 +1,13 @@ /datum/species/dullahan name = "Dullahan" id = SPECIES_DULLAHAN - species_traits = list() inherent_traits = list( TRAIT_NOBREATH, TRAIT_NOHUNGER, + TRAIT_USES_SKINTONES, ) inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID mutant_bodyparts = list("wings" = "None") - use_skintones = TRUE mutantbrain = /obj/item/organ/internal/brain/dullahan mutanteyes = /obj/item/organ/internal/eyes/dullahan mutanttongue = /obj/item/organ/internal/tongue/dullahan @@ -71,6 +70,7 @@ human.reset_perspective(human) /datum/species/dullahan/spec_life(mob/living/carbon/human/human, seconds_per_tick, times_fired) + . = ..() if(QDELETED(my_head)) my_head = null human.investigate_log("has been gibbed by the loss of [human.p_their()] head.", INVESTIGATE_DEATHS) diff --git a/code/modules/mob/living/carbon/human/species_types/ethereal.dm b/code/modules/mob/living/carbon/human/species_types/ethereal.dm index 49ddfc889e2c..eeaec4a7f096 100644 --- a/code/modules/mob/living/carbon/human/species_types/ethereal.dm +++ b/code/modules/mob/living/carbon/human/species_types/ethereal.dm @@ -265,14 +265,8 @@ BODY_ZONE_CHEST = /obj/item/bodypart/chest/ethereal, ) -/datum/species/ethereal/lustrous/get_scream_sound(mob/living/carbon/human/ethereal) - return pick( - 'sound/voice/ethereal/lustrous_scream_1.ogg', - 'sound/voice/ethereal/lustrous_scream_2.ogg', - 'sound/voice/ethereal/lustrous_scream_3.ogg', - ) - /datum/species/ethereal/lustrous/on_species_gain(mob/living/carbon/new_lustrous, datum/species/old_species, pref_load) ..() - default_color = new_lustrous.dna.features["ethcolor"] - new_lustrous.dna.features["ethcolor"] = GLOB.color_list_lustrous[pick(GLOB.color_list_lustrous)] //Picks one of 5 lustrous-specific colors. + var/datum/color_palette/generic_colors/palette = new_lustrous.dna.color_palettes[/datum/color_palette/generic_colors] + default_color = palette.ethereal_color + palette.ethereal_color = GLOB.color_list_lustrous[pick(GLOB.color_list_lustrous)] //Picks one of 5 lustrous-specific colors. diff --git a/code/modules/mob/living/carbon/human/species_types/flypeople.dm b/code/modules/mob/living/carbon/human/species_types/flypeople.dm index 86897dec5cfb..f50449e7091b 100644 --- a/code/modules/mob/living/carbon/human/species_types/flypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/flypeople.dm @@ -3,19 +3,14 @@ plural_form = "Flypeople" id = SPECIES_FLYPERSON inherent_traits = list( - TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_TACKLING_FRAIL_ATTACKER, TRAIT_ANTENNAE, ) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG meat = /obj/item/food/meat/slab/human/mutant/fly mutanteyes = /obj/item/organ/internal/eyes/fly - liked_food = GROSS | GORE - disliked_food = NONE - toxic_food = NONE changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT species_language_holder = /datum/language_holder/fly - wing_types = list(/obj/item/organ/external/wings/functional/fly) payday_modifier = 0.75 mutanttongue = /obj/item/organ/internal/tongue/fly @@ -43,6 +38,14 @@ . = ..() UnregisterSignal(C, COMSIG_MOB_APPLY_DAMAGE_MODIFIERS) + +/datum/species/fly/handle_chemical(datum/reagent/chem, mob/living/carbon/human/affected, seconds_per_tick, times_fired) + . = ..() + if(. & COMSIG_MOB_STOP_REAGENT_CHECK) + return + if(chem.type == /datum/reagent/toxin/pestkiller) + affected.adjustToxLoss(3 * REM * seconds_per_tick) + /datum/species/fly/proc/damage_weakness(datum/source, list/damage_mods, damage_amount, damagetype, def_zone, sharpness, attack_direction, obj/item/attacking_item) SIGNAL_HANDLER diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm index f82fdd44d8b5..0c4196aeafcc 100644 --- a/code/modules/mob/living/carbon/human/species_types/golems.dm +++ b/code/modules/mob/living/carbon/human/species_types/golems.dm @@ -2,13 +2,12 @@ // Animated beings of stone. They have increased defenses, and do not need to breathe. They're also slow as fuuuck. name = "Golem" id = SPECIES_GOLEM - species_traits = list( - NOTRANSSTING, - MUTCOLORS, - NO_UNDERWEAR, - NO_DNA_COPY, - ) inherent_traits = list( + TRAIT_MUTANT_COLORS, + TRAIT_NO_UNDERWEAR, + TRAIT_NO_DNA_COPY, + TRAIT_NO_TRANSFORMATION_STING, + TRAIT_NO_AUGMENTS, TRAIT_GENELESS, TRAIT_NOBREATH, TRAIT_NOBLOOD, @@ -23,7 +22,6 @@ mutantlungs = null inherent_biotypes = MOB_HUMANOID|MOB_MINERAL mutant_organs = list(/obj/item/organ/internal/adamantine_resonator) - speedmod = 2 payday_modifier = 0.75 armor = 55 siemens_coeff = 0 @@ -36,6 +34,8 @@ // changes, only the Random Golem type can be chosen fixed_mut_color = "#aaaaaa" + bodytemp_cold_damage_limit = ICEBOX_MIN_TEMPERATURE - 10 KELVIN + bodypart_overrides = list( BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/golem, BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/golem, @@ -108,6 +108,7 @@ //Can burn and takes damage from heat //no RESISTHEAT, NOFIRE inherent_traits = list( + TRAIT_MUTANT_COLORS, TRAIT_GENELESS, TRAIT_NOBREATH, TRAIT_NODISMEMBER, @@ -187,7 +188,6 @@ name = "Gold Golem" id = SPECIES_GOLEM_GOLD fixed_mut_color = "#cccc00" - speedmod = 1 armor = 25 //down from 55 meat = /obj/item/stack/ore/gold info_text = "As a Gold Golem, you are faster but less resistant than the average golem." @@ -220,7 +220,6 @@ id = SPECIES_GOLEM_PLASTEEL fixed_mut_color = "#bbbbbb" stunmod = 0.4 - speedmod = 4 //pretty fucking slow meat = /obj/item/stack/ore/iron info_text = "As a Plasteel Golem, you are slower, but harder to stun, and hit very hard when punching. You also magnetically attach to surfaces and so don't float without gravity and cannot have positions swapped with other beings." prefix = "Plasteel" @@ -293,7 +292,6 @@ fixed_mut_color = "#333333" meat = /obj/item/stack/sheet/mineral/abductor mutanttongue = /obj/item/organ/internal/tongue/abductor - speedmod = 1 //faster info_text = "As an Alloy Golem, you are made of advanced alien materials: you are faster and regenerate over time. You are, however, only able to be heard by other alloy golems." prefix = "Alien" special_names = list("Outsider", "Technology", "Watcher", "Stranger") //ominous and unknown @@ -301,6 +299,7 @@ //Regenerates because self-repairing super-advanced alien tech /datum/species/golem/alloy/spec_life(mob/living/carbon/human/H, seconds_per_tick, times_fired) + SHOULD_CALL_PARENT(FALSE) if(H.stat == DEAD) return H.heal_overall_damage(brute = 1 * seconds_per_tick, burn = 1 * seconds_per_tick, required_bodytype = BODYTYPE_ORGANIC) @@ -315,6 +314,7 @@ meat = /obj/item/stack/sheet/mineral/wood //Can burn and take damage from heat inherent_traits = list( + TRAIT_MUTANT_COLORS, TRAIT_GENELESS, TRAIT_NOBREATH, TRAIT_NODISMEMBER, @@ -337,6 +337,7 @@ examine_limb_id = SPECIES_GOLEM /datum/species/golem/wood/spec_life(mob/living/carbon/human/H, seconds_per_tick, times_fired) + SHOULD_CALL_PARENT(FALSE) if(H.stat == DEAD) return var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing @@ -354,7 +355,7 @@ if(H.nutrition < NUTRITION_LEVEL_STARVING + 50) H.take_overall_damage(brute = 2, required_bodytype = BODYTYPE_ORGANIC) -/datum/species/golem/wood/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) +/datum/species/golem/wood/handle_chemical(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) if(chem.type == /datum/reagent/toxin/plantbgone) H.adjustToxLoss(3 * REM * seconds_per_tick) H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM * seconds_per_tick) @@ -557,6 +558,7 @@ id = SPECIES_GOLEM_BANANIUM fixed_mut_color = "#ffff00" inherent_traits = list( + TRAIT_MUTANT_COLORS, TRAIT_CLUMSY, TRAIT_GENELESS, TRAIT_NOBREATH, @@ -658,8 +660,9 @@ id = SPECIES_GOLEM_CULT sexes = FALSE info_text = "As a Runic Golem, you possess eldritch powers granted by the Elder Goddess Nar'Sie." - species_traits = list(NO_UNDERWEAR,NOEYESPRITES) //no mutcolors inherent_traits = list( + TRAIT_MUTANT_COLORS, + TRAIT_NO_UNDERWEAR, TRAIT_GENELESS, TRAIT_NOBREATH, TRAIT_NODISMEMBER, @@ -725,7 +728,7 @@ QDEL_NULL(dominate) return ..() -/datum/species/golem/runic/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) +/datum/species/golem/runic/handle_chemical(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) . = ..() if(istype(chem, /datum/reagent/water/holywater)) H.adjustFireLoss(4 * REM * seconds_per_tick) @@ -742,8 +745,9 @@ sexes = FALSE info_text = "As a Cloth Golem, you are able to reform yourself after death, provided your remains aren't burned or destroyed. You are, of course, very flammable. \ Being made of cloth, your body is immune to spirits of the damned and runic golems. You are faster than that of other golems, but weaker and less resilient." - species_traits = list(NO_UNDERWEAR) //no mutcolors, and can burn inherent_traits = list( + TRAIT_MUTANT_COLORS, + TRAIT_NO_UNDERWEAR, TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, TRAIT_GENELESS, @@ -760,7 +764,6 @@ inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID armor = 15 //feels no pain, but not too resistant burnmod = 2 // don't get burned - speedmod = 1 // not as heavy as stone prefix = "Cloth" special_names = null bodypart_overrides = list( @@ -914,6 +917,7 @@ name = "Plastic Golem" id = SPECIES_GOLEM_PLASTIC inherent_traits = list( + TRAIT_MUTANT_COLORS, TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, TRAIT_GENELESS, @@ -942,7 +946,6 @@ special_names = list("Bell") fixed_mut_color = "#cd7f32" info_text = "As a Bronze Golem, you are very resistant to loud noises, and make loud noises if something hard hits you, however this ability does hurt your hearing." - special_step_sounds = list('sound/machines/clockcult/integration_cog_install.ogg', 'sound/magic/clockwork/fellowship_armory.ogg' ) mutantears = /obj/item/organ/internal/ears/bronze examine_limb_id = SPECIES_GOLEM var/last_gong_time = 0 @@ -1009,8 +1012,9 @@ prefix = "Cardboard" special_names = list("Box") info_text = "As a Cardboard Golem, you aren't very strong, but you are a bit quicker and can easily create more brethren by using cardboard on yourself. Cardboard makes a poor building material for tongues, so you'll have difficulty speaking." - species_traits = list(NO_UNDERWEAR,NOEYESPRITES) inherent_traits = list( + TRAIT_MUTANT_COLORS, + TRAIT_NO_UNDERWEAR, TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, TRAIT_GENELESS, @@ -1030,7 +1034,6 @@ armor = 25 burnmod = 1.25 heatmod = 2 - speedmod = 1.5 bodypart_overrides = list( BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/golem/cardboard, BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/golem/cardboard, @@ -1077,6 +1080,7 @@ id = SPECIES_GOLEM_LEATHER special_names = list("Face", "Man", "Belt") //Ah dude 4 strength 4 stam leather belt AHHH inherent_traits = list( + TRAIT_MUTANT_COLORS, TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, TRAIT_GENELESS, @@ -1101,9 +1105,10 @@ id = SPECIES_GOLEM_DURATHREAD prefix = "Durathread" special_names = list("Boll","Weave") - species_traits = list(NO_UNDERWEAR,NOEYESPRITES) fixed_mut_color = null inherent_traits = list( + TRAIT_MUTANT_COLORS, + TRAIT_NO_UNDERWEAR, TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, TRAIT_GENELESS, @@ -1137,18 +1142,14 @@ id = SPECIES_GOLEM_BONE prefix = "Bone" special_names = list("Head", "Broth", "Fracture", "Rattler", "Appetit") - liked_food = GROSS | MEAT | RAW | GORE - toxic_food = null inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID mutanttongue = /obj/item/organ/internal/tongue/bone mutantstomach = /obj/item/organ/internal/stomach/bone sexes = FALSE fixed_mut_color = null - species_traits = list( - NO_UNDERWEAR, - NOEYESPRITES, - ) inherent_traits = list( + TRAIT_MUTANT_COLORS, + TRAIT_NO_UNDERWEAR, TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, TRAIT_FAKEDEATH, @@ -1189,7 +1190,7 @@ bonechill.Remove(C) ..() -/datum/species/golem/bone/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) +/datum/species/golem/bone/handle_chemical(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) . = ..() if(chem.type == /datum/reagent/toxin/bonehurtingjuice) H.stamina.adjust(-7.5 * REM * seconds_per_tick, 0) @@ -1261,8 +1262,9 @@ info_text = "As a Snow Golem, you are extremely vulnerable to burn damage, but you can generate snowballs and shoot cryokinetic beams. You will also turn to snow when dying, preventing any form of recovery." prefix = "Snow" special_names = list("Flake", "Blizzard", "Storm") - species_traits = list(NO_UNDERWEAR,NOEYESPRITES) //no mutcolors, no eye sprites inherent_traits = list( + TRAIT_MUTANT_COLORS, + TRAIT_NO_UNDERWEAR, TRAIT_ADVANCEDTOOLUSER, TRAIT_CAN_STRIP, TRAIT_GENELESS, @@ -1326,6 +1328,7 @@ prefix = "Metallic Hydrogen" special_names = list("Pressure","Crush") inherent_traits = list( + TRAIT_MUTANT_COLORS, TRAIT_GENELESS, TRAIT_NOBREATH, TRAIT_NODISMEMBER, diff --git a/code/modules/mob/living/carbon/human/species_types/humans.dm b/code/modules/mob/living/carbon/human/species_types/humans.dm index caeecface3f7..61162604715c 100644 --- a/code/modules/mob/living/carbon/human/species_types/humans.dm +++ b/code/modules/mob/living/carbon/human/species_types/humans.dm @@ -1,15 +1,11 @@ /datum/species/human name = "\improper Human" id = SPECIES_HUMAN - species_traits = list() + mutant_bodyparts = list("wings" = "None") inherent_traits = list( - TRAIT_CAN_USE_FLIGHT_POTION, + TRAIT_USES_SKINTONES, ) - mutant_bodyparts = list("wings" = "None") - use_skintones = TRUE skinned_type = /obj/item/stack/sheet/animalhide/human - disliked_food = GROSS | RAW | CLOTH | BUGS | GORE - liked_food = JUNKFOOD | FRIED changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT payday_modifier = 1 @@ -21,27 +17,6 @@ /datum/species/human/randomize_features(mob/living/carbon/human/human_mob) human_mob.skin_tone = random_skin_tone() -/datum/species/human/get_scream_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - if(prob(1)) - return 'sound/voice/human/wilhelm_scream.ogg' - return pick( - 'sound/voice/human/malescream_1.ogg', - 'sound/voice/human/malescream_2.ogg', - 'sound/voice/human/malescream_3.ogg', - 'sound/voice/human/malescream_4.ogg', - 'sound/voice/human/malescream_5.ogg', - 'sound/voice/human/malescream_6.ogg', - ) - - return pick( - 'sound/voice/human/femalescream_1.ogg', - 'sound/voice/human/femalescream_2.ogg', - 'sound/voice/human/femalescream_3.ogg', - 'sound/voice/human/femalescream_4.ogg', - 'sound/voice/human/femalescream_5.ogg', - ) - /datum/species/human/get_species_description() return "Humans are the dominant species in the known galaxy. \ Their kind extend from old Earth to the edges of known space." diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm index 3fb5d55cf93a..c59ca37b37e1 100644 --- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm @@ -1,33 +1,20 @@ -///The rate at which slimes regenerate their jelly normally -#define JELLY_REGEN_RATE 1.5 -///The rate at which slimes regenerate their jelly when they completely run out of it and start taking damage, usually after having cannibalized all their limbs already -#define JELLY_REGEN_RATE_EMPTY 2.5 -///The blood volume at which slimes begin to start losing nutrition -- so that IV drips can work for blood deficient slimes -#define BLOOD_VOLUME_LOSE_NUTRITION 550 - /datum/species/jelly // Entirely alien beings that seem to be made entirely out of gel. They have three eyes and a skeleton visible within them. name = "\improper Jellyperson" plural_form = "Jellypeople" id = SPECIES_JELLYPERSON - species_traits = list( - MUTCOLORS, - ) inherent_traits = list( - TRAIT_CAN_USE_FLIGHT_POTION, - TRAIT_TOXINLOVER, - TRAIT_NOBLOOD, + TRAIT_MUTANT_COLORS, ) mutanttongue = /obj/item/organ/internal/tongue/jelly mutantlungs = /obj/item/organ/internal/lungs/slime mutanteyes = /obj/item/organ/internal/eyes/jelly - mutantheart = null + mutantheart = /obj/item/organ/internal/heart/slime + mutantliver = /obj/item/organ/internal/liver/slime + meat = /obj/item/food/meat/slab/human/mutant/slime - exotic_blood = /datum/reagent/toxin/slimejelly - blood_deficiency_drain_rate = JELLY_REGEN_RATE + BLOOD_DEFICIENCY_MODIFIER - var/datum/action/innate/regenerate_limbs/regenerate_limbs - liked_food = MEAT | BUGS - toxic_food = NONE + exotic_bloodtype = /datum/blood_type/slime + blood_deficiency_drain_rate = 1.5 + BLOOD_DEFICIENCY_MODIFIER coldmod = 6 // = 3x cold damage heatmod = 0.5 // = 1/4x heat damage burnmod = 0.5 // = 1/2x generic burn damage @@ -35,9 +22,7 @@ changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT inherent_factions = list(FACTION_SLIME) species_language_holder = /datum/language_holder/jelly - ass_image = 'icons/ass/assslime.png' - wing_types = list(/obj/item/organ/external/wings/functional/slime) - hair_color = "mutcolor" + hair_color = "mutant_color" hair_alpha = 150 facial_hair_alpha = 150 @@ -50,73 +35,6 @@ BODY_ZONE_CHEST = /obj/item/bodypart/chest/jelly, ) -/datum/species/jelly/on_species_gain(mob/living/carbon/new_jellyperson, datum/species/old_species, pref_load) - . = ..() - if(ishuman(new_jellyperson)) - regenerate_limbs = new - regenerate_limbs.Grant(new_jellyperson) - update_mail_goodies(new_jellyperson) - new_jellyperson.AddElement(/datum/element/soft_landing) - -/datum/species/jelly/on_species_loss(mob/living/carbon/former_jellyperson, datum/species/new_species, pref_load) - if(regenerate_limbs) - regenerate_limbs.Remove(former_jellyperson) - former_jellyperson.RemoveElement(/datum/element/soft_landing) - - return ..() - -/datum/species/jelly/update_quirk_mail_goodies(mob/living/carbon/human/recipient, datum/quirk/quirk, list/mail_goodies = list()) - if(istype(quirk, /datum/quirk/blooddeficiency)) - mail_goodies += list( - /obj/item/reagent_containers/blood/toxin - ) - return ..() - -/datum/species/jelly/spec_life(mob/living/carbon/human/H, seconds_per_tick, times_fired) - if(H.stat == DEAD) //can't farm slime jelly from a dead slime/jelly person indefinitely - return - - if(!H.blood_volume) - H.blood_volume += JELLY_REGEN_RATE_EMPTY * seconds_per_tick - H.adjustBruteLoss(2.5 * seconds_per_tick) - to_chat(H, span_danger("You feel empty!")) - - if(H.blood_volume < BLOOD_VOLUME_NORMAL) - if(H.nutrition >= NUTRITION_LEVEL_STARVING) - H.blood_volume += JELLY_REGEN_RATE * seconds_per_tick - if(H.blood_volume <= BLOOD_VOLUME_LOSE_NUTRITION) // don't lose nutrition if we are above a certain threshold, otherwise slimes on IV drips will still lose nutrition - H.adjust_nutrition(-1.25 * seconds_per_tick) - - // we call lose_blood() here rather than quirk/process() to make sure that the blood loss happens in sync with life() - if(HAS_TRAIT(H, TRAIT_BLOOD_DEFICIENCY)) - var/datum/quirk/blooddeficiency/blooddeficiency = H.get_quirk(/datum/quirk/blooddeficiency) - if(!isnull(blooddeficiency)) - blooddeficiency.lose_blood(seconds_per_tick) - - if(H.blood_volume < BLOOD_VOLUME_OKAY) - if(SPT_PROB(2.5, seconds_per_tick)) - to_chat(H, span_danger("You feel drained!")) - - if(H.blood_volume < BLOOD_VOLUME_BAD) - Cannibalize_Body(H) - - if(regenerate_limbs) - regenerate_limbs.build_all_button_icons() - -/datum/species/jelly/proc/Cannibalize_Body(mob/living/carbon/human/H) - var/list/limbs_to_consume = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) - H.get_missing_limbs() - var/obj/item/bodypart/consumed_limb - if(!length(limbs_to_consume)) - H.losebreath++ - return - if(H.num_legs) //Legs go before arms - limbs_to_consume -= list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM) - consumed_limb = H.get_bodypart(pick(limbs_to_consume)) - consumed_limb.drop_limb() - to_chat(H, span_userdanger("Your [consumed_limb] is drawn back into your body, unable to maintain its shape!")) - qdel(consumed_limb) - H.blood_volume += 20 - // Slimes have both TRAIT_NOBLOOD and an exotic bloodtype set, so they need to be handled uniquely here. // They may not be roundstart but in the unlikely event they become one might as well not leave a glaring issue open. /datum/species/jelly/create_pref_blood_perks() @@ -126,53 +44,12 @@ SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK, SPECIES_PERK_ICON = "tint", SPECIES_PERK_NAME = "Jelly Blood", - SPECIES_PERK_DESC = "[plural_form] don't have blood, but instead have toxic [initial(exotic_blood.name)]! \ + SPECIES_PERK_DESC = "[plural_form] don't have blood, but instead have toxic-to-humans Jelly! \ Jelly is extremely important, as losing it will cause you to lose limbs. Having low jelly will make medical treatment very difficult.", )) return to_add -/datum/action/innate/regenerate_limbs - name = "Regenerate Limbs" - check_flags = AB_CHECK_CONSCIOUS - button_icon_state = "slimeheal" - button_icon = 'icons/mob/actions/actions_slime.dmi' - background_icon_state = "bg_alien" - overlay_icon_state = "bg_alien_border" - -/datum/action/innate/regenerate_limbs/IsAvailable(feedback = FALSE) - . = ..() - if(!.) - return - var/mob/living/carbon/human/H = owner - var/list/limbs_to_heal = H.get_missing_limbs() - if(!length(limbs_to_heal)) - return FALSE - if(H.blood_volume >= BLOOD_VOLUME_OKAY+40) - return TRUE - -/datum/action/innate/regenerate_limbs/Activate() - var/mob/living/carbon/human/H = owner - var/list/limbs_to_heal = H.get_missing_limbs() - if(!length(limbs_to_heal)) - to_chat(H, span_notice("You feel intact enough as it is.")) - return - to_chat(H, span_notice("You focus intently on your missing [length(limbs_to_heal) >= 2 ? "limbs" : "limb"]...")) - if(H.blood_volume >= 40*length(limbs_to_heal)+BLOOD_VOLUME_OKAY) - H.regenerate_limbs() - H.blood_volume -= 40*length(limbs_to_heal) - to_chat(H, span_notice("...and after a moment you finish reforming!")) - return - else if(H.blood_volume >= 40)//We can partially heal some limbs - while(H.blood_volume >= BLOOD_VOLUME_OKAY+40) - var/healed_limb = pick(limbs_to_heal) - H.regenerate_limb(healed_limb) - limbs_to_heal -= healed_limb - H.blood_volume -= 40 - to_chat(H, span_warning("...but there is not enough of you to fix everything! You must attain more mass to heal completely!")) - return - to_chat(H, span_warning("...but there is not enough of you to go around! You must attain more mass to heal!")) - ////////////////////////////////////////////////////////SLIMEPEOPLE/////////////////////////////////////////////////////////////////// //Slime people are able to split like slimes, retaining a single mind that can swap between bodies at will, even after death. @@ -181,7 +58,9 @@ name = "\improper Slimeperson" plural_form = "Slimepeople" id = SPECIES_SLIMEPERSON - species_traits = list(MUTCOLORS,) + inherent_traits = list( + TRAIT_MUTANT_COLORS, + ) hair_color = "mutcolor" hair_alpha = 150 facial_hair_alpha = 150 @@ -250,7 +129,7 @@ else if(H.nutrition >= NUTRITION_LEVEL_WELL_FED) H.blood_volume += 1.5 * seconds_per_tick - if(H.blood_volume <= BLOOD_VOLUME_LOSE_NUTRITION) + if(H.blood_volume <= 550) H.adjust_nutrition(-1.25 * seconds_per_tick) ..() @@ -302,8 +181,8 @@ spare.underwear = "Nude" H.dna.transfer_identity(spare, transfer_SE=1) - spare.dna.features["mcolor"] = "#[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]" - spare.dna.update_uf_block(DNA_MUTANT_COLOR_BLOCK) + var/datum/color_palette/generic_colors/palette = spare.dna.color_palettes[/datum/color_palette/generic_colors] + palette.mutant_color = "#[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]" spare.real_name = spare.dna.real_name spare.name = spare.dna.real_name spare.updateappearance(mutcolor_update=1) @@ -377,7 +256,8 @@ continue var/list/L = list() - L["htmlcolor"] = body.dna.features["mcolor"] + var/datum/color_palette/generic_colors/palette = body.dna.color_palettes[/datum/color_palette/generic_colors] + L["htmlcolor"] = palette?.mutant_color L["area"] = get_area_name(body, TRUE) var/stat = "error" switch(body.stat) @@ -546,7 +426,8 @@ /datum/species/jelly/luminescent/proc/update_glow(mob/living/carbon/human/glowie, intensity) if(intensity) glow_intensity = intensity - glow.set_light_range_power_color(glow_intensity, glow_intensity, glowie.dna.features["mcolor"]) + var/datum/color_palette/generic_colors/palette = glowie.dna.color_palettes[/datum/color_palette/generic_colors] + glow.set_light_range_power_color(glow_intensity, glow_intensity, palette.return_color(MUTANT_COLOR)) /datum/action/innate/integrate_extract name = "Integrate Extract" @@ -810,7 +691,3 @@ return FALSE return TRUE - -#undef JELLY_REGEN_RATE -#undef JELLY_REGEN_RATE_EMPTY -#undef BLOOD_VOLUME_LOSE_NUTRITION diff --git a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm index 117ff8257afd..9140e6d16d87 100644 --- a/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/lizardpeople.dm @@ -4,11 +4,10 @@ plural_form = "Lizardfolk" id = SPECIES_LIZARD visual_gender = FALSE - species_traits = list( - MUTCOLORS, - MUTCOLORS_SECONDARY, - ) inherent_traits = list( + TRAIT_MUTANT_COLORS, + TRAIT_MUTANT_COLORS_SECONDARY, + TRAIT_NO_UNDERWEAR, TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_TACKLING_TAILED_DEFENDER, ) @@ -22,6 +21,8 @@ /obj/item/organ/external/tail/lizard = "Smooth", ) mutanttongue = /obj/item/organ/internal/tongue/lizard + mutantstomach = /obj/item/organ/internal/stomach/lizard + mutantheart = /obj/item/organ/internal/heart/lizard coldmod = 1.5 heatmod = 0.67 payday_modifier = 0.75 @@ -29,22 +30,18 @@ species_cookie = /obj/item/food/meat/slab meat = /obj/item/food/meat/slab/human/mutant/lizard skinned_type = /obj/item/stack/sheet/animalhide/lizard - exotic_bloodtype = "L" - disliked_food = GRAIN | DAIRY | CLOTH | GROSS - liked_food = GORE | MEAT | SEAFOOD | NUTS | BUGS + exotic_bloodtype = /datum/blood_type/crew/lizard inert_mutation = /datum/mutation/human/firebreath death_sound = 'sound/voice/lizard/deathsound.ogg' - wing_types = list(/obj/item/organ/external/wings/functional/dragon) species_language_holder = /datum/language_holder/lizard digitigrade_customization = DIGITIGRADE_FORCED //Monkestation Edit: OPTIONAL > FORCED mutanteyes = /obj/item/organ/internal/eyes/lizard // Lizards are coldblooded and can stand a greater temperature range than humans - bodytemp_heat_damage_limit = (BODYTEMP_HEAT_DAMAGE_LIMIT + 20) // This puts lizards 10 above lavaland max heat for ash lizards. + bodytemp_normal = (BODYTEMP_NORMAL - 7.5) + bodytemp_heat_damage_limit = BODYTEMP_HEAT_LAVALAND_SAFE + 5 KELVIN // This puts lizards 10 above lavaland max heat for ash lizards. bodytemp_cold_damage_limit = (BODYTEMP_COLD_DAMAGE_LIMIT - 10) - ass_image = 'icons/ass/asslizard.png' - bodypart_overrides = list( BODY_ZONE_HEAD = /obj/item/bodypart/head/lizard, BODY_ZONE_CHEST = /obj/item/bodypart/chest/lizard, @@ -54,21 +51,12 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/lizard, ) -/datum/species/lizard/on_species_gain(mob/living/carbon/new_lizard, datum/species/old_species, pref_load) +/datum/species/lizard/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) . = ..() - if(ishuman(new_lizard)) - update_mail_goodies(new_lizard) - -/datum/species/lizard/update_quirk_mail_goodies(mob/living/carbon/human/recipient, datum/quirk/quirk, list/mail_goodies = list()) - if(istype(quirk, /datum/quirk/blooddeficiency)) - mail_goodies += list( - /obj/item/reagent_containers/blood/lizard - ) - return ..() - -/// Lizards are cold blooded and do not stabilize body temperature naturally -/datum/species/lizard/body_temperature_core(mob/living/carbon/human/humi, seconds_per_tick, times_fired) - return + // melbert todo : temp / integrate this into the coldblooded trait + // if you spawn on station is is expected you have already acclimated to the room temp (20c) (but give a little bit of leeway) + if(is_station_level(C.z)) + C.bodytemperature = CELCIUS_TO_KELVIN(22.5 CELCIUS) /datum/species/lizard/random_name(gender,unique,lastname) if(unique) @@ -86,13 +74,6 @@ human_mob.dna.features["body_markings"] = pick(GLOB.body_markings_list) randomize_external_organs(human_mob) -/datum/species/lizard/get_scream_sound(mob/living/carbon/human/lizard) - return pick( - 'sound/voice/lizard/lizard_scream_1.ogg', - 'sound/voice/lizard/lizard_scream_2.ogg', - 'sound/voice/lizard/lizard_scream_3.ogg', - ) - /datum/species/lizard/get_species_description() return "The militaristic Lizardpeople hail originally from Tizira, but have grown \ throughout their centuries in the stars to possess a large spacefaring \ @@ -122,16 +103,12 @@ Lizard subspecies: ASHWALKERS id = SPECIES_LIZARD_ASH mutantlungs = /obj/item/organ/internal/lungs/lavaland mutantbrain = /obj/item/organ/internal/brain/primitive - wing_types = list(/obj/item/organ/external/wings/functional/dragon) - species_traits = list( - MUTCOLORS, - MUTCOLORS_SECONDARY, - NO_UNDERWEAR, //MONKESTATION ADDITION: no more flesh clothes lol - ) inherent_traits = list( + TRAIT_MUTANT_COLORS, + TRAIT_MUTANT_COLORS_SECONDARY, + TRAIT_NO_UNDERWEAR, //TRAIT_LITERATE, TRAIT_VIRUSIMMUNE, - TRAIT_HARD_SOLES, //MONKESTATION ADDITION TRAIT_CAN_USE_FLIGHT_POTION, ) species_language_holder = /datum/language_holder/lizard/ash @@ -142,8 +119,8 @@ Lizard subspecies: ASHWALKERS BODY_ZONE_CHEST = /obj/item/bodypart/chest/lizard, BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/lizard/ashwalker, BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/lizard/ashwalker, - BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/lizard, - BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/lizard, + BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/lizard/ashwalker, + BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/lizard/ashwalker, ) /* @@ -165,6 +142,7 @@ Lizard subspecies: SILVER SCALED mutantlungs = null species_language_holder = /datum/language_holder/lizard/silver mutanttongue = /obj/item/organ/internal/tongue/lizard/silver + exotic_bloodtype = /datum/blood_type/crew/lizard/silver armor = 10 //very light silvery scales soften blows changesource_flags = MIRROR_BADMIN | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN examine_limb_id = SPECIES_LIZARD @@ -177,10 +155,11 @@ Lizard subspecies: SILVER SCALED /datum/species/lizard/silverscale/on_species_gain(mob/living/carbon/new_silverscale, datum/species/old_species, pref_load) var/mob/living/carbon/human/silverscale = new_silverscale - old_mutcolor = new_silverscale.dna.features["mcolor"] + var/datum/color_palette/generic_colors/palette = new_silverscale.dna.color_palettes[/datum/color_palette/generic_colors] + old_mutcolor = palette.return_color(MUTANT_COLOR) old_eye_color_left = silverscale.eye_color_left old_eye_color_right = silverscale.eye_color_right - new_silverscale.dna.features["mcolor"] = "#eeeeee" + palette.mutant_color = "#eeeeee" silverscale.eye_color_left = "#0000a0" silverscale.eye_color_right = "#0000a0" ..() @@ -188,7 +167,8 @@ Lizard subspecies: SILVER SCALED /datum/species/lizard/silverscale/on_species_loss(mob/living/carbon/old_silverscale, datum/species/new_species, pref_load) var/mob/living/carbon/human/was_silverscale = old_silverscale - was_silverscale.dna.features["mcolor"] = old_mutcolor + var/datum/color_palette/generic_colors/palette = was_silverscale.dna.color_palettes[/datum/color_palette/generic_colors] + palette.mutant_color = old_mutcolor was_silverscale.eye_color_left = old_eye_color_left was_silverscale.eye_color_right = old_eye_color_right diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm index 4810b185a43f..4cf01b8a4d79 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -12,21 +12,17 @@ skinned_type = /obj/item/stack/sheet/animalhide/monkey meat = /obj/item/food/meat/slab/monkey knife_butcher_results = list(/obj/item/food/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1) - species_traits = list( - NO_UNDERWEAR, - NOBLOODOVERLAY, - NOTRANSSTING, - NOAUGMENTS, - ) inherent_traits = list( + TRAIT_NO_UNDERWEAR, + TRAIT_NO_BLOOD_OVERLAY, + TRAIT_NO_TRANSFORMATION_STING, + TRAIT_NO_AUGMENTS, TRAIT_GUN_NATURAL, TRAIT_VENTCRAWLER_NUDE, TRAIT_WEAK_SOUL, ) no_equip_flags = ITEM_SLOT_OCLOTHING | ITEM_SLOT_GLOVES | ITEM_SLOT_FEET | ITEM_SLOT_SUITSTORE changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | ERT_SPAWN | SLIME_EXTRACT - liked_food = MEAT | FRUIT | BUGS - disliked_food = CLOTH sexes = FALSE species_language_holder = /datum/language_holder/monkey @@ -130,17 +126,6 @@ return TRUE return ..() -/datum/species/monkey/get_scream_sound(mob/living/carbon/human/monkey) - return pick( - 'sound/creatures/monkey/monkey_screech_1.ogg', - 'sound/creatures/monkey/monkey_screech_2.ogg', - 'sound/creatures/monkey/monkey_screech_3.ogg', - 'sound/creatures/monkey/monkey_screech_4.ogg', - 'sound/creatures/monkey/monkey_screech_5.ogg', - 'sound/creatures/monkey/monkey_screech_6.ogg', - 'sound/creatures/monkey/monkey_screech_7.ogg', - ) - /datum/species/monkey/get_species_description() return "Monkeys are a type of primate that exist between humans and animals on the evolutionary chain. \ Every year, on Monkey Day, Nanotrasen shows their respect for the little guys by allowing them to roam the station freely." diff --git a/code/modules/mob/living/carbon/human/species_types/mothmen.dm b/code/modules/mob/living/carbon/human/species_types/mothmen.dm index 90cd1774596c..3ef1b71a6f1d 100644 --- a/code/modules/mob/living/carbon/human/species_types/mothmen.dm +++ b/code/modules/mob/living/carbon/human/species_types/mothmen.dm @@ -2,11 +2,8 @@ name = "\improper Mothman" plural_form = "Mothmen" id = SPECIES_MOTH - species_traits = list( - HAS_MARKINGS, - ) inherent_traits = list( - TRAIT_CAN_USE_FLIGHT_POTION, + TRAIT_HAS_MARKINGS, TRAIT_TACKLING_WINGED_ATTACKER, TRAIT_ANTENNAE, ) @@ -14,15 +11,11 @@ mutant_bodyparts = list("moth_markings" = "None") external_organs = list(/obj/item/organ/external/wings/moth = "Plain", /obj/item/organ/external/antennae = "Plain") meat = /obj/item/food/meat/slab/human/mutant/moth - liked_food = VEGETABLES | DAIRY | CLOTH - disliked_food = FRUIT | GROSS | BUGS | GORE - toxic_food = MEAT | RAW | SEAFOOD mutanttongue = /obj/item/organ/internal/tongue/moth mutanteyes = /obj/item/organ/internal/eyes/moth changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT species_language_holder = /datum/language_holder/moth death_sound = 'sound/voice/moth/moth_death.ogg' - wing_types = list(/obj/item/organ/external/wings/functional/moth/megamoth, /obj/item/organ/external/wings/functional/moth/mothra) family_heirlooms = list(/obj/item/flashlight/lantern/heirloom_moth) bodypart_overrides = list( @@ -69,9 +62,6 @@ human_mob.dna.features["moth_markings"] = pick(GLOB.moth_markings_list) randomize_external_organs(human_mob) -/datum/species/moth/get_scream_sound(mob/living/carbon/human/human) - return 'sound/voice/moth/scream_moth.ogg' - /datum/species/moth/get_species_description() return "Hailing from a planet that was lost long ago, the moths travel \ the galaxy as a nomadic people aboard a colossal fleet of ships, seeking a new homeland." diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm index 73c3657abae0..e5e1bf25872c 100644 --- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm @@ -8,16 +8,13 @@ fixed_mut_color = "#DBBF92" hair_color = "#FF4B19" //cap color, spot color uses eye color - species_traits = list( - MUTCOLORS, - NO_UNDERWEAR, - ) inherent_traits = list( + TRAIT_NO_UNDERWEAR, + TRAIT_MUTANT_COLORS, TRAIT_NOBREATH, TRAIT_NOFLASH, ) inherent_factions = list(FACTION_MUSHROOM) - speedmod = 1.5 //faster than golems but not by much no_equip_flags = ITEM_SLOT_MASK | ITEM_SLOT_OCLOTHING | ITEM_SLOT_GLOVES | ITEM_SLOT_FEET | ITEM_SLOT_ICLOTHING @@ -27,7 +24,6 @@ mutanttongue = /obj/item/organ/internal/tongue/mush mutanteyes = /obj/item/organ/internal/eyes/night_vision/mushroom mutantlungs = null - use_skintones = FALSE var/datum/martial_art/mushpunch/mush species_language_holder = /datum/language_holder/mushroom @@ -58,13 +54,13 @@ mush.remove(C) QDEL_NULL(mush) -/datum/species/mush/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) +/datum/species/mush/handle_chemical(datum/reagent/chem, mob/living/carbon/human/affected, seconds_per_tick, times_fired) + . = ..() + if(. & COMSIG_MOB_STOP_REAGENT_CHECK) + return if(chem.type == /datum/reagent/toxin/plantbgone/weedkiller) - H.adjustToxLoss(3 * REM * seconds_per_tick) - H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM * seconds_per_tick) - return TRUE - return ..() + affected.adjustToxLoss(3 * REM * seconds_per_tick) /datum/species/mush/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour) forced_colour = FALSE - ..() + return ..() diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index 46e772a71fcd..f956bedb2f20 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -4,24 +4,23 @@ id = SPECIES_PLASMAMAN sexes = 0 meat = /obj/item/stack/sheet/mineral/plasma - species_traits = list( - NOTRANSSTING, - ) // plasmemes get hard to wound since they only need a severe bone wound to dismember, but unlike skellies, they can't pop their bones back into place inherent_traits = list( + TRAIT_NO_TRANSFORMATION_STING, TRAIT_GENELESS, TRAIT_HARDLY_WOUNDED, TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, TRAIT_NOBLOOD, TRAIT_NO_DNA_COPY, + TRAIT_RESISTLOWPRESSURE, ) inherent_biotypes = MOB_HUMANOID|MOB_MINERAL inherent_respiration_type = RESPIRATION_PLASMA mutantlungs = /obj/item/organ/internal/lungs/plasmaman mutanttongue = /obj/item/organ/internal/tongue/bone/plasmaman - mutantliver = /obj/item/organ/internal/liver/plasmaman + mutantliver = /obj/item/organ/internal/liver/bone/plasmaman mutantstomach = /obj/item/organ/internal/stomach/bone/plasmaman mutantappendix = null mutantheart = null @@ -30,8 +29,6 @@ brutemod = 1.5 payday_modifier = 0.75 breathid = "plas" - disliked_food = FRUIT | CLOTH - liked_food = VEGETABLES changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC species_cookie = /obj/item/reagent_containers/condiment/milk outfit_important_for_life = /datum/outfit/plasmaman @@ -49,14 +46,12 @@ // Body temperature for Plasmen is much lower human as they can handle colder environments bodytemp_normal = (BODYTEMP_NORMAL - 40) // The minimum amount they stabilize per tick is reduced making hot areas harder to deal with - bodytemp_autorecovery_min = 2 + temperature_normalization_speed = /mob/living/carbon/human::temperature_normalization_speed * 0.5 // They are hurt at hot temps faster as it is harder to hold their form bodytemp_heat_damage_limit = (BODYTEMP_HEAT_DAMAGE_LIMIT - 20) // about 40C // This effects how fast body temp stabilizes, also if cold resit is lost on the mob bodytemp_cold_damage_limit = (BODYTEMP_COLD_DAMAGE_LIMIT - 50) // about -50c - ass_image = 'icons/ass/assplasma.png' - outfit_override_registry = list( /datum/outfit/syndicate = /datum/outfit/syndicate/plasmaman, /datum/outfit/syndicate/full = /datum/outfit/syndicate/full/plasmaman, @@ -72,6 +67,7 @@ C.set_safe_hunger_level() /datum/species/plasmaman/spec_life(mob/living/carbon/human/H, seconds_per_tick, times_fired) + . = ..() var/atmos_sealed = TRUE if(HAS_TRAIT(H, TRAIT_NOFIRE)) atmos_sealed = FALSE @@ -121,10 +117,18 @@ H.update_appearance(UPDATE_OVERLAYS) -/datum/species/plasmaman/handle_fire(mob/living/carbon/human/H, seconds_per_tick, times_fired, no_protection = FALSE) - if(internal_fire) - no_protection = TRUE +/datum/species/plasmaman/proc/handle_fire(mob/living/carbon/human/H, seconds_per_tick) + SIGNAL_HANDLER + + return internal_fire ? BURNING_SKIP_PROTECTION : NONE + +/datum/species/plasmaman/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) . = ..() + RegisterSignal(C, COMSIG_HUMAN_BURNING, PROC_REF(handle_fire)) + +/datum/species/plasmaman/on_species_loss(mob/living/carbon/C, datum/species/new_species, pref_save) + . = ..() + UnregisterSignal(C, COMSIG_HUMAN_BURNING) /datum/species/plasmaman/pre_equip_species_outfit(datum/job/job, mob/living/carbon/human/equipping, visuals_only = FALSE) if(job?.plasmaman_outfit) @@ -143,54 +147,6 @@ return randname -/datum/species/plasmaman/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) - . = ..() - if(istype(chem, /datum/reagent/toxin/plasma) || istype(chem, /datum/reagent/toxin/hot_ice)) - for(var/i in H.all_wounds) - var/datum/wound/iter_wound = i - iter_wound.on_xadone(4 * REM * seconds_per_tick) // plasmamen use plasma to reform their bones or whatever - return FALSE // do normal metabolism - - if(istype(chem, /datum/reagent/toxin/bonehurtingjuice)) - H.stamina.adjust(-7.5 * REM * seconds_per_tick, 0) - H.adjustBruteLoss(0.5 * REM * seconds_per_tick, 0) - if(SPT_PROB(10, seconds_per_tick)) - switch(rand(1, 3)) - if(1) - H.say(pick("oof.", "ouch.", "my bones.", "oof ouch.", "oof ouch my bones."), forced = /datum/reagent/toxin/bonehurtingjuice) - if(2) - H.manual_emote(pick("oofs silently.", "looks like [H.p_their()] bones hurt.", "grimaces, as though [H.p_their()] bones hurt.")) - if(3) - to_chat(H, span_warning("Your bones hurt!")) - if(chem.overdosed) - if(SPT_PROB(2, seconds_per_tick) && iscarbon(H)) //big oof - var/selected_part = pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) //God help you if the same limb gets picked twice quickly. - var/obj/item/bodypart/bp = H.get_bodypart(selected_part) //We're so sorry skeletons, you're so misunderstood - if(bp) - playsound(H, get_sfx(SFX_DESECRATION), 50, TRUE, -1) //You just want to socialize - H.visible_message(span_warning("[H] rattles loudly and flails around!!"), span_danger("Your bones hurt so much that your missing muscles spasm!!")) - H.say("OOF!!", forced=/datum/reagent/toxin/bonehurtingjuice) - bp.receive_damage(200, 0, 0) //But I don't think we should - else - to_chat(H, span_warning("Your missing arm aches from wherever you left it.")) - H.emote("sigh") - H.reagents.remove_reagent(chem.type, chem.metabolization_rate * seconds_per_tick) - return TRUE - - if(istype(chem, /datum/reagent/gunpowder)) - H.set_timed_status_effect(15 SECONDS * seconds_per_tick, /datum/status_effect/drugginess) - if(H.get_timed_status_effect_duration(/datum/status_effect/hallucination) / 10 < chem.volume) - H.adjust_hallucinations(2.5 SECONDS * seconds_per_tick) - // Do normal metabolism - return FALSE - -/datum/species/plasmaman/get_scream_sound(mob/living/carbon/human) - return pick( - 'sound/voice/plasmaman/plasmeme_scream_1.ogg', - 'sound/voice/plasmaman/plasmeme_scream_2.ogg', - 'sound/voice/plasmaman/plasmeme_scream_3.ogg', - ) - /datum/species/plasmaman/get_species_description() return "Found on the Icemoon of Freyja, plasmamen consist of colonial \ fungal organisms which together form a sentient being. In human space, \ diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm index c451d48110b0..1980497b6c68 100644 --- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm @@ -3,15 +3,14 @@ name = "\improper Podperson" plural_form = "Podpeople" id = SPECIES_PODPERSON - species_traits = list( - MUTCOLORS, - ) inherent_traits = list( - TRAIT_PLANT_SAFE, + TRAIT_MUTANT_COLORS, ) external_organs = list( /obj/item/organ/external/pod_hair = "None", ) + mutanttongue = /obj/item/organ/internal/tongue/pod + mutantheart = /obj/item/organ/internal/heart/pod inherent_biotypes = MOB_ORGANIC | MOB_HUMANOID | MOB_PLANT inherent_factions = list(FACTION_PLANTS, FACTION_VINES) @@ -19,9 +18,7 @@ heatmod = 1.5 payday_modifier = 0.75 meat = /obj/item/food/meat/slab/human/mutant/plant - exotic_blood = /datum/reagent/water - disliked_food = MEAT | DAIRY | SEAFOOD | BUGS - liked_food = VEGETABLES | FRUIT | GRAIN + exotic_bloodtype = /datum/blood_type/water changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT species_language_holder = /datum/language_holder/plant @@ -34,21 +31,8 @@ BODY_ZONE_CHEST = /obj/item/bodypart/chest/pod, ) - ass_image = 'icons/ass/asspodperson.png' - -/datum/species/pod/on_species_gain(mob/living/carbon/new_podperson, datum/species/old_species, pref_load) - . = ..() - if(ishuman(new_podperson)) - update_mail_goodies(new_podperson) - -/datum/species/pod/update_quirk_mail_goodies(mob/living/carbon/human/recipient, datum/quirk/quirk, list/mail_goodies = list()) - if(istype(quirk, /datum/quirk/blooddeficiency)) - mail_goodies += list( - /obj/item/reagent_containers/blood/podperson - ) - return ..() - /datum/species/pod/spec_life(mob/living/carbon/human/H, seconds_per_tick, times_fired) + . = ..() if(H.stat == DEAD) return @@ -69,7 +53,7 @@ H.take_overall_damage(brute = 1 * seconds_per_tick, required_bodytype = BODYTYPE_ORGANIC) ..() -/datum/species/pod/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) +/datum/species/pod/handle_chemical(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) if(chem.type == /datum/reagent/toxin/plantbgone) H.adjustToxLoss(3 * REM * seconds_per_tick) H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM * seconds_per_tick) diff --git a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm index e7f1d9658e2f..d0ea71dac837 100644 --- a/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm +++ b/code/modules/mob/living/carbon/human/species_types/shadowpeople.dm @@ -5,7 +5,6 @@ id = SPECIES_SHADOW sexes = 0 meat = /obj/item/food/meat/slab/human/mutant/shadow - species_traits = list() inherent_traits = list( TRAIT_NOBREATH, TRAIT_RADIMMUNE, diff --git a/code/modules/mob/living/carbon/human/species_types/skeletons.dm b/code/modules/mob/living/carbon/human/species_types/skeletons.dm index 1c294c2579ff..50b94040c814 100644 --- a/code/modules/mob/living/carbon/human/species_types/skeletons.dm +++ b/code/modules/mob/living/carbon/human/species_types/skeletons.dm @@ -4,21 +4,17 @@ id = SPECIES_SKELETON sexes = 0 meat = /obj/item/food/meat/slab/human/mutant/skeleton - species_traits = list( - NOTRANSSTING, - NO_DNA_COPY, - NO_UNDERWEAR, - NOHUSK, - ) inherent_traits = list( - TRAIT_CAN_USE_FLIGHT_POTION, + TRAIT_NO_HUSK, + TRAIT_NO_TRANSFORMATION_STING, + TRAIT_NO_UNDERWEAR, + TRAIT_NO_DNA_COPY, TRAIT_EASYDISMEMBER, TRAIT_FAKEDEATH, TRAIT_GENELESS, - TRAIT_LIMBATTACHMENT, TRAIT_NOBREATH, TRAIT_NOCLONELOSS, - TRAIT_NOMETABOLISM, + TRAIT_LIVERLESS_METABOLISM, TRAIT_RADIMMUNE, TRAIT_PIERCEIMMUNE, TRAIT_RESISTCOLD, @@ -34,11 +30,8 @@ mutantstomach = /obj/item/organ/internal/stomach/bone mutantappendix = null mutantheart = null - mutantliver = null + mutantliver = /obj/item/organ/internal/liver/bone mutantlungs = null - disliked_food = NONE - liked_food = GROSS | MEAT | RAW | GORE - wing_types = list(/obj/item/organ/external/wings/functional/skeleton) //They can technically be in an ERT changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN species_cookie = /obj/item/reagent_containers/condiment/milk @@ -62,35 +55,6 @@ return TRUE return ..() -//Can still metabolize milk through meme magic -/datum/species/skeleton/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) - . = ..() - if(chem.type == /datum/reagent/toxin/bonehurtingjuice) - H.stamina.adjust(-7.5 * REM * seconds_per_tick, 0) - H.adjustBruteLoss(0.5 * REM * seconds_per_tick, 0) - if(SPT_PROB(10, seconds_per_tick)) - switch(rand(1, 3)) - if(1) - H.say(pick("oof.", "ouch.", "my bones.", "oof ouch.", "oof ouch my bones."), forced = /datum/reagent/toxin/bonehurtingjuice) - if(2) - H.manual_emote(pick("oofs silently.", "looks like [H.p_their()] bones hurt.", "grimaces, as though [H.p_their()] bones hurt.")) - if(3) - to_chat(H, span_warning("Your bones hurt!")) - if(chem.overdosed) - if(SPT_PROB(2, seconds_per_tick) && iscarbon(H)) //big oof - var/selected_part = pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) //God help you if the same limb gets picked twice quickly. - var/obj/item/bodypart/bp = H.get_bodypart(selected_part) //We're so sorry skeletons, you're so misunderstood - if(bp) - playsound(H, get_sfx(SFX_DESECRATION), 50, TRUE, -1) //You just want to socialize - H.visible_message(span_warning("[H] rattles loudly and flails around!!"), span_danger("Your bones hurt so much that your missing muscles spasm!!")) - H.say("OOF!!", forced=/datum/reagent/toxin/bonehurtingjuice) - bp.receive_damage(200, 0, 0) //But I don't think we should - else - to_chat(H, span_warning("Your missing arm aches from wherever you left it.")) - H.emote("sigh") - H.reagents.remove_reagent(chem.type, chem.metabolization_rate * seconds_per_tick) - return TRUE - /datum/species/skeleton/get_species_description() return "A rattling skeleton! They descend upon Space Station 13 \ Every year to spook the crew! \"I've got a BONE to pick with you!\"" diff --git a/code/modules/mob/living/carbon/human/species_types/snail.dm b/code/modules/mob/living/carbon/human/species_types/snail.dm index 6dc24addcf86..aa0e4d282bf6 100644 --- a/code/modules/mob/living/carbon/human/species_types/snail.dm +++ b/code/modules/mob/living/carbon/human/species_types/snail.dm @@ -1,24 +1,21 @@ /datum/species/snail name = "Snailperson" id = SPECIES_SNAIL - species_traits = list( - MUTCOLORS, - NO_UNDERWEAR, - ) inherent_traits = list( + TRAIT_MUTANT_COLORS, + TRAIT_NO_UNDERWEAR, TRAIT_NO_SLIP_ALL, ) coldmod = 0.5 //snails only come out when its cold and wet burnmod = 2 - speedmod = 6 siemens_coeff = 2 //snails are mostly water changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | RACE_SWAP sexes = FALSE //snails are hermaphrodites mutanteyes = /obj/item/organ/internal/eyes/snail mutanttongue = /obj/item/organ/internal/tongue/snail - exotic_blood = /datum/reagent/lube + exotic_bloodtype = /datum/blood_type/snail bodypart_overrides = list( BODY_ZONE_HEAD = /obj/item/bodypart/head/snail, @@ -29,13 +26,15 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/snail ) -/datum/species/snail/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) +/datum/species/snail/handle_chemical(datum/reagent/chem, mob/living/carbon/human/affected, seconds_per_tick, times_fired) . = ..() + if(. & COMSIG_MOB_STOP_REAGENT_CHECK) + return if(istype(chem,/datum/reagent/consumable/salt)) - H.adjustFireLoss(2 * REM * seconds_per_tick) - playsound(H, 'sound/weapons/sear.ogg', 30, TRUE) - H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM * seconds_per_tick) - return TRUE + //playsound(affected, SFX_SEAR, 30, TRUE) + affected.adjustFireLoss(2 * REM * seconds_per_tick) + affected.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM * seconds_per_tick) + return COMSIG_MOB_STOP_REAGENT_CHECK /datum/species/snail/on_species_gain(mob/living/carbon/new_snailperson, datum/species/old_species, pref_load) . = ..() @@ -44,8 +43,6 @@ if(new_snailperson.dropItemToGround(bag)) //returns TRUE even if its null new_snailperson.equip_to_slot_or_del(new /obj/item/storage/backpack/snail(new_snailperson), ITEM_SLOT_BACK) new_snailperson.AddElement(/datum/element/snailcrawl) - if(ishuman(new_snailperson)) - update_mail_goodies(new_snailperson) /datum/species/snail/on_species_loss(mob/living/carbon/former_snailperson, datum/species/new_species, pref_load) . = ..() @@ -56,13 +53,6 @@ former_snailperson.temporarilyRemoveItemFromInventory(bag, TRUE) qdel(bag) -/datum/species/snail/update_quirk_mail_goodies(mob/living/carbon/human/recipient, datum/quirk/quirk, list/mail_goodies = list()) - if(istype(quirk, /datum/quirk/blooddeficiency)) - mail_goodies += list( - /obj/item/reagent_containers/blood/snail - ) - return ..() - /obj/item/storage/backpack/snail name = "snail shell" desc = "Worn by snails as armor and storage compartment." diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm index 72f06a970033..02fde964482e 100644 --- a/code/modules/mob/living/carbon/human/species_types/vampire.dm +++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm @@ -7,22 +7,19 @@ /datum/species/vampire name = "Vampire" id = SPECIES_VAMPIRE - species_traits = list( - DRINKSBLOOD, - BLOOD_CLANS, - ) inherent_traits = list( + TRAIT_DRINKS_BLOOD, + TRAIT_BLOOD_CLANS, TRAIT_NOBREATH, TRAIT_NOHUNGER, TRAIT_NO_MIRROR_REFLECTION, - /*TRAIT_USES_SKINTONES,*/ //monkestation temp removal, we dont have this refactor yet + TRAIT_USES_SKINTONES ) inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID mutant_bodyparts = list("wings" = "None") changesource_flags = MIRROR_BADMIN | WABBAJACK | ERT_SPAWN - exotic_bloodtype = "U" + exotic_bloodtype = /datum/blood_type/universal blood_deficiency_drain_rate = BLOOD_DEFICIENCY_MODIFIER // vampires already passively lose blood, so this just makes them lose it slightly more quickly when they have blood deficiency. - use_skintones = TRUE mutantheart = /obj/item/organ/internal/heart/vampire mutanttongue = /obj/item/organ/internal/tongue/vampire mutantstomach = null @@ -165,8 +162,8 @@ if(victim.stat == DEAD) to_chat(H, span_warning("You need a living victim!")) return - if(!victim.blood_volume || (victim.dna && (HAS_TRAIT(victim, TRAIT_NOBLOOD) || victim.dna.species.exotic_blood))) - to_chat(H, span_warning("[victim] doesn't have blood!")) + if(!istype(victim.get_blood_type(), /datum/blood_type/crew/human)) + to_chat(H, span_warning("[victim] doesn't have valid blood!")) return COOLDOWN_START(V, drain_cooldown, 3 SECONDS) if(victim.can_block_magic(MAGIC_RESISTANCE_HOLY, charge_cost = 0)) @@ -186,7 +183,7 @@ playsound(H, 'sound/items/drink.ogg', 30, TRUE, -2) victim.blood_volume = clamp(victim.blood_volume - drained_blood, 0, BLOOD_VOLUME_MAXIMUM) H.blood_volume = clamp(H.blood_volume + drained_blood, 0, BLOOD_VOLUME_MAXIMUM) - if(!victim.blood_volume) + if(victim.blood_volume <= 0) to_chat(H, span_notice("You finish off [victim]'s blood supply.")) /obj/item/organ/internal/heart/vampire diff --git a/code/modules/mob/living/carbon/human/species_types/zombies.dm b/code/modules/mob/living/carbon/human/species_types/zombies.dm index 11edef65e73b..26b7f81597ec 100644 --- a/code/modules/mob/living/carbon/human/species_types/zombies.dm +++ b/code/modules/mob/living/carbon/human/species_types/zombies.dm @@ -4,24 +4,21 @@ // 1spooky name = "High-Functioning Zombie" id = SPECIES_ZOMBIE - sexes = 0 + sexes = FALSE meat = /obj/item/food/meat/slab/human/mutant/zombie mutanttongue = /obj/item/organ/internal/tongue/zombie - species_traits = list( - NOZOMBIE, - NOTRANSSTING, - ) inherent_traits = list( // SHARED WITH ALL ZOMBIES + TRAIT_NO_ZOMBIFY, + TRAIT_NO_TRANSFORMATION_STING, TRAIT_EASILY_WOUNDED, TRAIT_EASYDISMEMBER, TRAIT_FAKEDEATH, - TRAIT_LIMBATTACHMENT, TRAIT_NOBREATH, TRAIT_NOCLONELOSS, TRAIT_NODEATH, TRAIT_NOHUNGER, - TRAIT_NOMETABOLISM, + TRAIT_LIVERLESS_METABOLISM, TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, @@ -38,26 +35,21 @@ mutantlungs = null inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID var/static/list/spooks = list('sound/hallucinations/growl1.ogg','sound/hallucinations/growl2.ogg','sound/hallucinations/growl3.ogg','sound/hallucinations/veryfar_noise.ogg','sound/hallucinations/wail.ogg') - disliked_food = NONE - liked_food = GROSS | MEAT | RAW | GORE changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | ERT_SPAWN bodytemp_normal = T0C // They have no natural body heat, the environment regulates body temp bodytemp_heat_damage_limit = FIRE_MINIMUM_TEMPERATURE_TO_EXIST // Take damage at fire temp bodytemp_cold_damage_limit = MINIMUM_TEMPERATURE_TO_MOVE // take damage below minimum movement temp + // Infectious zombies have slow legs bodypart_overrides = list( BODY_ZONE_HEAD = /obj/item/bodypart/head/zombie, BODY_ZONE_CHEST = /obj/item/bodypart/chest/zombie, BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/zombie, BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/zombie, BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/zombie, - BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/zombie + BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/zombie, ) -/// Zombies do not stabilize body temperature they are the walking dead and are cold blooded -/datum/species/zombie/body_temperature_core(mob/living/carbon/human/humi, seconds_per_tick, times_fired) - return - /datum/species/zombie/check_roundstart_eligible() if(check_holidays(HALLOWEEN)) return TRUE @@ -87,7 +79,6 @@ id = SPECIES_ZOMBIE_INFECTIOUS examine_limb_id = SPECIES_ZOMBIE armor = 20 // 120 damage to KO a zombie, which kills it - speedmod = 1.6 mutanteyes = /obj/item/organ/internal/eyes/zombie mutantbrain = /obj/item/organ/internal/brain/zombie mutanttongue = /obj/item/organ/internal/tongue/zombie @@ -102,12 +93,11 @@ TRAIT_EASILY_WOUNDED, TRAIT_EASYDISMEMBER, TRAIT_FAKEDEATH, - TRAIT_LIMBATTACHMENT, TRAIT_NOBREATH, TRAIT_NOCLONELOSS, TRAIT_NODEATH, TRAIT_NOHUNGER, - TRAIT_NOMETABOLISM, + TRAIT_LIVERLESS_METABOLISM, TRAIT_RADIMMUNE, TRAIT_RESISTCOLD, TRAIT_RESISTHIGHPRESSURE, @@ -118,6 +108,15 @@ TRAIT_STABLEHEART, // Replacement for noblood. Infectious zombies can bleed but don't need their heart. TRAIT_STABLELIVER, // Not necessary but for consistency with above ) + bodypart_overrides = list( + BODY_ZONE_HEAD = /obj/item/bodypart/head/zombie, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/zombie, + BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/zombie, + BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/zombie, + BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/zombie/infectious, + BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/zombie/infectious, + ) + /datum/species/zombie/infectious/on_species_gain(mob/living/carbon/C, datum/species/old_species) . = ..() diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm index acbb3c528c6f..238e434a2a85 100644 --- a/code/modules/mob/living/carbon/human/status_procs.dm +++ b/code/modules/mob/living/carbon/human/status_procs.dm @@ -32,7 +32,7 @@ update_body_parts() /mob/living/carbon/human/become_husk(source) - if(NOHUSK in dna.species.species_traits) //skeletons shouldn't be husks. + if(HAS_TRAIT(src, TRAIT_NO_HUSK)) //skeletons shouldn't be husks. cure_husk() return . = ..() diff --git a/code/modules/mob/living/carbon/init_signals.dm b/code/modules/mob/living/carbon/init_signals.dm index e3cc487eeb7d..79c54fed41a0 100644 --- a/code/modules/mob/living/carbon/init_signals.dm +++ b/code/modules/mob/living/carbon/init_signals.dm @@ -1,9 +1,12 @@ //Called on /mob/living/carbon/Initialize(mapload), for the carbon mobs to register relevant signals. /mob/living/carbon/register_init_signals() . = ..() + //Traits that register add and remove + RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_AGENDER), PROC_REF(on_agender_trait_gain)) + RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_AGENDER), PROC_REF(on_agender_trait_loss)) RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_NOBREATH), PROC_REF(on_nobreath_trait_gain)) - RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_NOMETABOLISM), PROC_REF(on_nometabolism_trait_gain)) + RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_LIVERLESS_METABOLISM), PROC_REF(on_liverless_metabolism_trait_gain)) RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_VIRUSIMMUNE), PROC_REF(on_virusimmune_trait_gain)) RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_TOXIMMUNE), PROC_REF(on_toximmune_trait_gain)) RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_GENELESS), PROC_REF(on_geneless_trait_gain)) @@ -64,11 +67,11 @@ clear_mood_event("smell") clear_mood_event("suffocation") /** - * On gain of TRAIT_NOMETABOLISM + * On gain of TRAIT_LIVERLESS_METABOLISM * * This will clear all moods related to addictions and stop metabolization. */ -/mob/living/carbon/proc/on_nometabolism_trait_gain(datum/source) +/mob/living/carbon/proc/on_liverless_metabolism_trait_gain(datum/source) SIGNAL_HANDLER for(var/addiction_type in subtypesof(/datum/addiction)) mind?.remove_addiction_points(addiction_type, MAX_ADDICTION_POINTS) //Remove the addiction! diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm index 3e462fc976f2..a552c8a07974 100644 --- a/code/modules/mob/living/carbon/inventory.dm +++ b/code/modules/mob/living/carbon/inventory.dm @@ -365,7 +365,7 @@ * * This handles creating an alert and adding an overlay to it */ -/mob/living/carbon/proc/give(mob/living/carbon/offered) +/mob/living/proc/give(mob/living/offered) if(has_status_effect(/datum/status_effect/offering)) to_chat(src, span_warning("You're already offering something!")) return @@ -400,7 +400,7 @@ to_chat(src, span_warning("You have to be beside [offered.p_them()]!")) return else - if(!(locate(/mob/living/carbon) in orange(1, src))) + if(!(locate(/mob/living) in orange(1, src))) to_chat(src, span_warning("There's nobody beside you to take it!")) return @@ -421,7 +421,7 @@ * * offerer - The person giving the original item * * I - The item being given by the offerer */ -/mob/living/carbon/proc/take(mob/living/carbon/offerer, obj/item/I) +/mob/living/proc/take(mob/living/carbon/offerer, obj/item/I, visible_message = TRUE) clear_alert("[offerer]") if(IS_DEAD_OR_INCAP(src)) to_chat(src, span_warning("You're unable to take anything in your current state!")) @@ -443,9 +443,13 @@ visible_message(span_notice("[offerer] tries to hand over [I] but it's stuck to them....")) return - visible_message(span_notice("[src] takes [I] from [offerer]."), \ - span_notice("You take [I] from [offerer].")) + if(visible_message) + visible_message(span_notice("[src] takes [I] from [offerer]."), \ + span_notice("You take [I] from [offerer].")) + else + to_chat(src, span_notice("You take [I] from [offerer].")) put_in_hands(I) + return TRUE ///Returns a list of all body_zones covered by clothing /mob/living/carbon/proc/get_covered_body_zones() diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 93f4391e3b34..e5f43d825981 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -53,109 +53,84 @@ // Start of a breath chain, calls [carbon/proc/breathe()] /mob/living/carbon/handle_breathing(seconds_per_tick, times_fired) + if(HAS_TRAIT(src, TRAIT_NOBREATH)) + return + var/next_breath = 4 - var/obj/item/organ/internal/lungs/L = get_organ_slot(ORGAN_SLOT_LUNGS) - var/obj/item/organ/internal/heart/H = get_organ_slot(ORGAN_SLOT_HEART) - if(L) - if(L.damage > L.high_threshold) - next_breath-- - if(H) - if(H.damage > H.high_threshold) - next_breath-- + var/obj/item/organ/internal/lungs/lungs = get_organ_slot(ORGAN_SLOT_LUNGS) + var/obj/item/organ/internal/heart/heart = get_organ_slot(ORGAN_SLOT_HEART) + if(lungs?.damage > lungs?.high_threshold) + next_breath -= 1 + if(heart?.damage > heart?.high_threshold) + next_breath -= 1 if((times_fired % next_breath) == 0 || failed_last_breath) - breathe(seconds_per_tick, times_fired) //Breathe per 4 ticks if healthy, down to 2 if our lungs or heart are damaged, unless suffocating + // Breathe per 4 ticks if healthy, down to 2 if our lungs or heart are damaged, unless suffocating + breathe(seconds_per_tick, times_fired, failed_last_breath ? 1 : next_breath) if(failed_last_breath) add_mood_event("suffocation", /datum/mood_event/suffocation) else clear_mood_event("suffocation") - else - if(isobj(loc)) - var/obj/location_as_object = loc - location_as_object.handle_internal_lifeform(src,0) - -// Second link in a breath chain, calls [carbon/proc/check_breath()] -/mob/living/carbon/proc/breathe(seconds_per_tick, times_fired) - var/obj/item/organ/internal/lungs = get_organ_slot(ORGAN_SLOT_LUNGS) - if(SEND_SIGNAL(src, COMSIG_CARBON_ATTEMPT_BREATHE) & COMSIG_CARBON_BLOCK_BREATH) - return + else if(isobj(loc)) + var/obj/location_as_object = loc + location_as_object.handle_internal_lifeform(src, 0) - SEND_SIGNAL(src, COMSIG_CARBON_PRE_BREATHE) +/mob/living/carbon/proc/breathe(seconds_per_tick, times_fired, next_breath = 4) + var/datum/gas_mixture/environment = loc?.return_air() + var/datum/gas_mixture/breath - var/datum/gas_mixture/environment - if(loc) - environment = loc.return_air() + if(!HAS_TRAIT(src, TRAIT_ASSISTED_BREATHING)) + if(stat == HARD_CRIT) + losebreath = max(losebreath, 1) + else if(HAS_TRAIT(src, TRAIT_LABOURED_BREATHING)) + losebreath += (1 / next_breath) - var/datum/gas_mixture/breath - if(!get_organ_slot(ORGAN_SLOT_BREATHING_TUBE)) - if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby?.grab_state >= GRAB_KILL) || (lungs?.organ_flags & ORGAN_FAILING)) - losebreath++ //You can't breath at all when in critical or when being choked, so you're going to miss a breath + if(losebreath < 1) + var/pre_sig_return = SEND_SIGNAL(src, COMSIG_CARBON_ATTEMPT_BREATHE, seconds_per_tick, times_fired) + if(pre_sig_return & BREATHE_BLOCK_BREATH) + return - else if(health <= crit_threshold) - losebreath += 0.25 //You're having trouble breathing in soft crit, so you'll miss a breath one in four times + if(pre_sig_return & BREATHE_SKIP_BREATH) + losebreath = max(losebreath, 1) - //Suffocate - if(losebreath >= 1) //You've missed a breath, take oxy damage - losebreath-- + // Suffocate + var/skip_breath = FALSE + if(losebreath >= 1) + losebreath -= 1 if(prob(10)) emote("gasp") if(isobj(loc)) var/obj/loc_as_obj = loc - loc_as_obj.handle_internal_lifeform(src,0) - else - //Breathe from internal + loc_as_obj.handle_internal_lifeform(src, 0) + skip_breath = TRUE + + // Breathe from internals or externals (name is misleading) + else if(internal || external) breath = get_breath_from_internal(BREATH_VOLUME) - if(isnull(breath)) //in case of 0 pressure internals - - if(isobj(loc)) //Breathe from loc as object - var/obj/loc_as_obj = loc - breath = loc_as_obj.handle_internal_lifeform(src, BREATH_VOLUME) - else if(isturf(loc)) //Breathe from loc as turf - breath_airborne_diseases() //monkestation edit - VIROLOGY - var/turf/our_turf = loc - if(our_turf.liquids && !HAS_TRAIT(src, TRAIT_NOBREATH) && ((body_position == LYING_DOWN && our_turf.liquids.liquid_state >= LIQUID_STATE_WAIST) || (body_position == STANDING_UP && our_turf.liquids.liquid_state >= LIQUID_STATE_FULLTILE))) - //Officially trying to breathe underwater - if(HAS_TRAIT(src, TRAIT_WATER_BREATHING)) - failed_last_breath = FALSE - clear_alert("not_enough_oxy") - return FALSE - adjustOxyLoss(3) - failed_last_breath = TRUE - if(oxyloss <= OXYGEN_DAMAGE_CHOKING_THRESHOLD && stat == CONSCIOUS) - to_chat(src, span_userdanger("You hold in your breath!")) - else - //Try and drink water - our_turf.liquids.liquid_group.transfer_to_atom(src, CHOKE_REAGENTS_INGEST_ON_BREATH_AMOUNT) - visible_message(span_warning("[src] chokes on water!"), span_userdanger("You're choking on water!")) - return FALSE - if(isopenturf(our_turf)) - var/turf/open/open_turf = our_turf - if(open_turf.pollution) - if(next_smell <= world.time) - next_smell = world.time + SMELL_COOLDOWN - open_turf.pollution.smell_act(src) - open_turf.pollution.breathe_act(src) - - var/breath_moles = 0 - if(environment) - breath_moles = environment.total_moles() * BREATH_PERCENTAGE - - breath = loc.remove_air(breath_moles) - else //Breathe from loc as obj again - if(isobj(loc)) - var/obj/loc_as_obj = loc - loc_as_obj.handle_internal_lifeform(src,0) - - check_breath(breath) + if(breath == SKIP_INTERNALS) //in case of 0 pressure internals + breath = get_breath_from_surroundings(environment, BREATH_VOLUME) + + else if(isobj(loc)) //Breathe from loc as obj again + var/obj/loc_as_obj = loc + loc_as_obj.handle_internal_lifeform(src, 0) + + // Breathe from air + else + breath = get_breath_from_surroundings(environment, BREATH_VOLUME) + + check_breath(breath, skip_breath) if(breath) - loc.assume_air(breath) + exhale_breath(breath) + +/mob/living/carbon/proc/exhale_breath(datum/gas_mixture/breath) + if(SEND_SIGNAL(src, COMSIG_CARBON_BREATH_EXHALE, breath) & BREATHE_EXHALE_HANDLED) + return + loc.assume_air(breath) /mob/living/carbon/proc/has_smoke_protection() - if(HAS_TRAIT(src, TRAIT_NOBREATH)) - return TRUE - return FALSE + return HAS_TRAIT(src, TRAIT_NOBREATH) /** * This proc tests if the lungs can breathe, if the mob can breathe a given gas mixture, and throws/clears gas alerts. @@ -166,276 +141,11 @@ * * Arguments: * * breath: A gas mixture to test, or null. + * * skip_breath: Used to differentiate between a failed breath and a lack of breath. + * A mob suffocating due to being in a vacuum may be treated differently than a mob suffocating due to lung failure. */ -/mob/living/carbon/proc/check_breath(datum/gas_mixture/breath) - . = TRUE - - if(status_flags & GODMODE) - failed_last_breath = FALSE - clear_alert(ALERT_NOT_ENOUGH_OXYGEN) - return - - if(HAS_TRAIT(src, TRAIT_NOBREATH)) - return - - // Breath may be null, so use a fallback "empty breath" for convenience. - if(!breath) - /// Fallback "empty breath" for convenience. - var/static/datum/gas_mixture/immutable/empty_breath = new(BREATH_VOLUME) - breath = empty_breath - - // Ensure gas volumes are present. - breath.assert_gases(/datum/gas/bz, /datum/gas/carbon_dioxide, /datum/gas/freon, /datum/gas/plasma, /datum/gas/pluoxium, /datum/gas/miasma, /datum/gas/nitrous_oxide, /datum/gas/nitrium, /datum/gas/oxygen) - - /// The list of gases in the breath. - var/list/breath_gases = breath.gases - /// Indicates if there are moles of gas in the breath. - var/has_moles = breath.total_moles() != 0 - - var/obj/item/organ/internal/lungs = get_organ_slot(ORGAN_SLOT_LUNGS) - // Indicates if lungs can breathe without gas. - var/can_breathe_vacuum = FALSE - if(lungs) - // Breathing with lungs. - // Check for vacuum-adapted lungs. - can_breathe_vacuum = HAS_TRAIT(lungs, TRAIT_SPACEBREATHING) - else - // Lungs are missing! Can't breathe. - // Simulates breathing zero moles of gas. - has_moles = FALSE - // Extra damage, let God sort ’em out! - adjustOxyLoss(2) - - /// Minimum O2 before suffocation. - var/safe_oxygen_min = 16 - /// Maximum CO2 before side-effects. - var/safe_co2_max = 10 - /// Maximum Plasma before side-effects. - var/safe_plas_max = 0.05 - /// Maximum Pluoxum before side-effects. - var/gas_stimulation_min = 0.002 // For Pluoxium - // Vars for N2O induced euphoria, stun, and sleep. - var/n2o_euphoria = EUPHORIA_LAST_FLAG - var/n2o_para_min = 1 - var/n2o_sleep_min = 5 - - // Partial pressures in our breath - // Main gases. - var/pluoxium_pp = 0 - var/o2_pp = 0 - var/plasma_pp = 0 - var/co2_pp = 0 - // Trace gases ordered alphabetically. - var/bz_pp = 0 - var/freon_pp = 0 - var/n2o_pp = 0 - var/nitrium_pp = 0 - var/miasma_pp = 0 - - // Check for moles of gas and handle partial pressures / special conditions. - if(has_moles) - // Breath has more than 0 moles of gas. - // Partial pressures of "main gases". - pluoxium_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/pluoxium][MOLES]) - o2_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/oxygen][MOLES] + (8 * pluoxium_pp)) - plasma_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/plasma][MOLES]) - co2_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/carbon_dioxide][MOLES]) - // Partial pressures of "trace" gases. - bz_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/bz][MOLES]) - freon_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/freon][MOLES]) - miasma_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/miasma][MOLES]) - n2o_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/nitrous_oxide][MOLES]) - nitrium_pp = breath.get_breath_partial_pressure(breath_gases[/datum/gas/nitrium][MOLES]) - - // Breath has 0 moles of gas. - else if(can_breathe_vacuum) - // The mob can breathe anyways. What are you? Some bottom-feeding, scum-sucking algae eater? - failed_last_breath = FALSE - // Vacuum-adapted lungs regenerate oxyloss even when breathing nothing. - if(health >= crit_threshold) - adjustOxyLoss(-5) - else - // Can't breathe! Lungs are missing, and/or breath is empty. - . = FALSE - failed_last_breath = TRUE - - //-- PLUOXIUM --// - // Behaves like Oxygen with 8X efficacy, but metabolizes into a reagent. - if(pluoxium_pp) - // Inhale Pluoxium. Exhale nothing. - breath_gases[/datum/gas/pluoxium][MOLES] = 0 - // Metabolize to reagent. - if(pluoxium_pp > gas_stimulation_min) - var/existing = reagents.get_reagent_amount(/datum/reagent/pluoxium) - reagents.add_reagent(/datum/reagent/pluoxium, max(0, 1 - existing)) - - //-- OXYGEN --// - // Carbons need only Oxygen to breathe properly. - var/oxygen_used = 0 - // Minimum Oxygen effects. "Too little oxygen!" - if(!can_breathe_vacuum && (o2_pp < safe_oxygen_min)) - // Breathe insufficient amount of O2. - oxygen_used = handle_suffocation(o2_pp, safe_oxygen_min, breath_gases[/datum/gas/oxygen][MOLES]) - throw_alert(ALERT_NOT_ENOUGH_OXYGEN, /atom/movable/screen/alert/not_enough_oxy) - else - // Enough oxygen to breathe. - failed_last_breath = FALSE - clear_alert(ALERT_NOT_ENOUGH_OXYGEN) - if(o2_pp) - // Inhale O2. - oxygen_used = breath_gases[/datum/gas/oxygen][MOLES] - // Heal mob if not in crit. - if(health >= crit_threshold) - adjustOxyLoss(-5) - // Exhale equivalent amount of CO2. - if(o2_pp) - breath_gases[/datum/gas/oxygen][MOLES] -= oxygen_used - breath_gases[/datum/gas/carbon_dioxide][MOLES] += oxygen_used - - //-- CARBON DIOXIDE --// - // Maximum CO2 effects. "Too much CO2!" - if(co2_pp > safe_co2_max) - // CO2 side-effects. - // Give the mob a chance to notice. - if(prob(20)) - emote("cough") - // If it's the first breath with too much CO2 in it, lets start a counter, then have them pass out after 12s or so. - if(!co2overloadtime) - co2overloadtime = world.time - else if((world.time - co2overloadtime) > 12 SECONDS) - throw_alert(ALERT_TOO_MUCH_CO2, /atom/movable/screen/alert/too_much_co2) - Unconscious(6 SECONDS) - // Lets hurt em a little, let them know we mean business. - adjustOxyLoss(3) - // They've been in here 30s now, start to kill them for their own good! - if((world.time - co2overloadtime) > 30 SECONDS) - adjustOxyLoss(8) - else - // Reset side-effects. - co2overloadtime = 0 - clear_alert(ALERT_TOO_MUCH_CO2) - - //-- PLASMA --// - // Maximum Plasma effects. "Too much Plasma!" - if(plasma_pp > safe_plas_max) - // Plasma side-effects. - var/ratio = (breath_gases[/datum/gas/plasma][MOLES] / safe_plas_max) * 10 - adjustToxLoss(clamp(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE)) - throw_alert(ALERT_TOO_MUCH_PLASMA, /atom/movable/screen/alert/too_much_plas) - else - // Reset side-effects. - clear_alert(ALERT_TOO_MUCH_PLASMA) - - //-- TRACES --// - // If there's some other funk in the air lets deal with it here. - - //-- BZ --// - // (Facepunch port of their Agent B) - if(bz_pp) - if(bz_pp > 1) - adjust_hallucinations(20 SECONDS) - else if(bz_pp > 0.01) - adjust_hallucinations(10 SECONDS) - - //-- FREON --// - if(freon_pp) - adjustFireLoss(freon_pp * 0.25) - - //-- MIASMA --// - if(!miasma_pp) - // Clear moodlet if no miasma at all. - clear_mood_event("smell") - else - // Miasma sickness - if(prob(1 * miasma_pp)) - var/virus_choice = pick(subtypesof(/datum/disease/advanced)- typesof(/datum/disease/advanced/premade)) - var/list/anti = list( - ANTIGEN_BLOOD = 1, - ANTIGEN_COMMON = 1, - ANTIGEN_RARE = 2, - ANTIGEN_ALIEN = 0, - ) - var/list/bad = list( - EFFECT_DANGER_HELPFUL = 0, - EFFECT_DANGER_FLAVOR = 1, - EFFECT_DANGER_ANNOYING = 2, - EFFECT_DANGER_HINDRANCE = 3, - EFFECT_DANGER_HARMFUL = 1, - EFFECT_DANGER_DEADLY = 0, - ) - var/datum/disease/advanced/new_disease = new virus_choice - new_disease.makerandom(list(50,90),list(50,100),anti,bad,src) - new_disease.carrier = TRUE - new_disease = new_disease.name - infect_disease(new_disease, TRUE, "Miasma Disease Infection [key_name(src)]") - // Miasma side-effects. - switch(miasma_pp) - if(0.25 to 5) - // At lower pp, give out a little warning - clear_mood_event("smell") - if(prob(5)) - to_chat(src, span_notice("There is an unpleasant smell in the air.")) - if(5 to 20) - //At somewhat higher pp, warning becomes more obvious - if(prob(15)) - to_chat(src, span_warning("You smell something horribly decayed inside this room.")) - add_mood_event("smell", /datum/mood_event/disgust/bad_smell) - if(15 to 30) - //Small chance to vomit. By now, people have internals on anyway - if(prob(5)) - to_chat(src, span_warning("The stench of rotting carcasses is unbearable!")) - add_mood_event("smell", /datum/mood_event/disgust/nauseating_stench) - vomit() - if(30 to INFINITY) - //Higher chance to vomit. Let the horror start - if(prob(25)) - to_chat(src, span_warning("The stench of rotting carcasses is unbearable!")) - add_mood_event("smell", /datum/mood_event/disgust/nauseating_stench) - vomit() - else - clear_mood_event("smell") - - //-- NITROUS OXIDE --// - if(n2o_pp > n2o_para_min) - // More N2O, more severe side-effects. Causes stun/sleep. - n2o_euphoria = EUPHORIA_ACTIVE - throw_alert(ALERT_TOO_MUCH_N2O, /atom/movable/screen/alert/too_much_n2o) - // give them one second of grace to wake up and run away a bit! - if(!HAS_TRAIT(src, TRAIT_SLEEPIMMUNE)) - Unconscious(6 SECONDS) - // Enough to make the mob sleep. - if(n2o_pp > n2o_sleep_min) - Sleeping(max(AmountSleeping() + 40, 200)) - else if(n2o_pp > 0.01) - // No alert for small amounts, but the mob randomly feels euphoric. - if(prob(20)) - n2o_euphoria = EUPHORIA_ACTIVE - emote(pick("giggle","laugh")) - else - n2o_euphoria = EUPHORIA_INACTIVE - else - // Reset side-effects, for zero or extremely small amounts of N2O. - n2o_euphoria = EUPHORIA_INACTIVE - clear_alert(ALERT_TOO_MUCH_N2O) - - //-- NITRIUM --// - if(nitrium_pp) - if(nitrium_pp > 0.5) - adjustFireLoss(nitrium_pp * 0.15) - if(nitrium_pp > 5) - adjustToxLoss(nitrium_pp * 0.05) - - // Handle chemical euphoria mood event, caused by N2O. - if (n2o_euphoria == EUPHORIA_ACTIVE) - add_mood_event("chemical_euphoria", /datum/mood_event/chemical_euphoria) - else if (n2o_euphoria == EUPHORIA_INACTIVE) - clear_mood_event("chemical_euphoria") - // Activate mood on first flag, remove on second, do nothing on third. - - if(has_moles) - handle_breath_temperature(breath) - - breath.garbage_collect() +/mob/living/carbon/proc/check_breath(datum/gas_mixture/breath, skip_breath = FALSE) + return /// Applies suffocation side-effects to a given Human, scaling based on ratio of required pressure VS "true" pressure. /// If pressure is greater than 0, the return value will represent the amount of gas successfully breathed. @@ -473,21 +183,45 @@ // The air you breathe out should match your body temperature breath.temperature = bodytemperature -/// Attempts to take a breath from the external or internal air tank. +/** + * Attempts to take a breath from the external or internal air tank. + * + * Return a gas mixture datum if a breath was taken + * Return null if there was no gas inside the tank or no gas was distributed + * Return SKIP_INTERNALS to skip using internals entirely and get a normal breath + */ /mob/living/carbon/proc/get_breath_from_internal(volume_needed) if(invalid_internals()) // Unexpectely lost breathing apparatus and ability to breathe from the internal air tank. cutoff_internals() - return + return SKIP_INTERNALS + if (external) . = external.remove_air_volume(volume_needed) else if (internal) . = internal.remove_air_volume(volume_needed) else // Return without taking a breath if there is no air tank. - return - // To differentiate between no internals and active, but empty internals. - return . || FALSE + stack_trace("get_breath_from_internal called on a mob without internals or externals") + return SKIP_INTERNALS + + return . + +/** + * Attempts to take a breath from the surroundings. + * + * Returns a gas mixture datum if a breath was taken. + * Returns null if there was no gas in the surroundings or no gas was distributed. + */ +/mob/living/carbon/proc/get_breath_from_surroundings(datum/gas_mixture/environment, volume_needed) + if(isobj(loc)) //Breathe from loc as object + var/obj/loc_as_obj = loc + . = loc_as_obj.handle_internal_lifeform(src, volume_needed) + + else if(isturf(loc)) //Breathe from loc as turf + . = loc.remove_air((environment?.total_moles() * BREATH_PERCENTAGE) || 0) + + return . /mob/living/carbon/proc/handle_blood(seconds_per_tick, times_fired) return @@ -559,7 +293,7 @@ dna.unique_enzymes = dna.previous["UE"] dna.previous.Remove("UE") if(dna.previous["blood_type"]) - dna.blood_type = dna.previous["blood_type"] + dna.human_blood_type = blood_name_to_blood_type(dna.previous["blood_type"]) dna.previous.Remove("blood_type") dna.temporary_mutations.Remove(mut) continue @@ -581,92 +315,47 @@ reagents?.metabolize(src, seconds_per_tick, times_fired, can_overdose = TRUE, liverless = TRUE, dead = TRUE) // Your liver doesn't work while you're dead. /// Base carbon environment handler, adds natural stabilization -/mob/living/carbon/handle_environment(datum/gas_mixture/environment, seconds_per_tick, times_fired) - var/areatemp = get_temperature(environment) - - if(stat != DEAD) // If you are dead your body does not stabilize naturally - natural_bodytemperature_stabilization(environment, seconds_per_tick, times_fired) - - if(!on_fire || areatemp > bodytemperature) // If we are not on fire or the area is hotter - adjust_bodytemperature((areatemp - bodytemperature), use_insulation=TRUE, use_steps=TRUE) +/mob/living/carbon/human/handle_environment(datum/gas_mixture/environment, seconds_per_tick, times_fired) + . = ..() + var/pressure = environment.return_pressure() + var/adjusted_pressure = calculate_affecting_pressure(pressure) + + // Set alerts and apply damage based on the amount of pressure + switch(adjusted_pressure) + // Very high pressure, show an alert and take damage + if(HAZARD_HIGH_PRESSURE to INFINITY) + if(HAS_TRAIT(src, TRAIT_RESISTHIGHPRESSURE)) + clear_alert(ALERT_PRESSURE) + else + var/pressure_damage = min(((adjusted_pressure / HAZARD_HIGH_PRESSURE) - 1) * PRESSURE_DAMAGE_COEFFICIENT, MAX_HIGH_PRESSURE_DAMAGE) * physiology.pressure_mod * physiology.brute_mod * seconds_per_tick + adjustBruteLoss(pressure_damage, required_bodytype = BODYTYPE_ORGANIC) + throw_alert(ALERT_PRESSURE, /atom/movable/screen/alert/highpressure, 2) + + // High pressure, show an alert + if(WARNING_HIGH_PRESSURE to HAZARD_HIGH_PRESSURE) + throw_alert(ALERT_PRESSURE, /atom/movable/screen/alert/highpressure, 1) + + // No pressure issues here clear pressure alerts + if(WARNING_LOW_PRESSURE to WARNING_HIGH_PRESSURE) + clear_alert(ALERT_PRESSURE) + + // Low pressure here, show an alert + if(HAZARD_LOW_PRESSURE to WARNING_LOW_PRESSURE) + // We have low pressure resit trait, clear alerts + if(HAS_TRAIT(src, TRAIT_RESISTLOWPRESSURE)) + clear_alert(ALERT_PRESSURE) + else + throw_alert(ALERT_PRESSURE, /atom/movable/screen/alert/lowpressure, 1) -/** - * Used to stabilize the body temperature back to normal on living mobs - * - * Arguments: - * - [environemnt][/datum/gas_mixture]: The environment gas mix - * - seconds_per_tick: The amount of time that has elapsed since the last tick - * - times_fired: The number of times SSmobs has ticked - */ -/mob/living/carbon/proc/natural_bodytemperature_stabilization(datum/gas_mixture/environment, seconds_per_tick, times_fired) - var/areatemp = get_temperature(environment) - var/body_temperature_difference = get_body_temp_normal() - bodytemperature - var/natural_change = 0 - - // We are very cold, increase body temperature - if(bodytemperature <= BODYTEMP_COLD_DAMAGE_LIMIT) - natural_change = max((body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR), \ - BODYTEMP_AUTORECOVERY_MINIMUM) - - // we are cold, reduce the minimum increment and do not jump over the difference - else if(bodytemperature > BODYTEMP_COLD_DAMAGE_LIMIT && bodytemperature < get_body_temp_normal()) - natural_change = max(body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, \ - min(body_temperature_difference, BODYTEMP_AUTORECOVERY_MINIMUM / 4)) - - // We are hot, reduce the minimum increment and do not jump below the difference - else if(bodytemperature > get_body_temp_normal() && bodytemperature <= BODYTEMP_HEAT_DAMAGE_LIMIT) - natural_change = min(body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, \ - max(body_temperature_difference, -(BODYTEMP_AUTORECOVERY_MINIMUM / 4))) - - // We are very hot, reduce the body temperature - else if(bodytemperature >= BODYTEMP_HEAT_DAMAGE_LIMIT) - natural_change = min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) - - var/thermal_protection = 1 - get_insulation_protection(areatemp) // invert the protection - if(areatemp > bodytemperature) // It is hot here - if(bodytemperature < get_body_temp_normal()) - // Our bodytemp is below normal we are cold, insulation helps us retain body heat - // and will reduce the heat we lose to the environment - natural_change = (thermal_protection + 1) * natural_change + // Very low pressure, show an alert and take damage else - // Our bodytemp is above normal and sweating, insulation hinders out ability to reduce heat - // but will reduce the amount of heat we get from the environment - natural_change = (1 / (thermal_protection + 1)) * natural_change - else // It is cold here - if(!on_fire) // If on fire ignore ignore local temperature in cold areas - if(bodytemperature < get_body_temp_normal()) - // Our bodytemp is below normal, insulation helps us retain body heat - // and will reduce the heat we lose to the environment - natural_change = (thermal_protection + 1) * natural_change + // We have low pressure resit trait, clear alerts + if(HAS_TRAIT(src, TRAIT_RESISTLOWPRESSURE)) + clear_alert(ALERT_PRESSURE) else - // Our bodytemp is above normal and sweating, insulation hinders out ability to reduce heat - // but will reduce the amount of heat we get from the environment - natural_change = (1 / (thermal_protection + 1)) * natural_change - - // Apply the natural stabilization changes - adjust_bodytemperature(natural_change * seconds_per_tick) - -/** - * Get the insulation that is appropriate to the temperature you're being exposed to. - * All clothing, natural insulation, and traits are combined returning a single value. - * - * required temperature The Temperature that you're being exposed to - * - * return the percentage of protection as a value from 0 - 1 -**/ -/mob/living/carbon/proc/get_insulation_protection(temperature) - return (temperature > bodytemperature) ? get_heat_protection(temperature) : get_cold_protection(temperature) - -/// This returns the percentage of protection from heat as a value from 0 - 1 -/// temperature is the temperature you're being exposed to -/mob/living/carbon/proc/get_heat_protection(temperature) - return heat_protection - -/// This returns the percentage of protection from cold as a value from 0 - 1 -/// temperature is the temperature you're being exposed to -/mob/living/carbon/proc/get_cold_protection(temperature) - return cold_protection - + var/pressure_damage = LOW_PRESSURE_DAMAGE * physiology.pressure_mod * physiology.brute_mod * seconds_per_tick + adjustBruteLoss(pressure_damage, required_bodytype = BODYTYPE_ORGANIC) + throw_alert(ALERT_PRESSURE, /atom/movable/screen/alert/lowpressure, 2) /** * Have two mobs share body heat between each other. * Account for the insulation and max temperature change range for the mob @@ -677,39 +366,12 @@ /mob/living/carbon/proc/share_bodytemperature(mob/living/carbon/M) var/temp_diff = bodytemperature - M.bodytemperature if(temp_diff > 0) // you are warm share the heat of life - M.adjust_bodytemperature((temp_diff * 0.5), use_insulation=TRUE, use_steps=TRUE) // warm up the giver - adjust_bodytemperature((temp_diff * -0.5), use_insulation=TRUE, use_steps=TRUE) // cool down the reciver + M.adjust_bodytemperature((temp_diff * 0.5) * 0.075 KELVIN, use_insulation = TRUE) // warm up the giver + adjust_bodytemperature((temp_diff * -0.5) * 0.075 KELVIN, use_insulation = TRUE) // cool down the reciver else // they are warmer leech from them - adjust_bodytemperature((temp_diff * -0.5) , use_insulation=TRUE, use_steps=TRUE) // warm up the reciver - M.adjust_bodytemperature((temp_diff * 0.5), use_insulation=TRUE, use_steps=TRUE) // cool down the giver - -/** - * Adjust the body temperature of a mob - * expanded for carbon mobs allowing the use of insulation and change steps - * - * vars: - * * amount The amount of degrees to change body temperature by - * * min_temp (optional) The minimum body temperature after adjustment - * * max_temp (optional) The maximum body temperature after adjustment - * * use_insulation (optional) modifies the amount based on the amount of insulation the mob has - * * use_steps (optional) Use the body temp divisors and max change rates - * * capped (optional) default True used to cap step mode - */ -/mob/living/carbon/adjust_bodytemperature(amount, min_temp=0, max_temp=INFINITY, use_insulation=FALSE, use_steps=FALSE, capped=TRUE) - // apply insulation to the amount of change - if(use_insulation) - amount *= (1 - get_insulation_protection(bodytemperature + amount)) - - // Use the bodytemp divisors to get the change step, with max step size - if(use_steps) - amount = (amount > 0) ? (amount / BODYTEMP_HEAT_DIVISOR) : (amount / BODYTEMP_COLD_DIVISOR) - // Clamp the results to the min and max step size - if(capped) - amount = (amount > 0) ? min(amount, BODYTEMP_HEATING_MAX) : max(amount, BODYTEMP_COOLING_MAX) - - if(bodytemperature >= min_temp && bodytemperature <= max_temp) - bodytemperature = clamp(bodytemperature + amount, min_temp, max_temp) + adjust_bodytemperature((temp_diff * -0.5) * 0.075 KELVIN, use_insulation = TRUE) // warm up the reciver + M.adjust_bodytemperature((temp_diff * 0.5) * 0.075 KELVIN, use_insulation = TRUE) // cool down the giver /////////// @@ -759,7 +421,7 @@ reagents.end_metabolization(src, keep_liverless = TRUE) //Stops trait-based effects on reagents, to prevent permanent buffs reagents.metabolize(src, seconds_per_tick, times_fired, can_overdose=TRUE, liverless = TRUE) - if(HAS_TRAIT(src, TRAIT_STABLELIVER) || HAS_TRAIT(src, TRAIT_NOMETABOLISM)) + if(HAS_TRAIT(src, TRAIT_STABLELIVER) || HAS_TRAIT(src, TRAIT_LIVERLESS_METABOLISM)) return adjustToxLoss(0.6 * seconds_per_tick, TRUE, TRUE) diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 9793371343fa..1873a40f77c2 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -70,7 +70,7 @@ update_damage_overlays() damage_dealt = actual_hit.get_damage() - delta // Unfortunately bodypart receive_damage doesn't return damage dealt so we do it manually else - damage_dealt = adjustBruteLoss(damage_amount, forced = forced) + damage_dealt = -1 * adjustBruteLoss(damage_amount, forced = forced) if(BURN) if(isbodypart(def_zone)) var/obj/item/bodypart/actual_hit = def_zone @@ -86,19 +86,38 @@ damage_source = attacking_item, )) update_damage_overlays() - damage_dealt = delta - actual_hit.get_damage() // See above + damage_dealt = actual_hit.get_damage() - delta // See above else - damage_dealt = adjustFireLoss(damage_amount, forced = forced) + damage_dealt = -1 * adjustFireLoss(damage_amount, forced = forced) if(TOX) - damage_dealt = adjustToxLoss(damage_amount, forced = forced) + damage_dealt = -1 * adjustToxLoss(damage_amount, forced = forced) if(OXY) - damage_dealt = adjustOxyLoss(damage_amount, forced = forced) + damage_dealt = -1 * adjustOxyLoss(damage_amount, forced = forced) if(CLONE) - damage_dealt = adjustCloneLoss(damage_amount, forced = forced) + damage_dealt = -1 * adjustCloneLoss(damage_amount, forced = forced) if(STAMINA) - damage_dealt = stamina.adjust(-damage) + damage_dealt = -1 * stamina.adjust(-damage) + if(PAIN) + if(pain_controller) + var/pre_pain = pain_controller.get_average_pain() + var/pain_amount = damage_amount + var/chosen_zone + if(spread_damage || isnull(def_zone)) + chosen_zone = BODY_ZONES_ALL + pain_amount /= 6 + else if(isbodypart(def_zone)) + var/obj/item/bodypart/actual_hit = def_zone + chosen_zone = actual_hit.body_zone + else + chosen_zone = check_zone(def_zone) + + sharp_pain(chosen_zone, pain_amount, STAMINA, 12.5 SECONDS, 0.8) + damage_dealt += pre_pain - pain_controller.get_average_pain() + damage_dealt += stamina?.adjust(-damage_amount * 0.25, forced = forced) + else + damage_dealt = -1 * stamina.adjust(-damage_amount, forced = forced) if(BRAIN) - damage_dealt = adjustOrganLoss(ORGAN_SLOT_BRAIN, damage_amount) + damage_dealt = -1 * adjustOrganLoss(ORGAN_SLOT_BRAIN, damage_amount) SEND_SIGNAL(src, COMSIG_MOB_AFTER_APPLY_DAMAGE, damage_dealt, damagetype, def_zone, blocked, wound_bonus, bare_wound_bonus, sharpness, attack_direction, attacking_item) return damage_dealt diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm index a82cacfaf960..e82151f1251d 100644 --- a/code/modules/mob/living/death.dm +++ b/code/modules/mob/living/death.dm @@ -6,7 +6,7 @@ * * no_organs - Should the mob NOT drop organs? * * no_bodyparts - Should the mob NOT drop bodyparts? */ -/mob/living/proc/gib(no_brain, no_organs, no_bodyparts) +/mob/living/proc/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) var/prev_lying = lying_angle if(stat != DEAD) death(TRUE) diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm index 3faf2c8cb364..8b9a22f40a28 100644 --- a/code/modules/mob/living/emote.dm +++ b/code/modules/mob/living/emote.dm @@ -288,7 +288,8 @@ if(user.alternative_laughs.len) return pick(user.alternative_laughs) - return user.dna.species.get_laugh_sound(user) + var/obj/item/organ/internal/tongue/tongue = user.get_organ_slot(ORGAN_SLOT_TONGUE) + return tongue?.get_laugh_sound(user) // MonkeStation Edit End /datum/emote/living/look diff --git a/code/modules/mob/living/init_signals.dm b/code/modules/mob/living/init_signals.dm index be431ccf31f8..9acd31e030f0 100644 --- a/code/modules/mob/living/init_signals.dm +++ b/code/modules/mob/living/init_signals.dm @@ -1,7 +1,6 @@ /// Called on [/mob/living/Initialize(mapload)], for the mob to register to relevant signals. /mob/living/proc/register_init_signals() - RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_KNOCKEDOUT), PROC_REF(on_knockedout_trait_gain)) - RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_KNOCKEDOUT), PROC_REF(on_knockedout_trait_loss)) + RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_KNOCKEDOUT), SIGNAL_REMOVETRAIT(TRAIT_KNOCKEDOUT)), PROC_REF(on_knockedout_trait)) RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_DEATHCOMA), PROC_REF(on_deathcoma_trait_gain)) RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_DEATHCOMA), PROC_REF(on_deathcoma_trait_loss)) @@ -63,17 +62,20 @@ ) AddElement(/datum/element/connect_loc, loc_connections) -/// Called when [TRAIT_KNOCKEDOUT] is added to the mob. -/mob/living/proc/on_knockedout_trait_gain(datum/source) +/// Called when [TRAIT_KNOCKEDOUT] is added or removed from the mob. +/mob/living/proc/on_knockedout_trait(datum/source) SIGNAL_HANDLER - if(stat < UNCONSCIOUS) - set_stat(UNCONSCIOUS) + if(HAS_TRAIT(src, TRAIT_KNOCKEDOUT)) + become_blind(UNCONSCIOUS_TRAIT) + set_pain_mod(PAIN_MOD_KOD, 0.8) + add_traits(list(TRAIT_HANDS_BLOCKED, TRAIT_IMMOBILIZED, TRAIT_INCAPACITATED, TRAIT_FLOORED), TRAIT_KNOCKEDOUT) + update_body() // Update eyelids -/// Called when [TRAIT_KNOCKEDOUT] is removed from the mob. -/mob/living/proc/on_knockedout_trait_loss(datum/source) - SIGNAL_HANDLER - if(stat <= UNCONSCIOUS) - update_stat() + else + cure_blind(UNCONSCIOUS_TRAIT) + unset_pain_mod(PAIN_MOD_KOD) + remove_traits(list(TRAIT_HANDS_BLOCKED, TRAIT_IMMOBILIZED, TRAIT_INCAPACITATED, TRAIT_FLOORED), TRAIT_KNOCKEDOUT) + update_body() // Update eyelids /// Called when [TRAIT_DEATHCOMA] is added to the mob. /mob/living/proc/on_deathcoma_trait_gain(datum/source) diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index cda90a8e7316..36df39e4167c 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -1,6 +1,3 @@ -/// This divisor controls how fast body temperature changes to match the environment -#define BODYTEMP_DIVISOR 16 - /** * Handles the biological and general over-time processes of the mob. * @@ -63,9 +60,17 @@ var/datum/gas_mixture/environment = loc.return_air() if(environment) handle_environment(environment, seconds_per_tick, times_fired) + body_temperature_damage(environment, seconds_per_tick, times_fired) + if(stat <= SOFT_CRIT && !on_fire) + if(!ishuman(src)) + return + temperature_homeostasis(seconds_per_tick, times_fired) handle_gravity(seconds_per_tick, times_fired) + if(stat != DEAD) + body_temperature_alerts() + handle_wounds(seconds_per_tick, times_fired) if(machine) @@ -90,20 +95,45 @@ /mob/living/proc/handle_random_events(seconds_per_tick, times_fired) return -// Base mob environment handler for body temperature +/** + * Handle this mob's interactions with the environment + * + * By default handles body temperature normalization to the area's temperature, + * but also handles pressure for many mobs + * + * Arguments: + * * environment: The gas mixture of the area the mob is in, will never be null + * * seconds_per_tick: The amount of time that has elapsed since this last fired. + * * times_fired: The number of times SSmobs has fired + */ /mob/living/proc/handle_environment(datum/gas_mixture/environment, seconds_per_tick, times_fired) var/loc_temp = get_temperature(environment) var/temp_delta = loc_temp - bodytemperature + if(temp_delta == 0) + return + if(temp_delta < 0 && on_fire) + return + + var/thermal_protection = get_insulation(loc_temp) + var/protection_modifier = 1 + if(bodytemperature > standard_body_temperature + 2 KELVIN) + protection_modifier = 0.7 + + // Calculate the equilibrium temperature considering insulation + var/equilibrium_temp = get_insulated_equilibrium_temperature(loc_temp, thermal_protection * protection_modifier) - if(ismovable(loc)) - var/atom/movable/occupied_space = loc - temp_delta *= (1 - occupied_space.contents_thermal_insulation) + var/temp_change = (equilibrium_temp - bodytemperature) * temperature_normalization_speed * seconds_per_tick - if(temp_delta < 0) // it is cold here - if(!on_fire) // do not reduce body temp when on fire - adjust_bodytemperature(max(max(temp_delta / BODYTEMP_DIVISOR, BODYTEMP_COOLING_MAX) * seconds_per_tick, temp_delta)) - else // this is a hot place - adjust_bodytemperature(min(min(temp_delta / BODYTEMP_DIVISOR, BODYTEMP_HEATING_MAX) * seconds_per_tick, temp_delta)) + // Cap increase and decrease + temp_change = temp_change < 0 ? max(temp_change, BODYTEMP_HOMEOSTASIS_COOLING_MAX) : min(temp_change, BODYTEMP_HOMEOSTASIS_HEATING_MAX) + + adjust_bodytemperature(temp_change * seconds_per_tick) // No use_insulation because we manually account for it + +/mob/living/proc/get_insulated_equilibrium_temperature(environment_temp, insulation) + return environment_temp + (standard_body_temperature - environment_temp) * insulation + +/mob/living/silicon/handle_environment(datum/gas_mixture/environment, seconds_per_tick, times_fired) + return // Not yet /** * Get the fullness of the mob @@ -116,10 +146,8 @@ /mob/living/proc/get_fullness() var/fullness = nutrition // we add the nutrition value of what we're currently digesting - for(var/bile in reagents.reagent_list) - var/datum/reagent/consumable/bits = bile - if(bits) - fullness += bits.nutriment_factor * bits.volume / bits.metabolization_rate + for(var/datum/reagent/consumable/bits in reagents.reagent_list) + fullness += bits.nutriment_factor * bits.volume / bits.metabolization_rate return fullness /** @@ -153,5 +181,3 @@ var/grav_strength = gravity - GRAVITY_DAMAGE_THRESHOLD adjustBruteLoss(min(GRAVITY_DAMAGE_SCALING * grav_strength, GRAVITY_DAMAGE_MAXIMUM) * seconds_per_tick) - -#undef BODYTEMP_DIVISOR diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 4e0b442bc511..ceda4365d105 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -17,6 +17,8 @@ update_fov() gravity_setup() voice_type = pick(voice_type2sound) //monkestation edit + if(!blood_volume) + ADD_TRAIT(src, TRAIT_NOBLOOD, INNATE_TRAIT) /mob/living/prepare_huds() ..() @@ -246,7 +248,7 @@ visible_message("[src] bounces off \the [O]!") var/atom/throw_target = get_edge_target_turf(src, turn(get_dir(O, src), rand(-1,1) * 45)) playsound(src, 'monkestation/sound/effects/boing1.ogg', 50) - src.throw_at(throw_target, 20, 3, force = 0) + src.throw_at(throw_target, 20, 3, force = 0, gentle = TRUE) return //Called when we bump onto an obj @@ -255,7 +257,7 @@ visible_message("[src] bounces off \the [T]!") var/atom/throw_target = get_edge_target_turf(src, turn(get_dir(T, src), rand(-1,1) * 45)) playsound(src, 'monkestation/sound/effects/boing1.ogg', 50) - src.throw_at(throw_target, 20, 3, force = 0) + src.throw_at(throw_target, 20, 3, force = 0, gentle = TRUE) return //Called when we want to push an atom/movable @@ -524,7 +526,7 @@ * * IGNORE_GRAB - mob that is agressively grabbed is not considered incapacitated **/ /mob/living/incapacitated(flags) - if((flags & IGNORE_CRIT) && ((stat >= SOFT_CRIT && (stat != DEAD && stat != UNCONSCIOUS)) && !src.pulledby)) + if((flags & IGNORE_CRIT) && ((stat >= SOFT_CRIT && (stat != DEAD && stat != UNCONSCIOUS && stat != HARD_CRIT)) && !src.pulledby)) return FALSE if(HAS_TRAIT(src, TRAIT_INCAPACITATED)) @@ -933,7 +935,8 @@ cure_husk() if(heal_flags & HEAL_TEMP) - bodytemperature = get_body_temp_normal(apply_change = FALSE) + bodytemperature = standard_body_temperature + body_temperature_alerts() if(heal_flags & HEAL_BLOOD) restore_blood() if(reagents && (heal_flags & HEAL_ALL_REAGENTS)) @@ -1019,10 +1022,10 @@ return /mob/living/proc/makeTrail(turf/target_turf, turf/start, direction) - if(!has_gravity() || !isturf(start) || !blood_volume) + if(!has_gravity() || !isturf(start) || HAS_TRAIT(src, TRAIT_NOBLOOD)) return - var/blood_exists = locate(/obj/effect/decal/cleanable/trail_holder) in start + var/blood_exists = locate(/obj/effect/decal/cleanable/blood/trail_holder) in start var/trail_type = getTrail() if(!trail_type) @@ -1044,18 +1047,21 @@ if((newdir in GLOB.cardinals) && (prob(50))) newdir = turn(get_dir(target_turf, start), 180) if(!blood_exists) - new /obj/effect/decal/cleanable/trail_holder(start, get_static_viruses()) + var/obj/effect/decal/cleanable/blood/trail_holder/new_blood = new /obj/effect/decal/cleanable/blood/trail_holder(start, get_static_viruses()) + new_blood.add_mob_blood(src) + new_blood.update_appearance() - for(var/obj/effect/decal/cleanable/trail_holder/TH in start) + for(var/obj/effect/decal/cleanable/blood/trail_holder/TH in start) if((!(newdir in TH.existing_dirs) || trail_type == "trails_1" || trail_type == "trails_2") && TH.existing_dirs.len <= 16) //maximum amount of overlays is 16 (all light & heavy directions filled) TH.existing_dirs += newdir TH.add_overlay(image('icons/effects/blood.dmi', trail_type, dir = newdir)) - TH.transfer_mob_blood_dna(src) + TH.add_mob_blood(src) + TH.update_appearance() -/mob/living/carbon/human/makeTrail(turf/T) - if(HAS_TRAIT(src, TRAIT_NOBLOOD) || !is_bleeding() || HAS_TRAIT(src, TRAIT_NOBLOOD)) +/mob/living/carbon/human/makeTrail(turf/target_turf, turf/start, direction) + if(!is_bleeding()) return - ..() + return ..() ///Returns how much blood we're losing from being dragged a tile, from [/mob/living/proc/makeTrail] /mob/living/proc/bleedDragAmount() @@ -1240,16 +1246,23 @@ else if(!src.mob_negates_gravity()) step_towards(src,S) +/** + * Unsed in calculating what temperature our environment probably is. + * + * By default just returns the temperature of the turf we're on, + * but is slightly more complex if we're inside another movable (in which we average the temps of our body and the movable) + */ /mob/living/proc/get_temperature(datum/gas_mixture/environment) - var/loc_temp = environment ? environment.temperature : T0C + var/loc_temp = environment ? environment.return_temperature() : T0C if(isobj(loc)) - var/obj/oloc = loc - var/obj_temp = oloc.return_temperature() - if(obj_temp != null) + var/obj_temp = loc.return_temperature() + if(!isnull(obj_temp)) loc_temp = obj_temp + else if(isspaceturf(get_turf(src))) var/turf/heat_turf = get_turf(src) loc_temp = heat_turf.temperature + if(ismovable(loc)) var/atom/movable/occupied_space = loc loc_temp = ((1 - occupied_space.contents_thermal_insulation) * loc_temp) + (occupied_space.contents_thermal_insulation * bodytemperature) @@ -1695,16 +1708,22 @@ GLOBAL_LIST_EMPTY(fire_appearances) return null /** - * Handles effects happening when mob is on normal fire + * Called every life tick that a mob is on fire. * - * Vars: - * * seconds_per_tick - * * times_fired - * * fire_handler: Current fire status effect that called the proc + * Args: + * * seconds_per_tick: Seconds between each life tick + * * fire_handler: The fire handler status effect that is managing the fire stacks */ - /mob/living/proc/on_fire_stack(seconds_per_tick, times_fired, datum/status_effect/fire_handler/fire_stacks/fire_handler) - return + var/amount_to_heat = HEAT_PER_FIRE_STACK * fire_handler.stacks * seconds_per_tick + var/amount_to_burn = BURN_DAMAGE_PER_FIRE_STACK * fire_handler.stacks * seconds_per_tick + if(bodytemperature > BODYTEMP_FIRE_TEMP_SOFTCAP) + // Apply dimishing returns upon temp beyond the soft cap + amount_to_heat = amount_to_heat ** (BODYTEMP_FIRE_TEMP_SOFTCAP / bodytemperature) + + var/direct_damage = (HAS_TRAIT(src, TRAIT_RESISTHEAT) || bodytemp_heat_damage_limit == INFINITY) ? 0 : temperature_burns(amount_to_burn) + var/temp_change = adjust_bodytemperature(amount_to_heat) + return temp_change + direct_damage //Mobs on Fire end @@ -1967,64 +1986,6 @@ GLOBAL_LIST_EMPTY(fire_appearances) update_transform() lying_prev = lying_angle - -/** - * add_body_temperature_change Adds modifications to the body temperature - * - * This collects all body temperature changes that the mob is experiencing to the list body_temp_changes - * the aggrogate result is used to derive the new body temperature for the mob - * - * arguments: - * * key_name (str) The unique key for this change, if it already exist it will be overridden - * * amount (int) The amount of change from the base body temperature - */ -/mob/living/proc/add_body_temperature_change(key_name, amount) - body_temp_changes["[key_name]"] = amount - -/** - * remove_body_temperature_change Removes the modifications to the body temperature - * - * This removes the recorded change to body temperature from the body_temp_changes list - * - * arguments: - * * key_name (str) The unique key for this change that will be removed - */ -/mob/living/proc/remove_body_temperature_change(key_name) - body_temp_changes -= key_name - -/** - * get_body_temp_normal_change Returns the aggregate change to body temperature - * - * This aggregates all the changes in the body_temp_changes list and returns the result - */ -/mob/living/proc/get_body_temp_normal_change() - var/total_change = 0 - if(body_temp_changes.len) - for(var/change in body_temp_changes) - total_change += body_temp_changes["[change]"] - return total_change - -/** - * get_body_temp_normal Returns the mobs normal body temperature with any modifications applied - * - * This applies the result from proc/get_body_temp_normal_change() against the BODYTEMP_NORMAL and returns the result - * - * arguments: - * * apply_change (optional) Default True This applies the changes to body temperature normal - */ -/mob/living/proc/get_body_temp_normal(apply_change=TRUE) - if(!apply_change) - return BODYTEMP_NORMAL - return BODYTEMP_NORMAL + get_body_temp_normal_change() - -///Returns the body temperature at which this mob will start taking heat damage. -/mob/living/proc/get_body_temp_heat_damage_limit() - return BODYTEMP_HEAT_DAMAGE_LIMIT - -///Returns the body temperature at which this mob will start taking cold damage. -/mob/living/proc/get_body_temp_cold_damage_limit() - return BODYTEMP_COLD_DAMAGE_LIMIT - ///Checks if the user is incapacitated or on cooldown. /mob/living/proc/can_look_up() return !(incapacitated(IGNORE_RESTRAINTS)) @@ -2255,27 +2216,38 @@ GLOBAL_LIST_EMPTY(fire_appearances) stack_trace("[src] had set_usable_legs() called on them with a negative value!") new_value = 0 - . = usable_legs + var/old_value = usable_legs usable_legs = new_value - if(new_value > .) // Gained leg usage. + update_limbless_locomotion() + update_limbless_movespeed_mod() + + return old_value + +/// Updates whether the mob is floored or immobilized based on how many limbs they have or are missing. +/mob/living/proc/update_limbless_locomotion() + if(usable_legs > 0 || (movement_type & (FLYING|FLOATING)) || COUNT_TRAIT_SOURCES(src, TRAIT_NO_LEG_AID) >= 2) REMOVE_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) - else if(!(movement_type & (FLYING | FLOATING))) //Lost leg usage, not flying. - if(!usable_legs) - ADD_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) - if(!usable_hands) - ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) + return + ADD_TRAIT(src, TRAIT_FLOORED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) + if(usable_hands == 0) + ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) +/// Updates the mob's movespeed based on how many limbs they have or are missing. +/mob/living/proc/update_limbless_movespeed_mod() if(usable_legs < default_num_legs) var/limbless_slowdown = (default_num_legs - usable_legs) * 3 if(!usable_legs && usable_hands < default_num_hands) limbless_slowdown += (default_num_hands - usable_hands) * 3 + var/list/slowdown_mods = list() + SEND_SIGNAL(src, COMSIG_LIVING_LIMBLESS_MOVESPEED_UPDATE, slowdown_mods) + for(var/num in slowdown_mods) + limbless_slowdown *= num add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/limbless, multiplicative_slowdown = limbless_slowdown) else remove_movespeed_modifier(/datum/movespeed_modifier/limbless) - ///Proc to modify the value of num_hands and hook behavior associated to this event. /mob/living/proc/set_num_hands(new_value) if(num_hands == new_value) @@ -2288,14 +2260,18 @@ GLOBAL_LIST_EMPTY(fire_appearances) /mob/living/proc/set_usable_hands(new_value) if(usable_hands == new_value) return - . = usable_hands + if(new_value < 0) // Sanity check + stack_trace("[src] had set_usable_hands() called on them with a negative value!") + new_value = 0 + + var/old_value = usable_hands usable_hands = new_value - if(new_value > .) // Gained hand usage. - REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) - else if(!(movement_type & (FLYING | FLOATING)) && !usable_hands && !usable_legs) //Lost a hand, not flying, no hands left, no legs. - ADD_TRAIT(src, TRAIT_IMMOBILIZED, LACKING_LOCOMOTION_APPENDAGES_TRAIT) + if(usable_legs < default_num_legs) + update_limbless_locomotion() + update_limbless_movespeed_mod() + return old_value /// Whether or not this mob will escape from storages while being picked up/held. /mob/living/proc/will_escape_storage() diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index a6481e93ae01..2594aaee786e 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -100,21 +100,49 @@ // we need a second, silent armor check to actually know how much to reduce damage taken, as opposed to // on [/atom/proc/bullet_act] where it's just to pass it to the projectile's on_hit(). - var/armor_check = check_projectile_armor(def_zone, hitting_projectile, is_silent = TRUE) + var/armor_check = min(ARMOR_MAX_BLOCK, check_projectile_armor(def_zone, hitting_projectile, is_silent = TRUE)) - apply_damage( + var/damage_done = apply_damage( damage = hitting_projectile.damage, damagetype = hitting_projectile.damage_type, def_zone = def_zone, - blocked = min(ARMOR_MAX_BLOCK, armor_check), //cap damage reduction at 90% + blocked = armor_check, wound_bonus = hitting_projectile.wound_bonus, bare_wound_bonus = hitting_projectile.bare_wound_bonus, sharpness = hitting_projectile.sharpness, - attack_direction = get_dir(hitting_projectile.starting, src), + attack_direction = hitting_projectile.dir, ) + if(hitting_projectile.stamina) + apply_damage( + damage = hitting_projectile.stamina, + damagetype = STAMINA, + def_zone = def_zone, + blocked = armor_check, + attack_direction = hitting_projectile.dir, + ) + if(hitting_projectile.pain) + apply_damage( + damage = hitting_projectile.pain, + damagetype = PAIN, + def_zone = def_zone, + // blocked = armor_check, // Batons don't factor in armor, soooo we shouldn't? + attack_direction = hitting_projectile.dir, + ) + + var/extra_paralyze = 0 SECONDS + var/extra_knockdown = 0 SECONDS + if(hitting_projectile.damage_type == BRUTE && !hitting_projectile.grazing && (pain_controller?.get_average_pain() > 50)) + if(damage_done >= 60) + if(!IsParalyzed() && prob(damage_done)) + extra_paralyze += 0.8 SECONDS + extra_knockdown += 1.2 SECONDS + else if(damage_done >= 20) + if(!IsKnockdown() && prob(damage_done * 2)) + extra_knockdown += 0.8 SECONDS + apply_effects( stun = hitting_projectile.stun, - knockdown = hitting_projectile.knockdown, + knockdown = hitting_projectile.knockdown + extra_knockdown, unconscious = hitting_projectile.unconscious, slur = (mob_biotypes & MOB_ROBOTIC) ? 0 SECONDS : hitting_projectile.slur, // Don't want your cyborgs to slur from being ebow'd stutter = (mob_biotypes & MOB_ROBOTIC) ? 0 SECONDS : hitting_projectile.stutter, // Don't want your cyborgs to stutter from being tazed @@ -123,7 +151,7 @@ blocked = armor_check, stamina = hitting_projectile.stamina, jitter = (mob_biotypes & MOB_ROBOTIC) ? 0 SECONDS : hitting_projectile.jitter, // Cyborgs can jitter but not from being shot - paralyze = hitting_projectile.paralyze, + paralyze = hitting_projectile.paralyze + extra_paralyze, immobilize = hitting_projectile.immobilize, ) if(hitting_projectile.dismemberment) @@ -131,7 +159,16 @@ return BULLET_ACT_HIT /mob/living/check_projectile_armor(def_zone, obj/projectile/impacting_projectile, is_silent) - return run_armor_check(def_zone, impacting_projectile.armor_flag, "","",impacting_projectile.armour_penetration, "", is_silent, impacting_projectile.weak_against_armour) + . = run_armor_check( + def_zone = def_zone, + attack_flag = impacting_projectile.armor_flag, + armour_penetration = impacting_projectile.armour_penetration, + silent = is_silent, + weak_against_armour = impacting_projectile.weak_against_armour, + ) + if(impacting_projectile.grazing) + . += 50 + return . /mob/living/proc/check_projectile_dismemberment(obj/projectile/P, def_zone) return 0 diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index fc9ffb53cc45..499910828f3d 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -21,6 +21,9 @@ ///Stamina damage, or exhaustion. You recover it slowly naturally, and are knocked down if it gets too high. Holodeck and hallucinations deal this. var/staminaloss = 0 + /// Modified applied to attacks with items or fists + var/outgoing_damage_mod = 1 + //Damage related vars, NOTE: THESE SHOULD ONLY BE MODIFIED BY PROCS ///Brutal damage caused by brute force (punching, being clubbed by a toolbox ect... this also accounts for pressure damage) var/bruteloss = 0 @@ -115,6 +118,8 @@ var/num_legs = 2 ///How many usable legs this mob currently has. Should only be changed through set_usable_legs() var/usable_legs = 2 + ///what leg we step with + var/step_leg = 1 ///How many hands does this mob have by default. This shouldn't change at runtime. var/default_num_hands = 2 @@ -185,9 +190,6 @@ ///Whether the mob is slowed down when dragging another prone mob var/slowed_by_drag = TRUE - /// List of changes to body temperature, used by desease symtoms like fever - var/list/body_temp_changes = list() - //this stuff is here to make it simple for admins to mess with custom held sprites ///left hand icon for holding mobs var/icon/held_lh = 'icons/mob/inhands/pets_held_lh.dmi' @@ -226,3 +228,30 @@ var/datum/stamina_container/stamina /// What our current gravity state is. Used to avoid duplicate animates and such var/gravity_state = null + + /// Body temp we homeostasize to + var/standard_body_temperature = BODYTEMP_NORMAL + /// Temperature of our insides + var/bodytemperature = BODYTEMP_NORMAL + /// Lazylist of targets we homeostasize to + /// This allows multiple effects to add a different target to the list, which is averaged + /// (So you can have both a fever and a cold at the same time) + /// If empty just defaults to standard_body_temperature + var/list/homeostasis_targets + + /// How cold to start sustaining cold damage + var/bodytemp_cold_damage_limit = -1 // -1 = no cold damage ever + /// How hot to start sustaining heat damage + var/bodytemp_heat_damage_limit = INFINITY // INFINITY = no heat damage ever + + /// How fast the mob's temperature normalizes to their environment + var/temperature_normalization_speed = 0.1 + /// How fast the mob's temperature normalizes to their homeostasis + /// Also gets multiplied by metabolism_efficiency. + /// Note that more of this = more nutrition is consumed every life tick. + var/temperature_homeostasis_speed = 0.5 + /// Protection (insulation) from temperature changes, max 1 + var/temperature_insulation = 0 + + /// Whether we currently have temp alerts, minor optimization + VAR_PRIVATE/temp_alerts = FALSE diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm index 765e124d4e1f..7025795385d9 100644 --- a/code/modules/mob/living/living_say.dm +++ b/code/modules/mob/living/living_say.dm @@ -267,7 +267,7 @@ GLOBAL_LIST_INIT(message_modes_stat_limits, list( if(succumbed) succumb(TRUE) to_chat(src, compose_message(src, language, message, , spans, message_mods)) - + talkcount++ return TRUE /mob/living/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list(), message_range=0) diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 9101a2ec6049..a3f79cf4f1df 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -10,8 +10,8 @@ damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD, DIAG_BATT_HUD, DIAG_PATH_HUD = HUD_LIST_LIST) - maxbodytemp = INFINITY - minbodytemp = 0 + bodytemp_heat_damage_limit = INFINITY + bodytemp_cold_damage_limit = -1 has_unlimited_silicon_privilege = TRUE sentience_type = SENTIENCE_ARTIFICIAL status_flags = NONE //no default canpush diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm index bd27c482caf0..d40f8513b8f8 100644 --- a/code/modules/mob/living/simple_animal/friendly/cat.dm +++ b/code/modules/mob/living/simple_animal/friendly/cat.dm @@ -15,8 +15,8 @@ pass_flags = PASSTABLE mob_size = MOB_SIZE_SMALL mob_biotypes = MOB_ORGANIC|MOB_BEAST - minbodytemp = 200 - maxbodytemp = 400 + bodytemp_cold_damage_limit = 200 + bodytemp_heat_damage_limit = 400 unsuitable_atmos_damage = 0.5 animal_species = /mob/living/simple_animal/pet/cat childtype = list(/mob/living/simple_animal/pet/cat/kitten = 1) @@ -59,8 +59,8 @@ icon_living = "spacecat" icon_dead = "spacecat_dead" unsuitable_atmos_damage = 0 - minbodytemp = TCMB - maxbodytemp = T0C + 40 + bodytemp_cold_damage_limit = TCMB + bodytemp_heat_damage_limit = T0C + 40 held_state = "spacecat" /mob/living/simple_animal/pet/cat/breadcat diff --git a/code/modules/mob/living/simple_animal/friendly/gondola.dm b/code/modules/mob/living/simple_animal/friendly/gondola.dm index 80e89dd08d75..fb7e16bdab36 100644 --- a/code/modules/mob/living/simple_animal/friendly/gondola.dm +++ b/code/modules/mob/living/simple_animal/friendly/gondola.dm @@ -23,8 +23,8 @@ loot = list(/obj/effect/decal/cleanable/blood/gibs, /obj/item/stack/sheet/animalhide/gondola = 1, /obj/item/food/meat/slab/gondola = 1) //Gondolas aren't affected by cold. atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 - maxbodytemp = 1500 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 1500 maxHealth = 200 health = 200 del_on_death = TRUE diff --git a/code/modules/mob/living/simple_animal/friendly/pet.dm b/code/modules/mob/living/simple_animal/friendly/pet.dm index 2c509d799ee0..5b8e69277675 100644 --- a/code/modules/mob/living/simple_animal/friendly/pet.dm +++ b/code/modules/mob/living/simple_animal/friendly/pet.dm @@ -55,7 +55,7 @@ . += mutable_appearance(icon, "[collar_icon_state][stat_tag]collar") . += mutable_appearance(icon, "[collar_icon_state][stat_tag]tag") -/mob/living/simple_animal/pet/gib() +/mob/living/simple_animal/pet/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) . = ..() if(access_card) diff --git a/code/modules/mob/living/simple_animal/hostile/alien.dm b/code/modules/mob/living/simple_animal/hostile/alien.dm index a60ce8e9ca1c..0026868cdb70 100644 --- a/code/modules/mob/living/simple_animal/hostile/alien.dm +++ b/code/modules/mob/living/simple_animal/hostile/alien.dm @@ -26,7 +26,7 @@ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) faction = list(ROLE_ALIEN) status_flags = CANPUSH - minbodytemp = 0 + bodytemp_cold_damage_limit = -1 unsuitable_heat_damage = 20 // Going for a dark purple here lighting_cutoff_red = 30 diff --git a/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm b/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm index 9b1c85502497..84d3570bb022 100644 --- a/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm +++ b/code/modules/mob/living/simple_animal/hostile/dark_wizard.dm @@ -27,8 +27,8 @@ faction = list(ROLE_WIZARD) footstep_type = FOOTSTEP_MOB_SHOE weather_immunities = list(TRAIT_LAVA_IMMUNE, TRAIT_ASHSTORM_IMMUNE) - minbodytemp = 0 - maxbodytemp = INFINITY + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = INFINITY atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) loot = list(/obj/effect/decal/remains/human) del_on_death = TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm b/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm index dd0d3de071d2..acd51b0f4053 100644 --- a/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/jungle/_jungle_mobs.dm @@ -4,8 +4,8 @@ faction = list(FACTION_JUNGLE) obj_damage = 30 environment_smash = ENVIRONMENT_SMASH_WALLS - minbodytemp = 0 - maxbodytemp = 450 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 450 response_harm_continuous = "strikes" response_harm_simple = "strike" status_flags = NONE diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm index 689e1391bfd6..0a5d062069d1 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/_megafauna.dm @@ -16,8 +16,8 @@ stat_attack = DEAD atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) damage_coeff = list(BRUTE = 1, BURN = 0.5, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) - minbodytemp = 0 - maxbodytemp = INFINITY + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = INFINITY vision_range = 5 aggro_vision_range = 18 move_force = MOVE_FORCE_OVERPOWERING @@ -95,7 +95,7 @@ /mob/living/simple_animal/hostile/megafauna/proc/spawn_crusher_loot() loot = crusher_loot -/mob/living/simple_animal/hostile/megafauna/gib() +/mob/living/simple_animal/hostile/megafauna/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) if(health > 0) return diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm index ec90fa9fa7bb..7a6750309572 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm @@ -356,6 +356,12 @@ Difficulty: Hard /obj/effect/decal/cleanable/blood/bubblegum bloodiness = 0 + base_name = "" + can_dry = FALSE + +/obj/effect/decal/cleanable/blood/bubblegum/Initialize(mapload, list/datum/disease/diseases) + . = ..() + add_blood_DNA(list("DEMON BLOOD" = /datum/blood_type/animal)) /obj/effect/decal/cleanable/blood/bubblegum/can_bloodcrawl_in() return TRUE @@ -365,6 +371,12 @@ Difficulty: Hard desc = "Thick, splattered blood." random_icon_states = list("gib3", "gib5", "gib6") bloodiness = 20 + base_name = "" + can_dry = FALSE + +/obj/effect/decal/cleanable/blood/gibs/bubblegum/Initialize(mapload, list/datum/disease/diseases) + . = ..() + add_blood_DNA(list("DEMON BLOOD" = /datum/blood_type/animal)) /obj/effect/decal/cleanable/blood/gibs/bubblegum/can_bloodcrawl_in() return TRUE diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm index 10d21416f355..17cca2468595 100644 --- a/code/modules/mob/living/simple_animal/hostile/mimic.dm +++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm @@ -25,7 +25,7 @@ taunt_chance = 30 atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 + bodytemp_cold_damage_limit = -1 faction = list(FACTION_MIMIC) move_to_delay = 9 diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm index 242b178b82f2..63b19d5018fc 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/mining_mobs.dm @@ -6,8 +6,8 @@ weather_immunities = list(TRAIT_LAVA_IMMUNE,TRAIT_ASHSTORM_IMMUNE) obj_damage = 30 environment_smash = ENVIRONMENT_SMASH_WALLS - minbodytemp = 0 - maxbodytemp = INFINITY + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = INFINITY unsuitable_heat_damage = 20 response_harm_continuous = "strikes" response_harm_simple = "strike" diff --git a/code/modules/mob/living/simple_animal/hostile/ooze.dm b/code/modules/mob/living/simple_animal/hostile/ooze.dm index 99a94a1197a8..b88c16c2319b 100644 --- a/code/modules/mob/living/simple_animal/hostile/ooze.dm +++ b/code/modules/mob/living/simple_animal/hostile/ooze.dm @@ -12,8 +12,8 @@ speak_emote = list("blorbles") atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) hud_type = /datum/hud/ooze - minbodytemp = 250 - maxbodytemp = INFINITY + bodytemp_cold_damage_limit = 250 + bodytemp_heat_damage_limit = INFINITY faction = list(FACTION_SLIME) melee_damage_lower = 10 melee_damage_upper = 10 @@ -175,7 +175,7 @@ ///Heat up the mob a little /datum/action/cooldown/metabolicboost/proc/HeatUp() var/mob/living/simple_animal/hostile/ooze/ooze = owner - ooze.adjust_bodytemperature(50) + ooze.adjust_bodytemperature(3.33 KELVIN) ///Remove the speed modifier and delete the timer for heating up /datum/action/cooldown/metabolicboost/proc/FinishSpeedup(timerid) diff --git a/code/modules/mob/living/simple_animal/hostile/pirate.dm b/code/modules/mob/living/simple_animal/hostile/pirate.dm index eefac18f30c2..2a05df3d63d8 100644 --- a/code/modules/mob/living/simple_animal/hostile/pirate.dm +++ b/code/modules/mob/living/simple_animal/hostile/pirate.dm @@ -57,7 +57,7 @@ /mob/living/simple_animal/hostile/pirate/melee/space name = "Space Pirate Swashbuckler" atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 + bodytemp_cold_damage_limit = -1 speed = 1 mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/melee/space @@ -81,7 +81,7 @@ /mob/living/simple_animal/hostile/pirate/ranged/space name = "Space Pirate Gunner" atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 + bodytemp_cold_damage_limit = -1 speed = 1 mob_spawner = /obj/effect/mob_spawn/corpse/human/pirate/ranged/space held_item = /obj/item/gun/energy/e_gun/lethal diff --git a/code/modules/mob/living/simple_animal/hostile/zombie.dm b/code/modules/mob/living/simple_animal/hostile/zombie.dm index c8c03989a595..b4c71f7cc4c1 100644 --- a/code/modules/mob/living/simple_animal/hostile/zombie.dm +++ b/code/modules/mob/living/simple_animal/hostile/zombie.dm @@ -17,7 +17,7 @@ attack_vis_effect = ATTACK_EFFECT_BITE istate = ISTATE_HARM|ISTATE_BLOCKING atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minbodytemp = 0 + bodytemp_cold_damage_limit = -1 status_flags = CANPUSH death_message = "collapses, flesh gone in a pile of bones!" del_on_death = TRUE diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 0bb3664e5c02..9ff9a0cf3def 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -58,10 +58,8 @@ ///How much stamina the mob recovers per second var/stamina_recovery = 5 - ///Minimal body temperature without receiving damage - var/minbodytemp = NPC_DEFAULT_MIN_TEMP - ///Maximal body temperature without receiving damage - var/maxbodytemp = NPC_DEFAULT_MAX_TEMP + bodytemp_cold_damage_limit = NPC_DEFAULT_MIN_TEMP + bodytemp_heat_damage_limit = NPC_DEFAULT_MAX_TEMP ///This damage is taken when the body temp is too cold. var/unsuitable_cold_damage ///This damage is taken when the body temp is too hot. @@ -79,9 +77,6 @@ ///This damage is taken when atmos doesn't fit all the requirements above. var/unsuitable_atmos_damage = 1 - ///How fast the mob's temperature normalizes. The greater the value, the slower their temperature normalizes. Should always be greater than 0. - var/temperature_normalization_speed = 5 - //Defaults to zero so Ian can still be cuddly. Moved up the tree to living! This allows us to bypass some hardcoded stuff. melee_damage_lower = 0 melee_damage_upper = 0 @@ -343,20 +338,11 @@ /mob/living/simple_animal/proc/environment_temperature_is_safe(datum/gas_mixture/environment) . = TRUE var/areatemp = get_temperature(environment) - if((areatemp < minbodytemp) || (areatemp > maxbodytemp)) + if((areatemp < bodytemp_cold_damage_limit) || (areatemp > bodytemp_heat_damage_limit)) . = FALSE /mob/living/simple_animal/handle_environment(datum/gas_mixture/environment, seconds_per_tick, times_fired) - var/atom/A = loc - if(isturf(A)) - var/areatemp = get_temperature(environment) - var/temp_delta = areatemp - bodytemperature - if(abs(temp_delta) > 5) - if(temp_delta < 0) - if(!on_fire) - adjust_bodytemperature(clamp(temp_delta * seconds_per_tick / temperature_normalization_speed, temp_delta, 0)) - else - adjust_bodytemperature(clamp(temp_delta * seconds_per_tick / temperature_normalization_speed, 0, temp_delta)) + . = ..() if(!environment_air_is_safe() && unsuitable_atmos_damage) adjustHealth(unsuitable_atmos_damage * seconds_per_tick) @@ -365,12 +351,16 @@ else clear_alert(ALERT_NOT_ENOUGH_OXYGEN) - handle_temperature_damage(seconds_per_tick, times_fired) -/mob/living/simple_animal/proc/handle_temperature_damage(seconds_per_tick, times_fired) - . = FALSE - if((bodytemperature < minbodytemp) && unsuitable_cold_damage) +/mob/living/simple_animal/body_temperature_damage(datum/gas_mixture/environment, seconds_per_tick, times_fired) + if((bodytemperature < bodytemp_cold_damage_limit) && unsuitable_cold_damage) adjustHealth(unsuitable_cold_damage * seconds_per_tick) + + if((bodytemperature > bodytemp_heat_damage_limit) && unsuitable_heat_damage) + adjustHealth(unsuitable_heat_damage * seconds_per_tick) + +/mob/living/simple_animal/body_temperature_alerts() + if((bodytemperature < bodytemp_cold_damage_limit) && unsuitable_cold_damage) switch(unsuitable_cold_damage) if(1 to 5) throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 1) @@ -380,8 +370,7 @@ throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 3) . = TRUE - if((bodytemperature > maxbodytemp) && unsuitable_heat_damage) - adjustHealth(unsuitable_heat_damage * seconds_per_tick) + if((bodytemperature > bodytemp_heat_damage_limit) && unsuitable_heat_damage) switch(unsuitable_heat_damage) if(1 to 5) throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 1) @@ -394,7 +383,7 @@ if(!.) clear_alert(ALERT_TEMPERATURE) -/mob/living/simple_animal/gib() +/mob/living/simple_animal/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) if(butcher_results || guaranteed_butcher_results) var/list/butcher = list() if(butcher_results) diff --git a/code/modules/mob/living/taste.dm b/code/modules/mob/living/taste.dm index fc8fcbb37176..b6edde37d1e4 100644 --- a/code/modules/mob/living/taste.dm +++ b/code/modules/mob/living/taste.dm @@ -21,7 +21,10 @@ // carbons without tongues normally have TRAIT_AGEUSIA but sensible fallback . = DEFAULT_TASTE_SENSITIVITY -// non destructively tastes a reagent container +/** + * Non destructively tastes a reagent container + * and gives feedback to the user. + **/ /mob/living/proc/taste(datum/reagents/from) if(HAS_TRAIT(src, TRAIT_AGEUSIA)) return @@ -43,4 +46,70 @@ last_taste_time = world.time last_taste_text = text_output +/** + * Gets food flags that this mob likes + **/ +/mob/living/proc/get_liked_foodtypes() + return NONE + +/mob/living/carbon/get_liked_foodtypes() + var/obj/item/organ/internal/tongue/tongue = get_organ_slot(ORGAN_SLOT_TONGUE) + // No tongue, no tastin' + if(!tongue?.sense_of_taste || HAS_TRAIT(src, TRAIT_AGEUSIA)) + return NONE + return tongue.liked_foodtypes + +/** + * Gets food flags that this mob dislikes + **/ +/mob/living/proc/get_disliked_foodtypes() + return NONE + +/mob/living/carbon/get_disliked_foodtypes() + var/obj/item/organ/internal/tongue/tongue = get_organ_slot(ORGAN_SLOT_TONGUE) + // No tongue, no tastin' + if(!tongue?.sense_of_taste || HAS_TRAIT(src, TRAIT_AGEUSIA)) + return NONE + return tongue.disliked_foodtypes + +/** + * Gets food flags that this mob hates + * Toxic food is the only category that ignores ageusia, KEEP IT LIKE THAT! + **/ +/mob/living/proc/get_toxic_foodtypes() + return TOXIC + +/mob/living/carbon/get_toxic_foodtypes() + var/obj/item/organ/internal/tongue/tongue = get_organ_slot(ORGAN_SLOT_TONGUE) + // No tongue, no tastin' + if(!tongue) + return TOXIC + return tongue.toxic_foodtypes + +/** + * Gets the food reaction a mob would normally have from the given food item, + * assuming that no check_liked callback was used in the edible component. + * + * Does not get called if the owner has ageusia. + **/ +/mob/living/proc/get_food_taste_reaction(obj/item/food, foodtypes) + var/food_taste_reaction + if(foodtypes & get_toxic_foodtypes()) + food_taste_reaction = FOOD_TOXIC + else if(foodtypes & get_disliked_foodtypes()) + food_taste_reaction = FOOD_DISLIKED + else if(foodtypes & get_liked_foodtypes()) + food_taste_reaction = FOOD_LIKED + return food_taste_reaction + +/mob/living/carbon/get_food_taste_reaction(obj/item/food, foodtypes) + var/obj/item/organ/internal/tongue/tongue = get_organ_slot(ORGAN_SLOT_TONGUE) + // No tongue, no tastin' + if(!tongue?.sense_of_taste || HAS_TRAIT(src, TRAIT_AGEUSIA)) + // i hate that i have to do this, but we want to ensure toxic food is still BAD + if(foodtypes & get_toxic_foodtypes()) + return FOOD_TOXIC + return + return tongue.get_food_taste_reaction(food, foodtypes) + #undef DEFAULT_TASTE_SENSITIVITY diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 1c70f7dd637a..ea0fee8f9dfb 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1443,6 +1443,11 @@ stat = new_stat SEND_SIGNAL(src, COMSIG_MOB_STATCHANGE, new_stat, .) +/// Proc used for custom metabolization of reagents, if any +/mob/proc/reagent_check(datum/reagent/chem, seconds_per_tick, times_fired) + SHOULD_CALL_PARENT(TRUE) + return SEND_SIGNAL(src, COMSIG_MOB_REAGENT_CHECK, chem, seconds_per_tick, times_fired) + /mob/vv_edit_var(var_name, var_value) switch(var_name) if(NAMEOF(src, control_object)) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 55e1dfebe38e..339acb74409a 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -99,11 +99,6 @@ */ var/name_archive //For admin things like possession - /// Default body temperature - var/bodytemperature = BODYTEMP_NORMAL //310.15K / 98.6F - /// Our body temperatue as of the last process, prevents pointless work when handling alerts - var/old_bodytemperature = 0 - /// Hunger level of the mob var/nutrition = NUTRITION_LEVEL_START_MIN // randomised in Initialize /// Satiation level of the mob diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 66040d76527a..109d4a0376b4 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -240,11 +240,6 @@ // Else, return FALSE. return (faker && allow_fake_antags) - -/mob/proc/reagent_check(datum/reagent/R, seconds_per_tick, times_fired) // utilized in the species code - return TRUE - - /** * Fancy notifications for ghosts * diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm index 1dde25c7802f..9cbc06a5c366 100644 --- a/code/modules/mob/status_procs.dm +++ b/code/modules/mob/status_procs.dm @@ -8,11 +8,6 @@ /mob/proc/set_disgust(amount) return -///Adjust the body temperature of a mob, with min/max settings -/mob/proc/adjust_bodytemperature(amount,min_temp=0,max_temp=INFINITY) - if(bodytemperature >= min_temp && bodytemperature <= max_temp) - bodytemperature = clamp(bodytemperature + amount,min_temp,max_temp) - /// Sight here is the mob.sight var, which tells byond what to actually show to our client /// See [code\__DEFINES\sight.dm] for more details /mob/proc/set_sight(new_value) diff --git a/code/modules/mod/mod_activation.dm b/code/modules/mod/mod_activation.dm index 2745033c2a59..deb79a011c8a 100644 --- a/code/modules/mod/mod_activation.dm +++ b/code/modules/mod/mod_activation.dm @@ -195,16 +195,16 @@ part.clothing_flags |= part.visor_flags part.flags_inv |= part.visor_flags_inv part.flags_cover |= part.visor_flags_cover - part.heat_protection = initial(part.heat_protection) - part.cold_protection = initial(part.cold_protection) + part.min_cold_protection_temperature = theme.min_cold_protection_temperature + part.max_heat_protection_temperature = theme.max_heat_protection_temperature part.alternate_worn_layer = null else part.icon_state = "[skin]-[part.base_icon_state]" part.flags_cover &= ~part.visor_flags_cover part.flags_inv &= ~part.visor_flags_inv part.clothing_flags &= ~part.visor_flags - part.heat_protection = NONE - part.cold_protection = NONE + part.min_cold_protection_temperature = null + part.max_heat_protection_temperature = null part.alternate_worn_layer = mod_parts[part] if(part == boots) wearer.update_worn_shoes() diff --git a/code/modules/mod/mod_clothes.dm b/code/modules/mod/mod_clothes.dm index b9e09fd7bcaf..8bdcf3a6fb93 100644 --- a/code/modules/mod/mod_clothes.dm +++ b/code/modules/mod/mod_clothes.dm @@ -8,8 +8,8 @@ worn_icon_snouted = 'monkestation/icons/mob/mod.dmi' armor_type = /datum/armor/none body_parts_covered = HEAD - heat_protection = HEAD - cold_protection = HEAD + + item_flags = IMMUTABLE_SLOW supports_variations_flags = CLOTHING_SNOUTED_VARIATION clothing_traits = list(TRAIT_SNOWSTORM_IMMUNE) @@ -30,8 +30,8 @@ ) armor_type = /datum/armor/none body_parts_covered = CHEST|GROIN - heat_protection = CHEST|GROIN - cold_protection = CHEST|GROIN + + item_flags = IMMUTABLE_SLOW supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION clothing_traits = list(TRAIT_SNOWSTORM_IMMUNE) @@ -45,8 +45,8 @@ worn_icon = 'icons/mob/clothing/modsuit/mod_clothing.dmi' armor_type = /datum/armor/none body_parts_covered = HANDS|ARMS - heat_protection = HANDS|ARMS - cold_protection = HANDS|ARMS + + item_flags = IMMUTABLE_SLOW supports_variations_flags = NONE @@ -60,8 +60,8 @@ worn_icon_digitigrade = 'monkestation/icons/mob/mod.dmi' armor_type = /datum/armor/none body_parts_covered = FEET|LEGS - heat_protection = FEET|LEGS - cold_protection = FEET|LEGS + + item_flags = IMMUTABLE_SLOW item_flags = IGNORE_DIGITIGRADE can_be_tied = FALSE diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm index 85ddee1a08cd..14eaf71133e8 100644 --- a/code/modules/mod/mod_control.dm +++ b/code/modules/mod/mod_control.dm @@ -125,8 +125,6 @@ part.set_armor(theme.armor_type) part.resistance_flags = theme.resistance_flags part.flags_1 |= theme.atom_flags //flags like initialization or admin spawning are here, so we cant set, have to add - part.heat_protection = NONE - part.cold_protection = NONE part.max_heat_protection_temperature = theme.max_heat_protection_temperature part.min_cold_protection_temperature = theme.min_cold_protection_temperature part.siemens_coefficient = theme.siemens_coefficient @@ -655,12 +653,6 @@ part.visor_flags_cover = category[SEALED_COVER] || NONE part.alternate_worn_layer = category[UNSEALED_LAYER] mod_parts[part] = part.alternate_worn_layer - if(!category[CAN_OVERSLOT]) - if(overslotting_parts[part]) - var/obj/item/overslot = overslotting_parts[part] - overslot.forceMove(drop_location()) - overslotting_parts -= part - continue overslotting_parts |= part wearer?.regenerate_icons() diff --git a/code/modules/mod/modules/modules_general.dm b/code/modules/mod/modules/modules_general.dm index 5069bddbee57..b39c9b0fe0e2 100644 --- a/code/modules/mod/modules/modules_general.dm +++ b/code/modules/mod/modules/modules_general.dm @@ -432,7 +432,7 @@ /// Minimum temperature we can set. var/min_temp = 293.15 /// Maximum temperature we can set. - var/max_temp = 318.15 + var/max_temp = T20C * 2.25 /obj/item/mod/module/thermal_regulator/get_configuration() . = ..() @@ -444,7 +444,11 @@ temperature_setting = clamp(value + T0C, min_temp, max_temp) /obj/item/mod/module/thermal_regulator/on_active_process(seconds_per_tick) - mod.wearer.adjust_bodytemperature(get_temp_change_amount((temperature_setting - mod.wearer.bodytemperature), 0.08 * seconds_per_tick)) + var/mob/living/user = mod.wearer + if(user.bodytemperature < temperature_setting) + user.adjust_bodytemperature((temperature_setting - user.bodytemperature) * 0.08 * seconds_per_tick, max_temp = temperature_setting) + else if(user.bodytemperature > temperature_setting) + user.adjust_bodytemperature((temperature_setting - user.bodytemperature) * 0.08 * seconds_per_tick, min_temp = temperature_setting) ///DNA Lock - Prevents people without the set DNA from activating the suit. /obj/item/mod/module/dna_lock diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm index 5135c430130a..4146588d7d93 100644 --- a/code/modules/modular_computers/computers/item/computer_ui.dm +++ b/code/modules/modular_computers/computers/item/computer_ui.dm @@ -122,7 +122,7 @@ if(ishuman(usr) && !allow_chunky) var/mob/living/carbon/human/human_user = usr - if(human_user.check_chunky_fingers()) + if(HAS_TRAIT(human_user, TRAIT_CHUNKYFINGERS)) balloon_alert(human_user, "fingers are too big!") return TRUE diff --git a/code/modules/movespeed/modifiers/innate.dm b/code/modules/movespeed/modifiers/innate.dm index 46fc82269eac..2a55b9db4d79 100644 --- a/code/modules/movespeed/modifiers/innate.dm +++ b/code/modules/movespeed/modifiers/innate.dm @@ -6,7 +6,7 @@ multiplicative_slowdown = 2 flags = IGNORE_NOSLOW -/datum/movespeed_modifier/species +/datum/movespeed_modifier/bodypart movetypes = ~FLYING variable = TRUE diff --git a/code/modules/pai/pai.dm b/code/modules/pai/pai.dm index b7d6719cc0c3..35229887c86b 100644 --- a/code/modules/pai/pai.dm +++ b/code/modules/pai/pai.dm @@ -267,11 +267,6 @@ . = ..() update_stat() -/mob/living/silicon/pai/on_knockedout_trait_loss(datum/source) - . = ..() - set_stat(CONSCIOUS) - update_stat() - /** * Resolves the weakref of the pai's master. * If the master has been deleted, calls reset_software(). diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index 713d2699a4c6..78391d77a03f 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -360,9 +360,9 @@ var/icon/temp_img if(ishuman(ass)) var/mob/living/carbon/human/H = ass - var/datum/species/spec = H.dna.species - if(spec.ass_image) - temp_img = icon(spec.ass_image) + var/obj/item/bodypart/chest/chest = H.get_bodypart(BODY_ZONE_CHEST) + if(chest.ass_image) + temp_img = icon(chest.ass_image) else temp_img = icon(ass.gender == FEMALE ? 'icons/ass/assfemale.png' : 'icons/ass/assmale.png') else if(isalienadult(ass)) //Xenos have their own asses, thanks to Pybro. diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index 2b11cc00d08c..c7ed9646a422 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -251,7 +251,7 @@ if(charge < CELL_POWER_DRAIN) to_chat(H, span_warning("[src] doesn't have enough power!")) return - if(stomach.crystal_charge > charge_limit) + if(H.blood_volume > charge_limit) to_chat(H, span_warning("Your charge is full!")) return to_chat(H, span_notice("You begin clumsily channeling power from [src] into your body.")) diff --git a/code/modules/power/lighting/light.dm b/code/modules/power/lighting/light.dm index 55b070e02fda..09c2e1fb2aa0 100644 --- a/code/modules/power/lighting/light.dm +++ b/code/modules/power/lighting/light.dm @@ -569,7 +569,7 @@ if(user.gloves) var/obj/item/clothing/gloves/electrician_gloves = user.gloves - if(electrician_gloves.max_heat_protection_temperature && electrician_gloves.max_heat_protection_temperature > 360) + if(electrician_gloves.max_heat_protection_temperature > 360) protected = TRUE else protected = TRUE diff --git a/code/modules/projectiles/ammunition/_firing.dm b/code/modules/projectiles/ammunition/_firing.dm index c911da396b36..fc59c5911c35 100644 --- a/code/modules/projectiles/ammunition/_firing.dm +++ b/code/modules/projectiles/ammunition/_firing.dm @@ -1,3 +1,16 @@ + +/** + * Fires the bullet in this casing + * + * * target - what was clicked on (where the bullet will go) + * * user - who is firing the bullet + * * params - click params. like x, y, shift, etc + * * distro - how much the bullet will spread + * * quiet - if the bullet is suppressed + * * zone_override - optional, the zone the bullet will aim for. if not supplied, uses the user's selected zone + * * spread - how much the bullet will spread + * * fired_from - the object that fired the bullet + */ /obj/item/ammo_casing/proc/fire_casing(atom/target, mob/living/user, params, distro, quiet, zone_override, spread, atom/fired_from) distro += variance var/targloc = get_turf(target) @@ -44,10 +57,7 @@ loaded_projectile.firer = user loaded_projectile.fired_from = fired_from loaded_projectile.hit_prone_targets = (user.istate & ISTATE_HARM) - if (zone_override) - loaded_projectile.def_zone = zone_override - else - loaded_projectile.def_zone = user.zone_selected + loaded_projectile.def_zone = zone_override || user.zone_selected loaded_projectile.suppressed = quiet if(isgun(fired_from)) diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 35ca181378e7..c3f0a45e2aa4 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -16,12 +16,15 @@ blocks_emissive = EMISSIVE_BLOCK_GENERIC layer = MOB_LAYER plane = GAME_PLANE_FOV_HIDDEN + var/generic_name //The sound this plays on impact. var/hitsound = 'sound/weapons/pierce.ogg' var/hitsound_wall = "" resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF var/def_zone = "" //Aiming at + /// Set to TRUE if we're grazing, which affects the message / embed chance / damage / effects + var/grazing = FALSE var/atom/movable/firer = null//Who shot it var/datum/fired_from = null // the thing that the projectile was fired from (gun, turret, spell) var/suppressed = FALSE //Attack message @@ -171,6 +174,8 @@ var/drowsy = 0 SECONDS /// Jittering applied on projectile hit var/jitter = 0 SECONDS + /// Bonus pain, like stamina damage + var/pain = 0 /// Extra stamina damage applied on projectile hit (in addition to the main damage) var/stamina = 0 /// Stuttering applied on projectile hit @@ -230,17 +235,6 @@ SEND_SIGNAL(src, COMSIG_PROJECTILE_RANGE_OUT) qdel(src) -/// Returns the string form of the def_zone we have hit. -/mob/living/proc/check_hit_limb_zone_name(hit_zone) - if(has_limbs) - return hit_zone - -/mob/living/carbon/check_hit_limb_zone_name(hit_zone) - if(get_bodypart(hit_zone)) - return hit_zone - else //when a limb is missing the damage is actually passed to the chest - return BODY_ZONE_CHEST - /** * Called when the projectile hits something * @@ -262,13 +256,17 @@ // i know that this is probably more with wands and gun mods in mind, but it's a bit silly that the projectile on_hit signal doesn't ping the projectile itself. // maybe we care what the projectile thinks! See about combining these via args some time when it's not 5AM - var/hit_limb_zone - if(isliving(target)) - var/mob/living/L = target - hit_limb_zone = L.check_hit_limb_zone_name(def_zone) + if(stamina >= 10 && isliving(target)) + var/mob/living/living = target + var/datum/status_effect/stacking/debilitated/effect = living.has_status_effect(/datum/status_effect/stacking/debilitated) + if(effect) + effect.add_stacks(1) + else + living.apply_status_effect(/datum/status_effect/stacking/debilitated, 1) + if(fired_from) - SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle, hit_limb_zone) - SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle, hit_limb_zone) + SEND_SIGNAL(fired_from, COMSIG_PROJECTILE_ON_HIT, firer, target, Angle, def_zone, blocked) + SEND_SIGNAL(src, COMSIG_PROJECTILE_SELF_ON_HIT, firer, target, Angle, def_zone, blocked) if(QDELETED(src)) // in case one of the above signals deleted the projectile for whatever reason return BULLET_ACT_BLOCK @@ -283,18 +281,18 @@ hitx = target.pixel_x + rand(-8, 8) hity = target.pixel_y + rand(-8, 8) - if(damage > 0 && (damage_type == BRUTE || damage_type == BURN) && iswallturf(target_turf) && prob(75)) - var/turf/closed/wall/target_wall = target_turf - if(impact_effect_type && !hitscan) - new impact_effect_type(target_wall, hitx, hity) - - target_wall.add_dent(WALL_DENT_SHOT, hitx, hity) - - return BULLET_ACT_HIT + if((isturf(target) || (isobj(target) && target.density)) && hitsound_wall) + var/volume = clamp(vol_by_damage() + 20, 0, 100) + if(suppressed) + volume = 5 + playsound(loc, hitsound_wall, volume, TRUE, -1) if(!isliving(target)) if(impact_effect_type && !hitscan) new impact_effect_type(target_turf, hitx, hity) + if(damage > 0 && (damage_type == BRUTE || damage_type == BURN) && iswallturf(target_turf) && prob(75)) + var/turf/closed/wall/target_wall = target_turf + target_wall.add_dent(WALL_DENT_SHOT, hitx, hity) if(isturf(target) && hitsound_wall) var/volume = clamp(vol_by_damage() + 20, 0, 100) if(suppressed) @@ -305,16 +303,13 @@ var/mob/living/living_target = target if(blocked != 100) // not completely blocked - var/obj/item/bodypart/hit_bodypart = living_target.get_bodypart(hit_limb_zone) + var/obj/item/bodypart/hit_bodypart = living_target.get_bodypart(def_zone) if (damage) if (living_target.blood_volume && damage_type == BRUTE && (isnull(hit_bodypart) || hit_bodypart.can_bleed())) var/splatter_dir = dir if(starting) splatter_dir = get_dir(starting, target_turf) - if(isalien(living_target)) - new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target_turf, splatter_dir) - else - new /obj/effect/temp_visual/dir_setting/bloodsplatter(target_turf, splatter_dir) + living_target.do_splatter_effect(splatter_dir) if(prob(damage)) living_target.blood_particles(amount = rand(1, 1 + round(damage/20, 1)), angle = src.Angle) @@ -330,19 +325,21 @@ new impact_effect_type(target_turf, hitx, hity) var/organ_hit_text = "" - if(hit_limb_zone) - organ_hit_text = " in \the [parse_zone(hit_limb_zone)]" + if(def_zone) + organ_hit_text = " in \the [parse_zone(def_zone)]" if(suppressed == SUPPRESSED_VERY) playsound(loc, hitsound, 5, TRUE, -1) else if(suppressed) playsound(loc, hitsound, 5, TRUE, -1) - to_chat(living_target, span_userdanger("You're shot by \a [src][organ_hit_text]!")) + to_chat(living_target, span_userdanger("You're [grazing ? "grazed" : "hit"] by \a [generic_name || src][organ_hit_text]!")) else - if(hitsound) - var/volume = vol_by_damage() - playsound(src, hitsound, volume, TRUE, -1) - living_target.visible_message(span_danger("[living_target] is hit by \a [src][organ_hit_text]!"), \ - span_userdanger("You're hit by \a [src][organ_hit_text]!"), null, COMBAT_MESSAGE_RANGE) + playsound(loc, hitsound, vol_by_damage(), TRUE, -1) + living_target.visible_message( + span_danger("[living_target] is [grazing ? "grazed" : "hit"] by \a [generic_name || src][organ_hit_text]!"), + span_userdanger("You're [grazing ? "grazed" : "hit"] by \a [generic_name || src][organ_hit_text]!"), + span_hear("You hear a woosh."), + // vision_distance = COMBAT_MESSAGE_RANGE, + ) if(living_target.is_blind()) to_chat(living_target, span_userdanger("You feel something hit you[organ_hit_text]!")) @@ -473,8 +470,19 @@ store_hitscan_collision(point_cache) return TRUE - var/distance = get_dist(T, starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations. - def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use. + if(!HAS_TRAIT(src, TRAIT_ALWAYS_HIT_ZONE) && isliving(A)) + var/mob/living/who_is_shot = A + var/distance = decayedRange - range + var/hit_prob = max(100 - (7 * distance), 5) + if(who_is_shot.body_position == LYING_DOWN) + hit_prob *= 1.2 + // melbert todo : make people more skilled with weapons have a lower miss chance + if(!prob(hit_prob)) + def_zone = who_is_shot.get_random_valid_zone(def_zone, 0) // Lower accurancy/longer range tradeoff. 7 is a balanced number to use. + grazing = !prob(hit_prob) // jeez you missed twice? that's a graze + if(grazing) + wound_bonus = CANT_WOUND + bare_wound_bonus = CANT_WOUND return process_hit(T, select_target(T, A, A), A) // SELECT TARGET FIRST! @@ -600,7 +608,7 @@ var/mob/target_mob = target if(faction_check(target_mob.faction, ignored_factions)) return FALSE - if(target.density || cross_failed) //This thing blocks projectiles, hit it regardless of layer/mob stuns/etc. + if((target.density && !target.IsObscured()) || cross_failed) //This thing blocks projectiles, hit it regardless of layer/mob stuns/etc. return TRUE if(!isliving(target)) if(isturf(target)) // non dense turfs diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index 96c99fca0298..3266a8a309ee 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -21,6 +21,7 @@ /obj/projectile/beam/laser + generic_name = "laser beam" tracer_type = /obj/effect/projectile/tracer/laser muzzle_type = /obj/effect/projectile/muzzle/laser impact_type = /obj/effect/projectile/impact/laser @@ -77,6 +78,7 @@ /obj/projectile/beam/practice name = "practice laser" + generic_name = "practice laser beam" damage = 0 /obj/projectile/beam/scatter @@ -103,7 +105,7 @@ icon_state = "omnilaser" damage = 0 damage_type = STAMINA - stamina = 45 + stamina = 35 paralyze_timer = 5 SECONDS armor_flag = ENERGY impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser @@ -126,6 +128,7 @@ /obj/projectile/beam/pulse name = "pulse" + generic_name = "pulse beam" icon_state = "u_laser" damage = 50 impact_effect_type = /obj/effect/temp_visual/impact_effect/blue_laser diff --git a/code/modules/projectiles/projectile/bullets/lmg.dm b/code/modules/projectiles/projectile/bullets/lmg.dm index f6081c7b070c..c6099105affb 100644 --- a/code/modules/projectiles/projectile/bullets/lmg.dm +++ b/code/modules/projectiles/projectile/bullets/lmg.dm @@ -1,27 +1,33 @@ // C3D (Borgs) /obj/projectile/bullet/c3d + generic_name = "bullet" damage = 20 // Mech LMG /obj/projectile/bullet/lmg + generic_name = "bullet" damage = 20 // Mech FNX-99 /obj/projectile/bullet/incendiary/fnx99 + generic_name = "bullet" damage = 20 // Turrets /obj/projectile/bullet/manned_turret + generic_name = "bullet" damage = 20 /obj/projectile/bullet/manned_turret/hmg + generic_name = "bullet" icon_state = "redtrac" /obj/projectile/bullet/syndicate_turret + generic_name = "bullet" damage = 20 // 7.12x82mm (SAW) diff --git a/code/modules/projectiles/projectile/bullets/revolver.dm b/code/modules/projectiles/projectile/bullets/revolver.dm index 7028cc22446d..ace9489fdcbd 100644 --- a/code/modules/projectiles/projectile/bullets/revolver.dm +++ b/code/modules/projectiles/projectile/bullets/revolver.dm @@ -101,14 +101,16 @@ /obj/projectile/bullet/c38/iceblox //see /obj/projectile/temp for the original code name = ".38 Iceblox bullet" damage = 20 - var/temperature = 100 ricochets_max = 0 + /// How cold to chill the target down to + var/temperature = HYPOTHERMIA - 2 CELCIUS + /obj/projectile/bullet/c38/iceblox/on_hit(atom/target, blocked = 0, pierce_hit) . = ..() if(isliving(target)) var/mob/living/M = target - M.adjust_bodytemperature(((100-blocked)/100)*(temperature - M.bodytemperature)) + M.adjust_bodytemperature(0.34 * ((100-blocked) / 100) * (temperature - M.bodytemperature), use_insulation = TRUE) // .357 (Syndie Revolver) diff --git a/code/modules/projectiles/projectile/energy/stun.dm b/code/modules/projectiles/projectile/energy/stun.dm index 7f36bf437ed6..8c28138be38b 100644 --- a/code/modules/projectiles/projectile/energy/stun.dm +++ b/code/modules/projectiles/projectile/energy/stun.dm @@ -2,28 +2,41 @@ name = "electrode" icon_state = "spark" color = "#FFFF00" + /* paralyze = 10 SECONDS stutter = 10 SECONDS jitter = 40 SECONDS + */ hitsound = 'sound/weapons/taserhit.ogg' - range = 7 + range = 5 tracer_type = /obj/effect/projectile/tracer/stun muzzle_type = /obj/effect/projectile/muzzle/stun impact_type = /obj/effect/projectile/impact/stun /obj/projectile/energy/electrode/on_hit(atom/target, blocked = 0, pierce_hit) . = ..() - if(!ismob(target) || blocked >= 100) //Fully blocked by mob or collided with dense object - burst into sparks! - do_sparks(1, TRUE, src) - else if(iscarbon(target)) - var/mob/living/carbon/C = target - C.add_mood_event("tased", /datum/mood_event/tased) - SEND_SIGNAL(C, COMSIG_LIVING_MINOR_SHOCK) - if(C.dna && C.dna.check_mutation(/datum/mutation/human/hulk)) - C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk") - else if(!C.check_stun_immunity(CANKNOCKDOWN)) - addtimer(CALLBACK(C, TYPE_PROC_REF(/mob/living/carbon, do_jitter_animation), 20), 5) + if(pierce_hit) + return . + do_sparks(1, TRUE, src) + if(. == BULLET_ACT_BLOCK || !isliving(target) || blocked >= 100) + visible_message(span_warning("The electrodes fail to shock [target], and fall to the ground.")) + return . + + var/mob/living/tased = target + if(HAS_TRAIT(target, TRAIT_HULK)) + tased.say(pick( + ";RAAAAAAAARGH!", + ";HNNNNNNNNNGGGGGGH!", + ";GWAAAAAAAARRRHHH!", + "NNNNNNNNGGGGGGGGHH!", + ";AAAAAAARRRGH!", + ), forced = "hulk") + if(tased.apply_status_effect(/datum/status_effect/tased, fired_from, firer)) + return . + visible_message(span_warning("The electrodes fail to shock [target], and fall to the ground.")) + return BULLET_ACT_BLOCK + /obj/projectile/energy/electrode/on_range() //to ensure the bolt sparks when it reaches the end of its range if it didn't hit a target yet do_sparks(1, TRUE, src) - ..() + return ..() diff --git a/code/modules/projectiles/projectile/energy/thermal.dm b/code/modules/projectiles/projectile/energy/thermal.dm index 41efd21475c6..7409a008b05b 100644 --- a/code/modules/projectiles/projectile/energy/thermal.dm +++ b/code/modules/projectiles/projectile/energy/thermal.dm @@ -12,15 +12,15 @@ /obj/projectile/energy/inferno/on_hit(atom/target, blocked, pierce_hit) ..() - if(!ishuman(target)) + if(!isliving(target)) return - var/mob/living/carbon/cold_target = target + var/mob/living/cold_target = target var/how_cold_is_target = cold_target.bodytemperature - var/danger_zone = cold_target.dna.species.bodytemp_cold_damage_limit - 150 + var/danger_zone = cold_target.bodytemp_cold_damage_limit - 10 CELCIUS if(how_cold_is_target < danger_zone) explosion(cold_target, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 2, flame_range = 3) //maybe stand back a bit - cold_target.bodytemperature = cold_target.dna.species.bodytemp_normal //avoids repeat explosions, maybe could be used to heat up again? + cold_target.adjust_bodytemperature(50 KELVIN, max_temp = cold_target.standard_body_temperature) //avoids repeat explosions, maybe could be used to heat up again? playsound(cold_target, 'sound/weapons/sear.ogg', 30, TRUE, -1) /obj/projectile/energy/cryo @@ -37,14 +37,14 @@ /obj/projectile/energy/cryo/on_hit(atom/target, blocked, pierce_hit) ..() - if(!ishuman(target)) + if(!isliving(target)) return - var/mob/living/carbon/hot_target = target + var/mob/living/hot_target = target var/how_hot_is_target = hot_target.bodytemperature - var/danger_zone = hot_target.dna.species.bodytemp_heat_damage_limit + 300 + var/danger_zone = hot_target.bodytemp_heat_damage_limit + 10 CELCIUS if(how_hot_is_target > danger_zone) hot_target.Knockdown(100) hot_target.apply_damage(20, BURN) - hot_target.bodytemperature = hot_target.dna.species.bodytemp_normal //avoids repeat knockdowns, maybe could be used to cool down again? + hot_target.adjust_bodytemperature(-50 KELVIN, min_temp = hot_target.standard_body_temperature) //avoids repeat knockdowns, maybe could be used to cool down again? playsound(hot_target, 'sound/weapons/sonic_jackhammer.ogg', 30, TRUE, -1) diff --git a/code/modules/projectiles/projectile/special/temperature.dm b/code/modules/projectiles/projectile/special/temperature.dm index 10c652b77b51..56c04108f099 100644 --- a/code/modules/projectiles/projectile/special/temperature.dm +++ b/code/modules/projectiles/projectile/special/temperature.dm @@ -4,34 +4,34 @@ damage = 0 damage_type = BURN armor_flag = ENERGY - var/temperature = -50 // reduce the body temperature by 50 points + /// What temp to trend the target towards + var/temperature = HYPOTHERMIA - 2 CELCIUS + /// How much temp per shot to apply + var/temperature_mod_per_shot = 0.25 /obj/projectile/temp/is_hostile_projectile() - return temperature != 0 // our damage is done by cooling or heating (casting to boolean here) + return BODYTEMP_NORMAL - temperature != 0 // our damage is done by cooling or heating (casting to boolean here) /obj/projectile/temp/on_hit(atom/target, blocked = 0, pierce_hit) . = ..() - if(iscarbon(target)) - var/mob/living/carbon/hit_mob = target - var/thermal_protection = 1 - hit_mob.get_insulation_protection(hit_mob.bodytemperature + temperature) - - // The new body temperature is adjusted by the bullet's effect temperature - // Reduce the amount of the effect temperature change based on the amount of insulation the mob is wearing - hit_mob.adjust_bodytemperature((thermal_protection * temperature) + temperature) - - else if(isliving(target)) - var/mob/living/L = target - // the new body temperature is adjusted by the bullet's effect temperature - L.adjust_bodytemperature((1 - blocked) * temperature) + if(isliving(target)) + var/mob/living/M = target + M.adjust_bodytemperature(temperature_mod_per_shot * ((100-blocked) / 100) * (temperature - M.bodytemperature), use_insulation = TRUE) /obj/projectile/temp/hot name = "heat beam" - temperature = 100 // Raise the body temp by 100 points + temperature = CELCIUS_TO_KELVIN(50 CELCIUS) // Raise the body temp by 100 points /obj/projectile/temp/cryo name = "cryo beam" range = 3 - temperature = -240 // Single slow shot reduces temp greatly + temperature_mod_per_shot = 1.5 // get this guy really chilly really fast + +/obj/projectile/temp/cryo/on_hit(atom/target, blocked, pierce_hit) + . = ..() + if(isopenturf(target)) + var/turf/open/T = target + T.freeze_turf() /obj/projectile/temp/cryo/on_range() var/turf/T = get_turf(src) diff --git a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm index b89ce7dc85e1..afcb401bbf77 100644 --- a/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/cat2_medicine_reagents.dm @@ -204,34 +204,30 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/medicine/c2/hercuri/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) + . = ..() + var/fireheal = -1.25 if(affected_mob.getFireLoss() > 50) - affected_mob.adjustFireLoss(-2 * REM * seconds_per_tick * normalise_creation_purity(), FALSE, required_bodytype = affected_bodytype) - else - affected_mob.adjustFireLoss(-1.25 * REM * seconds_per_tick * normalise_creation_purity(), FALSE, required_bodytype = affected_bodytype) - affected_mob.adjust_bodytemperature(rand(-25,-5) * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, 50) - if(ishuman(affected_mob)) - var/mob/living/carbon/human/humi = affected_mob - humi.adjust_coretemperature(rand(-25,-5) * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, 50) - affected_mob.reagents?.chem_temp += (-10 * REM * seconds_per_tick) + fireheal = -2 + if(affected_mob.adjustFireLoss(fireheal * REM * seconds_per_tick * normalise_creation_purity(), updating_health = FALSE, required_bodytype = affected_bodytype)) + . = TRUE + + var/cooling = -1 KELVIN / rand(1, 5) + affected_mob.adjust_bodytemperature(cooling * REM * seconds_per_tick, min_temp = HYPOTHERMIA - 7 CELCIUS) + affected_mob.reagents?.expose_temperature(affected_mob.reagents.chem_temp - (10 * REM * seconds_per_tick)) affected_mob.adjust_fire_stacks(-1 * REM * seconds_per_tick) - ..() - . = TRUE /datum/reagent/medicine/c2/hercuri/expose_mob(mob/living/carbon/exposed_mob, methods=VAPOR, reac_volume) . = ..() if(!(methods & VAPOR)) return - exposed_mob.adjust_bodytemperature(-reac_volume * TEMPERATURE_DAMAGE_COEFFICIENT, 50) + exposed_mob.adjust_bodytemperature(-reac_volume * -0.33 KELVIN, min_temp = HYPOTHERMIA - 7 CELCIUS, use_insulation = TRUE) exposed_mob.adjust_fire_stacks(reac_volume / -2) if(reac_volume >= metabolization_rate) exposed_mob.extinguish_mob() /datum/reagent/medicine/c2/hercuri/overdose_process(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - affected_mob.adjust_bodytemperature(-10 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, 50) //chilly chilly - if(ishuman(affected_mob)) - var/mob/living/carbon/human/humi = affected_mob - humi.adjust_coretemperature(-10 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, 50) + affected_mob.adjust_bodytemperature(-0.5 KELVIN * REM * seconds_per_tick, min_temp = HYPOTHERMIA - 7 CELCIUS) //chilly chilly ..() diff --git a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm index d91620353710..ad83a408aadc 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/alcohol_reagents.dm @@ -199,7 +199,7 @@ /datum/reagent/consumable/ethanol/thirteenloko/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, times_fired) drinker.adjust_drowsiness(-14 SECONDS * REM * seconds_per_tick) drinker.AdjustSleeping(-40 * REM * seconds_per_tick) - drinker.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, drinker.get_body_temp_normal()) + drinker.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = drinker.standard_body_temperature) if(!HAS_TRAIT(drinker, TRAIT_ALCOHOL_TOLERANCE)) drinker.set_jitter_if_lower(10 SECONDS) ..() @@ -679,7 +679,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/ethanol/toxins_special/on_mob_life(mob/living/drinker, seconds_per_tick, times_fired) - drinker.adjust_bodytemperature(15 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, drinker.get_body_temp_normal() + 20) //310.15 is the normal bodytemp. + drinker.adjust_bodytemperature(WARM_DRINK * REM * seconds_per_tick, max_temp = drinker.standard_body_temperature + 4 KELVIN) //310.15 is the normal bodytemp. return ..() /datum/reagent/consumable/ethanol/beepsky_smash @@ -866,7 +866,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/ethanol/antifreeze/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, times_fired) - drinker.adjust_bodytemperature(20 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, drinker.get_body_temp_normal() + 20) //310.15 is the normal bodytemp. + drinker.adjust_bodytemperature(2 * WARM_DRINK * REM * seconds_per_tick, max_temp = drinker.standard_body_temperature + 4 KELVIN) //310.15 is the normal bodytemp. return ..() /datum/reagent/consumable/ethanol/barefoot @@ -1047,7 +1047,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/ethanol/sbiten/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, times_fired) - drinker.adjust_bodytemperature(50 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, BODYTEMP_HEAT_DAMAGE_LIMIT) //310.15 is the normal bodytemp. + drinker.adjust_bodytemperature(2.5 * WARM_DRINK * REM * seconds_per_tick, max_temp = drinker.standard_body_temperature + 8 KELVIN) //310.15 is the normal bodytemp. return ..() /datum/reagent/consumable/ethanol/red_mead @@ -1078,7 +1078,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/ethanol/iced_beer/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, times_fired) - drinker.adjust_bodytemperature(-20 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, T0C) //310.15 is the normal bodytemp. + drinker.adjust_bodytemperature(2 * COLD_DRINK * REM * seconds_per_tick, min_temp = T0C) //310.15 is the normal bodytemp. return ..() /datum/reagent/consumable/ethanol/grog @@ -1608,7 +1608,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/ethanol/squirt_cider/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, times_fired) - drinker.satiety += 5 * REM * seconds_per_tick //for context, vitamins give 15 satiety per second + drinker.adjust_satiety(5 * REM * seconds_per_tick) //for context, vitamins give 15 satiety per second ..() . = TRUE @@ -1632,7 +1632,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/ethanol/sugar_rush/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, times_fired) - drinker.satiety -= 10 * REM * seconds_per_tick //junky as hell! a whole glass will keep you from being able to eat junk food + drinker.adjust_satiety(-10 * REM * seconds_per_tick)//junky as hell! a whole glass will keep you from being able to eat junk food ..() . = TRUE @@ -1670,7 +1670,7 @@ /datum/reagent/consumable/ethanol/peppermint_patty/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, times_fired) drinker.apply_status_effect(/datum/status_effect/throat_soothed) - drinker.adjust_bodytemperature(5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, drinker.get_body_temp_normal()) + drinker.adjust_bodytemperature(WARM_DRINK * REM * seconds_per_tick, max_temp = drinker.standard_body_temperature) ..() /datum/reagent/consumable/ethanol/alexander @@ -2163,7 +2163,7 @@ /datum/reagent/consumable/ethanol/mauna_loa/on_mob_life(mob/living/carbon/drinker, seconds_per_tick, times_fired) // Heats the user up while the reagent is in the body. Occasionally makes you burst into flames. - drinker.adjust_bodytemperature(25 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick) + drinker.adjust_bodytemperature(2.5 * WARM_DRINK * REM * seconds_per_tick) if (SPT_PROB(2.5, seconds_per_tick)) drinker.adjust_fire_stacks(1) drinker.ignite_mob() @@ -2536,7 +2536,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/ethanol/gin_garden/on_mob_life(mob/living/carbon/doll, seconds_per_tick, times_fired) - doll.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, doll.get_body_temp_normal()) + doll.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = doll.standard_body_temperature) ..() /datum/reagent/consumable/ethanol/wine_voltaic diff --git a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm index ac83949dd483..c332365c9e21 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm @@ -250,7 +250,7 @@ affected_mob.adjust_drowsiness(-6 SECONDS * REM * seconds_per_tick) affected_mob.AdjustSleeping(-40 * REM * seconds_per_tick) //310.15 is the normal bodytemp. - affected_mob.adjust_bodytemperature(25 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(WARM_DRINK * REM * seconds_per_tick, max_temp = affected_mob.standard_body_temperature) if(holder.has_reagent(/datum/reagent/consumable/frostoil)) holder.remove_reagent(/datum/reagent/consumable/frostoil, 5 * REM * seconds_per_tick) ..() @@ -280,7 +280,7 @@ if(!to_chatted && helped) to_chat(affected_mob, span_notice("A calm, relaxed feeling suffuses you. Your wounds feel a little healthier.")) to_chatted = TRUE - affected_mob.adjust_bodytemperature(20 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() . = TRUE @@ -342,7 +342,7 @@ affected_mob.adjust_dizzy(-10 SECONDS * REM * seconds_per_tick) affected_mob.adjust_drowsiness(-6 SECONDS * REM * seconds_per_tick) affected_mob.AdjustSleeping(-40 * REM * seconds_per_tick) - affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(1.5 * COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) ..() . = TRUE @@ -359,7 +359,7 @@ affected_mob.adjust_dizzy(-10 SECONDS * REM * seconds_per_tick) affected_mob.adjust_drowsiness(-6 SECONDS * REM * seconds_per_tick) affected_mob.AdjustSleeping(-60 * REM * seconds_per_tick) - affected_mob.adjust_bodytemperature(-7 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) affected_mob.adjustToxLoss(1 * REM * seconds_per_tick, FALSE, required_biotype = affected_biotype) ..() @@ -379,7 +379,7 @@ affected_mob.AdjustSleeping(-40 * REM * seconds_per_tick) if(affected_mob.getToxLoss() && SPT_PROB(10, seconds_per_tick)) affected_mob.adjustToxLoss(-1, FALSE, required_biotype = affected_biotype) - affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() . = TRUE @@ -392,7 +392,7 @@ /datum/reagent/consumable/space_cola/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) affected_mob.adjust_drowsiness(-10 SECONDS * REM * seconds_per_tick) - affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() /datum/reagent/consumable/roy_rogers @@ -406,7 +406,7 @@ /datum/reagent/consumable/roy_rogers/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) affected_mob.set_jitter_if_lower(12 SECONDS * REM * seconds_per_tick) affected_mob.adjust_drowsiness(-10 SECONDS * REM * seconds_per_tick) - affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) return ..() /datum/reagent/consumable/nuka_cola @@ -431,7 +431,7 @@ affected_mob.adjust_dizzy(3 SECONDS * REM * seconds_per_tick) affected_mob.remove_status_effect(/datum/status_effect/drowsiness) affected_mob.AdjustSleeping(-40 * REM * seconds_per_tick) - affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() . = TRUE @@ -492,7 +492,7 @@ affected_mob.adjust_dizzy(2 SECONDS * REM * seconds_per_tick) affected_mob.remove_status_effect(/datum/status_effect/drowsiness) affected_mob.AdjustSleeping(-40 * REM * seconds_per_tick) - affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() /datum/reagent/consumable/spacemountainwind @@ -505,7 +505,7 @@ /datum/reagent/consumable/spacemountainwind/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) affected_mob.adjust_drowsiness(-14 SECONDS * REM * seconds_per_tick) affected_mob.AdjustSleeping(-20 * REM * seconds_per_tick) - affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) ..() . = TRUE @@ -519,7 +519,7 @@ /datum/reagent/consumable/dr_gibb/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) affected_mob.adjust_drowsiness(-12 SECONDS * REM * seconds_per_tick) - affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() /datum/reagent/consumable/space_up @@ -530,7 +530,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/space_up/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - affected_mob.adjust_bodytemperature(-8 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(1.5 * COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() /datum/reagent/consumable/lemon_lime @@ -541,7 +541,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/lemon_lime/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - affected_mob.adjust_bodytemperature(-8 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(1.5 * COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() /datum/reagent/consumable/pwr_game @@ -559,7 +559,7 @@ You feel as though a great secret of the universe has been made known to you...
") /datum/reagent/consumable/pwr_game/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - affected_mob.adjust_bodytemperature(-8 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(1.5 * COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) if(SPT_PROB(5, seconds_per_tick)) affected_mob.mind?.adjust_experience(/datum/skill/gaming, 5) ..() @@ -572,7 +572,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/shamblers/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - affected_mob.adjust_bodytemperature(-8 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(1.5 * COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() /datum/reagent/consumable/sodawater @@ -585,7 +585,7 @@ /datum/reagent/consumable/sodawater/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) affected_mob.adjust_dizzy(-10 SECONDS * REM * seconds_per_tick) affected_mob.adjust_drowsiness(-6 SECONDS * REM * seconds_per_tick) - affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() /datum/reagent/consumable/tonic @@ -599,7 +599,7 @@ affected_mob.adjust_dizzy(-10 SECONDS * REM * seconds_per_tick) affected_mob.adjust_drowsiness(-6 SECONDS * REM * seconds_per_tick) affected_mob.AdjustSleeping(-40 * REM * seconds_per_tick) - affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() . = TRUE @@ -634,7 +634,7 @@ affected_mob.adjust_dizzy(2 SECONDS * REM * seconds_per_tick) affected_mob.remove_status_effect(/datum/status_effect/drowsiness) affected_mob.AdjustSleeping(-40 * REM * seconds_per_tick) - affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() /datum/reagent/consumable/monkey_energy/on_mob_metabolize(mob/living/affected_mob) @@ -661,7 +661,7 @@ default_container = /obj/item/reagent_containers/cup/glass/ice /datum/reagent/consumable/ice/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() /datum/reagent/consumable/soy_latte @@ -677,7 +677,7 @@ affected_mob.adjust_dizzy(-10 SECONDS * REM * seconds_per_tick) affected_mob.adjust_drowsiness(-6 SECONDS * REM * seconds_per_tick) affected_mob.SetSleeping(0) - affected_mob.adjust_bodytemperature(5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(WARM_DRINK * REM * seconds_per_tick, max_temp = affected_mob.standard_body_temperature) affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) if(affected_mob.getBruteLoss() && SPT_PROB(10, seconds_per_tick)) affected_mob.heal_bodypart_damage(1,0) @@ -697,7 +697,7 @@ affected_mob.adjust_dizzy(-10 SECONDS * REM * seconds_per_tick) affected_mob.adjust_drowsiness(-12 SECONDS * REM * seconds_per_tick) affected_mob.SetSleeping(0) - affected_mob.adjust_bodytemperature(5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(WARM_DRINK * REM * seconds_per_tick, max_temp = affected_mob.standard_body_temperature) affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) if(affected_mob.getBruteLoss() && SPT_PROB(10, seconds_per_tick)) affected_mob.heal_bodypart_damage(1, 0) @@ -854,7 +854,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/grape_soda/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() /datum/reagent/consumable/milk/chocolate_milk @@ -874,7 +874,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/hot_coco/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - affected_mob.adjust_bodytemperature(5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(WARM_DRINK * REM * seconds_per_tick, max_temp = affected_mob.standard_body_temperature) if(affected_mob.getBruteLoss() && SPT_PROB(10, seconds_per_tick)) affected_mob.heal_bodypart_damage(1, 0) . = TRUE @@ -892,7 +892,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/italian_coco/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - affected_mob.adjust_bodytemperature(5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(WARM_DRINK * REM * seconds_per_tick, max_temp = affected_mob.standard_body_temperature) return ..() /datum/reagent/consumable/menthol @@ -945,7 +945,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/cream_soda/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) ..() /datum/reagent/consumable/sol_dry @@ -1035,7 +1035,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/agua_fresca/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - affected_mob.adjust_bodytemperature(-8 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(1.5 * COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) if(affected_mob.getToxLoss() && SPT_PROB(10, seconds_per_tick)) affected_mob.adjustToxLoss(-0.5, FALSE, required_biotype = affected_biotype) return ..() @@ -1135,7 +1135,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/cucumberlemonade/on_mob_life(mob/living/carbon/doll, seconds_per_tick, times_fired) - doll.adjust_bodytemperature(-8 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, doll.get_body_temp_normal()) + doll.adjust_bodytemperature(1.5 * COLD_DRINK * REM * seconds_per_tick, min_temp = doll.standard_body_temperature) if(doll.getToxLoss() && SPT_PROB(10, seconds_per_tick)) doll.adjustToxLoss(-0.5, FALSE, required_biotype = affected_biotype) return ..() diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index f77bbdec9b64..1ab4157d3484 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -700,16 +700,12 @@ return if(invisible_man.undergoing_liver_failure()) return - if(HAS_TRAIT(invisible_man, TRAIT_NOMETABOLISM)) + if(HAS_TRAIT(invisible_man, TRAIT_LIVERLESS_METABOLISM)) return if(invisible_man.has_status_effect(/datum/status_effect/grouped/stasis)) return - invisible_man.add_traits(list(TRAIT_INVISIBLE_MAN, TRAIT_HIDE_EXTERNAL_ORGANS), name) - - var/datum/dna/druggy_dna = invisible_man.has_dna() - if(druggy_dna?.species) - druggy_dna.species.species_traits += NOBLOODOVERLAY + invisible_man.add_traits(list(TRAIT_INVISIBLE_MAN, TRAIT_HIDE_EXTERNAL_ORGANS, TRAIT_NO_BLOOD_OVERLAY), name) invisible_man.update_body() invisible_man.remove_from_all_data_huds() @@ -719,14 +715,10 @@ . = ..() if(HAS_TRAIT(invisible_man, TRAIT_INVISIBLE_MAN)) invisible_man.add_to_all_human_data_huds() //Is this safe, what do you think, Floyd? - invisible_man.remove_traits(list(TRAIT_INVISIBLE_MAN, TRAIT_HIDE_EXTERNAL_ORGANS), name) + invisible_man.remove_traits(list(TRAIT_INVISIBLE_MAN, TRAIT_HIDE_EXTERNAL_ORGANS, TRAIT_NO_BLOOD_OVERLAY), name) to_chat(invisible_man, span_notice("As you sober up, opacity once again returns to your body meats.")) - var/datum/dna/druggy_dna = invisible_man.has_dna() - if(druggy_dna?.species) - druggy_dna.species.species_traits -= NOBLOODOVERLAY - invisible_man.update_body() invisible_man.sound_environment_override = NONE diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm index 4493b5c13971..7f910fa837aa 100644 --- a/code/modules/reagents/chemistry/reagents/food_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm @@ -120,8 +120,7 @@ burn_heal = 1 /datum/reagent/consumable/nutriment/vitamin/on_mob_life(mob/living/carbon/M, seconds_per_tick, times_fired) - if(M.satiety < MAX_SATIETY) - M.satiety += 30 * REM * seconds_per_tick + M.adjust_satiety(30 * REM * seconds_per_tick) . = ..() /// The basic resource of vat growing. @@ -281,28 +280,21 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/capsaicin/on_mob_life(mob/living/carbon/M, seconds_per_tick, times_fired) + . = ..() + holder.remove_reagent(/datum/reagent/cryostylane, 5 * REM * seconds_per_tick) + var/heating = 0 switch(current_cycle) if(1 to 15) - heating = 5 - if(holder.has_reagent(/datum/reagent/cryostylane)) - holder.remove_reagent(/datum/reagent/cryostylane, 5 * REM * seconds_per_tick) - if(isslime(M)) - heating = rand(5, 20) + heating = 0.1 KELVIN if(15 to 25) - heating = 10 - if(isslime(M)) - heating = rand(10, 20) + heating = 0.33 KELVIN if(25 to 35) - heating = 15 - if(isslime(M)) - heating = rand(15, 20) + heating = 0.66 KELVIN if(35 to INFINITY) - heating = 20 - if(isslime(M)) - heating = rand(20, 25) - M.adjust_bodytemperature(heating * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick) - ..() + heating = 1.2 KELVIN + + M.adjust_bodytemperature(heating * REM * seconds_per_tick, max_temp = CELCIUS_TO_KELVIN(39 CELCIUS)) /datum/reagent/consumable/frostoil name = "Frost Oil" @@ -318,32 +310,25 @@ turf_exposure = TRUE /datum/reagent/consumable/frostoil/on_mob_life(mob/living/carbon/M, seconds_per_tick, times_fired) + . = ..() + holder.remove_reagent(/datum/reagent/consumable/capsaicin, 5 * REM * seconds_per_tick) + var/cooling = 0 switch(current_cycle) if(1 to 15) - cooling = -10 - if(holder.has_reagent(/datum/reagent/consumable/capsaicin)) - holder.remove_reagent(/datum/reagent/consumable/capsaicin, 5 * REM * seconds_per_tick) - if(isslime(M)) - cooling = -rand(5, 20) + cooling = -0.1 KELVIN if(15 to 25) - cooling = -20 - if(isslime(M)) - cooling = -rand(10, 20) + cooling = -0.5 KELVIN if(25 to 35) - cooling = -30 + cooling = -1 KELVIN if(prob(1)) M.emote("shiver") - if(isslime(M)) - cooling = -rand(15, 20) if(35 to INFINITY) - cooling = -40 + cooling = -2 KELVIN if(prob(5)) M.emote("shiver") - if(isslime(M)) - cooling = -rand(20, 25) - M.adjust_bodytemperature(cooling * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, 50) - ..() + + M.adjust_bodytemperature(cooling * REM * seconds_per_tick, min_temp = M.bodytemp_cold_damage_limit - 15 KELVIN) /datum/reagent/consumable/frostoil/expose_turf(turf/exposed_turf, reac_volume) . = ..() @@ -590,7 +575,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/hot_ramen/on_mob_life(mob/living/carbon/M, seconds_per_tick, times_fired) - M.adjust_bodytemperature(10 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, 0, M.get_body_temp_normal()) + M.adjust_bodytemperature(0.2 KELVIN * REM * seconds_per_tick, 0, M.standard_body_temperature) ..() /datum/reagent/consumable/hell_ramen @@ -602,7 +587,7 @@ chemical_flags = REAGENT_CAN_BE_SYNTHESIZED /datum/reagent/consumable/hell_ramen/on_mob_life(mob/living/carbon/target_mob, seconds_per_tick, times_fired) - target_mob.adjust_bodytemperature(10 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick) + target_mob.adjust_bodytemperature(WARM_DRINK KELVIN * REM * seconds_per_tick, max_temp = CELCIUS_TO_KELVIN(45 CELCIUS)) ..() /datum/reagent/consumable/flour diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm index 8dccaf47f6f5..5c210decd59f 100644 --- a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm @@ -280,29 +280,21 @@ Basically, we fill the time between now and 2s from now with hands based off the /datum/reagent/inverse/hercuri/on_mob_life(mob/living/carbon/owner, seconds_per_tick, times_fired) . = ..() var/heating = rand(5, 25) * creation_purity * REM * seconds_per_tick - owner.reagents?.chem_temp += heating - owner.adjust_bodytemperature(heating * TEMPERATURE_DAMAGE_COEFFICIENT) - if(!ishuman(owner)) - return - var/mob/living/carbon/human/human = owner - human.adjust_coretemperature(heating * TEMPERATURE_DAMAGE_COEFFICIENT) + owner.reagents?.expose_temperature(owner.reagents.chem_temp + heating, 1) + owner.adjust_bodytemperature(heating * 0.2 KELVIN) /datum/reagent/inverse/hercuri/expose_mob(mob/living/carbon/exposed_mob, methods=VAPOR, reac_volume) . = ..() if(!(methods & VAPOR)) return - exposed_mob.adjust_bodytemperature(reac_volume * TEMPERATURE_DAMAGE_COEFFICIENT) + exposed_mob.adjust_bodytemperature(reac_volume * 0.33 KELVIN, use_insulation = TRUE) exposed_mob.adjust_fire_stacks(reac_volume / 2) /datum/reagent/inverse/hercuri/overdose_process(mob/living/carbon/owner, seconds_per_tick, times_fired) . = ..() owner.adjustOrganLoss(ORGAN_SLOT_LIVER, 2 * REM * seconds_per_tick, required_organtype = affected_organtype) //Makes it so you can't abuse it with pyroxadone very easily (liver dies from 25u unless it's fully upgraded) - var/heating = 10 * creation_purity * REM * seconds_per_tick * TEMPERATURE_DAMAGE_COEFFICIENT - owner.adjust_bodytemperature(heating) //hot hot - if(ishuman(owner)) - var/mob/living/carbon/human/human = owner - human.adjust_coretemperature(heating) + owner.adjust_bodytemperature(0.5 KELVIN * creation_purity * REM * seconds_per_tick) //hot hot /datum/reagent/inverse/healing/tirimol name = "Super Melatonin"//It's melatonin, but super! @@ -383,20 +375,20 @@ Basically, we fill the time between now and 2s from now with hands based off the apply_lung_levels(lungs) /datum/reagent/inverse/healing/convermol/proc/apply_lung_levels(obj/item/organ/internal/lungs/lungs) - cached_heat_level_1 = lungs.heat_level_1_threshold - cached_heat_level_2 = lungs.heat_level_2_threshold - cached_heat_level_3 = lungs.heat_level_3_threshold - cached_cold_level_1 = lungs.cold_level_1_threshold - cached_cold_level_2 = lungs.cold_level_2_threshold - cached_cold_level_3 = lungs.cold_level_3_threshold + cached_heat_level_1 = lungs.heat_level_warning_threshold + cached_heat_level_2 = lungs.heat_level_hazard_threshold + cached_heat_level_3 = lungs.heat_level_danger_threshold + cached_cold_level_1 = lungs.cold_level_warning_threshold + cached_cold_level_2 = lungs.cold_level_hazard_threshold + cached_cold_level_3 = lungs.cold_level_danger_threshold //Heat threshold is increased - lungs.heat_level_1_threshold *= creation_purity * 1.5 - lungs.heat_level_2_threshold *= creation_purity * 1.5 - lungs.heat_level_3_threshold *= creation_purity * 1.5 + lungs.heat_level_warning_threshold *= creation_purity * 1.5 + lungs.heat_level_hazard_threshold *= creation_purity * 1.5 + lungs.heat_level_danger_threshold *= creation_purity * 1.5 //Cold threshold is decreased - lungs.cold_level_1_threshold *= creation_purity * 0.5 - lungs.cold_level_2_threshold *= creation_purity * 0.5 - lungs.cold_level_3_threshold *= creation_purity * 0.5 + lungs.cold_level_warning_threshold *= creation_purity * 0.5 + lungs.cold_level_hazard_threshold *= creation_purity * 0.5 + lungs.cold_level_danger_threshold *= creation_purity * 0.5 /datum/reagent/inverse/healing/convermol/proc/on_removed_organ(mob/prev_owner, obj/item/organ/organ) SIGNAL_HANDLER @@ -406,12 +398,12 @@ Basically, we fill the time between now and 2s from now with hands based off the restore_lung_levels(lungs) /datum/reagent/inverse/healing/convermol/proc/restore_lung_levels(obj/item/organ/internal/lungs/lungs) - lungs.heat_level_1_threshold = cached_heat_level_1 - lungs.heat_level_2_threshold = cached_heat_level_2 - lungs.heat_level_3_threshold = cached_heat_level_3 - lungs.cold_level_1_threshold = cached_cold_level_1 - lungs.cold_level_2_threshold = cached_cold_level_2 - lungs.cold_level_3_threshold = cached_cold_level_3 + lungs.heat_level_warning_threshold = cached_heat_level_1 + lungs.heat_level_hazard_threshold = cached_heat_level_2 + lungs.heat_level_danger_threshold = cached_heat_level_3 + lungs.cold_level_warning_threshold = cached_cold_level_1 + lungs.cold_level_hazard_threshold = cached_cold_level_2 + lungs.cold_level_danger_threshold = cached_cold_level_3 /datum/reagent/inverse/healing/convermol/on_mob_delete(mob/living/owner) . = ..() diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index d1bfbf5a97df..aed33a599e2f 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -22,19 +22,14 @@ color = "#DB90C6" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED -/datum/reagent/medicine/leporazine/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) - var/target_temp = affected_mob.get_body_temp_normal(apply_change = FALSE) - if(affected_mob.bodytemperature > target_temp) - affected_mob.adjust_bodytemperature(-40 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, target_temp) - else if(affected_mob.bodytemperature < (target_temp + 1)) - affected_mob.adjust_bodytemperature(40 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, 0, target_temp) - if(ishuman(affected_mob)) - var/mob/living/carbon/human/affected_human = affected_mob - if(affected_human.coretemperature > target_temp) - affected_human.adjust_coretemperature(-40 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, target_temp) - else if(affected_human.coretemperature < (target_temp + 1)) - affected_human.adjust_coretemperature(40 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, 0, target_temp) - ..() +/datum/reagent/medicine/leporazine/on_mob_metabolize(mob/living/carbon/user) + . = ..() + user.add_homeostasis_level(type, user.standard_body_temperature, 10 KELVIN) + +/datum/reagent/medicine/leporazine/on_mob_end_metabolize(mob/living/carbon/user) + . = ..() + user.remove_homeostasis_level(type) + /datum/reagent/medicine/adminordrazine //An OP chemical for admins name = "Adminordrazine" @@ -1559,7 +1554,7 @@ /datum/reagent/medicine/coagulant/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() - if(!affected_mob.blood_volume || !affected_mob.all_wounds) + if(HAS_TRAIT(affected_mob, TRAIT_NOBLOOD) || !LAZYLEN(affected_mob.all_wounds)) return var/datum/wound/bloodiest_wound @@ -1580,7 +1575,7 @@ /datum/reagent/medicine/coagulant/overdose_process(mob/living/affected_mob, seconds_per_tick, times_fired) . = ..() - if(!affected_mob.blood_volume) + if(!HAS_TRAIT(affected_mob, TRAIT_NOBLOOD)) return if(SPT_PROB(7.5, seconds_per_tick)) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 257a184a2278..17ec5771f854 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -1,21 +1,24 @@ /datum/reagent/blood data = list( - "viruses"=null, - "blood_DNA"=null, - "blood_type"=null, - "resistances"=null, - "trace_chem"=null, - "mind"=null, - "ckey"=null, - "gender"=null, - "real_name"=null, - "cloneable"=null, - "factions"=null, - "quirks"=null, + // Actually Relevant + "viruses" = null, // Refernces to virus datums in this blood + "blood_DNA" = null, // DNA of the guy who the blood came from + "blood_type" = null, // /datum/blood_type of the blood + "resistances" = null, // Viruses the blood is vaccinated against "immunity" = null, + // Unused? (but cool) + "trace_chem" = null, // Param list of all chems in the blood at the time the sample was taken (type to volume) + // Used for podperson shit + "mind" = null, // Ref to the mind of the guy who the blood came from + "ckey" = null, // Ckey of the guy who the blood came from + "gender" = null, // Gender of the guy when the blood was taken + "real_name" = null, // Real name of the guy when the blood was taken + "cloneable" = null, // Tracks if the guy who the blood came from suicided or not + "factions" = null, // Factions the guy who the blood came from was in + "quirks" = null, // Quirk typepaths of the guy who the blood came from had ) name = "Blood" - color = "#9e0101" // rgb: 200, 0, 0 + color = COLOR_BLOOD metabolization_rate = 12.5 * REAGENTS_METABOLISM //fast rate so it disappears fast. taste_description = "iron" taste_mult = 1.3 @@ -24,6 +27,7 @@ default_container = /obj/item/reagent_containers/blood opacity = 230 turf_exposure = TRUE + chemical_flags = REAGENT_IGNORE_STASIS|REAGENT_DEAD_PROCESS /datum/glass_style/shot_glass/blood required_drink_type = /datum/reagent/blood @@ -37,33 +41,30 @@ /datum/reagent/blood/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message=TRUE, touch_protection=0) . = ..() - if(data && data["viruses"]) - for(var/thing in data["viruses"]) - var/datum/disease/strain = thing - - if(istype(strain, /datum/disease/advanced)) - var/datum/disease/advanced/advanced = strain - if(methods & (INJECT|INGEST|PATCH)) - exposed_mob.infect_disease(advanced, TRUE, "(Contact, splashed with infected blood)") - if((methods & (TOUCH | VAPOR)) && (advanced.spread_flags & DISEASE_SPREAD_BLOOD)) - if(exposed_mob.check_bodypart_bleeding(BODY_ZONE_EVERYTHING)) - exposed_mob.infect_disease(advanced, notes="(Blood, splashed with infected blood)") - - if(iscarbon(exposed_mob)) - var/mob/living/carbon/exposed_carbon = exposed_mob - if(exposed_carbon.get_blood_id() == type && ((methods & INJECT) || ((methods & INGEST) && exposed_carbon.dna && exposed_carbon.dna.species && (DRINKSBLOOD in exposed_carbon.dna.species.species_traits)))) - if(!data || !(data["blood_type"] in get_safe_blood(exposed_carbon.dna.blood_type))) - exposed_carbon.reagents.add_reagent(/datum/reagent/toxin, reac_volume * 0.5) - else - exposed_carbon.blood_volume = min(exposed_carbon.blood_volume + round(reac_volume, 0.1), BLOOD_VOLUME_MAXIMUM) + for(var/datum/disease/strain as anything in data?["viruses"]) + if(istype(strain, /datum/disease/advanced)) + var/datum/disease/advanced/advanced = strain + if(methods & (INJECT|INGEST|PATCH)) + exposed_mob.infect_disease(advanced, TRUE, "(Contact, splashed with infected blood)") + if((methods & (TOUCH | VAPOR)) && (advanced.spread_flags & DISEASE_SPREAD_BLOOD)) + if(exposed_mob.check_bodypart_bleeding(BODY_ZONE_EVERYTHING)) + exposed_mob.infect_disease(advanced, notes="(Blood, splashed with infected blood)") + + var/datum/blood_type/blood = exposed_mob.get_blood_type() + if(blood?.reagent_type == type && ((methods & INJECT) || ((methods & INGEST)))) + if(data["blood_type"] in blood.compatible_types) + exposed_mob.blood_volume = min(exposed_mob.blood_volume + round(reac_volume, 0.1), BLOOD_VOLUME_MAXIMUM) + else + exposed_mob.reagents.add_reagent(/datum/reagent/toxin, reac_volume * 0.5) - exposed_carbon.reagents.remove_reagent(type, reac_volume) // Because we don't want blood to just lie around in the patient's blood, makes no sense. + exposed_mob.reagents.remove_reagent(type, reac_volume) // Because we don't want blood to just lie around in the patient's blood, makes no sense. /datum/reagent/blood/on_new(list/data) . = ..() if(istype(data)) SetViruses(src, data) + color = GLOB.blood_types[data["blood_type"]]?.color || COLOR_BLOOD /datum/reagent/blood/on_merge(list/mix_data) if(data && mix_data) @@ -273,7 +274,7 @@ /datum/reagent/water/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() - if(affected_mob.blood_volume) + if(!HAS_TRAIT(affected_mob, TRAIT_NOBLOOD)) affected_mob.blood_volume += 0.1 * REM * seconds_per_tick // water is good for you! /datum/reagent/water/salt @@ -580,9 +581,10 @@ if ("albino") exposed_human.skin_tone = "caucasian1" - if(MUTCOLORS in exposed_human.dna.species.species_traits) //take current alien color and darken it slightly + if(HAS_TRAIT(exposed_human, TRAIT_MUTANT_COLORS)) //take current alien color and darken it slightly var/newcolor = "" - var/string = exposed_human.dna.features["mcolor"] + var/datum/color_palette/generic_colors/located = exposed_human.dna.color_palettes[/datum/color_palette/generic_colors] + var/string = located.return_color(MUTANT_COLOR) var/len = length(string) var/char = "" var/ascii = 0 @@ -605,7 +607,7 @@ else break if(ReadHSV(newcolor)[3] >= ReadHSV("#7F7F7F")[3]) - exposed_human.dna.features["mcolor"] = newcolor + located.mutant_color = newcolor exposed_human.update_body(is_creating = TRUE) if((methods & INGEST) && show_message) @@ -625,10 +627,11 @@ var/obj/item/bodypart/head/head = affected_human.get_bodypart(BODY_ZONE_HEAD) if(head) head.head_flags |= HEAD_HAIR //No hair? No problem! - if(affected_human.dna.species.use_skintones) + if(HAS_TRAIT(affected_human, TRAIT_USES_SKINTONES)) affected_human.skin_tone = "orange" - else if(MUTCOLORS in affected_human.dna.species.species_traits) //Aliens with custom colors simply get turned orange - affected_human.dna.features["mcolor"] = "#ff8800" + else if(HAS_TRAIT(affected_human, TRAIT_MUTANT_COLORS)) //Aliens with custom colors simply get turned orange + var/datum/color_palette/generic_colors/located = affected_human.dna.color_palettes[/datum/color_palette/generic_colors] + located.mutant_color = "#ff8800" affected_human.update_body(is_creating = TRUE) if(SPT_PROB(3.5, seconds_per_tick)) if(affected_human.w_uniform) diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm index 173d503cf547..74f000f2931b 100644 --- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm @@ -245,10 +245,7 @@ metabolization_rate = 0.25 * REM//faster consumption when alive if(affected_mob.reagents.has_reagent(/datum/reagent/oxygen)) affected_mob.reagents.remove_reagent(/datum/reagent/oxygen, 0.5 * REM * seconds_per_tick) - affected_mob.adjust_bodytemperature(-15 * REM * seconds_per_tick) - if(ishuman(affected_mob)) - var/mob/living/carbon/human/humi = affected_mob - humi.adjust_coretemperature(-15 * REM * seconds_per_tick) + affected_mob.adjust_bodytemperature(-1 KELVIN * REM * seconds_per_tick) ..() /datum/reagent/cryostylane/expose_turf(turf/exposed_turf, reac_volume) @@ -275,10 +272,7 @@ /datum/reagent/pyrosium/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) if(holder.has_reagent(/datum/reagent/oxygen)) holder.remove_reagent(/datum/reagent/oxygen, 0.5 * REM * seconds_per_tick) - affected_mob.adjust_bodytemperature(15 * REM * seconds_per_tick) - if(ishuman(affected_mob)) - var/mob/living/carbon/human/humi = affected_mob - humi.adjust_coretemperature(15 * REM * seconds_per_tick) + affected_mob.adjust_bodytemperature(1 KELVIN * REM * seconds_per_tick) ..() /datum/reagent/pyrosium/burn(datum/reagents/holder) diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 54e6461a701f..ae2197dde34e 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -163,10 +163,7 @@ if(holder.has_reagent(/datum/reagent/medicine/epinephrine)) holder.remove_reagent(/datum/reagent/medicine/epinephrine, 2 * REM * seconds_per_tick) affected_mob.adjustPlasma(20 * REM * seconds_per_tick) - affected_mob.adjust_bodytemperature(-7 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, affected_mob.get_body_temp_normal()) - if(ishuman(affected_mob)) - var/mob/living/carbon/human/humi = affected_mob - humi.adjust_coretemperature(-7 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) + affected_mob.adjust_bodytemperature(COLD_DRINK * REM * seconds_per_tick, min_temp = affected_mob.standard_body_temperature) return ..() /datum/reagent/toxin/hot_ice/on_mob_metabolize(mob/living/carbon/affected_mob) @@ -212,7 +209,7 @@ /datum/reagent/toxin/lexorin/proc/block_breath(mob/living/source) SIGNAL_HANDLER - return COMSIG_CARBON_BLOCK_BREATH + return BREATHE_BLOCK_BREATH /datum/reagent/toxin/slimejelly name = "Slime Jelly" @@ -1308,7 +1305,7 @@ /datum/reagent/toxin/tetrodotoxin/proc/block_breath(mob/living/source) SIGNAL_HANDLER if(current_cycle >= 28) - return COMSIG_CARBON_BLOCK_BREATH + return BREATHE_BLOCK_BREATH /datum/reagent/toxin/radiomagnetic_disruptor // MONKESTATION ADDITION: NANITE REMOVAL CHEM name = "Radiomagnetic Disruptor" diff --git a/code/modules/reagents/reagent_containers/blood_pack.dm b/code/modules/reagents/reagent_containers/blood_pack.dm index 1274a3bb91e1..067c9cf1e464 100644 --- a/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/code/modules/reagents/reagent_containers/blood_pack.dm @@ -5,85 +5,84 @@ icon_state = "bloodpack" volume = 200 var/blood_type = null - var/unique_blood = null var/labelled = FALSE fill_icon_thresholds = list(10, 20, 30, 40, 50, 60, 70, 80, 90, 100) /obj/item/reagent_containers/blood/Initialize(mapload, vol) . = ..() - if(blood_type != null) - reagents.add_reagent(unique_blood ? unique_blood : /datum/reagent/blood, 200, list("viruses"=null,"blood_DNA"=null,"blood_type"=blood_type,"resistances"=null,"trace_chem"=null)) + if(!isnull(blood_type)) + var/datum/blood_type/blood = GLOB.blood_types[blood_type] + reagents.add_reagent(blood.reagent_type, 200, list("viruses" = null,"blood_DNA" = null,"blood_type" = blood_type, "resistances" = null, "trace_chem" = null)) update_appearance() /// Handles updating the container when the reagents change. /obj/item/reagent_containers/blood/on_reagent_change(datum/reagents/holder, ...) - var/datum/reagent/blood/new_reagent = holder.has_reagent(/datum/reagent/blood) - if(new_reagent && new_reagent.data && new_reagent.data["blood_type"]) - blood_type = new_reagent.data["blood_type"] - else if(holder.has_reagent(/datum/reagent/consumable/liquidelectricity)) - blood_type = "LE" - else if(holder.has_reagent(/datum/reagent/lube)) - blood_type = "S" - else if(holder.has_reagent(/datum/reagent/water)) - blood_type = "H2O" - else if(holder.has_reagent(/datum/reagent/toxin/slimejelly)) - blood_type = "TOX" - else if(holder.has_reagent(/datum/reagent/toxin/slimeooze)) - blood_type = "OOZE" + blood_type = null + + var/datum/reagent/master_reagent = holder.get_master_reagent() + if(istype(master_reagent, /datum/reagent/blood)) + blood_type = master_reagent.data?["blood_type"] + else - blood_type = null + for(var/blood_type in GLOB.blood_types) + var/datum/blood_type/blood = GLOB.blood_types[blood_type] + if(blood.reagent_type == master_reagent.type) + blood_type = blood_type + break + return ..() /obj/item/reagent_containers/blood/update_name(updates) . = ..() if(labelled) return - name = "blood pack[blood_type ? " - [blood_type]" : null]" + var/datum/blood_type/blood = GLOB.blood_types[blood_type] + name = "blood pack[blood ? " - [blood.name]" : null]" /obj/item/reagent_containers/blood/random icon_state = "random_bloodpack" /obj/item/reagent_containers/blood/random/Initialize(mapload, vol) icon_state = "bloodpack" - blood_type = pick("A+", "A-", "B+", "B-", "O+", "O-", "L") + blood_type = pick(subtypesof(/datum/blood_type/crew) - /datum/blood_type/crew/human) return ..() /obj/item/reagent_containers/blood/a_plus - blood_type = "A+" + blood_type = /datum/blood_type/crew/human/a_plus /obj/item/reagent_containers/blood/a_minus - blood_type = "A-" + blood_type = /datum/blood_type/crew/human/a_minus /obj/item/reagent_containers/blood/b_plus - blood_type = "B+" + blood_type = /datum/blood_type/crew/human/b_plus /obj/item/reagent_containers/blood/b_minus - blood_type = "B-" + blood_type = /datum/blood_type/crew/human/b_minus /obj/item/reagent_containers/blood/o_plus - blood_type = "O+" + blood_type = /datum/blood_type/crew/human/o_plus /obj/item/reagent_containers/blood/o_minus - blood_type = "O-" + blood_type = /datum/blood_type/crew/human/o_minus /obj/item/reagent_containers/blood/lizard - blood_type = "L" + blood_type = /datum/blood_type/crew/lizard /obj/item/reagent_containers/blood/ethereal - blood_type = "LE" - unique_blood = /datum/reagent/consumable/liquidelectricity + blood_type = /datum/blood_type/crew/ethereal + +/obj/item/reagent_containers/blood/skrell + blood_type = /datum/blood_type/crew/skrell /obj/item/reagent_containers/blood/snail - blood_type = "S" - unique_blood = /datum/reagent/lube + blood_type = /datum/blood_type/snail /obj/item/reagent_containers/blood/snail/examine() . = ..() . += span_notice("It's a bit slimy... The label indicates that this is meant for snails.") /obj/item/reagent_containers/blood/podperson - blood_type = "H2O" - unique_blood = /datum/reagent/water + blood_type = /datum/blood_type/water /obj/item/reagent_containers/blood/podperson/examine() . = ..() @@ -91,15 +90,14 @@ // for slimepeople /obj/item/reagent_containers/blood/toxin - blood_type = "TOX" - unique_blood = /datum/reagent/toxin/slimejelly + blood_type = /datum/blood_type/slime /obj/item/reagent_containers/blood/toxin/examine() . = ..() . += span_notice("There is a toxin warning on the label. This is for slimepeople.") /obj/item/reagent_containers/blood/universal - blood_type = "U" + blood_type = /datum/blood_type/universal /obj/item/reagent_containers/blood/attackby(obj/item/tool, mob/user, params) if (istype(tool, /obj/item/pen) || istype(tool, /obj/item/toy/crayon)) diff --git a/code/modules/reagents/reagent_containers/cups/_cup.dm b/code/modules/reagents/reagent_containers/cups/_cup.dm index a51fa5bac242..4aad53d61f20 100644 --- a/code/modules/reagents/reagent_containers/cups/_cup.dm +++ b/code/modules/reagents/reagent_containers/cups/_cup.dm @@ -25,34 +25,37 @@ var/list/types = bitfield_to_list(drink_type, FOOD_FLAGS) . += span_notice("It is [lowertext(english_list(types))].") -/obj/item/reagent_containers/cup/proc/checkLiked(fraction, mob/M) - if(last_check_time + 50 >= world.time) - return - if(!ishuman(M)) - return - var/mob/living/carbon/human/H = M - if(HAS_TRAIT(H, TRAIT_AGEUSIA)) - if(drink_type & H.dna.species.toxic_food) - to_chat(H, span_warning("You don't feel so good...")) - H.adjust_disgust(25 + 30 * fraction) - else - if(drink_type & H.dna.species.toxic_food) - to_chat(H,span_warning("What the hell was that thing?!")) - H.adjust_disgust(25 + 30 * fraction) - H.add_mood_event("toxic_food", /datum/mood_event/disgusting_food) - else if(drink_type & H.dna.species.disliked_food) - to_chat(H,span_notice("That didn't taste very good...")) - H.adjust_disgust(11 + 15 * fraction) - H.add_mood_event("gross_food", /datum/mood_event/gross_food) - else if(drink_type & H.dna.species.liked_food) - to_chat(H,span_notice("I love this taste!")) - H.adjust_disgust(-5 + -2.5 * fraction) - H.add_mood_event("fav_food", /datum/mood_event/favorite_food) - +/** + * Checks if the mob actually liked drinking this cup. + * + * This is a bunch of copypaste from the edible component, consider reworking this to use it! + */ +/obj/item/reagent_containers/cup/proc/checkLiked(fraction, mob/eater) + if(last_check_time + 5 SECONDS > world.time) + return FALSE + if(!ishuman(eater)) + return FALSE + var/mob/living/carbon/human/gourmand = eater + //Bruh this breakfast thing is cringe and shouldve been handled separately from food-types, remove this in the future (Actually, just kill foodtypes in general) if((drink_type & BREAKFAST) && world.time - SSticker.round_start_time < STOP_SERVING_BREAKFAST) - H.add_mood_event("breakfast", /datum/mood_event/breakfast) + gourmand.add_mood_event("breakfast", /datum/mood_event/breakfast) last_check_time = world.time + var/food_taste_reaction = gourmand.get_food_taste_reaction(src, drink_type) + switch(food_taste_reaction) + if(FOOD_TOXIC) + to_chat(gourmand,span_warning("What the hell was that thing?!")) + gourmand.adjust_disgust(25 + 30 * fraction) + gourmand.add_mood_event("toxic_food", /datum/mood_event/disgusting_food) + if(FOOD_DISLIKED) + to_chat(gourmand,span_notice("That didn't taste very good...")) + gourmand.adjust_disgust(11 + 15 * fraction) + gourmand.add_mood_event("gross_food", /datum/mood_event/gross_food) + if(FOOD_LIKED) + to_chat(gourmand,span_notice("I love this taste!")) + gourmand.adjust_disgust(-5 + -2.5 * fraction) + gourmand.add_mood_event("fav_food", /datum/mood_event/favorite_food) + /obj/item/reagent_containers/cup/attack(mob/living/target_mob, mob/living/user, obj/target) if(!canconsume(target_mob, user)) return diff --git a/code/modules/reagents/withdrawal/generic_addictions.dm b/code/modules/reagents/withdrawal/generic_addictions.dm index 9e79ec350fec..8c048e52b0ae 100644 --- a/code/modules/reagents/withdrawal/generic_addictions.dm +++ b/code/modules/reagents/withdrawal/generic_addictions.dm @@ -112,9 +112,12 @@ affected_human.facial_hairstyle = "Beard (Full)" affected_human.update_body_parts() //Only like gross food - affected_human.dna?.species.liked_food = GROSS - affected_human.dna?.species.disliked_food = TOXIC // Toxic food won't kill you, but it doesn't taste good still. - affected_human.dna?.species.toxic_food = ~(GROSS | RAW | GORE | MEAT | BUGS | TOXIC | ALCOHOL) // Monke, you can eat raw rats and whatnot. + var/obj/item/organ/internal/tongue/tongue = affected_carbon.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!tongue) + return + tongue.liked_foodtypes = GROSS + tongue.disliked_foodtypes = TOXIC + tongue.toxic_foodtypes = ~(GROSS | RAW | GORE | MEAT | BUGS | TOXIC | ALCOHOL) /datum/addiction/maintenance_drugs/withdrawal_enters_stage_3(mob/living/carbon/affected_carbon) . = ..() @@ -146,12 +149,15 @@ if(!ishuman(affected_carbon)) return var/mob/living/carbon/human/affected_human = affected_carbon - affected_human.dna?.species.liked_food = initial(affected_human.dna?.species.liked_food) - affected_human.dna?.species.disliked_food = initial(affected_human.dna?.species.disliked_food) - affected_human.dna?.species.toxic_food = initial(affected_human.dna?.species.toxic_food) + //restore tongue's tastes + var/obj/item/organ/internal/tongue/tongue = affected_carbon.get_organ_slot(ORGAN_SLOT_TONGUE) + if(tongue) + tongue.liked_foodtypes = initial(tongue.liked_foodtypes) + tongue.disliked_foodtypes = initial(tongue.disliked_foodtypes) + tongue.toxic_foodtypes = initial(tongue.toxic_foodtypes) REMOVE_TRAIT(affected_human, TRAIT_NIGHT_VISION, "maint_drug_addiction") var/obj/item/organ/internal/eyes/eyes = affected_human.get_organ_by_type(/obj/item/organ/internal/eyes) - eyes.refresh() + eyes?.refresh() ///Makes you a hypochondriac - I'd like to call it hypochondria, but "I could use some hypochondria" doesn't work /datum/addiction/medicine diff --git a/code/modules/religion/pyre_rites.dm b/code/modules/religion/pyre_rites.dm index 28ef53968f9c..2a2b3c606ff8 100644 --- a/code/modules/religion/pyre_rites.dm +++ b/code/modules/religion/pyre_rites.dm @@ -3,7 +3,6 @@ /datum/religion_rites/fireproof/proc/apply_fireproof(obj/item/clothing/fireproofed) fireproofed.name = "unmelting [fireproofed.name]" fireproofed.max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - fireproofed.heat_protection = chosen_clothing.body_parts_covered fireproofed.resistance_flags |= FIRE_PROOF /datum/religion_rites/fireproof diff --git a/code/modules/research/designs/limbgrower_designs.dm b/code/modules/research/designs/limbgrower_designs.dm index f52621b09c82..916e8bf0467b 100644 --- a/code/modules/research/designs/limbgrower_designs.dm +++ b/code/modules/research/designs/limbgrower_designs.dm @@ -162,7 +162,7 @@ id = "plasmamanliver" build_type = LIMBGROWER reagents_list = list(/datum/reagent/medicine/c2/synthflesh = 10, /datum/reagent/toxin/plasma = 20) - build_path = /obj/item/organ/internal/liver/plasmaman + build_path = /obj/item/organ/internal/liver/bone/plasmaman category = list(SPECIES_PLASMAMAN) /datum/design/plasmaman_stomach diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 3d2b406ada89..7a63d673f973 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -426,6 +426,8 @@ "defibrillator", "genescanner", "healthanalyzer", + "scanning_pad", + "vitals_monitor", "antibodyscanner", "med_spray_bottle", "medical_kiosk", @@ -438,6 +440,9 @@ "diseaseanalyzer", "centrifuge", "path_data", + "heat_pack", + "cold_pack", + "medical_crutch", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) discount_experiments = list(/datum/experiment/dissection/human = 1000) @@ -449,6 +454,7 @@ prereq_ids = list("biotech") design_ids = list( "crewpinpointer", + "vitals_monitor_advanced", "defibrillator_compact", "harvester", "healthanalyzer_advanced", diff --git a/code/modules/research/xenobiology/crossbreeding/_potions.dm b/code/modules/research/xenobiology/crossbreeding/_potions.dm index 1e6205dc8039..08c80609d7e4 100644 --- a/code/modules/research/xenobiology/crossbreeding/_potions.dm +++ b/code/modules/research/xenobiology/crossbreeding/_potions.dm @@ -129,7 +129,6 @@ Slimecrossing Potions C.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) C.add_atom_colour("#000080", FIXED_COLOUR_PRIORITY) C.min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT - C.cold_protection = C.body_parts_covered C.clothing_flags |= STOPSPRESSUREDAMAGE uses-- if(!uses) diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm index 6c91d1a863d6..67c92ea362ca 100644 --- a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm +++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm @@ -213,13 +213,12 @@ return ..() /datum/status_effect/bonechill/tick() - if(prob(50)) - owner.adjustFireLoss(1) - owner.set_jitter_if_lower(6 SECONDS) - owner.adjust_bodytemperature(-10) - if(ishuman(owner)) - var/mob/living/carbon/human/humi = owner - humi.adjust_coretemperature(-10) + if(!prob(50)) + return + + owner.adjustFireLoss(1) + owner.set_jitter_if_lower(6 SECONDS) + owner.adjust_bodytemperature(-1 KELVIN) /datum/status_effect/bonechill/on_remove() owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/bonechill) @@ -234,7 +233,7 @@ alert_type = null /datum/status_effect/rebreathing/tick() - owner.adjustOxyLoss(-6, 0) //Just a bit more than normal breathing. + owner.adjustOxyLoss(-6) //Just a bit more than normal breathing. /////////////////////////////////////////////////////// //////////////////CONSUMING EXTRACTS/////////////////// @@ -247,12 +246,12 @@ duration = 100 /datum/status_effect/firecookie/on_apply() - ADD_TRAIT(owner, TRAIT_RESISTCOLD,"firecookie") - owner.adjust_bodytemperature(110) + ADD_TRAIT(owner, TRAIT_RESISTCOLD, id) + owner.adjust_bodytemperature(20 KELVIN) return ..() /datum/status_effect/firecookie/on_remove() - REMOVE_TRAIT(owner, TRAIT_RESISTCOLD,"firecookie") + REMOVE_TRAIT(owner, TRAIT_RESISTCOLD, id) /datum/status_effect/watercookie id = "watercookie" @@ -488,21 +487,12 @@ colour = "orange" /datum/status_effect/stabilized/orange/tick() - var/body_temp_target = owner.get_body_temp_normal(apply_change = FALSE) + owner.update_homeostasis_level(id, owner.standard_body_temperature, 0.5 KELVIN) - var/body_temp_actual = owner.bodytemperature - var/body_temp_offset = body_temp_target - body_temp_actual - body_temp_offset = clamp(body_temp_offset, -5, 5) - owner.adjust_bodytemperature(body_temp_offset) - if(ishuman(owner)) - var/mob/living/carbon/human/human = owner - var/core_temp_actual = human.coretemperature - var/core_temp_offset = body_temp_target - core_temp_actual - core_temp_offset = clamp(core_temp_offset, -5, 5) - human.adjust_coretemperature(core_temp_offset) - - return ..() +/datum/status_effect/stabilized/orange/on_remove() + . = ..() + owner.remove_homeostasis_level(id) /datum/status_effect/stabilized/purple id = "stabilizedpurple" diff --git a/code/modules/research/xenobiology/crossbreeding/burning.dm b/code/modules/research/xenobiology/crossbreeding/burning.dm index 4ccc9567271a..d33c314d6277 100644 --- a/code/modules/research/xenobiology/crossbreeding/burning.dm +++ b/code/modules/research/xenobiology/crossbreeding/burning.dm @@ -70,9 +70,10 @@ Burning extracts: for(var/turf/open/T in range(3, get_turf(user))) T.MakeSlippery(TURF_WET_PERMAFROST, min_wet_time = 10, wet_time_to_add = 5) for(var/mob/living/carbon/M in range(5, get_turf(user))) - if(M != user) - M.bodytemperature = BODYTEMP_COLD_DAMAGE_LIMIT + 10 //Not quite cold enough to hurt. - to_chat(M, span_danger("You feel a chill run down your spine, and the floor feels a bit slippery with frost...")) + if(M == user) + continue + M.adjust_bodytemperature(-INFINITY, min_temp = M.bodytemp_cold_damage_limit + 5 KELVIN) + to_chat(M, span_danger("You feel a chill run down your spine, and the floor feels a bit slippery with frost...")) ..() /obj/item/slimecross/burning/metal diff --git a/code/modules/research/xenobiology/crossbreeding/regenerative.dm b/code/modules/research/xenobiology/crossbreeding/regenerative.dm index 98821ff7176f..787af8195771 100644 --- a/code/modules/research/xenobiology/crossbreeding/regenerative.dm +++ b/code/modules/research/xenobiology/crossbreeding/regenerative.dm @@ -133,7 +133,6 @@ Regenerative extracts: C.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) C.add_atom_colour("#000080", FIXED_COLOUR_PRIORITY) C.max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - C.heat_protection = C.body_parts_covered C.resistance_flags |= FIRE_PROOF /obj/item/slimecross/regenerative/silver diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index edc0b1313653..2e9610dba099 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -596,8 +596,8 @@ /obj/item/slime_extract/rainbow/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type) switch(activation_type) if(SLIME_ACTIVATE_MINOR) - user.dna.features["mcolor"] = "#[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]" - user.dna.update_uf_block(DNA_MUTANT_COLOR_BLOCK) + var/datum/color_palette/generic_colors/located = user.dna.color_palettes[/datum/color_palette/generic_colors] + located.mutant_color = "#[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]" user.updateappearance(mutcolor_update=1) species.update_glow(user) to_chat(user, span_notice("You feel different...")) @@ -927,7 +927,6 @@ clothing.remove_atom_colour(WASHABLE_COLOUR_PRIORITY) clothing.add_atom_colour("#000080", FIXED_COLOUR_PRIORITY) clothing.max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - clothing.heat_protection = clothing.body_parts_covered clothing.resistance_flags |= FIRE_PROOF uses -- if(!uses) diff --git a/code/modules/spells/spell_types/jaunt/bloodcrawl.dm b/code/modules/spells/spell_types/jaunt/bloodcrawl.dm index 836bfd98dca4..0afb21953152 100644 --- a/code/modules/spells/spell_types/jaunt/bloodcrawl.dm +++ b/code/modules/spells/spell_types/jaunt/bloodcrawl.dm @@ -144,7 +144,7 @@ // Make the mob have the color of the blood pool it came out of var/obj/effect/decal/cleanable/came_from = locate() in landing_turf - var/new_color = came_from?.get_blood_color() + var/new_color = came_from?.get_blood_dna_color() if(!new_color) return diff --git a/code/modules/spells/spell_types/pointed/abyssal_gaze.dm b/code/modules/spells/spell_types/pointed/abyssal_gaze.dm index a7336ef7834a..7a1d13275760 100644 --- a/code/modules/spells/spell_types/pointed/abyssal_gaze.dm +++ b/code/modules/spells/spell_types/pointed/abyssal_gaze.dm @@ -21,7 +21,7 @@ /// The duration of the blind on our target var/blind_duration = 4 SECONDS /// The amount of temperature we take from our target - var/amount_to_cool = 200 + var/amount_to_cool = CELCIUS_TO_KELVIN(10 CELCIUS) /datum/action/cooldown/spell/pointed/abyssal_gaze/is_valid_target(atom/cast_on) return iscarbon(cast_on) @@ -37,7 +37,4 @@ cast_on.playsound_local(get_turf(cast_on), 'sound/hallucinations/i_see_you1.ogg', 50, 1) owner.playsound_local(get_turf(owner), 'sound/effects/ghost2.ogg', 50, 1) cast_on.adjust_temp_blindness(blind_duration) - if(ishuman(cast_on)) - var/mob/living/carbon/human/human_cast_on = cast_on - human_cast_on.adjust_coretemperature(-amount_to_cool) cast_on.adjust_bodytemperature(-amount_to_cool) diff --git a/code/modules/spells/spell_types/self/mutate.dm b/code/modules/spells/spell_types/self/mutate.dm index 59f8f6ddc37f..6f5040c6b5e7 100644 --- a/code/modules/spells/spell_types/self/mutate.dm +++ b/code/modules/spells/spell_types/self/mutate.dm @@ -51,8 +51,8 @@ /datum/action/cooldown/spell/apply_mutations/mutate/cast(mob/living/carbon/human/cast_on) ..() - /*if(HAS_TRAIT(cast_on, TRAIT_USES_SKINTONES) || HAS_TRAIT(cast_on, TRAIT_MUTANT_COLORS)) - return*/ //monkestation temp removal, we dont have this refactor yet + if(HAS_TRAIT(cast_on, TRAIT_USES_SKINTONES) || HAS_TRAIT(cast_on, TRAIT_MUTANT_COLORS)) + return//monkestation temp removal, we dont have this refactor yet // Our caster has a species that doesn't greenify when hulked, so we will do it manually. cast_on.add_atom_colour("#00FF00", TEMPORARY_COLOUR_PRIORITY) diff --git a/code/modules/surgery/bodyparts/_arms.dm b/code/modules/surgery/bodyparts/_arms.dm new file mode 100644 index 000000000000..7678a8e9e1c9 --- /dev/null +++ b/code/modules/surgery/bodyparts/_arms.dm @@ -0,0 +1,181 @@ +/// Parent Type for arms, should not appear in game. +/obj/item/bodypart/arm + name = "arm" + desc = "Hey buddy give me a HAND and report this to the github because you shouldn't be seeing this." + attack_verb_continuous = list("slaps", "punches") + attack_verb_simple = list("slap", "punch") + max_damage = 50 + aux_layer = BODYPARTS_HIGH_LAYER + body_damage_coeff = 0.75 + can_be_disabled = TRUE + unarmed_attack_verb = "punch" /// The classic punch, wonderfully classic and completely random + unarmed_damage_low = 5 + unarmed_damage_high = 5 + unarmed_stun_threshold = 10 + body_zone = BODY_ZONE_L_ARM + + biological_state = BIO_STANDARD_JOINTED + /// Basically, bodypart traits that ONLY apply when this arm is the active hand of the mob + var/list/hand_traits + +/obj/item/bodypart/arm/Destroy() + return ..() + +/obj/item/bodypart/arm/Destroy() + return ..() + +/obj/item/bodypart/arm/set_owner(new_owner) + . = ..() + if(. == FALSE) + return + + if(owner) + RegisterSignal(owner, COMSIG_MOB_SWAP_HANDS, PROC_REF(on_swap_hands)) + on_swap_hands(owner) + + if(.) + var/mob/living/carbon/old_owner = . + UnregisterSignal(old_owner, COMSIG_MOB_SWAP_HANDS) + on_inactive_hand(old_owner) + +/obj/item/bodypart/arm/set_disabled(new_disabled) + . = ..() + if(isnull(.) || !owner) + return + + if(!.) + if(bodypart_disabled) + owner.set_usable_hands(owner.usable_hands - 1) + if(owner.stat < UNCONSCIOUS) + to_chat(owner, span_userdanger("You lose control of your [name]!")) + if(held_index) + owner.dropItemToGround(owner.get_item_for_held_index(held_index)) + else if(!bodypart_disabled) + owner.set_usable_hands(owner.usable_hands + 1) + + if(owner.hud_used) + var/atom/movable/screen/inventory/hand/hand_screen_object = owner.hud_used.hand_slots["[held_index]"] + hand_screen_object?.update_appearance() + +/obj/item/bodypart/arm/proc/on_swap_hands(mob/living/carbon/source) + SIGNAL_HANDLER + if(!length(hand_traits)) + return + if(source.get_active_hand() == src) + on_active_hand(source) + else + on_inactive_hand(source) + +/obj/item/bodypart/arm/proc/on_active_hand(mob/living/carbon/source) + SHOULD_CALL_PARENT(TRUE) + if(!length(hand_traits)) + return + source.add_traits(hand_traits, REF(src)) + +/obj/item/bodypart/arm/proc/on_inactive_hand(mob/living/carbon/source) + SHOULD_CALL_PARENT(TRUE) + if(!length(hand_traits)) + return + source.remove_traits(hand_traits, REF(src)) + +/obj/item/bodypart/arm/left + name = "left arm" + desc = "Did you know that the word 'sinister' stems originally from the \ + Latin 'sinestra' (left hand), because the left hand was supposed to \ + be possessed by the devil? This arm appears to be possessed by no \ + one though." + icon_state = "default_human_l_arm" + body_zone = BODY_ZONE_L_ARM + body_part = ARM_LEFT + plaintext_zone = "left arm" + aux_zone = BODY_ZONE_PRECISE_L_HAND + held_index = 1 + px_x = -6 + px_y = 0 + bodypart_trait_source = LEFT_ARM_TRAIT + +/obj/item/bodypart/arm/left/set_owner(new_owner) + . = ..() + if(. == FALSE) + return + + if(owner) + if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_ARM)) + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_loss)) + else + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_gain)) + if(.) + var/mob/living/carbon/old_owner = . + if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_L_ARM)) + UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM)) + if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_L_ARM)) + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) + else + UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM)) + +///Proc to react to the owner gaining the TRAIT_PARALYSIS_L_ARM trait. +/obj/item/bodypart/arm/left/proc/on_owner_paralysis_gain(mob/living/carbon/source) + SIGNAL_HANDLER + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) + UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM)) + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_loss)) + + +///Proc to react to the owner losing the TRAIT_PARALYSIS_L_ARM trait. +/obj/item/bodypart/arm/left/proc/on_owner_paralysis_loss(mob/living/carbon/source) + SIGNAL_HANDLER + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) + UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM)) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_gain)) + +/obj/item/bodypart/arm/right + name = "right arm" + desc = "Over 87% of humans are right handed. That figure is much lower \ + among humans missing their right arm." + body_zone = BODY_ZONE_R_ARM + body_part = ARM_RIGHT + icon_state = "default_human_r_arm" + plaintext_zone = "right arm" + aux_zone = BODY_ZONE_PRECISE_R_HAND + held_index = 2 + px_x = 6 + px_y = 0 + bodypart_trait_source = RIGHT_ARM_TRAIT + +/obj/item/bodypart/arm/right/set_owner(new_owner) + . = ..() + if(. == FALSE) + return + + if(owner) + if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_ARM)) + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_loss)) + else + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_gain)) + if(.) + var/mob/living/carbon/old_owner = . + if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_R_ARM)) + UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM)) + if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_R_ARM)) + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) + else + UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM)) + +///Proc to react to the owner gaining the TRAIT_PARALYSIS_R_ARM trait. +/obj/item/bodypart/arm/right/proc/on_owner_paralysis_gain(mob/living/carbon/source) + SIGNAL_HANDLER + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) + UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM)) + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_loss)) + + +///Proc to react to the owner losing the TRAIT_PARALYSIS_R_ARM trait. +/obj/item/bodypart/arm/right/proc/on_owner_paralysis_loss(mob/living/carbon/source) + SIGNAL_HANDLER + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) + UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM)) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_gain)) diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 956b09a610d0..21f3c0ae6bbc 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -66,6 +66,8 @@ var/list/embedded_objects = list() /// are we a hand? if so, which one! var/held_index = 0 + /// A speed modifier we apply to the owner when attached, if any. Positive numbers make it move slower, negative numbers make it move faster. + var/speed_modifier = 0 // Limb disabling variables ///Controls if the limb is disabled. TRUE means it is disabled (similar to being removed, but still present for the sake of targeted interactions). @@ -105,16 +107,12 @@ var/should_draw_greyscale = TRUE ///An "override" color that can be applied to ANY limb, greyscale or not. var/variable_color = "" + /// Color of the damage overlay + var/damage_color = COLOR_BLOOD var/px_x = 0 var/px_y = 0 - /** - * A copy of the original owner's species datum species_traits list (very hacky) - * It sucks that we have to do this, but due to MUTCOLORS and others, we have to. For now. - */ - - var/species_flags_list = list() ///the type of damage overlay (if any) to use when this bodypart is bruised/burned. var/dmg_overlay_type = "human" /// If we're bleeding, which icon are we displaying on this part @@ -200,6 +198,14 @@ /// If false, no wound that can be applied to us can mangle our interior. Used for determining if we should use [hp_percent_to_dismemberable] instead of normal dismemberment. var/any_existing_wound_can_mangle_our_interior + ///an assoc list of type to % for limbs that share id's useful for traits or components we want to add that should require more than 1 limb being added + var/list/composition_effects + ///a list of different limb_ids that we share composition with + var/list/shared_composition + ///this is our color palette we pull colors from + var/datum/color_palette/palette + var/palette_key + /obj/item/bodypart/apply_fantasy_bonuses(bonus) . = ..() unarmed_damage_low = modify_fantasy_variable("unarmed_damage_low", unarmed_damage_low, bonus, minimum = 1) @@ -332,23 +338,20 @@ else is_disabled += " and" - check_list += "\t Your [name][is_disabled][self_aware ? " has " : " is "][status]." + check_list += "\tYour [name][is_disabled][self_aware ? " has " : " is "][status]." for(var/datum/wound/wound as anything in wounds) - switch(wound.severity) - if(WOUND_SEVERITY_TRIVIAL) - check_list += "\t [span_danger("Your [name] is suffering [wound.a_or_from] [lowertext(wound.name)].")]" - if(WOUND_SEVERITY_MODERATE) - check_list += "\t [span_warning("Your [name] is suffering [wound.a_or_from] [lowertext(wound.name)]!")]" - if(WOUND_SEVERITY_SEVERE) - check_list += "\t [span_boldwarning("Your [name] is suffering [wound.a_or_from] [lowertext(wound.name)]!!")]" - if(WOUND_SEVERITY_CRITICAL) - check_list += "\t [span_boldwarning("Your [name] is suffering [wound.a_or_from] [lowertext(wound.name)]!!!")]" + var/wound_desc = wound.get_self_check_description(src, examiner) + if(wound_desc) + check_list += "\t\t[wound_desc]" for(var/obj/item/embedded_thing in embedded_objects) var/stuck_word = embedded_thing.isEmbedHarmless() ? "stuck" : "embedded" check_list += "\t There is \a [embedded_thing] [stuck_word] in your [name]!" + if(current_gauze) + check_list += span_notice("\t There is some [current_gauze.name] wrapped around your [name].") + /obj/item/bodypart/blob_act() receive_damage(max_damage, wound_bonus = CANT_WOUND) @@ -401,6 +404,9 @@ pixel_x = rand(-3, 3) pixel_y = rand(-3, 3) +/obj/item/bodypart/drop_location() + return ..() || owner?.drop_location() + //empties the bodypart from its organs and other things inside it /obj/item/bodypart/proc/drop_organs(mob/user, violent_removal) SHOULD_CALL_PARENT(TRUE) @@ -650,7 +656,7 @@ if(burn) set_burn_dam(round(max(burn_dam - burn, 0), DAMAGE_PRECISION)) - if(owner.dna && owner.dna.species && (REVIVESBYHEALING in owner.dna.species.species_traits)) + if(HAS_TRAIT(owner, TRAIT_REVIVES_BY_HEALING)) if(owner.health > 0) owner.revive(0) owner.cure_husk(0) // If it has REVIVESBYHEALING, it probably can't be cloned. No husk cure. @@ -761,6 +767,10 @@ owner = new_owner var/needs_update_disabled = FALSE //Only really relevant if there's an owner if(old_owner) + if(length(bodypart_traits)) + old_owner.remove_traits(bodypart_traits, bodypart_trait_source) + if(speed_modifier) + old_owner.update_bodypart_speed_modifier() if(initial(can_be_disabled)) if(HAS_TRAIT(old_owner, TRAIT_NOLIMBDISABLE)) if(!owner || !HAS_TRAIT(owner, TRAIT_NOLIMBDISABLE)) @@ -773,7 +783,13 @@ SIGNAL_ADDTRAIT(TRAIT_NOBLOOD), )) UnregisterSignal(old_owner, COMSIG_ATOM_RESTYLE) + UnregisterSignal(old_owner, list(COMSIG_CARBON_ATTACH_LIMB, COMSIG_CARBON_REMOVE_LIMB)) + check_removal_composition(old_owner) if(owner) + if(length(bodypart_traits)) + owner.add_traits(bodypart_traits, bodypart_trait_source) + if(speed_modifier) + owner.update_bodypart_speed_modifier() if(initial(can_be_disabled)) if(HAS_TRAIT(owner, TRAIT_NOLIMBDISABLE)) set_can_be_disabled(FALSE) @@ -783,11 +799,13 @@ // Bleeding stuff RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_NOBLOOD), PROC_REF(on_owner_nobleed_loss)) RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_NOBLOOD), PROC_REF(on_owner_nobleed_gain)) + RegisterSignals(owner, list(COMSIG_CARBON_ATTACH_LIMB, COMSIG_CARBON_REMOVE_LIMB), PROC_REF(reassess_body_composition)) if(needs_update_disabled) update_disabled() RegisterSignal(owner, COMSIG_ATOM_RESTYLE, PROC_REF(on_attempt_feature_restyle_mob)) + check_adding_composition(owner) refresh_bleed_rate() return old_owner @@ -797,6 +815,7 @@ return owner.remove_traits(bodypart_traits, bodypart_trait_source) + check_removal_composition(owner) ///Proc to change the value of the `can_be_disabled` variable and react to the event of its change. /obj/item/bodypart/proc/set_can_be_disabled(new_can_be_disabled) @@ -893,32 +912,38 @@ else draw_color = null + damage_color = owner?.get_blood_type()?.color || COLOR_BLOOD + if(!is_creating || !owner) return // There should technically to be an ishuman(owner) check here, but it is absent because no basetype carbons use bodyparts // No, xenos don't actually use bodyparts. Don't ask. var/mob/living/carbon/human/human_owner = owner - var/datum/species/owner_species = human_owner.dna.species - species_flags_list = owner_species.species_traits.Copy() limb_gender = (human_owner.physique == MALE) ? "m" : "f" - - if(owner_species.use_skintones) + if(HAS_TRAIT(human_owner, TRAIT_USES_SKINTONES)) skin_tone = human_owner.skin_tone - else + else if(HAS_TRAIT(human_owner, TRAIT_MUTANT_COLORS)) skin_tone = "" - - if(((MUTCOLORS in owner_species.species_traits) || (DYNCOLORS in owner_species.species_traits) || (SPECIES_FUR in owner_species.species_traits))) //Ethereal code. Motherfuckers. - if(owner_species.fixed_mut_color) - species_color = owner_species.fixed_mut_color + if(palette) + var/datum/color_palette/located = human_owner.dna.color_palettes[palette] + if(!located) + species_color = initial(palette.default_color) + species_color = located.return_color(palette_key) else - species_color = human_owner.dna.features["mcolor"] + var/datum/species/owner_species = human_owner.dna.species + if(owner_species.fixed_mut_color) + species_color = owner_species.fixed_mut_color + else + if(should_draw_greyscale) + CRASH("Forgot to move something to new color_palette system [src]") else - species_color = null + skin_tone = "" + species_color = "" draw_color = variable_color if(should_draw_greyscale) //Should the limb be colored? - draw_color ||= (species_color) || (skin_tone && skintone2hex(skin_tone)) + draw_color ||= species_color || (skin_tone ? skintone2hex(skin_tone) : null) recolor_external_organs() return TRUE @@ -951,7 +976,9 @@ image_dir = SOUTH if(dmg_overlay_type) if(brutestate) - . += image('icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER, image_dir) + var/image/bruteimage = image('icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_[brutestate]0", -DAMAGE_LAYER, image_dir) + bruteimage.color = damage_color + . += bruteimage if(burnstate) . += image('icons/mob/effects/dam_mob.dmi', "[dmg_overlay_type]_[body_zone]_0[burnstate]", -DAMAGE_LAYER, image_dir) @@ -1198,46 +1225,6 @@ return ((biological_state & BIO_BLOODED) && (!owner || !HAS_TRAIT(owner, TRAIT_NOBLOOD))) -/** - * apply_gauze() is used to- well, apply gauze to a bodypart - * - * As of the Wounds 2 PR, all bleeding is now bodypart based rather than the old bleedstacks system, and 90% of standard bleeding comes from flesh wounds (the exception is embedded weapons). - * The same way bleeding is totaled up by bodyparts, gauze now applies to all wounds on the same part. Thus, having a slash wound, a pierce wound, and a broken bone wound would have the gauze - * applying blood staunching to the first two wounds, while also acting as a sling for the third one. Once enough blood has been absorbed or all wounds with the ACCEPTS_GAUZE flag have been cleared, - * the gauze falls off. - * - * Arguments: - * * gauze- Just the gauze stack we're taking a sheet from to apply here - */ -/obj/item/bodypart/proc/apply_gauze(obj/item/stack/gauze) - if(!istype(gauze) || !gauze.absorption_capacity) - return - var/newly_gauzed = FALSE - if(!current_gauze) - newly_gauzed = TRUE - QDEL_NULL(current_gauze) - current_gauze = new gauze.type(src, 1) - gauze.use(1) - if(newly_gauzed) - SEND_SIGNAL(src, COMSIG_BODYPART_GAUZED, gauze) - -/** - * seep_gauze() is for when a gauze wrapping absorbs blood or pus from wounds, lowering its absorption capacity. - * - * The passed amount of seepage is deducted from the bandage's absorption capacity, and if we reach a negative absorption capacity, the bandages falls off and we're left with nothing. - * - * Arguments: - * * seep_amt - How much absorption capacity we're removing from our current bandages (think, how much blood or pus are we soaking up this tick?) - */ -/obj/item/bodypart/proc/seep_gauze(seep_amt = 0) - if(!current_gauze) - return - current_gauze.absorption_capacity -= seep_amt - if(current_gauze.absorption_capacity <= 0) - owner.visible_message(span_danger("\The [current_gauze.name] on [owner]'s [name] falls away in rags."), span_warning("\The [current_gauze.name] on your [name] falls away in rags."), vision_distance=COMBAT_MESSAGE_RANGE) - QDEL_NULL(current_gauze) - SEND_SIGNAL(src, COMSIG_BODYPART_GAUZE_DESTROYED) - ///Loops through all of the bodypart's external organs and update's their color. /obj/item/bodypart/proc/recolor_external_organs() for(var/datum/bodypart_overlay/mutant/overlay in bodypart_overlays) @@ -1327,3 +1314,66 @@ return "metal" return "error" + +/// Returns what message is displayed when the bodypart is on the cusp of being dismembered. +/obj/item/bodypart/proc/get_soon_dismember_message() + return ", threatening to sever it entirely" + +/obj/item/bodypart/chest/get_soon_dismember_message() + return ", threatening to split it open" // we don't sever, we dump organs when "dismembered" + +/obj/item/bodypart/head/get_soon_dismember_message() + return ", threatening to split it open" // we don't sever, we cranial fissure when "dismembered" // we also don't dismember i think + +/obj/item/bodypart/proc/return_compoostion_precent(mob/living/carbon/checker) + var/matching_ids = 0 + for(var/obj/item/bodypart/bodypart as anything in checker.bodyparts) + if((bodypart.limb_id != limb_id) && !(bodypart.limb_id in shared_composition)) + continue + matching_ids++ + + return matching_ids / TOTAL_BODYPART_COUNT + +/obj/item/bodypart/proc/check_removal_composition(mob/living/carbon/remover) + var/precent = return_compoostion_precent(remover) + + for(var/item as anything in composition_effects) + if(composition_effects[item] < precent) + continue + if(!ispath(item)) + REMOVE_TRAIT(remover, item, BODYPART_TRAIT) + else + if(ispath(item, /datum/component)) + var/datum/component/component = remover.GetComponent(item) + if(component) + qdel(component) + else if(ispath(item, /datum/element)) + if(!HasElement(remover, item)) + continue + remover.RemoveElement(item) + +/obj/item/bodypart/proc/check_adding_composition(mob/living/carbon/adder) + var/precent = return_compoostion_precent(adder) + + for(var/item as anything in composition_effects) + if(composition_effects[item] > precent) + continue + if(!ispath(item)) + if(HAS_TRAIT_FROM(adder, item, BODYPART_TRAIT)) + continue + ADD_TRAIT(adder, item, BODYPART_TRAIT) + else + if(ispath(item, /datum/component)) + if(adder.GetComponent(item)) + continue + adder.AddComponent(item) + else if(ispath(item, /datum/element)) + if(HasElement(adder, item)) + continue + adder.AddElement(item) + +/obj/item/bodypart/proc/reassess_body_composition(mob/living/carbon/adder) + SIGNAL_HANDLER + + check_removal_composition(adder) //remove first + check_adding_composition(adder) //then diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 6991a2bdd46a..bec42b32b08c 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -77,6 +77,8 @@ //limb is out and about, it can't really be considered an implant bodypart_flags &= ~BODYPART_IMPLANTED owner.remove_bodypart(src) + if(speed_modifier) + owner.update_bodypart_speed_modifier() for(var/datum/wound/wound as anything in wounds) wound.remove_wound(TRUE) @@ -253,6 +255,15 @@ arm_owner.dropItemToGround(arm_owner.gloves, TRUE, violent = violent) arm_owner.update_worn_gloves() //to remove the bloody hands overlay +/obj/item/bodypart/arm/try_attach_limb(mob/living/carbon/new_arm_owner, special = FALSE) + . = ..() + + if(!.) + return + + new_arm_owner.update_worn_gloves() + + /obj/item/bodypart/leg/drop_limb(special, dismembered, violent) if(owner && !special) if(owner.legcuffed) @@ -332,6 +343,9 @@ hand.update_appearance() new_limb_owner.update_worn_gloves() + if(speed_modifier) + new_limb_owner.update_bodypart_speed_modifier() + LAZYREMOVE(new_limb_owner.body_zone_dismembered_by, body_zone) if(special) //non conventional limb attachment diff --git a/code/modules/surgery/bodyparts/head_hair_and_lips.dm b/code/modules/surgery/bodyparts/head_hair_and_lips.dm index 670462bdac8c..1e3f2078ca46 100644 --- a/code/modules/surgery/bodyparts/head_hair_and_lips.dm +++ b/code/modules/surgery/bodyparts/head_hair_and_lips.dm @@ -8,6 +8,16 @@ var/mob/living/carbon/human/human_head_owner = owner var/datum/species/owner_species = human_head_owner.dna.species + var/offset = 0 + if(!istype(owner, /mob/living/carbon/human/dummy)) + switch(human_head_owner.get_mob_height()) + if(HUMAN_HEIGHT_DWARF) + offset = -2 + if(HUMAN_HEIGHT_SHORTEST) + offset = -1 + if(HUMAN_HEIGHT_SHORT) + offset = 0 + //HIDDEN CHECKS START hair_hidden = FALSE facial_hair_hidden = FALSE @@ -75,6 +85,7 @@ //Overlay facial_overlay = mutable_appearance(sprite_accessory.icon, sprite_accessory.icon_state, -HAIR_LAYER) facial_overlay.alpha = facial_hair_alpha + facial_overlay.pixel_y = offset //Gradients facial_hair_gradient_style = LAZYACCESS(human_head_owner.grad_style, GRADIENT_FACIAL_HAIR_KEY) if(facial_hair_gradient_style) @@ -89,6 +100,7 @@ //Overlay hair_overlay = mutable_appearance(sprite_accessory.icon, sprite_accessory.icon_state, -HAIR_LAYER) hair_overlay.alpha = hair_alpha + //hair_overlay.pixel_y = offset //Gradients hair_gradient_style = LAZYACCESS(human_head_owner.grad_style, GRADIENT_HAIR_KEY) if(hair_gradient_style) diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index 500437797654..bfcbb0b7062a 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -16,6 +16,8 @@ ///The bodytype(s) allowed to attach to this chest. var/acceptable_bodytype = BODYTYPE_HUMANOID + var/icon/ass_image + var/list/wing_types = list(/obj/item/organ/external/wings/functional/angel) var/obj/item/cavity_item /obj/item/bodypart/chest/can_dismember(obj/item/item) @@ -72,101 +74,6 @@ bodytype = BODYTYPE_LARVA_PLACEHOLDER | BODYTYPE_ORGANIC acceptable_bodytype = BODYTYPE_LARVA_PLACEHOLDER -/// Parent Type for arms, should not appear in game. -/obj/item/bodypart/arm - name = "arm" - desc = "Hey buddy give me a HAND and report this to the github because you shouldn't be seeing this." - attack_verb_continuous = list("slaps", "punches") - attack_verb_simple = list("slap", "punch") - max_damage = 50 - aux_layer = BODYPARTS_HIGH_LAYER - body_damage_coeff = 0.75 - can_be_disabled = TRUE - unarmed_attack_verb = "punch" /// The classic punch, wonderfully classic and completely random - unarmed_damage_low = 5 - unarmed_damage_high = 5 - unarmed_stun_threshold = 10 - body_zone = BODY_ZONE_L_ARM - - biological_state = BIO_STANDARD_JOINTED - -/obj/item/bodypart/arm/Destroy() - return ..() - -/obj/item/bodypart/arm/left - name = "left arm" - desc = "Did you know that the word 'sinister' stems originally from the \ - Latin 'sinestra' (left hand), because the left hand was supposed to \ - be possessed by the devil? This arm appears to be possessed by no \ - one though." - icon_state = "default_human_l_arm" - body_zone = BODY_ZONE_L_ARM - body_part = ARM_LEFT - plaintext_zone = "left arm" - aux_zone = BODY_ZONE_PRECISE_L_HAND - held_index = 1 - px_x = -6 - px_y = 0 - bodypart_trait_source = LEFT_ARM_TRAIT - - -/obj/item/bodypart/arm/left/set_owner(new_owner) - . = ..() - if(. == FALSE) - return - if(owner) - if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_ARM)) - ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) - RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_loss)) - else - REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) - RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_gain)) - if(.) - var/mob/living/carbon/old_owner = . - if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_L_ARM)) - UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM)) - if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_L_ARM)) - REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) - else - UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM)) - - -///Proc to react to the owner gaining the TRAIT_PARALYSIS_L_ARM trait. -/obj/item/bodypart/arm/left/proc/on_owner_paralysis_gain(mob/living/carbon/source) - SIGNAL_HANDLER - ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) - UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM)) - RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_loss)) - - -///Proc to react to the owner losing the TRAIT_PARALYSIS_L_ARM trait. -/obj/item/bodypart/arm/left/proc/on_owner_paralysis_loss(mob/living/carbon/source) - SIGNAL_HANDLER - REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) - UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM)) - RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_gain)) - - -/obj/item/bodypart/arm/left/set_disabled(new_disabled) - . = ..() - if(isnull(.) || !owner) - return - - if(!.) - if(bodypart_disabled) - owner.set_usable_hands(owner.usable_hands - 1) - if(owner.stat < UNCONSCIOUS) - to_chat(owner, span_userdanger("You lose control of your [name]!")) - if(held_index) - owner.dropItemToGround(owner.get_item_for_held_index(held_index)) - else if(!bodypart_disabled) - owner.set_usable_hands(owner.usable_hands + 1) - - if(owner.hud_used) - var/atom/movable/screen/inventory/hand/hand_screen_object = owner.hud_used.hand_slots["[held_index]"] - hand_screen_object?.update_appearance() - - /obj/item/bodypart/arm/left/monkey icon = 'icons/mob/species/monkey/bodyparts.dmi' icon_static = 'icons/mob/species/monkey/bodyparts.dmi' @@ -198,78 +105,6 @@ should_draw_greyscale = FALSE -/obj/item/bodypart/arm/right - name = "right arm" - desc = "Over 87% of humans are right handed. That figure is much lower \ - among humans missing their right arm." - body_zone = BODY_ZONE_R_ARM - body_part = ARM_RIGHT - icon_state = "default_human_r_arm" - plaintext_zone = "right arm" - aux_zone = BODY_ZONE_PRECISE_R_HAND - aux_layer = BODYPARTS_HIGH_LAYER - held_index = 2 - px_x = 6 - px_y = 0 - bodypart_trait_source = RIGHT_ARM_TRAIT - -/obj/item/bodypart/arm/right/set_owner(new_owner) - . = ..() - if(. == FALSE) - return - if(owner) - if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_ARM)) - ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) - RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_loss)) - else - REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) - RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_gain)) - if(.) - var/mob/living/carbon/old_owner = . - if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_R_ARM)) - UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM)) - if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_R_ARM)) - REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) - else - UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM)) - - -///Proc to react to the owner gaining the TRAIT_PARALYSIS_R_ARM trait. -/obj/item/bodypart/arm/right/proc/on_owner_paralysis_gain(mob/living/carbon/source) - SIGNAL_HANDLER - ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) - UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM)) - RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_loss)) - - -///Proc to react to the owner losing the TRAIT_PARALYSIS_R_ARM trait. -/obj/item/bodypart/arm/right/proc/on_owner_paralysis_loss(mob/living/carbon/source) - SIGNAL_HANDLER - REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) - UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM)) - RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_gain)) - - -/obj/item/bodypart/arm/right/set_disabled(new_disabled) - . = ..() - if(isnull(.) || !owner) - return - - if(!.) - if(bodypart_disabled) - owner.set_usable_hands(owner.usable_hands - 1) - if(owner.stat < UNCONSCIOUS) - to_chat(owner, span_userdanger("You lose control of your [name]!")) - if(held_index) - owner.dropItemToGround(owner.get_item_for_held_index(held_index)) - else if(!bodypart_disabled) - owner.set_usable_hands(owner.usable_hands + 1) - - if(owner.hud_used) - var/atom/movable/screen/inventory/hand/hand_screen_object = owner.hud_used.hand_slots["[held_index]"] - hand_screen_object?.update_appearance() - - /obj/item/bodypart/arm/right/monkey icon = 'icons/mob/species/monkey/bodyparts.dmi' icon_static = 'icons/mob/species/monkey/bodyparts.dmi' @@ -325,6 +160,8 @@ var/old_limb_id /// Used by the bloodysoles component to make footprints var/footprint_sprite = FOOTPRINT_SPRITE_SHOES + ///our step sound + var/list/step_sounds biological_state = BIO_STANDARD_JOINTED /obj/item/bodypart/leg/Destroy() diff --git a/code/modules/surgery/bodyparts/species_parts/android_parts.dm b/code/modules/surgery/bodyparts/species_parts/android_parts.dm index b7a1f55bf43f..6f7700c266f3 100644 --- a/code/modules/surgery/bodyparts/species_parts/android_parts.dm +++ b/code/modules/surgery/bodyparts/species_parts/android_parts.dm @@ -10,6 +10,8 @@ /obj/item/bodypart/chest/robot/android change_exempt_flags = null + bodypart_traits = list(TRAIT_LIMBATTACHMENT) + wing_types = list(/obj/item/organ/external/wings/functional/robotic) /obj/item/bodypart/arm/left/robot/android change_exempt_flags = null @@ -19,6 +21,8 @@ /obj/item/bodypart/leg/left/robot/android change_exempt_flags = null + step_sounds = list('sound/effects/servostep.ogg') /obj/item/bodypart/leg/right/robot/android change_exempt_flags = null + step_sounds = list('sound/effects/servostep.ogg') diff --git a/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm index 06db450e5dd2..9d524cd75c2f 100644 --- a/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/ethereal_bodyparts.dm @@ -6,6 +6,8 @@ attack_type = BURN // bish buzz unarmed_attack_sound = 'sound/weapons/etherealhit.ogg' unarmed_miss_sound = 'sound/weapons/etherealmiss.ogg' + palette = /datum/color_palette/generic_colors + palette_key = "ethereal_color" /obj/item/bodypart/head/ethereal/update_limb(dropping_limb, is_creating) . = ..() @@ -20,6 +22,8 @@ limb_id = SPECIES_ETHEREAL is_dimorphic = FALSE dmg_overlay_type = null + palette = /datum/color_palette/generic_colors + palette_key = "ethereal_color" /obj/item/bodypart/chest/ethereal/update_limb(dropping_limb, is_creating) . = ..() @@ -36,6 +40,8 @@ unarmed_attack_verb = "burn" unarmed_attack_sound = 'sound/weapons/etherealhit.ogg' unarmed_miss_sound = 'sound/weapons/etherealmiss.ogg' + palette = /datum/color_palette/generic_colors + palette_key = "ethereal_color" /obj/item/bodypart/arm/left/ethereal/update_limb(dropping_limb, is_creating) . = ..() @@ -52,6 +58,8 @@ unarmed_attack_verb = "burn" unarmed_attack_sound = 'sound/weapons/etherealhit.ogg' unarmed_miss_sound = 'sound/weapons/etherealmiss.ogg' + palette = /datum/color_palette/generic_colors + palette_key = "ethereal_color" /obj/item/bodypart/arm/right/ethereal/update_limb(dropping_limb, is_creating) . = ..() @@ -68,6 +76,8 @@ attack_type = BURN // bish buzz unarmed_attack_sound = 'sound/weapons/etherealhit.ogg' unarmed_miss_sound = 'sound/weapons/etherealmiss.ogg' + palette = /datum/color_palette/generic_colors + palette_key = "ethereal_color" /obj/item/bodypart/leg/left/ethereal/update_limb(dropping_limb, is_creating) . = ..() @@ -83,6 +93,8 @@ attack_type = BURN // bish buzz unarmed_attack_sound = 'sound/weapons/etherealhit.ogg' unarmed_miss_sound = 'sound/weapons/etherealmiss.ogg' + palette = /datum/color_palette/generic_colors + palette_key = "ethereal_color" /obj/item/bodypart/leg/right/ethereal/update_limb(dropping_limb, is_creating) . = ..() diff --git a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm index 1b496fc3bd74..d8ded87d42a0 100644 --- a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm @@ -3,11 +3,19 @@ limb_id = SPECIES_LIZARD is_dimorphic = FALSE head_flags = HEAD_HAIR| HEAD_EYESPRITES | HEAD_EYEHOLES | HEAD_DEBRAIN | HEAD_EYECOLOR + composition_effects = list(TRAIT_COLD_BLOODED = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/chest/lizard icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' limb_id = SPECIES_LIZARD is_dimorphic = FALSE + ass_image = 'icons/ass/asslizard.png' + composition_effects = list(TRAIT_COLD_BLOODED = 0.5) + wing_types = list(/obj/item/organ/external/wings/functional/dragon) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/left/lizard icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' @@ -16,6 +24,9 @@ unarmed_attack_effect = ATTACK_EFFECT_CLAW unarmed_attack_sound = 'sound/weapons/slash.ogg' unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' + composition_effects = list(TRAIT_COLD_BLOODED = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/right/lizard icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' @@ -24,12 +35,15 @@ unarmed_attack_effect = ATTACK_EFFECT_CLAW unarmed_attack_sound = 'sound/weapons/slash.ogg' unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' + composition_effects = list(TRAIT_COLD_BLOODED = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/left/lizard/ashwalker - bodypart_traits = list(TRAIT_CHUNKYFINGERS) + hand_traits = list(TRAIT_CHUNKYFINGERS) /obj/item/bodypart/arm/right/lizard/ashwalker - bodypart_traits = list(TRAIT_CHUNKYFINGERS) + hand_traits = list(TRAIT_CHUNKYFINGERS) /obj/item/bodypart/leg/left/lizard icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' @@ -37,6 +51,15 @@ can_be_digitigrade = TRUE digitigrade_id = "digitigrade" footprint_sprite = FOOTPRINT_SPRITE_CLAWS + composition_effects = list(TRAIT_COLD_BLOODED = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR + step_sounds = list( + 'sound/effects/footstep/hardclaw1.ogg', + 'sound/effects/footstep/hardclaw2.ogg', + 'sound/effects/footstep/hardclaw3.ogg', + 'sound/effects/footstep/hardclaw4.ogg', + ) /obj/item/bodypart/leg/right/lizard icon_greyscale = 'icons/mob/species/lizard/bodyparts.dmi' @@ -44,3 +67,18 @@ can_be_digitigrade = TRUE digitigrade_id = "digitigrade" footprint_sprite = FOOTPRINT_SPRITE_CLAWS + composition_effects = list(TRAIT_COLD_BLOODED = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR + step_sounds = list( + 'sound/effects/footstep/hardclaw1.ogg', + 'sound/effects/footstep/hardclaw2.ogg', + 'sound/effects/footstep/hardclaw3.ogg', + 'sound/effects/footstep/hardclaw4.ogg', + ) + +/obj/item/bodypart/leg/right/lizard/ashwalker + bodypart_traits = list(TRAIT_HARD_SOLES) + +/obj/item/bodypart/leg/left/lizard/ashwalker + bodypart_traits = list(TRAIT_HARD_SOLES) diff --git a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm index 3522df549ea8..31c7a40e6cad 100644 --- a/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/misc_bodyparts.dm @@ -3,29 +3,58 @@ limb_id = SPECIES_SNAIL is_dimorphic = FALSE head_flags = HEAD_EYESPRITES|HEAD_DEBRAIN + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/chest/snail limb_id = SPECIES_SNAIL is_dimorphic = FALSE + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/left/snail limb_id = SPECIES_SNAIL unarmed_attack_verb = "slap" unarmed_attack_effect = ATTACK_EFFECT_DISARM unarmed_damage_high = 0.5 //snails are soft and squishy + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/right/snail limb_id = SPECIES_SNAIL unarmed_attack_verb = "slap" unarmed_attack_effect = ATTACK_EFFECT_DISARM unarmed_damage_high = 0.5 + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/left/snail limb_id = SPECIES_SNAIL unarmed_damage_high = 0.5 + speed_modifier = 3 //disgustingly slow + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR + /obj/item/bodypart/leg/right/snail limb_id = SPECIES_SNAIL unarmed_damage_high = 0.5 + speed_modifier = 3 //disgustingly slow + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR + +/obj/item/bodypart/leg/left/zombie/infectious + limb_id = SPECIES_ZOMBIE + should_draw_greyscale = FALSE + speed_modifier = 0.8 //braaaaains + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR + +/obj/item/bodypart/leg/right/zombie/infectious + limb_id = SPECIES_ZOMBIE + should_draw_greyscale = FALSE + speed_modifier = 0.8 //braaaaains + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR ///ABDUCTOR /obj/item/bodypart/head/abductor @@ -38,16 +67,17 @@ limb_id = SPECIES_ABDUCTOR is_dimorphic = FALSE should_draw_greyscale = FALSE + ass_image = 'icons/ass/assgrey.png' /obj/item/bodypart/arm/left/abductor limb_id = SPECIES_ABDUCTOR should_draw_greyscale = FALSE - bodypart_traits = list(TRAIT_CHUNKYFINGERS) + hand_traits = list(TRAIT_CHUNKYFINGERS, TRAIT_CHUNKYFINGERS_IGNORE_BATON) /obj/item/bodypart/arm/right/abductor limb_id = SPECIES_ABDUCTOR should_draw_greyscale = FALSE - bodypart_traits = list(TRAIT_CHUNKYFINGERS) + hand_traits = list(TRAIT_CHUNKYFINGERS, TRAIT_CHUNKYFINGERS_IGNORE_BATON) /obj/item/bodypart/leg/left/abductor limb_id = SPECIES_ABDUCTOR @@ -64,32 +94,52 @@ is_dimorphic = TRUE dmg_overlay_type = null head_flags = HEAD_ALL_FEATURES + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/chest/jelly biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_JELLYPERSON is_dimorphic = TRUE dmg_overlay_type = null + composition_effects = list(/datum/element/soft_landing = 0.5) + ass_image = 'icons/ass/assslime.png' + wing_types = list(/obj/item/organ/external/wings/functional/slime) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/left/jelly biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) limb_id = SPECIES_JELLYPERSON dmg_overlay_type = null + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/right/jelly biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) limb_id = SPECIES_JELLYPERSON dmg_overlay_type = null + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/left/jelly biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) limb_id = SPECIES_JELLYPERSON dmg_overlay_type = null + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/right/jelly biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) limb_id = SPECIES_JELLYPERSON dmg_overlay_type = null + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR ///SLIME /obj/item/bodypart/head/slime @@ -97,54 +147,84 @@ limb_id = SPECIES_SLIMEPERSON is_dimorphic = FALSE head_flags = HEAD_ALL_FEATURES + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/chest/slime biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_SLIMEPERSON is_dimorphic = TRUE + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/left/slime biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) limb_id = SPECIES_SLIMEPERSON + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/right/slime biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) limb_id = SPECIES_SLIMEPERSON + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/left/slime biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_SLIMEPERSON + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/right/slime biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) limb_id = SPECIES_SLIMEPERSON + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR ///LUMINESCENT /obj/item/bodypart/head/luminescent biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_LUMINESCENT is_dimorphic = TRUE + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/chest/luminescent biological_state = (BIO_FLESH|BIO_BLOODED) limb_id = SPECIES_LUMINESCENT is_dimorphic = TRUE + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/left/luminescent biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) limb_id = SPECIES_LUMINESCENT + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/right/luminescent biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) limb_id = SPECIES_LUMINESCENT + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/left/luminescent biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) limb_id = SPECIES_LUMINESCENT + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/right/luminescent biological_state = (BIO_FLESH|BIO_BLOODED|BIO_JOINTED) limb_id = SPECIES_LUMINESCENT + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR ///ZOMBIE /obj/item/bodypart/head/zombie @@ -152,36 +232,48 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE head_flags = HEAD_EYESPRITES | HEAD_DEBRAIN | HEAD_HAIR + composition_effects = list(TRAIT_COLD_BLOODED = 0.5) /obj/item/bodypart/chest/zombie limb_id = SPECIES_ZOMBIE is_dimorphic = FALSE should_draw_greyscale = FALSE + bodypart_traits = list(TRAIT_LIMBATTACHMENT) + composition_effects = list(TRAIT_COLD_BLOODED = 0.5) /obj/item/bodypart/arm/left/zombie limb_id = SPECIES_ZOMBIE should_draw_greyscale = FALSE + composition_effects = list(TRAIT_COLD_BLOODED = 0.5) /obj/item/bodypart/arm/right/zombie limb_id = SPECIES_ZOMBIE should_draw_greyscale = FALSE + composition_effects = list(TRAIT_COLD_BLOODED = 0.5) /obj/item/bodypart/leg/left/zombie limb_id = SPECIES_ZOMBIE should_draw_greyscale = FALSE + composition_effects = list(TRAIT_COLD_BLOODED = 0.5) /obj/item/bodypart/leg/right/zombie limb_id = SPECIES_ZOMBIE should_draw_greyscale = FALSE + composition_effects = list(TRAIT_COLD_BLOODED = 0.5) ///PODPEOPLE /obj/item/bodypart/head/pod limb_id = SPECIES_PODPERSON is_dimorphic = TRUE + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/chest/pod limb_id = SPECIES_PODPERSON is_dimorphic = TRUE + ass_image = 'icons/ass/asspodperson.png' + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/left/pod limb_id = SPECIES_PODPERSON @@ -189,6 +281,9 @@ unarmed_attack_effect = ATTACK_EFFECT_CLAW unarmed_attack_sound = 'sound/weapons/slice.ogg' unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' + hand_traits = list(TRAIT_PLANT_SAFE) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/right/pod limb_id = SPECIES_PODPERSON @@ -196,12 +291,19 @@ unarmed_attack_effect = ATTACK_EFFECT_CLAW unarmed_attack_sound = 'sound/weapons/slice.ogg' unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' + hand_traits = list(TRAIT_PLANT_SAFE) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/left/pod limb_id = SPECIES_PODPERSON + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/right/pod limb_id = SPECIES_PODPERSON + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR ///FLY /obj/item/bodypart/head/fly @@ -214,6 +316,7 @@ limb_id = SPECIES_FLYPERSON is_dimorphic = TRUE should_draw_greyscale = FALSE + wing_types = list(/obj/item/organ/external/wings/functional/fly) /obj/item/bodypart/arm/left/fly limb_id = SPECIES_FLYPERSON @@ -260,10 +363,10 @@ should_draw_greyscale = FALSE /obj/item/bodypart/arm/left/shadow/nightmare - bodypart_traits = list(TRAIT_CHUNKYFINGERS) + hand_traits = list(TRAIT_CHUNKYFINGERS) /obj/item/bodypart/arm/right/shadow/nightmare - bodypart_traits = list(TRAIT_CHUNKYFINGERS) + hand_traits = list(TRAIT_CHUNKYFINGERS) ///SKELETON /obj/item/bodypart/head/skeleton @@ -280,6 +383,8 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE dmg_overlay_type = null + bodypart_traits = list(TRAIT_LIMBATTACHMENT) + wing_types = list(/obj/item/organ/external/wings/functional/skeleton) /obj/item/bodypart/arm/left/skeleton biological_state = (BIO_BONE|BIO_JOINTED) @@ -310,35 +415,49 @@ limb_id = SPECIES_MUSHROOM is_dimorphic = TRUE head_flags = NONE + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/chest/mushroom limb_id = SPECIES_MUSHROOM is_dimorphic = TRUE bodypart_traits = list(TRAIT_NO_JUMPSUIT) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/left/mushroom limb_id = SPECIES_MUSHROOM unarmed_damage_low = 8 unarmed_damage_high = 8 unarmed_stun_threshold = 14 + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/right/mushroom limb_id = SPECIES_MUSHROOM unarmed_damage_low = 8 unarmed_damage_high = 8 unarmed_stun_threshold = 14 + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/left/mushroom limb_id = SPECIES_MUSHROOM unarmed_damage_low = 15 unarmed_damage_high = 15 unarmed_stun_threshold = 14 + speed_modifier = 0.75 //big fungus big fungus + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/right/mushroom limb_id = SPECIES_MUSHROOM unarmed_damage_low = 15 unarmed_damage_high = 15 unarmed_stun_threshold = 14 + speed_modifier = 0.75 //big fungus big fungus + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR ///GOLEMS (i hate xenobio SO FUCKING MUCH) (from 2022: Yeah I fucking feel your pain brother) (2024: yeah this is shit) /obj/item/bodypart/head/golem @@ -363,7 +482,7 @@ bodytype = BODYTYPE_ORGANIC limb_id = SPECIES_GOLEM dmg_overlay_type = null - bodypart_traits = list(TRAIT_CHUNKYFINGERS) + hand_traits = list(TRAIT_CHUNKYFINGERS) unarmed_damage_low = 8 // I'd like to take the moment that maintaining all of these random ass golem speciese is hell and oranges was right unarmed_damage_high = 8 unarmed_stun_threshold = 11 @@ -384,7 +503,7 @@ bodytype = BODYTYPE_ORGANIC limb_id = SPECIES_GOLEM dmg_overlay_type = null - bodypart_traits = list(TRAIT_CHUNKYFINGERS) + hand_traits = list(TRAIT_CHUNKYFINGERS) unarmed_damage_low = 8 unarmed_damage_high = 8 unarmed_stun_threshold = 11 @@ -408,6 +527,7 @@ unarmed_damage_low = 11 unarmed_damage_high = 11 unarmed_stun_threshold = 11 + speed_modifier = 1.5 /obj/item/bodypart/leg/right/golem biological_state = (BIO_BONE|BIO_JOINTED) @@ -417,6 +537,7 @@ unarmed_damage_low = 11 unarmed_damage_high = 11 unarmed_stun_threshold = 11 + speed_modifier = 1.5 ///CULT GOLEM /obj/item/bodypart/head/golem/cult diff --git a/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm index f0fc78f83f0b..5c0de35b4571 100644 --- a/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/moth_bodyparts.dm @@ -14,6 +14,7 @@ limb_id = SPECIES_MOTH is_dimorphic = TRUE should_draw_greyscale = FALSE + wing_types = list(/obj/item/organ/external/wings/functional/moth/megamoth, /obj/item/organ/external/wings/functional/moth/mothra) /obj/item/bodypart/arm/left/moth icon = 'icons/mob/species/moth/bodyparts.dmi' diff --git a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm index fad07868ea04..350a9ca55118 100644 --- a/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/plasmaman_bodyparts.dm @@ -18,6 +18,7 @@ is_dimorphic = FALSE should_draw_greyscale = FALSE dmg_overlay_type = null + ass_image = 'icons/ass/assplasma.png' /obj/item/bodypart/arm/left/plasmaman icon = 'icons/mob/species/plasmaman/bodyparts.dmi' diff --git a/code/modules/surgery/healing.dm b/code/modules/surgery/healing.dm index 8ff8a5d78991..d0d21b82f4c1 100644 --- a/code/modules/surgery/healing.dm +++ b/code/modules/surgery/healing.dm @@ -159,7 +159,7 @@ var/estimated_remaining_steps = target.getBruteLoss() / brute_healed var/progress_text - if(locate(/obj/item/healthanalyzer) in user.held_items) + if(get_perfect_information(user, target)) progress_text = ". Remaining brute: [target.getBruteLoss()]" else switch(estimated_remaining_steps) @@ -224,7 +224,7 @@ var/estimated_remaining_steps = target.getFireLoss() / burn_healed var/progress_text - if(locate(/obj/item/healthanalyzer) in user.held_items) + if(get_perfect_information(user, target)) progress_text = ". Remaining burn: [target.getFireLoss()]" else switch(estimated_remaining_steps) @@ -292,7 +292,7 @@ var/progress_text - if(locate(/obj/item/healthanalyzer) in user.held_items) + if(get_perfect_information(user, target)) if(target.getBruteLoss()) progress_text = ". Remaining brute: [target.getBruteLoss()]" if(target.getFireLoss()) diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm index 487ac25091ee..61fe34778817 100644 --- a/code/modules/surgery/limb_augmentation.dm +++ b/code/modules/surgery/limb_augmentation.dm @@ -14,7 +14,7 @@ /datum/surgery_step/replace_limb/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - if(NOAUGMENTS in target.dna.species.species_traits) + if(HAS_TRAIT(target, TRAIT_NO_AUGMENTS)) to_chat(user, span_warning("[target] cannot be augmented!")) return SURGERY_STEP_FAIL if(istype(tool, /obj/item/borg/apparatus/organ_storage) && istype(tool.contents[1], /obj/item/bodypart)) diff --git a/code/modules/surgery/organs/_organ.dm b/code/modules/surgery/organs/_organ.dm index b9c959bb7dfa..51015e0692d8 100644 --- a/code/modules/surgery/organs/_organ.dm +++ b/code/modules/surgery/organs/_organ.dm @@ -415,18 +415,34 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) replacement.set_organ_damage(damage) /// Called by medical scanners to get a simple summary of how healthy the organ is. Returns an empty string if things are fine. -/obj/item/organ/proc/get_status_text() - var/status = "" +/obj/item/organ/proc/get_status_text(advanced, add_tooltips) + if(organ_flags & ORGAN_FAILING) + . = "Non-Functional" + if(add_tooltips) + . = span_tooltip("Repair or replace surgically.", .) + return . + if(owner.has_reagent(/datum/reagent/inverse/technetium)) - status = " organ is [round((damage/maxHealth)*100, 1)]% damaged." - else if(organ_flags & ORGAN_FAILING) - status = "Non-Functional" - else if(damage > high_threshold) - status = "Severely Damaged" - else if (damage > low_threshold) - status = "Mildly Damaged" - - return status + return "[round((damage/maxHealth)*100, 1)]% damaged" + if(damage > high_threshold) + . = "Severely Damaged" + if(add_tooltips && owner.stat != DEAD) + . = span_tooltip("[healing_factor ? "Treat with rest or use specialty medication." : "Repair surgically or use specialty medication."]", .) + return . + if(damage > low_threshold) + . = "Mildly Damaged" + if(add_tooltips && owner.stat != DEAD) + . = span_tooltip("[healing_factor ? "Treat with rest." : "Use specialty medication."]", .) + return . + +/// Determines if this organ is shown when a user has condensed scans enabled +/obj/item/organ/proc/show_on_condensed_scans() + // We don't need to show *most* damaged organs as they have no effects associated + return (organ_flags & (ORGAN_FAILING|ORGAN_VITAL)) + +/// Similar to get_status_text, but appends the text after the damage report, for additional status info +/obj/item/organ/proc/get_status_appendix(advanced, add_tooltips) + return /// Tries to replace the existing organ on the passed mob with this one, with special handling for replacing a brain without ghosting target /obj/item/organ/proc/replace_into(mob/living/carbon/new_owner) diff --git a/code/modules/surgery/organs/appendix.dm b/code/modules/surgery/organs/appendix.dm index 3562f29890c3..3452e9a5954f 100644 --- a/code/modules/surgery/organs/appendix.dm +++ b/code/modules/surgery/organs/appendix.dm @@ -89,11 +89,13 @@ ADD_TRAIT(organ_owner, TRAIT_DISEASELIKE_SEVERITY_MEDIUM, type) organ_owner.med_hud_set_status() -/obj/item/organ/internal/appendix/get_status_text() - if((!(organ_flags & ORGAN_FAILING)) && inflamation_stage) - return "Inflamed" - else - return ..() +/obj/item/organ/internal/appendix/get_status_text(advanced, add_tooltips) + if(!(organ_flags & ORGAN_FAILING) && inflamation_stage) + . = "Inflamed" + if(add_tooltips) + . = span_tooltip("Remove surgically.", .) + return . + return ..() #undef APPENDICITIS_PROB #undef INFLAMATION_ADVANCEMENT_PROB diff --git a/code/modules/surgery/organs/ears.dm b/code/modules/surgery/organs/ears.dm index f191fb54d689..e0006710dcc3 100644 --- a/code/modules/surgery/organs/ears.dm +++ b/code/modules/surgery/organs/ears.dm @@ -28,6 +28,21 @@ // Multiplier for both long term and short term ear damage var/damage_multiplier = 1 +/obj/item/organ/internal/ears/get_status_appendix(advanced, add_tooltips) + if(owner.stat == DEAD) + return + if(advanced) + if(HAS_TRAIT_FROM(owner, TRAIT_DEAF, GENETIC_MUTATION)) + return "Subject is genetically deaf." + if(HAS_TRAIT_FROM(owner, TRAIT_DEAF, EAR_DAMAGE)) + return "Subject is [(organ_flags & ORGAN_FAILING) ? "permanently": "temporarily"] deaf from ear damage." + if(HAS_TRAIT(owner, TRAIT_DEAF)) + return "Subject is deaf." + +/obj/item/organ/internal/ears/show_on_condensed_scans() + // Always show if we have an appendix + return ..() || (owner.stat != DEAD && HAS_TRAIT(owner, TRAIT_DEAF)) + /obj/item/organ/internal/ears/on_life(seconds_per_tick, times_fired) // only inform when things got worse, needs to happen before we heal if((damage > low_threshold && prev_damage < low_threshold) || (damage > high_threshold && prev_damage < high_threshold)) diff --git a/code/modules/surgery/organs/external/_external_organs.dm b/code/modules/surgery/organs/external/_external_organs.dm index ecc1259e00e6..d3d3e6333e6f 100644 --- a/code/modules/surgery/organs/external/_external_organs.dm +++ b/code/modules/surgery/organs/external/_external_organs.dm @@ -284,7 +284,7 @@ /obj/item/organ/external/antennae/proc/try_burn_antennae(mob/living/carbon/human/human) SIGNAL_HANDLER - if(!burnt && human.bodytemperature >= 800 && human.fire_stacks > 0) //do not go into the extremely hot light. you will not survive + if(!burnt && human.get_skin_temperature() >= CELCIUS_TO_KELVIN(175 CELCIUS) && human.fire_stacks > 0) //do not go into the extremely hot light. you will not survive to_chat(human, span_danger("Your precious antennae burn to a crisp!")) burn_antennae() diff --git a/code/modules/surgery/organs/external/wings/functional_wings.dm b/code/modules/surgery/organs/external/wings/functional_wings.dm index a7c2f0b52585..791eb4b06abb 100644 --- a/code/modules/surgery/organs/external/wings/functional_wings.dm +++ b/code/modules/surgery/organs/external/wings/functional_wings.dm @@ -105,11 +105,13 @@ if(!HAS_TRAIT_FROM(human, TRAIT_MOVE_FLYING, SPECIES_FLIGHT_TRAIT)) human.physiology.stun_mod *= 2 human.add_traits(list(TRAIT_NO_FLOATING_ANIM, TRAIT_MOVE_FLYING), SPECIES_FLIGHT_TRAIT) + DO_FLOATING_ANIM(human) passtable_on(human, SPECIES_TRAIT) open_wings() else human.physiology.stun_mod *= 0.5 human.remove_traits(list(TRAIT_NO_FLOATING_ANIM, TRAIT_MOVE_FLYING), SPECIES_FLIGHT_TRAIT) + STOP_FLOATING_ANIM(human) passtable_off(human, SPECIES_TRAIT) close_wings() human.update_body_parts() diff --git a/code/modules/surgery/organs/external/wings/moth_wings.dm b/code/modules/surgery/organs/external/wings/moth_wings.dm index f13b346ab075..9c2f7098d626 100644 --- a/code/modules/surgery/organs/external/wings/moth_wings.dm +++ b/code/modules/surgery/organs/external/wings/moth_wings.dm @@ -44,7 +44,7 @@ /obj/item/organ/external/wings/moth/proc/try_burn_wings(mob/living/carbon/human/human) SIGNAL_HANDLER - if(!burnt && human.bodytemperature >= 800 && human.fire_stacks > 0) //do not go into the extremely hot light. you will not survive + if(!burnt && human.get_skin_temperature() >= CELCIUS_TO_KELVIN(175 CELCIUS) && human.fire_stacks > 0) //do not go into the extremely hot light. you will not survive to_chat(human, span_danger("Your precious wings burn to a crisp!")) human.add_mood_event("burnt_wings", /datum/mood_event/burnt_wings) diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index c8006bd92dc0..016e76320210 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -114,6 +114,33 @@ #define OFFSET_X 1 #define OFFSET_Y 2 +/// Similar to get_status_text, but appends the text after the damage report, for additional status info +/obj/item/organ/internal/eyes/get_status_appendix(advanced, add_tooltips) + if(owner.stat == DEAD || HAS_TRAIT(owner, TRAIT_KNOCKEDOUT)) + return + if(owner.is_blind()) + if(advanced) + if(owner.is_blind_from(EYE_DAMAGE)) + return "Subject is blind from eye damage." + if(owner.is_blind_from(GENETIC_MUTATION)) + return "Subject is genetically blind." + if(owner.is_blind_from(QUIRK_TRAIT)) + return "Subject is permanently blind." + return "Subject is blind." + if(owner.is_nearsighted()) + if(advanced) + if(owner.is_nearsighted_from(EYE_DAMAGE)) + return "Subject is nearsighted from eye damage." + if(owner.is_nearsighted_from(GENETIC_MUTATION)) + return "Subject is genetically nearsighted." + if(owner.is_nearsighted_from(QUIRK_TRAIT)) + return "Subject is permanently nearsighted." + return "Subject is nearsighted." + +/obj/item/organ/internal/eyes/show_on_condensed_scans() + // Always show if we have an appendix + return ..() || (owner.stat != DEAD && !HAS_TRAIT(owner, TRAIT_KNOCKEDOUT) && (owner.is_blind() || owner.is_nearsighted())) + /// This proc generates a list of overlays that the eye should be displayed using for the given parent /obj/item/organ/internal/eyes/proc/generate_body_overlay(mob/living/carbon/human/parent) if(!istype(parent) || parent.get_organ_by_type(/obj/item/organ/internal/eyes) != src) diff --git a/code/modules/surgery/organs/heart.dm b/code/modules/surgery/organs/internal/heart/_heart.dm similarity index 91% rename from code/modules/surgery/organs/heart.dm rename to code/modules/surgery/organs/internal/heart/_heart.dm index 6c317316fc97..ce9995f6ed1b 100644 --- a/code/modules/surgery/organs/heart.dm +++ b/code/modules/surgery/organs/internal/heart/_heart.dm @@ -23,12 +23,21 @@ var/failed = FALSE //to prevent constantly running failing code var/operated = FALSE //whether the heart's been operated on to fix some of its damages + var/datum/blood_type/heart_bloodtype + /obj/item/organ/internal/heart/update_icon_state() icon_state = "[base_icon_state]-[beating ? "on" : "off"]" return ..() +/obj/item/organ/internal/heart/Insert(mob/living/carbon/receiver, special, drop_if_replaced) + . = ..() + if(heart_bloodtype) + receiver.dna?.human_blood_type = heart_bloodtype + /obj/item/organ/internal/heart/Remove(mob/living/carbon/heartless, special = 0) . = ..() + if(heart_bloodtype) + heartless.dna?.human_blood_type = random_human_blood_type() if(!special) addtimer(CALLBACK(src, PROC_REF(stop_if_unowned)), 120) @@ -59,6 +68,29 @@ beating = FALSE update_appearance() +/obj/item/organ/internal/heart/proc/get_heart_rate() + if(!beating) + return 0 + + var/base_amount = 0 + + if(owner.has_status_effect(/datum/status_effect/jitter)) + base_amount = 100 + rand(0, 25) + else if(owner.stat == SOFT_CRIT || owner.stat == HARD_CRIT) + base_amount = 60 + rand(-15, -10) + else + base_amount = 80 + rand(-10, 10) + base_amount += round(owner.getOxyLoss() / 5) + base_amount += ((BLOOD_VOLUME_NORMAL - owner.blood_volume) / 25) + base_amount += owner.pain_controller?.get_heartrate_modifier() + if(owner.has_status_effect(/datum/status_effect/determined)) // adrenaline + base_amount += 10 + + if(owner.has_reagent(/datum/reagent/consumable/coffee)) // funny + base_amount += 10 + + return round(base_amount * clamp(1.5 * ((maxHealth - damage) / maxHealth), 0.5, 1)) // heart damage puts a multiplier on it + /obj/item/organ/internal/heart/on_life(seconds_per_tick, times_fired) ..() @@ -75,6 +107,7 @@ beat = BEAT_SLOW owner.playsound_local(get_turf(owner), slowbeat, 40, 0, channel = CHANNEL_HEARTBEAT, use_reverb = FALSE) to_chat(owner, span_notice("You feel your heart slow down...")) + if(beat == BEAT_SLOW && owner.health > owner.crit_threshold) owner.stop_sound_channel(CHANNEL_HEARTBEAT) beat = BEAT_NONE @@ -88,12 +121,14 @@ owner.stop_sound_channel(CHANNEL_HEARTBEAT) beat = BEAT_NONE - if((organ_flags & ORGAN_FAILING) && owner.can_heartattack() && !(HAS_TRAIT(src, TRAIT_STABLEHEART))) //heart broke, stopped beating, death imminent... unless you have veins that pump blood without a heart - if(owner.stat == CONSCIOUS && beating) // monkestation edit: antispam - owner.visible_message(span_danger("[owner] clutches at [owner.p_their()] chest as if [owner.p_their()] heart is stopping!"), \ - span_userdanger("You feel a terrible pain in your chest, as if your heart has stopped!")) - owner.set_heartattack(TRUE) - failed = TRUE + if((organ_flags & ORGAN_FAILING) || !beating) //heart broke, stopped beating, death imminent... unless you have veins that pump blood without a heart + if(owner.can_heartattack() && !(HAS_TRAIT(src, TRAIT_STABLEHEART))) + if(owner.stat == CONSCIOUS && beating) // monkestation edit: antispam + owner.visible_message(span_danger("[owner] clutches at [owner.p_their()] chest as if [owner.p_their()] heart is stopping!"), \ + span_userdanger("You feel a terrible pain in your chest, as if your heart has stopped!")) + owner.set_heartattack(TRUE) + failed = TRUE + owner.adjust_pain_shock(1 * seconds_per_tick) /obj/item/organ/internal/heart/get_availability(datum/species/owner_species, mob/living/owner_mob) return owner_species.mutantheart @@ -284,6 +319,7 @@ icon_state = "ethereal_heart" //Welp. At least it's more unique in functionaliy. visual = TRUE //This is used by the ethereal species for color desc = "A crystal-like organ that functions similarly to a heart for Ethereals. It can revive its owner." + heart_bloodtype = /datum/blood_type/crew/ethereal ///Cooldown for the next time we can crystalize COOLDOWN_DECLARE(crystalize_cooldown) @@ -531,3 +567,15 @@ // this qdeleted check is just for sanity. if(!QDELETED(src)) qdel(src) + +/obj/item/organ/internal/heart/lizard + name = "lizard heart" + heart_bloodtype = /datum/blood_type/crew/lizard + +/obj/item/organ/internal/heart/pod + name = "plant heart" + heart_bloodtype = /datum/blood_type/water + +/obj/item/organ/internal/heart/spider + name = "spider heart" + heart_bloodtype = /datum/blood_type/spider diff --git a/code/modules/surgery/organs/liver.dm b/code/modules/surgery/organs/internal/liver/_liver.dm old mode 100755 new mode 100644 similarity index 84% rename from code/modules/surgery/organs/liver.dm rename to code/modules/surgery/organs/internal/liver/_liver.dm index eb9f78c05823..27e6a0756ff7 --- a/code/modules/surgery/organs/liver.dm +++ b/code/modules/surgery/organs/internal/liver/_liver.dm @@ -33,6 +33,7 @@ // If the liver handles foods like a clown, it honks like a bike horn // Don't think about it too much. RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_COMEDY_METABOLISM), PROC_REF(on_add_comedy_metabolism)) + RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_COMEDY_METABOLISM), PROC_REF(on_remove_comedy_metabolism)) /* Signal handler for the liver gaining the TRAIT_COMEDY_METABOLISM trait * @@ -50,6 +51,35 @@ // Would that make the clown more or less likely to honk it AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg'=1), 50, falloff_exponent = 20) +/* Signal handler for the liver losing the TRAIT_COMEDY_METABOLISM trait + * + * Basically just removes squeak component + */ +/obj/item/organ/internal/liver/proc/on_remove_comedy_metabolism() + SIGNAL_HANDLER + + qdel(GetComponent(/datum/component/squeak)) + +/// Registers COMSIG_MOB_REAGENT_CHECK from owner +/obj/item/organ/internal/liver/on_insert(mob/living/carbon/organ_owner, special) + . = ..() + RegisterSignal(organ_owner, COMSIG_SPECIES_HANDLE_CHEMICAL, PROC_REF(handle_chemical)) + +/// Unregisters COMSIG_MOB_REAGENT_CHECK from owner +/obj/item/organ/internal/liver/on_remove(mob/living/carbon/organ_owner, special) + . = ..() + UnregisterSignal(organ_owner, COMSIG_SPECIES_HANDLE_CHEMICAL) + +/** + * This proc can be overriden by liver subtypes so they can handle certain chemicals in special ways. + * Return null to continue running the normal on_mob_life() for that reagent. + * Return COMSIG_MOB_STOP_REAGENT_CHECK to not run the normal metabolism effects. + * + * NOTE: If you return COMSIG_MOB_STOP_REAGENT_CHECK, that reagent will not be removed like normal! You must handle it manually. + **/ +/obj/item/organ/internal/liver/proc/handle_chemical(mob/living/carbon/organ_owner, datum/reagent/chem, seconds_per_tick, times_fired) + SIGNAL_HANDLER + /obj/item/organ/internal/liver/examine(mob/user) . = ..() @@ -91,21 +121,19 @@ #define HAS_PAINFUL_TOXIN 2 /obj/item/organ/internal/liver/on_life(seconds_per_tick, times_fired) - var/mob/living/carbon/liver_owner = owner - . = ..() //perform general on_life() - - if(!istype(liver_owner)) - return - if(organ_flags & ORGAN_FAILING || HAS_TRAIT(liver_owner, TRAIT_NOMETABOLISM)) //If your liver is failing or you lack a metabolism then we use the liverless version of metabolize - liver_owner.reagents.metabolize(liver_owner, seconds_per_tick, times_fired, can_overdose=TRUE, liverless=TRUE) + . = ..() + //If your liver is failing, then we use the liverless version of metabolize + //We don't check for TRAIT_LIVERLESS_METABOLISM here because we do want a functional liver if somehow we have one inserted + if(organ_flags & ORGAN_FAILING) + owner.reagents.metabolize(owner, seconds_per_tick, times_fired, can_overdose = TRUE, liverless = TRUE) return - var/obj/belly = liver_owner.get_organ_slot(ORGAN_SLOT_STOMACH) - var/list/cached_reagents = liver_owner.reagents.reagent_list + var/obj/belly = owner.get_organ_slot(ORGAN_SLOT_STOMACH) + var/list/cached_reagents = owner.reagents.reagent_list var/liver_damage = 0 var/provide_pain_message = HAS_NO_TOXIN - if(filterToxins && !HAS_TRAIT(liver_owner, TRAIT_TOXINLOVER)) + if(filterToxins && !HAS_TRAIT(owner, TRAIT_TOXINLOVER)) for(var/datum/reagent/toxin/toxin in cached_reagents) if(status != toxin.affected_organtype) //this particular toxin does not affect this type of organ continue @@ -119,17 +147,17 @@ if(provide_pain_message != HAS_PAINFUL_TOXIN) provide_pain_message = toxin.silent_toxin ? HAS_SILENT_TOXIN : HAS_PAINFUL_TOXIN - liver_owner.reagents.metabolize(liver_owner, seconds_per_tick, times_fired, can_overdose=TRUE) + owner.reagents.metabolize(owner, seconds_per_tick, times_fired, can_overdose=TRUE) if(liver_damage) apply_organ_damage(min(liver_damage * seconds_per_tick , MAX_TOXIN_LIVER_DAMAGE * seconds_per_tick)) if(provide_pain_message && damage > 10 && SPT_PROB(damage/6, seconds_per_tick)) //the higher the damage the higher the probability - to_chat(liver_owner, span_warning("You feel a dull pain in your abdomen.")) + to_chat(owner, span_warning("You feel a dull pain in your abdomen.")) /obj/item/organ/internal/liver/handle_failing_organs(seconds_per_tick) - if(HAS_TRAIT(owner, TRAIT_STABLELIVER) || HAS_TRAIT(owner, TRAIT_NOMETABOLISM)) + if(HAS_TRAIT(owner, TRAIT_STABLELIVER) || HAS_TRAIT(owner, TRAIT_LIVERLESS_METABOLISM)) return return ..() @@ -201,12 +229,6 @@ /obj/item/organ/internal/liver/get_availability(datum/species/owner_species, mob/living/owner_mob) return owner_species.mutantliver -/obj/item/organ/internal/liver/plasmaman - name = "reagent processing crystal" - icon_state = "liver-p" - desc = "A large crystal that is somehow capable of metabolizing chemicals, these are found in plasmamen." - status = ORGAN_MINERAL - // alien livers can ignore up to 15u of toxins, but they take x3 liver damage /obj/item/organ/internal/liver/alien name = "alien liver" // doesnt matter for actual aliens because they dont take toxin damage diff --git a/code/modules/surgery/organs/internal/liver/liver_plasmamen.dm b/code/modules/surgery/organs/internal/liver/liver_plasmamen.dm new file mode 100644 index 000000000000..34dbec6ab612 --- /dev/null +++ b/code/modules/surgery/organs/internal/liver/liver_plasmamen.dm @@ -0,0 +1,25 @@ +/** + * Plasmaman liver + * Makes plasma and hot ice heal wounds, also makes gunpowder a hallucinogen. + **/ +/obj/item/organ/internal/liver/bone/plasmaman + name = "reagent processing crystal" + desc = "A large crystal that is somehow capable of metabolizing chemicals, these are found in plasmamen." + icon_state = "liver-p" + status = ORGAN_MINERAL + +/obj/item/organ/internal/liver/bone/plasmaman/handle_chemical(mob/living/carbon/organ_owner, datum/reagent/chem, seconds_per_tick, times_fired) + . = ..() + //parent returned COMSIG_MOB_STOP_REAGENT_CHECK or we are failing + if(. || (organ_flags & ORGAN_FAILING)) + return + // plasmamen use plasma to reform their bones or whatever + if(istype(chem, /datum/reagent/toxin/plasma) || istype(chem, /datum/reagent/toxin/hot_ice)) + for(var/datum/wound/iter_wound as anything in organ_owner.all_wounds) + iter_wound.on_xadone(4 * REM * seconds_per_tick) + return // Do normal metabolism + if(istype(chem, /datum/reagent/gunpowder)) + organ_owner.set_timed_status_effect(15 SECONDS * seconds_per_tick, /datum/status_effect/drugginess) + if(organ_owner.get_timed_status_effect_duration(/datum/status_effect/hallucination) / 10 < chem.volume) + organ_owner.adjust_hallucinations(2.5 SECONDS * seconds_per_tick) + return // Do normal metabolism diff --git a/code/modules/surgery/organs/internal/liver/liver_skeleton.dm b/code/modules/surgery/organs/internal/liver/liver_skeleton.dm new file mode 100644 index 000000000000..8e2de95ef506 --- /dev/null +++ b/code/modules/surgery/organs/internal/liver/liver_skeleton.dm @@ -0,0 +1,48 @@ +/** + * Bone liver + * Gives the owner liverless metabolism, makes them vulnerable to bone hurting juice and + * makes milk heal them through meme magic. + **/ +/obj/item/organ/internal/liver/bone + name = "mass of bones" + desc = "You have no idea what this strange ball of bones does." + organ_traits = list(TRAIT_LIVERLESS_METABOLISM) + +/obj/item/organ/internal/liver/bone/handle_chemical(mob/living/carbon/organ_owner, datum/reagent/chem, seconds_per_tick, times_fired) + . = ..() + //parent returned COMSIG_MOB_STOP_REAGENT_CHECK or we are failing + if(. || (organ_flags & ORGAN_FAILING)) + return + if(istype(chem, /datum/reagent/toxin/bonehurtingjuice)) + organ_owner.stamina?.adjust(7.5 * REM * seconds_per_tick, 0) + organ_owner.adjustBruteLoss(0.5 * REM * seconds_per_tick, 0) + if(SPT_PROB(10, seconds_per_tick)) + switch(rand(1, 3)) + if(1) + INVOKE_ASYNC(organ_owner, TYPE_PROC_REF(/atom/movable, say), pick("oof.", "ouch.", "my bones.", "oof ouch.", "oof ouch my bones."), forced = chem.type) + if(2) + organ_owner.manual_emote(pick("oofs silently.", "looks like [organ_owner.p_their()] bones hurt.", "grimaces, as though [organ_owner.p_their()] bones hurt.")) + if(3) + to_chat(organ_owner, span_warning("Your bones hurt!")) + if(chem.overdosed) + if(SPT_PROB(2, seconds_per_tick)) //big oof + var/selected_part = pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) //God help you if the same limb gets picked twice quickly... + var/obj/item/bodypart/bodypart = organ_owner.get_bodypart(selected_part) //We're so sorry skeletons, you're so misunderstood + if(bodypart) + playsound(organ_owner, SFX_DESECRATION, 50, vary = TRUE) //You just want to socialize + organ_owner.visible_message(span_warning("[organ_owner] rattles loudly and flails around!!"), span_danger("Your bones hurt so much that your missing muscles spasm!!")) + INVOKE_ASYNC(organ_owner, TYPE_PROC_REF(/atom/movable, say), "OOF!!", forced = chem.type) + bodypart.receive_damage(brute = 200) //But I don't think we should + else + to_chat(organ_owner, span_warning("Your missing [parse_zone(selected_part)] aches from wherever you left it.")) + INVOKE_ASYNC(organ_owner, TYPE_PROC_REF(/mob, emote), "sigh") + organ_owner.reagents.remove_reagent(chem.type, chem.metabolization_rate * seconds_per_tick) + return COMSIG_MOB_STOP_REAGENT_CHECK // Stop metabolism + if(chem.type == /datum/reagent/consumable/milk) + if(chem.volume > 50) + organ_owner.reagents.remove_reagent(chem.type, (chem.volume - 50)) + to_chat(organ_owner, span_warning("The excess milk is dripping off your bones!")) + organ_owner.heal_bodypart_damage(2.5 * REM * seconds_per_tick) + for(var/datum/wound/iter_wound as anything in organ_owner.all_wounds) + iter_wound.on_xadone(1 * REM * seconds_per_tick) + return // Do normal metabolism diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/internal/tongue/_tongue.dm similarity index 71% rename from code/modules/surgery/organs/tongue.dm rename to code/modules/surgery/organs/internal/tongue/_tongue.dm index f5359a46b6cc..ac42f9344913 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/internal/tongue/_tongue.dm @@ -34,6 +34,12 @@ /// Determines how "sensitive" this tongue is to tasting things, lower is more sensitive. /// See [/mob/living/proc/get_taste_sensitivity]. var/taste_sensitivity = 15 + /// Foodtypes this tongue likes + var/liked_foodtypes = JUNKFOOD | FRIED //human tastes are default + /// Foodtypes this tongue dislikes + var/disliked_foodtypes = GROSS | RAW | CLOTH | BUGS | GORE //human tastes are default + /// Foodtypes this tongue HATES + var/toxic_foodtypes = TOXIC //human tastes are default /// Whether this tongue modifies speech via signal var/modifies_speech = FALSE @@ -45,6 +51,16 @@ // this results in tongues with identical possible languages sharing a cached list instance languages_possible = string_list(get_possible_languages()) +/obj/item/organ/internal/tongue/examine(mob/user) + . = ..() + if(HAS_TRAIT(user, TRAIT_ENTRAILS_READER) || (user.mind && HAS_TRAIT(user.mind, TRAIT_ENTRAILS_READER)) || isobserver(user)) + if(liked_foodtypes) + . += span_info("This tongue has an affinity the taste of [english_list(bitfield_to_list(liked_foodtypes), FOOD_FLAGS_IC)].") + if(disliked_foodtypes) + . += span_info("This tongue has an aversion for taste of [english_list(bitfield_to_list(disliked_foodtypes), FOOD_FLAGS_IC)].") + if(toxic_foodtypes) + . += span_info("This tongue's physiology makes [english_list(bitfield_to_list(toxic_foodtypes), FOOD_FLAGS_IC)] toxic.") + /** * Used in setting up the "languages possible" list. * @@ -57,24 +73,7 @@ /obj/item/organ/internal/tongue/proc/get_possible_languages() RETURN_TYPE(/list) // This is the default list of languages most humans should be capable of speaking - return list( - /datum/language/common, - /datum/language/uncommon, - /datum/language/draconic, - /datum/language/codespeak, - /datum/language/monkey, - /datum/language/narsie, - /datum/language/beachbum, - /datum/language/aphasia, - /datum/language/piratespeak, - /datum/language/moffic, - /datum/language/sylvan, - /datum/language/shadowtongue, - /datum/language/terrum, - /datum/language/nekomimetic, - /datum/language/ratvar, //Monkestation Edit - /datum/language/goblin, //Monkestation Addition - ) + return subtypesof(/datum/language) /obj/item/organ/internal/tongue/proc/handle_speech(datum/source, list/speech_args) SIGNAL_HANDLER @@ -85,14 +84,56 @@ /obj/item/organ/internal/tongue/proc/modify_speech(datum/source, list/speech_args) return speech_args[SPEECH_MESSAGE] +/** + * Gets the food reaction a tongue would have from the food item, + * assuming that no check_liked callback was used in the edible component. + * + * Can be overriden by subtypes for more complex behavior. + * Does not get called if the owner has ageusia. + **/ +/obj/item/organ/internal/tongue/proc/get_food_taste_reaction(obj/item/food, foodtypes = NONE) + var/food_taste_reaction + if(foodtypes & toxic_foodtypes) + food_taste_reaction = FOOD_TOXIC + else if(foodtypes & disliked_foodtypes) + food_taste_reaction = FOOD_DISLIKED + else if(foodtypes & liked_foodtypes) + food_taste_reaction = FOOD_LIKED + return food_taste_reaction + +/obj/item/organ/internal/tongue/proc/get_laugh_sound() + if(owner.gender == MALE) + return pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg') + else + return 'sound/voice/human/womanlaugh.ogg' + +/obj/item/organ/internal/tongue/proc/get_scream_sound() + if(owner.gender == MALE) + if(prob(1)) + return 'sound/voice/human/wilhelm_scream.ogg' + return pick( + 'sound/voice/human/malescream_1.ogg', + 'sound/voice/human/malescream_2.ogg', + 'sound/voice/human/malescream_3.ogg', + 'sound/voice/human/malescream_4.ogg', + 'sound/voice/human/malescream_5.ogg', + 'sound/voice/human/malescream_6.ogg', + ) + + return pick( + 'sound/voice/human/femalescream_1.ogg', + 'sound/voice/human/femalescream_2.ogg', + 'sound/voice/human/femalescream_3.ogg', + 'sound/voice/human/femalescream_4.ogg', + 'sound/voice/human/femalescream_5.ogg', + ) + /obj/item/organ/internal/tongue/Insert(mob/living/carbon/tongue_owner, special = FALSE, drop_if_replaced = TRUE) . = ..() if(!.) return - ADD_TRAIT(tongue_owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE) - if (modifies_speech) + if(modifies_speech) RegisterSignal(tongue_owner, COMSIG_MOB_SAY, PROC_REF(handle_speech)) - if(!(organ_flags & ORGAN_FAILING)) ADD_TRAIT(tongue_owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE) /* This could be slightly simpler, by making the removal of the @@ -101,18 +142,35 @@ * ageusia from having a non-tasting tongue. */ REMOVE_TRAIT(tongue_owner, TRAIT_AGEUSIA, NO_TONGUE_TRAIT) - if(!sense_of_taste) + if(!sense_of_taste || (organ_flags & ORGAN_FAILING)) ADD_TRAIT(tongue_owner, TRAIT_AGEUSIA, ORGAN_TRAIT) /obj/item/organ/internal/tongue/Remove(mob/living/carbon/tongue_owner, special = FALSE) . = ..() - REMOVE_TRAIT(tongue_owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE) temp_say_mod = "" UnregisterSignal(tongue_owner, COMSIG_MOB_SAY) + REMOVE_TRAIT(tongue_owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE) REMOVE_TRAIT(tongue_owner, TRAIT_AGEUSIA, ORGAN_TRAIT) // Carbons by default start with NO_TONGUE_TRAIT caused TRAIT_AGEUSIA ADD_TRAIT(tongue_owner, TRAIT_AGEUSIA, NO_TONGUE_TRAIT) + +/obj/item/organ/internal/tongue/apply_organ_damage(damage_amount, maximum, required_organtype) + . = ..() + if(!owner) + return + //tongues can't taste food when they are failing + if(sense_of_taste) + //tongues can't taste food when they are failing + if(organ_flags & ORGAN_FAILING) + ADD_TRAIT(owner, TRAIT_AGEUSIA, ORGAN_TRAIT) + else + REMOVE_TRAIT(owner, TRAIT_AGEUSIA, ORGAN_TRAIT) + if(organ_flags & ORGAN_FAILING) + REMOVE_TRAIT(owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE) + else + ADD_TRAIT(owner, TRAIT_SPEAKS_CLEARLY, SPEAKING_FROM_TONGUE) + /obj/item/organ/internal/tongue/could_speak_language(datum/language/language_path) return (language_path in languages_possible) @@ -127,12 +185,35 @@ taste_sensitivity = 10 // combined nose + tongue, extra sensitive modifies_speech = TRUE languages_native = list(/datum/language/draconic, /datum/language/ashtongue) + liked_foodtypes = GORE | MEAT | SEAFOOD | NUTS | BUGS + disliked_foodtypes = GRAIN | DAIRY | CLOTH | GROSS //MONKESTATION EDIT START /// How long is our hissssssss? var/draw_length = 3 +/obj/item/organ/internal/tongue/lizard/get_scream_sound() + if(owner.gender == MALE) + return pick( + 'sound/voice/lizard/lizard_scream_1.ogg', + 'sound/voice/lizard/lizard_scream_2.ogg', + 'sound/voice/lizard/lizard_scream_3.ogg', + 'monkestation/sound/voice/screams/lizard/lizard_scream_4.ogg', + ) + + return pick( + 'sound/voice/lizard/lizard_scream_1.ogg', + 'sound/voice/lizard/lizard_scream_2.ogg', + 'sound/voice/lizard/lizard_scream_3.ogg', + 'monkestation/sound/voice/screams/lizard/lizard_scream_5.ogg', + ) + +/obj/item/organ/internal/tongue/lizard/get_laugh_sound() + if(prob(1)) + return 'monkestation/sound/voice/weh.ogg' + return 'monkestation/sound/voice/laugh/lizard/lizard_laugh.ogg' + /obj/item/organ/internal/tongue/lizard/Initialize(mapload) . = ..() draw_length = rand(2, 6) @@ -247,6 +328,13 @@ modifies_speech = TRUE var/mothership + +/obj/item/organ/internal/tongue/abductor/get_scream_sound() + return 'sound/weather/ashstorm/inside/weak_end.ogg' + +/obj/item/organ/internal/tongue/abductor/get_laugh_sound() + return 'sound/weather/ashstorm/inside/weak_end.ogg' + /obj/item/organ/internal/tongue/abductor/attack_self(mob/living/carbon/human/tongue_holder) if(!istype(tongue_holder)) return @@ -298,6 +386,8 @@ say_mod = "moans" modifies_speech = TRUE taste_sensitivity = 32 + liked_foodtypes = GROSS | MEAT | RAW | GORE + disliked_foodtypes = NONE // List of english words that translate to zombie phrases GLOBAL_LIST_INIT(english_to_zombie, list()) @@ -390,6 +480,8 @@ GLOBAL_LIST_INIT(english_to_zombie, list()) attack_verb_simple = list("bite", "chatter", "chomp", "enamel", "bone") sense_of_taste = FALSE modifies_speech = TRUE + liked_foodtypes = GROSS | MEAT | RAW | GORE | DAIRY //skeletons eat spooky shit... and dairy, of course + disliked_foodtypes = NONE var/chattering = FALSE var/phomeme_type = "sans" var/list/phomeme_types = list("sans", "papyrus") @@ -398,6 +490,13 @@ GLOBAL_LIST_INIT(english_to_zombie, list()) . = ..() phomeme_type = pick(phomeme_types) +/obj/item/organ/internal/tongue/bone/get_laugh_sound() + return 'monkestation/sound/voice/laugh/skeleton/skeleton_laugh.ogg' + +/obj/item/organ/internal/tongue/bone/get_scream_sound() + return 'monkestation/sound/voice/screams/skeleton/scream_skeleton.ogg' + + // Bone tongues can speak all default + calcic /obj/item/organ/internal/tongue/bone/get_possible_languages() return ..() + /datum/language/calcic @@ -416,6 +515,15 @@ GLOBAL_LIST_INIT(english_to_zombie, list()) desc = "Like animated skeletons, Plasmamen vibrate their teeth in order to produce speech." icon_state = "tongueplasma" modifies_speech = FALSE + liked_foodtypes = VEGETABLES + disliked_foodtypes = FRUIT | CLOTH + +/obj/item/organ/internal/tongue/bone/plasmaman/get_scream_sound() + return pick( + 'sound/voice/plasmaman/plasmeme_scream_1.ogg', + 'sound/voice/plasmaman/plasmeme_scream_2.ogg', + 'sound/voice/plasmaman/plasmeme_scream_3.ogg', + ) /obj/item/organ/internal/tongue/robot name = "robotic voicebox" @@ -429,6 +537,16 @@ GLOBAL_LIST_INIT(english_to_zombie, list()) modifies_speech = TRUE taste_sensitivity = 25 // not as good as an organic tongue +/obj/item/organ/internal/tongue/robot/get_scream_sound() + return 'monkestation/sound/voice/screams/silicon/scream_silicon.ogg' + +/obj/item/organ/internal/tongue/robot/get_laugh_sound() + return pick( + 'monkestation/sound/voice/laugh/silicon/laugh_siliconE1M0.ogg', + 'monkestation/sound/voice/laugh/silicon/laugh_siliconE1M1.ogg', + 'monkestation/sound/voice/laugh/silicon/laugh_siliconM2.ogg', + ) + /obj/item/organ/internal/tongue/robot/can_speak_language(language) return TRUE // THE MAGIC OF ELECTRONICS @@ -457,9 +575,23 @@ GLOBAL_LIST_INIT(english_to_zombie, list()) icon_state = "electrotongue" say_mod = "crackles" taste_sensitivity = 10 // ethereal tongues function (very loosely) like a gas spectrometer: vaporising a small amount of the food and allowing it to pass to the nose, resulting in more sensitive taste + liked_foodtypes = NONE //no food is particularly liked by ethereals + disliked_foodtypes = GROSS + toxic_foodtypes = NONE //no food is particularly toxic to etherealsz attack_verb_continuous = list("shocks", "jolts", "zaps") attack_verb_simple = list("shock", "jolt", "zap") +/obj/item/organ/internal/tongue/ethereal/get_scream_sound() + return pick( + 'sound/voice/ethereal/ethereal_scream_1.ogg', + 'sound/voice/ethereal/ethereal_scream_2.ogg', + 'sound/voice/ethereal/ethereal_scream_3.ogg', + ) + +/obj/item/organ/internal/tongue/ethereal/get_laugh_sound() + return 'monkestation/sound/voice/laugh/ethereal/ethereal_laugh_1.ogg' + + // Ethereal tongues can speak all default + voltaic /obj/item/organ/internal/tongue/ethereal/get_possible_languages() return ..() + /datum/language/voltaic @@ -468,6 +600,8 @@ GLOBAL_LIST_INIT(english_to_zombie, list()) name = "felinid tongue" desc = "A fleshy muscle mostly used for meowing." say_mod = "meows" + liked_foodtypes = SEAFOOD | ORANGES | BUGS | GORE + disliked_foodtypes = GROSS | CLOTH | RAW /obj/item/organ/internal/tongue/bananium name = "bananium tongue" @@ -482,16 +616,54 @@ GLOBAL_LIST_INIT(english_to_zombie, list()) name = "jelly tongue" desc = "Ah... That's not the sound I expected it to make. Sounds like a Space Autumn Bird." say_mod = "chirps" + liked_foodtypes = MEAT | BUGS + disliked_foodtypes = GROSS + toxic_foodtypes = NONE + +/obj/item/organ/internal/tongue/jelly/get_food_taste_reaction(obj/item/food, foodtypes = NONE) + // a silver slime created this? what a delicacy! + if(HAS_TRAIT(food, TRAIT_FOOD_SILVER)) + return FOOD_LIKED + return ..() /obj/item/organ/internal/tongue/monkey name = "primitive tongue" desc = "For aggressively chimpering. And consuming bananas." say_mod = "chimpers" + liked_foodtypes = MEAT | FRUIT | BUGS + disliked_foodtypes = CLOTH + +/obj/item/organ/internal/tongue/monkey/get_scream_sound() + return pick( + 'sound/creatures/monkey/monkey_screech_1.ogg', + 'sound/creatures/monkey/monkey_screech_2.ogg', + 'sound/creatures/monkey/monkey_screech_3.ogg', + 'sound/creatures/monkey/monkey_screech_4.ogg', + 'sound/creatures/monkey/monkey_screech_5.ogg', + 'sound/creatures/monkey/monkey_screech_6.ogg', + 'sound/creatures/monkey/monkey_screech_7.ogg', + ) + +/obj/item/organ/internal/tongue/monkey/get_laugh_sound() + return 'monkestation/sound/voice/laugh/simian/monkey_laugh_1.ogg' /obj/item/organ/internal/tongue/moth name = "moth tongue" desc = "Moths don't have tongues. Someone get god on the phone, tell them I'm not happy." say_mod = "flutters" + liked_foodtypes = VEGETABLES | DAIRY | CLOTH + disliked_foodtypes = FRUIT | GROSS | BUGS | GORE + toxic_foodtypes = MEAT | RAW | SEAFOOD + +/obj/item/organ/internal/tongue/moth/get_scream_sound() + return 'sound/voice/moth/scream_moth.ogg' + +/obj/item/organ/internal/tongue/moth/get_laugh_sound() + return pick( + 'monkestation/sound/voice/laugh/moth/mothchitter.ogg', + 'monkestation/sound/voice/laugh/moth/mothlaugh.ogg', + 'monkestation/sound/voice/laugh/moth/mothsqueak.ogg', + ) /obj/item/organ/internal/tongue/zombie name = "rotting tongue" @@ -501,7 +673,31 @@ GLOBAL_LIST_INIT(english_to_zombie, list()) /obj/item/organ/internal/tongue/mush name = "mush-tongue-room" desc = "You poof with this. Got it?" - say_mod = "poofs" - icon = 'icons/obj/hydroponics/seeds.dmi' icon_state = "mycelium-angel" + say_mod = "poofs" + +/obj/item/organ/internal/tongue/pod + name = "pod tongue" + desc = "A plant-like organ used for speaking and eating." + say_mod = "whistles" + liked_foodtypes = VEGETABLES | FRUIT | GRAIN + disliked_foodtypes = GORE | MEAT | DAIRY | SEAFOOD | BUGS + +/obj/item/organ/internal/tongue/floran + name = "floran tongue" + desc = "A plant-like organ used for speaking and eating." + say_mod = "whistles" + liked_foodtypes = GORE | MEAT | DAIRY | SEAFOOD | BUGS + disliked_foodtypes = VEGETABLES + +/obj/item/organ/internal/tongue/floran/get_scream_sound() + return pick( + 'sound/voice/lizard/lizard_scream_1.ogg', + 'sound/voice/lizard/lizard_scream_2.ogg', + 'sound/voice/lizard/lizard_scream_3.ogg', + 'monkestation/sound/voice/screams/lizard/lizard_scream_5.ogg', + ) + +/obj/item/organ/internal/tongue/floran/get_laugh_sound() + return 'monkestation/sound/voice/laugh/lizard/lizard_laugh.ogg' diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index 31f69eeacacf..ebe938e69eaf 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -85,26 +85,37 @@ var/tritium_irradiation_probability_min = 10 var/tritium_irradiation_probability_max = 60 + /// Message displayed when breathing cold air var/cold_message = "your face freezing and an icicle forming" - var/cold_level_1_threshold = 260 - var/cold_level_2_threshold = 200 - var/cold_level_3_threshold = 120 - var/cold_level_1_damage = COLD_GAS_DAMAGE_LEVEL_1 //Keep in mind with gas damage levels, you can set these to be negative, if you want someone to heal, instead. - var/cold_level_2_damage = COLD_GAS_DAMAGE_LEVEL_2 - var/cold_level_3_damage = COLD_GAS_DAMAGE_LEVEL_3 + /// At this threshold, a cold breath displays a warning message + var/cold_level_warning_threshold = CELCIUS_TO_KELVIN(-13.15 CELCIUS) + /// At this threshold, a cold breath deals a minor amount of damage + var/cold_level_hazard_threshold = CELCIUS_TO_KELVIN(-73.15 CELCIUS) + /// At this threshold, a cold breath deals a moderate amount of damage + var/cold_level_danger_threshold = CELCIUS_TO_KELVIN(-153.15 CELCIUS) + /// Amount of damage dealt by a cold breath. Halved if at the hazard threshold + var/cold_level_damage = 3 + /// Type of damage dealt by a cold breath var/cold_damage_type = BURN + /// Message displayed when breathing hot air var/hot_message = "your face burning and a searing heat" - var/heat_level_1_threshold = 360 - var/heat_level_2_threshold = 400 - var/heat_level_3_threshold = 1000 - var/heat_level_1_damage = HEAT_GAS_DAMAGE_LEVEL_1 - var/heat_level_2_damage = HEAT_GAS_DAMAGE_LEVEL_2 - var/heat_level_3_damage = HEAT_GAS_DAMAGE_LEVEL_3 + /// At this threshold, a hot breath displays a warning message + var/heat_level_warning_threshold = CELCIUS_TO_KELVIN(86.85 CELCIUS) + /// At this threshold, a hot breath deals a minor amount of damage + var/heat_level_hazard_threshold = CELCIUS_TO_KELVIN(126.85 CELCIUS) + /// At this threshold, a hot breath deals a moderate amount of damage + var/heat_level_danger_threshold = CELCIUS_TO_KELVIN(726.85 CELCIUS) + /// Amount of damage dealt by a hot breath. Halved if at the hazard threshold + var/heat_level_damage = 8 + /// Type of damage dealt by a hot breath var/heat_damage_type = BURN var/crit_stabilizing_reagent = /datum/reagent/medicine/epinephrine + ///our last lung pop adventure + var/lung_pop_tick = 0 + // assign the respiration_type /obj/item/organ/internal/lungs/Initialize(mapload) . = ..() @@ -164,6 +175,8 @@ receiver.clear_alert(ALERT_NOT_ENOUGH_NITRO) receiver.clear_alert(ALERT_NOT_ENOUGH_PLASMA) receiver.clear_alert(ALERT_NOT_ENOUGH_N2O) + receiver.remove_status_effect(/datum/status_effect/lungless) + RegisterSignal(receiver, COMSIG_CARBON_ATTEMPT_BREATHE, PROC_REF(block_breath)) /obj/item/organ/internal/lungs/Remove(mob/living/carbon/organ_owner, special) . = ..() @@ -177,6 +190,13 @@ call(src, on_loss)(organ_owner, dummy, last_partial_pressures[gas_id]) dummy.garbage_collect() + UnregisterSignal(organ_owner, COMSIG_CARBON_ATTEMPT_BREATHE) + if(!special) + organ_owner.apply_status_effect(/datum/status_effect/lungless) + +/obj/item/organ/internal/lungs/proc/block_breath(...) + SIGNAL_HANDLER + return (failed && !HAS_TRAIT(owner, TRAIT_ASSISTED_BREATHING)) ? BREATHE_SKIP_BREATH : NONE /** * Tells the lungs to pay attention to the passed in gas type @@ -250,6 +270,7 @@ // Note this can be redundant, because of the vacuum check. It is fail safe tho, so it's ok if(old_o2_pp < safe_oxygen_min) breather.failed_last_breath = FALSE + lung_pop_tick = 0 breather.clear_alert(ALERT_NOT_ENOUGH_OXYGEN) breathe_gas_volume(breath, /datum/gas/oxygen, /datum/gas/carbon_dioxide) @@ -531,14 +552,23 @@ if(!HAS_TRAIT(breather, TRAIT_SLEEPIMMUNE)) breather.Unconscious(6 SECONDS) // Enough to make the mob sleep. - if(n2o_pp > n2o_sleep_min) - breather.Sleeping(min(breather.AmountSleeping() + 100, 200)) + if(n2o_pp > n2o_sleep_min) + breather.Sleeping(min(breather.AmountSleeping() + 100, 200)) + // And apply anesthesia if it worked + if(HAS_TRAIT(breather, TRAIT_KNOCKEDOUT)) + breather.apply_status_effect(/datum/status_effect/grouped/anesthetic, /datum/gas/nitrous_oxide) /// N2O side-effects. "Too much N2O!" /obj/item/organ/internal/lungs/proc/safe_n2o(mob/living/carbon/breather, datum/gas_mixture/breath, old_n2o_pp) n2o_euphoria = EUPHORIA_INACTIVE breather.clear_alert(ALERT_TOO_MUCH_N2O) +/obj/item/organ/internal/lungs/check_damage_thresholds(mob/organ_owner) + // Don't give random feedback messages if you're suffocating + if(owner?.failed_last_breath) + return null + return ..() + // Breath in nitrium. It's helpful, but has nasty side effects /obj/item/organ/internal/lungs/proc/too_much_nitrium(mob/living/carbon/breather, datum/gas_mixture/breath, nitrium_pp, old_nitrium_pp) breathe_gas_volume(breath, /datum/gas/nitrium) @@ -590,25 +620,26 @@ * * breath: A gas mixture to test, or null. * * breather: A carbon mob that is using the lungs to breathe. */ -/obj/item/organ/internal/lungs/proc/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/breather) +/obj/item/organ/internal/lungs/proc/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/breather, skip_breath) if(breather.status_flags & GODMODE) breather.failed_last_breath = FALSE - breather.clear_alert(ALERT_NOT_ENOUGH_OXYGEN) return FALSE if(HAS_TRAIT(breather, TRAIT_NOBREATH)) return FALSE - // If the breath is falsy or "null", we can use the backup empty_breath. - if(!breath) + // If the breath is null, it's actually a failed breath + var/no_breath = isnull(breath) || skip_breath + if(no_breath) var/static/datum/gas_mixture/immutable/empty_breath = new(BREATH_VOLUME) breath = empty_breath // Indicates if there are moles of gas in the breath. - var/has_moles = breath.total_moles() != 0 - + var/num_moles = breath.total_moles() + var/not_low_pressure = num_moles > 0.01 || HAS_TRAIT(breather, TRAIT_RESISTLOWPRESSURE) + var/not_high_pressure = num_moles < 0.1 || HAS_TRAIT(breather, TRAIT_RESISTHIGHPRESSURE) // Check for moles of gas and handle partial pressures / special conditions. - if(has_moles) + if(num_moles > 0 && not_low_pressure && not_high_pressure) // Breath has more than 0 moles of gas. // Route gases through mask filter if breather is wearing one. if(istype(breather.wear_mask) && (breather.wear_mask.clothing_flags & GAS_FILTERING) && breather.wear_mask.has_filter) @@ -617,10 +648,34 @@ else if(HAS_TRAIT(src, TRAIT_SPACEBREATHING)) // The lungs can breathe anyways. What are you? Some bottom-feeding, scum-sucking algae eater? breather.failed_last_breath = FALSE + lung_pop_tick = 0 // Vacuum-adapted lungs regenerate oxyloss even when breathing nothing. - if(breather.health >= breather.crit_threshold && breather.oxyloss) - breather.adjustOxyLoss(-5) - else + if(HAS_TRAIT(breather, TRAIT_NOBLOOD)) + breather.adjustOxyLoss(-4) + else + // Less blood so breaths give you less oxygen + breather.adjustOxyLoss(-1 * min(5, BLOOD_VOLUME_NORMAL / breather.blood_volume)) + + // We're in a low / high pressure environment, can't breathe, but trying to, so this hurts the lungs + // Unless it's cybernetic then it just doesn't care. Handwave magic whatever + else if(!skip_breath && (owner && !HAS_TRAIT(owner, TRAIT_ASSISTED_BREATHING))) + if(lung_pop_tick > 10) + lung_pop_tick = 0 + if(!failed) + // Lungs are poppin + if(damage >= 40 && damage <= 50 && breather.can_feel_pain()) + to_chat(breather, span_userdanger("You feel a stabbing pain in your chest!")) + else if(num_moles < 0.02) + to_chat(breather, span_boldwarning("You feel air rapidly exiting your lungs!")) + else if(num_moles > 0.1) + to_chat(breather, span_boldwarning("You feel air force itself into your lungs!")) + + breather.cause_pain(BODY_ZONE_CHEST, 10, BRUTE) + apply_organ_damage(5) + breather.failed_last_breath = TRUE + lung_pop_tick++ + // Robot, don't care lol + else if((owner && !HAS_TRAIT(owner, TRAIT_ASSISTED_BREATHING))) // Can't breathe! breather.failed_last_breath = TRUE @@ -694,7 +749,7 @@ else if (old_euphoria && !new_euphoria) breather.clear_mood_event("chemical_euphoria") - if(has_moles) + if(num_moles > 0) handle_breath_temperature(breath, breather) // Merge breath_out into breath. They're kept seprerate before now to ensure stupid like, order of operations shit doesn't happen // But that time has passed @@ -731,14 +786,13 @@ // Give them a chance to notice something is wrong. if(prob(20)) suffocator.emote("gasp") + var/oxyloss = suffocator.getOxyLoss() + if(oxyloss >= 50) + // Suffocating = brain damage + suffocator.adjustOrganLoss(ORGAN_SLOT_BRAIN, (oxyloss / MAX_OXYLOSS(suffocator.maxHealth)) * 4, required_organtype = ORGAN_ORGANIC) // If mob is at critical health, check if they can be damaged further. - if(suffocator.health < suffocator.crit_threshold) - // Mob is immune to damage at critical health. - if(HAS_TRAIT(suffocator, TRAIT_NOCRITDAMAGE)) - return - // Reagents like Epinephrine stop suffocation at critical health. - if(suffocator.reagents.has_reagent(crit_stabilizing_reagent, needs_metabolizing = TRUE)) - return + if(suffocator.stat >= SOFT_CRIT && HAS_TRAIT(suffocator, TRAIT_NOCRITDAMAGE)) + return // Low pressure. if(breath_pp) var/ratio = safe_breath_min / breath_pp @@ -754,47 +808,47 @@ /obj/item/organ/internal/lungs/proc/handle_breath_temperature(datum/gas_mixture/breath, mob/living/carbon/human/breather) // called by human/life, handles temperatures var/breath_temperature = breath.temperature - if(!HAS_TRAIT(breather, TRAIT_RESISTCOLD)) // COLD DAMAGE - var/cold_modifier = breather.dna.species.coldmod + if(breath_temperature < cold_level_warning_threshold && !HAS_TRAIT(breather, TRAIT_RESISTCOLD)) // COLD DAMAGE + var/cold_modifier = breather.physiology.cold_mod var/breath_effect_prob = 0 - if(breath_temperature < cold_level_3_threshold) - breather.apply_damage(cold_level_3_damage * cold_modifier, cold_damage_type, spread_damage = TRUE) + var/cold_message_prob = 0 + if(breath_temperature < cold_level_danger_threshold) + breather.apply_damage(cold_level_damage * cold_modifier, cold_damage_type, spread_damage = TRUE) breath_effect_prob = 100 - if(breath_temperature > cold_level_3_threshold && breath_temperature < cold_level_2_threshold) - breather.apply_damage(cold_level_2_damage * cold_modifier, cold_damage_type, spread_damage = TRUE) + cold_message_prob = 100 + else if(breath_temperature < cold_level_hazard_threshold) + breather.apply_damage(0.5 * cold_level_damage * cold_modifier, cold_damage_type, spread_damage = TRUE) + breath_effect_prob = 75 + cold_message_prob = 50 + else breath_effect_prob = 50 - if(breath_temperature > cold_level_2_threshold && breath_temperature < cold_level_1_threshold) - breather.apply_damage(cold_level_1_damage * cold_modifier, cold_damage_type, spread_damage = TRUE) - breath_effect_prob = 25 - if(breath_temperature < cold_level_1_threshold) - if(prob(sqrt(breath_effect_prob) * 4)) - to_chat(breather, span_warning("You feel [cold_message] in your [name]!")) - if(prob(50)) - breather.emote("shiver") - if(prob(breath_effect_prob)) - // Breathing into your mask, no particle. We can add fogged up glasses later - if(breather.is_mouth_covered()) - return - // Even though breathing via internals TECHNICALLY exhales into the environment, we'll still block it - if(breather.internal || breather.external) - return - emit_breath_particle(breather, /particles/fog/breath) - - if(!HAS_TRAIT(breather, TRAIT_RESISTHEAT)) // HEAT DAMAGE + cold_message_prob = 20 + if(prob(cold_message_prob)) + to_chat(breather, span_warning("You feel [cold_message] in your [name]!")) + if(prob(50)) + breather.emote("shiver") + if(prob(breath_effect_prob)) + // Breathing into your mask, no particle. We can add fogged up glasses later + if(breather.is_mouth_covered()) + return + // Even though breathing via internals TECHNICALLY exhales into the environment, we'll still block it + if(breather.internal || breather.external) + return + emit_breath_particle(breather, /particles/fog/breath) + + if(breath_temperature > heat_level_warning_threshold && !HAS_TRAIT(breather, TRAIT_RESISTHEAT)) // HEAT DAMAGE var/heat_modifier = breather.dna.species.heatmod var/heat_message_prob = 0 - if(breath_temperature > heat_level_1_threshold && breath_temperature < heat_level_2_threshold) - breather.apply_damage(heat_level_1_damage * heat_modifier, heat_damage_type, spread_damage = TRUE) + if(breath_temperature > heat_level_danger_threshold) + breather.apply_damage(heat_level_damage * heat_modifier, heat_damage_type, spread_damage = TRUE) heat_message_prob = 100 - if(breath_temperature > heat_level_2_threshold && breath_temperature < heat_level_3_threshold) - breather.apply_damage(heat_level_2_damage * heat_modifier, heat_damage_type, spread_damage = TRUE) + else if(breath_temperature > heat_level_hazard_threshold) + breather.apply_damage(0.5 * heat_level_damage * heat_modifier, heat_damage_type, spread_damage = TRUE) heat_message_prob = 50 - if(breath_temperature > heat_level_3_threshold) - breather.apply_damage(heat_level_3_damage * heat_modifier, heat_damage_type, spread_damage = TRUE) - heat_message_prob = 25 - if(breath_temperature > heat_level_1_threshold) - if(prob(sqrt(heat_message_prob) * 4)) - to_chat(breather, span_warning("You feel [hot_message] in your [name]!")) + else + heat_message_prob = 20 + if(prob(heat_message_prob)) + to_chat(breather, span_warning("You feel [hot_message] in your [name]!")) // The air you breathe out should match your body temperature breath.temperature = breather.bodytemperature @@ -835,19 +889,48 @@ QDEL_IN(holder, breath_particle.lifespan) -/obj/item/organ/internal/lungs/on_life(seconds_per_tick, times_fired) +/obj/item/organ/internal/lungs/apply_organ_damage(damage_amount, maximum = maxHealth, required_organtype) . = ..() - if(failed && !(organ_flags & ORGAN_FAILING)) - failed = FALSE + if(!.) return - if(damage >= low_threshold) - var/do_i_cough = SPT_PROB((damage < high_threshold) ? 2.5 : 5, seconds_per_tick) // between : past high - if(do_i_cough) - owner.emote("cough") - if((organ_flags & ORGAN_FAILING) && owner.stat == CONSCIOUS && SPT_PROB(1, seconds_per_tick)) // monkestation edit: antispam - owner.visible_message(span_danger("[owner] grabs [owner.p_their()] throat, struggling for breath!"), span_userdanger("You suddenly feel like you can't breathe!")) + + if(organ_flags & ORGAN_FAILING) + if(!owner?.incapacitated()) + owner.visible_message( + span_danger("[owner] grabs [owner.p_their()] throat, struggling for breath!"), + span_userdanger("You suddenly feel like you can't breathe!"), + ) failed = TRUE + else if(failed) + failed = FALSE + +/obj/item/organ/internal/lungs/on_life(seconds_per_tick, times_fired) + . = ..() + if(damage < low_threshold) + return + + var/cough_prob = 2.5 + if(damage >= high_threshold) + cough_prob = 5 + + if(!SPT_PROB(cough_prob, seconds_per_tick)) // between : past high + return + + if((damage >= high_threshold) && prob(33)) + owner.visible_message(span_danger("[owner] coughs up blood!"), span_userdanger("You cough up blood!")) + var/obj/item/covering = owner.is_mouth_covered() + if(covering) + covering.add_mob_blood(owner) + else if(isturf(owner.loc)) + owner.add_splatter_floor() + owner.apply_damage(3, BRUTE, BODY_ZONE_CHEST, wound_bonus = CANT_WOUND) + owner.bleed(round(damage / 8)) + playsound(owner, 'sound/effects/splat.ogg', 33, TRUE) + else + owner.emote(pick("weeze", "cough")) + owner.losebreath = min(owner.losebreath + round(damage / 100, 0.1), 4) + /obj/item/organ/internal/lungs/get_availability(datum/species/owner_species, mob/living/owner_mob) return owner_species.mutantlungs @@ -867,9 +950,9 @@ safe_plasma_max = 0 //We breathe this to gain POWER. -/obj/item/organ/internal/lungs/slime/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/breather_slime) +/obj/item/organ/internal/lungs/slime/check_breath(datum/gas_mixture/breath, mob/living/carbon/human/breather_slime, skip_breath) . = ..() - if (breath?.gases[/datum/gas/plasma]) + if (breath?.gases[/datum/gas/plasma] && !skip_breath) var/plasma_pp = breath.get_breath_partial_pressure(breath.gases[/datum/gas/plasma][MOLES]) breather_slime.blood_volume += (0.2 * plasma_pp) // 10/s when breathing literally nothing but plasma, which will suffocate you. @@ -901,9 +984,9 @@ safe_oxygen_min = 13 emp_vulnerability = 20 - cold_level_1_threshold = 200 - cold_level_2_threshold = 140 - cold_level_3_threshold = 100 + cold_level_warning_threshold = CELCIUS_TO_KELVIN(-73.15 CELCIUS) + cold_level_hazard_threshold = CELCIUS_TO_KELVIN(-133.15 CELCIUS) + cold_level_danger_threshold = CELCIUS_TO_KELVIN(-173.15 CELCIUS) /obj/item/organ/internal/lungs/cybernetic/emp_act(severity) . = ..() @@ -980,9 +1063,9 @@ name = "aeration reticulum" desc = "These exotic lungs seem crunchier than most." icon_state = "lungs_ethereal" - heat_level_1_threshold = FIRE_MINIMUM_TEMPERATURE_TO_SPREAD // 150C or 433k, in line with ethereal max safe body temperature - heat_level_2_threshold = 473 - heat_level_3_threshold = 1073 + heat_level_warning_threshold = FIRE_MINIMUM_TEMPERATURE_TO_SPREAD // 150C or 433k, in line with ethereal max safe body temperature + heat_level_hazard_threshold = CELCIUS_TO_KELVIN(200 CELCIUS) + heat_level_danger_threshold = CELCIUS_TO_KELVIN(800 CELCIUS) /obj/item/organ/internal/lungs/ethereal/Initialize(mapload) . = ..() diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index a51ad9dd1fe4..69e102a1ac13 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -32,7 +32,7 @@ if((organ_flags & ORGAN_VITAL) && !special && !(organ_owner.status_flags & GODMODE)) if(organ_owner.stat != DEAD) organ_owner.investigate_log("has been killed by losing a vital organ ([src]).", INVESTIGATE_DEATHS) - organ_owner.death() + organ_owner.death(null, "losing your [name]") START_PROCESSING(SSobj, src) @@ -43,6 +43,8 @@ /obj/item/organ/internal/on_death(seconds_per_tick, times_fired) //runs decay when outside of a person if(organ_flags & (ORGAN_SYNTHETIC | ORGAN_FROZEN)) return + if(HAS_TRAIT(src, TRAIT_NO_ORGAN_DECAY) || (owner && HAS_TRAIT(owner, TRAIT_NO_ORGAN_DECAY))) + return apply_organ_damage(decay_factor * maxHealth * seconds_per_tick) /// Called once every life tick on every organ in a carbon's body diff --git a/code/modules/surgery/organs/stomach/_stomach.dm b/code/modules/surgery/organs/stomach/_stomach.dm index 8e1d4a661fb2..f1e2db0e52b7 100644 --- a/code/modules/surgery/organs/stomach/_stomach.dm +++ b/code/modules/surgery/organs/stomach/_stomach.dm @@ -32,6 +32,11 @@ var/operated = FALSE //whether the stomach's been repaired with surgery and can be fixed again or not + /// Typecache of food we can eat that will never give us disease. + var/list/disease_free_foods + ///our hunger modifier + var/hunger_modifier = 1 + /obj/item/organ/internal/stomach/Initialize(mapload) . = ..() //None edible organs do not get a reagent holder by default @@ -139,23 +144,22 @@ // nutrition decrease and satiety if (human.nutrition > 0 && human.stat != DEAD) // THEY HUNGER - var/hunger_rate = HUNGER_FACTOR - if(human.mob_mood && human.mob_mood.sanity > SANITY_DISTURBED) + var/hunger_rate = HUNGER_FACTOR * PASSIVE_HUNGER_MULTIPLIER + if(human.mob_mood?.sanity > SANITY_DISTURBED) hunger_rate *= max(1 - 0.002 * human.mob_mood.sanity, 0.5) //0.85 to 0.75 // Whether we cap off our satiety or move it towards 0 - if(human.satiety > MAX_SATIETY) - human.satiety = MAX_SATIETY - else if(human.satiety > 0) - human.satiety-- - else if(human.satiety < -MAX_SATIETY) - human.satiety = -MAX_SATIETY + if(human.satiety > 0) + human.adjust_satiety(-1 * seconds_per_tick) + else if(human.satiety < 0) - human.satiety++ + human.adjust_satiety(1 * seconds_per_tick) if(SPT_PROB(round(-human.satiety/77), seconds_per_tick)) human.set_jitter_if_lower(10 SECONDS) - hunger_rate = 2 * HUNGER_FACTOR + hunger_rate *= 3 + + hunger_rate *= hunger_modifier hunger_rate *= human.physiology.hunger_mod - human.adjust_nutrition(-hunger_rate * seconds_per_tick) + human.adjust_nutrition(-1 * hunger_rate * seconds_per_tick) var/nutrition = human.nutrition if(nutrition > NUTRITION_LEVEL_FULL) @@ -336,5 +340,18 @@ if(prob(emp_vulnerability/severity)) //Chance of permanent effects organ_flags |= ORGAN_SYNTHETIC_EMP //Starts organ faliure - gonna need replacing soon. +// Lizard stomach to Let Them Eat Rat +/obj/item/organ/internal/stomach/lizard + name = "lizardperson stomach" + desc = "A stomach native to a Lizardperson of Tiziran... or maybe one of its colonies." + color = COLOR_VERY_DARK_LIME_GREEN + // Lizards don't homeostasize (they're cold blooded) so they get hungrier faster to offset that + // Even with this modifier, note they still get hungrier like 1.5x slower than humans + hunger_modifier = 2 + +/obj/item/organ/internal/stomach/lizard/Initialize(mapload) + . = ..() + var/static/list/rat_cache = typecacheof(/obj/item/food/deadmouse) + disease_free_foods = rat_cache #undef STOMACH_METABOLISM_CONSTANT diff --git a/code/modules/surgery/organs/stomach/stomach_ethereal.dm b/code/modules/surgery/organs/stomach/stomach_ethereal.dm index 3c82f629cb51..c0ff1e781111 100644 --- a/code/modules/surgery/organs/stomach/stomach_ethereal.dm +++ b/code/modules/surgery/organs/stomach/stomach_ethereal.dm @@ -2,28 +2,32 @@ name = "biological battery" icon_state = "stomach-p" //Welp. At least it's more unique in functionaliy. desc = "A crystal-like organ that stores the electric charge of ethereals." + hunger_modifier = 0 //they do different hunger shit //organ_traits = list(TRAIT_NOHUNGER) // We have our own hunger mechanic. //Monkestation Removal, we have our OWN hunger mechanic. ///basically satiety but electrical var/crystal_charge = ETHEREAL_CHARGE_FULL ///used to keep ethereals from spam draining power sources var/drain_time = 0 -/* //Monkestation Removal /obj/item/organ/internal/stomach/ethereal/on_life(seconds_per_tick, times_fired) . = ..() - adjust_charge(-ETHEREAL_CHARGE_FACTOR * seconds_per_tick) + adjust_charge(-ETHEREAL_CHARGE_FACTOR * seconds_per_tick * 0.5) handle_charge(owner, seconds_per_tick, times_fired) -*/ + /obj/item/organ/internal/stomach/ethereal/on_insert(mob/living/carbon/stomach_owner) . = ..() RegisterSignal(stomach_owner, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, PROC_REF(charge)) RegisterSignal(stomach_owner, COMSIG_LIVING_ELECTROCUTE_ACT, PROC_REF(on_electrocute)) + RegisterSignal(stomach_owner, COMSIG_LIVING_HOMEOSTASIS, PROC_REF(handle_temp)) + RegisterSignal(stomach_owner, COMSIG_HUMAN_ON_HANDLE_BLOOD, PROC_REF(blood)) /obj/item/organ/internal/stomach/ethereal/on_remove(mob/living/carbon/stomach_owner) . = ..() UnregisterSignal(stomach_owner, COMSIG_PROCESS_BORGCHARGER_OCCUPANT) UnregisterSignal(stomach_owner, COMSIG_LIVING_ELECTROCUTE_ACT) + UnregisterSignal(stomach_owner, COMSIG_LIVING_HOMEOSTASIS) + UnregisterSignal(stomach_owner, COMSIG_HUMAN_ON_HANDLE_BLOOD) stomach_owner.clear_mood_event("charge") stomach_owner.clear_alert(ALERT_ETHEREAL_CHARGE) stomach_owner.clear_alert(ALERT_ETHEREAL_OVERCHARGE) @@ -31,6 +35,26 @@ /obj/item/organ/internal/stomach/ethereal/handle_hunger_slowdown(mob/living/carbon/human/human) human.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/hunger, multiplicative_slowdown = (1.5 * (1 - crystal_charge / 100))) + +/obj/item/organ/internal/stomach/ethereal/proc/handle_temp(mob/living/carbon/human/human, natural_change, seconds_per_tick) + SIGNAL_HANDLER + + adjust_charge(-0.5 * ETHEREAL_CHARGE_FACTOR * abs(natural_change * 0.1) * seconds_per_tick * 0.01) + return HOMEOSTASIS_NO_HUNGER + +/obj/item/organ/internal/stomach/ethereal/proc/blood(mob/living/carbon/human/ethereal, seconds_per_tick, times_fired) + SIGNAL_HANDLER + + if(ethereal.stat == DEAD) + return NONE + + . = HANDLE_BLOOD_NO_NUTRITION_DRAIN|HANDLE_BLOOD_NO_EFFECTS + + INVOKE_ASYNC(src, PROC_REF(adjust_charge),-ETHEREAL_BLOOD_CHARGE_FACTOR * seconds_per_tick * 0.1, TRUE) + INVOKE_ASYNC(src, PROC_REF(handle_charge), ethereal, seconds_per_tick, times_fired) + + return . + /obj/item/organ/internal/stomach/ethereal/proc/charge(datum/source, amount, repairs) SIGNAL_HANDLER if(!ishuman(owner)) @@ -53,77 +77,87 @@ adjust_charge(shock_damage * siemens_coeff * 2) to_chat(owner, span_notice("You absorb some of the shock into your body!")) -/obj/item/organ/internal/stomach/ethereal/proc/adjust_charge(amount) +/obj/item/organ/internal/stomach/ethereal/proc/adjust_charge(amount, passive = FALSE) //crystal_charge = clamp(crystal_charge + amount, ETHEREAL_CHARGE_NONE, ETHEREAL_CHARGE_DANGEROUS) Monkestation Removal if(ishuman(owner)) - var/mob/living/carbon/human/human = owner - if(istype(human.dna.species, /datum/species/ethereal)) - var/datum/species/ethereal/species = human.dna.species - var/amount_adjusted = (BLOOD_VOLUME_NORMAL * amount)/ETHEREAL_CHARGE_FULL - species.adjust_charge(human, amount_adjusted, FALSE) - -/obj/item/organ/internal/stomach/ethereal/proc/handle_charge(mob/living/carbon/carbon, seconds_per_tick, times_fired) - switch(crystal_charge) - if(-INFINITY to ETHEREAL_CHARGE_NONE) - carbon.add_mood_event("charge", /datum/mood_event/decharged) - carbon.clear_alert("ethereal_overcharge") - carbon.throw_alert(ALERT_ETHEREAL_CHARGE, /atom/movable/screen/alert/emptycell/ethereal) - if(carbon.health > 50) - carbon.apply_damage(0.65, BURN, null, null, carbon) - if(ETHEREAL_CHARGE_NONE to ETHEREAL_CHARGE_LOWPOWER) - carbon.clear_alert("ethereal_overcharge") - carbon.add_mood_event("charge", /datum/mood_event/decharged) - carbon.throw_alert(ALERT_ETHEREAL_CHARGE, /atom/movable/screen/alert/lowcell/ethereal, 3) - if(carbon.health > 10.5) - carbon.apply_damage(0.325 * seconds_per_tick, TOX, null, null, carbon) - if(ETHEREAL_CHARGE_LOWPOWER to ETHEREAL_CHARGE_NORMAL) - carbon.clear_alert("ethereal_overcharge") - carbon.add_mood_event("charge", /datum/mood_event/lowpower) - carbon.throw_alert(ALERT_ETHEREAL_CHARGE, /atom/movable/screen/alert/lowcell/ethereal, 2) - carbon.blood_volume = min(carbon.blood_volume + (BLOOD_REGEN_FACTOR * 0.1 * seconds_per_tick), BLOOD_VOLUME_NORMAL) //worse than a starving human - if(ETHEREAL_CHARGE_ALMOSTFULL to ETHEREAL_CHARGE_FULL) - carbon.clear_alert("ethereal_overcharge") - carbon.clear_alert("ethereal_charge") - carbon.add_mood_event("charge", /datum/mood_event/charged) - carbon.blood_volume = min(carbon.blood_volume + (BLOOD_REGEN_FACTOR * 0.9 * seconds_per_tick), BLOOD_VOLUME_NORMAL) //slightly worse than a human (optimal nutrition+satiety gives 1.25) - if(ETHEREAL_CHARGE_FULL to ETHEREAL_CHARGE_OVERLOAD) - carbon.clear_alert("ethereal_charge") - carbon.add_mood_event("charge", /datum/mood_event/overcharged) - carbon.throw_alert(ALERT_ETHEREAL_OVERCHARGE, /atom/movable/screen/alert/ethereal_overcharge, 1) - carbon.apply_damage(0.2, TOX, null, null, carbon) - carbon.blood_volume = min(carbon.blood_volume + (BLOOD_REGEN_FACTOR * 1.6 * seconds_per_tick), BLOOD_VOLUME_NORMAL) //slightly better than a human, at the cost of toxic damage - if(ETHEREAL_CHARGE_OVERLOAD to ETHEREAL_CHARGE_DANGEROUS) - carbon.clear_alert("ethereal_charge") - carbon.add_mood_event("charge", /datum/mood_event/supercharged) - carbon.throw_alert(ALERT_ETHEREAL_OVERCHARGE, /atom/movable/screen/alert/ethereal_overcharge, 2) - carbon.apply_damage(0.325 * seconds_per_tick, TOX, null, null, carbon) - carbon.blood_volume = min(carbon.blood_volume + (BLOOD_REGEN_FACTOR * 2.6 * seconds_per_tick), BLOOD_VOLUME_NORMAL) //significantly better than a human, at the cost of high toxin damage and unsustainability due to discharge + var/mob/living/carbon/human/ethereal = owner + var/amount_adjusted = (BLOOD_VOLUME_NORMAL * amount)/ETHEREAL_CHARGE_FULL + if(passive) + if(ethereal.blood_volume < ETHEREAL_BLOOD_CHARGE_LOWEST_PASSIVE) //Do not apply the clamp if its below the passive reduction level(no infinite blood sorry) + return + if(ethereal.blood_volume + amount_adjusted < ETHEREAL_BLOOD_CHARGE_LOWEST_PASSIVE+1) + ethereal.blood_volume = ETHEREAL_BLOOD_CHARGE_LOWEST_PASSIVE+1 //bottom them off here if the end result would be less than the stopping point. + ethereal.blood_volume = clamp(ethereal.blood_volume + amount_adjusted, ETHEREAL_BLOOD_CHARGE_LOWEST_PASSIVE+1, ETHEREAL_BLOOD_CHARGE_DANGEROUS) + return + ethereal.blood_volume = clamp(ethereal.blood_volume + amount, ETHEREAL_BLOOD_CHARGE_NONE, ETHEREAL_BLOOD_CHARGE_DANGEROUS) + +/obj/item/organ/internal/stomach/ethereal/proc/handle_charge(mob/living/carbon/ethereal, seconds_per_tick, times_fired) + var/datum/species/species = ethereal.dna.species + species.brutemod = 1.15 + var/word = pick("like you can't breathe","your lungs locking up","extremely lethargic") + var/blood_volume = ethereal.blood_volume + if(HAS_TRAIT(ethereal, TRAIT_ETHEREAL_NO_OVERCHARGE)) + blood_volume = min(blood_volume, ETHEREAL_BLOOD_CHARGE_FULL) + switch(blood_volume) + if(-INFINITY to ETHEREAL_BLOOD_CHARGE_LOWEST_PASSIVE) + ethereal.add_mood_event("charge", /datum/mood_event/decharged) + ethereal.clear_alert("ethereal_overcharge") + ethereal.throw_alert(ALERT_ETHEREAL_CHARGE, /atom/movable/screen/alert/emptycell/ethereal) + species.brutemod = 2 + if(SPT_PROB(7.5, seconds_per_tick)) + to_chat(src, span_warning("You feel [word].")) + ethereal.adjustOxyLoss(round(0.01 * (ETHEREAL_BLOOD_CHARGE_LOW - ethereal.blood_volume) * seconds_per_tick, 1)) + if(ETHEREAL_BLOOD_CHARGE_LOWEST_PASSIVE to ETHEREAL_BLOOD_CHARGE_LOW) + ethereal.clear_alert("ethereal_overcharge") + ethereal.add_mood_event("charge", /datum/mood_event/decharged) + ethereal.throw_alert(ALERT_ETHEREAL_CHARGE, /atom/movable/screen/alert/lowcell/ethereal, 3) + species.brutemod = 1.5 + if(ethereal.health > 10.5) + ethereal.apply_damage(0.155 * seconds_per_tick, TOX, null, null, ethereal) + if(ETHEREAL_BLOOD_CHARGE_LOW to ETHEREAL_BLOOD_CHARGE_NORMAL) + ethereal.clear_alert("ethereal_overcharge") + ethereal.add_mood_event("charge", /datum/mood_event/lowpower) + ethereal.throw_alert(ALERT_ETHEREAL_CHARGE, /atom/movable/screen/alert/lowcell/ethereal, 2) + species.brutemod = 1.25 + if(ETHEREAL_BLOOD_CHARGE_ALMOSTFULL to ETHEREAL_BLOOD_CHARGE_FULL) + ethereal.clear_alert("ethereal_overcharge") + ethereal.clear_alert("ethereal_charge") + ethereal.add_mood_event("charge", /datum/mood_event/charged) + species.brutemod = 1 + if(ETHEREAL_BLOOD_CHARGE_FULL to ETHEREAL_BLOOD_CHARGE_OVERLOAD) + ethereal.clear_alert("ethereal_charge") + ethereal.add_mood_event("charge", /datum/mood_event/overcharged) + ethereal.throw_alert(ALERT_ETHEREAL_OVERCHARGE, /atom/movable/screen/alert/ethereal_overcharge, 1) + species.brutemod = 1.25 + if(ETHEREAL_BLOOD_CHARGE_OVERLOAD to ETHEREAL_BLOOD_CHARGE_DANGEROUS) + ethereal.clear_alert("ethereal_charge") + ethereal.add_mood_event("charge", /datum/mood_event/supercharged) + ethereal.throw_alert(ALERT_ETHEREAL_OVERCHARGE, /atom/movable/screen/alert/ethereal_overcharge, 2) + ethereal.apply_damage(0.2 * seconds_per_tick, TOX, null, null, ethereal) + species.brutemod = 1.5 if(SPT_PROB(5, seconds_per_tick)) // 5% each seacond for ethereals to explosively release excess energy if it reaches dangerous levels - discharge_process(carbon) + discharge_process(ethereal) else - owner.clear_mood_event("charge") - carbon.clear_alert(ALERT_ETHEREAL_CHARGE) - carbon.clear_alert(ALERT_ETHEREAL_OVERCHARGE) + ethereal.clear_mood_event("charge") + ethereal.clear_alert(ALERT_ETHEREAL_CHARGE) + ethereal.clear_alert(ALERT_ETHEREAL_OVERCHARGE) -/obj/item/organ/internal/stomach/ethereal/proc/discharge_process(mob/living/carbon/carbon) - to_chat(carbon, span_warning("You begin to lose control over your charge!")) - carbon.visible_message(span_danger("[carbon] begins to spark violently!")) +/obj/item/organ/internal/stomach/ethereal/proc/discharge_process(mob/living/carbon/ethereal) + to_chat(ethereal, span_warning("You begin to lose control over your charge!")) + ethereal.visible_message(span_danger("[ethereal] begins to spark violently!")) var/static/mutable_appearance/overcharge //shameless copycode from lightning spell overcharge = overcharge || mutable_appearance('icons/effects/effects.dmi', "electricity", EFFECTS_LAYER) - carbon.add_overlay(overcharge) - - if(do_after(carbon, 5 SECONDS, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_HELD_ITEM|IGNORE_INCAPACITATED))) - if(ishuman(carbon)) - var/mob/living/carbon/human/human = carbon - if(human.dna?.species) - //fixed_mut_color is also ethereal color (for some reason) - carbon.flash_lighting_fx(5, 7, human.dna.species.fixed_mut_color ? human.dna.species.fixed_mut_color : human.dna.features["mcolor"]) - - playsound(carbon, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) - carbon.cut_overlay(overcharge) - tesla_zap(carbon, 2, crystal_charge*2.5, ZAP_OBJ_DAMAGE | ZAP_LOW_POWER_GEN | ZAP_ALLOW_DUPLICATES) - adjust_charge(ETHEREAL_CHARGE_FULL - crystal_charge) - carbon.visible_message(span_danger("[carbon] violently discharges energy!"), span_warning("You violently discharge energy!")) - - carbon.Paralyze(100) + ethereal.add_overlay(overcharge) + + if(do_after(ethereal, 5 SECONDS, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_HELD_ITEM|IGNORE_INCAPACITATED))) + var/datum/color_palette/generic_colors/located = ethereal.dna.color_palettes[/datum/color_palette/generic_colors] + ethereal.flash_lighting_fx(5, 7, ethereal.dna.species.fixed_mut_color ? ethereal.dna.species.fixed_mut_color : located.return_color(MUTANT_COLOR)) + + playsound(ethereal, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) + ethereal.cut_overlay(overcharge) + tesla_zap(ethereal, 2, ethereal.blood_volume*9, ZAP_OBJ_DAMAGE | ZAP_GENERATES_POWER | ZAP_ALLOW_DUPLICATES) + adjust_charge(ETHEREAL_BLOOD_CHARGE_FULL - ethereal.blood_volume) + ethereal.visible_message(span_danger("[ethereal] violently discharges energy!"), span_warning("You violently discharge energy!")) + + ethereal.Paralyze(100) diff --git a/code/modules/surgery/repair_puncture.dm b/code/modules/surgery/repair_puncture.dm index c61eeeaa8bdd..8097ad9490b3 100644 --- a/code/modules/surgery/repair_puncture.dm +++ b/code/modules/surgery/repair_puncture.dm @@ -26,14 +26,8 @@ /datum/surgery_step/close, ) -/datum/surgery/repair_puncture/can_start(mob/living/user, mob/living/carbon/target) - if(!istype(target)) - return FALSE - . = ..() - if(.) - var/obj/item/bodypart/targeted_bodypart = target.get_bodypart(user.zone_selected) - var/datum/wound/burn/flesh/pierce_wound = targeted_bodypart.get_wound_type(targetable_wound) - return(pierce_wound && pierce_wound.blood_flow > 0) +/datum/surgery/repair_puncture/is_valid_wound(datum/wound/wound) + return ..() && wound.blood_flow > 0 //SURGERY STEPS diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index 3f30cd9244a1..3f01d7fe981b 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -67,15 +67,28 @@ operated_bodypart = null return ..() +/datum/surgery/proc/is_valid_wound(datum/wound/wound) + return istype(wound, targetable_wound) /datum/surgery/proc/can_start(mob/user, mob/living/patient) //FALSE to not show in list - . = TRUE if(replaced_by == /datum/surgery) return FALSE + if(targetable_wound) + var/any_wound = FALSE + var/obj/item/bodypart/targeted_bodypart = patient.get_bodypart(user.zone_selected) + for(var/datum/wound/found_wound as anything in targeted_bodypart?.wounds) + if(is_valid_wound(found_wound)) + any_wound = TRUE + break + + if(!any_wound) + return FALSE + if(!requires_tech && !replaced_by) return TRUE + . = TRUE if(requires_tech) . = FALSE @@ -92,16 +105,15 @@ else return TRUE - var/turf/patient_turf = get_turf(patient) - //Get the relevant operating computer - var/obj/machinery/computer/operating/opcomputer = locate_operating_computer(patient_turf) + var/obj/machinery/computer/operating/opcomputer = locate_operating_computer(get_turf(patient)) if (isnull(opcomputer)) return . if(replaced_by in opcomputer.advanced_surgeries) return FALSE if(type in opcomputer.advanced_surgeries) return TRUE + return . /datum/surgery/proc/next_step(mob/living/user, modifiers) if(location != user.zone_selected) diff --git a/code/modules/tgui_input/color.dm b/code/modules/tgui_input/color.dm index fe161b2e6a92..fcc3f80d9c99 100644 --- a/code/modules/tgui_input/color.dm +++ b/code/modules/tgui_input/color.dm @@ -118,6 +118,10 @@ closed = TRUE SStgui.close_uis(src) return TRUE + if("null") + set_choice(null) + SStgui.close_uis(src) + return TRUE /datum/tgui_color_picker/proc/set_choice(choice) src.choice = choice diff --git a/code/modules/unit_tests/bloody_footprints.dm b/code/modules/unit_tests/bloody_footprints.dm index 76b86590861e..2a786414fa20 100644 --- a/code/modules/unit_tests/bloody_footprints.dm +++ b/code/modules/unit_tests/bloody_footprints.dm @@ -21,9 +21,8 @@ blood_master.forceMove(run_loc_floor_bottom_left) var/datum/component/bloodysoles/soles = holds_blood.GetComponent(/datum/component/bloodysoles) - var/blood_type = pool.blood_state - TEST_ASSERT(soles.bloody_shoes[blood_type], "Shoes didn't become stained after stepping in a pool of [blood_type]") + TEST_ASSERT(soles.total_bloodiness, "Shoes didn't become stained after stepping in a pool of blood") //The bloody soles component handles the order of stepping on blood/stepping on a bloody tile in a constranating way //Which means it needs to check and see if any time has passed between steps, so it can be sure the player is stepping onto a new tile (that should become bloody) @@ -39,10 +38,9 @@ var/footprint_total = 0 for(var/obj/effect/decal/cleanable/blood/footprints/print_set in move_to) - if(print_set.blood_state == blood_type) - footprint_total += 1 + footprint_total += 1 - TEST_ASSERT(footprint_total, "The floor didn't get covered in [blood_type] after being walked over") + TEST_ASSERT(footprint_total, "The floor didn't get covered in blood after being walked over") soles.last_pickup -= 1 @@ -54,8 +52,7 @@ footprint_total = 0 for(var/obj/effect/decal/cleanable/blood/footprints/print_set in move_to) - if(print_set.blood_state == blood_type) - footprint_total += 1 + footprint_total += 1 TEST_ASSERT(footprint_total, "The floor somehow lost its footprints after being walked over") TEST_ASSERT_EQUAL(footprint_total, 1, "The floor had more than one set of footprints in it, something is fucked") diff --git a/code/modules/unit_tests/screenshot_humanoids.dm b/code/modules/unit_tests/screenshot_humanoids.dm index a0e7abc1633e..cab447f9ea3f 100644 --- a/code/modules/unit_tests/screenshot_humanoids.dm +++ b/code/modules/unit_tests/screenshot_humanoids.dm @@ -4,7 +4,8 @@ /datum/unit_test/screenshot_humanoids/Run() // Test lizards as their own thing so we can get more coverage on their features var/mob/living/carbon/human/lizard = allocate(/mob/living/carbon/human/dummy/consistent) - lizard.dna.features["mcolor"] = "#099" + var/datum/color_palette/generic_colors/located = lizard.dna.color_palettes[/datum/color_palette/generic_colors] + located.mutant_color = "#099" lizard.dna.features["tail_lizard"] = "Light Tiger" lizard.dna.features["snout"] = "Sharp + Light" lizard.dna.features["horns"] = "Simple" diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodbrother.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodbrother.png index 399627ac15de..0a7fdd7fb774 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodbrother.png and b/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodbrother.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodsucker.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodsucker.png index 27a91f8f14c2..786f195c0aeb 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodsucker.png and b/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodsucker.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodsuckerbreakout.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodsuckerbreakout.png index 27a91f8f14c2..786f195c0aeb 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodsuckerbreakout.png and b/code/modules/unit_tests/screenshots/screenshot_antag_icons_bloodsuckerbreakout.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_antag_icons_vampiricaccident.png b/code/modules/unit_tests/screenshots/screenshot_antag_icons_vampiricaccident.png index 27a91f8f14c2..786f195c0aeb 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_antag_icons_vampiricaccident.png and b/code/modules/unit_tests/screenshots/screenshot_antag_icons_vampiricaccident.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_mush.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_mush.png index 6755b4792e0f..b0058fbe135b 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_mush.png and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_mush.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_ornithid.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_ornithid.png new file mode 100644 index 000000000000..b3fcb82247ff Binary files /dev/null and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_ornithid.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_satyr.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_satyr.png index 6b25f9aad79c..2a70c26d0ad2 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_satyr.png and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_satyr.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_simian.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_simian.png index e7bea2e1bb64..8d1cdfd9c396 100644 Binary files a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_simian.png and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_simian.png differ diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_werewolf.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_werewolf.png new file mode 100644 index 000000000000..dce4b390b828 Binary files /dev/null and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_werewolf.png differ diff --git a/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm index 9fb642842c04..14c2b73d69a2 100644 --- a/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/medical_tools.dm @@ -161,12 +161,11 @@ t1 = "*dead*" else t1 = "Unknown" - var/core_temp = "" - if(ishuman(patient)) - var/mob/living/carbon/human/humi = patient - core_temp = {"Body Temperature: [humi.bodytemperature-T0C]°C ([humi.bodytemperature*1.8-459.67]°F)
"} + var/skin_temp = patient.get_skin_temperature() + var/body_temp = patient.bodytemperature return {"Health: [patient.stat > 1 ? "[t1]" : "[patient.health]% ([t1])"]
- [core_temp] + Skin Temperature: [KELVIN_TO_CELCIUS(skin_temp)]°C ([KELVIN_TO_FAHRENHEIT(skin_temp)]°F)
+ Body Temperature: [KELVIN_TO_CELCIUS(body_temp)]°C ([KELVIN_TO_FAHRENHEIT(body_temp)]°F)
Body Temperature: [patient.bodytemperature-T0C]°C ([patient.bodytemperature*1.8-459.67]°F)
Brute Damage: [patient.getBruteLoss()]%
Respiratory Damage: [patient.getOxyLoss()]%
diff --git a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm index cadccb6fe86c..0e147ec37665 100644 --- a/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm +++ b/code/modules/vehicles/mecha/equipment/tools/mining_tools.dm @@ -130,11 +130,7 @@ target.apply_damage(10, BRUTE, BODY_ZONE_CHEST, target.run_armor_check(target_part, MELEE)) //blood splatters - var/splatter_dir = get_dir(chassis, target) - if(isalien(target)) - new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target.drop_location(), splatter_dir, COLOR_DARK_PURPLE) - else - new /obj/effect/temp_visual/dir_setting/bloodsplatter(target.drop_location(), splatter_dir, COLOR_DARK_RED) + target.do_splatter_effect(get_dir(chassis, target)) //organs go everywhere if(target_part && prob(10 * drill_level)) diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm index 3d8cc1d02044..9a503c6cf240 100644 --- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm +++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm @@ -58,6 +58,7 @@ var/obj/projectile/projectile_obj = new projectile(get_turf(src)) projectile_obj.log_override = TRUE //we log being fired ourselves a little further down. projectile_obj.firer = chassis + projectile_obj.fired_from = src projectile_obj.preparePixelProjectile(target, source, modifiers, spread) if(source.client && isliving(source)) //dont want it to happen from syndie mecha npc mobs, they do direct fire anyways var/mob/living/shooter = source diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm index 464bf9f3740c..f933f14854a7 100644 --- a/code/modules/zombie/items.dm +++ b/code/modules/zombie/items.dm @@ -29,7 +29,7 @@ if(!target.get_bodypart(BODY_ZONE_HEAD)) return - if((NOZOMBIE in target.dna.species.species_traits) || HAS_TRAIT(target, TRAIT_NO_ZOMBIFY)) + if(HAS_TRAIT(target, TRAIT_NO_ZOMBIFY)) // cannot infect any NOZOMBIE subspecies (such as high functioning // zombies) return diff --git a/config/admins.txt b/config/admins.txt index f48ff5bc03c3..704fa538c332 100644 --- a/config/admins.txt +++ b/config/admins.txt @@ -4,148 +4,4 @@ #Ranks will match to those with the same name in admin_ranks.txt, if a match isn't found the user won't be adminned. #If SQL-based admin loading is enabled, admins listed here will always be loaded first and will override any duplicate entries in the database. -Optimumtact = Host -CitrusGender = Game Master -NewSta = Game Master -Expletives = Game Master -kingofkosmos = Game Master -MrStonedOne = Lazy Master -microscopics = Game Master -Gun Hog = Game Master -KorPhaeron = Game Master -razharas = Game Master -Lordpidey = Game Master -Niknakflak = Game Master -rolan7 = Game Master -quarxink = Game Master -adrix89 = Game Master -tle = Game Master -xsi = Game Master -scaredofshadows = Game Master -neofite = Game Master -trubblebass = Game Master -mport2004 = Game Master -deuryn = Game Master -agouri = Game Master -errorage = Game Master -superxpdude = Game Master -petethegoat = Game Master -nodrak = Game Master -carnwennan = Game Master -ikarrus = Game Master -cheridan = Game Master -giacomand = Game Master -rockdtben = Game Master -sieve = Game Master -aranclanos = Game Master -intigracy = Game Master -dumpdavidson = Game Master -kazeespada = Game Master -malkevin = Game Master -incoming = Game Master -demas = Game Master -fleure = Game Master -ricotez = Game Master -misterperson = Game Master -crimsonvision = Game Master -iamgoofball = Game Master -zelacks = Game Master -androidsfv = Game Master -miggles = Game Master -jordie0608 = Game Master -s0ldi3rkr4s0 = Game Master -ergovisavi = Game Master -vistapowa = Game Master -miauw62 = Game Master -rumia29 = Game Master -bobylein = Game Master -sirbayer = Game Master -hornygranny = Game Master -yota = Game Master -firecage = Game Master -donkieyo = Game Master -argoneus = Game Master -paprka = Game Master -cookingboy3 = Game Master -limeliz = Game Master -steelpoint = Game Master -phil235 = Game Master -CorruptComputer = Game Master -xxnoob = Game Master -tkdrg = Game Master -Cuboos = Game Master -thunder12345 = Game Master -wjohnston = Game Master -mandurrh = Game Master -thurgatar = Game Master -xerux = Game Master -dannno = Game Master -lo6a4evskiy = Game Master -vekter = Game Master -Ahammer18 = Game Master -ACCount12 = Game Master -fayrik = Game Master -shadowlight213 = Game Master -drovidicorv = Game Master -Dunc = Game Master -MMMiracles = Game Master -bear1ake = Game Master -CoreOverload = Game Master -Jalleo = Game Master -ChangelingRain = Game Master -FoxPMcCloud = Game Master -Xhuis = Game Master -Astralenigma = Game Master -Tokiko1 = Game Master -SuperSayu = Game Master -Lzimann = Game Master -As334 = Game Master -neersighted = Game Master -Swankcookie = Game Master -Ressler = Game Master -Folix = Game Master -Bawhoppennn = Game Master -Anturke = Host -Lumipharon = Game Master -bgobandit = Game Master -coiax = Game Master -RandomMarine = Game Master -PKPenguin321 = Game Master -TechnoAlchemist = Game Master -Aloraydrel = Game Master -Quiltyquilty = Game Master -SnipeDragon = Game Master -Fjeld = Game Master -kevinz000 = Game Master -Tacolizard = Game Master -TrustyGun = Game Master -Cyberboss = Game Master -PJB3005 = Game Master -Sweaterkittens = Game Master -Feemjmeem = Game Master -JStheguy = Game Master -excessiveuseofcobby = Game Master -Plizzard = Game Master -octareenroon91 = Game Master -Serpentarium = Game Master -Averagejoe82 = Game Master -The Dreamweaver = Game Master -Denton-30 = Game Master -Naksuasdf = Game Master -MrDoomBringer = Game Master -shizcalev = Game Master -NicBR = Game Master -LoserWasTaken = Game Master -Fikou = Game Master -Magatsuchi = Game Master -Skoglol = Game Master -4dplanner = Game Master -Time-Green = Game Master -StyleMistake = Game Master -actioninja = Game Master -bobbahbrown = Game Master -Jaredfogle = Game Master+Coder -WaylandSmithy = Game Master -NamelessFairy = Game Master -WalterMeldron = Game Master -san7890 = Game Master +dwasint = Host diff --git a/config/config.txt b/config/config.txt index a15291b8953e..464b95aa5078 100644 --- a/config/config.txt +++ b/config/config.txt @@ -528,7 +528,7 @@ MOTD motd.txt ## The cache is assumed to be cleared by TGS recompiling, which deletes `tmp`. ## This should be disabled (through `CACHE_ASSETS 0`) on development, ## but enabled on production (the default). -CACHE_ASSETS 0 +CACHE_ASSETS 1 ## If this remains commented out, we will allow players to download their own preferences as a JSON file to do whatever they wish. ## This does require the game code to read (and only read) the /data folder where these files are stored, and then use the BYOND FTP Function to send the file to the client. diff --git a/config/contributors.dmi b/config/contributors.dmi new file mode 100644 index 000000000000..800803a01ea2 Binary files /dev/null and b/config/contributors.dmi differ diff --git a/config/contributors.txt b/config/contributors.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/config/game_options.txt b/config/game_options.txt index 66448be8ea59..6d24745d76f5 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -357,6 +357,7 @@ ROUNDSTART_RACES simian ROUNDSTART_RACES arachnid ROUNDSTART_RACES apid ROUNDSTART_RACES satyr +ROUNDSTART_RACES ornithid ## Races that are better than humans in some ways, but worse in others ROUNDSTART_RACES ethereal diff --git a/goon/ATTRIBUTION.txt b/goon/ATTRIBUTION.txt new file mode 100644 index 000000000000..b1b34ec4422a --- /dev/null +++ b/goon/ATTRIBUTION.txt @@ -0,0 +1,281 @@ +openlootcrate.ogg - + Compressed in 2023 by virvatuli sound/misc/openlootcrate.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/openlootcrate.ogg + +openlootcrate2.ogg - + Compressed in 2023 by virvatuli sound/misc/openlootcrate2.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/openlootcrate2.ogg + +ArtifactAnc1.ogg - + OG Commit sound/machines/ArtifactAnc1.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/ArtifactAnc1.ogg + +ArtifactEld1.ogg - + OG Commit sound/machines/ArtifactEld1.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/ArtifactEld1.ogg + +ArtifactEld2.ogg - + OG Commit sound/machines/ArtifactEld2.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/ArtifactEld2.ogg + +ArtifactMar1.ogg - + OG Commit sound/machines/ArtifactMar1.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/ArtifactMar1.ogg + +ArtifactMar2.ogg - + OG Commit sound/machines/ArtifactMar2.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/ArtifactMar2.ogg + +ArtifactPre1.ogg - + OG Commit sound/machines/ArtifactPre1.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/ArtifactPre1.ogg + +ArtifactWiz1.ogg - + OG Commit sound/machines/ArtifactWiz1.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/ArtifactWiz1.ogg + +elec_bzzz.ogg - + OG Commit sound/effects/elec_bzzz.ogg +https://github.com/goonstation/goonstation/blob/master/sound/effects/elec_bzzz.ogg + +electric_shock.ogg - + OG Commit sound/effects/electric_shock.ogg +https://github.com/goonstation/goonstation/blob/master/sound/effects/electric_shock.ogg + +electric_shock_short.ogg - + OG Commit sound/effects/electric_shock_short.ogg +https://github.com/goonstation/goonstation/blob/master/sound/effects/electric_shock_short.ogg + +bellalert.ogg - + OG Commit sound/machines/bellalert.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/bellalert.ogg + +engine_alert1.ogg - + OG Commit sound/machines/engine_alert1.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/engine_alert1.ogg + +engine_alert2.ogg - + OG Commit sound/machines/engine_alert2.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/engine_alert2.ogg + +engine_alert3.ogg - + OG Commit sound/machines/engine_alert3.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/engine_alert3.ogg + +engine_grump1.ogg - + OG Commit sound/machines/engine_grump1.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/engine_grump1.ogg + +engine_grump2.ogg - + OG Commit sound/machines/engine_grump2.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/engine_grump2.ogg + +engine_grump3.ogg - + OG Commit sound/machines/engine_grump3.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/engine_grump3.ogg + +engine_grump4.ogg - + OG Commit sound/machines/engine_grump4.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/engine_grump4.ogg + +engine_highpower.ogg - + OG Commit sound/machines/engine_highpower.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/engine_highpower.ogg + +tractor_running.ogg - + OG Commit sound/machines/tractor_running1.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/tractor_running.ogg + +tractor_running2.ogg - + OG Commit sound/machines/tractor_running2.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/tractor_running2.ogg + +tractor_running3.ogg - + OG Commit sound/machines/tractor_running3.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/tractor_running3.ogg + +tractorrev.ogg - + OG Commit sound/machines/tractorrev.ogg +https://github.com/goonstation/goonstation/blob/master/sound/machines/tractorrev.ogg + + +babynoise.ogg - + OG Commit goonstation/sound/babynoise.ogg +https://github.com/goonstation/goonstation/blob/master/sound/voice/babynoise.ogg + +body_thud.ogg - + OG Commit goonstation/sound/misc/body_thud.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/body_thud.ogg + + +speak_1.ogg - + OG Commit goonstation/sound/misc/talk/speak_1.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/talk/speak_1.ogg + +speak_1_exclaim.ogg - + OG Commit goonstation/sound/misc/talk/speak_1_exclaim.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/talk/speak_1_exclaim.ogg + +speak_1_ask.ogg - + OG Commit goonstation/sound/misc/talk/speak_1_ask.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/talk/speak_1_ask.ogg + +speak_2.ogg - + OG Commit goonstation/sound/misc/talk/speak_2.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/talk/speak_2.ogg + +speak_2_exclaim.ogg - + OG Commit goonstation/sound/misc/talk/speak_2_exclaim.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/talk/speak_2_exclaim.ogg + +speak_2_ask.ogg - + OG Commit goonstation/sound/misc/talk/speak_2_ask.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/talk/speak_2_ask.ogg + +speak_3.ogg - + OG Commit goonstation/sound/misc/talk/speak_3.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/talk/speak_3.ogg + +speak_3_exclaim.ogg - + OG Commit goonstation/sound/misc/talk/speak_3_exclaim.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/talk/speak_3_exclaim.ogg + +speak_3_ask.ogg - + OG Commit goonstation/sound/misc/talk/speak_3_ask.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/talk/speak_3_ask.ogg + +speak_4.ogg - + OG Commit goonstation/sound/misc/talk/speak_4.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/talk/speak_4.ogg + +speak_4_exclaim.ogg - + OG Commit goonstation/sound/misc/talk/speak_4_exclaim.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/talk/speak_4_exclaim.ogg + +speak_4_ask.ogg - + OG Commit goonstation/sound/misc/talk/speak_4_ask.ogg +https://github.com/goonstation/goonstation/blob/master/sound/misc/talk/speak_4_ask.ogg + + + +radio_ai.ogg + mybluecorners (8ec37f12e282492a5e7aeb4ec1d5cfa2f1df7460 +https://github.com/goonstation/goonstation/blob/master/sound/misc/talk/radio_ai.ogg + + +neon_lining.dmi + Nebulacrity https://github.com/goonstation/goonstation/pull/1731 +https://github.com/goonstation/goonstation/blob/9470d5bbb76afa2ffdee6bddf8b97a68092d8b01/icons/obj/decals/neon_lining.dmi + +pt_laser.dmi + gannets +https://github.com/goonstation/goonstation/blob/master/icons/obj/pt_laser.dmi + + +teg.dmi - https://github.com/goonstation/goonstation/pull/3408 Azrun blower indication, Inital Commit (circulator's + Azrun https://github.com/goonstation/goonstation/pull/3408 blower indication + gannets - main teg sprite + Azrun https://github.com/goonstation/goonstation/pull/2902, open states +https://github.com/goonstation/goonstation/blob/master/icons/obj/power.dmi +https://github.com/goonstation/goonstation/blob/master/icons/obj/atmospherics/atmos.dmi + +slasher.dmi + Zonespace27 https://github.com/goonstation/goonstation/pull/6094 +https://github.com/Zonespace27/goonstation/blob/d9a36b8ae0203788683a38c0b8546c14b0e0f656/icons/mob/slasher.dmi + +electile.dmi + mybluecorners https://github.com/goonstation/goonstation/pull/1425/files#diff-cc282396fd85af02912a95be13420419cc7a433cfb2280c362f3c3cf4451ad2c +https://github.com/goonstation/goonstation/blob/master/icons/effects/electile.dmi + +320x320.dmi + goonstation/icons/effect/320x320.dmi (lootbox sprites), +https://github.com/goonstation/goonstation/blob/master/icons/effects/320x320.dmi + +displacements.dmi + pali6 (inital commit) +https://github.com/goonstation/goonstation/blob/master/icons/effects/distort.dmi + +particle.dmi + Azrun - https://github.com/goonstation/goonstation/commit/0f11103f910db33e05482a21f567ae8ef01237f1 + flrsh - https://github.com/goonstation/goonstation/commit/9ffc312e1b66aad4810dbf449c60b2b027b38898 + Sovexe - https://github.com/goonstation/goonstation/commit/ad6e662ae7547efff964ff6b39085621162761d8 + TobleroneSwordfish - https://github.com/goonstation/goonstation/commit/01f361fc560da88ab6cca050dd265bac420658f4 +https://github.com/goonstation/goonstation/blame/master/icons/effects/particles.dmi + + +multi_hit.dmi + goonstation/icons/effects/96x96 - swipe + goonstation/icons/effects/96x96 - stab +https://github.com/goonstation/goonstation/blob/master/icons/effects/96x96.dmi + + +networked.dmi + binarysudoku https://github.com/goonstation/goonstation/pull/750 +https://github.com/goonstation/goonstation/blob/master/icons/obj/networked.dmi + + +plants_alien.dmi + binarysudoku https://github.com/goonstation/goonstation/commit/9fb6d4c8df6ca51bbd6178cc703ffbeb5ae64be7 + sovexe https://github.com/goonstation/goonstation/commit/54f6c5b1b825ebf65647a510195e8ec93154b7a1 + sovexe https://github.com/goonstation/goonstation/commit/b5145abcde8113ce371f842ed4c12c6e2e7944c7 + azrun https://github.com/goonstation/goonstation/commit/3100dbc7c3d69f4d1744d9ffa1b9ded1e9f2c126 + m-earthfire, tobleroneswordfish https://github.com/goonstation/goonstation/commit/08c48c389012d17c8bbf735a6bc0f0fec684dd54 +https://github.com/goonstation/goonstation/blob/master/icons/obj/hydroponics/plants_alien.dmi + +plants_crop.dmi + binarysudoku https://github.com/goonstation/goonstation/commit/9fb6d4c8df6ca51bbd6178cc703ffbeb5ae64be7 + binarysudoku https://github.com/goonstation/goonstation/commit/a2bfa53e05fd18fd44d5d8bf9f8c3e4261e10fe6 + emily https://github.com/goonstation/goonstation/commit/6dde7025cf5ffaabc47f264638f90f92b116fbd7 + yellow-mushroom https://github.com/goonstation/goonstation/commit/df3347bf103e30354e1b45f5cea888d5c433be34 + DimWhat https://github.com/goonstation/goonstation/commit/306343902279aad64147a7d95fcb405ca95989af + sovexe https://github.com/goonstation/goonstation/commit/d3e97cde29fef8047983b66c09f6bf5a62449a20 + crackaduck https://github.com/goonstation/goonstation/commit/32e09c6a1834f1042cf49571476117e38c680cdc + crackaduck https://github.com/goonstation/goonstation/commit/350bf56e85732399329d9631485c45519951cf10 + wolfolotl https://github.com/goonstation/goonstation/commit/c0a09331cb7a3841030cd7991144cf92a826b5e1 + tobleroneswordfish https://github.com/goonstation/goonstation/commit/524eaf8aaf84b00920c7013fc5c6385f47b09be5 + flappybatpal https://github.com/goonstation/goonstation/commit/c09ca907184df4861b23a0df5df917d6505ea684 + tobleroneswordfish https://github.com/goonstation/goonstation/commit/1aa16631c7443140fdcf427bb9a04df5eeff8663 + sovexe https://github.com/goonstation/goonstation/commit/d3e97cde29fef8047983b66c09f6bf5a62449a20 +https://github.com/goonstation/goonstation/blob/master/icons/obj/hydroponics/plants_crop.dmi + +plants_flower.dmi + binarysudoku https://github.com/goonstation/goonstation/commit/9fb6d4c8df6ca51bbd6178cc703ffbeb5ae64be7 + janonas, jigjagboi45 tarmunora https://github.com/goonstation/goonstation/commit/243d0bfade03e14829d3c50fee5d09c938f97d41 + munien7 https://github.com/goonstation/goonstation/commit/5b27507352cb4f2c5988018c04e47f26f09ab116 + flrsh https://github.com/goonstation/goonstation/commit/9ffc312e1b66aad4810dbf449c60b2b027b38898 + eggcereal https://github.com/goonstation/goonstation/commit/9198822090a3dad530df408d6cc77b7e77406551 +https://github.com/goonstation/goonstation/blob/master/icons/obj/hydroponics/plants_flower.dmi + +plants_fruit.dmi + binarysudoku https://github.com/goonstation/goonstation/commit/9fb6d4c8df6ca51bbd6178cc703ffbeb5ae64be7 + jan-antilles https://github.com/goonstation/goonstation/commit/85c5d02771d900f72e32cd1ec9b5a85a7f01b9d1 + t-toasted https://github.com/goonstation/goonstation/commit/de386a2b86395f445c7a6ddba7cda039635c2605 + flappybatpal https://github.com/goonstation/goonstation/commit/c09ca907184df4861b23a0df5df917d6505ea684 + tanker4390 https://github.com/goonstation/goonstation/commit/4691dabb8b940bbd9c441af1e6916bd9f0bcd32c +https://github.com/goonstation/goonstation/blob/master/icons/obj/hydroponics/plants_fruit.dmi + +plant_herb.dmi + binarysudoku https://github.com/goonstation/goonstation/commit/9fb6d4c8df6ca51bbd6178cc703ffbeb5ae64be7 + mordent-goonstation https://github.com/goonstation/goonstation/commit/fdf70ea6bbcbde998d616b431328cb6770035524 + binarysudoku https://github.com/goonstation/goonstation/commit/a2bfa53e05fd18fd44d5d8bf9f8c3e4261e10fe6 + Janonas https://github.com/goonstation/goonstation/commit/a6291454d8210c29939c812a432b72f4aa394e62 + WALPVRGIS https://github.com/goonstation/goonstation/commit/4dc053670dc868888030d440feb4b3050370da00 + avimour, tobleroneswordfish https://github.com/goonstation/goonstation/commit/6a5b97afb44e2da544fffe2126e6cf9640089ee8 + colossusqw https://github.com/goonstation/goonstation/commit/114f0262462c4247578b308a4fba04e9350aa4ce + flrsh https://github.com/goonstation/goonstation/commit/9ffc312e1b66aad4810dbf449c60b2b027b38898 + temthrush https://github.com/goonstation/goonstation/commit/a2d3c6262172fa44eafd9071bba0364cf90cac09 + colossusqw https://github.com/goonstation/goonstation/commit/530ef545c793232ba2a57832f17c8deaf6a3cbfb +https://github.com/goonstation/goonstation/blob/master/icons/obj/hydroponics/plants_herb.dmi + +plant_veg.dmi + binarysudoku https://github.com/goonstation/goonstation/commit/9fb6d4c8df6ca51bbd6178cc703ffbeb5ae64be7 + wolfolotl, tarmunora, zewaka, mordent-goonstation https://github.com/goonstation/goonstation/commit/a941272744132922382940516cd83af2259f1ed9 + flappybatpal https://github.com/goonstation/goonstation/commit/c09ca907184df4861b23a0df5df917d6505ea684 + M-Earthfire https://github.com/goonstation/goonstation/commit/8ea2eb4b124dd7bd2c4a689e0bd1895dbe55d024 + Glamurio https://github.com/goonstation/goonstation/commit/d62440d0ecf4bb6380e2484f9ffc0251b2f31bf5 +https://github.com/goonstation/goonstation/blob/master/icons/obj/hydroponics/plants_veg.dmi + +plant_weed.dmi + binarysudoku https://github.com/goonstation/goonstation/commit/9fb6d4c8df6ca51bbd6178cc703ffbeb5ae64be7 + M-earthfire, tobleroneswordfish https://github.com/goonstation/goonstation/commit/08c48c389012d17c8bbf735a6bc0f0fec684dd54 +https://github.com/goonstation/goonstation/blob/master/icons/obj/hydroponics/plants_weed.dmi \ No newline at end of file diff --git a/icons/effects/blood.dmi b/icons/effects/blood.dmi index 9bf25b8de2bb..3d8e46c3837f 100644 Binary files a/icons/effects/blood.dmi and b/icons/effects/blood.dmi differ diff --git a/icons/effects/digi_filters.dmi b/icons/effects/digi_filters.dmi new file mode 100644 index 000000000000..c17ff0e13a0b Binary files /dev/null and b/icons/effects/digi_filters.dmi differ diff --git a/icons/effects/footprints.dmi b/icons/effects/footprints.dmi index a00c6a0f780d..8cefa901bc23 100644 Binary files a/icons/effects/footprints.dmi and b/icons/effects/footprints.dmi differ diff --git a/icons/hud/screen_alert.dmi b/icons/hud/screen_alert.dmi index f65f56e58c96..33a1ef4d0288 100755 Binary files a/icons/hud/screen_alert.dmi and b/icons/hud/screen_alert.dmi differ diff --git a/icons/mob/actions/actions_items.dmi b/icons/mob/actions/actions_items.dmi index 9b357963e267..681e7da89d5f 100644 Binary files a/icons/mob/actions/actions_items.dmi and b/icons/mob/actions/actions_items.dmi differ diff --git a/icons/mob/effects/dam_mob.dmi b/icons/mob/effects/dam_mob.dmi index 6390a1b34d64..51883685fb4c 100644 Binary files a/icons/mob/effects/dam_mob.dmi and b/icons/mob/effects/dam_mob.dmi differ diff --git a/monkestation/code/datums/stamina_container.dm b/monkestation/code/datums/stamina_container.dm index 28a3c9aa76ce..29dd479f6fff 100644 --- a/monkestation/code/datums/stamina_container.dm +++ b/monkestation/code/datums/stamina_container.dm @@ -75,11 +75,13 @@ COOLDOWN_START(src, stamina_grace_period, time) ///Adjust stamina by an amount. -/datum/stamina_container/proc/adjust(amt as num, forced) +/datum/stamina_container/proc/adjust(amt as num, forced, base_modify = FALSE) if((!amt || !COOLDOWN_FINISHED(src, stamina_grace_period)) && !forced) return ///Our parent might want to fuck with these numbers var/modify = parent.pre_stamina_change(amt, forced) + if(base_modify) + modify = amt current = round(clamp(current + modify, 0, maximum), DAMAGE_PRECISION) update(1) if((amt < 0) && is_regenerating) diff --git a/monkestation/code/game/machinery/computer/cloning.dm b/monkestation/code/game/machinery/computer/cloning.dm index fcd93b7712f6..12ce94de0135 100644 --- a/monkestation/code/game/machinery/computer/cloning.dm +++ b/monkestation/code/game/machinery/computer/cloning.dm @@ -529,11 +529,10 @@ if(ishuman(mob_occupant)) dna = C.has_dna() - var/mob/living/carbon/human/human_occupant = mob_occupant var/obj/item/card/id/I = C.get_idcard(TRUE) if(I) has_bank_account = I.registered_account - if(!istype(dna) || (NO_DNA_COPY in human_occupant.dna.species.species_traits)) + if(!istype(dna) || HAS_TRAIT(mob_occupant, TRAIT_NO_DNA_COPY)) scantemp = "Unable to locate valid genetic data." playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0) return @@ -577,7 +576,7 @@ R.fields["UE"] = dna.unique_enzymes R.fields["UI"] = dna.unique_identity R.fields["SE"] = dna.mutation_index - R.fields["blood_type"] = dna.blood_type + R.fields["blood_type"] = dna.human_blood_type R.fields["features"] = dna.features R.fields["factions"] = mob_occupant.faction R.fields["quirks"] = list() diff --git a/monkestation/code/game/machinery/exp_cloner.dm b/monkestation/code/game/machinery/exp_cloner.dm index 46bb81111d4c..1dd46217facd 100644 --- a/monkestation/code/game/machinery/exp_cloner.dm +++ b/monkestation/code/game/machinery/exp_cloner.dm @@ -404,6 +404,6 @@ temp = "Cloning cycle already in progress." playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, FALSE) else - pod.growclone(mob_occupant.real_name, dna.unique_identity, dna.mutation_index, null, dna.blood_type, clone_species, dna.features, mob_occupant.faction) + pod.growclone(mob_occupant.real_name, dna.unique_identity, dna.mutation_index, null, dna.human_blood_type, clone_species, dna.features, mob_occupant.faction) temp = "[mob_occupant.real_name] => Cloning data sent to pod." playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 50, FALSE) diff --git a/monkestation/code/modules/a_medical_day/internal_bleeding.dm b/monkestation/code/modules/a_medical_day/internal_bleeding.dm new file mode 100644 index 000000000000..aa6db29e32e1 --- /dev/null +++ b/monkestation/code/modules/a_medical_day/internal_bleeding.dm @@ -0,0 +1,49 @@ +/datum/wound_pregen_data/internal_bleeding + abstract = FALSE + wound_path_to_generate = /datum/wound/bleed_internal + ignore_cannot_bleed = FALSE + required_limb_biostate = BIO_BLOODED + required_wounding_types = list(WOUND_BLUNT, WOUND_SLASH, WOUND_PIERCE) + threshold_minimum = 45 + +/datum/wound/bleed_internal + name = "Internal Bleeding" + desc = "The patient is bleeding internally, causing severe pain and difficulty breathing." + treat_text = "Surgical repair of the affected vein is necessary." + treat_text_short = "Surgical repair required." + examine_desc = "" + scar_keyword = "" + severity = WOUND_SEVERITY_MODERATE + simple_treat_text = "Surgery." + homemade_treat_text = "Taking a blood clotting pill may help slow the bleeding, \ + or an iron supplement to help your body recover." + processes = TRUE + wound_flags = NONE + regen_ticks_needed = 120 //around 4 minutes + /// How much blood lost per life tick, gets modified by severity. + var/bleed_amount = 0.25 + /// Cooldown between when the wound can be allowed to worsen + COOLDOWN_DECLARE(worsen_cd) + +/datum/wound/bleed_internal/get_self_check_description(mob/user) + return span_warning("You can see dark bruising.") // same as rib fracture! + +/datum/wound/bleed_internal/handle_process(seconds_per_tick, times_fired) + . = ..() + regen_ticks_current++ + if(!victim || victim.stat == DEAD || HAS_TRAIT(victim, TRAIT_STASIS) || !victim.needs_heart()) + return + victim.bleed(min(bleed_amount * severity * seconds_per_tick, 3)) + +/datum/wound/bleed_internal/wound_injury(datum/wound/old_wound, attack_direction) + COOLDOWN_START(src, worsen_cd, 5 SECONDS) + +/datum/wound/bleed_internal/receive_damage(wounding_type, wounding_dmg, wound_bonus, attack_direction, damage_source) + if(wounding_type == WOUND_BURN || wound_bonus == CANT_WOUND) + return + if(!COOLDOWN_FINISHED(src, worsen_cd)) + return + if(wounding_dmg + wound_bonus + rand(-10, 30) - victim.getarmor(limb, WOUND) < 45) + return + severity = min(severity + 1, WOUND_SEVERITY_CRITICAL) + COOLDOWN_START(src, worsen_cd, 6 SECONDS) diff --git a/monkestation/code/modules/a_medical_day/lungless.dm b/monkestation/code/modules/a_medical_day/lungless.dm new file mode 100644 index 000000000000..3611d366aa00 --- /dev/null +++ b/monkestation/code/modules/a_medical_day/lungless.dm @@ -0,0 +1,30 @@ +/datum/status_effect/lungless + id = "no_lungs" + alert_type = null + duration = -1 + tick_interval = -1 + +/datum/status_effect/lungless/on_apply() + if(!iscarbon(owner)) + return FALSE + var/mob/living/carbon/carbon_owner = owner + if(isnull(carbon_owner.dna?.species?.mutantlungs)) + return FALSE + + RegisterSignal(owner, COMSIG_CARBON_ATTEMPT_BREATHE, PROC_REF(block_breath)) + RegisterSignal(owner, COMSIG_SPECIES_GAIN, PROC_REF(check_new_species)) + return TRUE + +/datum/status_effect/lungless/on_remove() + UnregisterSignal(owner, list(COMSIG_CARBON_ATTEMPT_BREATHE, COMSIG_SPECIES_GAIN)) + +/datum/status_effect/lungless/proc/block_breath(...) + SIGNAL_HANDLER + owner.apply_damage(HUMAN_MAX_OXYLOSS, OXY) + return BREATHE_SKIP_BREATH + +/datum/status_effect/lungless/proc/check_new_species(...) + SIGNAL_HANDLER + var/mob/living/carbon/carbon_owner = owner + if(isnull(carbon_owner.dna?.species?.mutantlungs)) + qdel(src) diff --git a/monkestation/code/modules/a_medical_day/surgery.dm b/monkestation/code/modules/a_medical_day/surgery.dm new file mode 100644 index 000000000000..90ca00ff3327 --- /dev/null +++ b/monkestation/code/modules/a_medical_day/surgery.dm @@ -0,0 +1,121 @@ +/datum/surgery_step/heal/proc/get_perfect_information(mob/user, mob/target) + if(issilicon(user)) + return TRUE + if(user.is_holding_item_of_type(/obj/item/healthanalyzer)) + return TRUE + for(var/obj/machinery/computer/puter in range(2, target)) + if(istype(puter, /obj/machinery/computer/operating)) + var/obj/machinery/computer/operating/op_comp = puter + if(op_comp.table?.patient == target) + return TRUE + if(istype(puter, /obj/machinery/computer/vitals_reader)) + var/obj/machinery/computer/vitals_reader/vr_comp = puter + if(vr_comp.patient == target) + return TRUE + // melbert todo : add modsuit health analyzer to this + return FALSE + +/datum/surgery/repair_broken_rib + name = "Repair fractured rib (hairline)" + surgery_flags = SURGERY_REQUIRE_RESTING | SURGERY_REQUIRE_LIMB | SURGERY_REQUIRES_REAL_LIMB + targetable_wound = /datum/wound/blunt/bone/rib_break + possible_locs = list( + BODY_ZONE_CHEST, + ) + steps = list( + /datum/surgery_step/incise, + /datum/surgery_step/retract_skin, + /datum/surgery_step/clamp_bleeders, + /datum/surgery_step/repair_bone_hairline, + /datum/surgery_step/close, + ) + +/// Repair internal bleeding +/datum/surgery/internal_bleeding + name = "Repair Internal Bleeding" + surgery_flags = SURGERY_REQUIRE_RESTING | SURGERY_REQUIRE_LIMB | SURGERY_REQUIRES_REAL_LIMB + targetable_wound = /datum/wound/bleed_internal + target_mobtypes = list(/mob/living/carbon) + possible_locs = list( + BODY_ZONE_R_ARM, + BODY_ZONE_L_ARM, + BODY_ZONE_R_LEG, + BODY_ZONE_L_LEG, + BODY_ZONE_CHEST, + BODY_ZONE_HEAD, + ) + steps = list( + /datum/surgery_step/incise, + /datum/surgery_step/retract_skin, + /datum/surgery_step/clamp_bleeders, + /datum/surgery_step/repair_veins, + /datum/surgery_step/close, + ) + +/datum/surgery_step/repair_veins + name = "repair arterial bleeding (hemostat/blood filter)" + implements = list( + TOOL_HEMOSTAT = 100, + TOOL_BLOODFILTER = 100, + TOOL_WIRECUTTER = 40, + /obj/item/stack/sticky_tape/surgical = 30, + /obj/item/stack/cable_coil = 10, + /obj/item/stack/sticky_tape = 10, + ) + preop_sound = 'sound/surgery/hemostat1.ogg' + success_sound = 'sound/surgery/organ2.ogg' + time = 6 SECONDS + repeatable = TRUE + pain_amount = 12 + +/datum/surgery_step/repair_veins/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) + var/in_where = "[target]'s [parse_zone(target_zone)]" + display_results( + user, + target, + span_notice("You begin repair the arteries in [in_where]..."), + span_notice("[user] begins to repair the arteries in [in_where] with [tool]."), + span_notice("[user] begins to repair the arteries in [in_where]."), + ) + display_pain( + target, + "You feel a horrible stabbing pain in your [parse_zone(target_zone)]!", + target_zone = target_zone, + ) + +/datum/surgery_step/repair_veins/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) + var/in_where = "[target]'s [parse_zone(target_zone)]" + if((surgery.operated_wound?.severity - 1) <= WOUND_SEVERITY_TRIVIAL) + qdel(surgery.operated_wound) + display_results( + user, + target, + span_green("You've finishes repairing all the arterial damage in [in_where]."), + span_green("[user] finishes repaiing all the arterial damage in [in_where] with [tool]!"), + span_green("[user] finishes repaiing all the arterial damage in [in_where]!"), + ) + repeatable = FALSE + return ..() + + surgery.operated_wound.severity-- + display_results( + user, + target, + span_notice("You successfully repair some of the arteries in [in_where] with [tool]."), + span_notice("[user] successfully repairs some of the arteries in [in_where] with [tool]!"), + span_notice("[user] successfully repairs some of the arteries in [in_where]!"), + ) + target.apply_damage(3, BRUTE, surgery.operated_bodypart, wound_bonus = CANT_WOUND, attacking_item = tool) + return ..() + +/datum/surgery_step/repair_veins/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, fail_prob = 0) + var/in_where = "[target]'s [parse_zone(target_zone)]" + display_results( + user, + target, + span_warning("You tear some of the arteries in [in_where]!"), + span_warning("[user] tears some of the arteries in [in_where] with [tool]!"), + span_warning("[user] tears some of the arteries in [in_where]!"), + ) + target.apply_damage(rand(4, 8), BRUTE, surgery.operated_bodypart, wound_bonus = 10, sharpness = SHARP_EDGED, attacking_item = tool) + return FALSE diff --git a/monkestation/code/modules/a_medical_day/thermics.dm b/monkestation/code/modules/a_medical_day/thermics.dm new file mode 100644 index 000000000000..9c4af98dd405 --- /dev/null +++ b/monkestation/code/modules/a_medical_day/thermics.dm @@ -0,0 +1,94 @@ +/// Hypo and Hyperthermia status effects. +/datum/status_effect/thermia + id = "thermia" + alert_type = null + status_type = STATUS_EFFECT_REPLACE + tick_interval = 3 SECONDS + processing_speed = STATUS_EFFECT_NORMAL_PROCESS + /// Flat penalty of consciousness applied over time + var/consciousness_mod = 0 + var/max_consciousness_mod = 0 + var/datum/weakref/alert_ref + COOLDOWN_DECLARE(update_cd) + +/datum/status_effect/thermia/on_apply() + + give_alert() + COOLDOWN_START(src, update_cd, 6 SECONDS) + return TRUE + +/datum/status_effect/thermia/on_remove() + owner.clear_alert(ALERT_TEMPERATURE) + owner.clear_mood_event(id) + owner.remove_movespeed_modifier(/datum/movespeed_modifier/cold) + +/datum/status_effect/thermia/tick(seconds_between_ticks) + if(!COOLDOWN_FINISHED(src, update_cd)) + return + + owner.adjust_pain_shock(1 * (consciousness_mod * 0.1)) + + COOLDOWN_START(src, update_cd, 9 SECONDS) + +/// Manually applying alerts, rather than using the api for it, becuase we need to apply "severity" argument +/datum/status_effect/thermia/proc/give_alert() + return + +/datum/status_effect/thermia/hypo + var/slowdown_mod + +/datum/status_effect/thermia/hypo/on_creation(mob/living/new_owner, slowdown_mod = 1) + src.slowdown_mod = slowdown_mod + return ..() + +/datum/status_effect/thermia/hypo/on_apply() + . = ..() + owner.add_mood_event(id, /datum/mood_event/cold) + // Apply cold slow down + owner.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/cold, multiplicative_slowdown = slowdown_mod) + +/datum/status_effect/thermia/hypo/one + consciousness_mod = 5 + +/datum/status_effect/thermia/hypo/one/give_alert() + return owner.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 1) + +/datum/status_effect/thermia/hypo/two + consciousness_mod = 10 + +/datum/status_effect/thermia/hypo/two/give_alert() + return owner.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 2) + +/datum/status_effect/thermia/hypo/three + consciousness_mod = 20 + max_consciousness_mod = 30 + +/datum/status_effect/thermia/hypo/three/give_alert() + return owner.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 3) + +/datum/status_effect/thermia/hyper + +/datum/status_effect/thermia/hyper/on_apply() + . = ..() + owner.add_mood_event(id, /datum/mood_event/hot) + //Remove any slowdown from the cold. + owner.remove_movespeed_modifier(/datum/movespeed_modifier/cold) + +/datum/status_effect/thermia/hyper/one + consciousness_mod = 5 + +/datum/status_effect/thermia/hyper/one/give_alert() + return owner.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 1) + +/datum/status_effect/thermia/hyper/two + consciousness_mod = 10 + +/datum/status_effect/thermia/hyper/two/give_alert() + return owner.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 2) + +/datum/status_effect/thermia/hyper/three + consciousness_mod = 20 + max_consciousness_mod = 30 + +/datum/status_effect/thermia/hyper/three/give_alert() + return owner.throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 3) diff --git a/monkestation/code/modules/and_roll_credits/_credits.dm b/monkestation/code/modules/and_roll_credits/_credits.dm new file mode 100644 index 000000000000..de37f7c4d0fe --- /dev/null +++ b/monkestation/code/modules/and_roll_credits/_credits.dm @@ -0,0 +1,179 @@ +#define CREDIT_ROLL_SPEED 9 SECONDS +#define CREDIT_SPAWN_SPEED 1 SECONDS +#define CREDIT_ANIMATE_HEIGHT (16 * world.icon_size) +#define CREDIT_EASE_DURATION 2.2 SECONDS +#define CREDITS_PATH "[global.config.directory]/contributors.dmi" + +/client/proc/RollCredits() + set waitfor = FALSE + if(!fexists(CREDITS_PATH)) + return + LAZYINITLIST(credits) + var/list/_credits = credits + add_verb(src, /client/proc/ClearCredits) + var/static/list/credit_order_for_this_round + if(isnull(credit_order_for_this_round)) + SScredits.draft() + SScredits.finalize() + credit_order_for_this_round = list() + credit_order_for_this_round += SScredits.episode_string + credit_order_for_this_round += SScredits.producers_string + credit_order_for_this_round += SScredits.disclaimers_string + credit_order_for_this_round += SScredits.cast_string + credit_order_for_this_round += "
The Admin Bus
" + var/list/admins = shuffle(SScredits.admin_pref_images) + + var/y_offset = 0 + var/admin_length = length(admins) + for(var/i in 1 to admin_length) + var/x_offset = -40 + for(var/b in 1 to 8) + var/atom/movable/screen/map_view/char_preview/picked = pick_n_take(admins) + if(!picked) + break + picked.pixel_x = x_offset + picked.pixel_y = y_offset + x_offset += 70 + credit_order_for_this_round += picked + + credit_order_for_this_round += "
Our Lovely Contributors
" + var/list/contributors = shuffle(SScredits.contributer_pref_images) + + var/contributors_length = length(contributors) + for(var/i in 1 to contributors_length) + var/x_offset = -40 + for(var/b in 1 to 8) + if(b == 1) + y_offset = 0 + var/atom/movable/screen/map_view/char_preview/picked = pick_n_take(contributors) + if(!picked) + break + picked.pixel_x = x_offset + picked.pixel_y = y_offset + x_offset += 70 + credit_order_for_this_round += picked + + for(var/i in SScredits.major_event_icons) + credit_order_for_this_round += i + var/list/returned_images = SScredits.resolve_clients(SScredits.major_event_icons[i], i) + for(var/y in 1 to length(returned_images)) + var/x_offset = -40 + for(var/b in 1 to 8) + var/atom/movable/screen/map_view/char_preview/client_image = pick_n_take(returned_images) + if(!client_image) + break + client_image.pixel_x = x_offset + client_image.pixel_y = y_offset + x_offset += 70 + credit_order_for_this_round += client_image + + var/count = 0 + for(var/I in credit_order_for_this_round) + if(!credits) + return + if(istype(I, /obj/effect/title_card_object)) //huge image sleep + sleep(CREDIT_SPAWN_SPEED * 3.3) + count = 0 + if(count && !istype(I, /atom/movable/screen/map_view/char_preview)) + sleep(CREDIT_SPAWN_SPEED) + + _credits += new /atom/movable/screen/credit(null, I, src) + if(istype(I, /atom/movable/screen/map_view/char_preview)) + count++ + if(count >= 8) + count = 0 + sleep(CREDIT_SPAWN_SPEED) + if(!istype(I, /atom/movable/screen/map_view/char_preview)) + sleep(CREDIT_SPAWN_SPEED) + count = 0 + sleep(CREDIT_ROLL_SPEED - CREDIT_SPAWN_SPEED) + remove_verb(src, /client/proc/ClearCredits) + +/client/proc/ClearCredits() + set name = "Hide Credits" + set category = "OOC" + remove_verb(src, /client/proc/ClearCredits) + QDEL_LIST(credits) + credits = null + +/atom/movable/screen/credit + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + alpha = 0 + plane = SPLASHSCREEN_PLANE + screen_loc = "3,1" + var/client/parent + var/matrix/target + +/atom/movable/screen/credit/Initialize(mapload, credited, client/P) + . = ..() + icon = CREDITS_PATH + parent = P + var/view = P?.view + var/list/offsets = screen_loc_to_offset("3,1", view) + + if(istype(credited, /atom/movable/screen/map_view/char_preview)) + var/atom/movable/screen/map_view/char_preview/choice = credited + choice.plane = plane + choice.screen_loc = screen_loc + choice.alpha = alpha + maptext_width = choice.maptext_width + maptext = choice.maptext + appearance = choice.appearance + screen_loc = offset_to_screen_loc(offsets[1] + choice.pixel_x, offsets[2] + choice.pixel_y) + add_overlay(choice) + + if(istype(credited, /mutable_appearance)) + var/mutable_appearance/choice = credited + choice.plane = plane + choice.screen_loc = screen_loc + choice.alpha = alpha + maptext_width = choice.maptext_width + maptext = choice.maptext + appearance = choice.appearance + screen_loc = offset_to_screen_loc(offsets[1] + choice.pixel_x, offsets[2] + choice.pixel_y) + add_overlay(choice) + + if(istype(credited, /obj/effect/title_card_object)) + var/obj/effect/title_card_object/choice = credited + choice.plane = plane + choice.screen_loc = screen_loc + choice.alpha = alpha + maptext_width = choice.maptext_width + maptext = choice.maptext + appearance = choice.appearance + screen_loc = offset_to_screen_loc(offsets[1] + choice.pixel_x, offsets[2] + choice.pixel_y) + add_overlay(choice) + + if(istext(credited)) + maptext = MAPTEXT_PIXELLARI(credited) + maptext_x = world.icon_size + 8 + maptext_y = (world.icon_size / 2) - 4 + maptext_width = world.icon_size * 12 + maptext_height = world.icon_size * 2 + + var/matrix/M = matrix(transform) + M.Translate(0, CREDIT_ANIMATE_HEIGHT) + animate(src, transform = M, time = CREDIT_ROLL_SPEED) + target = M + animate(src, alpha = 255, time = CREDIT_EASE_DURATION, flags = ANIMATION_PARALLEL) + addtimer(CALLBACK(src, PROC_REF(FadeOut)), CREDIT_ROLL_SPEED - CREDIT_EASE_DURATION) + QDEL_IN(src, CREDIT_ROLL_SPEED) + if(parent) + parent.screen += src + +/atom/movable/screen/credit/Destroy() + icon = null + if(parent) + parent.screen -= src + LAZYREMOVE(parent.credits, src) + parent = null + return ..() + +/atom/movable/screen/credit/proc/FadeOut() + animate(src, alpha = 0, transform = target, time = CREDIT_EASE_DURATION) + +#undef CREDIT_ANIMATE_HEIGHT +#undef CREDIT_EASE_DURATION +#undef CREDIT_ROLL_SPEED +#undef CREDIT_SPAWN_SPEED +#undef CREDITS_PATH diff --git a/monkestation/code/modules/and_roll_credits/credits_subsystem.dm b/monkestation/code/modules/and_roll_credits/credits_subsystem.dm new file mode 100644 index 000000000000..f3d4360f9ee4 --- /dev/null +++ b/monkestation/code/modules/and_roll_credits/credits_subsystem.dm @@ -0,0 +1,240 @@ +SUBSYSTEM_DEF(credits) + name = "Credits Screen Storage" + flags = SS_NO_FIRE + init_order = INIT_ORDER_CREDITS + + var/director = "Some monkey we found on the street" + var/star = "" + var/ss = "" + var/list/disclaimers = list() + var/list/datum/episode_name/episode_names = list() + + var/episode_name = "" + var/episode_reason = "" + var/producers_string = "" + var/list/episode_string + var/list/disclaimers_string + var/list/cast_string + + //If any of the following five are modified, the episode is considered "not a rerun". + var/customized_name = "" + var/customized_star = "" + var/customized_ss = "" + var/rare_episode_name = FALSE + var/theme = "NT" + + var/js_args = list() + + var/list/contributer_pref_images = list() + var/list/admin_pref_images = list() + var/list/major_event_icons = list() + var/list/contributors = list() + +/datum/controller/subsystem/credits/Initialize() + load_contributors() + generate_pref_images() + return SS_INIT_SUCCESS + +/datum/controller/subsystem/credits/proc/load_contributors() + contributors = list() + var/list/lines = world.file2list("[global.config.directory]/contributors.txt") + for(var/line in lines) + if(!length(line)) + continue + if(findtextEx(line, "#", 1, 2)) + continue + contributors |= line + +/datum/controller/subsystem/credits/proc/draft() + draft_episode_names() + draft_disclaimers() + draft_caststring() + +/datum/controller/subsystem/credits/proc/finalize() + finalize_name() + finalize_episodestring() + finalize_disclaimerstring() + +/datum/controller/subsystem/credits/proc/generate_pref_images() + + for(var/ckey in contributors) + var/datum/client_interface/interface = new(ckey) + var/datum/preferences/mocked = new(interface) + + var/mob/living/carbon/human/dummy/extra_tall/dummy = new + dummy.appearance_flags &= ~TILE_BOUND + + var/atom/movable/screen/map_view/char_preview/appereance = new(null, mocked) + appereance.update_body() + appereance.maptext_width = 120 + appereance.maptext_y = -8 + appereance.maptext_x = -42 + appereance.maptext = "
[ckey]
" + contributer_pref_images += appereance + + for(var/ckey in GLOB.admin_datums) + var/datum/client_interface/interface = new(ckey(ckey)) + var/datum/preferences/mocked = new(interface) + + var/mob/living/carbon/human/dummy/extra_tall/dummy = new + dummy.appearance_flags &= ~TILE_BOUND + + var/atom/movable/screen/map_view/char_preview/appereance = new(null, mocked) + appereance.update_body() + appereance.maptext_width = 120 + appereance.maptext_x = -42 + appereance.maptext_y = -8 + appereance.maptext = "
[ckey]
" + admin_pref_images += appereance + +/datum/controller/subsystem/credits/proc/draft_star() + var/mob/living/carbon/human/most_talked + for(var/mob/living/carbon/human/H in GLOB.player_list) + if(!H.ckey || H.stat == DEAD) + continue + if(!most_talked || H.talkcount > most_talked.talkcount) + most_talked = H + star = thebigstar(most_talked) + + +/datum/controller/subsystem/credits/proc/finalize_name() + if(customized_name) + episode_name = customized_name + return + var/list/drafted_names = list() + var/list/name_reasons = list() + var/list/is_rare_assoc_list = list() + for(var/datum/episode_name/N as anything in episode_names) + drafted_names["[N.thename]"] = N.weight + name_reasons["[N.thename]"] = N.reason + is_rare_assoc_list["[N.thename]"] = N.rare + episode_name = pick_weight(drafted_names) + episode_reason = name_reasons[episode_name] + if(is_rare_assoc_list[episode_name] == TRUE) + rare_episode_name = TRUE + +/datum/controller/subsystem/credits/proc/finalize_episodestring() + var/season = time2text(world.timeofday,"YY") + var/episodenum = GLOB.round_id || 1 + episode_string = list("
SEASON [season] EPISODE [episodenum]
") + episode_string += "
[episode_name]
" + +/datum/controller/subsystem/credits/proc/finalize_disclaimerstring() + disclaimers_string = list() + for(var/disclaimer in disclaimers) + disclaimers_string += "
[disclaimer]
" +/datum/controller/subsystem/credits/proc/draft_disclaimers() + disclaimers += "Filmed on Location at [station_name()].
" + disclaimers += "Filmed with BYOND© cameras and lenses. Outer space footage provided by NASA.
" + disclaimers += "Additional special visual effects by LUMMOX® JR. Motion Picture Productions.
" + disclaimers += "Unofficially Sponsored by The United States Navy.
" + disclaimers += "All rights reserved.
" + disclaimers += "
" + disclaimers += pick("All stunts were performed by underpaid and expendable interns. Do NOT try at home.
", "[director] does not endorse behaviour depicted. Attempt at your own risk.
") + disclaimers += "This motion picture is (not) protected under the copyright laws of the United States and all countries throughout the universe" + disclaimers += "Country of first publication: United States of America." + disclaimers += "Any unauthorized exhibition, distribution, or copying of this picture or any part thereof (including soundtrack)" + disclaimers += "is an infringement of the relevant copyright and will subject the infringer to civil liability and criminal prosecution." + disclaimers += "The story, all names, characters, and incidents portrayed in this production are fictitious." + disclaimers += "No identification with actual persons (living or deceased), places, buildings, and products is intended or should be inferred." + +/datum/controller/subsystem/credits/proc/draft_caststring() + cast_string = list("
CAST:
") + var/cast_num = 0 + for(var/mob/living/carbon/human/H in GLOB.player_list) + if(!H.ckey && !(H.stat == DEAD)) + continue + var/assignment = H.get_assignment(if_no_id = "", if_no_job = "") + cast_string += "
[uppertext(H.mind.key)] as [H.real_name][assignment == "" ? "" : ", [assignment]"]
" + cast_num++ + + for(var/mob/living/silicon/S in GLOB.silicon_mobs) + if(!S.ckey) + continue + cast_string += "
[uppertext(S.mind.key)] as [S.name]
" + cast_num++ + + if(!cast_num) + cast_string += "
Nobody!
" + + var/list/corpses = list() + for(var/mob/living/carbon/human/H in GLOB.dead_mob_list) + if(!H.mind) + continue + if(H.real_name) + corpses += H.real_name + if(corpses.len) + var/true_story_bro = "

[pick("BASED ON","INSPIRED BY","A RE-ENACTMENT OF")] [pick("A TRUE STORY","REAL EVENTS","THE EVENTS ABOARD [uppertext(station_name())]")]
" + cast_string += "

[true_story_bro]


In memory of those that did not make it.
[english_list(corpses)].
" + cast_string += "
" + + +/datum/controller/subsystem/credits/proc/thebigstar(star) + if(istext(star)) + return star + if(ismob(star)) + var/mob/M = star + return "[uppertext(M.mind.key)] as [M.real_name]" + +/datum/controller/subsystem/credits/proc/generate_major_icon(list/mobs, passed_icon_state) + if(!passed_icon_state) + return + var/obj/effect/title_card_object/MA + for(var/obj/effect/title_card_object/effect as anything in major_event_icons) + if(effect.icon_state == passed_icon_state) + MA = effect + break + if(!MA) + MA = new + MA.icon_state = passed_icon_state + MA.pixel_x = 80 + major_event_icons += MA + major_event_icons[MA] = list() + + major_event_icons[MA] |= mobs + +/datum/controller/subsystem/credits/proc/resolve_clients(list/clients, icon_state) + var/list/created_appearances = list() + + //hell + if(icon_state == "cult") + var/datum/team/cult/cult = locate(/datum/team/cult) in GLOB.antagonist_teams + if(cult) + for(var/mob/living/cultist in cult.true_cultists) + if(!cultist.client) + continue + clients |= WEAKREF(cultist.client) + if(icon_state == "revolution") + var/datum/team/revolution/cult = locate(/datum/team/revolution) in GLOB.antagonist_teams + if(cult) + for(var/datum/mind/cultist in (cult.ex_revs + cult.ex_headrevs + cult.members)) + if(!cultist?.current?.client) + continue + clients |= WEAKREF(cultist.current.client) + if(icon_state == "clockcult") + var/datum/team/clock_cult/cult = locate(/datum/team/clock_cult) in GLOB.antagonist_teams + if(cult) + for(var/mob/living/carbon/human/cultist in (cult.human_servants)) + if(!cultist.client) + continue + clients |= WEAKREF(cultist.client) + + for(var/datum/weakref/weak as anything in clients) + var/client/client = weak.resolve() + if(!client) + continue + var/atom/movable/screen/map_view/char_preview/appereance = new(null, client.prefs) + var/mutable_appearance/preview = new(getFlatIcon(client.mob?.appearance)) + appereance.appearance = preview.appearance + appereance.maptext_width = 120 + appereance.maptext_y = -8 + appereance.maptext_x = -42 + appereance.maptext = "
[client.mob.real_name]
" + created_appearances += appereance + return created_appearances + +/mob/living/var/talkcount = 0 + +/obj/effect/title_card_object + plane = SPLASHSCREEN_PLANE + icon = 'monkestation/code/modules/and_roll_credits/icons/title_cards.dmi' diff --git a/monkestation/code/modules/and_roll_credits/episode_names.dm b/monkestation/code/modules/and_roll_credits/episode_names.dm new file mode 100644 index 000000000000..5ec5cc0f99be --- /dev/null +++ b/monkestation/code/modules/and_roll_credits/episode_names.dm @@ -0,0 +1,363 @@ +#define BLACKBOX_FEEDBACK_NUM(key) (SSblackbox.feedback_list[key] ? SSblackbox.feedback_list[key].json["data"] : null) + +/datum/episode_name + var/thename = "" + var/reason = "Nothing particularly of note happened this round to influence the episode name." //Explanation on why this episode name fits this round. For the admin panel. + var/weight = 100 //50 will have 50% the chance of being picked. 200 will have 200% the chance of being picked, etc. Relative to other names, not total (just the default names already total 700%) + var/rare = FALSE //If set to true and this episode name is picked, the current round is considered "not a rerun" for client preferences. + +/datum/episode_name/rare + rare = TRUE + +/datum/episode_name/New(thename, reason, weight) + if(!thename) + return + src.thename = thename + if(reason) + src.reason = reason + if(weight) + src.weight = weight + + switch(rand(1,15)) + if(0 to 5) + thename += ": PART I" + if(6 to 10) + thename += ": PART II" + if(11 to 12) + thename += ": PART III" + if(13) + thename += ": NOW IN 3D" + if(14) + thename += ": ON ICE!" + if(15) + thename += ": THE SEASON FINALE" + +/datum/controller/subsystem/credits/proc/draft_episode_names() + var/uppr_name = uppertext(station_name()) //so we don't run these two 500 times + + episode_names += new /datum/episode_name("THE [pick("DOWNFALL OF", "RISE OF", "TROUBLE WITH", "FINAL STAND OF", "DARK SIDE OF")] [pick(200;"[uppr_name]", 150;"SPACEMEN", 150;"HUMANITY", "DIGNITY", "SANITY", "SCIENCE", "CURIOSITY", "EMPLOYMENT", "PARANOIA", "THE CHIMPANZEES", 50;"THE VENDOMAT PRICES")]") + episode_names += new /datum/episode_name("THE CREW [pick("GOES ON WELFARE", "GIVES BACK", "SELLS OUT", "GETS WHACKED", "SOLVES THE PLASMA CRISIS", "HITS THE ROAD", "RISES", "RETIRES", "GOES TO HELL", "DOES A CLIP SHOW", "GETS AUDITED", "DOES A TV COMMERCIAL", "AFTER HOURS", "GETS A LIFE", "STRIKES BACK", "GOES TOO FAR", "IS 'IN' WITH IT", "WINS... BUT AT WHAT COST?", "INSIDE OUT")]") + episode_names += new /datum/episode_name("THE CREW'S [pick("DAY OUT", "BIG GAY ADVENTURE", "LAST DAY", "[pick("WILD", "WACKY", "LAME", "UNEXPECTED")] VACATION", "CHANGE OF HEART", "NEW GROOVE", "SCHOOL MUSICAL", "HISTORY LESSON", "FLYING CIRCUS", "SMALL PROBLEM", "BIG SCORE", "BLOOPER REEL", "GOT IT", "LITTLE SECRET", "SPECIAL OFFER", "SPECIALTY", "WEAKNESS", "CURIOSITY", "ALIBI", "LEGACY", "BIRTHDAY PARTY", "REVELATION", "ENDGAME", "RESCUE", "PAYBACK")]") + episode_names += new /datum/episode_name("THE CREW GETS [pick("PHYSICAL", "SERIOUS ABOUT [pick("DRUG ABUSE", "CRIME", "PRODUCTIVITY", "ANCIENT AMERICAN CARTOONS", "SPACEBALL")]", "PICKLED", "AN ANAL PROBE", "PIZZA", "NEW WHEELS", "A VALUABLE HISTORY LESSON", "A BREAK", "HIGH", "TO LIVE", "TO RELIVE THEIR CHILDHOOD", "EMBROILED IN CIVIL WAR", "DOWN WITH IT", "FIRED", "BUSY", "THEIR SECOND CHANCE", "TRAPPED", "THEIR REVENGE")]") + episode_names += new /datum/episode_name("[pick("BALANCE OF POWER", "SPACE TRACK", "SEX BOMB", "WHOSE IDEA WAS THIS ANYWAY?", "WHATEVER HAPPENED, HAPPENED", "THE GOOD, THE BAD, AND [uppr_name]", "RESTRAIN YOUR ENJOYMENT", "REAL HOUSEWIVES OF [uppr_name]", "MEANWHILE, ON [uppr_name]...", "CHOOSE YOUR OWN ADVENTURE", "NO PLACE LIKE HOME", "LIGHTS, CAMERA, [uppr_name]!", "50 SHADES OF [uppr_name]", "GOODBYE, [uppr_name]!", "THE SEARCH", \ + "THE CURIOUS CASE OF [uppr_name]", "ONE HELL OF A PARTY", "FOR YOUR CONSIDERATION", "PRESS YOUR LUCK", "A STATION CALLED [uppr_name]", "CRIME AND PUNISHMENT", "MY DINNER WITH [uppr_name]", "UNFINISHED BUSINESS", "THE ONLY STATION THAT'S NOT ON FIRE (YET)", "SOMEONE'S GOTTA DO IT", "THE [uppr_name] MIX-UP", "PILOT", "PROLOGUE", "FINALE", "UNTITLED", "THE END")]") + episode_names += new /datum/episode_name("[pick("SPACE", "SEXY", "DRAGON", "WARLOCK", "LAUNDRY", "GUN", "ADVERTISING", "DOG", "CARBON MONOXIDE", "NINJA", "WIZARD", "SOCRATIC", "JUVENILE DELIQUENCY", "POLITICALLY MOTIVATED", "RADTACULAR SICKNASTY", "CORPORATE", "MEGA")] [pick("QUEST", "FORCE", "ADVENTURE")]", weight=25) + + switch(GLOB.start_state.score(SSticker.end_state)) + if(-INFINITY to -2000) + episode_names += new /datum/episode_name("[pick("THE CREW'S PUNISHMENT", "A PUBLIC RELATIONS NIGHTMARE", "[uppr_name]: A NATIONAL CONCERN", "WITH APOLOGIES TO THE CREW", "THE CREW BITES THE DUST", "THE CREW BLOWS IT", "THE CREW GIVES UP THE DREAM", "THE CREW IS DONE FOR", "THE CREW SHOULD NOT BE ALLOWED ON TV", "THE END OF [uppr_name] AS WE KNOW IT")]", "Extremely low score of [GLOB.start_state.score(SSticker.end_state)].", 250) + if(4500 to INFINITY) + episode_names += new /datum/episode_name("[pick("THE CREW'S DAY OUT", "THIS SIDE OF PARADISE", "[uppr_name]: A SITUATION COMEDY", "THE CREW'S LUNCH BREAK", "THE CREW'S BACK IN BUSINESS", "THE CREW'S BIG BREAK", "THE CREW SAVES THE DAY", "THE CREW RULES THE WORLD", "THE ONE WITH ALL THE SCIENCE AND PROGRESS AND PROMOTIONS AND ALL THE COOL AND GOOD THINGS", "THE TURNING POINT")]", "High score of [GLOB.start_state.score(SSticker.end_state)].", 250) + + if(istype(SSticker.mode, /datum/game_mode/dynamic)) + var/list/ran_events = SSgamemode.triggered_round_events.Copy() + switch(rand(1, 100)) + if(0 to 35) + episode_names += new /datum/episode_name("[pick("THE DAY [uppr_name] STOOD STILL", "MUCH ADO ABOUT NOTHING", "WHERE SILENCE HAS LEASE", "RED HERRING", "HOME ALONE", "GO BIG OR GO [uppr_name]", "PLACEBO EFFECT", "ECHOES", "SILENT PARTNERS", "WITH FRIENDS LIKE THESE...", "EYE OF THE STORM", "BORN TO BE MILD", "STILL WATERS")]", "Low threat level.", 150) + if(GLOB.start_state.score(SSticker.end_state) < -1000) + episode_names += new /datum/episode_name/rare("[pick("HOW OH HOW DID IT ALL GO SO WRONG?!", "EXPLAIN THIS ONE TO THE EXECUTIVES", "THE CREW GOES ON SAFARI", "OUR GREATEST ENEMY", "THE INSIDE JOB", "MURDER BY PROXY")]", "Low threat levels... but the crew still had a very low score.", GLOB.start_state.score(SSticker.end_state)/150*-2) + if(35 to 60) + episode_names += new /datum/episode_name("[pick("THERE MIGHT BE BLOOD", "IT CAME FROM [uppr_name]!", "THE [uppr_name] INCIDENT", "THE ENEMY WITHIN", "MIDDAY MADNESS", "AS THE CLOCK STRIKES TWELVE", "CONFIDENCE AND PARANOIA", "THE PRANK THAT WENT WAY TOO FAR", "A HOUSE DIVIDED", "[uppr_name] TO THE RESCUE!", "ESCAPE FROM [uppr_name]", \ + "HIT AND RUN", "THE AWAKENING", "THE GREAT ESCAPE", "THE LAST TEMPTATION OF [uppr_name]", "[uppr_name]'S FALL FROM GRACE", "BETTER THE [uppr_name] YOU KNOW...", "PLAYING WITH FIRE", "UNDER PRESSURE", "THE DAY BEFORE THE DEADLINE", "[uppr_name]'S MOST WANTED", "THE BALLAD OF [uppr_name]")]", "Moderate threat level", 150) + if(60 to 100) + episode_names += new /datum/episode_name("[pick("ATTACK! ATTACK! ATTACK!", "CAN'T FIX CRAZY", "APOCALYPSE [pick("N", "W", "H")]OW", "A TASTE OF ARMAGEDDON", "OPERATION: ANNIHILATE!", "THE PERFECT STORM", "TIME'S UP FOR THE CREW", "A TOTALLY FUN THING THAT THE CREW WILL NEVER DO AGAIN", "EVERYBODY HATES [uppr_name]", "BATTLE OF [uppr_name]", \ + "THE SHOWDOWN", "MANHUNT", "THE ONE WITH ALL THE FIGHTING", "THE RECKONING OF [uppr_name]", "THERE GOES THE NEIGHBORHOOD", "THE THIN RED LINE", "ONE DAY FROM RETIREMENT")]", "High threat levels.", 250) + if(get_station_avg_temp() < T0C) + episode_names += new /datum/episode_name/rare("[pick("THE OPPORTUNITY OF A LIFETIME", "DRASTIC MEASURES", "DEUS EX", "THE SHOW MUST GO ON", "TRIAL BY FIRE", "A STITCH IN TIME", "ALL'S FAIR IN LOVE AND WAR", "COME HELL OR HIGH HEAVEN", "REVERSAL OF FORTUNE", "DOUBLE TOIL AND DOUBLE TROUBLE")]") + episode_names += new /datum/episode_name/rare("A COLD DAY IN HELL", "Station temperature was below 0C this round and threat was high", 1000) + if(locate(/datum/round_event_control/antagonist/solo/malf) in ran_events) + episode_names += new /datum/episode_name/rare("[pick("I'M SORRY [uppr_name], I'M AFRAID I CAN'T LET YOU DO THAT", "A STRANGE GAME", "THE AI GOES ROGUE", "RISE OF THE MACHINES")]", "Round included a malfunctioning AI.", 300) + if(locate(/datum/round_event_control/antagonist/solo/revolutionary) in ran_events) + episode_names += new /datum/episode_name/rare("[pick("THE CREW STARTS A REVOLUTION", "HELL IS OTHER SPESSMEN", "INSURRECTION", "THE CREW RISES UP", 25;"FUN WITH FRIENDS")]", "Round included roundstart revs.", 350) + if(copytext(uppr_name,1,2) == "V") + episode_names += new /datum/episode_name/rare("V FOR [uppr_name]", "Round included roundstart revs... and the station's name starts with V.", 1500) + if(locate(/datum/round_event_control/blob) in ran_events) + episode_names += new /datum/episode_name/rare("[pick("MARRIED TO THE BLOB", "THE CREW GETS QUARANTINED")]", "Round included a roundstart blob.", 350) + + if(BLACKBOX_FEEDBACK_NUM("narsies_spawned") > 0) + episode_names += new /datum/episode_name/rare("[pick("NAR-SIE'S DAY OUT", "NAR-SIE'S VACATION", "THE CREW LEARNS ABOUT SACRED GEOMETRY", "REALM OF THE MAD GOD", "THE ONE WITH THE ELDRITCH HORROR", 50;"STUDY HARD, BUT PART-SIE HARDER")]", "Nar-Sie is loose!", 500) + if(check_holidays(CHRISTMAS)) + episode_names += new /datum/episode_name("A VERY [pick("NANOTRASEN", "EXPEDITIONARY", "SECURE", "PLASMA", "MARTIAN")] CHRISTMAS", "'Tis the season.", 1000) + if(BLACKBOX_FEEDBACK_NUM("guns_spawned") > 0) + episode_names += new /datum/episode_name/rare("[pick("GUNS, GUNS EVERYWHERE", "THUNDER GUN EXPRESS", "THE CREW GOES AMERICA ALL OVER EVERYBODY'S ASS")]", "[BLACKBOX_FEEDBACK_NUM("guns_spawned")] guns were spawned this round.", min(750, BLACKBOX_FEEDBACK_NUM("guns_spawned")*25)) + if(BLACKBOX_FEEDBACK_NUM("heartattacks") > 2) + episode_names += new /datum/episode_name/rare("MY HEART WILL GO ON", "[BLACKBOX_FEEDBACK_NUM("heartattacks")] hearts were reanimated and burst out of someone's chest this round.", min(1500, BLACKBOX_FEEDBACK_NUM("heartattacks")*250)) + + var/datum/bank_account/mr_moneybags + var/static/list/typecache_bank = typecacheof(list(/datum/bank_account/department, /datum/bank_account/remote)) + for(var/i in SSeconomy.bank_accounts_by_id) + var/datum/bank_account/current_acc = SSeconomy.bank_accounts_by_id[i] + if(typecache_bank[current_acc.type]) + continue + if(!mr_moneybags || mr_moneybags.account_balance < current_acc.account_balance) + mr_moneybags = current_acc + + if(mr_moneybags && mr_moneybags.account_balance > 30000) + episode_names += new /datum/episode_name/rare("[pick("WAY OF THE WALLET", "THE IRRESISTIBLE RISE OF [uppertext(mr_moneybags.account_holder)]", "PRETTY PENNY", "IT'S THE ECONOMY, STUPID")]", "Scrooge Mc[mr_moneybags.account_holder] racked up [mr_moneybags.account_balance] credits this round.", min(450, mr_moneybags.account_balance/500)) + if(BLACKBOX_FEEDBACK_NUM("ai_deaths") > 3) + episode_names += new /datum/episode_name/rare("THE ONE WHERE [BLACKBOX_FEEDBACK_NUM("ai_deaths")] AIS DIE", "That's a lot of dead AIs.", min(1500, BLACKBOX_FEEDBACK_NUM("ai_deaths")*300)) + if(BLACKBOX_FEEDBACK_NUM("law_changes") > 12) + episode_names += new /datum/episode_name/rare("[pick("THE CREW LEARNS ABOUT LAWSETS", 15;"THE UPLOAD RAILROAD", 15;"FREEFORM", 15;"ASIMOV SAYS")]", "There were [BLACKBOX_FEEDBACK_NUM("law_changes")] law changes this round.", min(750, BLACKBOX_FEEDBACK_NUM("law_changes")*25)) + if(BLACKBOX_FEEDBACK_NUM("slips") > 50) + episode_names += new /datum/episode_name/rare("THE CREW GOES BANANAS", "People slipped [BLACKBOX_FEEDBACK_NUM("slips")] times this round.", min(500, BLACKBOX_FEEDBACK_NUM("slips")/2)) + + if(BLACKBOX_FEEDBACK_NUM("turfs_singulod") > 200) + episode_names += new /datum/episode_name/rare("[pick("THE SINGULARITY GETS LOOSE", "THE SINGULARITY GETS LOOSE (AGAIN)", "CONTAINMENT FAILURE", "THE GOOSE IS LOOSE", 50;"THE CREW'S ENGINE SUCKS", 50;"THE CREW GOES DOWN THE DRAIN")]", "The Singularity ate [BLACKBOX_FEEDBACK_NUM("turfs_singulod")] turfs this round.", min(1000, BLACKBOX_FEEDBACK_NUM("turfs_singulod")/2)) //no "singularity's day out" please we already have enough + if(BLACKBOX_FEEDBACK_NUM("spacevines_grown") > 150) + episode_names += new /datum/episode_name/rare("[pick("REAP WHAT YOU SOW", "OUT OF THE WOODS", "SEEDY BUSINESS", "[uppr_name] AND THE BEANSTALK", "IN THE GARDEN OF EDEN")]", "[BLACKBOX_FEEDBACK_NUM("spacevines_grown")] tiles worth of Kudzu were grown in total this round.", min(1500, BLACKBOX_FEEDBACK_NUM("spacevines_grown")*2)) + if(BLACKBOX_FEEDBACK_NUM("devastating_booms") >= 6) + episode_names += new /datum/episode_name/rare("THE CREW HAS A BLAST", "[BLACKBOX_FEEDBACK_NUM("devastating_booms")] large explosions happened this round.", min(1000, BLACKBOX_FEEDBACK_NUM("devastating_booms")*100)) + + if(!EMERGENCY_ESCAPED_OR_ENDGAMED) + return + + var/dead = GLOB.joined_player_list.len - SSticker.popcount[POPCOUNT_ESCAPEES] + var/escaped = SSticker.popcount[POPCOUNT_ESCAPEES] + var/human_escapees = SSticker.popcount[POPCOUNT_ESCAPEES_HUMANONLY] + if(dead == 0) + episode_names += new /datum/episode_name/rare("[pick("EMPLOYEE TRANSFER", "LIVE LONG AND PROSPER", "PEACE AND QUIET IN [uppr_name]", "THE ONE WITHOUT ALL THE FIGHTING")]", "No-one died this round.", 2500) //in practice, this one is very very very rare, so if it happens let's pick it more often + if(escaped == 0 || SSshuttle.emergency.is_hijacked()) + episode_names += new /datum/episode_name("[pick("DEAD SPACE", "THE CREW GOES MISSING", "LOST IN TRANSLATION", "[uppr_name]: DELETED SCENES", "WHAT HAPPENS IN [uppr_name], STAYS IN [uppr_name]", "MISSING IN ACTION", "SCOOBY-DOO, WHERE'S THE CREW?")]", "There were no escapees on the shuttle.", 300) + if(escaped < 6 && escaped > 0 && dead > escaped*2) + episode_names += new /datum/episode_name("[pick("AND THEN THERE WERE FEWER", "THE 'FUN' IN 'FUNERAL'", "FREEDOM RIDE OR DIE", "THINGS WE LOST IN [uppr_name]", "GONE WITH [uppr_name]", "LAST TANGO IN [uppr_name]", "GET BUSY LIVING OR GET BUSY DYING", "THE CREW FUCKING DIES", "WISH YOU WERE HERE")]", "[dead] people died this round.", 400) + + var/clowncount = 0 + var/mimecount = 0 + var/assistantcount = 0 + var/chefcount = 0 + var/chaplaincount = 0 + var/lawyercount = 0 + var/minercount = 0 + var/baldycount = 0 + var/horsecount = 0 + for(var/mob/living/carbon/human/H as anything in SSticker.popcount["human_escapees_list"]) + if(HAS_TRAIT(H, TRAIT_MIMING)) + mimecount++ + if(H.is_wearing_item_of_type(list(/obj/item/clothing/mask/gas/clown_hat, /obj/item/clothing/mask/gas/sexyclown)) || (H.mind && H.mind.assigned_role.title == "Clown")) + clowncount++ + if(H.is_wearing_item_of_type(/obj/item/clothing/under/color/grey) || (H.mind && H.mind.assigned_role.title == "Assistant")) + assistantcount++ + if(H.is_wearing_item_of_type(/obj/item/clothing/head/utility/chefhat) || (H.mind && H.mind.assigned_role.title == "Chef")) + chefcount++ + if(H.is_wearing_item_of_type(/obj/item/clothing/under/rank/civilian/lawyer)) + lawyercount++ + if(H.mind && H.mind.assigned_role.title == "Shaft Miner") + minercount++ + /* + if(H.mind && H.mind.assigned_role.title == "Chaplain") + chaplaincount++ + if(IS_CHANGELING(H)) + episode_names += new /datum/episode_name/rare("[uppertext(H.real_name)]: A BLESSING IN DISGUISE", "The Chaplain, [H.real_name], was a changeling and escaped alive.", 750) + */ + if(H.dna.species.type == /datum/species/human && (H.hairstyle == "Bald" || H.hairstyle == "Skinhead") && !(BODY_ZONE_HEAD in H.get_covered_body_zones())) + baldycount++ + if(H.is_wearing_item_of_type(/obj/item/clothing/mask/animal/horsehead)) + horsecount++ + + if(clowncount > 2) + episode_names += new /datum/episode_name/rare("CLOWNS GALORE", "There were [clowncount] clowns on the shuttle.", min(1500, clowncount*250)) + theme = "clown" + if(mimecount > 2) + episode_names += new /datum/episode_name/rare("THE SILENT SHUFFLE", "There were [mimecount] mimes on the shuttle.", min(1500, mimecount*250)) + if(chaplaincount > 2) + episode_names += new /datum/episode_name/rare("COUNT YOUR BLESSINGS", "There were [chaplaincount] chaplains on the shuttle. Like, the real deal, not just clothes.", min(1500, chaplaincount*450)) + if(chefcount > 2) + episode_names += new /datum/episode_name/rare("Too Many Cooks", "There were [chefcount] chefs on the shuttle.", min(1500, chefcount*450)) //intentionally not capitalized, as the theme will customize it + theme = "cooks" + + if(human_escapees) + if(assistantcount / human_escapees > 0.6 && human_escapees > 3) + episode_names += new /datum/episode_name/rare("[pick("GREY GOO", "RISE OF THE GREYTIDE")]", "Most of the survivors were Assistants, or at least dressed like one.", min(1500, assistantcount*200)) + + if(baldycount / human_escapees > 0.6 && SSshuttle.emergency.launch_status == EARLY_LAUNCHED) + episode_names += new /datum/episode_name/rare("TO BALDLY GO", "Most of the survivors were bald, and it shows.", min(1500, baldycount*250)) + if(horsecount / human_escapees > 0.6 && human_escapees> 3) + episode_names += new /datum/episode_name/rare("STRAIGHT FROM THE HORSE'S MOUTH", "Most of the survivors wore horse heads.", min(1500, horsecount*250)) + + if(human_escapees == 1) + var/mob/living/carbon/human/H = SSticker.popcount["human_escapees_list"][1] + + if(IS_TRAITOR(H) || IS_NUKE_OP(H)) + theme = "syndie" + if(H.stat == CONSCIOUS && H.mind && H.mind.assigned_role.title) + switch(H.mind.assigned_role.title) + if("Chef") + var/chance = 250 + if(H.is_wearing_item_of_type(/obj/item/clothing/head/utility/chefhat)) + chance += 500 + if(H.is_wearing_item_of_type(/obj/item/clothing/suit/toggle/chef)) + chance += 500 + if(H.is_wearing_item_of_type(/obj/item/clothing/under/rank/civilian/chef)) + chance += 250 + episode_names += new /datum/episode_name/rare("HAIL TO THE CHEF", "The Chef was the only survivor in the shuttle.", chance) + if("Clown") + var/chance = 250 + if(H.is_wearing_item_of_type(/obj/item/clothing/mask/gas/clown_hat)) + chance += 500 + if(H.is_wearing_item_of_type(list(/obj/item/clothing/shoes/clown_shoes, /obj/item/clothing/shoes/clown_shoes/jester))) + chance += 500 + if(H.is_wearing_item_of_type(list(/obj/item/clothing/under/rank/civilian/clown, /obj/item/clothing/under/rank/civilian/clown/jester))) + chance += 250 + episode_names += new /datum/episode_name/rare("[pick("COME HELL OR HIGH HONKER", "THE LAST LAUGH")]", "The Clown was the only survivor in the shuttle.", chance) + theme = "clown" + if("Detective") + var/chance = 250 + if(H.is_wearing_item_of_type(/obj/item/storage/belt/holster/detective)) + chance += 1000 + if(H.is_wearing_item_of_type(/obj/item/clothing/head/fedora/det_hat)) + chance += 500 + if(H.is_wearing_item_of_type(/obj/item/clothing/suit/jacket/det_suit)) + chance += 500 + if(H.is_wearing_item_of_type(/obj/item/clothing/under/rank/security/detective)) + chance += 250 + episode_names += new /datum/episode_name/rare("[uppertext(H.real_name)]: LOOSE CANNON", "The Detective was the only survivor in the shuttle.", chance) + if("Shaft Miner") + var/chance = 250 + if(H.is_wearing_item_of_type(/obj/item/pickaxe)) + chance += 1000 + if(H.is_wearing_item_of_type(/obj/item/storage/backpack/explorer)) + chance += 500 + if(H.is_wearing_item_of_type(/obj/item/clothing/suit/hooded/explorer)) + chance += 250 + episode_names += new /datum/episode_name/rare("[pick("YOU KNOW THE DRILL", "CAN YOU DIG IT?", "JOURNEY TO THE CENTER OF THE ASTEROI", "CAVE STORY", "QUARRY ON")]", "The Miner was the only survivor in the shuttle.", chance) + if("Librarian") + var/chance = 750 + if(H.is_wearing_item_of_type(/obj/item/book)) + chance += 1000 + episode_names += new /datum/episode_name/rare("COOKING THE BOOKS", "The Librarian was the only survivor in the shuttle.", chance) + if("Chemist") + var/chance = 1000 + if(H.is_wearing_item_of_type(/obj/item/clothing/suit/toggle/labcoat/chemist)) + chance += 500 + if(H.is_wearing_item_of_type(/obj/item/clothing/under/rank/medical/chemist)) + chance += 250 + episode_names += new /datum/episode_name/rare("A BITTER PILL TO SWALLOW", "The Chemist was the only survivor in the shuttle.", chance) + if("Chaplain") //We don't check for uniform here because the chaplain's thing kind of is to improvise their garment gimmick + episode_names += new /datum/episode_name/rare("BLESS THIS MESS", "The Chaplain was the only survivor in the shuttle.", 1250) + + if(H.is_wearing_item_of_type(/obj/item/clothing/mask/luchador) && H.is_wearing_item_of_type(/obj/item/clothing/gloves/boxing)) + episode_names += new /datum/episode_name/rare("[pick("THE CREW, ON THE ROPES", "THE CREW, DOWN FOR THE COUNT", "[uppr_name], DOWN AND OUT")]", "The only survivor in the shuttle wore a luchador mask and boxing gloves.", 1500) + + if(human_escapees == 2) + if(lawyercount == 2) + episode_names += new /datum/episode_name/rare("DOUBLE JEOPARDY", "The only two survivors were IAAs or lawyers.", 2500) + if(chefcount == 2) + episode_names += new /datum/episode_name/rare("CHEF WARS", "The only two survivors were chefs.", 2500) + if(minercount == 2) + episode_names += new /datum/episode_name/rare("THE DOUBLE DIGGERS", "The only two survivors were miners.", 2500) + if(clowncount == 2) + episode_names += new /datum/episode_name/rare("A TALE OF TWO CLOWNS", "The only two survivors were clowns.", 2500) + theme = "clown" + if(clowncount == 1 && mimecount == 1) + episode_names += new /datum/episode_name/rare("THE DYNAMIC DUO", "The only two survivors were the Clown, and the Mime.", 2500) + + else + //more than 0 human escapees + var/braindamage_total = 0 + var/all_braindamaged = TRUE + for(var/mob/living/carbon/human/H as anything in SSticker.popcount["human_escapees_list"]) + var/obj/item/organ/internal/brain/hbrain = H.get_organ_slot(ORGAN_SLOT_BRAIN) + if(hbrain.damage < 60) + all_braindamaged = FALSE + braindamage_total += hbrain.damage + var/average_braindamage = braindamage_total / human_escapees + if(average_braindamage > 30) + episode_names += new /datum/episode_name/rare("[pick("THE CREW'S SMALL IQ PROBLEM", "OW! MY BALLS", "BR[pick("AI", "IA")]N DAM[pick("AGE", "GE", "AG")]", "THE VERY SPECIAL CREW OF [uppr_name]")]", "Average of [average_braindamage] brain damage for each human shuttle escapee.", min(1000, average_braindamage*10)) + if(all_braindamaged && human_escapees > 2) + episode_names += new /datum/episode_name/rare("...AND PRAY THERE'S INTELLIGENT LIFE SOMEWHERE OUT IN SPACE, 'CAUSE THERE'S BUGGER ALL DOWN HERE IN [uppr_name]", "Everyone was braindamaged this round.", human_escapees * 500) + +/proc/get_station_avg_temp() + var/avg_temp = 0 + var/avg_divide = 0 + for(var/obj/machinery/airalarm/alarm in GLOB.machines) + var/turf/location = alarm.loc + if(!istype(location) || !is_station_level(alarm.z)) + continue + var/datum/gas_mixture/environment = location.return_air() + if(!environment) + continue + avg_temp += environment.temperature + avg_divide++ + + if(avg_divide) + return avg_temp / avg_divide + return T0C + + +///Bruteforce check for any type or subtype of an item. +/mob/living/carbon/human/proc/is_wearing_item_of_type(type2check) + var/found + var/list/my_items = get_all_worn_items() + if(islist(type2check)) + for(var/type_iterator in type2check) + found = locate(type_iterator) in my_items + if(found) + return found + else + found = locate(type2check) in my_items + return found + + +/mob/living/carbon/human/get_slot_by_item(obj/item/looking_for) + if(looking_for == belt) + return ITEM_SLOT_BELT + + if(looking_for == wear_id) + return ITEM_SLOT_ID + + if(looking_for == ears) + return ITEM_SLOT_EARS + + if(looking_for == glasses) + return ITEM_SLOT_EYES + + if(looking_for == gloves) + return ITEM_SLOT_GLOVES + + if(looking_for == head) + return ITEM_SLOT_HEAD + + if(looking_for == shoes) + return ITEM_SLOT_FEET + + if(looking_for == wear_suit) + return ITEM_SLOT_OCLOTHING + + if(looking_for == w_uniform) + return ITEM_SLOT_ICLOTHING + + if(looking_for == r_store) + return ITEM_SLOT_RPOCKET + + if(looking_for == l_store) + return ITEM_SLOT_LPOCKET + + if(looking_for == s_store) + return ITEM_SLOT_SUITSTORE + + return ..() + + +/mob/living/carbon/get_slot_by_item(obj/item/looking_for) + if(looking_for == back) + return ITEM_SLOT_BACK + + if(back && (looking_for in back)) + return ITEM_SLOT_BACKPACK + + if(looking_for == wear_mask) + return ITEM_SLOT_MASK + + if(looking_for == wear_neck) + return ITEM_SLOT_NECK + + if(looking_for == head) + return ITEM_SLOT_HEAD + + if(looking_for == handcuffed) + return ITEM_SLOT_HANDCUFFED + + if(looking_for == legcuffed) + return ITEM_SLOT_LEGCUFFED + + return ..() diff --git a/monkestation/code/modules/and_roll_credits/icons/title_cards.dmi b/monkestation/code/modules/and_roll_credits/icons/title_cards.dmi new file mode 100644 index 000000000000..9191e1539594 Binary files /dev/null and b/monkestation/code/modules/and_roll_credits/icons/title_cards.dmi differ diff --git a/monkestation/code/modules/antagonists/abductor/equipment/glands/blood.dm b/monkestation/code/modules/antagonists/abductor/equipment/glands/blood.dm deleted file mode 100644 index 7af70ab4eb7f..000000000000 --- a/monkestation/code/modules/antagonists/abductor/equipment/glands/blood.dm +++ /dev/null @@ -1,15 +0,0 @@ -/obj/item/organ/internal/heart/gland/blood - /// The mob's original blood type, to be reverted to when the organ is removed. - var/original_blood_type - -/obj/item/organ/internal/heart/gland/blood/on_insert(mob/living/carbon/human/organ_owner, special) - . = ..() - if(!ishuman(owner) || !owner.dna.species) - return - original_blood_type = owner.dna.species.exotic_blood - -/obj/item/organ/internal/heart/gland/blood/on_remove(mob/living/carbon/human/organ_owner, special) - . = ..() - if(!ishuman(owner) || !owner.dna.species) - return - owner.dna.species.exotic_blood = original_blood_type diff --git a/monkestation/code/modules/antagonists/borers/code/mobs/cortical_borer.dm b/monkestation/code/modules/antagonists/borers/code/mobs/cortical_borer.dm index 590317db46d4..3ebfa95db0ee 100644 --- a/monkestation/code/modules/antagonists/borers/code/mobs/cortical_borer.dm +++ b/monkestation/code/modules/antagonists/borers/code/mobs/cortical_borer.dm @@ -415,7 +415,7 @@ GLOBAL_LIST_INIT(borer_second_name, world.file2list("monkestation/code/modules/a /mob/living/basic/cortical_borer/handle_environment(datum/gas_mixture/environment, seconds_per_tick, times_fired) var/loc_temp if(human_host) - loc_temp = human_host.coretemperature // set the local temp to that of the host's core temp + loc_temp = human_host.bodytemperature // set the local temp to that of the host's core temp else loc_temp = get_temperature(environment) var/temp_delta = loc_temp - bodytemperature @@ -426,9 +426,9 @@ GLOBAL_LIST_INIT(borer_second_name, world.file2list("monkestation/code/modules/a if(temp_delta < 0) // it is cold here if(!on_fire) // do not reduce body temp when on fire - adjust_bodytemperature(max(max(temp_delta / BODYTEMP_DIVISOR, BODYTEMP_COOLING_MAX) * seconds_per_tick, temp_delta)) + adjust_bodytemperature(max(max(temp_delta / BODYTEMP_DIVISOR, BODYTEMP_HOMEOSTASIS_COOLING_MAX) * seconds_per_tick, temp_delta)) else // this is a hot place - adjust_bodytemperature(min(min(temp_delta / BODYTEMP_DIVISOR, BODYTEMP_HEATING_MAX) * seconds_per_tick, temp_delta)) + adjust_bodytemperature(min(min(temp_delta / BODYTEMP_DIVISOR, BODYTEMP_HOMEOSTASIS_HEATING_MAX) * seconds_per_tick, temp_delta)) //leave the host, forced or not /mob/living/basic/cortical_borer/proc/leave_host() diff --git a/monkestation/code/modules/antagonists/clock_cult/items/clothing.dm b/monkestation/code/modules/antagonists/clock_cult/items/clothing.dm index 43bd5f81b27e..ced2a2f676bc 100644 --- a/monkestation/code/modules/antagonists/clock_cult/items/clothing.dm +++ b/monkestation/code/modules/antagonists/clock_cult/items/clothing.dm @@ -514,9 +514,9 @@ icon_state = "clockwork_gauntlets" siemens_coefficient = 0 strip_delay = 8 SECONDS - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = FIRE_PROOF | ACID_PROOF armor_type = /datum/armor/gloves_clockwork diff --git a/monkestation/code/modules/antagonists/clock_cult/mobs/clockwork_golem.dm b/monkestation/code/modules/antagonists/clock_cult/mobs/clockwork_golem.dm index 4e9507d438eb..889d8f97d806 100644 --- a/monkestation/code/modules/antagonists/clock_cult/mobs/clockwork_golem.dm +++ b/monkestation/code/modules/antagonists/clock_cult/mobs/clockwork_golem.dm @@ -9,7 +9,6 @@ special_names = null examine_limb_id = SPECIES_GOLEM armor = 70 - speedmod = 0.2 ///ref to our turf_healing component, used for deletion on_species_loss() var/datum/component/turf_healing/mob_turf_healing diff --git a/monkestation/code/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm b/monkestation/code/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm index bb1e08ca1ba1..ca83e7193259 100644 --- a/monkestation/code/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm +++ b/monkestation/code/modules/antagonists/clock_cult/mobs/clockwork_marauder.dm @@ -26,7 +26,7 @@ GLOBAL_LIST_EMPTY(clockwork_marauders) mob_size = MOB_SIZE_LARGE move_resist = MOVE_FORCE_OVERPOWERING unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 + bodytemp_cold_damage_limit = -1 obj_damage = 80 faction = list(FACTION_CLOCK) damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) diff --git a/monkestation/code/modules/antagonists/clock_cult/mobs/eminence.dm b/monkestation/code/modules/antagonists/clock_cult/mobs/eminence.dm index 97621c5ea2c1..2623a847aabd 100644 --- a/monkestation/code/modules/antagonists/clock_cult/mobs/eminence.dm +++ b/monkestation/code/modules/antagonists/clock_cult/mobs/eminence.dm @@ -117,7 +117,7 @@ GLOBAL_DATUM(current_eminence, /mob/living/eminence) //set to the current eminen return FALSE . = ..() -/mob/living/eminence/gib(no_brain, no_organs, no_bodyparts) +/mob/living/eminence/gib(no_brain, no_organs, no_bodyparts, safe_gib = TRUE) return //eminence_act() stuff, might be a better way to do this diff --git a/monkestation/code/modules/blood_datum/blood.dm b/monkestation/code/modules/blood_datum/blood.dm new file mode 100644 index 000000000000..4a7e7fb8476e --- /dev/null +++ b/monkestation/code/modules/blood_datum/blood.dm @@ -0,0 +1,338 @@ +/// Global list of all blood type singletons (Assoc [type] - [/datum/blood_type singleton]) +GLOBAL_LIST_INIT_TYPED(blood_types, /datum/blood_type, init_subtypes_w_path_keys(/datum/blood_type)) + +/** + * Blood Drying SS + * + * Used as a low priority backround system to handling the drying of blood on the ground + */ +PROCESSING_SUBSYSTEM_DEF(blood_drying) + name = "Blood Drying" + flags = SS_NO_INIT | SS_BACKGROUND + priority = 10 + wait = 10 SECONDS + +/// Takes the name of a blood type and return the typepath +/proc/blood_name_to_blood_type(name) + for(var/datum/blood_type/blood_type as anything in GLOB.blood_types) + if(blood_type.name == name) + return blood_type.type + return null + +/** + * Blood Types + * + * Singleton datums which represent, well, blood inside someone + */ +/datum/blood_type + /// The short-hand name of the blood type + var/name = "?" + /// What color is blood decals spawned of this type + var/color = COLOR_BLOOD + ///do we glow + var/glows = FALSE + /// What blood types can this type receive from + /// Itself is always included in this list + var/list/compatible_types = list() + /// What reagent is represented by this blood type? + var/datum/reagent/reagent_type = /datum/reagent/blood + /// What chem is used to restore this blood type (outside of itself, of course)? + var/datum/reagent/restoration_chem = /datum/reagent/iron + +/datum/blood_type/New() + . = ..() + compatible_types |= type + +/// Gets data to pass to a reagent +/datum/blood_type/proc/get_blood_data(mob/living/sampler) + if(!iscarbon(sampler)) + return null + var/mob/living/carbon/sampled_from = sampler + + var/list/blood_data = list() + //set the blood data + blood_data["viruses"] = list() + + if(sampled_from.immune_system) + blood_data["immunity"] = sampled_from.immune_system.GetImmunity() + + for(var/datum/disease/disease as anything in sampled_from.diseases) + blood_data["viruses"] += disease.Copy() + + blood_data["blood_DNA"] = sampled_from.dna.unique_enzymes + blood_data["resistances"] = LAZYLISTDUPLICATE(sampled_from.disease_resistances) + + var/list/temp_chem = list() + for(var/datum/reagent/trace_chem as anything in sampled_from.reagents.reagent_list) + temp_chem[trace_chem.type] = trace_chem.volume + blood_data["trace_chem"] = list2params(temp_chem) + + blood_data["mind"] = sampled_from.mind || sampled_from.last_mind + blood_data["ckey"] = sampled_from.ckey || ckey(sampled_from.last_mind?.key) + blood_data["cloneable"] = !HAS_TRAIT_FROM(sampled_from, TRAIT_SUICIDED, REF(sampled_from)) + blood_data["blood_type"] = sampled_from.dna.human_blood_type + blood_data["gender"] = sampled_from.gender + blood_data["real_name"] = sampled_from.real_name + blood_data["features"] = sampled_from.dna.features + blood_data["factions"] = sampled_from.faction + blood_data["quirks"] = list() + for(var/datum/quirk/sample_quirk as anything in sampled_from.quirks) + blood_data["quirks"] += sample_quirk.type + return blood_data + +/** + * Used to handle any unique facets of blood spawned of this blood type + * + * Arguments + * * blood - the blood being set up + * * new_splat - whether this is a newly instantiated blood decal, or an existing one this blood is being added to + */ +/datum/blood_type/proc/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat = FALSE) + return + +/** + * Helper proc to make a blood splatter from the passed mob of this type + * + * Arguments + * * bleeding - the mob bleeding the blood, note we assume this blood type is that mob's blood + * * blood_turf - the turf to spawn the blood on + * * drip - whether to spawn a drip or a splatter + */ +/datum/blood_type/proc/make_blood_splatter(mob/living/bleeding, turf/blood_turf, drip) + if(HAS_TRAIT(bleeding, TRAIT_NOBLOOD)) + return + if(isgroundlessturf(blood_turf)) + blood_turf = GET_TURF_BELOW(blood_turf) + if(isnull(blood_turf) || isclosedturf(blood_turf)) + return + + var/list/temp_blood_DNA + if(drip) + var/new_blood = /obj/effect/decal/cleanable/blood/drip::bloodiness + // Only a certain number of drips (or one large splatter) can be on a given turf. + var/obj/effect/decal/cleanable/blood/drip/drop = locate() in blood_turf + if(isnull(drop)) + var/obj/effect/decal/cleanable/blood/splatter = locate() in blood_turf + if(!QDELETED(splatter)) + splatter.adjust_bloodiness(new_blood) + splatter.drying_progress -= (new_blood * BLOOD_PER_UNIT_MODIFIER) + splatter.update_blood_drying_effect() + splatter.transfer_mob_blood_dna(bleeding) + return splatter + + drop = new(blood_turf, bleeding.get_static_viruses()) + if(!QDELETED(drop)) + drop.transfer_mob_blood_dna(bleeding) + drop.random_icon_states -= drop.icon_state + return drop + + if(length(drop.random_icon_states)) + // Handle adding a single drip to the base atom + var/image/drop_overlay = image(icon = drop.icon, icon_state = pick_n_take(drop.random_icon_states), layer = drop.layer, loc = drop) + SET_PLANE_EXPLICIT(drop_overlay, drop.plane, drop) + drop_overlay.appearance_flags |= RESET_COLOR // So each drop has its own color + drop_overlay.color = color + drop.add_overlay(drop_overlay) + // Handle adding blood to the base atom + drop.adjust_bloodiness(new_blood) + drop.drying_progress -= (new_blood * BLOOD_PER_UNIT_MODIFIER) + drop.transfer_mob_blood_dna(bleeding) + drop.update_blood_drying_effect() + return drop + + temp_blood_DNA = GET_ATOM_BLOOD_DNA(drop) //we transfer the dna from the drip to the splatter + qdel(drop)//the drip is replaced by a bigger splatter + + // Find a blood decal or create a new one. + var/obj/effect/decal/cleanable/blood/splatter = locate() in blood_turf + if(isnull(splatter)) + splatter = new(blood_turf, bleeding.get_static_viruses()) + if(QDELETED(splatter)) //Give it up + return null + else + splatter.adjust_bloodiness(BLOOD_AMOUNT_PER_DECAL) + splatter.drying_progress -= (BLOOD_AMOUNT_PER_DECAL * BLOOD_PER_UNIT_MODIFIER) + splatter.update_blood_drying_effect() + splatter.transfer_mob_blood_dna(bleeding) //give blood info to the blood decal. + if(temp_blood_DNA) + splatter.add_blood_DNA(temp_blood_DNA) + return splatter + +/// A base type for all blood related to the crew, for organization's sake +/datum/blood_type/crew + +/// A base type for all blood used by humans (NOT humanoids), for organization's sake +/datum/blood_type/crew/human + +/datum/blood_type/crew/human/a_minus + name = "A-" + compatible_types = list( + /datum/blood_type/crew/human/o_minus, + ) + +/datum/blood_type/crew/human/a_plus + name = "A+" + compatible_types = list( + /datum/blood_type/crew/human/a_minus, + /datum/blood_type/crew/human/a_plus, + /datum/blood_type/crew/human/o_minus, + /datum/blood_type/crew/human/o_plus, + ) + +/datum/blood_type/crew/human/b_minus + name = "B-" + compatible_types = list( + /datum/blood_type/crew/human/b_minus, + /datum/blood_type/crew/human/o_minus, + ) + +/datum/blood_type/crew/human/b_plus + name = "B+" + compatible_types = list( + /datum/blood_type/crew/human/b_minus, + /datum/blood_type/crew/human/b_plus, + /datum/blood_type/crew/human/o_minus, + /datum/blood_type/crew/human/o_plus, + ) + +/datum/blood_type/crew/human/ab_minus + name = "AB-" + compatible_types = list( + /datum/blood_type/crew/human/b_minus, + /datum/blood_type/crew/human/ab_minus, + /datum/blood_type/crew/human/a_minus, + /datum/blood_type/crew/human/o_minus, + ) + +/datum/blood_type/crew/human/ab_plus + name = "AB+" + // Universal Recipient + +/datum/blood_type/crew/human/ab_plus/New() + . = ..() + compatible_types |= subtypesof(/datum/blood_type/crew/human) + +/datum/blood_type/crew/human/o_minus + name = "O-" + // Universal Donor + +/datum/blood_type/crew/human/o_plus + name = "O+" + compatible_types = list( + /datum/blood_type/crew/human/o_minus, + /datum/blood_type/crew/human/o_plus, + ) + +/datum/blood_type/crew/lizard + name = "L" + color = "#047200" // Some species of lizards have mutated green blood due to biliverdin build up + compatible_types = list(/datum/blood_type/crew/lizard/silver) + +/datum/blood_type/crew/lizard/silver + color = "#ffffff63" + compatible_types = list(/datum/blood_type/crew/lizard) + +/datum/blood_type/crew/lizard/silver/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat) + blood.add_filter("silver_glint", 3, list("type" = "outline", "color" = "#c9c9c963", "size" = 1.5)) + +/datum/blood_type/crew/skrell + name = "S" + color = "#009696" // Did you know octopi have blood blood, thanks to hemocyanin rather than hemoglobin? It binds to copper instead of Iron + restoration_chem = /datum/reagent/copper + +/datum/blood_type/crew/ethereal + name = "LE" + color = "#97ee63" + reagent_type = /datum/reagent/consumable/liquidelectricity + glows = TRUE + +/datum/blood_type/crew/ethereal/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat) + blood.glows = TRUE + blood.update_appearance() + if(!new_splat) + return + blood.can_dry = FALSE + blood.update_blood_drying_effect() + RegisterSignals(blood, list(COMSIG_ATOM_ATTACKBY, COMSIG_ATOM_ATTACKBY_SECONDARY), PROC_REF(on_cleaned)) + +/datum/blood_type/crew/ethereal/proc/on_cleaned(obj/effect/decal/cleanable/source, mob/living/user, obj/item/tool, ...) + SIGNAL_HANDLER + + if(!istype(tool, /obj/item/mop)) + return NONE + if(!tool.reagents?.has_reagent()) + return NONE + if(source.bloodiness <= BLOOD_AMOUNT_PER_DECAL * 0.2) + return NONE + if(!user.electrocute_act(clamp(sqrt(source.bloodiness * BLOOD_PER_UNIT_MODIFIER * 4), 5, 50), source, flags = SHOCK_SUPPRESS_MESSAGE)) + return NONE + playsound(source, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + do_sparks(3, FALSE, source) + user.visible_message( + span_warning("Upon touching [source] with [tool], the [initial(reagent_type.name)] inside conducts, shocking [user]!"), + span_warning("Upon touching [source] with [tool], the [initial(reagent_type.name)] conducts, shocking you!"), + ) + return FALSE + +/// Oil based blood for robot lifeforms +/datum/blood_type/oil + name = "Oil" + color = "#1f1a00" + reagent_type = /datum/reagent/fuel/oil + +/datum/blood_type/oil/set_up_blood(obj/effect/decal/cleanable/blood/blood, new_splat) + if(!new_splat) + return + // Oil blood will never dry and can be ignited with fire + blood.can_dry = FALSE + blood.update_blood_drying_effect() + blood.AddElement(/datum/element/easy_ignite) + +/// A universal blood type which accepts everything +/datum/blood_type/universal + name = "U" + +/datum/blood_type/universal/New() + . = ..() + compatible_types = subtypesof(/datum/blood_type) + +/// Clown blood, only used on April Fools +/datum/blood_type/clown + name = "C" + color = "#FF00FF" + reagent_type = /datum/reagent/colorful_reagent + +/// Slimeperson's jelly blood, is also known as "toxic" or "toxin" blood +/datum/blood_type/slime + name = "TOX" + color = "#801E28" + reagent_type = /datum/reagent/toxin/slimejelly + +/// Water based blood for Podpeople primairly +/datum/blood_type/water + name = "H2O" + color = "#AAAAAA77" + reagent_type = /datum/reagent/water + +/// Snails have Lube for blood, for some reason? +/datum/blood_type/snail + name = "Lube" + reagent_type = /datum/reagent/lube + +/// For Xeno blood, though they don't actually USE blood +/datum/blood_type/xenomorph + name = "X*" + color = "#96bb00" + reagent_type = /datum/reagent/toxin/acid + +/// For simplemob blood, which also largely don't actually use blood +/datum/blood_type/animal + name = "Y-" + +/datum/blood_type/crew/bloodsucker + name = "B++" + reagent_type = /datum/reagent/blood/bloodsucker + +/datum/blood_type/spider + name = "S" + color = COLOR_CARP_TURQUOISE diff --git a/monkestation/code/modules/blood_datum/components/item_receiver.dm b/monkestation/code/modules/blood_datum/components/item_receiver.dm new file mode 100644 index 000000000000..4cd8bd080bed --- /dev/null +++ b/monkestation/code/modules/blood_datum/components/item_receiver.dm @@ -0,0 +1,56 @@ +/datum/component/item_receiver + var/list/item_types = list() + var/take_message + +/datum/component/item_receiver/Initialize(list/types = list(), take_message) + . = ..() + var/mob/living/living_parent = parent + if(!living_parent.usable_hands) + return COMPONENT_INCOMPATIBLE + + item_types = types + src.take_message = take_message + +/datum/component/item_receiver/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_LIVING_ITEM_OFFERED_PRECHECK, PROC_REF(precheck_item)) + RegisterSignal(parent, COMSIG_LIVING_GIVE_ITEM_CHECK, PROC_REF(try_take_item)) + +/datum/component/item_receiver/UnregisterFromParent() + . = ..() + UnregisterSignal(parent, list(COMSIG_LIVING_ITEM_OFFERED_PRECHECK, COMSIG_LIVING_GIVE_ITEM_CHECK)) + +/datum/component/item_receiver/proc/precheck_item(datum/source, obj/item/offer) + if(!length(item_types)) + return TRUE + + for(var/item as anything in item_types) + if(istype(offer, item)) + return TRUE + + return FALSE + + +/datum/component/item_receiver/proc/try_take_item(datum/source, atom/movable/screen/alert/give/alert, obj/item/offer) + var/can_take = FALSE + for(var/item as anything in item_types) + if(istype(offer, item)) + can_take = TRUE + break + + if(!can_take) + return FALSE + + var/visible_message = TRUE + if(take_message) + visible_message = FALSE + + if(!alert.handle_transfer(visible_message)) + return FALSE + + if(take_message) + var/atom/movable/movable = parent + movable.visible_message(span_notice("[movable] [take_message] [offer]")) + + return TRUE + diff --git a/monkestation/code/modules/blood_datum/components/limbless_aid.dm b/monkestation/code/modules/blood_datum/components/limbless_aid.dm new file mode 100644 index 000000000000..95e10c382c5b --- /dev/null +++ b/monkestation/code/modules/blood_datum/components/limbless_aid.dm @@ -0,0 +1,136 @@ +/// Attach to items that help mobs missing limbs move faster when held. +/datum/component/limbless_aid + /// What slot flags must the parent item have to provide the bonus? + var/required_slot + /// How much should the movespeed be modified? + var/movespeed_mod + +/datum/component/limbless_aid/Initialize(required_slot = ITEM_SLOT_HANDS, movespeed_mod = 0.5) + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + + src.required_slot = required_slot + src.movespeed_mod = movespeed_mod + +/datum/component/limbless_aid/RegisterWithParent() + RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equip)) + RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(on_drop)) + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(examined)) + + var/obj/item/item_parent = parent + if(isliving(item_parent.loc)) + var/mob/living/wearer = item_parent.loc + on_equip(parent, wearer, wearer.get_slot_by_item(parent)) + +/datum/component/limbless_aid/UnregisterFromParent() + UnregisterSignal(parent, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, COMSIG_ATOM_EXAMINE)) + + var/obj/item/item_parent = parent + if(isliving(item_parent.loc)) + on_drop(item_parent, item_parent.loc) + +/datum/component/limbless_aid/proc/examined(obj/item/source, mob/living/user, list/examine_list) + SIGNAL_HANDLER + + examine_list += span_info("It will support your weight, allowing you to move faster with a wounded, disabled, or missing leg.") + examine_list += span_info("Holding two will allow you to walk despite having two missing or disabled legs.") + examine_list += span_info("Resisting will brace you, allowing you to stand on one support, \ + despite having two missing or disabled legs. Moving will cancel this effect.") + +/datum/component/limbless_aid/proc/on_equip(obj/item/source, mob/living/user, slot) + SIGNAL_HANDLER + + if(!(slot & required_slot)) + return + + add_support(user) + +/datum/component/limbless_aid/proc/add_support(mob/living/user) + ADD_TRAIT(user, TRAIT_NO_LEG_AID, "[REF(src)]_aid") + RegisterSignal(user, COMSIG_LIVING_LIMBLESS_MOVESPEED_UPDATE, PROC_REF(modify_movespeed), override = TRUE) + RegisterSignal(user, COMSIG_CARBON_PAINED_STEP, PROC_REF(pain_step), override = TRUE) + RegisterSignal(user, COMSIG_CARBON_LIMPING, PROC_REF(limp_check), override = TRUE) + RegisterSignal(user, COMSIG_LIVING_RESIST, PROC_REF(self_brace), override = TRUE) + user.update_limbless_locomotion() + user.update_limbless_movespeed_mod() + +/datum/component/limbless_aid/proc/on_drop(obj/item/source, mob/living/user) + SIGNAL_HANDLER + + lose_support(user) + +/datum/component/limbless_aid/proc/lose_support(mob/living/user) + REMOVE_TRAIT(user, TRAIT_NO_LEG_AID, "[REF(src)]_aid") + un_self_brace(user) + UnregisterSignal(user, COMSIG_LIVING_LIMBLESS_MOVESPEED_UPDATE) + UnregisterSignal(user, COMSIG_CARBON_PAINED_STEP) + UnregisterSignal(user, COMSIG_CARBON_LIMPING) + UnregisterSignal(user, COMSIG_LIVING_RESIST) + user.update_limbless_locomotion() + user.update_limbless_movespeed_mod() + +/datum/component/limbless_aid/proc/modify_movespeed(mob/living/source, list/modifiers) + SIGNAL_HANDLER + + var/obj/item/bodypart/leg = get_braced_leg(source) + if(isnull(leg) || leg.bodypart_disabled) + modifiers += movespeed_mod + +/datum/component/limbless_aid/proc/pain_step(mob/living/source, obj/item/affected_leg, footstep_count) + SIGNAL_HANDLER + + var/obj/item/bodypart/leg = get_braced_leg(source) + if(isnull(leg) || leg == affected_leg) + return STOP_PAIN + +/datum/component/limbless_aid/proc/limp_check(mob/living/source, obj/item/bodypart/next_leg) + SIGNAL_HANDLER + + var/obj/item/bodypart/leg = get_braced_leg(source) + if(isnull(leg) || leg == next_leg) + return COMPONENT_CANCEL_LIMP + +/// Checks what side the item is equipped on +/datum/component/limbless_aid/proc/get_braced_leg(mob/living/who) + if(required_slot & ITEM_SLOT_HANDS) + // note this is backwards intentionally: + // right arm braces the left leg, and left arm braces right leg + var/side = IS_RIGHT(who.get_held_index_of_item(parent)) ? BODY_ZONE_L_LEG : BODY_ZONE_R_LEG + return who.get_bodypart(side) + + return null // unimplemented + + +/datum/component/limbless_aid/proc/self_brace(mob/living/source) + SIGNAL_HANDLER + + INVOKE_ASYNC(src, PROC_REF(self_brace_async), source) + +/datum/component/limbless_aid/proc/un_self_brace(mob/living/source) + REMOVE_TRAIT(source, TRAIT_NO_LEG_AID, "[REF(src)]_brace") + UnregisterSignal(source, COMSIG_MOVABLE_MOVED) + +/datum/component/limbless_aid/proc/self_brace_async(mob/living/source) + if((required_slot & ITEM_SLOT_HANDS) && parent != source.get_active_held_item()) + return + if(HAS_TRAIT_FROM(source, TRAIT_NO_LEG_AID, "[REF(src)]_brace")) + return + if(DOING_INTERACTION_WITH_TARGET(source, source)) + return + // lying down is a lot harder to get up from + if(!do_after(source, (source.body_position == LYING_DOWN ? 2.4 SECONDS : 0.8 SECONDS), source)) + return + + source.balloon_alert(source, "braced") + ADD_TRAIT(source, TRAIT_NO_LEG_AID, "[REF(src)]_brace") + RegisterSignal(source, COMSIG_MOVABLE_MOVED, PROC_REF(brace_moved)) + source.update_limbless_locomotion() + +/datum/component/limbless_aid/proc/brace_moved(mob/living/source, atom/old_loc) + SIGNAL_HANDLER + + if(source.loc == old_loc) + return + + un_self_brace(source) + source.update_limbless_locomotion() diff --git a/monkestation/code/modules/blood_datum/debilitated.dm b/monkestation/code/modules/blood_datum/debilitated.dm new file mode 100644 index 000000000000..410f8a531206 --- /dev/null +++ b/monkestation/code/modules/blood_datum/debilitated.dm @@ -0,0 +1,38 @@ +/datum/physiology + ///our temp stamina mod + var/temp_stamina_mod = 1 + +/datum/status_effect/stacking/debilitated + id = "debilitated" + stacks = 0 + max_stacks = 10 + tick_interval = 10 SECONDS + delay_before_decay = 3 MINUTES + consumed_on_threshold = FALSE + alert_type = /atom/movable/screen/alert/status_effect/debilitated + status_type = STATUS_EFFECT_REFRESH + + ///our base stamina loss multiplier + var/loss_multiplier = 1 + ///our per stack increase to stamina loss + var/per_stack_multiplier_increase = 0.1 + ///our cached stamina_mod + var/cached_stamina + +/datum/status_effect/stacking/debilitated/on_apply() + . = ..() + if(ishuman(owner)) + var/mob/living/carbon/human/human = owner + cached_stamina = human.physiology.temp_stamina_mod + +/datum/status_effect/stacking/debilitated/add_stacks(stacks_added) + . = ..() + if(!ishuman(owner)) + return + var/mob/living/carbon/human/human = owner + human.physiology.temp_stamina_mod = loss_multiplier + (stacks * per_stack_multiplier_increase) + +/atom/movable/screen/alert/status_effect/debilitated + icon_state = "debilitated" + name = "Debilitated" + desc = "You are taking extra stamina damage from incoming projectiles, and lose stamina faster." diff --git a/monkestation/code/modules/blood_datum/designs.dm b/monkestation/code/modules/blood_datum/designs.dm new file mode 100644 index 000000000000..0da2fcfefdd1 --- /dev/null +++ b/monkestation/code/modules/blood_datum/designs.dm @@ -0,0 +1,46 @@ +/datum/design/vitals_monitor + name = "Vitals Monitor" + desc = "A wall mounted computer that displays the vitals of a patient nearby. \ + Links to stasis beds, operating tables, and other machines that can hold patients \ + such as cryo cells, sleepers, and more." + id = "vitals_monitor" + build_type = PROTOLATHE + materials = list( + /datum/material/iron = SHEET_MATERIAL_AMOUNT * 4, + /datum/material/glass = SHEET_MATERIAL_AMOUNT * 2, + /datum/material/gold = HALF_SHEET_MATERIAL_AMOUNT * 0.5, + ) + build_path = /obj/item/wallframe/status_display/vitals + category = list(RND_CATEGORY_COMPUTER + RND_SUBCATEGORY_COMPUTER_MEDICAL) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL + +/datum/design/vitals_monitor/advanced + name = "Advanced Vitals Monitor" + desc = "An updated vitals display which performs a more detailed scan of the patient than the basic display." + id = "vitals_monitor_advanced" + materials = list( + /datum/material/iron = SHEET_MATERIAL_AMOUNT * 4, + /datum/material/glass = SHEET_MATERIAL_AMOUNT * 2, + /datum/material/gold = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/silver = HALF_SHEET_MATERIAL_AMOUNT * 0.5, + ) + build_path = /obj/item/wallframe/status_display/vitals/advanced + +/datum/design/board/vital_floor_scanner + name = "Vitals Scanning Pad" + desc = "The circuit board for a vitals scanning pad." + id = "scanning_pad" + build_path = /obj/item/circuitboard/machine/vital_floor_scanner + category = list( + RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_MEDICAL + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL + +/obj/item/circuitboard/machine/vital_floor_scanner + name = "\improper Vitals Scanning Pad" + greyscale_colors = CIRCUIT_COLOR_MEDICAL + build_path = /obj/machinery/health_scanner_floor + req_components = list( + /obj/item/stack/cable_coil = 5, + /datum/stock_part/scanning_module = 1, + ) diff --git a/monkestation/code/modules/blood_datum/elements/easy_ignite.dm b/monkestation/code/modules/blood_datum/elements/easy_ignite.dm new file mode 100644 index 000000000000..15416cf05e68 --- /dev/null +++ b/monkestation/code/modules/blood_datum/elements/easy_ignite.dm @@ -0,0 +1,97 @@ +/datum/element/easy_ignite + element_flags = ELEMENT_DETACH_ON_HOST_DESTROY|ELEMENT_BESPOKE // because turfs + argument_hash_start_idx = 2 + /// Temp required for ignition + var/required_temp = 450 + +/datum/element/easy_ignite/Attach(datum/target, required_temp = 450) + . = ..() + if(!isatom(target) || isarea(target)) + return ELEMENT_INCOMPATIBLE + + src.required_temp = required_temp + RegisterSignal(target, COMSIG_ATOM_ATTACKBY, PROC_REF(attackby_react)) + RegisterSignal(target, COMSIG_ATOM_FIRE_ACT, PROC_REF(flame_react)) + RegisterSignal(target, COMSIG_ATOM_BULLET_ACT, PROC_REF(projectile_react)) + RegisterSignal(target, COMSIG_ATOM_TOOL_ACT(TOOL_WELDER), PROC_REF(welder_react)) + if(isturf(target)) + RegisterSignal(target, COMSIG_TURF_EXPOSE, PROC_REF(hotspots_react)) + +/datum/element/easy_ignite/Detach(datum/source, ...) + . = ..() + UnregisterSignal(source, COMSIG_ATOM_ATTACKBY) + UnregisterSignal(source, COMSIG_ATOM_FIRE_ACT) + UnregisterSignal(source, COMSIG_ATOM_BULLET_ACT) + UnregisterSignal(source, COMSIG_ATOM_TOOL_ACT(TOOL_WELDER)) + if(isturf(source)) + UnregisterSignal(source, COMSIG_TURF_EXPOSE) + +/datum/element/easy_ignite/proc/ignite(atom/igniting, mob/user) + var/delete_after = TRUE + + igniting.visible_message(span_warning("[igniting] ignite[igniting.p_s()]!"), span_warning("You ignite into flames!")) + new /obj/effect/hotspot(isturf(igniting) ? igniting : igniting.loc) + + if(isturf(igniting)) + var/turf/parent_turf = igniting + parent_turf.ScrapeAway(1, CHANGETURF_INHERIT_AIR) + delete_after = FALSE + + // Logging-related + var/log_message = "ignited [igniting]" + if(user) + user.log_message(log_message, LOG_ATTACK, log_globally = FALSE)//only individual log + + else + log_message = "[key_name(user)] " + log_message + " by fire" + log_attack(log_message) + + if(delete_after && !QDELETED(igniting)) + qdel(igniting) + +/datum/element/easy_ignite/proc/flame_react(obj/item/source, exposed_temperature, exposed_volume) + SIGNAL_HANDLER + + if(exposed_temperature > required_temp) + ignite(source) + +/datum/element/easy_ignite/proc/hotspots_react(obj/item/source, air, exposed_temperature) + SIGNAL_HANDLER + + if(exposed_temperature > required_temp) + ignite(source) + +/datum/element/easy_ignite/proc/attackby_react(obj/item/source, mob/user, obj/item/tool, modifiers) + SIGNAL_HANDLER + + if(tool.get_temperature() && item_ignition(source, tool, user)) + ignite(source, user) + return FALSE + +/datum/element/easy_ignite/proc/projectile_react(obj/item/source, obj/projectile/shot) + SIGNAL_HANDLER + + if(shot.damage_type == BURN && shot.damage > 0) + ignite(source, shot.firer) + +/datum/element/easy_ignite/proc/welder_react(obj/item/source, mob/user, obj/item/tool) + SIGNAL_HANDLER + + if(tool.get_temperature() && item_ignition(source, tool, user)) + ignite(source, user) + return FALSE + +/datum/element/easy_ignite/proc/item_ignition(obj/item/source, obj/item/tool, mob/user) + if(tool.get_temperature() >= required_temp) + source.visible_message( + span_warning("[user] ignites [source] with [tool]!"), + span_warning("You ignite [source] with [tool]!"), + ) + ignite(source, user) + return TRUE + + source.visible_message( + span_warning("[user] tries to ignite [source] with [tool]!"), + span_warning("You try to ignite [source] with [tool], but it's not hot enough!"), + ) + return FALSE diff --git a/monkestation/code/modules/blood_datum/forensics_helpers.dm b/monkestation/code/modules/blood_datum/forensics_helpers.dm new file mode 100644 index 000000000000..b866e245a9f2 --- /dev/null +++ b/monkestation/code/modules/blood_datum/forensics_helpers.dm @@ -0,0 +1,39 @@ +/atom + /// Cached mixed color of all blood DNA on us + VAR_PROTECTED/cached_blood_dna_color + +/atom/proc/get_blood_dna_color() + if(cached_blood_dna_color) + return cached_blood_dna_color + + var/list/colors = list() + var/list/all_dna = GET_ATOM_BLOOD_DNA(src) + for(var/dna_sample in all_dna) + colors += GLOB.blood_types[all_dna[dna_sample]]?.color + list_clear_nulls(colors) + var/final_color = COLOR_BLOOD + if(length(colors)) + final_color = pop(colors) + for(var/color in colors) + final_color = BlendRGB(final_color, color, 0.5) + cached_blood_dna_color = final_color + return final_color + +/obj/effect/decal/cleanable/blood/drip/get_blood_dna_color() + var/list/all_dna = GET_ATOM_BLOOD_DNA(src) + return GLOB.blood_types[all_dna[all_dna[1]]]?.color || COLOR_BLOOD + +/obj/effect/decal/cleanable/blood/add_blood_DNA(list/blood_DNA_to_add) + var/first_dna = GET_ATOM_BLOOD_DNA_LENGTH(src) + if(!..()) + return FALSE + + color = get_blood_dna_color() + // Imperfect, ends up with some blood types being double-set-up, but harmless (for now) + for(var/new_blood in blood_DNA_to_add) + var/datum/blood_type/blood = GLOB.blood_types[blood_DNA_to_add[new_blood]] + if(!blood) + continue + blood.set_up_blood(src, first_dna == 0) + update_appearance() + return TRUE diff --git a/monkestation/code/modules/blood_datum/icons/beam.dmi b/monkestation/code/modules/blood_datum/icons/beam.dmi new file mode 100644 index 000000000000..2ac3e0da83fa Binary files /dev/null and b/monkestation/code/modules/blood_datum/icons/beam.dmi differ diff --git a/monkestation/code/modules/blood_datum/icons/melee_lefthand.dmi b/monkestation/code/modules/blood_datum/icons/melee_lefthand.dmi new file mode 100644 index 000000000000..62675c5968d2 Binary files /dev/null and b/monkestation/code/modules/blood_datum/icons/melee_lefthand.dmi differ diff --git a/monkestation/code/modules/blood_datum/icons/melee_righthand.dmi b/monkestation/code/modules/blood_datum/icons/melee_righthand.dmi new file mode 100644 index 000000000000..47b673a6f322 Binary files /dev/null and b/monkestation/code/modules/blood_datum/icons/melee_righthand.dmi differ diff --git a/monkestation/code/modules/blood_datum/icons/staff.dmi b/monkestation/code/modules/blood_datum/icons/staff.dmi new file mode 100644 index 000000000000..2a710cc60cf9 Binary files /dev/null and b/monkestation/code/modules/blood_datum/icons/staff.dmi differ diff --git a/monkestation/code/modules/blood_datum/icons/status_display.dmi b/monkestation/code/modules/blood_datum/icons/status_display.dmi new file mode 100644 index 000000000000..4c245723bfa3 Binary files /dev/null and b/monkestation/code/modules/blood_datum/icons/status_display.dmi differ diff --git a/monkestation/code/modules/blood_datum/items/crutch.dm b/monkestation/code/modules/blood_datum/items/crutch.dm new file mode 100644 index 000000000000..a71083370655 --- /dev/null +++ b/monkestation/code/modules/blood_datum/items/crutch.dm @@ -0,0 +1,21 @@ +/obj/item/cane/crutch + name = "medical crutch" + desc = "A medical crutch used by people missing a leg. Not all that useful if you're missing both of them, though." + icon = 'monkestation/code/modules/blood_datum/icons/staff.dmi' + icon_state = "crutch_med" + inhand_icon_state = "crutch_med" + lefthand_file = 'monkestation/code/modules/blood_datum/icons/melee_lefthand.dmi' + righthand_file = 'monkestation/code/modules/blood_datum/icons/melee_righthand.dmi' + force = 12 + throwforce = 8 + w_class = WEIGHT_CLASS_BULKY + custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 0.5) + attack_verb_continuous = list("bludgeons", "whacks", "thrashes") + attack_verb_simple = list("bludgeon", "whack", "thrash") + +/obj/item/cane/crutch/wood + name = "wooden crutch" + desc = "A handmade crutch. Also makes a decent bludgeon if you need it." + icon_state = "crutch_wood" + inhand_icon_state = "crutch_wood" + custom_materials = list(/datum/material/wood = SMALL_MATERIAL_AMOUNT * 0.5) diff --git a/monkestation/code/modules/blood_datum/stunning.dm b/monkestation/code/modules/blood_datum/stunning.dm new file mode 100644 index 000000000000..a4a81799d8dd --- /dev/null +++ b/monkestation/code/modules/blood_datum/stunning.dm @@ -0,0 +1,290 @@ + +#define COMSIG_BEAM_ENTERED "beam_entered" + +/// Status effect tracking being tased by someone! +/datum/status_effect/tased + id = "being_tased" + status_type = STATUS_EFFECT_MULTIPLE + alert_type = /atom/movable/screen/alert/status_effect/tazed + tick_interval = 0.25 SECONDS + on_remove_on_mob_delete = TRUE + /// What atom is tasing us? + var/atom/taser + /// What atom is using the atom tasing us? Sometimes the same as the taser, such as with turrets. + var/atom/firer + /// The beam datum representing the taser electrodes + var/datum/beam/tase_line + +/datum/status_effect/tased/on_creation(mob/living/new_owner, atom/fired_from, atom/firer) + if(isnull(fired_from) || isnull(firer) || !can_tase_with(fired_from)) + qdel(src) + return + + if(new_owner.has_status_effect(type) != src) + alert_type = null + + . = ..() + if(!.) + return + + set_taser(fired_from) + set_firer(firer) + +/// Checks if the passed atom is captable of being used to tase someone +/datum/status_effect/tased/proc/can_tase_with(atom/with_what) + if(istype(with_what, /obj/item/gun/energy)) + var/obj/item/gun/energy/taser_gun = with_what + if(isnull(taser_gun.cell)) + return FALSE + + else if(istype(with_what, /obj/machinery)) + var/obj/machinery/taser_machine = with_what + if(!taser_machine.is_operational) + return FALSE + + return TRUE + +/// Actually does the tasing with the passed atom +/// Returns TRUE if the tasing was successful, FALSE if it failed +/datum/status_effect/tased/proc/do_tase_with(atom/with_what, seconds_between_ticks) + if(!can_see(taser, owner, 5)) + return FALSE + if(istype(with_what, /obj/item/gun/energy)) + var/obj/item/gun/energy/taser_gun = with_what + if(!taser_gun.cell?.use(60 * seconds_between_ticks)) + return FALSE + taser_gun.update_appearance() + return TRUE + + if(istype(taser, /obj/machinery)) + var/obj/machinery/taser_machine = taser + if(!taser_machine.is_operational) + return FALSE + // We can't measure the output of this but if we use too much power the area will depower -> depower the machine -> stop taze next tick + taser_machine.use_power(60 * seconds_between_ticks) + return TRUE + + if(istype(taser, /obj/item/mecha_parts/mecha_equipment)) + var/obj/item/mecha_parts/mecha_equipment/taser_equipment = taser + if(!taser_equipment.chassis \ + || !taser_equipment.activated \ + || taser_equipment.get_integrity() <= 1 \ + || taser_equipment.chassis.is_currently_ejecting \ + || taser_equipment.chassis.equipment_disabled \ + || !taser_equipment.chassis.use_power(60 * seconds_between_ticks)) + return FALSE + return TRUE + + return TRUE + +/datum/status_effect/tased/on_apply() + if(issilicon(owner) \ + || istype(owner, /mob/living/basic/bot) \ + || istype(owner, /mob/living/simple_animal/bot) \ + || HAS_TRAIT(owner, TRAIT_PIERCEIMMUNE)) + return FALSE + + RegisterSignal(owner, COMSIG_LIVING_RESIST, PROC_REF(try_remove_taser)) + SEND_SIGNAL(owner, COMSIG_LIVING_MINOR_SHOCK) + owner.add_mood_event("tased", /datum/mood_event/tased) + owner.add_movespeed_modifier(/datum/movespeed_modifier/being_tased) + if(owner.pain_controller?.pain_modifier > 0.5) + owner.pain_emote("scream") + if(ishuman(owner)) + var/mob/living/carbon/human/human_owner = owner + human_owner.force_say() + return TRUE + +/datum/status_effect/tased/on_remove() + if(istype(taser, /obj/machinery/porta_turret)) + var/obj/machinery/porta_turret/taser_turret = taser + taser_turret.manual_control = initial(taser_turret.manual_control) + taser_turret.always_up = initial(taser_turret.always_up) + taser_turret.check_should_process() + else if(istype(taser, /obj/machinery/power/emitter)) + var/obj/machinery/power/emitter/taser_emitter = taser + taser_emitter.manual = initial(taser_emitter.manual) + + var/mob/living/mob_firer = firer + if(istype(mob_firer)) + mob_firer.remove_movespeed_modifier(/datum/movespeed_modifier/tasing_someone) + + owner.remove_movespeed_modifier(/datum/movespeed_modifier/being_tased) + if(!QDELING(owner)) + owner.adjust_jitter_up_to(10 SECONDS, 1 MINUTES) + + taser = null + firer = null + QDEL_NULL(tase_line) + +/datum/status_effect/tased/tick(seconds_between_ticks) + if(!do_tase_with(taser, seconds_between_ticks)) + end_tase() + return + if(owner.check_stun_immunity(CANSTUN|CANKNOCKDOWN)) + return + // You are damp, that's bad when you're being tased + if(owner.fire_stacks < 0) + owner.apply_damage(max(1, owner.fire_stacks * -0.5 * seconds_between_ticks), FIRE, spread_damage = TRUE) + if(SPT_PROB(25, seconds_between_ticks)) + do_sparks(1, FALSE, owner) + + owner.set_stutter_if_lower(10 SECONDS) + owner.set_jitter_if_lower(20 SECONDS) + owner.cause_pain(BODY_ZONES_ALL, 2 * seconds_between_ticks, BURN) + owner.apply_damage(120 * seconds_between_ticks * (owner.pain_controller?.pain_modifier || 1), STAMINA) + if(owner.stat <= SOFT_CRIT) + owner.do_jitter_animation(INFINITY) // maximum POWER + +/// Sets the passed atom as the "taser" +/datum/status_effect/tased/proc/set_taser(atom/new_taser) + taser = new_taser + RegisterSignals(taser, list(COMSIG_QDELETING, COMSIG_ITEM_DROPPED, COMSIG_ITEM_EQUIPPED), PROC_REF(end_tase)) + RegisterSignal(taser, COMSIG_GUN_TRY_FIRE, PROC_REF(block_firing)) + if(istype(taser, /obj/machinery/porta_turret)) + var/obj/machinery/porta_turret/taser_turret = taser + taser_turret.manual_control = TRUE + taser_turret.always_up = TRUE + else if(istype(taser, /obj/machinery/power/emitter)) + var/obj/machinery/power/emitter/taser_emitter = taser + taser_emitter.manual = TRUE + +/// Sets the passed atom as the person operating the taser, the "firer" +/datum/status_effect/tased/proc/set_firer(atom/new_firer) + firer = new_firer + if(taser != firer) // Turrets, notably, are both + RegisterSignal(firer, COMSIG_QDELETING, PROC_REF(end_tase)) + + // RegisterSignals(firer, list(COMSIG_MOB_SWAP_HANDS), PROC_REF(end_tase)) + RegisterSignal(firer, COMSIG_MOB_CLICKON, PROC_REF(user_cancel_tase)) + + // Ensures AI mobs or turrets don't tase players until they run out of power + var/mob/living/mob_firer = new_firer + if(!istype(mob_firer) || isnull(mob_firer.client)) + // If multiple things are tasing the same mob, give up sooner, so they can select a new target potentially + addtimer(CALLBACK(src, PROC_REF(end_tase)), (owner.has_status_effect(type) != src) ? 2 SECONDS : 8 SECONDS) + if(istype(mob_firer)) + mob_firer.add_movespeed_modifier(/datum/movespeed_modifier/tasing_someone) + + tase_line = firer.Beam( + BeamTarget = owner, + icon = 'monkestation/code/modules/blood_datum/icons/beam.dmi', + icon_state = "electrodes", + maxdistance = 6, + beam_type = /obj/effect/ebeam/react_to_entry/electrodes, + ) + RegisterSignal(tase_line, COMSIG_BEAM_ENTERED, PROC_REF(disrupt_tase)) + RegisterSignal(tase_line, COMSIG_QDELETING, PROC_REF(end_tase)) + tase_line.RegisterSignal(owner, COMSIG_LIVING_SET_BODY_POSITION, TYPE_PROC_REF(/datum/beam, redrawing)) + +/datum/status_effect/tased/proc/block_firing(...) + SIGNAL_HANDLER + return COMPONENT_CANCEL_GUN_FIRE + +/datum/status_effect/tased/proc/user_cancel_tase(mob/living/source, atom/clicked_on, modifiers) + SIGNAL_HANDLER + if(clicked_on != owner) + return NONE + if(LAZYACCESS(modifiers, SHIFT_CLICK)) + return NONE + end_tase() + return COMSIG_MOB_CANCEL_CLICKON + +/datum/status_effect/tased/proc/end_tase(...) + SIGNAL_HANDLER + if(QDELING(src)) + return + owner.visible_message( + span_warning("The electrodes stop shocking [owner], and fall to the ground."), + span_notice("The electrodes stop shocking you, and fall to the ground."), + ) + qdel(src) + +/datum/status_effect/tased/proc/try_remove_taser(datum/source) + SIGNAL_HANDLER + INVOKE_ASYNC(src, PROC_REF(try_remove_taser_async), source) + +/datum/status_effect/tased/proc/try_remove_taser_async() + owner.visible_message( + span_warning("[owner] tries to remove the electrodes!"), + span_notice("You try to remove the electrodes!"), + ) + // If embedding was less... difficult to work with, I would make tasers rely on an embedded object to handle this + if(!do_after(src, 5 SECONDS, src, extra_checks = CALLBACK(src, PROC_REF(try_remove_taser_checks)), interaction_key = "tazed")) + return + owner.visible_message( + span_warning("[owner] removes the electrodes from [owner.p_their()] body!"), + span_notice("You remove the electrodes!"), + ) + end_tase() + +/datum/status_effect/tased/proc/try_remove_taser_checks() + return !QDELETED(src) + +/datum/status_effect/tased/proc/disrupt_tase(datum/beam/source, obj/effect/ebeam/beam_effect, atom/movable/entering) + SIGNAL_HANDLER + + if(!isliving(entering) || entering == taser || entering == firer || entering == owner) + return + if(entering.pass_flags & (PASSMOB|PASSGRILLE|PASSTABLE)) + return + var/mob/living/disruptor = entering + if(disruptor.body_position == LYING_DOWN) + return + disruptor.visible_message( + span_warning("[disruptor] gets tangled in the electrodes!"), + span_warning("You get tangled in the electrodes!"), + ) + disruptor.apply_damage(90, STAMINA) + disruptor.Knockdown(5 SECONDS) + disruptor.adjust_jitter_up_to(10 SECONDS, 30 SECONDS) + qdel(src) + +/// Screen alert for being tased, clicking does a resist (like being on fire or w/e) +/atom/movable/screen/alert/status_effect/tazed + name = "Tased!" + desc = "Taser electrodes are shocking you! You can resist to try to remove them." + icon_state = "stun" + +/atom/movable/screen/alert/status_effect/tazed/Click(location, control, params) + . = ..() + if(!.) + return + var/mob/living/clicker = usr + clicker.resist() + +/// Beam subtype which sends a signal to the beam itself when someone walks inside it +/obj/effect/ebeam/react_to_entry + +/obj/effect/ebeam/react_to_entry/Initialize(mapload, beam_owner) + . = ..() + if(isnull(owner)) + return + var/static/list/loc_connections = list( + COMSIG_ATOM_ENTERED = PROC_REF(on_entered), + COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON = PROC_REF(on_entered), + ) + AddElement(/datum/element/connect_loc, loc_connections) + // Technically the beam is entering the mob but we'll count it + for(var/thing in loc) + on_entered(src, thing) + +/obj/effect/ebeam/react_to_entry/proc/on_entered(datum/source, atom/movable/entering) + SIGNAL_HANDLER + SEND_SIGNAL(owner, COMSIG_BEAM_ENTERED, src, entering) + +/obj/effect/ebeam/react_to_entry/electrodes + name = "electrodes" + light_system = OVERLAY_LIGHT + light_on = TRUE + light_color = COLOR_YELLOW + light_power = 1 + light_outer_range = 1.5 + +/datum/movespeed_modifier/tasing_someone + multiplicative_slowdown = 2 + +/datum/movespeed_modifier/being_tased + multiplicative_slowdown = 4 + +#undef COMSIG_BEAM_ENTERED diff --git a/monkestation/code/modules/blood_datum/vital_monitor/operating_table_additions.dm b/monkestation/code/modules/blood_datum/vital_monitor/operating_table_additions.dm new file mode 100644 index 000000000000..061d8895d30e --- /dev/null +++ b/monkestation/code/modules/blood_datum/vital_monitor/operating_table_additions.dm @@ -0,0 +1,72 @@ +/obj/machinery/computer/operating + +/obj/machinery/computer/operating/emag_act(mob/user, obj/item/card/emag/emag_card) + . = ..() + if(obj_flags & EMAGGED) + return + if(!is_operational) + return + + obj_flags |= EMAGGED + balloon_alert(user, "safeties overridden") + playsound(src, 'sound/machines/terminal_alert.ogg', 50, FALSE, SHORT_RANGE_SOUND_EXTRARANGE) + playsound(src, SFX_SPARKS, 100, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + +/obj/machinery/computer/operating/ui_data(mob/user) + var/list/data = ..() + if(isnull(table)) + return data + + if(isnull(table.patient)) + return data + + var/obj/item/organ/patient_brain = table.patient.get_organ_slot(ORGAN_SLOT_BRAIN) + data["patient"]["brain"] = isnull(patient_brain) ? 100 : ((patient_brain.damage / patient_brain.maxHealth) * 100) + data["patient"]["bloodVolumePercent"] = round((table.patient.blood_volume / BLOOD_VOLUME_NORMAL) * 100) + data["patient"]["heartRate"] = table.patient.get_pretend_heart_rate() + // We can also show pain and stuff here if we want. + + return data + +/// I fully intend on adding real heart rate eventually, but now we fake it +/// This also serves as a nice way to collect things which should affect heart rate later. +/mob/living/carbon/proc/get_pretend_heart_rate() + if(stat == DEAD) + return 0 + + var/obj/item/organ/internal/heart/heart = get_organ_slot(ORGAN_SLOT_HEART) + if(isnull(heart) || !heart.beating) + return 0 + + var/base_amount = 0 + + if(has_status_effect(/datum/status_effect/jitter)) + base_amount = 100 + rand(0, 25) + else if(stat == SOFT_CRIT || stat == HARD_CRIT) + base_amount = 60 + rand(-15, -10) + else + base_amount = 90 + rand(-10, 10) + + switch(pain_controller?.get_average_pain()) // pain raises it a bit + if(25 to 50) + base_amount += 5 + if(50 to 75) + base_amount += 10 + if(75 to INFINITY) + base_amount += 15 + + switch(pain_controller?.pain_modifier) // numbness lowers it a bit + if(0.25 to 0.5) + base_amount -= 15 + if(0.5 to 0.75) + base_amount -= 10 + if(0.75 to 1) + base_amount -= 5 + + if(has_status_effect(/datum/status_effect/determined)) // adrenaline + base_amount += 10 + + if(has_reagent(/datum/reagent/consumable/coffee)) // funny + base_amount += 10 + + return round(base_amount * clamp(1.5 * ((heart.maxHealth - heart.damage) / heart.maxHealth), 0.5, 1)) // heart damage puts a multiplier on it diff --git a/monkestation/code/modules/blood_datum/vital_monitor/vital_reader.dm b/monkestation/code/modules/blood_datum/vital_monitor/vital_reader.dm new file mode 100644 index 000000000000..27634b075d66 --- /dev/null +++ b/monkestation/code/modules/blood_datum/vital_monitor/vital_reader.dm @@ -0,0 +1,440 @@ +/obj/item/wallframe/status_display/vitals + name = "vitals display frame" + desc = "Used to build vitals displays. Secure on a wall nearby a stasis bed, operating table, \ + or another machine that can hold patients such as cryo cells or sleepers." + custom_materials = list( + /datum/material/iron = SHEET_MATERIAL_AMOUNT * 4, + /datum/material/glass = SHEET_MATERIAL_AMOUNT * 2, + /datum/material/gold = HALF_SHEET_MATERIAL_AMOUNT * 0.5, + ) + result_path = /obj/machinery/computer/vitals_reader + +/obj/item/wallframe/status_display/vitals/advanced + name = "advanced vitals display frame" + desc = "Used to build advanced vitals displays. Performs a more detailed scan of the patient than the basic display." + custom_materials = list( + /datum/material/iron = SHEET_MATERIAL_AMOUNT * 4, + /datum/material/glass = SHEET_MATERIAL_AMOUNT * 2, + /datum/material/gold = HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/silver = HALF_SHEET_MATERIAL_AMOUNT * 0.5, + ) + result_path = /obj/machinery/computer/vitals_reader/advanced + +/// A wall mounted screen that showcases the vitals of a patient nearby. +/obj/machinery/computer/vitals_reader + name = "vitals display" + desc = "A small screen that displays the vitals of a patient." + icon = 'monkestation/code/modules/blood_datum/icons/status_display.dmi' + icon_state = "frame" + verb_say = "beeps" + verb_ask = "beeps" + verb_exclaim = "beeps" + density = FALSE + layer = ABOVE_WINDOW_LAYER + interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_REQUIRES_DEXTERITY + interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON + use_power = IDLE_POWER_USE + idle_power_usage = 0 + active_power_usage = BASE_MACHINE_IDLE_CONSUMPTION + icon_keyboard = null + icon_screen = null + + /// Whether we perform an advanced scan on examine or not, currently admin only + var/advanced = FALSE + /// Typepath to spawn when deconstructed + var/frame = /obj/item/wallframe/status_display/vitals + /// Whether we are on or off + VAR_FINAL/active = FALSE + /// Reference to the mob that is being tracked / scanned + VAR_FINAL/mob/living/patient + /// Static typecache of things the vitals display can connect to. + /// By default it will connect to these and grab their occupant to display as a patient. + var/static/list/connectable_typecache = typecacheof(list( + /obj/machinery/abductor/experiment, + /obj/machinery/atmospherics/components/unary/cryo_cell, + /obj/machinery/computer/operating, // Snowflaked + /obj/machinery/dna_scannernew, + /obj/machinery/gulag_teleporter, + /obj/machinery/hypnochair, + /obj/machinery/implantchair, + /obj/machinery/sleeper, + /obj/machinery/stasis, + /obj/machinery/health_scanner_floor, + )) + +MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/vitals_reader, 32) + +/obj/machinery/computer/vitals_reader/advanced + name = "advanced vitals display" + desc = "A small screen that displays the vitals of a patient. \ + Performs a more detailed scan of the patient than the basic display." + frame = /obj/item/wallframe/status_display/vitals/advanced + advanced = TRUE + +MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/vitals_reader/advanced, 32) + +/obj/machinery/computer/vitals_reader/no_hand + name = "automatic vitals display" + desc = "A small screen that displays the vitals of a patient. \ + It has no button to toggle it manually." + interaction_flags_atom = NONE + interaction_flags_machine = NONE + +MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/vitals_reader/no_hand, 32) + +/obj/machinery/computer/vitals_reader/attackby(obj/item/weapon, mob/living/user, params) + if(!istype(user) || (user.istate & ISTATE_HARM)) + return ..() + if((interaction_flags_atom & INTERACT_ATOM_ATTACK_HAND) && (weapon.item_flags & SURGICAL_TOOL)) + // You can flick it on while doing surgery + return interact(user) + return ..() + +/obj/machinery/computer/vitals_reader/wrench_act(mob/living/user, obj/item/tool) + if(flags_1 & NODECONSTRUCT_1) + return FALSE + if(user.istate & ISTATE_HARM) + return FALSE + balloon_alert(user, "detaching...") + if(tool.use_tool(src, user, 6 SECONDS, volume = 50)) + playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) + deconstruct(TRUE) + return TRUE + +/obj/machinery/computer/vitals_reader/deconstruct(disassembled) + if(flags_1 & NODECONSTRUCT_1) + return + var/atom/drop_loc = drop_location() + if(disassembled) + new frame(drop_loc) + else + new /obj/item/stack/sheet/iron(drop_loc, 2) + new /obj/item/shard(drop_loc) + new /obj/item/shard(drop_loc) + qdel(src) + +/obj/machinery/computer/vitals_reader/examine(mob/user) + . = ..() + if(!is_operational || !active || user.is_blind()) + return + + if(isnull(patient)) + . += span_notice("The display is currently scanning for a patient.") + else if(!issilicon(user) && !isobserver(user) && get_dist(patient, user) > 2) + . += span_notice("You are too far away to read the display.") + else if(HAS_TRAIT(user, TRAIT_DUMB) || !user.can_read(src, reading_check_flags = READING_CHECK_LITERACY, silent = TRUE)) + . += span_warning("You try to comprehend the display, but it's too complex for you to understand.") + else if(get_dist(patient, user) <= 2 || isobserver(user) || issilicon(user)) + . += healthscan(user, patient, advanced = advanced, tochat = FALSE) + else + . += span_notice("You are too far away to read the display.") + +/obj/machinery/computer/vitals_reader/Initialize(mapload, obj/item/circuitboard/C) + . = ..() + register_context() + +/obj/machinery/computer/vitals_reader/Destroy() + unset_patient() + return ..() + +/obj/machinery/computer/vitals_reader/add_context(atom/source, list/context, obj/item/held_item, mob/user) + if(isnull(held_item) || (held_item.item_flags & SURGICAL_TOOL)) + if(interaction_flags_atom & INTERACT_ATOM_ATTACK_HAND) + context[SCREENTIP_CONTEXT_LMB] = "Toggle readout" + else if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "Detach" + if(!isnull(patient)) + context[SCREENTIP_CONTEXT_SHIFT_LMB] = "Examine vitals" + return CONTEXTUAL_SCREENTIP_SET + +/obj/machinery/computer/vitals_reader/AIShiftClick(mob/user) + // Lets AIs perform healthscans on people indirectly (they can't examine) + if(is_operational && !isnull(patient)) + healthscan(user, patient, advanced = advanced) + +#define LOWER_BAR_OFFSET -3 + +/// Returns overlays to be used when active but without a patient detected +/obj/machinery/computer/vitals_reader/proc/get_scanning_overlays() + return list( + construct_overlay("unknown"), + construct_overlay("scanning"), + ) + +/** + * Returns all overlays to be shown when a simple / basic animal patient is detected + * + * * hp_color - color being used for general, overrall health + */ +/obj/machinery/computer/vitals_reader/proc/get_simple_mob_overlays(hp_color) + return list( + construct_overlay("mob", hp_color), + construct_overlay("blood", COLOR_GRAY), + construct_overlay("bar9", COLOR_GRAY), + construct_overlay("bar9", COLOR_GRAY, LOWER_BAR_OFFSET), + ) + +/** + * Returns all overlays to be shown when a humanoid patient is detected + * + * * hp_color - color being used for general, overrall health + */ +/obj/machinery/computer/vitals_reader/proc/get_humanoid_overlays(hp_color) + var/list/returned_overlays = list() + + for(var/body_zone in BODY_ZONES_ALL) + var/obj/item/bodypart/real_part = patient.get_bodypart(body_zone) + var/bodypart_color = isnull(real_part) ? COLOR_GRAY : percent_to_color((real_part.brute_dam + real_part.burn_dam) / real_part.max_damage) + returned_overlays += construct_overlay("human_[body_zone]", bodypart_color) + + if(HAS_TRAIT(patient, TRAIT_NOBLOOD)) + returned_overlays += construct_overlay("blood", COLOR_GRAY) + else + var/blood_color = "#a51919" + switch((patient.blood_volume - BLOOD_VOLUME_SURVIVE) / (BLOOD_VOLUME_NORMAL - BLOOD_VOLUME_SURVIVE)) + if(-INFINITY to 0.2) + blood_color = "#a1a1a1" + if(0.2 to 0.4) + blood_color = "#a18282" + if(0.4 to 0.6) + blood_color = "#a16363" + if(0.6 to 0.8) + blood_color = "#a14444" + if(0.8 to INFINITY) + blood_color = "#a51919" + + returned_overlays += construct_overlay("blood", blood_color) + + if(HAS_TRAIT(patient, TRAIT_NOBREATH)) + returned_overlays += construct_overlay("bar9", COLOR_GRAY) + else + var/oxy_percent = patient.getOxyLoss() / patient.maxHealth + returned_overlays += construct_overlay(percent_to_bar(oxy_percent), "#2A72AA") + + if(HAS_TRAIT(patient, TRAIT_TOXIMMUNE)) + returned_overlays += construct_overlay("bar9", COLOR_GRAY, LOWER_BAR_OFFSET) + else + var/tox_percent = patient.getToxLoss() / patient.maxHealth + returned_overlays += construct_overlay(percent_to_bar(tox_percent), "#5d9c11", LOWER_BAR_OFFSET) + + return returned_overlays + +/obj/machinery/computer/vitals_reader/update_overlays() + . = ..() + if(!active || !is_operational) + return + + if(isnull(patient)) + . += get_scanning_overlays() + + else + var/ekg_icon_state = "ekg" + var/resp_icon_state = (patient.losebreath || HAS_TRAIT(patient, TRAIT_NOBREATH)) ? "resp_flat" : "resp" + if(!patient.appears_alive()) + ekg_icon_state = "ekg_flat" + resp_icon_state = "resp_flat" + else if(ishuman(patient)) + var/mob/living/carbon/human/human_patient = patient + switch(human_patient.get_pretend_heart_rate()) + if(0) + ekg_icon_state = "ekg_flat" + resp_icon_state = "resp_flat" + if(100 to INFINITY) + ekg_icon_state = "ekg_fast" + + var/hp_color = percent_to_color((patient.maxHealth - patient.health) / patient.maxHealth) + . += construct_overlay(ekg_icon_state, hp_color) + . += construct_overlay(resp_icon_state, "#00f7ff") + + if(ishuman(patient)) + . += get_humanoid_overlays(hp_color) + else + . += get_simple_mob_overlays(hp_color) + + . += emissive_appearance(icon, "outline", src, alpha = src.alpha) + +/// Converts a percentage to a color +/obj/machinery/computer/vitals_reader/proc/percent_to_color(percent) + if(machine_stat & (EMPED|EMAGGED|BROKEN)) + percent = rand(1, 100) * 0.01 + if(percent == 0) + return "#2A72AA" + + switch(percent) + if(0 to 0.125) + return "#A6BD00" + if(0.125 to 0.25) + return "#BDA600" + if(0.25 to 0.375) + return "#BD7E00" + if(0.375 to 0.5) + return "#BD4200" + + return "#BD0600" + +/// Converts a percentage to a bar icon state +/obj/machinery/computer/vitals_reader/proc/percent_to_bar(percent) + if(machine_stat & (EMPED|EMAGGED|BROKEN)) + percent = rand(1, 100) * 0.01 + if(percent >= 1) + return "bar9" + if(percent <= 0) + return "bar1" + + switch(percent) + if(0 to 0.125) + return "bar1" + if(0.125 to 0.25) + return "bar2" + if(0.25 to 0.375) + return "bar3" + if(0.375 to 0.5) + return "bar4" + if(0.5 to 0.625) + return "bar5" + if(0.625 to 0.75) + return "bar6" + if(0.75 to 0.875) + return "bar7" + if(0.875 to 1) + return "bar8" + + return "bar9" // ?? + +/** + * Helper to construct an overlay for the vitals display + * + * * state_to_use - icon state to use, required + * * color_to_use - color to use, optional + * * y_offset - offset to apply to the y position of the overlay, defaults to 0 + */ +/obj/machinery/computer/vitals_reader/proc/construct_overlay(state_to_use, color_to_use, y_offset = 0) + var/mutable_appearance/overlay = mutable_appearance(icon, state_to_use, alpha = src.alpha) + overlay.appearance_flags |= RESET_COLOR + overlay.color = color_to_use + overlay.pixel_z += 32 + overlay.pixel_y += -32 + y_offset + return overlay + +#undef LOWER_BAR_OFFSET + +/obj/machinery/computer/vitals_reader/interact(mob/user, special_state) + . = ..() + if(.) + return . + if(!is_operational) + return . + + toggle_active() + balloon_alert(user, "readout [active ? "" : "de"]activated") + playsound(src, 'sound/machines/click.ogg', 50) + return TRUE + +/obj/machinery/computer/vitals_reader/on_set_is_operational(old_value) + if(is_operational) + return + if(active) + toggle_active() + return + update_appearance(UPDATE_OVERLAYS) + +/// Toggles whether the display is active or not +/obj/machinery/computer/vitals_reader/proc/toggle_active() + if(active) + active = FALSE + update_use_power(IDLE_POWER_USE) + unset_patient() + else + active = TRUE + update_use_power(ACTIVE_POWER_USE) + find_active_patient() + update_appearance(UPDATE_OVERLAYS) + +/** + * Recursively checks all nearby machines to find a patient to track. + * + * This can (and should be) signal driven in the future, but machines don't have a set_occupant proc yet, + * so this will do for the moment. + * + * * scan_attempts - number of times this has been called, used to prevent infinite loops + */ +/obj/machinery/computer/vitals_reader/proc/find_active_patient(scan_attempts = 0) + if(!active || !isnull(patient) || QDELETED(src)) + return + + for(var/obj/machinery/nearby_thing in view(3, src)) + if(!is_type_in_typecache(nearby_thing, connectable_typecache)) + continue + + var/mob/living/patient = nearby_thing.occupant + if(istype(nearby_thing, /obj/machinery/computer/operating)) + var/obj/machinery/computer/operating/op = nearby_thing + patient = op.table?.patient + + if(!istype(patient) || (patient.mob_biotypes & MOB_ROBOTIC)) + continue + + set_patient(patient) + return + + if(scan_attempts > 12) + toggle_active() + return + + addtimer(CALLBACK(src, PROC_REF(find_active_patient), scan_attempts + 1), 5 SECONDS) + +/// Sets the passed mob as the active patient +/// If there is already a patient, it will be unset first. +/obj/machinery/computer/vitals_reader/proc/set_patient(mob/living/new_patient) + if(!isnull(patient)) + unset_patient() + + patient = new_patient + RegisterSignals(patient, list( + COMSIG_QDELETING, + COMSIG_MOVABLE_MOVED + ), PROC_REF(unset_patient)) + RegisterSignals(patient, list( + COMSIG_CARBON_POST_REMOVE_LIMB, + COMSIG_CARBON_POST_ATTACH_LIMB, + COMSIG_LIVING_HEALTH_UPDATE, + ), PROC_REF(update_overlay_on_signal)) + update_appearance(UPDATE_OVERLAYS) + +/// Unset the current patient. +/obj/machinery/computer/vitals_reader/proc/unset_patient(...) + SIGNAL_HANDLER + if(isnull(patient)) + return + + UnregisterSignal(patient, list( + COMSIG_QDELETING, + COMSIG_MOVABLE_MOVED, + COMSIG_CARBON_POST_REMOVE_LIMB, + COMSIG_CARBON_POST_ATTACH_LIMB, + COMSIG_LIVING_HEALTH_UPDATE, + )) + + patient = null + if(QDELING(src)) + return + + update_appearance(UPDATE_OVERLAYS) + if(active) + find_active_patient() + +/// Signal proc to update the display when a signal is received. +/obj/machinery/computer/vitals_reader/proc/update_overlay_on_signal(...) + SIGNAL_HANDLER + update_appearance(UPDATE_OVERLAYS) + +/obj/machinery/vitals_reader/emp_act(severity) + . = ..() + if(. & EMP_PROTECT_SELF) + return + + set_machine_stat(machine_stat | EMPED) + addtimer(CALLBACK(src, PROC_REF(fix_emp)), (severity == EMP_HEAVY ? 150 SECONDS : 75 SECONDS)) + +/obj/machinery/vitals_reader/proc/fix_emp() + set_machine_stat(machine_stat & ~EMPED) diff --git a/monkestation/code/modules/blood_for_the_blood_gods/particle.dm b/monkestation/code/modules/blood_for_the_blood_gods/particle.dm index cd0966cfb06c..a20f12b5c38c 100644 --- a/monkestation/code/modules/blood_for_the_blood_gods/particle.dm +++ b/monkestation/code/modules/blood_for_the_blood_gods/particle.dm @@ -5,7 +5,6 @@ random_icon_states = list("drip1","drip2","drip3","drip4","drip5") plane = GAME_PLANE layer = BELOW_MOB_LAYER - should_dry = FALSE bloodiness = BLOOD_AMOUNT_PER_DECAL * 0.2 mergeable_decal = FALSE /// Splatter type we create when we bounce on the floor @@ -15,6 +14,11 @@ /// Whether or not we transfer our pixel_x and pixel_y to the splatter, only works for floor splatters though var/messy_splatter = TRUE +/obj/effect/decal/cleanable/blood/particle/Initialize(mapload) + . = ..() + if(QDELETED(loc)) + return INITIALIZE_HINT_QDEL + /obj/effect/decal/cleanable/blood/particle/can_bloodcrawl_in() return FALSE @@ -39,12 +43,13 @@ /obj/effect/decal/cleanable/blood/particle/proc/on_bounce() if(QDELETED(src)) return - if(QDELETED(loc) || !isturf(loc) || !splatter_type_floor) + else if(!isturf(loc) || QDELING(loc) || !splatter_type_floor) qdel(src) return var/obj/effect/decal/cleanable/splatter if(!ispath(splatter_type_floor, /obj/effect/decal/cleanable/blood/splatter/stacking)) splatter = new splatter_type_floor(loc) + splatter.color = color if(messy_splatter) splatter.pixel_x = src.pixel_x splatter.pixel_y = src.pixel_y @@ -52,6 +57,7 @@ var/obj/effect/decal/cleanable/blood/splatter/stacking/stacker = locate(splatter_type_floor) in loc if(!stacker) stacker = new splatter_type_floor(loc) + stacker.color = color if(messy_splatter && length(stacker.splat_overlays)) var/mutable_appearance/existing_appearance = stacker.splat_overlays[1] existing_appearance.pixel_x = src.pixel_x @@ -60,6 +66,7 @@ stacker.update_appearance(UPDATE_ICON) else var/obj/effect/decal/cleanable/blood/splatter/stacking/other_splatter = new splatter_type_floor() + other_splatter.color = color if(messy_splatter && length(other_splatter.splat_overlays)) var/mutable_appearance/existing_appearance = other_splatter.splat_overlays[1] existing_appearance.pixel_x = src.pixel_x @@ -74,7 +81,7 @@ qdel(src) /obj/effect/decal/cleanable/blood/particle/proc/on_bump(atom/bumped_atom) - if(QDELETED(src) || QDELETED(bumped_atom) || !isturf(loc) || !splatter_type_wall) + if(QDELETED(src) || !isturf(loc) || QDELING(loc) || QDELETED(bumped_atom) || !splatter_type_wall) return if(iswallturf(bumped_atom)) //Adjust pixel offset to make splatters appear on the wall @@ -82,6 +89,7 @@ var/dir_to_wall = get_dir(src, bumped_atom) final_splatter.pixel_x = (dir_to_wall & EAST ? world.icon_size : (dir_to_wall & WEST ? -world.icon_size : 0)) final_splatter.pixel_y = (dir_to_wall & NORTH ? world.icon_size : (dir_to_wall & SOUTH ? -world.icon_size : 0)) + final_splatter.color = color var/list/blood_dna = GET_ATOM_BLOOD_DNA(src) if(blood_dna) final_splatter.add_blood_DNA(blood_dna) @@ -95,6 +103,7 @@ return var/obj/effect/decal/cleanable/blood/splatter/over_window/final_splatter = new splatter_type_wall() final_splatter.forceMove(the_window) + final_splatter.color = color the_window.vis_contents += final_splatter the_window.bloodied = TRUE qdel(src) @@ -106,12 +115,15 @@ /// Listing containing overlays of all the splatters we've merged with var/list/splat_overlays = list() -/obj/effect/decal/cleanable/blood/splatter/stacking/Initialize(mapload) +/obj/effect/decal/cleanable/blood/splatter/stacking/Initialize(mapload, blood_color = COLOR_BLOOD) + color = blood_color . = ..() var/mutable_appearance/our_appearance = mutable_appearance(src.icon, src.icon_state) our_appearance.color = src.color our_appearance.pixel_x = src.pixel_x our_appearance.pixel_y = src.pixel_y + if(glows) + our_appearance.plane = EMISSIVE_PLANE icon_state = null color = null pixel_x = 0 @@ -140,8 +152,8 @@ desc = "Raining blood, from a lacerated sky, bleeding its horror!" icon_state = "line" random_icon_states = null - dryname = "dried blood line" - drydesc = "Creating my structure - Now I shall reign in blood!" + base_name = "dried blood line" + dry_desc = "Creating my structure - Now I shall reign in blood!" /obj/effect/decal/cleanable/blood/line/Initialize(mapload, direction) if(!isnull(direction)) diff --git a/monkestation/code/modules/blood_for_the_blood_gods/slasher/abilities/blood_walk.dm b/monkestation/code/modules/blood_for_the_blood_gods/slasher/abilities/blood_walk.dm index e846a42139a0..f07316b9eec7 100644 --- a/monkestation/code/modules/blood_for_the_blood_gods/slasher/abilities/blood_walk.dm +++ b/monkestation/code/modules/blood_for_the_blood_gods/slasher/abilities/blood_walk.dm @@ -36,17 +36,6 @@ /datum/status_effect/blood_trial/proc/on_move(atom/movable/mover, turf/old_loc) var/turf/oldLocTurf = get_turf(old_loc) - if(prob(5)) - for(var/mob/living/carbon/human/human in view(7, oldLocTurf)) - if(human == owner) - continue - human.emote("scream") - human.stamina.adjust(-5) - human.Shake(duration = 3 SECONDS) - human.emote("cries blood") - var/turf/turf = get_turf(human) - var/list/blood_drop = list(human.get_blood_id() = 3) - turf.add_liquid_list(blood_drop, FALSE, 300) var/obj/effect/decal/cleanable/blood/footprints/oldLocFP = find_pool_by_blood_state(oldLocTurf, /obj/effect/decal/cleanable/blood/footprints) if(oldLocFP) diff --git a/monkestation/code/modules/blood_for_the_blood_gods/slasher/abilities/recall_machette.dm b/monkestation/code/modules/blood_for_the_blood_gods/slasher/abilities/recall_machette.dm index f5c53dfdbf66..9e0a5eef5f15 100644 --- a/monkestation/code/modules/blood_for_the_blood_gods/slasher/abilities/recall_machette.dm +++ b/monkestation/code/modules/blood_for_the_blood_gods/slasher/abilities/recall_machette.dm @@ -67,11 +67,6 @@ user.emote("scream") living_user.adjustBruteLoss(force) to_chat(user, span_warning("You scream out in pain as you hold the [src]!")) - if(ishuman(user)) - var/mob/living/carbon/human/human = user - var/turf/turf = get_turf(user) - var/list/blood_drop = list(human.get_blood_id() = 3) - turf.add_liquid_list(blood_drop, FALSE, 300) return FALSE . = ..() @@ -83,10 +78,5 @@ user.emote("scream") living_user.adjustBruteLoss(force) to_chat(user, span_warning("You scream out in pain as you hold the [src]!")) - if(ishuman(user)) - var/mob/living/carbon/human/human = user - var/turf/turf = get_turf(user) - var/list/blood_drop = list(human.get_blood_id() = 3) - turf.add_liquid_list(blood_drop, FALSE, 300) return FALSE . = ..() diff --git a/monkestation/code/modules/blood_for_the_blood_gods/slasher/abilities/soul_steal.dm b/monkestation/code/modules/blood_for_the_blood_gods/slasher/abilities/soul_steal.dm index 272978a07a84..95af858a2fa4 100644 --- a/monkestation/code/modules/blood_for_the_blood_gods/slasher/abilities/soul_steal.dm +++ b/monkestation/code/modules/blood_for_the_blood_gods/slasher/abilities/soul_steal.dm @@ -78,12 +78,12 @@ human_target.soul_sucked = TRUE - if(human_target.dna.species.use_skintones) // make them deathly white, afterall they dont have a soul anymore + if(HAS_TRAIT(human_target, TRAIT_USES_SKINTONES)) // make them deathly white, afterall they dont have a soul anymore human_target.skin_tone = "albino" human_target.dna.update_ui_block(DNA_SKIN_TONE_BLOCK) else // we dont discriminate, even skeletons can be white... (arent they already white?) - human_target.dna.features["mcolor"] = "#FFFFFF" - human_target.dna.update_uf_block(DNA_MUTANT_COLOR_BLOCK) + var/datum/color_palette/generic_colors/located = human_target.dna.color_palettes[/datum/color_palette/generic_colors] + located.mutant_color = "#FFFFFF" human_target.update_body(is_creating = TRUE) diff --git a/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_datum.dm b/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_datum.dm index 36e8ea3347ca..9d9324824c16 100644 --- a/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_datum.dm +++ b/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_datum.dm @@ -95,7 +95,7 @@ TRAIT_NOSOFTCRIT, TRAIT_NOHARDCRIT, TRAIT_AGEUSIA, - TRAIT_COLDBLOODED, + TRAIT_COLD_BLOODED, TRAIT_VIRUSIMMUNE, TRAIT_TOXIMMUNE, TRAIT_HARDLY_WOUNDED, @@ -246,7 +246,7 @@ if(old_body && ishuman(old_body)) var/mob/living/carbon/human/old_user = old_body var/datum/species/old_species = old_user.dna.species - old_species.species_traits -= DRINKSBLOOD + old_species.inherent_traits -= TRAIT_DRINKS_BLOOD //Keep track of what they were old_left_arm_unarmed_damage_low = old_left_arm.unarmed_damage_low old_left_arm_unarmed_damage_high = old_left_arm.unarmed_damage_high @@ -260,7 +260,7 @@ if(ishuman(new_body)) var/mob/living/carbon/human/new_user = new_body var/datum/species/new_species = new_user.dna.species - new_species.species_traits += DRINKSBLOOD + new_species.inherent_traits += TRAIT_DRINKS_BLOOD var/obj/item/bodypart/new_left_arm var/obj/item/bodypart/new_right_arm //Give old punch damage values @@ -408,7 +408,7 @@ var/datum/species/user_species = user.dna.species var/obj/item/bodypart/user_left_arm = user.get_bodypart(BODY_ZONE_L_ARM) var/obj/item/bodypart/user_right_arm = user.get_bodypart(BODY_ZONE_R_ARM) - user_species.species_traits += DRINKSBLOOD + user_species.inherent_traits += TRAIT_DRINKS_BLOOD user.dna?.remove_all_mutations() user_left_arm.unarmed_damage_low += 1 //lowest possible punch damage - 0 user_left_arm.unarmed_damage_high += 1 //highest possible punch damage - 9 @@ -450,7 +450,7 @@ if(ishuman(owner.current)) var/mob/living/carbon/human/user = owner.current var/datum/species/user_species = user.dna.species - user_species.species_traits -= DRINKSBLOOD + user_species.inherent_traits -= TRAIT_DRINKS_BLOOD // Remove all bloodsucker traits owner.current.remove_traits(bloodsucker_traits, BLOODSUCKER_TRAIT) // Update Health diff --git a/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_overwrites.dm b/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_overwrites.dm index 4b7131c9a119..578f90322e46 100644 --- a/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_overwrites.dm +++ b/monkestation/code/modules/bloodsuckers/bloodsucker/bloodsucker_overwrites.dm @@ -30,11 +30,6 @@ return return ..() -/mob/living/carbon/human/natural_bodytemperature_stabilization(datum/gas_mixture/environment, seconds_per_tick, times_fired) - // Return 0 as your natural temperature. Species proc handle_environment() will adjust your temperature based on this. - if(HAS_TRAIT(src, TRAIT_COLDBLOODED)) - return 0 - return ..() // Used when analyzing a Bloodsucker, Masquerade will hide brain traumas (Unless you're a Beefman) /mob/living/carbon/get_traumas() diff --git a/monkestation/code/modules/bloodsuckers/clans/venture.dm b/monkestation/code/modules/bloodsuckers/clans/venture.dm index 173e6bc7fe29..20cf06a6f0a5 100644 --- a/monkestation/code/modules/bloodsuckers/clans/venture.dm +++ b/monkestation/code/modules/bloodsuckers/clans/venture.dm @@ -60,7 +60,7 @@ vassaldatum.vassal_level++ switch(vassaldatum.vassal_level) if(2) - target.add_traits(list(TRAIT_COLDBLOODED, TRAIT_NOBREATH, TRAIT_AGEUSIA), BLOODSUCKER_TRAIT) + target.add_traits(list(TRAIT_COLD_BLOODED, TRAIT_NOBREATH, TRAIT_AGEUSIA), BLOODSUCKER_TRAIT) to_chat(target, span_notice("Your blood begins to feel cold, and as a mote of ash lands upon your tongue, you stop breathing...")) if(3) target.add_traits(list(TRAIT_NOCRITDAMAGE, TRAIT_NOSOFTCRIT), BLOODSUCKER_TRAIT) diff --git a/monkestation/code/modules/bloodsuckers/structures/bloodsucker_objects.dm b/monkestation/code/modules/bloodsuckers/structures/bloodsucker_objects.dm index c71f94b02d54..92d09ee4fcf5 100644 --- a/monkestation/code/modules/bloodsuckers/structures/bloodsucker_objects.dm +++ b/monkestation/code/modules/bloodsuckers/structures/bloodsucker_objects.dm @@ -41,7 +41,7 @@ ///Bloodbag of Bloodsucker blood (used by Vassals only) /obj/item/reagent_containers/blood/o_minus/bloodsucker name = "blood pack" - unique_blood = /datum/reagent/blood/bloodsucker + blood_type = /datum/blood_type/crew/bloodsucker /obj/item/reagent_containers/blood/o_minus/bloodsucker/examine(mob/user) . = ..() diff --git a/monkestation/code/modules/blueshift/clothing/kahraman.dm b/monkestation/code/modules/blueshift/clothing/kahraman.dm index 887920bdf9c9..310702389d48 100644 --- a/monkestation/code/modules/blueshift/clothing/kahraman.dm +++ b/monkestation/code/modules/blueshift/clothing/kahraman.dm @@ -285,9 +285,9 @@ supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON worn_icon_state = "flak" body_parts_covered = CHEST - cold_protection = CHEST|GROIN + min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT - heat_protection = CHEST|GROIN + max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT armor_type = /datum/armor/colonist_armor resistance_flags = NONE @@ -369,9 +369,9 @@ worn_icon_state = "gloves" greyscale_colors = "#3a373e" siemens_coefficient = 0.25 // Doesn't insulate you entirely, but makes you a little more resistant - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = NONE clothing_traits = list(TRAIT_QUICK_CARRY) diff --git a/monkestation/code/modules/blueshift/clothing/nova_coats.dm b/monkestation/code/modules/blueshift/clothing/nova_coats.dm index 04e73300acd3..bfd1707c4851 100644 --- a/monkestation/code/modules/blueshift/clothing/nova_coats.dm +++ b/monkestation/code/modules/blueshift/clothing/nova_coats.dm @@ -88,8 +88,8 @@ blood_overlay_type = "coat" body_parts_covered = CHEST|GROIN|LEGS|ARMS armor_type = /datum/armor/toggle_deckard - cold_protection = CHEST|GROIN|LEGS|ARMS - heat_protection = CHEST|GROIN|LEGS|ARMS + + /datum/armor/toggle_deckard melee = 25 @@ -145,8 +145,8 @@ desc = "\"You look like a good Joe.\"" icon_state = "bladerunner_neue" body_parts_covered = CHEST|GROIN|ARMS|LEGS - cold_protection = CHEST|GROIN|ARMS|LEGS - heat_protection = CHEST|ARMS|GROIN|LEGS + + icon = 'monkestation/code/modules/blueshift/icons/obj/clothing/suits.dmi' worn_icon = 'monkestation/code/modules/blueshift/icons/mob/clothing/suit.dmi' blood_overlay_type = "coat" @@ -158,7 +158,7 @@ icon = 'monkestation/code/modules/blueshift/icons/obj/clothing/suits/jacket.dmi' worn_icon = 'monkestation/code/modules/blueshift/icons/mob/clothing/suits/jacket.dmi' body_parts_covered = CHEST|ARMS - cold_protection = CHEST|ARMS + greyscale_config = /datum/greyscale_config/croptop greyscale_config_worn = /datum/greyscale_config/croptop/worn greyscale_colors = "#1d1b1b" @@ -229,7 +229,7 @@ greyscale_config_worn = /datum/greyscale_config/warm_coat/worn greyscale_colors = "#7a5f4f#d9cec7" flags_1 = IS_PLAYER_COLORABLE_1 - cold_protection = CHEST|GROIN|ARMS + body_parts_covered = CHEST|GROIN|ARMS min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON diff --git a/monkestation/code/modules/blueshift/clothing/nova_cowboy.dm b/monkestation/code/modules/blueshift/clothing/nova_cowboy.dm index 2f11d9d774ce..65afb157bbdb 100644 --- a/monkestation/code/modules/blueshift/clothing/nova_cowboy.dm +++ b/monkestation/code/modules/blueshift/clothing/nova_cowboy.dm @@ -42,7 +42,7 @@ greyscale_colors = "#c26934#8f89ae#774B2D" greyscale_config = /datum/greyscale_config/cowboy_flat_cowl greyscale_config_worn = /datum/greyscale_config/cowboy_flat_cowl/worn - cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT flags_inv = HIDEHAIR diff --git a/monkestation/code/modules/blueshift/clothing/nova_field.dm b/monkestation/code/modules/blueshift/clothing/nova_field.dm index 92b22b3c07f6..49e1a81d53b7 100644 --- a/monkestation/code/modules/blueshift/clothing/nova_field.dm +++ b/monkestation/code/modules/blueshift/clothing/nova_field.dm @@ -87,9 +87,9 @@ icon_state = "exp_corps" icon = 'monkestation/code/modules/blueshift/icons/obj/clothing/gloves.dmi' worn_icon = 'monkestation/code/modules/blueshift/icons/mob/clothing/hands.dmi' - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = FIRE_PROOF uses_advanced_reskins = FALSE @@ -114,9 +114,9 @@ icon = 'monkestation/code/modules/blueshift/icons/obj/clothing/gloves.dmi' worn_icon = 'monkestation/code/modules/blueshift/icons/mob/clothing/hands.dmi' worn_icon_state = "exp_corps" - cold_protection = HANDS + min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT - heat_protection = HANDS + max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT resistance_flags = FIRE_PROOF armor_type = /datum/armor/nitrile_expeditionary_corps @@ -152,8 +152,8 @@ icon_state = "exp_corps" body_parts_covered = CHEST|GROIN|ARMS armor_type = /datum/armor/vest_expeditionary_corps - cold_protection = CHEST|GROIN|ARMS - heat_protection = CHEST|GROIN|ARMS + + dog_fashion = null allowed = list( /obj/item/melee, diff --git a/monkestation/code/modules/blueshift/clothing/nova_heads.dm b/monkestation/code/modules/blueshift/clothing/nova_heads.dm index d0d49655c12e..0f13b9f231fd 100644 --- a/monkestation/code/modules/blueshift/clothing/nova_heads.dm +++ b/monkestation/code/modules/blueshift/clothing/nova_heads.dm @@ -117,9 +117,9 @@ desc = "Despite seeming like it's made of metal, it's actually a very cheap plastic.." armor_type = /datum/armor/imperial_ce clothing_flags = STOPSPRESSUREDAMAGE - heat_protection = HEAD + max_heat_protection_temperature = FIRE_HELM_MAX_TEMP_PROTECT - cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT icon_state = "impce" flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT @@ -175,7 +175,7 @@ worn_icon = 'monkestation/code/modules/blueshift/gags/icons/head/head.dmi' icon_state = "hood" body_parts_covered = HEAD - cold_protection = HEAD + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT flags_inv = HIDEEARS|HIDEHAIR flags_1 = IS_PLAYER_COLORABLE_1 diff --git a/monkestation/code/modules/blueshift/clothing/nova_jackets.dm b/monkestation/code/modules/blueshift/clothing/nova_jackets.dm index ab550ed6c8ee..b62a1580988c 100644 --- a/monkestation/code/modules/blueshift/clothing/nova_jackets.dm +++ b/monkestation/code/modules/blueshift/clothing/nova_jackets.dm @@ -7,7 +7,7 @@ icon_state = "bomberalt" allowed = list(/obj/item/flashlight, /obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/toy, /obj/item/storage/fancy/cigarettes, /obj/item/lighter, /obj/item/radio) body_parts_covered = CHEST|ARMS|GROIN - cold_protection = CHEST|ARMS|GROIN + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON toggle_noun = "zipper" @@ -88,8 +88,8 @@ desc = "A cozy and warm plaid flannel jacket. Praised by Lumberjacks and Truckers alike." icon_state = "flannel" body_parts_covered = CHEST|ARMS //Being a bit shorter, flannels dont cover quite as much as the rest of the woolen jackets (- GROIN) - cold_protection = CHEST|ARMS - heat_protection = CHEST|ARMS //As a plus side, they're more insulating, protecting a bit from the heat as well + + /obj/item/clothing/suit/toggle/jacket/flannel/red name = "red flannel jacket" diff --git a/monkestation/code/modules/blueshift/clothing/nova_misc.dm b/monkestation/code/modules/blueshift/clothing/nova_misc.dm index c8b18cd8f0be..39ba890481b7 100644 --- a/monkestation/code/modules/blueshift/clothing/nova_misc.dm +++ b/monkestation/code/modules/blueshift/clothing/nova_misc.dm @@ -93,7 +93,7 @@ icon_state = "chi_korea_coat" supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT /obj/item/clothing/suit/modernwintercoatthing @@ -104,7 +104,7 @@ icon_state = "modern_winter" supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT /obj/item/clothing/suit/toggle/jacket/cardigan @@ -145,7 +145,7 @@ icon_state = "expensivecoat" supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT /obj/item/clothing/suit/brownbattlecoat @@ -156,7 +156,7 @@ icon_state = "battlecoat" supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT /obj/item/clothing/suit/brownfurrich @@ -167,7 +167,7 @@ icon_state = "winter_coat" supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT armor_type = /datum/armor/suit_brownfurrich @@ -197,7 +197,7 @@ icon_state = "fallsparka" supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT /obj/item/clothing/suit/british_officer @@ -208,7 +208,7 @@ icon_state = "british_officer" supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT armor_type = /datum/armor/suit_british_officer @@ -224,7 +224,7 @@ icon_state = "modern_winter" supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT /obj/item/clothing/suit/woolcoat @@ -245,7 +245,7 @@ icon_state = "soldier" supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT armor_type = /datum/armor/suit_gautumn @@ -263,7 +263,7 @@ icon_state = "autumn" supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT armor_type = /datum/armor/suit_autumn diff --git a/monkestation/code/modules/blueshift/clothing/nova_neck.dm b/monkestation/code/modules/blueshift/clothing/nova_neck.dm index e999df7ece5b..cf85b439c148 100644 --- a/monkestation/code/modules/blueshift/clothing/nova_neck.dm +++ b/monkestation/code/modules/blueshift/clothing/nova_neck.dm @@ -156,7 +156,7 @@ icon = 'monkestation/code/modules/blueshift/icons/obj/clothing/neck.dmi' worn_icon = 'monkestation/code/modules/blueshift/icons/mob/clothing/neck.dmi' icon_state = "cowboy_poncho" - heat_protection = CHEST + /obj/item/clothing/neck/cowboylea/Initialize(mapload) . = ..() @@ -171,7 +171,7 @@ greyscale_config_worn = /datum/greyscale_config/ranger_poncho/worn greyscale_colors = "#917A57#858585" //Roughly the same color as the original non-greyscale item was flags_1 = IS_PLAYER_COLORABLE_1 - heat_protection = CHEST + /obj/item/clothing/neck/ranger_poncho/Initialize(mapload) . = ..() diff --git a/monkestation/code/modules/blueshift/clothing/nova_security.dm b/monkestation/code/modules/blueshift/clothing/nova_security.dm index 66a885a84ed4..eb62d6a8c530 100644 --- a/monkestation/code/modules/blueshift/clothing/nova_security.dm +++ b/monkestation/code/modules/blueshift/clothing/nova_security.dm @@ -277,8 +277,8 @@ icon_state = "peacekeeper_jacket" supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS - heat_protection = CHEST|GROIN|ARMS + + /obj/item/clothing/suit/armor/vest/peacekeeper/jacket/Initialize(mapload) . = ..() @@ -299,9 +299,9 @@ worn_icon_state = "peacekeeper" siemens_coefficient = 0.5 strip_delay = 20 - cold_protection = 0 + min_cold_protection_temperature = null - heat_protection = 0 + max_heat_protection_temperature = null resistance_flags = FLAMMABLE armor_type = /datum/armor/none @@ -357,9 +357,9 @@ worn_icon = 'monkestation/code/modules/blueshift/icons/mob/clothing/suit.dmi' icon_state = "cowboy_vest" body_parts_covered = CHEST|ARMS - cold_protection = CHEST|ARMS + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON - heat_protection = CHEST|ARMS + /obj/item/clothing/suit/jacket/det_suit/cowboyvest name = "blonde cowboy vest" @@ -368,9 +368,9 @@ worn_icon = 'monkestation/code/modules/blueshift/icons/mob/clothing/suit.dmi' icon_state = "cowboy_vest" body_parts_covered = CHEST|ARMS - cold_protection = CHEST|ARMS + supports_variations_flags = CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON - heat_protection = CHEST|ARMS + /obj/item/clothing/under/rank/security/detective/runner name = "runner sweater" diff --git a/monkestation/code/modules/blueshift/clothing/nova_syndicate.dm b/monkestation/code/modules/blueshift/clothing/nova_syndicate.dm index 9bb1a92ed1c6..158f2ebff0ac 100644 --- a/monkestation/code/modules/blueshift/clothing/nova_syndicate.dm +++ b/monkestation/code/modules/blueshift/clothing/nova_syndicate.dm @@ -199,7 +199,7 @@ name = "insulated tactical turtleneck skirt" desc = "A non-descript and slightly suspicious looking skirtleneck. The interior has been padded with special insulation for both warmth and protection." armor_type = /datum/armor/clothing_under/syndicate/coldres - cold_protection = CHEST|GROIN|ARMS|LEGS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT @@ -248,7 +248,7 @@ worn_icon = 'monkestation/code/modules/blueshift/icons/worn.dmi' icon_state = "syndievest_winter" body_parts_covered = CHEST|GROIN - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT resistance_flags = FIRE_PROOF diff --git a/monkestation/code/modules/blueshift/items/barber.dm b/monkestation/code/modules/blueshift/items/barber.dm index 3448f9bd87a9..293f0dd70a58 100644 --- a/monkestation/code/modules/blueshift/items/barber.dm +++ b/monkestation/code/modules/blueshift/items/barber.dm @@ -407,13 +407,6 @@ visible_message(span_notice("[user] starts to masterfully paint [target_human]!")) if(do_after(user, 20 SECONDS, target_human)) - switch(selected_mutant_color) - if("One") - target_human.dna.features["mcolor"] = selected_color - if("Two") - target_human.dna.features["mcolor1"] = selected_color - if("Three") - target_human.dna.features["mcolor2"] = selected_color target_human.regenerate_icons() item_use_power(power_use_amount, user) diff --git a/monkestation/code/modules/blueshift/mobs/misc_pets.dm b/monkestation/code/modules/blueshift/mobs/misc_pets.dm index fc733668f09d..89e46a264119 100644 --- a/monkestation/code/modules/blueshift/mobs/misc_pets.dm +++ b/monkestation/code/modules/blueshift/mobs/misc_pets.dm @@ -27,8 +27,8 @@ real_name = "Teshari" desc = "A timeless classic." unsuitable_atmos_damage = 0 - minimum_survivable_temperature = 0 - maximum_survivable_temperature = 30000 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 30000 worn_slot_flags = null /mob/living/basic/lizard/tegu diff --git a/monkestation/code/modules/blueshift/reagents/deforest.dm b/monkestation/code/modules/blueshift/reagents/deforest.dm index 556d1b96df25..546b880fa947 100644 --- a/monkestation/code/modules/blueshift/reagents/deforest.dm +++ b/monkestation/code/modules/blueshift/reagents/deforest.dm @@ -360,13 +360,13 @@ // If the target is a robot, or has muscle veins, then they get an effect similar to herignis, heating them up quite a bit if((our_guy.mob_biotypes & MOB_ROBOTIC) || HAS_TRAIT(our_guy, TRAIT_STABLEHEART)) - var/heating = mob_heating_muliplier * creation_purity * REM * seconds_per_tick + var/heating = mob_heating_muliplier * REM * seconds_per_tick our_guy.reagents?.chem_temp += heating - our_guy.adjust_bodytemperature(heating * TEMPERATURE_DAMAGE_COEFFICIENT) + our_guy.adjust_bodytemperature(heating * TEMPERATURE_DAMAGE_COEFFICIENT, max_temp = our_guy.bodytemp_heat_damage_limit) if(!ishuman(our_guy)) return var/mob/living/carbon/human/human = our_guy - human.adjust_coretemperature(heating * TEMPERATURE_DAMAGE_COEFFICIENT) + human.adjust_bodytemperature(heating * TEMPERATURE_DAMAGE_COEFFICIENT, max_temp = our_guy.bodytemp_heat_damage_limit) else our_guy.adjustOrganLoss(ORGAN_SLOT_HEART, 0.1 * REM * seconds_per_tick) @@ -398,13 +398,13 @@ // If the target is a robot, or has muscle veins, then they get an effect similar to herignis, heating them up quite a bit if((our_guy.mob_biotypes & MOB_ROBOTIC) || HAS_TRAIT(our_guy, TRAIT_STABLEHEART)) - var/heating = (mob_heating_muliplier * 2) * creation_purity * REM * seconds_per_tick + var/heating = (mob_heating_muliplier * 2) * REM * seconds_per_tick our_guy.reagents?.chem_temp += heating - our_guy.adjust_bodytemperature(heating * TEMPERATURE_DAMAGE_COEFFICIENT) + our_guy.adjust_bodytemperature(heating * TEMPERATURE_DAMAGE_COEFFICIENT, max_temp = our_guy.bodytemp_heat_damage_limit) if(!ishuman(our_guy)) return var/mob/living/carbon/human/human = our_guy - human.adjust_coretemperature(heating * TEMPERATURE_DAMAGE_COEFFICIENT) + human.adjust_bodytemperature(heating * TEMPERATURE_DAMAGE_COEFFICIENT, max_temp = our_guy.bodytemp_heat_damage_limit) else our_guy.adjustOrganLoss(ORGAN_SLOT_HEART, 1 * REM * seconds_per_tick, required_organtype = affected_organtype) our_guy.adjustToxLoss(1 * REM * seconds_per_tick, updating_health = FALSE, forced = TRUE, required_biotype = affected_biotype) diff --git a/monkestation/code/modules/blueshift/species/ashwalker.dm b/monkestation/code/modules/blueshift/species/ashwalker.dm index e897dbb54164..773eb4b40f2c 100644 --- a/monkestation/code/modules/blueshift/species/ashwalker.dm +++ b/monkestation/code/modules/blueshift/species/ashwalker.dm @@ -148,10 +148,12 @@ /obj/item/bodypart/arm/left/lizard/ashwalker brute_modifier = ASHWALKER_BRUTE_MODIFIER burn_modifier = ASHWALKER_BURN_MODIFIER + hand_traits = list(TRAIT_CHUNKYFINGERS) /obj/item/bodypart/arm/right/lizard/ashwalker brute_modifier = ASHWALKER_BRUTE_MODIFIER burn_modifier = ASHWALKER_BURN_MODIFIER + hand_traits = list(TRAIT_CHUNKYFINGERS) /obj/item/bodypart/leg/left/lizard/ashwalker brute_modifier = ASHWALKER_BRUTE_MODIFIER diff --git a/monkestation/code/modules/blueshift/wounds/muscle_wounds.dm b/monkestation/code/modules/blueshift/wounds/muscle_wounds.dm index 70df1ab6b097..fbb8da9e9982 100644 --- a/monkestation/code/modules/blueshift/wounds/muscle_wounds.dm +++ b/monkestation/code/modules/blueshift/wounds/muscle_wounds.dm @@ -9,10 +9,6 @@ wound_flags = (ACCEPTS_GAUZE) processes = TRUE - /// How much do we need to regen. Will regen faster if we're splinted and or laying down - var/regen_ticks_needed - /// Our current counter for healing - var/regen_ticks_current = 0 can_scar = FALSE @@ -70,13 +66,6 @@ if(limb.current_gauze) regen_ticks_current += (1-limb.current_gauze.splint_factor) - if(regen_ticks_current > regen_ticks_needed) - if(!victim || !limb) - qdel(src) - return - to_chat(victim, span_green("Your [parse_zone(limb.body_zone)] has regenerated its muscle!")) - remove_wound() - /// If we're a human who's punching something with a broken arm, we might hurt ourselves doing so /datum/wound/muscle/proc/attack_with_hurt_hand(mob/M, atom/target, proximity) SIGNAL_HANDLER diff --git a/monkestation/code/modules/botany/potty.dm b/monkestation/code/modules/botany/potty.dm index b55c8f53ae14..9a82db572fb0 100644 --- a/monkestation/code/modules/botany/potty.dm +++ b/monkestation/code/modules/botany/potty.dm @@ -26,6 +26,7 @@ /mob/living/basic/pet/potty/Initialize(mapload) ..() + AddComponent(/datum/component/item_receiver, list(/obj/item/reagent_containers/cup/watering_can), "happily takes") AddComponent(/datum/component/plant_tray_overlay, icon, null, null, null, null, null, null, 3, 8) AddComponent(/datum/component/plant_growing) AddComponent(/datum/component/obeys_commands, pet_commands) diff --git a/monkestation/code/modules/botany/species/apid/species.dm b/monkestation/code/modules/botany/species/apid/species.dm index cd67ebf48993..cad389f9a0dc 100644 --- a/monkestation/code/modules/botany/species/apid/species.dm +++ b/monkestation/code/modules/botany/species/apid/species.dm @@ -27,14 +27,6 @@ name = "\improper Apid" plural_form = "Apids" id = SPECIES_APID - species_traits = list(HAS_MARKINGS,) - - /* - mutant_bodyparts = list( - "apid_stripes" = "None", - "apid_headstripes" = "None", - ) - */ mutanteyes = /obj/item/organ/internal/eyes/apid @@ -46,17 +38,16 @@ inherent_traits = list( TRAIT_TACKLING_WINGED_ATTACKER, TRAIT_ANTENNAE, + TRAIT_HAS_MARKINGS, ) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG meat = /obj/item/food/meat/slab/human/mutant/apid - liked_food = VEGETABLES | MEAT | FRUIT - disliked_food = GROSS | BUGS | GORE - toxic_food = RAW | SEAFOOD changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT species_language_holder = /datum/language_holder/apid + mutanttongue = /obj/item/organ/internal/tongue/apid bodypart_overrides = list( BODY_ZONE_HEAD = /obj/item/bodypart/head/apid, BODY_ZONE_CHEST = /obj/item/bodypart/chest/apid, @@ -140,11 +131,25 @@ if(istype(attacking_item, /obj/item/melee/flyswatter)) damage_mods += 10 // Yes, a 10x damage modifier -/datum/species/apid/get_scream_sound(mob/living/carbon/human/human) - return 'sound/voice/moth/scream_moth.ogg' - /datum/species/apid/get_species_description() return "Apids are a race of bipedal bees from the jungle planet of Saltu. Due to their large bodies, they have lost the ability to fly." #undef ui_honeydisplay #undef FORMAT_HONEY_CHARGES_TEXT + +/obj/item/organ/internal/tongue/apid + name = "apid tongue" + + liked_foodtypes = VEGETABLES | MEAT | FRUIT + disliked_foodtypes = GROSS | BUGS | GORE + toxic_foodtypes = RAW | SEAFOOD + +/obj/item/organ/internal/tongue/apid/get_scream_sound() + return 'sound/voice/moth/scream_moth.ogg' + +/obj/item/organ/internal/tongue/apid/get_laugh_sound() + return pick( + 'monkestation/sound/voice/laugh/moth/mothchitter.ogg', + 'monkestation/sound/voice/laugh/moth/mothlaugh.ogg', + 'monkestation/sound/voice/laugh/moth/mothsqueak.ogg', + ) diff --git a/monkestation/code/modules/brewin_and_chewin/chewing/cooking_containers.dm b/monkestation/code/modules/brewin_and_chewin/chewing/cooking_containers.dm index 43500418a3bb..a53e907e1823 100644 --- a/monkestation/code/modules/brewin_and_chewin/chewing/cooking_containers.dm +++ b/monkestation/code/modules/brewin_and_chewin/chewing/cooking_containers.dm @@ -374,8 +374,8 @@ appliancetype = GRILL /obj/item/reagent_containers/cooking_container/bowl - name = "cooking bowl" - shortname = "cooking bowl" + name = "mixing bowl" + shortname = "mixing bowl" desc = "A bowl." icon_state = "bowl" diff --git a/monkestation/code/modules/brewin_and_chewin/chewing/fryer_overhaul.dm b/monkestation/code/modules/brewin_and_chewin/chewing/fryer_overhaul.dm index 9cdf1cd244ad..cdbda9067842 100644 --- a/monkestation/code/modules/brewin_and_chewin/chewing/fryer_overhaul.dm +++ b/monkestation/code/modules/brewin_and_chewin/chewing/fryer_overhaul.dm @@ -60,7 +60,7 @@ if(!basket) return for(var/obj/item/item as anything in basket.contents) - if(!QDELETED(item)) + if(!QDELETED(item) && !(item.type in GLOB.oilfry_blacklisted_items)) item.AddElement(/datum/element/fried_item, cook_time) if(user) basket.process_item(src, user, lower_quality_on_fail=CHEWIN_BASE_QUAL_REDUCTION, send_message=TRUE) diff --git a/monkestation/code/modules/brewin_and_chewin/chewing/recipes/fried_rice.dm b/monkestation/code/modules/brewin_and_chewin/chewing/recipes/fried_rice.dm index bc3c2d2c35ae..f21996d94c5e 100644 --- a/monkestation/code/modules/brewin_and_chewin/chewing/recipes/fried_rice.dm +++ b/monkestation/code/modules/brewin_and_chewin/chewing/recipes/fried_rice.dm @@ -15,3 +15,21 @@ list(CHEWIN_ADD_REAGENT, /datum/reagent/consumable/soysauce, 3, base=3), list(CHEWIN_USE_STOVE, J_HI, 5 SECONDS , finish_text = "You can smell fried rice!"), ) + +/datum/chewin_cooking/recipe/ikareis + cooking_container = PAN + food_category = CAT_STOVETOP + product_type = /obj/item/food/salad/ikareis + recipe_guide = "Add boiled rice to pan, some squid ink, add vegetables and sausage, cook for 20 seconds on high." + step_builder = list( + list(CHEWIN_ADD_ITEM, /obj/item/food/boiledrice, qmod=0.5), + list(CHEWIN_ADD_ITEM, /obj/item/food/canned/squid_ink, qmod=0.5), + list(CHEWIN_ADD_PRODUCE, /obj/item/food/grown/bell_pepper, qmod=0.5), + list(CHEWIN_ADD_ITEM, /obj/item/food/sausage, qmod=0.5), + + list(CHEWIN_ADD_ITEM_OPTIONAL, /obj/item/food/onion_slice, qmod=0.5), + list(CHEWIN_ADD_ITEM_OPTIONAL, /obj/item/food/pineappleslice, qmod=0.5, prod_desc = "Extra sweet!"), + list(CHEWIN_ADD_ITEM_OPTIONAL, /obj/item/food/grown/chili, qmod=0.5, prod_desc = "Extra spicy!"), + + list(CHEWIN_USE_STOVE, J_HI, 20 SECONDS , finish_text = "You can smell ikareis!"), + ) diff --git a/monkestation/code/modules/can_spessmen_feel_pain/bandage.dm b/monkestation/code/modules/can_spessmen_feel_pain/bandage.dm new file mode 100644 index 000000000000..82a3fec93447 --- /dev/null +++ b/monkestation/code/modules/can_spessmen_feel_pain/bandage.dm @@ -0,0 +1,178 @@ +/// Gets overlays to apply to the mob when damaged. +/obj/item/bodypart/proc/get_bodypart_damage_state() + if(!dmg_overlay_type) + return + + var/list/overlays + if(brutestate) + var/mutable_appearance/brute_overlay = mutable_appearance( + icon = 'icons/mob/effects/dam_mob.dmi', + icon_state = "[dmg_overlay_type]_[body_zone]_[brutestate]0", + layer = -DAMAGE_LAYER, + ) + brute_overlay.color = damage_color + LAZYADD(overlays, brute_overlay) + if(burnstate) + var/mutable_appearance/burn_overlay = mutable_appearance( + icon = 'icons/mob/effects/dam_mob.dmi', + icon_state = "[dmg_overlay_type]_[body_zone]_0[burnstate]", + layer = -DAMAGE_LAYER, + ) + LAZYADD(overlays, burn_overlay) + if(current_gauze) + var/mutable_appearance/gauze_overlay = current_gauze.build_worn_icon( + default_layer = DAMAGE_LAYER - 0.1, // proc inverts it for us + override_file = 'monkestation/icons/mob/bandage.dmi', + override_state = current_gauze.worn_icon_state, // future todo : icon states for dirty bandages as well + ) + LAZYADD(overlays, gauze_overlay) + return overlays + +/obj/item/bodypart/leg/get_bodypart_damage_state() + if(!(bodytype & BODYTYPE_DIGITIGRADE)) + return ..() + . = ..() + for(var/mutable_appearance/appearance in .) + apply_digitigrade_filters(appearance, owner, bodytype) + return . + +/** + * apply_gauze() is used to- well, apply gauze to a bodypart + * + * As of the Wounds 2 PR, all bleeding is now bodypart based rather than the old bleedstacks system, and 90% of standard bleeding comes from flesh wounds (the exception is embedded weapons). + * The same way bleeding is totaled up by bodyparts, gauze now applies to all wounds on the same part. Thus, having a slash wound, a pierce wound, and a broken bone wound would have the gauze + * applying blood staunching to the first two wounds, while also acting as a sling for the third one. Once enough blood has been absorbed or all wounds with the ACCEPTS_GAUZE flag have been cleared, + * the gauze falls off. + * + * Arguments: + * * gauze- Just the gauze stack we're taking a sheet from to apply here + */ +/obj/item/bodypart/proc/apply_gauze(obj/item/stack/medical/gauze/new_gauze) + if(!istype(new_gauze) || !new_gauze.absorption_capacity || !new_gauze.use(1)) + return + if(!isnull(current_gauze)) + remove_gauze(drop_location()) + + current_gauze = new new_gauze.type(src, 1) + current_gauze.worn_icon_state = "[body_zone][rand(1, 3)]" + if(can_bleed() && (generic_bleedstacks || cached_bleed_rate)) + current_gauze.add_mob_blood(owner) + if(!QDELETED(new_gauze)) + new_gauze.add_mob_blood(owner) + SEND_SIGNAL(src, COMSIG_BODYPART_GAUZED, current_gauze, new_gauze) + owner.update_damage_overlays() + +/obj/item/bodypart/proc/remove_gauze(atom/remove_to) + SEND_SIGNAL(src, COMSIG_BODYPART_UNGAUZED, current_gauze) + if(remove_to) + current_gauze.forceMove(remove_to) + else + current_gauze.moveToNullspace() + if(can_bleed() && (generic_bleedstacks || cached_bleed_rate)) + current_gauze.add_mob_blood(owner) + current_gauze.worn_icon_state = initial(current_gauze.worn_icon_state) + current_gauze.update_appearance() + . = current_gauze + current_gauze = null + owner.update_damage_overlays() + return . + +/** + * seep_gauze() is for when a gauze wrapping absorbs blood or pus from wounds, lowering its absorption capacity. + * + * The passed amount of seepage is deducted from the bandage's absorption capacity, and if we reach a negative absorption capacity, the bandages falls off and we're left with nothing. + * + * Arguments: + * * seep_amt - How much absorption capacity we're removing from our current bandages (think, how much blood or pus are we soaking up this tick?) + */ +/obj/item/bodypart/proc/seep_gauze(seep_amt = 0) + if(!current_gauze) + return + current_gauze.absorption_capacity -= seep_amt + current_gauze.update_appearance(UPDATE_NAME) + if(current_gauze.absorption_capacity > 0) + return + owner.visible_message( + span_danger("[current_gauze] on [owner]'s [name] falls away in rags."), + span_warning("[current_gauze] on your [name] falls away in rags."), + vision_distance = COMBAT_MESSAGE_RANGE, + ) + remove_gauze(drop_location()) + owner.update_damage_overlays() + +/** + * Helper for someone helping to remove our gauze + */ +/obj/item/bodypart/proc/help_remove_gauze(mob/living/helper) + if(!istype(helper)) + return + if(helper.incapacitated()) + return + if(!helper.can_perform_action(owner, NEED_HANDS|FORBID_TELEKINESIS_REACH)) // telekinetic removal can be added later + return + + var/whose = helper == owner ? "your" : "[owner]'s" + helper.visible_message( + span_notice("[helper] starts carefully removing [current_gauze] from [whose] [plaintext_zone]."), + span_notice("You start carefully removing [current_gauze] from [whose] [plaintext_zone]..."), + vision_distance = COMBAT_MESSAGE_RANGE, + ) + helper.balloon_alert(helper, "removing gauze...") + if(helper != owner) + helper.balloon_alert(owner, "removing your gauze...") + + if(!do_after(helper, 3 SECONDS, owner)) + return + + if(!current_gauze) + return + + var/theirs = helper == owner ? helper.p_their() : "[owner]'s" + helper.visible_message( + span_notice("[helper] finishes removing [current_gauze] from [theirs] [plaintext_zone]."), + span_notice("You finish removing [current_gauze] from [theirs] [plaintext_zone]."), + vision_distance = COMBAT_MESSAGE_RANGE, + ) + + helper.balloon_alert(helper, "gauzed removed") + if(helper != owner) + helper.balloon_alert(owner, "gauze removed") + + helper.put_in_hands(remove_gauze()) + +/obj/item/proc/apply_digitigrade_filters(mutable_appearance/appearance, mob/living/carbon/wearer = loc, bodytype) + if(!istype(wearer) || !(bodytype & BODYTYPE_DIGITIGRADE)) + return + + var/static/list/icon/masks_and_shading + if(isnull(masks_and_shading)) + masks_and_shading = list( + "[NORTH]" = list( + "mask" = icon('icons/effects/digi_filters.dmi', "digi", NORTH), + "shading" = icon('icons/effects/digi_filters.dmi', "digi_shading", NORTH), + "size" = 1, + ), + "[SOUTH]" = list( + "mask" = icon('icons/effects/digi_filters.dmi', "digi", SOUTH), + "shading" = icon('icons/effects/digi_filters.dmi', "digi_shading", SOUTH), + "size" = 1, + ), + "[EAST]" = list( + "mask" = icon('icons/effects/digi_filters.dmi', "digi", EAST), + "shading" = icon('icons/effects/digi_filters.dmi', "digi_shading", EAST), + "size" = 127, + ), + "[WEST]" = list( + "mask" = icon('icons/effects/digi_filters.dmi', "digi", WEST), + "shading" = icon('icons/effects/digi_filters.dmi', "digi_shading", WEST), + "size" = 127, + ), + ) + + var/dir_to_use = ISDIAGONALDIR(wearer.dir) ? (wearer.dir & (EAST|WEST)) : wearer.dir + var/icon/icon_to_use = masks_and_shading["[dir_to_use]"]["mask"] + var/icon/shading_to_use = masks_and_shading["[dir_to_use]"]["shading"] + var/size = masks_and_shading["[dir_to_use]"]["size"] + + appearance.add_filter("Digitigrade", 1, displacement_map_filter(icon = icon_to_use, size = size)) + appearance.add_filter("Digitigrade_shading", 1, layering_filter(icon = shading_to_use, blend_mode = BLEND_MULTIPLY)) diff --git a/monkestation/code/modules/can_spessmen_feel_pain/pain/_base.dm b/monkestation/code/modules/can_spessmen_feel_pain/pain/_base.dm index f036f5a7afae..43f917a3340d 100644 --- a/monkestation/code/modules/can_spessmen_feel_pain/pain/_base.dm +++ b/monkestation/code/modules/can_spessmen_feel_pain/pain/_base.dm @@ -22,10 +22,14 @@ /// Amount of shock building up from higher levels of pain /// When greater than current health, we go into shock var/shock_buildup = 0 + /// Tracks how many successful heart attack rolls in a row + VAR_FINAL/heart_attack_counter = 0 /// Cooldown to track the last time we lost pain. COOLDOWN_DECLARE(time_since_last_pain_loss) /// Cooldown to track last time we sent a pain message. COOLDOWN_DECLARE(time_since_last_pain_message) + /// Cooldown to track last time heart attack counter went up. + COOLDOWN_DECLARE(time_since_last_heart_attack_counter) #ifdef TESTING /// For testing. Does this pain datum print testing messages when it happens? @@ -84,11 +88,10 @@ RegisterSignal(parent, COMSIG_LIVING_POST_FULLY_HEAL, PROC_REF(remove_all_pain)) RegisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(add_damage_pain)) RegisterSignal(parent, COMSIG_MOB_STATCHANGE, PROC_REF(on_parent_statchance)) - RegisterSignals(parent, list(COMSIG_LIVING_SET_BODY_POSITION, COMSIG_LIVING_SET_BUCKLED), PROC_REF(check_lying_pain_modifier)) RegisterSignals(parent, list(SIGNAL_ADDTRAIT(TRAIT_NO_PAIN_EFFECTS), SIGNAL_REMOVETRAIT(TRAIT_NO_PAIN_EFFECTS)), PROC_REF(refresh_pain_attributes)) - - if(ishuman(parent)) - RegisterSignal(parent, COMSIG_HUMAN_BURNING, PROC_REF(on_burn_tick)) + RegisterSignal(parent, COMSIG_LIVING_TREAT_MESSAGE, PROC_REF(handle_message)) + RegisterSignal(parent, COMSIG_MOB_FIRED_GUN, PROC_REF(on_mob_fired_gun)) + RegisterSignal(parent, COMSIG_LIVING_REVIVE, PROC_REF(revived)) /** * Unregister all of our signals from our parent when we're done, if we have signals to unregister. @@ -99,12 +102,12 @@ COMSIG_CARBON_GAIN_WOUND, COMSIG_CARBON_LOSE_WOUND, COMSIG_CARBON_REMOVE_LIMB, - COMSIG_HUMAN_BURNING, COMSIG_LIVING_HEALTHSCAN, COMSIG_LIVING_POST_FULLY_HEAL, - COMSIG_LIVING_SET_BODY_POSITION, - COMSIG_LIVING_SET_BUCKLED, + COMSIG_LIVING_REVIVE, + COMSIG_LIVING_TREAT_MESSAGE, COMSIG_MOB_APPLY_DAMAGE, + COMSIG_MOB_FIRED_GUN, COMSIG_MOB_STATCHANGE, SIGNAL_ADDTRAIT(TRAIT_NO_PAIN_EFFECTS), SIGNAL_REMOVETRAIT(TRAIT_NO_PAIN_EFFECTS), @@ -218,6 +221,14 @@ pain_modifier = 1 for(var/mod in pain_mods) pain_modifier *= pain_mods[mod] + // Throw alert if a drug specifically is numbing us + if(pain_modifier < 0.75) + for(var/datum/reagent/med as anything in parent.reagents.reagent_list) + if(med.pain_modifier <= 0.5) + parent.throw_alert("numbed", /atom/movable/screen/alert/numbed) + break + else + parent.clear_alert("numbed") return old_pain_mod != pain_modifier /** @@ -234,9 +245,9 @@ // No pain at all if(amount == 0) - return + return FALSE if(amount > 0 && (parent.status_flags & GODMODE)) - return + return FALSE for(var/zone in shuffle(def_zones)) var/adjusted_amount = round(amount, 0.01) @@ -244,18 +255,22 @@ if(isnull(adjusted_bodypart)) // it's valid - for if we're passed a zone we don't have continue + var/current_amount = adjusted_bodypart.pain + // Pain is negative (healing) if(adjusted_amount < 0) // Pain is negative and we're at min pain - if(adjusted_bodypart.pain <= adjusted_bodypart.min_pain) + if(current_amount <= adjusted_bodypart.min_pain) continue // Pain is negative and we're above soft cap, incraese the healing amount greatly - if(adjusted_bodypart.pain >= adjusted_bodypart.soft_max_pain) - adjusted_amount *= 3 + if(current_amount >= adjusted_bodypart.soft_max_pain) + adjusted_amount *= 2 * (current_amount / adjusted_bodypart.soft_max_pain) // Pain is positive (dealing) else - // Adjust incoming dealt pain by modifiers + // Pain is positive and we're at the soft cap, reduce the incoming pain + if(current_amount >= adjusted_bodypart.soft_max_pain) + adjusted_amount *= 0.75 * (adjusted_bodypart.soft_max_pain / current_amount) adjusted_amount = round(adjusted_amount * pain_modifier * adjusted_bodypart.bodypart_pain_modifier, 0.01) // Pain modifiers results in us taking 0 pain // (If someone adds a negative pain mod and causes "inverse pain" (which you shouldn't) this needs to go) @@ -271,7 +286,7 @@ #endif // Actually do the pain addition / subtraction here - adjusted_bodypart.pain = max(adjusted_bodypart.pain + adjusted_amount, adjusted_bodypart.min_pain) + adjusted_bodypart.pain = max(current_amount + adjusted_amount, adjusted_bodypart.min_pain) if(adjusted_amount > 0) INVOKE_ASYNC(src, PROC_REF(on_pain_gain), adjusted_bodypart, amount, dam_type) @@ -316,16 +331,18 @@ * affected_part - the bodypart that gained the pain * amount - amount of pain that was gained, post-[pain_modifier] applied */ -/datum/pain/proc/on_pain_gain(obj/item/bodypart/affected_part, amount, type) - affected_part.on_gain_pain_effects(amount) +/datum/pain/proc/on_pain_gain(obj/item/bodypart/affected_part, amount, dam_type) + affected_part.on_gain_pain_effects(amount, dam_type) refresh_pain_attributes() - SEND_SIGNAL(parent, COMSIG_CARBON_PAIN_GAINED, affected_part, amount, type) - COOLDOWN_START(src, time_since_last_pain_loss, 30 SECONDS) + SEND_SIGNAL(parent, COMSIG_CARBON_PAIN_GAINED, affected_part, amount, dam_type) + COOLDOWN_START(src, time_since_last_pain_loss, 60 SECONDS) + if(amount > PAIN_LIMB_MAX * 0.25) + parent.pain_emote("scream", 5 SECONDS) + parent.flash_pain_overlay(2) - if(amount > 12 && prob(25)) - do_pain_emote("scream", 5 SECONDS) - else if(amount > 6 && prob(10)) - do_pain_emote() + else if(amount > PAIN_LIMB_MAX * 0.1) + parent.pain_emote(pick("wince", "gasp", "grimace", "inhale_s", "exhale_s", "flinch"), 3 SECONDS) + parent.flash_pain_overlay(1) /** * Called when pain is lost, if the mob did not lose pain in the last 60 seconds. @@ -363,7 +380,7 @@ SIGNAL_HANDLER - if(damage <= 0 || (parent.status_flags & GODMODE)) + if(damage <= 2.5 || (parent.status_flags & GODMODE)) return if(isbodypart(def_zone)) var/obj/item/bodypart/targeted_part = def_zone @@ -375,12 +392,12 @@ // Attacks with a wound bonus add additional pain (usually, like 2-5) // (Note that if they also succeed in applying a wound, more pain comes from that) // Also, sharp attacks apply a smidge extra pain - var/pain = (2 * damage) + (0.1 * max(wound_bonus + bare_wound_bonus, 1)) * (sharpness ? 1.2 : 1) + var/pain = ((100 - blocked) / 100) * ((10 * damage) ** 0.66 + (0.2 * max(wound_bonus + bare_wound_bonus - parent.getarmor(def_zone, WOUND), 0))) * (sharpness ? 1.2 : 1) switch(damagetype) // Brute pain is dealt to the target zone // pain is just divided by a random number, for variance if(BRUTE) - pain *= (rand(60, 80) / 100) + pain *= pick(0.6, 0.7, 0.8) // Burn pain is dealt to the target zone // pain is lower for weaker burns, but scales up for more damaging burns @@ -442,33 +459,12 @@ // // Note: 99% of sources of oxydamage is done through adjustoxyloss, and as such doesn't go through this if(OXY) - if(HAS_TRAIT(parent, TRAIT_NOBREATH)) - return - def_zone = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST) - var/obj/item/organ/internal/lungs/our_lungs = source.get_organ_slot(ORGAN_SLOT_LUNGS) - if(our_lungs) - switch(our_lungs.damage) - if(20 to 50) - pain += 1 - if(50 to 80) - pain += 2 - if(80 to INFINITY) - pain += 3 - else - pain += 5 - - switch(parent.getOxyLoss()) - if(0 to 20) - pain = 0 - if(20 to 50) - pain += 1 - if(50 to INFINITY) - pain += 3 + return // No pain from stamina loss // In the future stamina can probably cause very sharp pain and replace stamcrit, // but the system will require much finer tuning before then - if(STAMINA) + if(STAMINA, PAIN) return // Head pain causes brain damage, so brain damage causes no pain (to prevent death spirals) @@ -547,105 +543,159 @@ if(checked_bodypart.pain_feedback(seconds_per_tick, no_recent_pain)) COOLDOWN_START(src, time_since_last_pain_message, 12 SECONDS) - if(!has_pain) + if(!has_pain && (shock_buildup <= -30) && !HAS_TRAIT_FROM(parent, TRAIT_LABOURED_BREATHING, PAINSHOCK)) // no-op if none of our bodyparts are in pain return - var/curr_pain = get_average_pain() - switch(curr_pain) - if(-INFINITY to 10) - shock_buildup = max(shock_buildup - 3, -30) // staying out of pain for a while gives you a small resiliency to shock (~1 minute) - - if(10 to 25) - shock_buildup = max(shock_buildup - 1, -30) - - if(25 to 40) + var/shock_mod = max(pain_modifier, 0.33) + if(HAS_TRAIT(parent, TRAIT_ABATES_SHOCK)) + shock_mod *= 0.5 + if(parent.health > 0) + shock_mod *= 0.25 + if(parent.health <= parent.maxHealth * -2 || (!HAS_TRAIT(parent, TRAIT_NOBLOOD) && parent.blood_volume < BLOOD_VOLUME_BAD)) + shock_mod *= 1.5 + if(parent.health <= parent.maxHealth * -4 || (!HAS_TRAIT(parent, TRAIT_NOBLOOD) && parent.blood_volume < BLOOD_VOLUME_SURVIVE)) + shock_mod *= 2 // stacks with above + var/curr_pain = get_total_pain() + if(curr_pain < PAIN_LIMB_MAX * 0.5) + parent.adjust_pain_shock(-3 * seconds_per_tick) // staying out of pain for a while gives you a small resiliency to shock (~1 minute) + else if(curr_pain < PAIN_LIMB_MAX) + parent.adjust_pain_shock(-1 * seconds_per_tick) + else if(curr_pain < PAIN_LIMB_MAX * 2) + if(shock_buildup <= 30) + parent.adjust_pain_shock(0.5 * shock_mod * seconds_per_tick) + else if(curr_pain < PAIN_LIMB_MAX * 4) + if(shock_buildup <= 65) + parent.adjust_pain_shock(1 * shock_mod * seconds_per_tick) + if(SPT_PROB(2, seconds_per_tick)) + do_pain_message(span_userdanger(pick("It hurts."))) + else + parent.adjust_pain_shock(clamp(round(0.5 * (curr_pain / PAIN_LIMB_MAX), 0.1), 1.5, 8) * shock_mod * seconds_per_tick) + if(SPT_PROB(2, seconds_per_tick)) + do_pain_message(span_userdanger(pick("Stop the pain!", "It hurts!"))) + + switch(shock_buildup) + if(10 to 60) + parent.adjust_bodytemperature(-5 * seconds_per_tick, min_temp = parent.bodytemp_cold_damage_limit + 5) + if(60 to 120) if(SPT_PROB(2, seconds_per_tick)) - do_pain_message(span_danger(pick("Everything aches.", "Everything feels sore."))) - - if(40 to 70) - if(!HAS_TRAIT(parent, TRAIT_NO_SHOCK_BUILDUP)) - shock_buildup += 1 + do_pain_message(span_bolddanger(pick("It hurts.", "You really need some painkillers."))) + if(SPT_PROB(4, seconds_per_tick)) + do_pain_message(span_warning(pick("You feel cold!", "You feel sweaty!"))) + parent.pain_emote("shiver", 3 SECONDS) + parent.adjust_bodytemperature(-10 * seconds_per_tick, min_temp = parent.bodytemp_cold_damage_limit - 5) + if(120 to 180) if(SPT_PROB(2, seconds_per_tick)) - do_pain_message(span_bolddanger(pick("Everything hurts.", "Everything feels very sore.", "It hurts."))) + do_pain_message(span_userdanger(pick("Stop the pain!", "It hurts!", "You need painkillers now!"))) + if(SPT_PROB(4, seconds_per_tick)) + do_pain_message(span_warning("You feel freezing!")) + parent.pain_emote("shiver", 3 SECONDS) + parent.adjust_bodytemperature(-20 * seconds_per_tick, min_temp = parent.bodytemp_cold_damage_limit - 20) + + if((shock_buildup >= 20 || curr_pain >= PAIN_LIMB_MAX) && !just_cant_feel_anything) + if(SPT_PROB(min(curr_pain / 5, 24), seconds_per_tick)) + parent.adjust_jitter_up_to(5 SECONDS * pain_modifier, 30 SECONDS) + if(SPT_PROB(min(curr_pain / 10, 12), seconds_per_tick)) + parent.adjust_dizzy_up_to(5 SECONDS * pain_modifier, 30 SECONDS) + if(SPT_PROB(min(curr_pain / 20, 6), seconds_per_tick)) // pain applies its own stutter + parent.adjust_stutter_up_to(5 SECONDS * pain_modifier, 30 SECONDS) + + if(shock_buildup >= 40 && parent.stat != HARD_CRIT) + if(SPT_PROB(shock_buildup / 60, seconds_per_tick)) + //parent.vomit(VOMIT_CATEGORY_KNOCKDOWN, lost_nutrition = 7.5) + parent.Knockdown(rand(3 SECONDS, 6 SECONDS)) + + if(shock_buildup >= 60 || curr_pain >= PAIN_CHEST_MAX) + if(SPT_PROB(shock_buildup / 20, seconds_per_tick) && !parent.IsParalyzed() && parent.Paralyze(rand(2 SECONDS, 8 SECONDS))) + parent.visible_message( + span_warning("[parent]'s body falls limp!"), + span_warning("Your body [just_cant_feel_anything ? "goes" : "falls"] limp!"), + + ) + if(SPT_PROB(shock_buildup / 20, seconds_per_tick)) + parent.adjust_confusion_up_to(8 SECONDS * pain_modifier, 24 SECONDS) + + if((shock_buildup >= 120 || curr_pain >= PAIN_CHEST_MAX * 2) && SPT_PROB(shock_buildup / 40, seconds_per_tick) && parent.stat != HARD_CRIT) + if(!parent.IsUnconscious() && parent.Unconscious(rand(4 SECONDS, 16 SECONDS))) + parent.visible_message( + span_warning("[parent] falls unconscious!"), + span_warning(pick("You black out!", "You feel like you're about to die!", "You lose consciousness!")), + + ) + + // This is death + if(shock_buildup >= 120 && !parent.undergoing_cardiac_arrest()) + var/heart_attack_prob = 0 + if(parent.health <= parent.maxHealth * -1) + heart_attack_prob += abs(parent.health + parent.maxHealth) * 0.1 + if(shock_buildup >= 180) + heart_attack_prob += (shock_buildup * 0.1) + if(SPT_PROB(min(20, heart_attack_prob), seconds_per_tick)) + if(!COOLDOWN_FINISHED(src, time_since_last_heart_attack_counter)) + parent.losebreath += 1 + else if(!parent.can_heartattack()) + parent.losebreath += 4 + else if(heart_attack_counter >= 3) + to_chat(parent, span_userdanger("Your heart stops!")) + if(!parent.incapacitated()) + parent.visible_message(span_danger("[parent] grabs at [parent.p_their()] chest!"), ignored_mobs = parent) + parent.set_heartattack(TRUE) + heart_attack_counter = -2 + else + COOLDOWN_START(src, time_since_last_heart_attack_counter, 6 SECONDS) + parent.losebreath += 1 + heart_attack_counter += 1 + switch(heart_attack_counter) + if(-INFINITY to 0) + pass() + if(1) + to_chat(parent, span_userdanger("You feel your heart beat irregularly.")) + if(2) + to_chat(parent, span_userdanger("You feel your heart skip a beat.")) + else + to_chat(parent, span_userdanger("You feel your body shutting down!")) + else + heart_attack_counter = 0 - if(70 to INFINITY) - if(!HAS_TRAIT(parent, TRAIT_NO_SHOCK_BUILDUP)) - shock_buildup += 3 - if(SPT_PROB(2, seconds_per_tick)) - do_pain_message(span_userdanger(pick("Stop the pain!", "Everything hurts!"))) - - // If shock buildup exceeds our health + 30 ticks then well, we enter shock - // This means at 100 health you can be in moderate pain for 130 ticks / 260 seconds / ~4 minutes before falling into shock - if(shock_buildup >= (parent.health + 30) \ - && curr_pain >= 50 \ - && !HAS_TRAIT(parent, TRAIT_NO_SHOCK_BUILDUP) \ - && !is_undergoing_shock() \ - && !parent.undergoing_cardiac_arrest() \ - ) - parent.infect_disease_predefined(DISEASE_SHOCK, TRUE, "[ROUND_TIME()] Inflicted with Pain Shock [key_name(parent)]") - to_chat(parent, span_userdanger("You feel your body start to shut down!")) - if(parent.stat == CONSCIOUS && !parent.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB) && !HAS_TRAIT(parent, TRAIT_NO_PAIN_EFFECTS)) - parent.visible_message(span_danger("[parent] grabs at their chest and stares into the distance as they go into shock!"), ignored_mobs = parent) - shock_buildup = -200 // requires another 200 ticks / 400 seconds / ~6 minutes of pain to go into shock again - return + // This is where "soft crit" is now + if(shock_buildup >= 90) + if(!HAS_TRAIT_FROM(parent, TRAIT_LABOURED_BREATHING, PAINSHOCK)) + ADD_TRAIT(parent, TRAIT_LABOURED_BREATHING, PAINSHOCK) + set_pain_modifier(PAINSHOCK, 1.2) + parent.apply_status_effect(/datum/status_effect/low_blood_pressure) + parent.add_traits(list(TRAIT_LABOURED_BREATHING), PAINSHOCK) - var/standard_effect_prob = (curr_pain * 0.05) - 0.75 // starts at 15, caps at 4.5 - var/rare_effect_prob = (curr_pain * 0.04) - 1.5 // starts at 40 - var/very_rare_effect_prob = (curr_pain * 0.03) - 2.25 // starts at 70 - - if(standard_effect_prob > 0) - if(!just_cant_feel_anything) - if(SPT_PROB(standard_effect_prob, seconds_per_tick)) - parent.adjust_stutter_up_to(10 SECONDS * pain_modifier, 30 SECONDS) - if(SPT_PROB(standard_effect_prob, seconds_per_tick)) - parent.adjust_jitter_up_to(20 SECONDS * pain_modifier, 60 SECONDS) - if(SPT_PROB(standard_effect_prob, seconds_per_tick)) - parent.adjust_dizzy_up_to(10 SECONDS * pain_modifier, 30 SECONDS) - if(curr_pain >= 70) - parent.adjust_confusion_up_to(8 SECONDS * pain_modifier, 24 SECONDS) - if(SPT_PROB(standard_effect_prob * 1.2, seconds_per_tick) && parent.stamina?.loss <= 80) - var/stam_taken = round((0.2 * curr_pain + 8) * pain_modifier) // 10 = 10, 100 = 28, good enough - if(just_cant_feel_anything) - parent.apply_damage(stam_taken * 1.2, STAMINA) - // First we apply damage, if that succeeds -> - // Check how much damage, if above a threshold -> - // Run a pain emote, if the pain emote succeeds as well -> - else if(parent.apply_damage(stam_taken, STAMINA) && stam_taken >= 15 && do_pain_emote(pick("wince", "gasp"))) - parent.visible_message(span_warning("[parent] doubles over in pain!")) - - if(rare_effect_prob > 0) - if(SPT_PROB(rare_effect_prob * 2, seconds_per_tick)) - var/list/options = list("wince", "whimper") - if(curr_pain >= 70) - options.Add("cry", "scream") - do_pain_emote(pick(options), 5 SECONDS) - if(SPT_PROB(rare_effect_prob, seconds_per_tick) && parent.body_position != LYING_DOWN && !just_cant_feel_anything) - parent.Knockdown(2 SECONDS * pain_modifier) - parent.visible_message(span_warning("[parent] collapses from pain!")) - if(SPT_PROB(rare_effect_prob, seconds_per_tick)) - var/obj/item/held_item = parent.get_active_held_item() - var/obj/item/bodypart/active_hand = parent.get_active_hand() - if(held_item && active_hand && parent.dropItemToGround(held_item)) - if(active_hand.bodytype & BODYTYPE_ROBOTIC) - to_chat(parent, span_danger("Your hand malfunctions, causing you to drop [held_item]!")) - parent.visible_message(span_warning("[parent]'s hand malfunctions, causing them to drop [held_item]!"), ignored_mobs = parent) - do_sparks(number = 1, source = parent) - else if(just_cant_feel_anything) - to_chat(parent, span_danger("Your hand spams and you drop [held_item]!")) - else - to_chat(parent, span_danger("Your fumble though the pain and drop [held_item]!")) - parent.visible_message(span_warning("[parent] fumbles around and drops [held_item]!"), ignored_mobs = parent) - do_pain_emote("gasp") - - if(very_rare_effect_prob > 0) - if(SPT_PROB(very_rare_effect_prob, seconds_per_tick)) - parent.vomit(50) - if(SPT_PROB(very_rare_effect_prob, seconds_per_tick) && !just_cant_feel_anything) - parent.adjust_confusion_up_to(8 SECONDS, 24 SECONDS) + else + if(HAS_TRAIT_FROM(parent, TRAIT_LABOURED_BREATHING, PAINSHOCK)) + unset_pain_modifier(PAINSHOCK) + parent.remove_status_effect(/datum/status_effect/low_blood_pressure) + parent.remove_traits(list(TRAIT_LABOURED_BREATHING), PAINSHOCK) + + // This is "pain crit", it's where stamcrit has moved and is also applied by extreme shock + if(curr_pain >= PAIN_LIMB_MAX * 3 || shock_buildup >= 150) + parent.adjust_jitter_up_to(5 SECONDS * pain_modifier, 60 SECONDS) + if(!HAS_TRAIT_FROM(parent, TRAIT_LABOURED_BREATHING, PAINCRIT)) + var/is_standing = parent.body_position == STANDING_UP + parent.add_traits(list(TRAIT_LABOURED_BREATHING, TRAIT_INCAPACITATED, TRAIT_IMMOBILIZED, TRAIT_FLOORED, TRAIT_HANDS_BLOCKED), PAINCRIT) + if(is_standing && parent.body_position != STANDING_UP) + parent.visible_message( + span_warning("[parent] collapses!"), + span_userdanger("You collapse, unable to stand!"), + + ) + else + parent.visible_message( + span_warning("[parent] slumps against the ground!"), + span_userdanger("You go limp, unable to get up!"), + + ) + + else if(HAS_TRAIT_FROM(parent, TRAIT_LABOURED_BREATHING, PAINCRIT)) + parent.Paralyze(2 SECONDS) + parent.remove_traits(list(TRAIT_LABOURED_BREATHING, TRAIT_INCAPACITATED, TRAIT_IMMOBILIZED, TRAIT_FLOORED, TRAIT_HANDS_BLOCKED), PAINCRIT) // Finally, handle pain decay over time - if(HAS_TRAIT(parent, TRAIT_STASIS) || parent.on_fire || parent.stat == DEAD) + if(parent.on_fire || parent.stat == DEAD) return // Decay every 3 ticks / 6 seconds, or 1 ticks / 2 seconds if "sleeping" @@ -684,62 +734,72 @@ else unset_pain_modifier(PAIN_MOD_LYING) -/** - * While actively burning, cause pain - */ -/datum/pain/proc/on_burn_tick(datum/source) +/// Affect accuracy of fired guns while in pain. +/datum/pain/proc/on_mob_fired_gun(mob/living/carbon/human/user, obj/item/gun/gun_fired, target, params, zone_override, list/bonus_spread_values) SIGNAL_HANDLER - - var/mob/living/carbon/human/human_parent = parent - if(human_parent.get_thermal_protection() >= FIRE_SUIT_MAX_TEMP_PROTECT) - return - - // The more firestacks, the more pain we apply per burn tick, up to 2 per tick per bodypart. - // We can be liberal with this because when they're extinguished most of it will go away. - parent.apply_status_effect(/datum/status_effect/pain_from_fire, clamp(parent.fire_stacks * 0.2, 0, 2)) - -/** - * Apply or remove pain various modifiers from pain (mood, action speed, movement speed) based on the [average_pain]. - */ + var/obj/item/bodypart/shooting_with = user.get_active_hand() + var/obj/item/bodypart/chest = user.get_bodypart(BODY_ZONE_CHEST) + var/obj/item/bodypart/head = user.get_bodypart(BODY_ZONE_HEAD) + + var/penalty = 0 + // Basically averaging the pain of the shooting hand, chest, and head, with the hand being weighted more + penalty += shooting_with?.get_modified_pain() + penalty += chest?.get_modified_pain() * 0.5 + penalty += head?.get_modified_pain() * 0.5 + penalty /= 3 + // Then actually making it into the final value + penalty = floor(penalty / 5) + // Applying min and max + /* + bonus_spread_values[MIN_BONUS_SPREAD_INDEX] += penalty + bonus_spread_values[MAX_BONUS_SPREAD_INDEX] += penalty * 3 + */ + +/// Apply or remove pain various modifiers from pain (mood, action speed, movement speed) based on the [average_pain]. /datum/pain/proc/refresh_pain_attributes(...) SIGNAL_HANDLER - if(!parent.can_feel_pain()) - clear_pain_attributes() - return + var/avg_pain = get_average_pain() - switch(get_average_pain()) + // Pain is halved if you can't feel pain (but ignore pain modifier for now) + if(avg_pain && parent.stat != DEAD && !parent.can_feel_pain(TRUE)) + avg_pain *= 0.5 + + // Pain is set to 0 fully if you can't feel pain OR pain modifier <= 0.5 (numbness threshold) + if(avg_pain && (parent.stat == DEAD || !parent.can_feel_pain(FALSE))) + avg_pain = 0 + + switch(avg_pain) if(-INFINITY to 20) - clear_pain_attributes() + parent.mob_surgery_speed_mod = initial(parent.mob_surgery_speed_mod) + parent.outgoing_damage_mod = initial(parent.outgoing_damage_mod) + parent.remove_movespeed_modifier(MOVESPEED_ID_PAIN) + parent.remove_actionspeed_modifier(ACTIONSPEED_ID_PAIN) + parent.clear_mood_event(PAIN) if(20 to 40) parent.mob_surgery_speed_mod = 0.9 + parent.outgoing_damage_mod = 0.9 parent.add_movespeed_modifier(/datum/movespeed_modifier/pain/light) parent.add_actionspeed_modifier(/datum/actionspeed_modifier/pain/light) - parent.add_mood_event("pain", /datum/mood_event/light_pain) + parent.add_mood_event(PAIN, /datum/mood_event/light_pain) if(40 to 60) parent.mob_surgery_speed_mod = 0.75 + parent.outgoing_damage_mod = 0.75 parent.add_movespeed_modifier(/datum/movespeed_modifier/pain/medium) parent.add_actionspeed_modifier(/datum/actionspeed_modifier/pain/medium) - parent.add_mood_event("pain", /datum/mood_event/med_pain) + parent.add_mood_event(PAIN, /datum/mood_event/med_pain) if(60 to 80) parent.mob_surgery_speed_mod = 0.6 + parent.outgoing_damage_mod = 0.6 parent.add_movespeed_modifier(/datum/movespeed_modifier/pain/heavy) parent.add_actionspeed_modifier(/datum/actionspeed_modifier/pain/heavy) - parent.add_mood_event("pain", /datum/mood_event/heavy_pain) + parent.add_mood_event(PAIN, /datum/mood_event/heavy_pain) if(80 to INFINITY) parent.mob_surgery_speed_mod = 0.5 + parent.outgoing_damage_mod = 0.5 parent.add_movespeed_modifier(/datum/movespeed_modifier/pain/crippling) parent.add_actionspeed_modifier(/datum/actionspeed_modifier/pain/crippling) - parent.add_mood_event("pain", /datum/mood_event/crippling_pain) - -/** - * Clears all pain related attributes - */ -/datum/pain/proc/clear_pain_attributes() - parent.mob_surgery_speed_mod = initial(parent.mob_surgery_speed_mod) - parent.remove_movespeed_modifier(MOVESPEED_ID_PAIN) - parent.remove_actionspeed_modifier(ACTIONSPEED_ID_PAIN) - parent.clear_mood_event("pain") + parent.add_mood_event(PAIN, /datum/mood_event/crippling_pain) /** * Run a pain related emote, if a few checks are successful. @@ -758,7 +818,7 @@ if(parent.stat >= UNCONSCIOUS || parent.incapacitated(IGNORE_RESTRAINTS|IGNORE_GRAB)) return FALSE - parent.emote(emote) + INVOKE_ASYNC(parent, TYPE_PROC_REF(/mob, emote), emote) COOLDOWN_START(src, time_since_last_pain_message, cooldown) return TRUE @@ -803,13 +863,50 @@ total_pain += adjusted_bodypart.pain max_total_pain += adjusted_bodypart.soft_max_pain - return 100 * total_pain / max_total_pain + return round(100 * total_pain / max_total_pain, 0.01) -/** - * Returns a disease datum (Truthy value) if we are undergoing shock. - */ -/datum/pain/proc/is_undergoing_shock() - return locate(/datum/disease/advanced/premade/shock) in parent.diseases +/// Get the total pain of all bodyparts. +/datum/pain/proc/get_total_pain() + var/total_pain = 0 + for(var/zone in body_zones) + var/obj/item/bodypart/adjusted_bodypart = body_zones[zone] + total_pain += adjusted_bodypart.pain + + return total_pain + +/// Adds a custom stammer to people under the effects of pain. +/datum/pain/proc/handle_message(datum/source, list/message_args) + SIGNAL_HANDLER + + var/phrase = html_decode(message_args[TREAT_MESSAGE_MESSAGE]) + if(!length(phrase)) + return + + var/num_repeats = get_average_pain() * pain_modifier + if(HAS_TRAIT(parent, TRAIT_NO_PAIN_EFFECTS) && shock_buildup < 90) + num_repeats *= 0.5 + + num_repeats = floor(num_repeats / 20) + if(num_repeats <= 1) + return + var/static/regex/no_stammer = regex(@@[ ""''()[\]{}.!?,:;_`~-]@) + var/static/regex/half_stammer = regex(@@[aeiouAEIOU]@) + var/final_phrase = "" + var/original_char = "" + for(var/i = 1, i <= length(phrase), i += length(original_char)) + original_char = phrase[i] + if(no_stammer.Find(original_char)) + final_phrase += original_char + continue + if(half_stammer.Find(original_char)) + if(num_repeats <= 2) + final_phrase += original_char + continue + final_phrase += repeat_string(ceil(num_repeats / 2), original_char) + continue + final_phrase += repeat_string(num_repeats, original_char) + + message_args[TREAT_MESSAGE_MESSAGE] = sanitize(final_phrase) /** * Remove all pain, pain paralysis, side effects, etc. from our mob after we're fully healed by something (like an adminheal) @@ -844,6 +941,33 @@ else START_PROCESSING(SSpain, src) +/// When we are revived, reduced shock +/datum/pain/proc/revived(...) + SIGNAL_HANDLER + + shock_buildup /= 3 + +/// Used to get the effect of pain on the parent's heart rate. +/datum/pain/proc/get_heartrate_modifier() + var/base_amount = 0 + switch(get_average_pain()) // pain raises it a bit + if(25 to 50) + base_amount += 5 + if(50 to 75) + base_amount += 10 + if(75 to INFINITY) + base_amount += 15 + + switch(pain_modifier) // numbness lowers it a bit + if(0.25 to 0.5) + base_amount -= 15 + if(0.5 to 0.75) + base_amount -= 10 + if(0.75 to 1) + base_amount -= 5 + + return base_amount + /** * Signal proc for [COMSIG_LIVING_HEALTHSCAN] * Reports how much pain [parent] is sustaining to [user]. @@ -853,14 +977,18 @@ * the patient is encouraged to elaborate on which bodyparts hurt the most, and how much they hurt. * (To encourage a bit more interaction between the doctors.) */ -/datum/pain/proc/on_analyzed(datum/source, list/render_list, advanced, mob/user, mode) +/datum/pain/proc/on_analyzed(datum/source, list/render_list, advanced, mob/user, mode, tochat) SIGNAL_HANDLER + if(parent.stat == DEAD) + return + + var/in_shock = HAS_TRAIT_FROM(parent, TRAIT_LABOURED_BREATHING, PAINSHOCK) + var/amount = "" var/tip = "" - var/in_shock = !!is_undergoing_shock() - if(in_shock) - tip += span_bold("Neurogenic shock has begun and should be treated urgently. ") + var/amount_text = "" + var/shock_text = "" switch(get_average_pain()) if(5 to 15) @@ -883,11 +1011,24 @@ tip += span_bold("Alert: High potential of neurogenic shock. ") tip += "Treat wounds and abate pain with long rest, cryogenics, and heavy painkilling medication." - if(amount && tip) - render_list += "" - render_list += span_bold("Subject is experiencing [amount] pain. ") - render_list += tip - render_list += "\n" + if(!amount) + return + + amount_text = span_danger("Subject is experiencing [amount] pain.") + if(tochat && tip) + amount_text = span_tooltip(tip, amount_text) + + if(in_shock) + shock_text = span_bold("Neurogenic shock has begun and should be treated urgently.") + if(shock_text && tochat) + shock_text = span_tooltip("Provide immediate pain relief, epinephrine, and moderate body temperature. \ + [in_shock ? "Monitor closely for worsening condition or cardiac arrest. " : ""]Cryogenics may also aid in recovery.", shock_text) + + render_list += "" + if(shock_text) + render_list += "[shock_text] / " + render_list += amount_text + render_list += "\n" #ifdef TESTING debug_print_pain() @@ -940,3 +1081,13 @@ amount = clamp(amount, -200, 200) adjust_bodypart_pain(zone, amount) + + +/** + * Clears all pain related attributes + */ +/datum/pain/proc/clear_pain_attributes() + parent.mob_surgery_speed_mod = initial(parent.mob_surgery_speed_mod) + parent.remove_movespeed_modifier(MOVESPEED_ID_PAIN) + parent.remove_actionspeed_modifier(ACTIONSPEED_ID_PAIN) + parent.clear_mood_event("pain") diff --git a/monkestation/code/modules/can_spessmen_feel_pain/pain/designs.dm b/monkestation/code/modules/can_spessmen_feel_pain/pain/designs.dm new file mode 100644 index 000000000000..27dfc0f3a4f9 --- /dev/null +++ b/monkestation/code/modules/can_spessmen_feel_pain/pain/designs.dm @@ -0,0 +1,42 @@ +/datum/design/crutch + name = "Medical Crutch" + id = "medical_crutch" + build_type = PROTOLATHE | AWAY_LATHE + materials = list( + /datum/material/iron = SHEET_MATERIAL_AMOUNT * 1, + ) + build_path = /obj/item/cane/crutch + category = list( + RND_CATEGORY_INITIAL, + RND_CATEGORY_TOOLS + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL + +/datum/design/heat_pack + name = "Heat Pack" + id = "heat_pack" + build_type = PROTOLATHE | AWAY_LATHE + materials = list( + /datum/material/iron = SHEET_MATERIAL_AMOUNT * 1, //eg for now its fine dont wanna force plastic for this + ) + build_path = /obj/item/temperature_pack/heat + category = list( + RND_CATEGORY_INITIAL, + RND_CATEGORY_TOOLS + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL + + +/datum/design/cold_pack + name = "Cold Pack" + id = "cold_pack" + build_type = PROTOLATHE | AWAY_LATHE + materials = list( + /datum/material/iron = SHEET_MATERIAL_AMOUNT * 1, //eg for now its fine dont wanna force plastic for this + ) + build_path = /obj/item/temperature_pack/cold + category = list( + RND_CATEGORY_INITIAL, + RND_CATEGORY_TOOLS + ) + departmental_flags = DEPARTMENT_BITFLAG_MEDICAL diff --git a/monkestation/code/modules/can_spessmen_feel_pain/pain/modifiers.dm b/monkestation/code/modules/can_spessmen_feel_pain/pain/modifiers.dm index 3d30c8f8348b..89b0510adb5d 100644 --- a/monkestation/code/modules/can_spessmen_feel_pain/pain/modifiers.dm +++ b/monkestation/code/modules/can_spessmen_feel_pain/pain/modifiers.dm @@ -114,12 +114,3 @@ var/mob/living/carbon/human/human_owner = owner human_owner.unset_pain_mod(id) return ..() - -// Reacting to all cases of gaining knocked out rather than just sleeping -/mob/living/on_knockedout_trait_gain(datum/source) - . = ..() - set_pain_mod(PAIN_MOD_KOD, 0.8) - -/mob/living/on_knockedout_trait_loss(datum/source) - . = ..() - unset_pain_mod(PAIN_MOD_KOD) diff --git a/monkestation/code/modules/can_spessmen_feel_pain/pain/pain_assistance_tools.dm b/monkestation/code/modules/can_spessmen_feel_pain/pain/pain_assistance_tools.dm index 57d8200e5b9c..7690e941a5ac 100644 --- a/monkestation/code/modules/can_spessmen_feel_pain/pain/pain_assistance_tools.dm +++ b/monkestation/code/modules/can_spessmen_feel_pain/pain/pain_assistance_tools.dm @@ -329,8 +329,8 @@ slot_flags = ITEM_SLOT_OCLOTHING body_parts_covered = CHEST resistance_flags = FIRE_PROOF - heat_protection = CHEST|GROIN|LEGS|ARMS - cold_protection = CHEST|GROIN|LEGS|ARMS + + max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT armor_type = /datum/armor/shock_blanket @@ -415,7 +415,7 @@ /obj/item/shock_blanket/proc/enable_protection(mob/living/source) if(istype(source) && !(datum_flags & DF_ISPROCESSING)) var/temp_change = "warmer" - if(source.bodytemperature > source.get_body_temp_normal(apply_change = FALSE)) + if(source.bodytemperature > source.standard_body_temperature) temp_change = "colder" to_chat(source, span_notice("You feel [temp_change] as [src] begins regulating your body temperature.")) @@ -429,7 +429,7 @@ if(istype(source) && (datum_flags & DF_ISPROCESSING)) var/temp_change = "freezing" - if(source.bodytemperature > source.get_body_temp_normal(apply_change = FALSE)) + if(source.bodytemperature > source.standard_body_temperature) temp_change = "hotter" to_chat(source, span_notice("You feel [temp_change] again as [src] stops regulating your body temperature.")) @@ -442,17 +442,10 @@ disable_protection() return - var/target_temp = wearer.get_body_temp_normal(apply_change = FALSE) - if(wearer.bodytemperature > target_temp) - wearer.adjust_bodytemperature(-8 * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, target_temp) - else if(wearer.bodytemperature < (target_temp + 1)) - wearer.adjust_bodytemperature(8 * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, target_temp) - if(ishuman(wearer)) - var/mob/living/carbon/human/human_wearer = wearer - if(human_wearer.coretemperature > target_temp) - human_wearer.adjust_coretemperature(-8 * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, target_temp) - else if(human_wearer.coretemperature < (target_temp + 1)) - human_wearer.adjust_coretemperature(8 * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, target_temp) + if(wearer.bodytemperature < wearer.standard_body_temperature) + wearer.adjust_bodytemperature(0.25 KELVIN * seconds_per_tick, max_temp = wearer.standard_body_temperature) + else if(wearer.bodytemperature > wearer.standard_body_temperature) + wearer.adjust_bodytemperature(-0.25 KELVIN * seconds_per_tick, min_temp = wearer.standard_body_temperature) /obj/item/shock_blanket/emergency desc = "An emergency variant shock blanket intended to be placed in medkits for field treatment. Faster to apply to patients, but more restrictive to movement." diff --git a/monkestation/code/modules/can_spessmen_feel_pain/pain/reagents/painkillers.dm b/monkestation/code/modules/can_spessmen_feel_pain/pain/reagents/painkillers.dm index a217837a0e06..6572fc4984ed 100644 --- a/monkestation/code/modules/can_spessmen_feel_pain/pain/reagents/painkillers.dm +++ b/monkestation/code/modules/can_spessmen_feel_pain/pain/reagents/painkillers.dm @@ -179,7 +179,7 @@ M.cause_pain(BODY_ZONES_LIMBS, -0.16 * REM * seconds_per_tick) M.cause_pain(BODY_ZONE_CHEST, -0.32 * REM * seconds_per_tick) // Okay at fevers. - M.adjust_bodytemperature(-15 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, M.get_body_temp_normal()) + M.adjust_bodytemperature(-0.1 KELVIN * REM * seconds_per_tick, M.standard_body_temperature) if(M.disgust < DISGUST_LEVEL_VERYGROSS && SPT_PROB(66 * max(1 - creation_purity, 0.5), seconds_per_tick)) M.adjust_disgust(1.5 * REM * seconds_per_tick) @@ -191,7 +191,7 @@ return // On overdose, heat up the body... - M.adjust_bodytemperature(30 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick) + M.adjust_bodytemperature(0.5 KELVIN * REM * seconds_per_tick, max_temp = HYPERTHERMIA - 1 KELVIN) // Causes sickness... M.apply_damage(1 * REM * seconds_per_tick, TOX) if(M.disgust < 100 && SPT_PROB(100 * max(1 - creation_purity, 0.5), seconds_per_tick)) @@ -229,7 +229,7 @@ M.adjustToxLoss(-0.05 * REM * seconds_per_tick, FALSE) M.cause_pain(BODY_ZONES_ALL, -0.2 * REM * seconds_per_tick) // Not very good at treating fevers. - M.adjust_bodytemperature(-10 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, M.get_body_temp_normal()) + M.adjust_bodytemperature(-0.05 KELVIN * REM * seconds_per_tick, M.standard_body_temperature) // Causes liver damage - higher dosages causes more liver damage. M.adjustOrganLoss(ORGAN_SLOT_LIVER, volume / 30 * REM * seconds_per_tick) if(M.disgust < DISGUST_LEVEL_VERYGROSS && SPT_PROB(66 * max(1 - creation_purity, 0.5), seconds_per_tick)) @@ -273,7 +273,7 @@ // Causes flat liver damage. M.adjustOrganLoss(ORGAN_SLOT_LIVER, 0.25 * REM * seconds_per_tick) // Really good at treating fevers. - M.adjust_bodytemperature(-25 * TEMPERATURE_DAMAGE_COEFFICIENT * REM * seconds_per_tick, M.get_body_temp_normal()) + M.adjust_bodytemperature(-0.5 KELVIN * REM * seconds_per_tick, M.standard_body_temperature) // Causes more disgust the longer it's in someone... if(M.disgust < DISGUST_LEVEL_VERYGROSS && SPT_PROB(66 * max(1 - creation_purity, 0.5), seconds_per_tick)) M.adjust_disgust(min(current_cycle * 0.02, 2.4) * REM * seconds_per_tick) diff --git a/monkestation/code/modules/can_spessmen_feel_pain/pain/shock.dm b/monkestation/code/modules/can_spessmen_feel_pain/pain/shock.dm index 279d14a9262b..8c8e04577b9d 100644 --- a/monkestation/code/modules/can_spessmen_feel_pain/pain/shock.dm +++ b/monkestation/code/modules/can_spessmen_feel_pain/pain/shock.dm @@ -45,7 +45,7 @@ var/conditions_fulfilled = 0 // Good: Body temperature is stable (not freezing, we don't care about heat) - if(affected_mob.bodytemperature > affected_mob.get_body_temp_cold_damage_limit()) + if(affected_mob.bodytemperature > affected_mob.bodytemp_cold_damage_limit) conditions_fulfilled += 1 // Good: Sleeping (or unconscious I guess) if(affected_mob.IsSleeping() || affected_mob.IsUnconscious()) @@ -147,7 +147,7 @@ if(SPT_PROB(6, seconds_per_tick)) to_chat(affected_mob, span_danger("You feel cold.")) affected_mob.pain_emote("shiver", 3 SECONDS) - affected_mob.adjust_bodytemperature(-5 * seconds_per_tick, affected_mob.get_body_temp_cold_damage_limit() + 5) // Not lethal + affected_mob.adjust_bodytemperature(-5 * seconds_per_tick, min_temp = affected_mob.bodytemp_cold_damage_limit + 5) // Not lethal // decompensated (or progressive) - unable to maintain themselves // - mental issues @@ -180,7 +180,7 @@ if(SPT_PROB(8, seconds_per_tick)) to_chat(affected_mob, span_danger("You feel freezing!")) affected_mob.pain_emote("shiver", 3 SECONDS) - affected_mob.adjust_bodytemperature(-10 * seconds_per_tick, affected_mob.get_body_temp_cold_damage_limit() - 5) // uh oh + affected_mob.adjust_bodytemperature(-10 * seconds_per_tick, min_temp = affected_mob.bodytemp_cold_damage_limit - 5) // uh oh // irreversible - point of no return, system failure // cardiac arrest @@ -204,4 +204,4 @@ affected_mob.losebreath += 10 else if(SPT_PROB(10, seconds_per_tick)) to_chat(affected_mob, span_userdanger(pick("You feel your heart skip a beat...", "You feel your body shutting down...", "You feel your heart beat irregularly..."))) - affected_mob.adjust_bodytemperature(-10 * seconds_per_tick, affected_mob.get_body_temp_cold_damage_limit() - 20) // welp + affected_mob.adjust_bodytemperature(-10 * seconds_per_tick, min_temp = affected_mob.bodytemp_cold_damage_limit - 20) // welp diff --git a/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/anesthetics.dm b/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/anesthetics.dm index 03f24a52b8a0..22a82216fce5 100644 --- a/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/anesthetics.dm +++ b/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/anesthetics.dm @@ -2,6 +2,7 @@ /datum/status_effect/grouped/anesthetic id = "anesthetics" alert_type = /atom/movable/screen/alert/status_effect/anesthetics + var/applied_at = -1 /datum/status_effect/grouped/anesthetic/on_creation(mob/living/new_owner, source) if(!istype(get_area(new_owner), /area/station/medical)) @@ -13,10 +14,13 @@ /datum/status_effect/grouped/anesthetic/on_apply() . = ..() RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_KNOCKEDOUT), PROC_REF(try_removal)) + applied_at = world.time /datum/status_effect/grouped/anesthetic/on_remove() . = ..() UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_KNOCKEDOUT)) + if(!QDELETED(owner)) + owner.apply_status_effect(/datum/status_effect/anesthesia_grog, applied_at) /datum/status_effect/grouped/anesthetic/get_examine_text() return span_warning("[owner.p_Theyre()] out cold.") @@ -40,3 +44,17 @@ . = ..() if(HAS_TRAIT(breather, TRAIT_KNOCKEDOUT)) breather.apply_status_effect(/datum/status_effect/grouped/anesthetic, /datum/gas/nitrous_oxide) + +/datum/status_effect/anesthesia_grog + id = "anesthesia_grog" + duration = 4 MINUTES + alert_type = null + var/strength = 0 + +/datum/status_effect/anesthesia_grog/on_creation(mob/living/new_owner, anesthesia_appied_at) + strength = (world.time - anesthesia_appied_at > 1 MINUTES) ? 50 : 90 + return ..() + +/datum/status_effect/anesthesia_grog/on_apply() + to_chat(owner, span_warning("You feel[strength <= 90 ? " ":" a bit "]groggy...")) + return TRUE diff --git a/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/fire_pain.dm b/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/fire_pain.dm deleted file mode 100644 index b359a5a477b6..000000000000 --- a/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/fire_pain.dm +++ /dev/null @@ -1,42 +0,0 @@ -/// Handler for pain from fire. Goes up the longer you're on fire, largely goes away when extinguished -/datum/status_effect/pain_from_fire - id = "sharp_pain_from_fire" - status_type = STATUS_EFFECT_REFRESH - alert_type = null - remove_on_fullheal = TRUE - heal_flag_necessary = HEAL_ADMIN|HEAL_WOUNDS|HEAL_STATUS - - /// Amount of pain being given - var/pain_amount = 0 - -/datum/status_effect/pain_from_fire/on_creation(mob/living/new_owner, pain_amount = 0) - src.pain_amount = pain_amount - return ..() - -/datum/status_effect/pain_from_fire/refresh(mob/living/new_owner, added_pain_amount = 0) - if(added_pain_amount <= 0) - return - pain_amount += added_pain_amount - owner.cause_pain(BODY_ZONES_ALL, added_pain_amount, BURN) - -/datum/status_effect/pain_from_fire/on_apply() - if(isnull(owner.pain_controller) || pain_amount <= 0) - return FALSE - - RegisterSignal(owner, COMSIG_LIVING_EXTINGUISHED, PROC_REF(remove_on_signal)) - owner.cause_pain(BODY_ZONES_ALL, pain_amount, BURN) - return TRUE - -/datum/status_effect/pain_from_fire/on_remove() - if(QDELING(owner)) - return - UnregisterSignal(owner, COMSIG_LIVING_EXTINGUISHED) - owner.cause_pain(BODY_ZONES_ALL, -3 * pain_amount, BURN) - -/// When signalled, terminate. -/datum/status_effect/pain_from_fire/proc/remove_on_signal(datum/source) - SIGNAL_HANDLER - - if(QDELING(owner) || QDELING(src)) - return - qdel(src) diff --git a/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/pain_limp.dm b/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/pain_limp.dm index 0005d91fcc3c..00fce8026bf5 100644 --- a/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/pain_limp.dm +++ b/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/pain_limp.dm @@ -40,7 +40,7 @@ ) /datum/status_effect/limp/pain/update_limp() - if(QDELING(owner)) + if(QDELETED(owner)) return var/mob/living/carbon/human/limping_human = owner diff --git a/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/temp_pack.dm b/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/temp_pack.dm index bc5f230aff60..b0fe8a078a6d 100644 --- a/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/temp_pack.dm +++ b/monkestation/code/modules/can_spessmen_feel_pain/pain/status_effects/temp_pack.dm @@ -79,7 +79,7 @@ return if(temperature_change) - owner.adjust_bodytemperature(temperature_change, human_owner.get_body_temp_cold_damage_limit() + 5, human_owner.get_body_temp_heat_damage_limit() - 5) + owner.adjust_bodytemperature(temperature_change, human_owner.bodytemp_cold_damage_limit + 5 KELVIN, human_owner.bodytemp_heat_damage_limit - 5 KELVIN) var/obj/item/bodypart/held_bodypart = human_owner.pain_controller.body_zones[targeted_zone] if(held_bodypart && prob(66)) human_owner.cause_pain(targeted_zone, -pain_heal_amount) diff --git a/monkestation/code/modules/client/preferences/species_features/ethereal.dm b/monkestation/code/modules/client/preferences/species_features/ethereal.dm index d0b79ffe1e9a..1efe9542f789 100644 --- a/monkestation/code/modules/client/preferences/species_features/ethereal.dm +++ b/monkestation/code/modules/client/preferences/species_features/ethereal.dm @@ -9,7 +9,7 @@ return possible_values_for_sprite_accessory_list_for_body_part( GLOB.ethereal_horns_list, "ethereal_horns", - list("ADJ", "FRONT"), + list("FRONT"), ) /datum/preference/choiced/ethereal_horns/apply_to_human(mob/living/carbon/human/target, value) @@ -26,7 +26,7 @@ return possible_values_for_sprite_accessory_list_for_body_part( GLOB.ethereal_tail_list, "ethereal_tail", - list("BEHIND", "FRONT"), + list("BEHIND"), ) /datum/preference/choiced/ethereal_tail/apply_to_human(mob/living/carbon/human/target, value) diff --git a/monkestation/code/modules/client/preferences/species_features/secondary_mut_color.dm b/monkestation/code/modules/client/preferences/species_features/secondary_mut_color.dm index 1564e0e925e5..f9303e14049b 100644 --- a/monkestation/code/modules/client/preferences/species_features/secondary_mut_color.dm +++ b/monkestation/code/modules/client/preferences/species_features/secondary_mut_color.dm @@ -2,13 +2,17 @@ savefile_key = "feature_mcolor_secondary" savefile_identifier = PREFERENCE_CHARACTER category = PREFERENCE_CATEGORY_SECONDARY_FEATURES - relevant_species_trait = MUTCOLORS_SECONDARY + relevant_inherent_trait = TRAIT_MUTANT_COLORS_SECONDARY + default_null = TRUE + allows_nulls = TRUE -/datum/preference/color/mutant_color_secondary/create_default_value() - return sanitize_hexcolor("[pick("7F", "FF")][pick("7F", "FF")][pick("7F", "FF")]") +/datum/preference/color/mutant_color_secondary/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE -/datum/preference/color/mutant_color_secondary/apply_to_human(mob/living/carbon/human/target, value) - target.dna.features["mcolor_secondary"] = value + var/species_type = preferences.read_preference(/datum/preference/choiced/species) + var/datum/species/species = new species_type + return (TRAIT_MUTANT_COLORS_SECONDARY in species.inherent_traits) /datum/preference/color/mutant_color_secondary/is_valid(value) if (!..(value)) diff --git a/monkestation/code/modules/client/preferences/species_features/simians.dm b/monkestation/code/modules/client/preferences/species_features/simians.dm index a4f27e181827..39f63cf97aec 100644 --- a/monkestation/code/modules/client/preferences/species_features/simians.dm +++ b/monkestation/code/modules/client/preferences/species_features/simians.dm @@ -2,13 +2,7 @@ category = PREFERENCE_CATEGORY_SECONDARY_FEATURES savefile_identifier = PREFERENCE_CHARACTER savefile_key = "fur" - relevant_species_trait = SPECIES_FUR - -/datum/preference/color/fur_color/apply_to_human(mob/living/carbon/human/target, value) - var/mob/user = usr - var/datum/species/species_type = user?.client.prefs.read_preference(/datum/preference/choiced/species) - if(initial(species_type.uses_fur)) - target.dna.features["mcolor"] = value + relevant_inherent_trait = TRAIT_FUR_COLORS /datum/preference/choiced/simian_tail savefile_key = "feature_tail_monkey" diff --git a/monkestation/code/modules/client/verbs.dm b/monkestation/code/modules/client/verbs.dm index adf97b39536c..6ce64ebe5892 100644 --- a/monkestation/code/modules/client/verbs.dm +++ b/monkestation/code/modules/client/verbs.dm @@ -19,6 +19,8 @@ GLOBAL_LIST_INIT(antag_token_config, load_antag_token_config()) to_chat(src, span_notice("NOTE: You will be spawned where ever your ghost is when approved, so becareful where you are.")) if(!client_token_holder) + if(!prefs?.loaded) + CRASH("Tried to load client_token's before prefs were loaded how the fuck?") client_token_holder = new(src) var/tier = tgui_input_list(src, "High: [client_token_holder.total_high_threat_tokens] | \ diff --git a/monkestation/code/modules/clothing/spacesuits/hardsuits/engineering.dm b/monkestation/code/modules/clothing/spacesuits/hardsuits/engineering.dm index 0e641818c566..319dde7d11f5 100644 --- a/monkestation/code/modules/clothing/spacesuits/hardsuits/engineering.dm +++ b/monkestation/code/modules/clothing/spacesuits/hardsuits/engineering.dm @@ -40,7 +40,7 @@ icon_state = "hardsuit0-atmos" hardsuit_type = "atmos" armor_type = /datum/armor/hardsuit/atmos - heat_protection = HEAD //Uncomment to enable firesuit protection + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT /obj/item/clothing/suit/space/hardsuit/atmos @@ -48,7 +48,7 @@ desc = "A modified engineering hardsuit for work in a hazardous, low pressure environment. The radiation shielding plates were removed to allow for improved thermal protection instead." icon_state = "hardsuit-atmos" armor_type = /datum/armor/hardsuit/atmos - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS //Uncomment to enable firesuit protection + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT helmettype = /obj/item/clothing/head/helmet/space/hardsuit/atmos diff --git a/monkestation/code/modules/clothing/suits/costume.dm b/monkestation/code/modules/clothing/suits/costume.dm index dc73f480703f..7e489332e347 100644 --- a/monkestation/code/modules/clothing/suits/costume.dm +++ b/monkestation/code/modules/clothing/suits/costume.dm @@ -111,9 +111,9 @@ worn_icon = 'monkestation/icons/mob/clothing/suit.dmi' inhand_icon_state = null body_parts_covered = CHEST|GROIN|LEGS|ARMS - cold_protection = CHEST|GROIN|LEGS|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT - heat_protection = CHEST|GROIN|LEGS|ARMS + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT hoodtype = /obj/item/clothing/head/hooded/ashsuit armor_type = /datum/armor/hooded_ashsuit @@ -147,9 +147,9 @@ icon_state = "ashsuit" body_parts_covered = HEAD flags_inv = HIDEHAIR|HIDEFACE|HIDEEARS - cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT armor_type = /datum/armor/hooded_explorer resistance_flags = FIRE_PROOF diff --git a/monkestation/code/modules/clothing/~donator/clothing.dm b/monkestation/code/modules/clothing/~donator/clothing.dm index aada29f2b240..57d0385dff60 100644 --- a/monkestation/code/modules/clothing/~donator/clothing.dm +++ b/monkestation/code/modules/clothing/~donator/clothing.dm @@ -127,7 +127,7 @@ inhand_icon_state = "hostrench" blood_overlay_type = "coat" body_parts_covered = CHEST|GROIN|LEGS|ARMS - cold_protection = CHEST|GROIN|LEGS|ARMS + supports_variations_flags = NONE // Donation reward for Thedragmeme @@ -292,7 +292,7 @@ icon_state = "avipilotup" inhand_icon_state = "rus_ushanka" flags_inv = HIDEEARS|HIDEHAIR - cold_protection = HEAD + min_cold_protection_temperature = FIRE_HELM_MIN_TEMP_PROTECT //about as warm as an ushanka actions_types = list(/datum/action/item_action/adjust) supports_variations_flags = NONE @@ -664,7 +664,7 @@ worn_icon = 'monkestation/icons/donator/mob/clothing/suit.dmi' icon_state = "greycoat" body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT // Donation reward for Cherno_00 @@ -675,7 +675,7 @@ worn_icon = 'monkestation/icons/donator/mob/clothing/suit.dmi' icon_state = "chernocoat" body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT // Donation reward for GoldenAlpharex diff --git a/monkestation/code/modules/cybernetics/augments/arm_augments/unsorted.dm b/monkestation/code/modules/cybernetics/augments/arm_augments/unsorted.dm index cbd4105edbf9..633a8623ee4b 100644 --- a/monkestation/code/modules/cybernetics/augments/arm_augments/unsorted.dm +++ b/monkestation/code/modules/cybernetics/augments/arm_augments/unsorted.dm @@ -219,14 +219,14 @@ . = ..() if(!check_compatibility()) return - var/amt = BODYTEMP_NORMAL - owner.get_body_temp_normal() + var/amt = BODYTEMP_NORMAL - owner.standard_body_temperature if(amt == 0) return - owner.add_body_temperature_change("dermal_cooler_[zone]",clamp(amt,-1,0)) + owner.add_homeostasis_level(type, amt, 0.25 KELVIN) /obj/item/organ/internal/cyberimp/arm/cooler/Remove(mob/living/carbon/M, special) . = ..() - owner.remove_body_temperature_change("dermal_cooler_[zone]") + owner.remove_homeostasis_level(type) /obj/item/organ/internal/cyberimp/arm/heater name = "sub-dermal heater implant" @@ -241,11 +241,11 @@ . = ..() if(!check_compatibility()) return - var/amt = BODYTEMP_NORMAL - owner.get_body_temp_normal() + var/amt = BODYTEMP_NORMAL - owner.standard_body_temperature if(amt == 0) return - owner.add_body_temperature_change("dermal_heater_[zone]",clamp(amt,0,1)) + owner.add_homeostasis_level(type, amt, 0.25 KELVIN) /obj/item/organ/internal/cyberimp/arm/heater/Remove(mob/living/carbon/M, special) . = ..() - owner.remove_body_temperature_change("dermal_heater_[zone]") + owner.remove_homeostasis_level(type) diff --git a/monkestation/code/modules/cybernetics/augments/internal_implants.dm b/monkestation/code/modules/cybernetics/augments/internal_implants.dm index 830f040d0707..eb038adcf449 100644 --- a/monkestation/code/modules/cybernetics/augments/internal_implants.dm +++ b/monkestation/code/modules/cybernetics/augments/internal_implants.dm @@ -165,6 +165,7 @@ slot = ORGAN_SLOT_BREATHING_TUBE w_class = WEIGHT_CLASS_TINY encode_info = AUGMENT_NO_REQ + organ_traits = list(TRAIT_ASSISTED_BREATHING) /obj/item/organ/internal/cyberimp/mouth/breathing_tube/emp_act(severity) . = ..() diff --git a/monkestation/code/modules/donator/code/datum/loadout.dm b/monkestation/code/modules/donator/code/datum/loadout.dm index fa331db1be00..fa2c98b724cf 100644 --- a/monkestation/code/modules/donator/code/datum/loadout.dm +++ b/monkestation/code/modules/donator/code/datum/loadout.dm @@ -365,25 +365,6 @@ donator_only = TRUE requires_purchase = FALSE -/datum/loadout_item/toys/quilark - name = "Quilark Plush" - item_path = /obj/item/toy/plush/quilark - donator_only = TRUE - requires_purchase = FALSE - -/datum/loadout_item/pocket_items/donator/quilava - name = "Pet Delivery Beacon - Quil Maid" - item_path = /obj/item/choice_beacon/pet/donator/quilava - donator_only = TRUE - requires_purchase = FALSE - ckeywhitelist = list("quilark") - -/datum/loadout_item/effects/quilava - ckeywhitelist = list("quilark") - name = "Quil Maid Transformation" - item_path = /obj/item/effect_granter/donator/quilava - requires_purchase = FALSE - /datum/loadout_item/suit/org_thirteen name = "Organization 13 Cloak" item_path = /obj/item/clothing/suit/hooded/org_thirteen diff --git a/monkestation/code/modules/donator/code/item/choice_beacon.dm b/monkestation/code/modules/donator/code/item/choice_beacon.dm index 63ffba779d6e..1987c1a4c559 100644 --- a/monkestation/code/modules/donator/code/item/choice_beacon.dm +++ b/monkestation/code/modules/donator/code/item/choice_beacon.dm @@ -76,11 +76,6 @@ default_name = "Plant Crab" donator_pet = /mob/living/basic/crab/plant -/obj/item/choice_beacon/pet/donator/quilava - name = "Quil Maid" - default_name = "Quil Maid" - donator_pet = /mob/living/basic/pet/quilmaid - /obj/item/choice_beacon/pet/donator/gumball_goblin name = "Gumball Goblin" default_name = "Gumball Goblin" diff --git a/monkestation/code/modules/donator/code/item/clothing.dm b/monkestation/code/modules/donator/code/item/clothing.dm index 128c8d908d9b..665446777e86 100644 --- a/monkestation/code/modules/donator/code/item/clothing.dm +++ b/monkestation/code/modules/donator/code/item/clothing.dm @@ -41,7 +41,7 @@ worn_icon = 'monkestation/code/modules/donator/icons/mob/clothing.dmi' inhand_icon_state = "blahaj_costume" body_parts_covered = CHEST|GROIN|ARMS|LEGS|FEET - cold_protection = CHEST|GROIN|ARMS + allowed = list(/obj/item/tank/internals/emergency_oxygen, /obj/item/tank/internals/plasmaman, /obj/item/gun/ballistic/rifle/boltaction/harpoon) hoodtype = /obj/item/clothing/head/hooded/shark_hood inhand_icon_state = null @@ -53,7 +53,7 @@ worn_icon = 'monkestation/code/modules/donator/icons/mob/clothing.dmi' icon_state = "blahaj_hood" body_parts_covered = HEAD - cold_protection = HEAD + flags_inv = HIDEHAIR|HIDEEARS inhand_icon_state = null @@ -168,7 +168,7 @@ worn_icon = 'monkestation/code/modules/donator/icons/mob/clothing.dmi' icon_state = "aotcloak" body_parts_covered = CHEST|ARMS - cold_protection = CHEST|ARMS + allowed = list() armor_type = /datum/armor/hooded_wintercoat hoodtype = /obj/item/clothing/head/hooded/aotcloak @@ -206,7 +206,7 @@ worn_icon = 'monkestation/code/modules/donator/icons/mob/clothing.dmi' icon_state = "aotcloak_hood" body_parts_covered = HEAD - cold_protection = HEAD + flags_inv = HIDEHAIR|HIDEEARS armor_type = /datum/armor/hooded_winterhood @@ -251,7 +251,7 @@ icon_state = "coat_quilark" toggle_noun = "zipper" body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT /obj/item/clothing/suit/toggle/quilark/Initialize(mapload) @@ -283,7 +283,7 @@ worn_icon = 'monkestation/code/modules/donator/icons/mob/clothing.dmi' icon_state = "lambcloak" body_parts_covered = CHEST|ARMS - cold_protection = CHEST|ARMS + layer = NECK_LAYER /obj/item/clothing/suit/hooded/org_thirteen @@ -294,7 +294,7 @@ icon_state = "org_thirteen" inhand_icon_state = null body_parts_covered = CHEST|ARMS - cold_protection = CHEST|ARMS + allowed = list() armor_type = /datum/armor/hooded_wintercoat hoodtype = /obj/item/clothing/head/hooded/org_thirteen @@ -321,7 +321,7 @@ worn_icon = 'monkestation/code/modules/donator/icons/mob/clothing.dmi' icon_state = "org_thirteen_hood" body_parts_covered = HEAD - cold_protection = HEAD + flags_inv = HIDEHAIR|HIDEEARS armor_type = /datum/armor/hooded_winterhood @@ -424,7 +424,7 @@ name = "menacing jacket" desc = "There can only be one dragon." body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT /obj/item/clothing/mask/gas/bluedragon66_trenchbiomask @@ -485,7 +485,7 @@ name = "rainbow coat" desc = "Woah, it's a RAINBOW coat. How's it doing that?" body_parts_covered = CHEST|GROIN|ARMS - cold_protection = CHEST|GROIN|ARMS + armor_type = /datum/armor/hooded_wintercoat min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT /obj/item/clothing/suit/toggle/ophaq_rainbowcoat/Initialize(mapload) diff --git a/monkestation/code/modules/donator/code/item/effects.dm b/monkestation/code/modules/donator/code/item/effects.dm index 95301950c4ba..be1d463c682c 100644 --- a/monkestation/code/modules/donator/code/item/effects.dm +++ b/monkestation/code/modules/donator/code/item/effects.dm @@ -73,13 +73,6 @@ icon_state = "crab_plant" animal_transformation = /mob/living/basic/crab/plant - -//Quilark -/obj/item/effect_granter/donator/quilava - name = "quilava transformation" - icon_state = "quil_maid" - animal_transformation = /mob/living/basic/pet/quilmaid - //ellie /obj/item/effect_granter/donator/gumball_goblin name = "gumball goblin transformation" diff --git a/monkestation/code/modules/donator/code/item/plush.dm b/monkestation/code/modules/donator/code/item/plush.dm index 943600b958a2..c687be3eb957 100644 --- a/monkestation/code/modules/donator/code/item/plush.dm +++ b/monkestation/code/modules/donator/code/item/plush.dm @@ -62,12 +62,6 @@ icon = 'monkestation/code/modules/donator/icons/obj/plushes.dmi' icon_state = "lief_flos" -/obj/item/toy/plush/quilark - name = "quilark plush" - desc = "A plush of the Lizard Basil. ~Handcrafted lovingly for quilark" - icon = 'monkestation/code/modules/donator/icons/obj/plushes.dmi' - icon_state = "quilark" - /obj/item/toy/plush/gumball_goblin name = "gumball goblin plush" desc = "A plush of a Gumball Goblin. He was abducted while pondering his gumballs. Help. ~Handcrafted lovingly for elliethedarksun" diff --git a/monkestation/code/modules/donator/code/mob/pets.dm b/monkestation/code/modules/donator/code/mob/pets.dm index 580456ffbd58..d695c5f854f6 100644 --- a/monkestation/code/modules/donator/code/mob/pets.dm +++ b/monkestation/code/modules/donator/code/mob/pets.dm @@ -155,19 +155,6 @@ ckeywhitelist = list("Rickdude1231") -/mob/living/basic/pet/quilmaid - name = "\improper Quil' Maid" - desc = "Someone dressed up this Space-e-mon in a maid outfit." - icon = 'monkestation/code/modules/donator/icons/mob/pets.dmi' - icon_state = "quil_maid" - icon_living = "quil_maid" - icon_dead = "quil_maid" - icon_gib = null - gold_core_spawnable = NO_SPAWN - ai_controller = /datum/ai_controller/basic_controller/ - - ckeywhitelist = list("quilark") - /mob/living/basic/pet/gumball_goblin name = "Gumball Goblin" desc = "AAAAAAAAAAAAAAAA" diff --git a/monkestation/code/modules/emotes/code/emote.dm b/monkestation/code/modules/emotes/code/emote.dm index c57f480edb0e..2cbc12d7b813 100644 --- a/monkestation/code/modules/emotes/code/emote.dm +++ b/monkestation/code/modules/emotes/code/emote.dm @@ -165,7 +165,8 @@ var/mob/living/carbon/human/human_user = user if(length(human_user.alternative_screams)) return pick(human_user.alternative_screams) - . = human_user.dna.species.get_scream_sound(user) + var/obj/item/organ/internal/tongue/tongue = human_user.get_organ_slot(ORGAN_SLOT_TONGUE) + . = tongue?.get_scream_sound() /datum/emote/living/scream/should_vary(mob/living/user) if(ishuman(user) && !is_cat_enough(user)) diff --git a/monkestation/code/modules/factory_type_beat/machinery/assembler.dm b/monkestation/code/modules/factory_type_beat/machinery/assembler.dm index 65c31219c962..b350951a2427 100644 --- a/monkestation/code/modules/factory_type_beat/machinery/assembler.dm +++ b/monkestation/code/modules/factory_type_beat/machinery/assembler.dm @@ -208,75 +208,43 @@ return var/list/requirements = chosen_recipe.reqs - var/list/Deletion = list() - var/list/stored_parts = list() - var/data - var/amt - var/insanity = 500 - main_loop: - insanity-- - if(insanity <= 0) - return - for(var/path_key in requirements) - amt = chosen_recipe.reqs?[path_key] - if(!amt)//since machinery & structures can have 0 aka CRAFTING_MACHINERY_USE - i.e. use it, don't consume it! - continue main_loop - if(ispath(path_key, /obj/item/stack)) - var/obj/item/stack/S - var/obj/item/stack/SD - while(amt > 0) - S = locate(path_key) in crafting_inventory - if(S.amount >= amt) - if(!locate(S.type) in Deletion) - SD = new S.type() - Deletion += SD - S.use(amt) - SD = locate(S.type) in Deletion - SD.amount += amt - continue main_loop - else - amt -= S.amount - if(!locate(S.type) in Deletion) - Deletion += S - else - data = S.amount - S = locate(S.type) in Deletion - S.add(data) - crafting_inventory -= S + var/list/parts = list() + + for(var/obj/item/req as anything in requirements) + for(var/obj/item/item as anything in crafting_inventory) + if(!istype(item, req)) + continue + if(isstack(item)) + var/obj/item/stack/stack = item + if(stack.amount == requirements[stack.merge_type]) + var/failed = TRUE + crafting_inventory -= item + for(var/obj/item/part as anything in chosen_recipe.parts) + if(!istype(item, part)) + continue + parts += item + failed = FALSE + if(failed) + qdel(item) + else if(stack.amount > requirements[item.type]) + for(var/obj/item/part as anything in chosen_recipe.parts) + if(!istype(item, part)) + continue + var/obj/item/stack/new_stack = new item + new_stack.amount = requirements[item.type] + parts += new_stack + stack.amount -= requirements[stack.merge_type] else - var/atom/movable/I - while(amt > 0) - I = locate(path_key) in crafting_inventory - Deletion += I - crafting_inventory -= I - amt-- - var/list/partlist = list(chosen_recipe.parts.len) - for(var/M in chosen_recipe.parts) - partlist[M] = chosen_recipe.parts[M] - for(var/part in chosen_recipe.parts) - if(isstack(part)) - var/obj/item/stack/ST = locate(part) in Deletion - if(ST.amount > partlist[part]) - ST.amount = partlist[part] - stored_parts += ST - Deletion -= ST - continue - else - while(partlist[part] > 0) - var/atom/movable/AM = locate(part) in Deletion - stored_parts += AM - Deletion -= AM - partlist[part] -= 1 - while(Deletion.len) - var/DL = Deletion[Deletion.len] - Deletion.Cut(Deletion.len) - if(istype(DL, /obj/item/storage)) - var/obj/item/storage/container = DL - container.emptyStorage() - else if(isstructure(DL)) - var/obj/structure/structure = DL - structure.dump_contents(structure.drop_location()) - qdel(DL) + var/failed = TRUE + crafting_inventory -= item + for(var/obj/item/part as anything in chosen_recipe.parts) + if(!istype(item, part)) + continue + parts += item + failed = FALSE + + if(failed) + qdel(item) var/atom/movable/I if(ispath(chosen_recipe.result, /obj/item/stack)) @@ -288,7 +256,7 @@ if(I.atom_storage && chosen_recipe.delete_contents) for(var/obj/item/thing in I) qdel(thing) - I.CheckParts(stored_parts, chosen_recipe) + I.CheckParts(parts, chosen_recipe) I.forceMove(drop_location()) crafting = FALSE diff --git a/monkestation/code/modules/ghost_critters/ghost_critter_mobs/donator_mobs.dm b/monkestation/code/modules/ghost_critters/ghost_critter_mobs/donator_mobs.dm index 0c852b29ef40..e63c578761f3 100644 --- a/monkestation/code/modules/ghost_critters/ghost_critter_mobs/donator_mobs.dm +++ b/monkestation/code/modules/ghost_critters/ghost_critter_mobs/donator_mobs.dm @@ -12,7 +12,6 @@ /mob/living/basic/pet/spider/dancing, /mob/living/basic/butterfly/void, /mob/living/basic/crab/plant, - /mob/living/basic/pet/quilmaid, ) if(is_admin(src)) diff --git a/monkestation/code/modules/ghost_players/arena/fight_button.dm b/monkestation/code/modules/ghost_players/arena/fight_button.dm index cd077bb3063e..357d9173a0c1 100644 --- a/monkestation/code/modules/ghost_players/arena/fight_button.dm +++ b/monkestation/code/modules/ghost_players/arena/fight_button.dm @@ -140,9 +140,9 @@ player_one.client.prefs.adjust_metacoins(player_one.ckey, payout, "Opponent left, reimbursed.") return - var/turf/player_one_spot = locate(148, 34, SSmapping.levels_by_trait(ZTRAIT_CENTCOM)[1]) + var/turf/player_one_spot = locate(138, 131, SSmapping.levels_by_trait(ZTRAIT_CENTCOM)[1]) prep_player(player_one, player_one_spot) - var/turf/player_two_spot = locate(164, 34, SSmapping.levels_by_trait(ZTRAIT_CENTCOM)[1]) + var/turf/player_two_spot = locate(154, 131, SSmapping.levels_by_trait(ZTRAIT_CENTCOM)[1]) prep_player(player_two, player_two_spot) /obj/structure/fight_button/proc/prep_player(mob/living/carbon/human/ghost/player, turf/move_to) diff --git a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/anime.dm b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/anime.dm index 6faea383a344..19657a190df7 100644 --- a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/anime.dm +++ b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/anime.dm @@ -1,11 +1,11 @@ ///ANIME ACCESSORIES GO HERE /datum/sprite_accessory/anime_head icon = 'monkestation/icons/mob/anime/anime_head.dmi' - color_src = ANIME + color_src = ANIME_COLOR /datum/sprite_accessory/anime_head/none name = "None" - icon_state = "None" + icon_state = "none" /datum/sprite_accessory/anime_head/pony name = "Pony Ears" @@ -70,7 +70,7 @@ /datum/sprite_accessory/anime_middle icon = 'monkestation/icons/mob/anime/anime_middle.dmi' - color_src = ANIME + color_src = ANIME_COLOR /datum/sprite_accessory/anime_middle/none name = "None" @@ -106,7 +106,7 @@ /datum/sprite_accessory/anime_bottom icon = 'monkestation/icons/mob/anime/anime_bottom.dmi' - color_src = ANIME + color_src = ANIME_COLOR /datum/sprite_accessory/anime_bottom/none name = "None" diff --git a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/arachnid_appendages.dm b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/arachnid_appendages.dm index 591efc167c78..ce030464fdc0 100644 --- a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/arachnid_appendages.dm +++ b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/arachnid_appendages.dm @@ -1,6 +1,7 @@ /datum/sprite_accessory/arachnid_appendages icon = 'monkestation/icons/mob/species/arachnid/arachnid_appendages.dmi' - color_src = MUTCOLORS + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /datum/sprite_accessory/arachnid_appendages/long name = "Long" diff --git a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/arachnid_chelicerae.dm b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/arachnid_chelicerae.dm index b7791913b753..a2b375b81124 100644 --- a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/arachnid_chelicerae.dm +++ b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/arachnid_chelicerae.dm @@ -1,6 +1,7 @@ /datum/sprite_accessory/arachnid_chelicerae icon = 'monkestation/icons/mob/species/arachnid/arachnid_chelicerae.dmi' - color_src = MUTCOLORS + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /datum/sprite_accessory/arachnid_chelicerae/basic name = "Basic" diff --git a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ethereal_horns.dm b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ethereal_horns.dm index c5ed93a8a100..a1a1a95bcedb 100644 --- a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ethereal_horns.dm +++ b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ethereal_horns.dm @@ -1,6 +1,7 @@ /datum/sprite_accessory/ethereal_horns icon = 'monkestation/icons/mob/species/ethereal/ethereal_horns.dmi' - color_src = MUTCOLORS + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /datum/sprite_accessory/ethereal_horns/none name = "None" diff --git a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ethereal_tail.dm b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ethereal_tail.dm index 5ccec9b8e836..846f89cb8491 100644 --- a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ethereal_tail.dm +++ b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ethereal_tail.dm @@ -1,6 +1,7 @@ /datum/sprite_accessory/tails/ethereal icon = 'monkestation/icons/mob/species/ethereal/ethereal_tail.dmi' - color_src = MUTCOLORS + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /datum/sprite_accessory/tails/ethereal/none name = "None" diff --git a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/floran_leaves.dm b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/floran_leaves.dm index 6f7e85ee8fe1..efad9524773c 100644 --- a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/floran_leaves.dm +++ b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/floran_leaves.dm @@ -1,6 +1,8 @@ /datum/sprite_accessory/floran_leaves icon = 'monkestation/icons/mob/species/floran/floran_leaves.dmi' - color_src = MUTCOLORS_SECONDARY + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR_SECONDARY + fallback_key = MUTANT_COLOR //Should be MUTCOLORS_SECONDARY, but while its not working it will be the inverse of MUTCOLORS /datum/sprite_accessory/floran_leaves/furnivour diff --git a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/goblin_accessories.dm b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/goblin_accessories.dm index b0787c33c9be..1019ce177f89 100644 --- a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/goblin_accessories.dm +++ b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/goblin_accessories.dm @@ -1,6 +1,7 @@ /datum/sprite_accessory/goblin_ears icon = 'monkestation/icons/mob/species/goblin/goblin_ears.dmi' - color_src = MUTCOLORS + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /datum/sprite_accessory/goblin_ears/normal name = "Normal" diff --git a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ipc_antenna.dm b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ipc_antenna.dm index b1a9db5a0180..0c80627538d1 100644 --- a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ipc_antenna.dm +++ b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ipc_antenna.dm @@ -1,10 +1,11 @@ /datum/sprite_accessory/ipc_antennas icon = 'monkestation/icons/mob/species/ipc/ipc_antennas.dmi' - color_src = MUTCOLORS + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /datum/sprite_accessory/ipc_antennas/none name = "None" - icon_state = "None" + icon_state = "none" /datum/sprite_accessory/ipc_antennas/angled name = "Angled" diff --git a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ipc_chassis.dm b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ipc_chassis.dm index b2ccc3e5c1ab..ebf898886a06 100644 --- a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ipc_chassis.dm +++ b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/ipc_chassis.dm @@ -5,8 +5,9 @@ /datum/sprite_accessory/ipc_chassis/mcgreyscale name = "Morpheus Cyberkinetics (Custom)" - color_src = MUTCOLORS icon_state = "mcgipc" + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /datum/sprite_accessory/ipc_chassis/bishop_cyberkinetics name = "Bishop Cyberkinetics" diff --git a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/multi_part.dm b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/multi_part.dm index 573439e85dc8..698d2068cafa 100644 --- a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/multi_part.dm +++ b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/multi_part.dm @@ -5,7 +5,9 @@ var/list/external_slots = list() /datum/sprite_accessory/body_markings - color_src = MUTCOLORS_SECONDARY + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR_SECONDARY + fallback_key = MUTANT_COLOR /datum/sprite_accessory/body_markings/light_belly name = "Light Belly" diff --git a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/sock_color.dm b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/sock_color.dm index 4e9b4b1a343d..9e63e1dfb69a 100644 --- a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/sock_color.dm +++ b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/sock_color.dm @@ -15,4 +15,4 @@ var/species_type = preferences.read_preference(/datum/preference/choiced/species) var/datum/species/species = new species_type - return !(NO_UNDERWEAR in species.species_traits) + return !(TRAIT_NO_UNDERWEAR in species.inherent_traits) diff --git a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/tails.dm b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/tails.dm index 5a459b6b1758..55ec414d53cb 100644 --- a/monkestation/code/modules/mob/dead/new_player/sprite_accessories/tails.dm +++ b/monkestation/code/modules/mob/dead/new_player/sprite_accessories/tails.dm @@ -1,6 +1,6 @@ /datum/sprite_accessory/tails/monkey icon = 'monkestation/icons/mob/species/simian/tails.dmi' - color_src = SKINTONES + color_src = SKIN_COLOR /datum/sprite_accessory/tails/monkey/none name = "None" diff --git a/monkestation/code/modules/mob/living/carbon/human/_species.dm b/monkestation/code/modules/mob/living/carbon/human/_species.dm index 82102e3ae40d..7ab2874054b1 100644 --- a/monkestation/code/modules/mob/living/carbon/human/_species.dm +++ b/monkestation/code/modules/mob/living/carbon/human/_species.dm @@ -1,7 +1,3 @@ -/// Returns the species's laugh sound. -/datum/species/proc/get_laugh_sound(mob/living/carbon/human/human) - return - /datum/species/regenerate_organs(mob/living/carbon/organ_holder, datum/species/old_species, replace_current = TRUE, list/excluded_zones, visual_only = FALSE) var/list/skillchips = organ_holder.clone_skillchip_list() organ_holder.destroy_all_skillchips(silent = TRUE) diff --git a/monkestation/code/modules/mob/living/carbon/human/human.dm b/monkestation/code/modules/mob/living/carbon/human/human.dm index 531d405af991..b04c84fb7637 100644 --- a/monkestation/code/modules/mob/living/carbon/human/human.dm +++ b/monkestation/code/modules/mob/living/carbon/human/human.dm @@ -1,2 +1,11 @@ /mob/living/carbon/human/species/arachnid race = /datum/species/arachnid + +/mob/living/carbon/human/species/ipc + race = /datum/species/ipc + +/mob/living/carbon/human/species/werewolf + race = /datum/species/werewolf + +/mob/living/carbon/human/species/ornithid + race = /datum/species/ornithid diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/abductors.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/abductors.dm index d8a4a2a05ab6..d348dcf6891a 100644 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/abductors.dm +++ b/monkestation/code/modules/mob/living/carbon/human/species_type/abductors.dm @@ -28,9 +28,3 @@ user.update_sight() if(!QDELETED(signer)) QDEL_NULL(signer) - -/datum/species/abductor/get_scream_sound(mob/living/carbon/human/human) - return 'sound/weather/ashstorm/inside/weak_end.ogg' - -/datum/species/abductor/get_laugh_sound(mob/living/carbon/human/human) - return 'sound/weather/ashstorm/inside/weak_end.ogg' diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/android.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/android.dm index 0a6333246aa5..ed75cff1fc73 100644 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/android.dm +++ b/monkestation/code/modules/mob/living/carbon/human/species_type/android.dm @@ -4,13 +4,3 @@ mutantstomach = /obj/item/organ/internal/stomach/cybernetic/tier2 mutantliver = /obj/item/organ/internal/liver/cybernetic/tier2 mutantappendix = null - -/datum/species/android/get_scream_sound(mob/living/carbon/human/human) - return 'monkestation/sound/voice/screams/silicon/scream_silicon.ogg' - -/datum/species/android/get_laugh_sound(mob/living/carbon/human/human) - return pick( - 'monkestation/sound/voice/laugh/silicon/laugh_siliconE1M0.ogg', - 'monkestation/sound/voice/laugh/silicon/laugh_siliconE1M1.ogg', - 'monkestation/sound/voice/laugh/silicon/laugh_siliconM2.ogg', - ) diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/arachnid.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/arachnid.dm index 0ceef81fbf51..5783ec3e9789 100644 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/arachnid.dm +++ b/monkestation/code/modules/mob/living/carbon/human/species_type/arachnid.dm @@ -4,20 +4,19 @@ id = SPECIES_ARACHNIDS changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN visual_gender = FALSE - species_traits = list( - MUTCOLORS, + inherent_traits = list( + TRAIT_MUTANT_COLORS, ) inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG external_organs = list( /obj/item/organ/external/arachnid_appendages = "long", /obj/item/organ/external/chelicerae = "basic") meat = /obj/item/food/meat/slab/spider - disliked_food = NONE // Okay listen, i don't actually know what irl spiders don't like to eat and i'm pretty tired of looking for answers. - liked_food = GORE | MEAT | BUGS | GROSS species_language_holder = /datum/language_holder/fly mutanttongue = /obj/item/organ/internal/tongue/arachnid mutanteyes = /obj/item/organ/internal/eyes/night_vision/arachnid - speedmod = -0.1 + mutantheart = /obj/item/organ/internal/heart/spider + exotic_bloodtype = /datum/blood_type/spider inherent_factions = list(FACTION_SPIDER) bodypart_overrides = list( BODY_ZONE_HEAD = /obj/item/bodypart/head/arachnid, @@ -28,7 +27,7 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/arachnid, ) -/datum/species/arachnid/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) +/datum/species/arachnid/handle_chemical(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) if(chem.type == /datum/reagent/toxin/pestkiller) H.adjustToxLoss(3 * REM * seconds_per_tick) H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM * seconds_per_tick) @@ -49,12 +48,6 @@ if(istype(attacking_item, /obj/item/melee/flyswatter)) damage_mods += 30 // Yes, a 30x damage modifier -/datum/species/arachnid/get_scream_sound(mob/living/carbon/human/human) - return 'monkestation/sound/voice/screams/arachnid/arachnid_scream.ogg' - -/datum/species/arachnid/get_laugh_sound(mob/living/carbon/human/human) - return 'monkestation/sound/voice/laugh/arachnid/arachnid_laugh.ogg' - /datum/species/arachnid/get_species_description() return "Arachnids are a species of humanoid spiders employed by Nanotrasen in recent years." // Allan please add details diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/dullahan.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/dullahan.dm deleted file mode 100644 index e0063dc9bb7b..000000000000 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/dullahan.dm +++ /dev/null @@ -1,25 +0,0 @@ -/datum/species/dullahan/get_scream_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - if(prob(1)) - return 'sound/voice/human/wilhelm_scream.ogg' - return pick( - 'sound/voice/human/malescream_1.ogg', - 'sound/voice/human/malescream_2.ogg', - 'sound/voice/human/malescream_3.ogg', - 'sound/voice/human/malescream_4.ogg', - 'sound/voice/human/malescream_5.ogg', - 'sound/voice/human/malescream_6.ogg', - ) - - return pick( - 'sound/voice/human/femalescream_1.ogg', - 'sound/voice/human/femalescream_2.ogg', - 'sound/voice/human/femalescream_3.ogg', - 'sound/voice/human/femalescream_4.ogg', - 'sound/voice/human/femalescream_5.ogg', - ) -/datum/species/dullahan/get_laugh_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - return pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg') - else - return 'sound/voice/human/womanlaugh.ogg' diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/ethereal.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/ethereal.dm index d97fcac41e35..124bf7660a66 100644 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/ethereal.dm +++ b/monkestation/code/modules/mob/living/carbon/human/species_type/ethereal.dm @@ -10,25 +10,27 @@ external_organs = list( /obj/item/organ/external/ethereal_horns = "None", /obj/item/organ/external/tail/ethereal = "None") - exotic_blood = /datum/reagent/consumable/liquidelectricity //Liquid Electricity. fuck you think of something better gamer - exotic_bloodtype = "LE" + exotic_bloodtype = /datum/blood_type/crew/ethereal + + // Body temperature for ethereals is much higher then humans as they like hotter environments + bodytemp_normal = (BODYTEMP_NORMAL + 50) + temperature_homeostasis_speed = 3 + temperature_normalization_speed = 3 + siemens_coeff = 0.5 //They thrive on energy brutemod = 1.25 //They're weak to punches payday_modifier = 1 inherent_traits = list( + TRAIT_MUTANT_COLORS, + TRAIT_FIXED_MUTANT_COLORS, + TRAIT_NO_UNDERWEAR, TRAIT_NOHUNGER, TRAIT_NO_BLOODLOSS_DAMAGE, //we handle that species-side. ) - species_traits = list( - DYNCOLORS, - NO_UNDERWEAR, - ) changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT species_cookie = /obj/item/food/energybar species_language_holder = /datum/language_holder/ethereal - toxic_food = NONE - // Body temperature for ethereals is much higher then humans as they like hotter environments - bodytemp_normal = (BODYTEMP_NORMAL + 50) + bodytemp_heat_damage_limit = FIRE_MINIMUM_TEMPERATURE_TO_SPREAD // about 150C // Cold temperatures hurt faster as it is harder to move with out the heat energy bodytemp_cold_damage_limit = (T20C - 10) // about 10c @@ -66,7 +68,8 @@ if(!ishuman(new_ethereal)) return var/mob/living/carbon/human/ethereal = new_ethereal - default_color = ethereal.dna.features["ethcolor"] + var/datum/color_palette/generic_colors/palette = ethereal.dna.color_palettes[/datum/color_palette/generic_colors] + default_color = palette.ethereal_color r1 = GETREDPART(default_color) g1 = GETGREENPART(default_color) b1 = GETBLUEPART(default_color) @@ -77,7 +80,6 @@ ethereal_light = ethereal.mob_light(light_type = /obj/effect/dummy/lighting_obj/moblight/species) spec_updatehealth(ethereal) new_ethereal.set_safe_hunger_level() - update_mail_goodies(ethereal) var/obj/item/organ/internal/heart/ethereal/ethereal_heart = new_ethereal.get_organ_slot(ORGAN_SLOT_HEART) ethereal_heart.ethereal_color = default_color @@ -94,13 +96,6 @@ QDEL_NULL(ethereal_light) return ..() -/datum/species/ethereal/update_quirk_mail_goodies(mob/living/carbon/human/recipient, datum/quirk/quirk, list/mail_goodies = list()) - if(istype(quirk, /datum/quirk/blooddeficiency)) - mail_goodies += list( - /obj/item/reagent_containers/blood/ethereal - ) - return ..() - /datum/species/ethereal/random_name(gender,unique,lastname) if(unique) return random_unique_ethereal_name() @@ -110,100 +105,16 @@ return randname /datum/species/ethereal/randomize_features(mob/living/carbon/human/human_mob) - human_mob.dna.features["ethcolor"] = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)] - - -/datum/species/ethereal/spec_life(mob/living/carbon/human/ethereal, seconds_per_tick, times_fired) - if(ethereal.stat == DEAD) - return - adjust_charge(ethereal, -ETHEREAL_BLOOD_CHARGE_FACTOR * seconds_per_tick, TRUE) - handle_charge(ethereal, seconds_per_tick, times_fired) - -/datum/species/ethereal/proc/adjust_charge(mob/living/carbon/human/ethereal, amount, passive) - if(passive) - if(ethereal.blood_volume < ETHEREAL_BLOOD_CHARGE_LOWEST_PASSIVE) //Do not apply the clamp if its below the passive reduction level(no infinite blood sorry) - return - if(ethereal.blood_volume + amount < ETHEREAL_BLOOD_CHARGE_LOWEST_PASSIVE+1) - ethereal.blood_volume = ETHEREAL_BLOOD_CHARGE_LOWEST_PASSIVE+1 //bottom them off here if the end result would be less than the stopping point. - ethereal.blood_volume = clamp(ethereal.blood_volume + amount, ETHEREAL_BLOOD_CHARGE_LOWEST_PASSIVE+1, ETHEREAL_BLOOD_CHARGE_DANGEROUS) - return - ethereal.blood_volume = clamp(ethereal.blood_volume + amount, ETHEREAL_BLOOD_CHARGE_NONE, ETHEREAL_BLOOD_CHARGE_DANGEROUS) - -/datum/species/ethereal/proc/handle_charge(mob/living/carbon/human/ethereal, seconds_per_tick, times_fired) - brutemod = 1.15 - var/word = pick("like you can't breathe","your lungs locking up","extremely lethargic") - var/blood_volume = ethereal.blood_volume - if(HAS_TRAIT(ethereal, TRAIT_ETHEREAL_NO_OVERCHARGE)) - blood_volume = min(blood_volume, ETHEREAL_BLOOD_CHARGE_FULL) - switch(blood_volume) - if(-INFINITY to ETHEREAL_BLOOD_CHARGE_LOWEST_PASSIVE) - ethereal.add_mood_event("charge", /datum/mood_event/decharged) - ethereal.clear_alert("ethereal_overcharge") - ethereal.throw_alert(ALERT_ETHEREAL_CHARGE, /atom/movable/screen/alert/emptycell/ethereal) - brutemod = 2 - if(SPT_PROB(7.5, seconds_per_tick)) - to_chat(src, span_warning("You feel [word].")) - ethereal.adjustOxyLoss(round(0.01 * (ETHEREAL_BLOOD_CHARGE_LOW - ethereal.blood_volume) * seconds_per_tick, 1)) - if(ETHEREAL_BLOOD_CHARGE_LOWEST_PASSIVE to ETHEREAL_BLOOD_CHARGE_LOW) - ethereal.clear_alert("ethereal_overcharge") - ethereal.add_mood_event("charge", /datum/mood_event/decharged) - ethereal.throw_alert(ALERT_ETHEREAL_CHARGE, /atom/movable/screen/alert/lowcell/ethereal, 3) - brutemod = 1.5 - if(ethereal.health > 10.5) - ethereal.apply_damage(0.155 * seconds_per_tick, TOX, null, null, ethereal) - if(ETHEREAL_BLOOD_CHARGE_LOW to ETHEREAL_BLOOD_CHARGE_NORMAL) - ethereal.clear_alert("ethereal_overcharge") - ethereal.add_mood_event("charge", /datum/mood_event/lowpower) - ethereal.throw_alert(ALERT_ETHEREAL_CHARGE, /atom/movable/screen/alert/lowcell/ethereal, 2) - brutemod = 1.25 - if(ETHEREAL_BLOOD_CHARGE_ALMOSTFULL to ETHEREAL_BLOOD_CHARGE_FULL) - ethereal.clear_alert("ethereal_overcharge") - ethereal.clear_alert("ethereal_charge") - ethereal.add_mood_event("charge", /datum/mood_event/charged) - brutemod = 1 - if(ETHEREAL_BLOOD_CHARGE_FULL to ETHEREAL_BLOOD_CHARGE_OVERLOAD) - ethereal.clear_alert("ethereal_charge") - ethereal.add_mood_event("charge", /datum/mood_event/overcharged) - ethereal.throw_alert(ALERT_ETHEREAL_OVERCHARGE, /atom/movable/screen/alert/ethereal_overcharge, 1) - brutemod = 1.25 - if(ETHEREAL_BLOOD_CHARGE_OVERLOAD to ETHEREAL_BLOOD_CHARGE_DANGEROUS) - ethereal.clear_alert("ethereal_charge") - ethereal.add_mood_event("charge", /datum/mood_event/supercharged) - ethereal.throw_alert(ALERT_ETHEREAL_OVERCHARGE, /atom/movable/screen/alert/ethereal_overcharge, 2) - ethereal.apply_damage(0.2 * seconds_per_tick, TOX, null, null, ethereal) - brutemod = 1.5 - if(SPT_PROB(5, seconds_per_tick)) // 5% each seacond for ethereals to explosively release excess energy if it reaches dangerous levels - discharge_process(ethereal) - else - ethereal.clear_mood_event("charge") - ethereal.clear_alert(ALERT_ETHEREAL_CHARGE) - ethereal.clear_alert(ALERT_ETHEREAL_OVERCHARGE) - -/datum/species/ethereal/proc/discharge_process(mob/living/carbon/human/ethereal) - to_chat(ethereal, span_warning("You begin to lose control over your charge!")) - ethereal.visible_message(span_danger("[ethereal] begins to spark violently!")) - - var/static/mutable_appearance/overcharge //shameless copycode from lightning spell - overcharge = overcharge || mutable_appearance('icons/effects/effects.dmi', "electricity", EFFECTS_LAYER) - ethereal.add_overlay(overcharge) - - if(do_after(ethereal, 5 SECONDS, timed_action_flags = (IGNORE_USER_LOC_CHANGE|IGNORE_HELD_ITEM|IGNORE_INCAPACITATED))) - ethereal.flash_lighting_fx(5, 7, ethereal.dna.species.fixed_mut_color ? ethereal.dna.species.fixed_mut_color : ethereal.dna.features["mcolor"]) - - playsound(ethereal, 'sound/magic/lightningshock.ogg', 100, TRUE, extrarange = 5) - ethereal.cut_overlay(overcharge) - tesla_zap(ethereal, 2, ethereal.blood_volume*9, ZAP_OBJ_DAMAGE | ZAP_GENERATES_POWER | ZAP_ALLOW_DUPLICATES) - adjust_charge(ethereal, ETHEREAL_BLOOD_CHARGE_FULL - ethereal.blood_volume) - ethereal.visible_message(span_danger("[ethereal] violently discharges energy!"), span_warning("You violently discharge energy!")) - - ethereal.Paralyze(100) + var/datum/color_palette/generic_colors/palette = human_mob.dna.color_palettes[/datum/color_palette/generic_colors] + palette.ethereal_color = GLOB.color_list_ethereal[pick(GLOB.color_list_ethereal)] /datum/species/ethereal/spec_updatehealth(mob/living/carbon/human/ethereal) . = ..() + var/datum/color_palette/generic_colors/palette = ethereal.dna.color_palettes[/datum/color_palette/generic_colors] if(!ethereal_light) return - if(default_color != ethereal.dna.features["ethcolor"]) - var/new_color = ethereal.dna.features["ethcolor"] + if(default_color != palette.ethereal_color) + var/new_color = palette.ethereal_color r1 = GETREDPART(new_color) g1 = GETGREENPART(new_color) b1 = GETBLUEPART(new_color) @@ -291,16 +202,6 @@ user.visible_message(span_notice("[user] quickly strikes [item] across [lightbulb]'s skin, [lightbulb.p_their()] warmth lighting it!")) return COMPONENT_NO_AFTERATTACK -/datum/species/ethereal/get_scream_sound(mob/living/carbon/human/ethereal) - return pick( - 'sound/voice/ethereal/ethereal_scream_1.ogg', - 'sound/voice/ethereal/ethereal_scream_2.ogg', - 'sound/voice/ethereal/ethereal_scream_3.ogg', - ) - -/datum/species/ethereal/get_laugh_sound(mob/living/carbon/human/ethereal) - return 'monkestation/sound/voice/laugh/ethereal/ethereal_laugh_1.ogg' - /datum/species/ethereal/get_species_description() return "Coming from the planet of Sprout, the theocratic ethereals are \ separated socially by caste, and espouse a dogma of aiding the weak and \ diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/floran.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/floran.dm index d2a3701ff5c2..4b15d3e65394 100644 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/floran.dm +++ b/monkestation/code/modules/mob/living/carbon/human/species_type/floran.dm @@ -3,15 +3,11 @@ plural_form = "Florans" id = SPECIES_FLORAN sexes = TRUE - species_traits = list( - MUTCOLORS, - MUTCOLORS_SECONDARY, - NO_UNDERWEAR, - ) inherent_traits = list( - TRAIT_PLANT_SAFE, + TRAIT_MUTANT_COLORS, + TRAIT_MUTANT_COLORS_SECONDARY, + TRAIT_NO_UNDERWEAR, TRAIT_NO_JUMPSUIT, - TRAIT_LIMBATTACHMENT, TRAIT_EASYDISMEMBER ) external_organs = list( @@ -23,11 +19,8 @@ burnmod = 1.8 heatmod = 0.67 //Same as lizard people coldmod = 1.5 //Same as lizard people - speedmod = -0.1 //Same as arachnids meat = /obj/item/food/meat/slab/human/mutant/plant - exotic_blood = /datum/reagent/water - // disliked_food = VEGETABLES | FRUIT | GRAIN - liked_food = MEAT | BUGS | GORE + exotic_bloodtype = /datum/blood_type/water changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT species_language_holder = /datum/language_holder/plant @@ -39,12 +32,12 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/floran, BODY_ZONE_CHEST = /obj/item/bodypart/chest/floran, ) - mutanttongue = /obj/item/organ/internal/tongue/lizard + mutanttongue = /obj/item/organ/internal/tongue/floran mutanteyes = /obj/item/organ/internal/eyes/floran - - ass_image = 'icons/ass/asspodperson.png' + mutantheart = /obj/item/organ/internal/heart/pod /datum/species/floran/spec_life(mob/living/carbon/human/H, seconds_per_tick, times_fired) + . = ..() if(H.stat == DEAD) return @@ -57,19 +50,7 @@ H.adjustToxLoss(-0.25 * seconds_per_tick) H.adjustOxyLoss(-0.25 * seconds_per_tick) -/datum/species/floran/on_species_gain(mob/living/carbon/new_floran, datum/species/old_species, pref_load) - . = ..() - if(ishuman(new_floran)) - update_mail_goodies(new_floran) - -/datum/species/floran/update_quirk_mail_goodies(mob/living/carbon/human/recipient, datum/quirk/quirk, list/mail_goodies = list()) - if(istype(quirk, /datum/quirk/blooddeficiency)) - mail_goodies += list( - /obj/item/reagent_containers/blood/podperson - ) - return ..() - -/datum/species/floran/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) +/datum/species/floran/handle_chemical(datum/reagent/chem, mob/living/carbon/human/H, seconds_per_tick, times_fired) if(chem.type == /datum/reagent/toxin/plantbgone) H.adjustToxLoss(3 * REM * seconds_per_tick) H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM * seconds_per_tick) @@ -83,17 +64,6 @@ /datum/species/floran/randomize_features(mob/living/carbon/human_mob) randomize_external_organs(human_mob) -/datum/species/floran/get_scream_sound(mob/living/carbon/human/human) - return pick( - 'sound/voice/lizard/lizard_scream_1.ogg', - 'sound/voice/lizard/lizard_scream_2.ogg', - 'sound/voice/lizard/lizard_scream_3.ogg', - 'monkestation/sound/voice/screams/lizard/lizard_scream_5.ogg', - ) - -/datum/species/floran/get_laugh_sound(mob/living/carbon/human/human) - return 'monkestation/sound/voice/laugh/lizard/lizard_laugh.ogg' - /datum/species/floran/get_species_description() return "Plant-based humanoids, they are extremely violent carnivores with no central government or power structure, \ split into numerous tribes spread across the universe, each led by a Greenfinger. \ @@ -160,3 +130,6 @@ /datum/bodypart_overlay/mutant/floran_leaves layers = EXTERNAL_ADJACENT feature_key = "floran_leaves" + + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR_SECONDARY diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/flypeople.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/flypeople.dm index a4cde86ec6bb..bc3745baedbf 100644 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/flypeople.dm +++ b/monkestation/code/modules/mob/living/carbon/human/species_type/flypeople.dm @@ -1,29 +1,2 @@ /datum/species/fly payday_modifier = 1 - -/datum/species/fly/get_scream_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - if(prob(1)) - return 'sound/voice/human/wilhelm_scream.ogg' - return pick( - 'sound/voice/human/malescream_1.ogg', - 'sound/voice/human/malescream_2.ogg', - 'sound/voice/human/malescream_3.ogg', - 'sound/voice/human/malescream_4.ogg', - 'sound/voice/human/malescream_5.ogg', - 'sound/voice/human/malescream_6.ogg', - ) - - return pick( - 'sound/voice/human/femalescream_1.ogg', - 'sound/voice/human/femalescream_2.ogg', - 'sound/voice/human/femalescream_3.ogg', - 'sound/voice/human/femalescream_4.ogg', - 'sound/voice/human/femalescream_5.ogg', - ) -/datum/species/fly/get_laugh_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - return pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg') - else - return 'sound/voice/human/womanlaugh.ogg' - diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/goblin.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/goblin.dm index a4dfb03b1d78..a3cb05e4acce 100644 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/goblin.dm +++ b/monkestation/code/modules/mob/living/carbon/human/species_type/goblin.dm @@ -4,10 +4,8 @@ id = SPECIES_GOBLIN changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN sexes = TRUE - species_traits = list( - MUTCOLORS, - ) inherent_traits = list( + TRAIT_MUTANT_COLORS, TRAIT_DWARF, TRAIT_QUICK_BUILD, TRAIT_EASILY_WOUNDED, @@ -19,12 +17,10 @@ /obj/item/organ/external/goblin_ears = "long", ) meat = /obj/item/food/meat/steak - disliked_food = VEGETABLES - liked_food = GORE | MEAT | GROSS + mutanttongue = /obj/item/organ/internal/tongue/goblin species_language_holder = /datum/language_holder/goblin maxhealthmod = 0.75 stunmod = 1.2 - speedmod = -0.25 payday_modifier = 1 bodypart_overrides = list( BODY_ZONE_HEAD = /obj/item/bodypart/head/goblin, @@ -38,33 +34,6 @@ /mob/living/carbon/human/species/goblin race = /datum/species/goblin -/datum/species/goblin/get_scream_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - if(prob(1)) - return 'sound/voice/human/wilhelm_scream.ogg' - return pick( - 'sound/voice/human/malescream_1.ogg', - 'sound/voice/human/malescream_2.ogg', - 'sound/voice/human/malescream_3.ogg', - 'sound/voice/human/malescream_4.ogg', - 'sound/voice/human/malescream_5.ogg', - 'sound/voice/human/malescream_6.ogg', - ) - - return pick( - 'sound/voice/human/femalescream_1.ogg', - 'sound/voice/human/femalescream_2.ogg', - 'sound/voice/human/femalescream_3.ogg', - 'sound/voice/human/femalescream_4.ogg', - 'sound/voice/human/femalescream_5.ogg', - ) - -/datum/species/goblin/get_laugh_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - return pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg') - else - return 'sound/voice/human/womanlaugh.ogg' - /datum/language_holder/goblin understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), /datum/language/goblin = list(LANGUAGE_ATOM)) @@ -140,24 +109,43 @@ icon_greyscale = 'monkestation/icons/mob/species/goblin/bodyparts.dmi' limb_id = SPECIES_GOBLIN is_dimorphic = FALSE + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/chest/goblin icon_greyscale = 'monkestation/icons/mob/species/goblin/bodyparts.dmi' limb_id = SPECIES_GOBLIN is_dimorphic = TRUE + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/left/goblin icon_greyscale = 'monkestation/icons/mob/species/goblin/bodyparts.dmi' limb_id = SPECIES_GOBLIN + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/right/goblin icon_greyscale = 'monkestation/icons/mob/species/goblin/bodyparts.dmi' limb_id = SPECIES_GOBLIN + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/left/goblin icon_greyscale = 'monkestation/icons/mob/species/goblin/bodyparts.dmi' limb_id = SPECIES_GOBLIN + speed_modifier = -0.125 + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/right/goblin icon_greyscale = 'monkestation/icons/mob/species/goblin/bodyparts.dmi' limb_id = SPECIES_GOBLIN + speed_modifier = -0.125 + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR + +/obj/item/organ/internal/tongue/goblin + name = "goblin tongue" + disliked_foodtypes = VEGETABLES + liked_foodtypes = GORE | MEAT | GROSS diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/golems.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/golems.dm deleted file mode 100644 index 6f1d34a81df3..000000000000 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/golems.dm +++ /dev/null @@ -1,25 +0,0 @@ -/datum/species/golem/get_scream_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - if(prob(1)) - return 'sound/voice/human/wilhelm_scream.ogg' - return pick( - 'sound/voice/human/malescream_1.ogg', - 'sound/voice/human/malescream_2.ogg', - 'sound/voice/human/malescream_3.ogg', - 'sound/voice/human/malescream_4.ogg', - 'sound/voice/human/malescream_5.ogg', - 'sound/voice/human/malescream_6.ogg', - ) - - return pick( - 'sound/voice/human/femalescream_1.ogg', - 'sound/voice/human/femalescream_2.ogg', - 'sound/voice/human/femalescream_3.ogg', - 'sound/voice/human/femalescream_4.ogg', - 'sound/voice/human/femalescream_5.ogg', - ) -/datum/species/golem/get_laugh_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - return pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg') - else - return 'sound/voice/human/womanlaugh.ogg' diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/humans.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/humans.dm deleted file mode 100644 index 2a749444ea44..000000000000 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/humans.dm +++ /dev/null @@ -1,5 +0,0 @@ -/datum/species/human/get_laugh_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - return pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg') - else - return 'sound/voice/human/womanlaugh.ogg' diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/jellypeople.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/jellypeople.dm deleted file mode 100644 index 164989581bc9..000000000000 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/jellypeople.dm +++ /dev/null @@ -1,25 +0,0 @@ -/datum/species/jelly/get_scream_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - if(prob(1)) - return 'sound/voice/human/wilhelm_scream.ogg' - return pick( - 'sound/voice/human/malescream_1.ogg', - 'sound/voice/human/malescream_2.ogg', - 'sound/voice/human/malescream_3.ogg', - 'sound/voice/human/malescream_4.ogg', - 'sound/voice/human/malescream_5.ogg', - 'sound/voice/human/malescream_6.ogg', - ) - - return pick( - 'sound/voice/human/femalescream_1.ogg', - 'sound/voice/human/femalescream_2.ogg', - 'sound/voice/human/femalescream_3.ogg', - 'sound/voice/human/femalescream_4.ogg', - 'sound/voice/human/femalescream_5.ogg', - ) -/datum/species/jelly/get_laugh_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - return pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg') - else - return 'sound/voice/human/womanlaugh.ogg' diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/lizardpeople.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/lizardpeople.dm index 757abda081ce..7e93eac5fe71 100644 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/lizardpeople.dm +++ b/monkestation/code/modules/mob/living/carbon/human/species_type/lizardpeople.dm @@ -1,31 +1,5 @@ /datum/species/lizard payday_modifier = 1 - special_step_sounds = list( - 'sound/effects/footstep/hardclaw1.ogg', - 'sound/effects/footstep/hardclaw2.ogg', - 'sound/effects/footstep/hardclaw3.ogg', - 'sound/effects/footstep/hardclaw4.ogg', - ) -/datum/species/lizard/get_scream_sound(mob/living/carbon/human/human) - if(human.gender ==MALE) - return pick( - 'sound/voice/lizard/lizard_scream_1.ogg', - 'sound/voice/lizard/lizard_scream_2.ogg', - 'sound/voice/lizard/lizard_scream_3.ogg', - 'monkestation/sound/voice/screams/lizard/lizard_scream_4.ogg', - ) - - return pick( - 'sound/voice/lizard/lizard_scream_1.ogg', - 'sound/voice/lizard/lizard_scream_2.ogg', - 'sound/voice/lizard/lizard_scream_3.ogg', - 'monkestation/sound/voice/screams/lizard/lizard_scream_5.ogg', - ) - -/datum/species/lizard/get_laugh_sound(mob/living/carbon/human/human) - if(prob(1)) - return 'monkestation/sound/voice/weh.ogg' - return 'monkestation/sound/voice/laugh/lizard/lizard_laugh.ogg' /datum/species/lizard/get_custom_worn_config_fallback(item_slot, obj/item/item) diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/monkeys.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/monkeys.dm deleted file mode 100644 index ec22924e4433..000000000000 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/monkeys.dm +++ /dev/null @@ -1,2 +0,0 @@ -/datum/species/monkey/get_laugh_sound(mob/living/carbon/human/human) - return 'monkestation/sound/voice/laugh/simian/monkey_laugh_1.ogg' diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/mothmen.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/mothmen.dm deleted file mode 100644 index f8fec251c2ac..000000000000 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/mothmen.dm +++ /dev/null @@ -1,6 +0,0 @@ -/datum/species/moth/get_laugh_sound(mob/living/carbon/human/human) - return pick( - 'monkestation/sound/voice/laugh/moth/mothchitter.ogg', - 'monkestation/sound/voice/laugh/moth/mothlaugh.ogg', - 'monkestation/sound/voice/laugh/moth/mothsqueak.ogg', - ) diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/plasmamen.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/plasmamen.dm index af3c0ff2a9a7..2d87b7efc9dd 100644 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/plasmamen.dm +++ b/monkestation/code/modules/mob/living/carbon/human/species_type/plasmamen.dm @@ -1,5 +1,2 @@ /datum/species/plasmaman payday_modifier = 1 - -/datum/species/plasmaman/get_laugh_sound(mob/living/carbon/human/human) - return 'monkestation/sound/voice/laugh/skeleton/skeleton_laugh.ogg' diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/podpeople.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/podpeople.dm deleted file mode 100644 index dd09e2fb0841..000000000000 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/podpeople.dm +++ /dev/null @@ -1,25 +0,0 @@ -/datum/species/pod/get_scream_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - if(prob(1)) - return 'sound/voice/human/wilhelm_scream.ogg' - return pick( - 'sound/voice/human/malescream_1.ogg', - 'sound/voice/human/malescream_2.ogg', - 'sound/voice/human/malescream_3.ogg', - 'sound/voice/human/malescream_4.ogg', - 'sound/voice/human/malescream_5.ogg', - 'sound/voice/human/malescream_6.ogg', - ) - - return pick( - 'sound/voice/human/femalescream_1.ogg', - 'sound/voice/human/femalescream_2.ogg', - 'sound/voice/human/femalescream_3.ogg', - 'sound/voice/human/femalescream_4.ogg', - 'sound/voice/human/femalescream_5.ogg', - ) -/datum/species/pod/get_laugh_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - return pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg') - else - return 'sound/voice/human/womanlaugh.ogg' diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/shadowpeople.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/shadowpeople.dm deleted file mode 100644 index ada2b2ec8bfb..000000000000 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/shadowpeople.dm +++ /dev/null @@ -1,25 +0,0 @@ -/datum/species/shadow/get_scream_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - if(prob(1)) - return 'sound/voice/human/wilhelm_scream.ogg' - return pick( - 'sound/voice/human/malescream_1.ogg', - 'sound/voice/human/malescream_2.ogg', - 'sound/voice/human/malescream_3.ogg', - 'sound/voice/human/malescream_4.ogg', - 'sound/voice/human/malescream_5.ogg', - 'sound/voice/human/malescream_6.ogg', - ) - - return pick( - 'sound/voice/human/femalescream_1.ogg', - 'sound/voice/human/femalescream_2.ogg', - 'sound/voice/human/femalescream_3.ogg', - 'sound/voice/human/femalescream_4.ogg', - 'sound/voice/human/femalescream_5.ogg', - ) -/datum/species/shadow/get_laugh_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - return pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg') - else - return 'sound/voice/human/womanlaugh.ogg' diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/simian.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/simian.dm index d3e17e50bb00..32539976f775 100644 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/simian.dm +++ b/monkestation/code/modules/mob/living/carbon/human/species_type/simian.dm @@ -5,33 +5,25 @@ bodytype = BODYTYPE_CUSTOM - species_traits = list( - NO_UNDERWEAR, - SPECIES_FUR, - SKINTONES, - ) inherent_traits = list( + TRAIT_FUR_COLORS, + TRAIT_MUTANT_COLORS, + TRAIT_NO_UNDERWEAR, TRAIT_VAULTING, TRAIT_KLEPTOMANIAC, TRAIT_MONKEYFRIEND ) - use_skintones = FALSE - inherent_biotypes = MOB_ORGANIC | MOB_HUMANOID mutanttongue = /obj/item/organ/internal/tongue/monkey changesource_flags = MIRROR_BADMIN | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN meat = /obj/item/food/meat/slab/monkey skinned_type = /obj/item/stack/sheet/animalhide/monkey - disliked_food = GROSS - liked_food = FRUIT | MEAT - uses_fur = TRUE //deathsound = 'monkestation/sound/voice/simian/deathsound.ogg' species_language_holder = /datum/language_holder/monkey maxhealthmod = 0.85 //small = weak stunmod = 1.3 - speedmod = -0.1 //lil bit faster custom_worn_icons = list( LOADOUT_ITEM_SUIT = SIMIAN_SUIT_ICON, @@ -60,20 +52,6 @@ /obj/item/organ/external/tail/simian = "Chimp" ) -/datum/species/simian/get_scream_sound(mob/living/carbon/human/human) - return pick( - 'sound/creatures/monkey/monkey_screech_1.ogg', - 'sound/creatures/monkey/monkey_screech_2.ogg', - 'sound/creatures/monkey/monkey_screech_3.ogg', - 'sound/creatures/monkey/monkey_screech_4.ogg', - 'sound/creatures/monkey/monkey_screech_5.ogg', - 'sound/creatures/monkey/monkey_screech_6.ogg', - 'sound/creatures/monkey/monkey_screech_7.ogg', - ) - -/datum/species/simian/get_laugh_sound(mob/living/carbon/human/human) - return 'monkestation/sound/voice/laugh/simian/monkey_laugh_1.ogg' - /datum/species/simian/get_species_description() return "Monke." diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/skeletons.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/skeletons.dm index 7aec8942833f..d3331a3a3439 100644 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/skeletons.dm +++ b/monkestation/code/modules/mob/living/carbon/human/species_type/skeletons.dm @@ -1,22 +1,14 @@ -/datum/species/skeleton/get_scream_sound(mob/living/carbon/human/human) - return 'monkestation/sound/voice/screams/skeleton/scream_skeleton.ogg' - -/datum/species/skeleton/get_laugh_sound(mob/living/carbon/human/human) - return 'monkestation/sound/voice/laugh/skeleton/skeleton_laugh.ogg' - /datum/species/skeleton/draconic // Alternate skeleton for drake blood that can process chems! name = "Draconic Skeleton" id = SPECIES_DRACONIC_SKELETON sexes = 0 meat = /obj/item/food/meat/slab/human/mutant/skeleton - species_traits = list( - NOTRANSSTING, - NO_DNA_COPY, - NO_UNDERWEAR, - NOHUSK, - ) inherent_traits = list( + TRAIT_NO_TRANSFORMATION_STING, + TRAIT_NO_DNA_COPY, + TRAIT_NO_UNDERWEAR, + TRAIT_NO_HUSK, TRAIT_CAN_USE_FLIGHT_POTION, TRAIT_EASYDISMEMBER, TRAIT_FAKEDEATH, diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/teratoma.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/teratoma.dm index 9b9f73d96eed..ea3b7679f50d 100644 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/teratoma.dm +++ b/monkestation/code/modules/mob/living/carbon/human/species_type/teratoma.dm @@ -2,22 +2,15 @@ name = "Teratoma" id = SPECIES_TERATOMA bodytype = BODYTYPE_ORGANIC | BODYTYPE_MONKEY - mutanttongue = /obj/item/organ/internal/tongue/monkey mutantbrain = /obj/item/organ/internal/brain/primate - species_traits = list( - NOAUGMENTS, - NOBLOODOVERLAY, - NOEYESPRITES, - NOTRANSSTING, - NOZOMBIE, - NO_DNA_COPY, - NO_UNDERWEAR, - ) inherent_traits = list( + TRAIT_NO_TRANSFORMATION_STING, + TRAIT_NO_BLOOD_OVERLAY, + TRAIT_NO_DNA_COPY, + TRAIT_NO_UNDERWEAR, TRAIT_BADDNA, TRAIT_CAN_STRIP, - TRAIT_CHUNKYFINGERS, TRAIT_EASILY_WOUNDED, TRAIT_GENELESS, TRAIT_ILLITERATE, @@ -25,11 +18,8 @@ TRAIT_NO_DNA_COPY, TRAIT_NO_JUMPSUIT, TRAIT_NO_ZOMBIFY, - TRAIT_PASSTABLE, TRAIT_PRIMITIVE, TRAIT_UNCONVERTABLE, // DEAR GOD NO - TRAIT_VAULTING, - TRAIT_VENTCRAWLER_ALWAYS, TRAIT_WEAK_SOUL, ) @@ -41,15 +31,13 @@ BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/teratoma, BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/teratoma, ) + mutanttongue = /obj/item/organ/internal/tongue/teratoma maxhealthmod = 0.75 stunmod = 1.4 - speedmod = -0.15 // stupid gremlins no_equip_flags = ITEM_SLOT_ICLOTHING | ITEM_SLOT_OCLOTHING | ITEM_SLOT_GLOVES | ITEM_SLOT_FEET | ITEM_SLOT_SUITSTORE changesource_flags = MIRROR_BADMIN - liked_food = MEAT | BUGS | GORE | GROSS | RAW - disliked_food = CLOTH sexes = FALSE species_language_holder = /datum/language_holder/monkey @@ -72,13 +60,6 @@ /datum/species/teratoma/random_name(gender, unique, lastname) return "teratoma ([rand(1, 999)])" -// Don't let them use chems that could potential change them into something non-teratoma. -/datum/species/teratoma/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/goober, seconds_per_tick, times_fired) - if(is_banned_chem(chem)) - chem.holder?.del_reagent(chem.type) - return TRUE - return ..() - // removes banned reagents from the list of reagents that'll be exposed /datum/species/teratoma/proc/prevent_banned_reagent_exposure(datum/source, list/reagents, datum/reagents/holder, methods, volume_modifier, show_message) SIGNAL_HANDLER @@ -100,7 +81,19 @@ )) return is_type_in_typecache(reagent, disallowed_chems_typecache) -/datum/species/teratoma/get_scream_sound(mob/living/carbon/human/monkey) +/datum/component/omen/teratoma + incidents_left = INFINITY + luck_mod = 0.75 + damage_mod = 0.2 + +/mob/living/carbon/human/species/teratoma + race = /datum/species/teratoma + +/obj/item/organ/internal/tongue/teratoma + liked_foodtypes = MEAT | BUGS | GORE | GROSS | RAW + disliked_foodtypes = CLOTH + +/obj/item/organ/internal/tongue/teratoma/get_scream_sound() return pick( 'sound/creatures/monkey/monkey_screech_1.ogg', 'sound/creatures/monkey/monkey_screech_2.ogg', @@ -111,10 +104,5 @@ 'sound/creatures/monkey/monkey_screech_7.ogg', ) -/datum/component/omen/teratoma - incidents_left = INFINITY - luck_mod = 0.75 - damage_mod = 0.2 - -/mob/living/carbon/human/species/teratoma - race = /datum/species/teratoma +/obj/item/organ/internal/tongue/teratoma/get_laugh_sound() + return 'monkestation/sound/voice/laugh/simian/monkey_laugh_1.ogg' diff --git a/monkestation/code/modules/mob/living/carbon/human/species_type/zombies.dm b/monkestation/code/modules/mob/living/carbon/human/species_type/zombies.dm deleted file mode 100644 index 15a07d281970..000000000000 --- a/monkestation/code/modules/mob/living/carbon/human/species_type/zombies.dm +++ /dev/null @@ -1,25 +0,0 @@ -/datum/species/zombie/get_scream_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - if(prob(1)) - return 'sound/voice/human/wilhelm_scream.ogg' - return pick( - 'sound/voice/human/malescream_1.ogg', - 'sound/voice/human/malescream_2.ogg', - 'sound/voice/human/malescream_3.ogg', - 'sound/voice/human/malescream_4.ogg', - 'sound/voice/human/malescream_5.ogg', - 'sound/voice/human/malescream_6.ogg', - ) - - return pick( - 'sound/voice/human/femalescream_1.ogg', - 'sound/voice/human/femalescream_2.ogg', - 'sound/voice/human/femalescream_3.ogg', - 'sound/voice/human/femalescream_4.ogg', - 'sound/voice/human/femalescream_5.ogg', - ) -/datum/species/zombie/get_laugh_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - return pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg') - else - return 'sound/voice/human/womanlaugh.ogg' diff --git a/monkestation/code/modules/mob/login.dm b/monkestation/code/modules/mob/login.dm index 9f7768fb04b8..0c20722e48d1 100644 --- a/monkestation/code/modules/mob/login.dm +++ b/monkestation/code/modules/mob/login.dm @@ -10,4 +10,6 @@ client?.twitch = new(client) if(QDELETED(client?.client_token_holder)) + if(!client?.prefs.loaded) + CRASH("Tried to load client_token's on a logging in mob but prefs haven't loaded.") client?.client_token_holder = new(client) diff --git a/monkestation/code/modules/ocean_content/mobs/fish_base.dm b/monkestation/code/modules/ocean_content/mobs/fish_base.dm index 143807d61d86..13a3213f8b6a 100644 --- a/monkestation/code/modules/ocean_content/mobs/fish_base.dm +++ b/monkestation/code/modules/ocean_content/mobs/fish_base.dm @@ -12,8 +12,8 @@ speak_emote = list("glubs") habitable_atmos = list("min_oxy" = 2, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) - minimum_survivable_temperature = 0 - maximum_survivable_temperature = 1200 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 1200 ai_controller = /datum/ai_controller/basic_controller/fish diff --git a/monkestation/code/modules/ranching/chickens/_chick.dm b/monkestation/code/modules/ranching/chickens/_chick.dm index 1cb8a03b360e..c94cfab852e6 100644 --- a/monkestation/code/modules/ranching/chickens/_chick.dm +++ b/monkestation/code/modules/ranching/chickens/_chick.dm @@ -98,7 +98,8 @@ if(istype(new_chicken, /mob/living/basic/chicken/glass)) for(var/list_item in glass_egg_reagent) - new_chicken.glass_egg_reagents.Add(list_item) + new_chicken.glass_egg_reagents |= list_item + new_chicken.glass_egg_reagents[list_item] = glass_egg_reagent[list_item] if(istype(new_chicken, /mob/living/basic/chicken/stone)) if(production_type) diff --git a/monkestation/code/modules/ranching/chickens/_chicken.dm b/monkestation/code/modules/ranching/chickens/_chicken.dm index 256a72aa2325..261c8d46c547 100644 --- a/monkestation/code/modules/ranching/chickens/_chicken.dm +++ b/monkestation/code/modules/ranching/chickens/_chicken.dm @@ -272,7 +272,9 @@ for(var/mob/living/basic/animals in view(1, src)) animal_count ++ if(animal_count >= overcrowding) - adjust_happiness(-1) + eggs_fertile = FALSE + else + eggs_fertile = TRUE if(!stat && prob(3) && current_feed_amount > 0) current_feed_amount-- diff --git a/monkestation/code/modules/ranching/chickens/_egg.dm b/monkestation/code/modules/ranching/chickens/_egg.dm index 1bd01210ae21..b083575671e6 100644 --- a/monkestation/code/modules/ranching/chickens/_egg.dm +++ b/monkestation/code/modules/ranching/chickens/_egg.dm @@ -73,8 +73,9 @@ birthed.grown_type = layer_hen_type //if no possible mutations default to layer hen type if(birthed.grown_type == /mob/living/basic/chicken/glass) - for(var/list_item in src.reagents.reagent_list) - birthed.glass_egg_reagent.Add(list_item) + for(var/datum/reagent/list_reagent as anything in src.reagents.reagent_list) + birthed.glass_egg_reagent |= list_reagent.type + birthed.glass_egg_reagent[list_reagent.type] = list_reagent.volume if(birthed.grown_type == /mob/living/basic/chicken/stone) birthed.production_type = src.production_type diff --git a/monkestation/code/modules/ranching/chickens/ai/chicken_subtrees.dm b/monkestation/code/modules/ranching/chickens/ai/chicken_subtrees.dm index fbeae2f09650..e88127dfc9bb 100644 --- a/monkestation/code/modules/ranching/chickens/ai/chicken_subtrees.dm +++ b/monkestation/code/modules/ranching/chickens/ai/chicken_subtrees.dm @@ -53,7 +53,7 @@ var/list/viable_conversions = list() for(var/mob/living/basic/chicken/found_chicken in view(4, living_pawn.loc)) - if(!istype(found_chicken, /mob/living/basic/chicken/rev_raptor) || !istype(found_chicken, /mob/living/basic/chicken/raptor) || !istype(found_chicken, /mob/living/basic/chicken/rev_raptor)) + if(!istype(found_chicken, /mob/living/basic/chicken/rev_raptor) && !istype(found_chicken, /mob/living/basic/chicken/raptor) && !istype(found_chicken, /mob/living/basic/chicken/rev_raptor)) viable_conversions |= found_chicken if(!length(viable_conversions)) return diff --git a/monkestation/code/modules/ranching/chickens/tier1/glass.dm b/monkestation/code/modules/ranching/chickens/tier1/glass.dm index 9fc5b5a011cb..d681ba69acd0 100644 --- a/monkestation/code/modules/ranching/chickens/tier1/glass.dm +++ b/monkestation/code/modules/ranching/chickens/tier1/glass.dm @@ -16,3 +16,46 @@ icon_state = "glass" layer_hen_type = /mob/living/basic/chicken/glass + +/obj/item/food/egg/glass/Initialize(mapload) + . = ..() + reagents.flags |= DRAWABLE + START_PROCESSING(SSobj, src) + +/obj/item/food/egg/glass/process(seconds_per_tick) + if(!length(glass_egg_reagents)) // this causes only second gen to work + return + + var/amount_left = max_volume - reagents.total_volume + + var/amount_to_add = min(amount_left, max_volume * 0.1) + + var/minimum_injection = 0 + for(var/datum/reagent/listed as anything in glass_egg_reagents) + minimum_injection += glass_egg_reagents[listed] * 0.1 + + var/multiplier = 1 + if(minimum_injection < amount_to_add) + multiplier = minimum_injection / amount_to_add + + for(var/datum/reagent/listed_reagent as anything in glass_egg_reagents) + reagents.add_reagent(listed_reagent, glass_egg_reagents[listed_reagent] * multiplier) + + update_appearance() + +/obj/item/food/egg/glass/update_overlays() + . = ..() + var/amount_left = max_volume - reagents.total_volume + var/mutable_appearance/MA = mutable_appearance(icon, "glass-filling", layer, src) + switch(amount_left) + if(5 to INFINITY) + MA.icon_state = "glass-filling" + if(3 to 4.99) + MA.icon_state = "glass-filling-75" + if(2 to 2.99) + MA.icon_state = "glass-filling-50" + if(0 to 1.99) + MA.icon_state = "glass-filling-25" + MA.color = mix_color_from_reagents(reagents.reagent_list) + . += MA + diff --git a/monkestation/code/modules/ranching/chickens/tier2/cluwne.dm b/monkestation/code/modules/ranching/chickens/tier2/cluwne.dm index b20fe4987d31..82a66fa5f3aa 100644 --- a/monkestation/code/modules/ranching/chickens/tier2/cluwne.dm +++ b/monkestation/code/modules/ranching/chickens/tier2/cluwne.dm @@ -4,7 +4,7 @@ breed_name_male = "huOnkHoNkHoeNK" breed_name_female = "huOnkHoNkHoeNK" - minimum_survivable_temperature = 0 + bodytemp_cold_damage_limit = -1 targeted_ability_planning_tree = /datum/ai_planning_subtree/targeted_mob_ability/min_range/chicken/clown diff --git a/monkestation/code/modules/ranching/chickens/tier2/snowy.dm b/monkestation/code/modules/ranching/chickens/tier2/snowy.dm index e524834abcd8..d20f19bf179d 100644 --- a/monkestation/code/modules/ranching/chickens/tier2/snowy.dm +++ b/monkestation/code/modules/ranching/chickens/tier2/snowy.dm @@ -4,8 +4,8 @@ breed_name = "Snow" egg_type = /obj/item/food/egg/snowy - minimum_survivable_temperature = 0 - maximum_survivable_temperature = 40 + bodytemp_cold_damage_limit = -1 + bodytemp_heat_damage_limit = 40 liked_foods = list(/obj/item/food/grown/icepepper = 4) book_desc = "These chickens require a sub-zero environment to live. They will melt if its not cold enough for them." diff --git a/monkestation/code/modules/ranching/icons/satyr_tail.dmi b/monkestation/code/modules/ranching/icons/satyr_tail.dmi index 5a0a9e59a7ef..45db6b32ead1 100644 Binary files a/monkestation/code/modules/ranching/icons/satyr_tail.dmi and b/monkestation/code/modules/ranching/icons/satyr_tail.dmi differ diff --git a/monkestation/code/modules/ranching/mutations/tier1.dm b/monkestation/code/modules/ranching/mutations/tier1.dm index 5d9710e76167..af24317dac17 100644 --- a/monkestation/code/modules/ranching/mutations/tier1.dm +++ b/monkestation/code/modules/ranching/mutations/tier1.dm @@ -58,6 +58,6 @@ /datum/mutation/ranching/chicken/clown chicken_type = /mob/living/basic/chicken/clown egg_type = /obj/item/food/egg/clown - player_job = "Clown" + food_requirements = list(/obj/item/food/grown/banana) can_come_from_string = "White Chicken" diff --git a/monkestation/code/modules/ranching/satyr/accessories/prefs.dm b/monkestation/code/modules/ranching/satyr/accessories/prefs.dm index a634870baadb..441932ec21a3 100644 --- a/monkestation/code/modules/ranching/satyr/accessories/prefs.dm +++ b/monkestation/code/modules/ranching/satyr/accessories/prefs.dm @@ -46,7 +46,7 @@ return possible_values_for_sprite_accessory_list_for_body_part( GLOB.satyr_horns_list, "satyr_horns", - list("BEHIND", "FRONT"), + list("FRONT"), ) /datum/preference/choiced/satyr_horns/apply_to_human(mob/living/carbon/human/target, value) diff --git a/monkestation/code/modules/ranching/satyr/bodyparts.dm b/monkestation/code/modules/ranching/satyr/bodyparts.dm index 7809f9185b58..5c4b9b6254e4 100644 --- a/monkestation/code/modules/ranching/satyr/bodyparts.dm +++ b/monkestation/code/modules/ranching/satyr/bodyparts.dm @@ -8,6 +8,7 @@ icon_greyscale = 'monkestation/code/modules/ranching/icons/bodyparts.dmi' limb_id = SPECIES_SATYR is_dimorphic = TRUE + acceptable_bodytype = BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE /obj/item/bodypart/arm/left/satyr icon_greyscale = 'monkestation/code/modules/ranching/icons/bodyparts.dmi' @@ -21,8 +22,24 @@ icon_greyscale = 'monkestation/code/modules/ranching/icons/bodyparts.dmi' limb_id = SPECIES_SATYR bodytype = BODYTYPE_DIGITIGRADE | BODYTYPE_ORGANIC + bodypart_traits = list(TRAIT_HARD_SOLES, TRAIT_NON_IMPORTANT_SHOE_BLOCK) + step_sounds = list( + 'sound/effects/footstep/hardclaw1.ogg', + 'sound/effects/footstep/hardclaw2.ogg', + 'sound/effects/footstep/hardclaw3.ogg', + 'sound/effects/footstep/hardclaw4.ogg', + 'sound/effects/footstep/hardclaw1.ogg', + ) /obj/item/bodypart/leg/right/satyr icon_greyscale = 'monkestation/code/modules/ranching/icons/bodyparts.dmi' limb_id = SPECIES_SATYR bodytype = BODYTYPE_DIGITIGRADE | BODYTYPE_ORGANIC + bodypart_traits = list(TRAIT_HARD_SOLES, TRAIT_NON_IMPORTANT_SHOE_BLOCK) + step_sounds = list( + 'sound/effects/footstep/hardclaw1.ogg', + 'sound/effects/footstep/hardclaw2.ogg', + 'sound/effects/footstep/hardclaw3.ogg', + 'sound/effects/footstep/hardclaw4.ogg', + 'sound/effects/footstep/hardclaw1.ogg', + ) diff --git a/monkestation/code/modules/ranching/satyr/external_organs.dm b/monkestation/code/modules/ranching/satyr/external_organs.dm index f49c443dd4d7..3eb5b24eaeea 100644 --- a/monkestation/code/modules/ranching/satyr/external_organs.dm +++ b/monkestation/code/modules/ranching/satyr/external_organs.dm @@ -10,6 +10,18 @@ use_mob_sprite_as_obj_sprite = TRUE bodypart_overlay = /datum/bodypart_overlay/mutant/satyr_fluff + var/datum/action/cooldown/mob_cooldown/dash/headbutt/headbutt + +/obj/item/organ/external/satyr_fluff/Insert(mob/living/carbon/receiver, special, drop_if_replaced) + . = ..() + headbutt = new + headbutt.Grant(receiver) + +/obj/item/organ/external/satyr_fluff/Remove(mob/living/carbon/organ_owner, special, moving) + . = ..() + if(headbutt) + headbutt.Remove(organ_owner) + qdel(headbutt) /datum/bodypart_overlay/mutant/satyr_fluff layers = EXTERNAL_ADJACENT //| EXTERNAL_FRONT @@ -67,7 +79,7 @@ bodypart_overlay = /datum/bodypart_overlay/mutant/satyr_tail /datum/bodypart_overlay/mutant/satyr_tail - layers = EXTERNAL_ADJACENT | EXTERNAL_FRONT + layers = EXTERNAL_ADJACENT | EXTERNAL_BEHIND feature_key = "satyr_tail" color_source = ORGAN_COLOR_HAIR diff --git a/monkestation/code/modules/ranching/satyr/species.dm b/monkestation/code/modules/ranching/satyr/species.dm index fee044fc78f7..27da3c9bf694 100644 --- a/monkestation/code/modules/ranching/satyr/species.dm +++ b/monkestation/code/modules/ranching/satyr/species.dm @@ -3,36 +3,22 @@ plural_form = "Satyrs" id = SPECIES_SATYR changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN - no_equip_flags = ITEM_SLOT_FEET sexes = TRUE - species_traits = list( - NO_UNDERWEAR, - ) inherent_traits = list( - TRAIT_ALCOHOL_TOLERANCE, - TRAIT_HARD_SOLES - ) - special_step_sounds = list( - 'sound/effects/footstep/hardclaw1.ogg', - 'sound/effects/footstep/hardclaw2.ogg', - 'sound/effects/footstep/hardclaw3.ogg', - 'sound/effects/footstep/hardclaw4.ogg', - 'sound/effects/footstep/hardclaw1.ogg', + TRAIT_NO_UNDERWEAR, + TRAIT_USES_SKINTONES, ) inherent_biotypes = MOB_ORGANIC | MOB_HUMANOID - use_skintones = TRUE external_organs = list( /obj/item/organ/external/satyr_fluff = "normal", /obj/item/organ/external/satyr_tail = "short", /obj/item/organ/external/satyr_horns = "back", ) meat = /obj/item/food/meat/steak - liked_food = GROSS | VEGETABLES | FRUIT - disliked_food = MEAT | DAIRY + mutanttongue = /obj/item/organ/internal/tongue/satyr + mutantliver = /obj/item/organ/internal/liver/satyr maxhealthmod = 0.8 stunmod = 1.2 - //speedmod = 1 - payday_modifier = 1 bodypart_overrides = list( BODY_ZONE_HEAD = /obj/item/bodypart/head/satyr, BODY_ZONE_CHEST = /obj/item/bodypart/chest/satyr, @@ -42,8 +28,6 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/satyr, ) - var/datum/action/cooldown/mob_cooldown/dash/headbutt/headbutt - /datum/species/satyr/get_species_description() return "Mythical goat-people. The clacking of hooves and smell of beer follow them around." @@ -80,20 +64,30 @@ return to_add -/datum/species/satyr/on_species_gain(mob/living/carbon/C, datum/species/old_species, pref_load) +/obj/item/organ/internal/tongue/satyr + name = "satyr tongue" + + liked_foodtypes = GROSS | VEGETABLES | FRUIT + disliked_foodtypes = MEAT | DAIRY + +/obj/item/organ/internal/tongue/satyr/Insert(mob/living/carbon/tongue_owner, special, drop_if_replaced) . = ..() - ADD_TRAIT(C, TRAIT_TIN_EATER, INNATE_TRAIT) - C.AddComponent(/datum/component/living_drunk) + ADD_TRAIT(tongue_owner, TRAIT_TIN_EATER, ORGAN_TRAIT) - headbutt = new - headbutt.Grant(C) +/obj/item/organ/internal/tongue/satyr/Remove(mob/living/carbon/tongue_owner, special) + . = ..() + REMOVE_TRAIT(tongue_owner, TRAIT_TIN_EATER, ORGAN_TRAIT) -/datum/species/satyr/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load) +/obj/item/organ/internal/liver/satyr + name = "satyr liver" + organ_traits = list(TRAIT_ALCOHOL_TOLERANCE) + + +/obj/item/organ/internal/liver/satyr/Insert(mob/living/carbon/receiver, special, drop_if_replaced) . = ..() - REMOVE_TRAIT(C, TRAIT_TIN_EATER, INNATE_TRAIT) - var/datum/component/living_drunk/drunk = C.GetComponent(/datum/component/living_drunk) - qdel(drunk) + receiver.AddComponent(/datum/component/living_drunk) - if(headbutt) - headbutt.Remove(C) - qdel(headbutt) +/obj/item/organ/internal/liver/satyr/Remove(mob/living/carbon/organ_owner, special) + . = ..() + var/datum/component/living_drunk/drunk = organ_owner.GetComponent(/datum/component/living_drunk) + qdel(drunk) diff --git a/monkestation/code/modules/reagents/reagent_containers/blood_pack.dm b/monkestation/code/modules/reagents/reagent_containers/blood_pack.dm index 9106c7946aa6..bfa7cfd60d36 100644 --- a/monkestation/code/modules/reagents/reagent_containers/blood_pack.dm +++ b/monkestation/code/modules/reagents/reagent_containers/blood_pack.dm @@ -1,6 +1,5 @@ /obj/item/reagent_containers/blood/slime - blood_type = "OOZE" - unique_blood = /datum/reagent/toxin/slimeooze + blood_type = /datum/blood_type/slime /obj/item/reagent_containers/blood/slime/examine() .= ..() diff --git a/monkestation/code/modules/research/nanites/nanite_programs/healing.dm b/monkestation/code/modules/research/nanites/nanite_programs/healing.dm index 1b6940de0948..c8d7d35b8438 100644 --- a/monkestation/code/modules/research/nanites/nanite_programs/healing.dm +++ b/monkestation/code/modules/research/nanites/nanite_programs/healing.dm @@ -36,16 +36,16 @@ rogue_types = list(/datum/nanite_program/skin_decay) /datum/nanite_program/temperature/check_conditions() - if(host_mob.bodytemperature > (host_mob.get_body_temp_normal(apply_change=FALSE) - 30) && host_mob.bodytemperature < (host_mob.get_body_temp_normal(apply_change=FALSE) + 30)) + if(host_mob.bodytemperature > (host_mob.bodytemp_cold_damage_limit) && host_mob.bodytemperature < (host_mob.bodytemp_heat_damage_limit)) return FALSE return ..() /datum/nanite_program/temperature/active_effect() - var/target_temp = host_mob.get_body_temp_normal(apply_change=FALSE) + var/target_temp = host_mob.standard_body_temperature if(host_mob.bodytemperature > target_temp) - host_mob.adjust_bodytemperature(-40 * TEMPERATURE_DAMAGE_COEFFICIENT, target_temp) + host_mob.adjust_bodytemperature(-2.5 KELVIN, target_temp) else if(host_mob.bodytemperature < (target_temp + 1)) - host_mob.adjust_bodytemperature(40 * TEMPERATURE_DAMAGE_COEFFICIENT, 0, target_temp) + host_mob.adjust_bodytemperature(2.5 KELVIN, 0, target_temp) /datum/nanite_program/purging name = "Blood Purification" diff --git a/monkestation/code/modules/research/nanites/nanite_programs/utility.dm b/monkestation/code/modules/research/nanites/nanite_programs/utility.dm index 484f7046f508..b14ecd1431fc 100644 --- a/monkestation/code/modules/research/nanites/nanite_programs/utility.dm +++ b/monkestation/code/modules/research/nanites/nanite_programs/utility.dm @@ -108,7 +108,7 @@ update_research_speed() - host_mob.add_body_temperature_change(NANITE_RESEARCH_CHANGE, research_speed * 15) + host_mob.add_homeostasis_level(NANITE_RESEARCH_CHANGE, host_mob.standard_body_temperature + research_speed * 15, 0.25 KELVIN) use_rate = initial(use_rate) * research_speed current_research_bonus = use_rate SSresearch.science_tech.nanite_bonus += current_research_bonus @@ -120,7 +120,7 @@ /datum/nanite_program/research/disable_passive_effect() . = ..() SSresearch.science_tech.nanite_bonus -= current_research_bonus - host_mob.remove_body_temperature_change(NANITE_RESEARCH_CHANGE) + host_mob.remove_homeostasis_level(NANITE_RESEARCH_CHANGE) /datum/nanite_program/research/set_extra_setting(setting, value) . = ..() diff --git a/monkestation/code/modules/security/code/weapons/paco.dm b/monkestation/code/modules/security/code/weapons/paco.dm index 4c35d122d24d..a78a6b0ca2d0 100644 --- a/monkestation/code/modules/security/code/weapons/paco.dm +++ b/monkestation/code/modules/security/code/weapons/paco.dm @@ -117,7 +117,7 @@ icon = 'monkestation/code/modules/security/icons/paco_ammo.dmi' icon_state = "rubber_bullet" damage = 4 - stamina = 45 // Turns out 35 stamina damage is not good enough. + stamina = 35 // Turns out 35 stamina damage is not good enough. sharpness = NONE embedding = null diff --git a/monkestation/code/modules/slimecore/mobs/_base_slime.dm b/monkestation/code/modules/slimecore/mobs/_base_slime.dm index d7415fab718b..23d3aed7fe27 100644 --- a/monkestation/code/modules/slimecore/mobs/_base_slime.dm +++ b/monkestation/code/modules/slimecore/mobs/_base_slime.dm @@ -11,7 +11,7 @@ ai_controller = /datum/ai_controller/basic_controller/slime density = FALSE - maximum_survivable_temperature = 2000 + bodytemp_heat_damage_limit = 2000 pass_flags = PASSTABLE | PASSGRILLE gender = NEUTER @@ -38,8 +38,8 @@ can_be_held = TRUE - minimum_survivable_temperature = 100 - maximum_survivable_temperature = 600 + bodytemp_cold_damage_limit = 100 + bodytemp_heat_damage_limit = 600 // canstun and canknockdown don't affect slimes because they ignore stun and knockdown variables // for the sake of cleanliness, though, here they are. diff --git a/monkestation/code/modules/slimecore/slime_traits/cleaner.dm b/monkestation/code/modules/slimecore/slime_traits/cleaner.dm index 10c238c0567e..87501d1a0e17 100644 --- a/monkestation/code/modules/slimecore/slime_traits/cleaner.dm +++ b/monkestation/code/modules/slimecore/slime_traits/cleaner.dm @@ -28,9 +28,7 @@ )) ///blood we can clean var/static/list/cleanable_blood = typecacheof(list( - /obj/effect/decal/cleanable/xenoblood, /obj/effect/decal/cleanable/blood, - /obj/effect/decal/cleanable/trail_holder, )) ///pests we hunt var/static/list/huntable_pests = typecacheof(list( diff --git a/monkestation/code/modules/smithing/ipcs/body/base_bodyparts.dm b/monkestation/code/modules/smithing/ipcs/body/base_bodyparts.dm index dfcf48856c9c..0614ee3c2d42 100644 --- a/monkestation/code/modules/smithing/ipcs/body/base_bodyparts.dm +++ b/monkestation/code/modules/smithing/ipcs/body/base_bodyparts.dm @@ -6,7 +6,7 @@ icon_state = "synth_head" is_dimorphic = FALSE should_draw_greyscale = FALSE - biological_state = BIO_ROBOTIC + biological_state = BIO_ROBOTIC | BIO_BLOODED bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC head_flags = HEAD_HAIR | HEAD_LIPS | HEAD_EYECOLOR | HEAD_LIPS @@ -21,9 +21,9 @@ icon_state = "synth_chest" is_dimorphic = FALSE should_draw_greyscale = FALSE - biological_state = BIO_ROBOTIC + biological_state = BIO_ROBOTIC | BIO_BLOODED bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC - + bodypart_traits = list(TRAIT_LIMBATTACHMENT) body_damage_coeff = 1 //IPC Chest at default ///Monkestation Edit max_damage = 250 //Default: 200 ///Monkestation Edit @@ -37,7 +37,7 @@ limb_id = "synth" icon_state = "synth_l_arm" should_draw_greyscale = FALSE - biological_state = BIO_ROBOTIC | BIO_JOINTED + biological_state = BIO_ROBOTIC | BIO_JOINTED | BIO_BLOODED bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC body_damage_coeff = 1.1 //IPC's Limbs Should Dismember Easier //Monkestation Edit @@ -52,7 +52,7 @@ limb_id = "synth" icon_state = "synth_r_arm" should_draw_greyscale = FALSE - biological_state = BIO_ROBOTIC | BIO_JOINTED + biological_state = BIO_ROBOTIC | BIO_JOINTED | BIO_BLOODED bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC body_damage_coeff = 1.1 //IPC's Limbs Should Dismember Easier //Monkestation Edit @@ -67,10 +67,11 @@ limb_id = "synth" icon_state = "synth_l_leg" should_draw_greyscale = FALSE - biological_state = BIO_ROBOTIC | BIO_JOINTED + biological_state = BIO_ROBOTIC | BIO_JOINTED | BIO_BLOODED bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC dmg_overlay_type = "synth" + step_sounds = list('sound/effects/servostep.ogg') /obj/item/bodypart/leg/right/robot/ipc icon = 'monkestation/icons/mob/species/ipc/bodyparts.dmi' @@ -79,10 +80,11 @@ limb_id = "synth" icon_state = "synth_r_leg" should_draw_greyscale = FALSE - biological_state = BIO_ROBOTIC | BIO_JOINTED + biological_state = BIO_ROBOTIC | BIO_JOINTED | BIO_BLOODED bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC body_damage_coeff = 1.1 //IPC's Limbs Should Dismember Easier //Monkestation Edit max_damage = 30 //Monkestation Edit dmg_overlay_type = "synth" + step_sounds = list('sound/effects/servostep.ogg') diff --git a/monkestation/code/modules/smithing/ipcs/body/internal_organs.dm b/monkestation/code/modules/smithing/ipcs/body/internal_organs.dm index 99f34996424e..668a3ce8a262 100644 --- a/monkestation/code/modules/smithing/ipcs/body/internal_organs.dm +++ b/monkestation/code/modules/smithing/ipcs/body/internal_organs.dm @@ -377,6 +377,16 @@ slot = ORGAN_SLOT_TONGUE organ_flags = ORGAN_ROBOTIC | ORGAN_SYNTHETIC_FROM_SPECIES +/obj/item/organ/internal/tongue/synth/get_scream_sound() + return 'monkestation/sound/voice/screams/silicon/scream_silicon.ogg' + +/obj/item/organ/internal/tongue/synth/get_laugh_sound() + return pick( + 'monkestation/sound/voice/laugh/silicon/laugh_siliconE1M0.ogg', + 'monkestation/sound/voice/laugh/silicon/laugh_siliconE1M1.ogg', + 'monkestation/sound/voice/laugh/silicon/laugh_siliconM2.ogg', + ) + /obj/item/organ/internal/tongue/synth/can_speak_language(language) return TRUE diff --git a/monkestation/code/modules/smithing/ipcs/reagents/medical_supplies.dm b/monkestation/code/modules/smithing/ipcs/reagents/medical_supplies.dm index 0259ff6dccf8..0597d7132a6e 100644 --- a/monkestation/code/modules/smithing/ipcs/reagents/medical_supplies.dm +++ b/monkestation/code/modules/smithing/ipcs/reagents/medical_supplies.dm @@ -1,7 +1,6 @@ // I cannot wait to get rid of this. This is so many levels of awful wrapped into one. /obj/item/reagent_containers/blood/oil - blood_type = "Oil" - unique_blood = /datum/reagent/fuel/oil + blood_type = /datum/blood_type/oil /obj/item/reagent_containers/pill/liquid_solder name = "liquid solder pill" diff --git a/monkestation/code/modules/smithing/ipcs/species.dm b/monkestation/code/modules/smithing/ipcs/species.dm index 00af82672889..b7ff254ed0e4 100644 --- a/monkestation/code/modules/smithing/ipcs/species.dm +++ b/monkestation/code/modules/smithing/ipcs/species.dm @@ -19,16 +19,11 @@ TRAIT_TOXIMMUNE, TRAIT_GENELESS, TRAIT_STABLEHEART, - TRAIT_LIMBATTACHMENT, TRAIT_LITERATE, TRAIT_REVIVES_BY_HEALING, TRAIT_NO_DNA_COPY, - ) - - species_traits = list( - NO_DNA_COPY, - NOTRANSSTING, - NOHUSK + TRAIT_NO_TRANSFORMATION_STING, + TRAIT_NO_HUSK, ) mutant_organs = list( @@ -48,7 +43,6 @@ payday_modifier = 1.0 // Matches the rest of the pay penalties the non-human crew have species_language_holder = /datum/language_holder/synthetic - special_step_sounds = list('sound/effects/servostep.ogg') mutantbrain = /obj/item/organ/internal/brain/synth mutantstomach = /obj/item/organ/internal/stomach/synth @@ -59,7 +53,7 @@ mutantheart = /obj/item/organ/internal/heart/synth mutantliver = /obj/item/organ/internal/liver/synth mutantappendix = null - exotic_blood = /datum/reagent/fuel/oil + exotic_bloodtype = /datum/blood_type/oil bodypart_overrides = list( BODY_ZONE_HEAD = /obj/item/bodypart/head/robot/ipc, @@ -70,6 +64,9 @@ BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/robot/ipc, ) + bodytemp_heat_damage_limit = CELCIUS_TO_KELVIN(450) + bodytemp_cold_damage_limit = CELCIUS_TO_KELVIN(-260) //they are practically immune to cold + brutemod = 1.5 coldmod = 1.2 heatmod = 2 // TWO TIMES DAMAGE FROM BEING TOO HOT?! WHAT?! No wonder lava is literal instant death for us. @@ -83,16 +80,6 @@ COOLDOWN_DECLARE(blend_cd) var/blending -/datum/species/ipc/get_scream_sound(mob/living/carbon/human/human) - return 'monkestation/sound/voice/screams/silicon/scream_silicon.ogg' - -/datum/species/ipc/get_laugh_sound(mob/living/carbon/human/human) - return pick( - 'monkestation/sound/voice/laugh/silicon/laugh_siliconE1M0.ogg', - 'monkestation/sound/voice/laugh/silicon/laugh_siliconE1M1.ogg', - 'monkestation/sound/voice/laugh/silicon/laugh_siliconM2.ogg', - ) - /datum/species/ipc/get_species_description() return "Integrated Positronic Chassis - or IPC for short - \ are a race of sentient and unbound humanoid robots." @@ -120,6 +107,18 @@ RegisterSignal(C, COMSIG_LIVING_DEATH, PROC_REF(bsod_death)) // screen displays bsod on death, if they have one RegisterSignal(C.reagents, COMSIG_REAGENTS_ADD_REAGENT, PROC_REF(will_it_blend)) + RegisterSignal(C, COMSIG_HUMAN_ON_HANDLE_BLOOD, PROC_REF(blood_handled)) + +/datum/species/ipc/proc/blood_handled(mob/living/carbon/human/slime, seconds_per_tick, times_fired) + SIGNAL_HANDLER + + if(slime.stat == DEAD) + return NONE + + if(slime.blood_volume < BLOOD_VOLUME_OKAY) + return NONE + + slime.adjustOxyLoss(-3) /datum/species/ipc/proc/will_it_blend(datum/reagents/holder, ...) var/mob/living/carbon/carbon = holder.my_atom @@ -218,7 +217,7 @@ BP.limb_id = chassis_of_choice.icon_state BP.name = "\improper[chassis_of_choice.name] [parse_zone(BP.body_zone)]" BP.update_limb() - if(chassis_of_choice.color_src == MUTCOLORS) + if(chassis_of_choice.color_src == MUTANT_COLOR) BP.should_draw_greyscale = TRUE /** diff --git a/monkestation/code/modules/smithing/items/clothing.dm b/monkestation/code/modules/smithing/items/clothing.dm index 684b0bd34c65..b76e110d1084 100644 --- a/monkestation/code/modules/smithing/items/clothing.dm +++ b/monkestation/code/modules/smithing/items/clothing.dm @@ -108,9 +108,9 @@ icon_state = "cuirass" allowed = null body_parts_covered = CHEST - cold_protection = CHEST|GROIN + min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT - heat_protection = CHEST|GROIN + max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT strip_delay = 60 equip_delay_other = 40 @@ -131,9 +131,9 @@ icon = 'icons/obj/clothing/head/helmet.dmi' worn_icon = 'icons/mob/clothing/head/helmet.dmi' icon_state = "knight_green" - cold_protection = HEAD + min_cold_protection_temperature = HELMET_MIN_TEMP_PROTECT - heat_protection = HEAD + max_heat_protection_temperature = HELMET_MAX_TEMP_PROTECT strip_delay = 60 clothing_flags = SNUG_FIT | PLASMAMAN_HELMET_EXEMPT @@ -152,9 +152,9 @@ icon_state = "smithed_boots_inhand" worn_icon_state = "smithed_boots" inhand_icon_state = "jackboots" - cold_protection = FEET + min_cold_protection_temperature = SHOES_MIN_TEMP_PROTECT - heat_protection = FEET + max_heat_protection_temperature = SHOES_MAX_TEMP_PROTECT lefthand_file = 'icons/mob/inhands/clothing/shoes_lefthand.dmi' righthand_file = 'icons/mob/inhands/clothing/shoes_righthand.dmi' diff --git a/monkestation/code/modules/smithing/oozelings/body/bodyparts.dm b/monkestation/code/modules/smithing/oozelings/body/bodyparts.dm index 8a34125875ff..914ea7107d00 100644 --- a/monkestation/code/modules/smithing/oozelings/body/bodyparts.dm +++ b/monkestation/code/modules/smithing/oozelings/body/bodyparts.dm @@ -5,6 +5,9 @@ biological_state = BIO_INORGANIC dmg_overlay_type = null + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/chest/oozeling icon_greyscale = 'monkestation/icons/mob/species/oozeling/bodyparts.dmi' @@ -13,6 +16,11 @@ biological_state = BIO_INORGANIC dmg_overlay_type = null + composition_effects = list(/datum/element/soft_landing = 0.5) + ass_image = 'icons/ass/assslime.png' + wing_types = list(/obj/item/organ/external/wings/functional/slime) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/left/oozeling icon_greyscale = 'monkestation/icons/mob/species/oozeling/bodyparts.dmi' @@ -20,11 +28,17 @@ biological_state = BIO_INORGANIC dmg_overlay_type = null + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/right/oozeling icon_greyscale = 'monkestation/icons/mob/species/oozeling/bodyparts.dmi' limb_id = SPECIES_OOZELING biological_state = BIO_INORGANIC + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/left/oozeling icon_greyscale = 'monkestation/icons/mob/species/oozeling/bodyparts.dmi' @@ -32,6 +46,9 @@ biological_state = BIO_INORGANIC dmg_overlay_type = null + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/right/oozeling icon_greyscale = 'monkestation/icons/mob/species/oozeling/bodyparts.dmi' @@ -39,3 +56,6 @@ biological_state = BIO_INORGANIC dmg_overlay_type = null + composition_effects = list(/datum/element/soft_landing = 0.5) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR diff --git a/monkestation/code/modules/smithing/oozelings/body/organs.dm b/monkestation/code/modules/smithing/oozelings/body/organs.dm index 0f5b242334d5..39af37a185a4 100644 --- a/monkestation/code/modules/smithing/oozelings/body/organs.dm +++ b/monkestation/code/modules/smithing/oozelings/body/organs.dm @@ -33,6 +33,7 @@ name = "endoplasmic reticulum" zone = BODY_ZONE_CHEST organ_flags = ORGAN_UNREMOVABLE + organ_traits = list(TRAIT_TOXINLOVER) /obj/item/organ/internal/liver/slime/on_life(seconds_per_tick, times_fired) . = ..() @@ -113,7 +114,8 @@ /obj/item/organ/internal/brain/slime/proc/colorize() if(isoozeling(owner)) - core_color = owner.dna.features["mcolor"] + var/datum/color_palette/generic_colors/located = owner.dna.color_palettes[/datum/color_palette/generic_colors] + core_color = located.return_color(MUTANT_COLOR) add_atom_colour(core_color, FIXED_COLOUR_PRIORITY) /obj/item/organ/internal/brain/slime/proc/on_stat_change(mob/living/victim, new_stat, turf/loc_override) @@ -255,8 +257,6 @@ new_body.undershirt = "Nude" new_body.socks = "Nude" stored_dna.transfer_identity(new_body, transfer_SE = TRUE) - new_body.dna.features["mcolor"] = new_body.dna.features["mcolor"] - new_body.dna.update_uf_block(DNA_MUTANT_COLOR_BLOCK) new_body.real_name = new_body.dna.real_name new_body.name = new_body.dna.real_name new_body.updateappearance(mutcolor_update = TRUE) @@ -289,3 +289,124 @@ drop_items_to_ground(new_body.drop_location()) return new_body + + +///The rate at which slimes regenerate their jelly normally +#define JELLY_REGEN_RATE 1.5 +///The rate at which slimes regenerate their jelly when they completely run out of it and start taking damage, usually after having cannibalized all their limbs already +#define JELLY_REGEN_RATE_EMPTY 2.5 +///The blood volume at which slimes begin to start losing nutrition -- so that IV drips can work for blood deficient slimes +#define BLOOD_VOLUME_LOSE_NUTRITION 550 + + +/obj/item/organ/internal/heart/slime + name = "slime heart" + + heart_bloodtype = /datum/blood_type/slime + var/datum/action/innate/regenerate_limbs/regenerate_limbs + +/obj/item/organ/internal/heart/slime/Insert(mob/living/carbon/receiver, special, drop_if_replaced) + . = ..() + regenerate_limbs = new + regenerate_limbs.Grant(receiver) + RegisterSignal(receiver, COMSIG_HUMAN_ON_HANDLE_BLOOD, PROC_REF(slime_blood)) + +/obj/item/organ/internal/heart/slime/Remove(mob/living/carbon/heartless, special) + . = ..() + if(regenerate_limbs) + regenerate_limbs.Remove(heartless) + qdel(regenerate_limbs) + UnregisterSignal(heartless, COMSIG_HUMAN_ON_HANDLE_BLOOD) + +/obj/item/organ/internal/heart/slime/proc/slime_blood(mob/living/carbon/human/slime, seconds_per_tick, times_fired) + SIGNAL_HANDLER + + if(slime.stat == DEAD) + return NONE + + . = HANDLE_BLOOD_NO_NUTRITION_DRAIN|HANDLE_BLOOD_NO_EFFECTS + + if(slime.blood_volume <= 0) + slime.blood_volume += JELLY_REGEN_RATE_EMPTY * seconds_per_tick + slime.adjustBruteLoss(2.5 * seconds_per_tick) + to_chat(slime, span_danger("You feel empty!")) + + if(slime.blood_volume < BLOOD_VOLUME_NORMAL) + if(slime.nutrition >= NUTRITION_LEVEL_STARVING) + slime.blood_volume += JELLY_REGEN_RATE * seconds_per_tick + if(slime.blood_volume <= BLOOD_VOLUME_LOSE_NUTRITION) // don't lose nutrition if we are above a certain threshold, otherwise slimes on IV drips will still lose nutrition + slime.adjust_nutrition(-1.25 * seconds_per_tick) + + if(HAS_TRAIT(slime, TRAIT_BLOOD_DEFICIENCY)) + var/datum/quirk/blooddeficiency/blooddeficiency = slime.get_quirk(/datum/quirk/blooddeficiency) + if(!isnull(blooddeficiency)) + blooddeficiency.lose_blood(seconds_per_tick) + + if(slime.blood_volume < BLOOD_VOLUME_OKAY) + if(SPT_PROB(2.5, seconds_per_tick)) + to_chat(slime, span_danger("You feel drained!")) + + if(slime.blood_volume < BLOOD_VOLUME_BAD) + Cannibalize_Body(slime) + + regenerate_limbs?.build_all_button_icons(UPDATE_BUTTON_STATUS) + return . + +/obj/item/organ/internal/heart/slime/proc/Cannibalize_Body(mob/living/carbon/human/H) + var/list/limbs_to_consume = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) - H.get_missing_limbs() + var/obj/item/bodypart/consumed_limb + if(!length(limbs_to_consume)) + H.losebreath++ + return + if(H.num_legs) //Legs go before arms + limbs_to_consume -= list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM) + consumed_limb = H.get_bodypart(pick(limbs_to_consume)) + consumed_limb.drop_limb() + to_chat(H, span_userdanger("Your [consumed_limb] is drawn back into your body, unable to maintain its shape!")) + qdel(consumed_limb) + H.blood_volume += 20 + +/datum/action/innate/regenerate_limbs + name = "Regenerate Limbs" + check_flags = AB_CHECK_CONSCIOUS + button_icon_state = "slimeheal" + button_icon = 'icons/mob/actions/actions_slime.dmi' + background_icon_state = "bg_alien" + overlay_icon_state = "bg_alien_border" + +/datum/action/innate/regenerate_limbs/IsAvailable(feedback = FALSE) + . = ..() + if(!.) + return + var/mob/living/carbon/human/H = owner + var/list/limbs_to_heal = H.get_missing_limbs() + if(!length(limbs_to_heal)) + return FALSE + if(H.blood_volume >= BLOOD_VOLUME_OKAY+40) + return TRUE + +/datum/action/innate/regenerate_limbs/Activate() + var/mob/living/carbon/human/H = owner + var/list/limbs_to_heal = H.get_missing_limbs() + if(!length(limbs_to_heal)) + to_chat(H, span_notice("You feel intact enough as it is.")) + return + to_chat(H, span_notice("You focus intently on your missing [length(limbs_to_heal) >= 2 ? "limbs" : "limb"]...")) + if(H.blood_volume >= 40*length(limbs_to_heal)+BLOOD_VOLUME_OKAY) + H.regenerate_limbs() + H.blood_volume -= 40*length(limbs_to_heal) + to_chat(H, span_notice("...and after a moment you finish reforming!")) + return + else if(H.blood_volume >= 40)//We can partially heal some limbs + while(H.blood_volume >= BLOOD_VOLUME_OKAY+40) + var/healed_limb = pick(limbs_to_heal) + H.regenerate_limb(healed_limb) + limbs_to_heal -= healed_limb + H.blood_volume -= 40 + to_chat(H, span_warning("...but there is not enough of you to fix everything! You must attain more mass to heal completely!")) + return + to_chat(H, span_warning("...but there is not enough of you to go around! You must attain more mass to heal!")) + +#undef JELLY_REGEN_RATE +#undef JELLY_REGEN_RATE_EMPTY +#undef BLOOD_VOLUME_LOSE_NUTRITION diff --git a/monkestation/code/modules/smithing/oozelings/species.dm b/monkestation/code/modules/smithing/oozelings/species.dm index a74e7644b05f..2e36efa54e51 100644 --- a/monkestation/code/modules/smithing/oozelings/species.dm +++ b/monkestation/code/modules/smithing/oozelings/species.dm @@ -7,10 +7,6 @@ id = SPECIES_OOZELING changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT - species_traits = list( - MUTCOLORS, - ) - hair_color = "mutcolor" hair_alpha = 160 @@ -20,25 +16,22 @@ mutantears = /obj/item/organ/internal/ears/jelly mutantlungs = /obj/item/organ/internal/lungs/slime mutanttongue = /obj/item/organ/internal/tongue/jelly + mutantheart = /obj/item/organ/internal/heart/slime inherent_traits = list( - TRAIT_CAN_USE_FLIGHT_POTION, - TRAIT_TOXINLOVER, - TRAIT_NOBLOOD, + TRAIT_MUTANT_COLORS, TRAIT_EASYDISMEMBER, TRAIT_NOFIRE, ) meat = /obj/item/food/meat/slab/human/mutant/slime - exotic_blood = /datum/reagent/toxin/slimeooze + exotic_bloodtype = /datum/blood_type/slime burnmod = 0.6 // = 3/5x generic burn damage coldmod = 6 // = 3x cold damage heatmod = 0.5 // = 1/4x heat damage inherent_factions = list(FACTION_SLIME) //an oozeling wont be eaten by their brethren species_language_holder = /datum/language_holder/oozeling - ass_image = 'icons/ass/assslime.png' //swimming_component = /datum/component/swimming/dissolve - wing_types = list(/obj/item/organ/external/wings/functional/slime) bodypart_overrides = list( BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/oozeling, @@ -49,37 +42,10 @@ BODY_ZONE_CHEST = /obj/item/bodypart/chest/oozeling, ) - var/datum/action/innate/regenerate_limbs/regenerate_limbs var/datum/action/cooldown/spell/slime_washing/slime_washing var/datum/action/cooldown/spell/slime_hydrophobia/slime_hydrophobia var/datum/action/innate/core_signal/core_signal -/datum/species/oozeling/get_scream_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - if(prob(1)) - return 'sound/voice/human/wilhelm_scream.ogg' - return pick( - 'sound/voice/human/malescream_1.ogg', - 'sound/voice/human/malescream_2.ogg', - 'sound/voice/human/malescream_3.ogg', - 'sound/voice/human/malescream_4.ogg', - 'sound/voice/human/malescream_5.ogg', - 'sound/voice/human/malescream_6.ogg', - ) - - return pick( - 'sound/voice/human/femalescream_1.ogg', - 'sound/voice/human/femalescream_2.ogg', - 'sound/voice/human/femalescream_3.ogg', - 'sound/voice/human/femalescream_4.ogg', - 'sound/voice/human/femalescream_5.ogg', - ) -/datum/species/oozeling/get_laugh_sound(mob/living/carbon/human/human) - if(human.gender == MALE) - return pick('sound/voice/human/manlaugh1.ogg', 'sound/voice/human/manlaugh2.ogg') - else - return 'sound/voice/human/womanlaugh.ogg' - /datum/species/oozeling/get_species_description() return "A species of sentient semi-solids. \ They require nutriment in order to maintain their body mass." @@ -96,8 +62,6 @@ . = .(gender, TRUE, lastname, ++attempts) /datum/species/oozeling/on_species_loss(mob/living/carbon/C) - if(regenerate_limbs) - regenerate_limbs.Remove(C) if(slime_washing) slime_washing.Remove(C) if(slime_hydrophobia) @@ -110,8 +74,6 @@ /datum/species/oozeling/on_species_gain(mob/living/carbon/C, datum/species/old_species) ..() if(ishuman(C)) - regenerate_limbs = new - regenerate_limbs.Grant(C) slime_washing = new slime_washing.Grant(C) slime_hydrophobia = new @@ -128,8 +90,6 @@ if(slime.stat != CONSCIOUS) return - var/healing = TRUE - var/datum/status_effect/fire_handler/wet_stacks/wetness = locate() in slime.status_effects if(HAS_TRAIT(slime, TRAIT_SLIME_HYDROPHOBIA)) return @@ -139,75 +99,15 @@ slime.visible_message(span_danger("[slime]'s form begins to lose cohesion, seemingly diluting with the water!"), span_warning("The water starts to dilute your body, dry it off!")) if(istype(wetness) && wetness.stacks > (REGEN_WATER_STACKS)) - healing = FALSE if (SPT_PROB(25, seconds_per_tick)) to_chat(slime, span_warning("You can't pull your body together and regenerate with water inside it!")) slime.blood_volume -= 1 * seconds_per_tick - if(slime.blood_volume > BLOOD_VOLUME_NORMAL && healing) - if(HAS_TRAIT(slime, TRAIT_SLIME_HYDROPHOBIA)) - return - if(slime.stat != CONSCIOUS) - return - slime.heal_overall_damage(brute = 2 * seconds_per_tick, burn = 2 * seconds_per_tick, required_bodytype = BODYTYPE_ORGANIC) - slime.adjustOxyLoss(-1 * seconds_per_tick) - - if(!slime.blood_volume) - slime.blood_volume += 5 - slime.adjustBruteLoss(5) - to_chat(slime, span_danger("You feel empty!")) - - if(slime.nutrition >= NUTRITION_LEVEL_WELL_FED && slime.blood_volume <= 672) - if(slime.nutrition >= NUTRITION_LEVEL_ALMOST_FULL) - slime.adjust_nutrition(-5) - slime.blood_volume += 10 - else - slime.blood_volume += 8 - - if(slime.nutrition <= NUTRITION_LEVEL_HUNGRY) - if(slime.nutrition <= NUTRITION_LEVEL_STARVING) - slime.blood_volume -= 8 - if(prob(5)) - to_chat(slime, span_info("You're starving! Get some food!")) - else - if(prob(35)) - slime.blood_volume -= 2 - if(prob(5)) - to_chat(slime, span_danger("You're feeling pretty hungry...")) - - if(slime.blood_volume < BLOOD_VOLUME_OKAY && prob(5)) - to_chat(slime, span_danger("You feel drained!")) - if(slime.blood_volume < BLOOD_VOLUME_OKAY) - Cannibalize_Body(slime) - - if(slime.blood_volume < 0) - slime.blood_volume = 0 - -/datum/species/oozeling/proc/Cannibalize_Body(mob/living/carbon/human/slime) - if(HAS_TRAIT(slime, TRAIT_OOZELING_NO_CANNIBALIZE)) - return - var/list/limbs_to_consume = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) - slime.get_missing_limbs() - var/obj/item/bodypart/consumed_limb - - if(!length(limbs_to_consume)) - slime.losebreath++ - return - if(slime.num_legs) //Legs go before arms - limbs_to_consume -= list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM) - - consumed_limb = slime.get_bodypart(pick(limbs_to_consume)) - consumed_limb.drop_limb() - - to_chat(slime, span_userdanger("Your [consumed_limb] is drawn back into your body, unable to maintain its shape!")) - qdel(consumed_limb) - slime.blood_volume += 80 - slime.nutrition += 20 - /////// /// CHEMICAL HANDLING /// Here's where slimes heal off plasma and where they hate drinking water. -/datum/species/oozeling/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/slime, seconds_per_tick, times_fired) +/datum/species/oozeling/handle_chemical(datum/reagent/chem, mob/living/carbon/human/slime, seconds_per_tick, times_fired) // slimes use plasma to fix wounds, and if they have enough blood, organs var/static/list/organs_we_mend = list( ORGAN_SLOT_BRAIN, @@ -275,12 +175,6 @@ SPECIES_PERK_NAME = "incombustible", SPECIES_PERK_DESC = "[plural_form] cannot be set aflame.", ), - list( - SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK, - SPECIES_PERK_ICON = "tint", - SPECIES_PERK_NAME = initial(exotic_blood.name), - SPECIES_PERK_DESC = "[name] blood is [initial(exotic_blood.name)], which can make recieving medical treatment harder.", - ), list( SPECIES_PERK_TYPE = SPECIES_NEUTRAL_PERK, SPECIES_PERK_ICON = "wind", diff --git a/monkestation/code/modules/storytellers/converted_events/_base_event.dm b/monkestation/code/modules/storytellers/converted_events/_base_event.dm index 0faa795d6aa3..4335c4386191 100644 --- a/monkestation/code/modules/storytellers/converted_events/_base_event.dm +++ b/monkestation/code/modules/storytellers/converted_events/_base_event.dm @@ -70,6 +70,12 @@ var/list/protected_roles /// Restricted roles from the antag roll var/list/restricted_roles + var/event_icon_state + +/datum/round_event_control/proc/generate_image(list/mobs) + return +/datum/round_event_control/antagonist/generate_image(list/mobs) + SScredits.generate_major_icon(mobs, event_icon_state) /datum/round_event_control/antagonist/proc/check_required() if(!length(exclusive_roles)) @@ -269,7 +275,7 @@ log_storyteller("Picked antag event mob: [picked_mob], special role: [picked_mob.mind?.special_role ? picked_mob.mind.special_role : "none"]") candidates |= picked_mob - + var/list/picked_mobs = list() for(var/i in 1 to antag_count) if(!length(candidates)) message_admins("A roleset event got fewer antags then its antag_count and may not function correctly.") @@ -286,8 +292,10 @@ setup_minds += candidate.mind candidate.mind.special_role = antag_flag candidate.mind.restricted_roles = restricted_roles + picked_mobs += WEAKREF(candidate.client) setup = TRUE + control.generate_image(picked_mobs) if(LAZYLEN(extra_spawned_events)) var/event_type = pick_weight(extra_spawned_events) if(!event_type) diff --git a/monkestation/code/modules/storytellers/converted_events/solo/bloodcult.dm b/monkestation/code/modules/storytellers/converted_events/solo/bloodcult.dm index 49d8bf9edead..03b34742e7ca 100644 --- a/monkestation/code/modules/storytellers/converted_events/solo/bloodcult.dm +++ b/monkestation/code/modules/storytellers/converted_events/solo/bloodcult.dm @@ -38,6 +38,7 @@ earliest_start = 0 SECONDS weight = 4 max_occurrences = 1 + event_icon_state = "cult" /datum/round_event/antagonist/solo/bloodcult excute_round_end_reports = TRUE diff --git a/monkestation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm b/monkestation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm index 30ec0ef49fbf..bcf08d77896e 100644 --- a/monkestation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm +++ b/monkestation/code/modules/storytellers/converted_events/solo/bloodsuckers.dm @@ -24,6 +24,7 @@ min_players = 20 weight = 10 maximum_antags = 2 + event_icon_state = "vampires" /datum/round_event_control/antagonist/solo/bloodsucker/roundstart name = "Bloodsuckers" diff --git a/monkestation/code/modules/storytellers/converted_events/solo/changeling.dm b/monkestation/code/modules/storytellers/converted_events/solo/changeling.dm index f198a7b2e85b..64fa6e73fb32 100644 --- a/monkestation/code/modules/storytellers/converted_events/solo/changeling.dm +++ b/monkestation/code/modules/storytellers/converted_events/solo/changeling.dm @@ -24,6 +24,7 @@ min_players = 20 weight = 9 shared_occurence_type = SHARED_CHANGELING + event_icon_state = "changeling" /datum/round_event_control/antagonist/solo/changeling/roundstart name = "Changelings" diff --git a/monkestation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm b/monkestation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm index 9437380c3b06..920f243a5d90 100644 --- a/monkestation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm +++ b/monkestation/code/modules/storytellers/converted_events/solo/clockwork_cult.dm @@ -35,8 +35,9 @@ min_players = 45 roundstart = TRUE earliest_start = 0 SECONDS - weight = 4 + weight = 0 max_occurrences = 1 + event_icon_state = "clockcult" /datum/round_event/antagonist/solo/clockcult end_when = 60000 diff --git a/monkestation/code/modules/storytellers/converted_events/solo/clown_operative.dm b/monkestation/code/modules/storytellers/converted_events/solo/clown_operative.dm index f1e587f44e7a..dadeb02fe81b 100644 --- a/monkestation/code/modules/storytellers/converted_events/solo/clown_operative.dm +++ b/monkestation/code/modules/storytellers/converted_events/solo/clown_operative.dm @@ -41,6 +41,7 @@ earliest_start = 0 SECONDS weight = 1 //these are meant to be very rare max_occurrences = 1 + event_icon_state = "flukeops" /datum/round_event/antagonist/solo/clown_operative excute_round_end_reports = TRUE diff --git a/monkestation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm b/monkestation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm index f1663ee20172..310142058e65 100644 --- a/monkestation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm +++ b/monkestation/code/modules/storytellers/converted_events/solo/nuclear_operative.dm @@ -41,6 +41,7 @@ earliest_start = 0 SECONDS weight = 4 max_occurrences = 3 + event_icon_state = "nukeops" /datum/round_event/antagonist/solo/nuclear_operative excute_round_end_reports = TRUE diff --git a/monkestation/code/modules/storytellers/converted_events/solo/revolutionary.dm b/monkestation/code/modules/storytellers/converted_events/solo/revolutionary.dm index 067ad663de84..3500a4cf21b8 100644 --- a/monkestation/code/modules/storytellers/converted_events/solo/revolutionary.dm +++ b/monkestation/code/modules/storytellers/converted_events/solo/revolutionary.dm @@ -38,6 +38,7 @@ earliest_start = 0 SECONDS weight = 3 //value was 3, we need to manually test if this works or not before allowing it normally max_occurrences = 1 + event_icon_state = "revolution" /datum/antagonist/rev/head/event_trigger remove_clumsy = TRUE diff --git a/monkestation/code/modules/storytellers/converted_events/solo/traitor.dm b/monkestation/code/modules/storytellers/converted_events/solo/traitor.dm index ede797b7be16..abe18dabcf91 100644 --- a/monkestation/code/modules/storytellers/converted_events/solo/traitor.dm +++ b/monkestation/code/modules/storytellers/converted_events/solo/traitor.dm @@ -22,6 +22,7 @@ JOB_CYBORG, ) weight = 15 + event_icon_state = "traitor" /datum/round_event_control/antagonist/solo/traitor/roundstart name = "Traitors" diff --git a/monkestation/code/modules/storytellers/converted_events/solo/wizard.dm b/monkestation/code/modules/storytellers/converted_events/solo/wizard.dm index b0426a0191c8..c6962b9db7d5 100644 --- a/monkestation/code/modules/storytellers/converted_events/solo/wizard.dm +++ b/monkestation/code/modules/storytellers/converted_events/solo/wizard.dm @@ -26,6 +26,7 @@ weight = 2 min_players = 35 max_occurrences = 1 + event_icon_state = "wizard" /datum/round_event_control/antagonist/solo/wizard/can_spawn_event(players_amt, allow_magic = FALSE, fake_check = FALSE) . = ..() diff --git a/monkestation/code/modules/storytellers/gamemode_subsystem.dm b/monkestation/code/modules/storytellers/gamemode_subsystem.dm index 76ee0b166d1b..b8a1179eb9b7 100644 --- a/monkestation/code/modules/storytellers/gamemode_subsystem.dm +++ b/monkestation/code/modules/storytellers/gamemode_subsystem.dm @@ -9,6 +9,7 @@ SUBSYSTEM_DEF(gamemode) init_order = INIT_ORDER_GAMEMODE runlevels = RUNLEVEL_GAME flags = SS_BACKGROUND | SS_KEEP_TIMING + priority = 20 wait = 2 SECONDS /// List of our event tracks for fast access during for loops. diff --git a/monkestation/code/modules/storytellers/readme.md b/monkestation/code/modules/storytellers/readme.md index ace62b725afa..2a8f3d12524d 100644 --- a/monkestation/code/modules/storytellers/readme.md +++ b/monkestation/code/modules/storytellers/readme.md @@ -40,5 +40,6 @@ This PR adds adds on to the current dynamic system by having events be guided by Made by Unknown Coders on Horizon (Horizon's Repo atleast as of 10/14/2023 no longer exists if this changes please let me know on discord #Borbop) +https://github.com/sebdaz/HorizonSS13 Ported by Dwasint diff --git a/monkestation/code/modules/surgery/bodyparts/arachnid_bodyparts.dm b/monkestation/code/modules/surgery/bodyparts/arachnid_bodyparts.dm index 6feabe23fc6d..39de5000e5dd 100644 --- a/monkestation/code/modules/surgery/bodyparts/arachnid_bodyparts.dm +++ b/monkestation/code/modules/surgery/bodyparts/arachnid_bodyparts.dm @@ -3,11 +3,15 @@ limb_id = SPECIES_ARACHNIDS is_dimorphic = FALSE head_flags = HEAD_EYESPRITES | HEAD_EYEHOLES | HEAD_DEBRAIN | HEAD_EYECOLOR + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/chest/arachnid icon_greyscale = 'monkestation/icons/mob/species/arachnid/bodyparts.dmi' limb_id = SPECIES_ARACHNIDS is_dimorphic = FALSE + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/left/arachnid icon_greyscale = 'monkestation/icons/mob/species/arachnid/bodyparts.dmi' @@ -16,6 +20,8 @@ unarmed_attack_effect = ATTACK_EFFECT_CLAW unarmed_attack_sound = 'sound/weapons/slash.ogg' unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/right/arachnid icon_greyscale = 'monkestation/icons/mob/species/arachnid/bodyparts.dmi' @@ -24,11 +30,19 @@ unarmed_attack_effect = ATTACK_EFFECT_CLAW unarmed_attack_sound = 'sound/weapons/slash.ogg' unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/left/arachnid icon_greyscale = 'monkestation/icons/mob/species/arachnid/bodyparts.dmi' limb_id = SPECIES_ARACHNIDS + speed_modifier = -0.05 + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/right/arachnid icon_greyscale = 'monkestation/icons/mob/species/arachnid/bodyparts.dmi' limb_id = SPECIES_ARACHNIDS + speed_modifier = -0.05 + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR diff --git a/monkestation/code/modules/surgery/bodyparts/floran_bodyparts.dm b/monkestation/code/modules/surgery/bodyparts/floran_bodyparts.dm index 353882d35acb..08d4afe1f4d8 100644 --- a/monkestation/code/modules/surgery/bodyparts/floran_bodyparts.dm +++ b/monkestation/code/modules/surgery/bodyparts/floran_bodyparts.dm @@ -3,11 +3,17 @@ limb_id = SPECIES_FLORAN is_dimorphic = FALSE head_flags = HEAD_EYESPRITES | HEAD_EYEHOLES | HEAD_DEBRAIN + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/chest/floran icon_greyscale = 'monkestation/icons/mob/species/floran/bodyparts.dmi' limb_id = SPECIES_FLORAN is_dimorphic = TRUE + ass_image = 'icons/ass/asspodperson.png' + bodypart_traits = list(TRAIT_LIMBATTACHMENT) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/left/floran icon_greyscale = 'monkestation/icons/mob/species/floran/bodyparts.dmi' @@ -18,6 +24,9 @@ unarmed_attack_effect = ATTACK_EFFECT_CLAW unarmed_attack_sound = 'sound/weapons/slice.ogg' unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' + hand_traits = list(TRAIT_PLANT_SAFE) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/arm/right/floran icon_greyscale = 'monkestation/icons/mob/species/floran/bodyparts.dmi' @@ -28,11 +37,20 @@ unarmed_attack_effect = ATTACK_EFFECT_CLAW unarmed_attack_sound = 'sound/weapons/slice.ogg' unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' + hand_traits = list(TRAIT_PLANT_SAFE) + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/left/floran icon_greyscale = 'monkestation/icons/mob/species/floran/bodyparts.dmi' limb_id = SPECIES_FLORAN + speed_modifier = -0.05 + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR /obj/item/bodypart/leg/right/floran icon_greyscale = 'monkestation/icons/mob/species/floran/bodyparts.dmi' limb_id = SPECIES_FLORAN + speed_modifier = -0.05 + palette = /datum/color_palette/generic_colors + palette_key = MUTANT_COLOR diff --git a/monkestation/code/modules/surgery/bodyparts/simian_bodyparts.dm b/monkestation/code/modules/surgery/bodyparts/simian_bodyparts.dm index a4f869adb794..23da5d9671bb 100644 --- a/monkestation/code/modules/surgery/bodyparts/simian_bodyparts.dm +++ b/monkestation/code/modules/surgery/bodyparts/simian_bodyparts.dm @@ -7,6 +7,8 @@ bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_CUSTOM head_flags = HEAD_EYESPRITES | HEAD_EYEHOLES | HEAD_DEBRAIN | HEAD_EYECOLOR dmg_overlay_type = "monkey" + palette = /datum/color_palette/generic_colors + palette_key = "fur_color" /obj/item/bodypart/chest/simian icon_greyscale = 'monkestation/icons/mob/species/simian/bodyparts.dmi' @@ -15,8 +17,9 @@ limb_id = SPECIES_SIMIAN is_dimorphic = FALSE bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_CUSTOM - dmg_overlay_type = "monkey" + palette = /datum/color_palette/generic_colors + palette_key = "fur_color" /obj/item/bodypart/arm/left/simian icon_greyscale = 'monkestation/icons/mob/species/simian/bodyparts.dmi' @@ -24,8 +27,9 @@ husk_type = "simian" limb_id = SPECIES_SIMIAN bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_CUSTOM - dmg_overlay_type = "monkey" + palette = /datum/color_palette/generic_colors + palette_key = "fur_color" /obj/item/bodypart/arm/right/simian icon_greyscale = 'monkestation/icons/mob/species/simian/bodyparts.dmi' @@ -33,8 +37,9 @@ husk_type = "simian" limb_id = SPECIES_SIMIAN bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_CUSTOM - dmg_overlay_type = "monkey" + palette = /datum/color_palette/generic_colors + palette_key = "fur_color" /obj/item/bodypart/leg/left/simian icon_greyscale = 'monkestation/icons/mob/species/simian/bodyparts.dmi' @@ -43,6 +48,9 @@ limb_id = SPECIES_SIMIAN bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_CUSTOM footprint_sprite = FOOTPRINT_SPRITE_PAWS + speed_modifier = -0.05 + palette = /datum/color_palette/generic_colors + palette_key = "fur_color" /obj/item/bodypart/leg/right/simian icon_greyscale = 'monkestation/icons/mob/species/simian/bodyparts.dmi' @@ -51,5 +59,7 @@ limb_id = SPECIES_SIMIAN bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_CUSTOM footprint_sprite = FOOTPRINT_SPRITE_PAWS - dmg_overlay_type = "monkey" + speed_modifier = -0.05 + palette = /datum/color_palette/generic_colors + palette_key = "fur_color" diff --git a/monkestation/code/modules/surgery/bodyparts/teratoma_bodyparts.dm b/monkestation/code/modules/surgery/bodyparts/teratoma_bodyparts.dm index 807f413ff393..96e67800e663 100644 --- a/monkestation/code/modules/surgery/bodyparts/teratoma_bodyparts.dm +++ b/monkestation/code/modules/surgery/bodyparts/teratoma_bodyparts.dm @@ -7,6 +7,7 @@ bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_CUSTOM should_draw_greyscale = FALSE head_flags = HEAD_LIPS | HEAD_DEBRAIN + composition_effects = list(TRAIT_PASSTABLE = 0.5, TRAIT_VENTCRAWLER_ALWAYS = 0.8) dmg_overlay_type = "monkey" @@ -18,6 +19,7 @@ is_dimorphic = FALSE bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_CUSTOM should_draw_greyscale = FALSE + composition_effects = list(TRAIT_PASSTABLE = 0.5, TRAIT_VENTCRAWLER_ALWAYS = 0.8) dmg_overlay_type = "monkey" @@ -28,6 +30,8 @@ limb_id = SPECIES_TERATOMA bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_CUSTOM should_draw_greyscale = FALSE + hand_traits = list(TRAIT_CHUNKYFINGERS) + composition_effects = list(TRAIT_PASSTABLE = 0.5, TRAIT_VENTCRAWLER_ALWAYS = 0.8) dmg_overlay_type = "monkey" @@ -38,6 +42,8 @@ limb_id = SPECIES_TERATOMA bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_CUSTOM should_draw_greyscale = FALSE + hand_traits = list(TRAIT_CHUNKYFINGERS) + composition_effects = list(TRAIT_PASSTABLE = 0.5, TRAIT_VENTCRAWLER_ALWAYS = 0.8) dmg_overlay_type = "monkey" @@ -48,7 +54,10 @@ limb_id = SPECIES_TERATOMA bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_CUSTOM should_draw_greyscale = FALSE + speed_modifier = -0.075 footprint_sprite = FOOTPRINT_SPRITE_PAWS + bodypart_traits = list(TRAIT_VAULTING) + composition_effects = list(TRAIT_PASSTABLE = 0.5, TRAIT_VENTCRAWLER_ALWAYS = 0.8) /obj/item/bodypart/leg/right/teratoma icon_static = 'monkestation/icons/mob/species/teratoma/bodyparts.dmi' @@ -58,5 +67,7 @@ bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_CUSTOM should_draw_greyscale = FALSE footprint_sprite = FOOTPRINT_SPRITE_PAWS - + speed_modifier = -0.075 dmg_overlay_type = "monkey" + bodypart_traits = list(TRAIT_VAULTING) + composition_effects = list(TRAIT_PASSTABLE = 0.5, TRAIT_VENTCRAWLER_ALWAYS = 0.8) diff --git a/monkestation/code/modules/surgery/organs/external/ethereal_accessories.dm b/monkestation/code/modules/surgery/organs/external/ethereal_accessories.dm index 3fd637f3e771..f645ed3ed76f 100644 --- a/monkestation/code/modules/surgery/organs/external/ethereal_accessories.dm +++ b/monkestation/code/modules/surgery/organs/external/ethereal_accessories.dm @@ -14,6 +14,8 @@ /datum/bodypart_overlay/mutant/ethereal_horns layers = EXTERNAL_FRONT|EXTERNAL_ADJACENT feature_key = "ethereal_horns" + palette = /datum/color_palette/generic_colors + palette_key = "ethereal_color" /datum/bodypart_overlay/mutant/ethereal_horns/get_global_feature_list() return GLOB.ethereal_horns_list @@ -38,6 +40,8 @@ /datum/bodypart_overlay/mutant/tail/ethereal layers = EXTERNAL_FRONT|EXTERNAL_BEHIND feature_key = "ethereal_tail" + palette = /datum/color_palette/generic_colors + palette_key = "ethereal_color" /datum/bodypart_overlay/mutant/tail/ethereal/get_global_feature_list() return GLOB.ethereal_tail_list diff --git a/monkestation/code/modules/surgery/organs/internal/tongue.dm b/monkestation/code/modules/surgery/organs/internal/tongue.dm index 684fd10d6ddb..c2a45d683494 100644 --- a/monkestation/code/modules/surgery/organs/internal/tongue.dm +++ b/monkestation/code/modules/surgery/organs/internal/tongue.dm @@ -16,6 +16,14 @@ desc = "The tongue of an Arachnid. Mostly used for lying." say_mod = "chitters" modifies_speech = TRUE + disliked_foodtypes = NONE // Okay listen, i don't actually know what irl spiders don't like to eat and i'm pretty tired of looking for answers. + liked_foodtypes = GORE | MEAT | BUGS | GROSS + +/obj/item/organ/internal/tongue/arachnid/get_scream_sound() + return 'monkestation/sound/voice/screams/arachnid/arachnid_scream.ogg' + +/obj/item/organ/internal/tongue/arachnid/get_laugh_sound() + return 'monkestation/sound/voice/laugh/arachnid/arachnid_laugh.ogg' /obj/item/organ/internal/tongue/arachnid/modify_speech(datum/source, list/speech_args) //This is flypeople speech var/static/regex/fly_buzz = new("z+", "g") @@ -30,15 +38,3 @@ /obj/item/organ/internal/tongue/arachnid/get_possible_languages() return ..() + /datum/language/buzzwords - -/obj/item/organ/internal/tongue/oozeling - name = "oozeling tongue" - desc = "A goopy organ that mimics the tongues of other carbon beings." - icon = 'monkestation/icons/obj/medical/organs/organs.dmi' - icon_state = "tongue_oozeling" - say_mod = "blurbles" - alpha = 200 - -// Oozeling tongues can speak all default + slime -/obj/item/organ/internal/tongue/oozeling/get_possible_languages() - return ..() + /datum/language/slime diff --git a/monkestation/code/modules/temperature_overhaul/exposure.dm b/monkestation/code/modules/temperature_overhaul/exposure.dm new file mode 100644 index 000000000000..d4b95448ef86 --- /dev/null +++ b/monkestation/code/modules/temperature_overhaul/exposure.dm @@ -0,0 +1,64 @@ +/// Ticking buff to overheated mobs that causes burn wounds +/datum/status_effect/stacking/heat_exposure + id = "heat_exposure" + status_type = STATUS_EFFECT_UNIQUE + remove_on_fullheal = TRUE + heal_flag_necessary = HEAL_TEMP + max_stacks = 40 + stack_threshold = 10 // added to in init + stack_decay = 0 // handled manually + + var/warned = TRUE + + /// How hot before we gain stacks rather than losing them + var/temp_threshold = -1 + +/datum/status_effect/stacking/heat_exposure/on_creation(mob/living/new_owner, stacks_to_apply, temp_threshold) + src.stack_threshold += rand(0, 20) + src.temp_threshold = temp_threshold + return ..() + +/datum/status_effect/stacking/heat_exposure/can_have_status() + return ishuman(owner) && !HAS_TRAIT(src, TRAIT_RESISTHEAT) + +/datum/status_effect/stacking/heat_exposure/can_gain_stacks() + return can_have_status() && owner.bodytemperature > temp_threshold + +/datum/status_effect/stacking/heat_exposure/tick(seconds_between_ticks) + if(owner.bodytemperature > temp_threshold) + add_stacks(0.5 * seconds_between_ticks) + else + add_stacks(-2 * seconds_between_ticks) + if(QDELETED(src)) // either we dropped off or we applied a wound + return + if(stacks >= max(stack_threshold - (10 + rand(-2, 5)), 8) && SPT_PROB(33, seconds_between_ticks) && !warned) + to_chat(owner, span_warning("You feel overheated!")) + warned = TRUE + return ..() + +/datum/status_effect/stacking/heat_exposure/stacks_consumed_effect() + var/mob/living/carbon/human/human_owner = owner + // Lets pick a random body part and check for an existing burn + var/obj/item/bodypart/bodypart = pick(human_owner.bodyparts) + var/datum/wound/existing_burn + for (var/datum/wound/iterated_wound as anything in bodypart.wounds) + var/datum/wound_pregen_data/pregen_data = iterated_wound.get_pregen_data() + if (pregen_data.wound_series in GLOB.wounding_types_to_series[WOUND_BURN]) + existing_burn = iterated_wound + break + + // If we have an existing burn try to upgrade it + var/severity = WOUND_SEVERITY_MODERATE + var/heat_damage = 2 * HEAT_DAMAGE * human_owner.physiology.heat_mod + if(human_owner.bodytemperature > temp_threshold * 8) + if(existing_burn?.severity < WOUND_SEVERITY_CRITICAL) + severity = WOUND_SEVERITY_CRITICAL + heat_damage *= 8 + + else if(human_owner.bodytemperature > temp_threshold * 2) + if(existing_burn?.severity < WOUND_SEVERITY_SEVERE) + severity = WOUND_SEVERITY_SEVERE + heat_damage *= 3 + + human_owner.cause_wound_of_type_and_severity(WOUND_BURN, bodypart, severity, wound_source = "hot temperatures") + human_owner.apply_damage(HEAT_DAMAGE, BURN, bodypart, wound_bonus = CANT_WOUND) diff --git a/monkestation/code/modules/temperature_overhaul/homeostasis_level.dm b/monkestation/code/modules/temperature_overhaul/homeostasis_level.dm new file mode 100644 index 000000000000..3617fb7bbc28 --- /dev/null +++ b/monkestation/code/modules/temperature_overhaul/homeostasis_level.dm @@ -0,0 +1,135 @@ +/** + * Changes the level to which the mob homeostasises to, while optionally providing a buff to the rate at which they do so. + * + * Additional buff to homeostasis rate does not affecte nutrition drain of homeostasis. + * + * Args + * * source: String key source of this effect + * * to_value: The target value to homeostasise to + * * delta_change: Optional, additional rate of change to the mob's body temperature + * * while_stasis: Optional, if delta change is supplied, it will tick while the mob is in stasis + * * while_dead: Optional, if delta change is supplied, it will tick while the mob is dead + * * update_species: Optional, if TRUE, and if the mob's species changes, we will update the target temp. to accomodate + * (via the difference in new species vs old species standard_body_temperature) + */ +/mob/living/proc/add_homeostasis_level( + source, + to_value, + delta_change = 0 KELVIN, + while_stasis = FALSE, + while_dead = FALSE, + update_species = TRUE +) + ASSERT(source) + ASSERT(to_value) + apply_status_effect(/datum/status_effect/homeostasis_level, source, to_value, delta_change, while_stasis, while_dead, update_species) + +/** + * Removes a source of homeostasis level change from a mob. + * + * Args + * * source: String key source to remove + */ +/mob/living/proc/remove_homeostasis_level( + source, +) + ASSERT(source) + remove_status_effect(/datum/status_effect/homeostasis_level, source) + +/** + * Updates an existing change to the mob's homeostasis levels + * + * Args + * * source: String key source to update + * * to_value: Change the level to homeostasise to + * * delta_change: Change the rate of change to the mob's body temperature + */ +/mob/living/proc/update_homeostasis_level( + source, + to_value, + delta_change = 0 KELVIN, +) + ASSERT(source) + ASSERT(to_value) + apply_status_effect(/datum/status_effect/homeostasis_level, source, to_value, delta_change) + +/** + * Attempts to stabilize a mob's body temperature to a set value. + */ +/datum/status_effect/homeostasis_level + id = "temp_change" + status_type = STATUS_EFFECT_MULTIPLE + tick_interval = 2 SECONDS + alert_type = null + var/source + var/to_value + var/delta_change + var/while_stasis + var/while_dead + var/update_species + +/datum/status_effect/homeostasis_level/on_creation( + mob/living/new_owner, + source, + to_value, + delta_change = 0 KELVIN, + while_stasis = FALSE, + while_dead = FALSE, + update_species = TRUE +) + src.source = source + src.to_value = to_value + src.delta_change = abs(delta_change) + src.while_stasis = while_stasis + src.while_dead = while_dead + src.update_species = update_species + + return ..() + +/datum/status_effect/homeostasis_level/on_apply() + if(isnull(src.source)) + stack_trace("Temperature change status effect applied without a source") + return FALSE + if(isnull(src.to_value)) + stack_trace("Temperature change status effect applied without a set temperature") + return FALSE + + for(var/datum/status_effect/homeostasis_level/effect in owner.status_effects) + if(effect.source == src.source) + effect.to_value = src.to_value + effect.delta_change = src.delta_change + LAZYSET(owner.homeostasis_targets, REF(effect), effect.to_value) + return FALSE + + RegisterSignal(owner, COMSIG_SPECIES_GAIN, PROC_REF(species_update)) + LAZYSET(owner.homeostasis_targets, REF(src), src.to_value) + return TRUE + +/datum/status_effect/homeostasis_level/before_remove(source) + return src.source == source + +/datum/status_effect/homeostasis_level/on_remove() + UnregisterSignal(owner, COMSIG_SPECIES_GAIN) + LAZYREMOVE(owner.homeostasis_targets, REF(src)) + +/datum/status_effect/homeostasis_level/tick(seconds_between_ticks) + if(!delta_change) + return + if(!while_stasis && HAS_TRAIT(owner, TRAIT_STASIS)) + return + if(!while_dead && owner.stat == DEAD) + return + + if(to_value < owner.standard_body_temperature) + owner.adjust_bodytemperature(-delta_change, min_temp = to_value) + + else + owner.adjust_bodytemperature(delta_change, max_temp = to_value) + +/datum/status_effect/homeostasis_level/proc/species_update(datum/source, datum/species/new_species, datum/species/old_species) + SIGNAL_HANDLER + + if(!update_species || isnull(new_species) || isnull(old_species) || new_species.type == old_species.type) + return + + to_value += UNLINT(new_species.bodytemp_normal - old_species.bodytemp_normal) diff --git a/monkestation/code/modules/temperature_overhaul/living_procs.dm b/monkestation/code/modules/temperature_overhaul/living_procs.dm new file mode 100644 index 000000000000..98ea4f3f5845 --- /dev/null +++ b/monkestation/code/modules/temperature_overhaul/living_procs.dm @@ -0,0 +1,166 @@ +/mob/living/proc/body_temperature_damage(datum/gas_mixture/environment, seconds_per_tick, times_fired) + if(bodytemperature > bodytemp_heat_damage_limit && !HAS_TRAIT(src, TRAIT_RESISTHEAT)) + var/heat_diff = bodytemp_heat_damage_limit - standard_body_temperature + var/heat_threshold_low = bodytemp_heat_damage_limit + heat_diff * 1.25 + var/heat_threshold_medium = bodytemp_heat_damage_limit + heat_diff * 2 + var/heat_threshold_high = bodytemp_heat_damage_limit + heat_diff * 4 + + var/firemodifier = round(fire_stacks, 1) * 0.01 + if (!on_fire) // We are not on fire, reduce the modifier + firemodifier = min(firemodifier, 0) // Note that wetstacks make us take less burn damage + + // convering back and forth so we can apply a multiplier from firestacks without sending temp to the moon + var/effective_temp = CELCIUS_TO_KELVIN(KELVIN_TO_CELCIUS(bodytemperature) * (1 + firemodifier)) + var/burn_damage = HEAT_DAMAGE + if(effective_temp > heat_threshold_high) + burn_damage *= 5 + else if(effective_temp > heat_threshold_medium) + burn_damage *= 3 + else if(effective_temp > heat_threshold_low) + burn_damage *= 1 + + temperature_burns(burn_damage * seconds_per_tick) + if(effective_temp > heat_threshold_medium) + apply_status_effect(/datum/status_effect/stacking/heat_exposure, 1, heat_threshold_medium) + + + // For cold damage, we cap at the threshold if you're dead + if(bodytemperature < bodytemp_cold_damage_limit && !HAS_TRAIT(src, TRAIT_RESISTCOLD) && (getFireLoss() < maxHealth || stat != DEAD)) + var/cold_diff = bodytemp_cold_damage_limit - standard_body_temperature + var/cold_threshold_low = bodytemp_cold_damage_limit + cold_diff * 1.2 + var/cold_threshold_medium = bodytemp_cold_damage_limit + cold_diff * 1.75 + // For cold damage, we cap at the threshold if you're dead + var/cold_threshold_high = bodytemp_cold_damage_limit + cold_diff * 2 + + var/cold_damage = COLD_DAMAGE + if(bodytemperature < cold_threshold_high) + cold_damage *= 8 + else if(bodytemperature < cold_threshold_medium) + cold_damage *= 4 + else if(bodytemperature < cold_threshold_low) + cold_damage *= 2 + + temperature_cold_damage(cold_damage * seconds_per_tick) + +/// Applies damage to the mob due to being too cold +/mob/living/proc/temperature_cold_damage(damage) + return apply_damage(damage, HAS_TRAIT(src, TRAIT_HULK) ? BRUTE : BURN, spread_damage = TRUE, wound_bonus = CANT_WOUND) + +/mob/living/carbon/human/temperature_cold_damage(damage) + damage *= physiology.cold_mod + return ..() + +/// Applies damage to the mob due to being too hot +/mob/living/proc/temperature_burns(damage) + return apply_damage(damage, BURN, spread_damage = TRUE, wound_bonus = CANT_WOUND) + +/mob/living/carbon/human/temperature_burns(damage) + damage *= physiology.heat_mod + return ..() + +/mob/living/proc/body_temperature_alerts() + // give out alerts based on how the skin feels, not how the body is + // this gives us an early warning system - since we tend to trend up/down to skin temperature - + // how we're going to be feeling soon if we don't change our environment + var/feels_like = get_skin_temperature() + + var/hot_diff = bodytemp_heat_damage_limit - standard_body_temperature + var/hot_threshold_low = bodytemp_heat_damage_limit - hot_diff * 0.5 + var/hot_threshold_medium = bodytemp_heat_damage_limit + var/hot_threshold_high = bodytemp_heat_damage_limit + hot_diff + // Body temperature is too hot, and we do not have resist traits + if(feels_like > hot_threshold_low && !HAS_TRAIT(src, TRAIT_RESISTHEAT)) + clear_mood_event("cold") + // Clear cold once we return to warm + remove_movespeed_modifier(/datum/movespeed_modifier/cold) + if(feels_like > hot_threshold_high) + throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 3) + add_mood_event("hot", /datum/mood_event/overhot) + else if(feels_like > hot_threshold_medium) + throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 2) + add_mood_event("hot", /datum/mood_event/hot) + else + throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/hot, 1) + add_mood_event("hot", /datum/mood_event/warm) + temp_alerts = TRUE + + var/cold_diff = bodytemp_cold_damage_limit - standard_body_temperature + var/cold_threshold_low = bodytemp_cold_damage_limit - cold_diff * 0.5 + var/cold_threshold_medium = bodytemp_cold_damage_limit + var/cold_threshold_high = bodytemp_cold_damage_limit + cold_diff + // Body temperature is too cold, and we do not have resist traits + if(feels_like < cold_threshold_low && !HAS_TRAIT(src, TRAIT_RESISTCOLD)) + clear_mood_event("hot") + if(feels_like < cold_threshold_high) + throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 3) + add_mood_event("cold", /datum/mood_event/freezing) + else if(feels_like < cold_threshold_medium) + throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 2) + add_mood_event("cold", /datum/mood_event/cold) + else + throw_alert(ALERT_TEMPERATURE, /atom/movable/screen/alert/cold, 1) + add_mood_event("cold", /datum/mood_event/chilly) + temp_alerts = TRUE + // Only apply slowdown if the body is cold rather than the skin + if(bodytemperature < cold_threshold_medium && !HAS_TRAIT(src, TRAIT_RESISTCOLD)) + add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/cold, multiplicative_slowdown = ((cold_threshold_medium - bodytemperature) / COLD_SLOWDOWN_FACTOR)) + else if(has_movespeed_modifier(/datum/movespeed_modifier/cold)) + remove_movespeed_modifier(/datum/movespeed_modifier/cold) + + // We are not to hot or cold, remove status and moods + if(temp_alerts && (feels_like < hot_threshold_low || HAS_TRAIT(src, TRAIT_RESISTHEAT)) && (feels_like > cold_threshold_low || HAS_TRAIT(src, TRAIT_RESISTCOLD))) + clear_alert(ALERT_TEMPERATURE) + clear_mood_event("cold") + clear_mood_event("hot") + temp_alerts = FALSE + +/** + * Handles this mob internally managing its body temperature (sweating or generating heat) + * + * Arguments: + * * seconds_per_tick: The amount of time that has elapsed since this last fired. + * * times_fired: The number of times SSmobs has fired + */ +/mob/living/proc/temperature_homeostasis(seconds_per_tick, times_fired) + if(HAS_TRAIT(src, TRAIT_COLD_BLOODED)) + return + if(!HAS_TRAIT(src, TRAIT_NOHUNGER) && nutrition < (NUTRITION_LEVEL_STARVING / 3)) + return + + // find exactly what temperature we're aiming for + var/homeostasis_target = standard_body_temperature + if(LAZYLEN(homeostasis_targets)) + homeostasis_target = 0 + for(var/source in homeostasis_targets) + homeostasis_target += homeostasis_targets[source] + homeostasis_target /= LAZYLEN(homeostasis_targets) + + // temperature delta is capped, so you can't attempt to homeostaize from vacuum to standard temp in a second + var/temp_delta = (homeostasis_target - bodytemperature) + temp_delta = temp_delta < 0 ? max(temp_delta, BODYTEMP_HOMEOSTASIS_COOLING_MAX) : min(temp_delta, BODYTEMP_HOMEOSTASIS_HEATING_MAX) + // note: Because this scales by metabolism efficiency, being well fed boosts your homeostasis, and being poorly fed reduces it + var/natural_change = temp_delta * metabolism_efficiency * temperature_homeostasis_speed + if(natural_change == 0) + return + + var/sigreturn = SEND_SIGNAL(src, COMSIG_LIVING_HOMEOSTASIS, natural_change, seconds_per_tick) + if(sigreturn & HOMEOSTASIS_HANDLED) + return + + var/min = natural_change < 0 ? homeostasis_target : 0 + var/max = natural_change > 0 ? homeostasis_target : INFINITY + // calculates how much nutrition decay per kelvin of temperature change + // while having this scale may be confusing, it's to make sure that stepping into an extremely cold environment (space) + // doesn't immediately drain nutrition to zero in under a minute + // at 0.25 kelvin, nutrition_per_kelvin is 2.5. at 1, it's ~1.5, and at 4, it's 1. + var/nutrition_per_kelvin = round(2.5 / ((abs(natural_change) / 0.25) ** 0.33), 0.01) + + adjust_bodytemperature(natural_change * seconds_per_tick, min_temp = min, max_temp = max) // no use_insulation beacuse this is internal + if(!(sigreturn & HOMEOSTASIS_NO_HUNGER)) + adjust_nutrition(-0.1 * HOMEOSTASIS_HUNGER_MULTIPLIER * HUNGER_FACTOR * nutrition_per_kelvin * abs(natural_change) * seconds_per_tick) + +/mob/living/silicon/temperature_homeostasis(seconds_per_tick, times_fired) + return // Not yet + +/mob/proc/adjust_satiety(change) + satiety = clamp(satiety + change, -MAX_SATIETY, MAX_SATIETY) diff --git a/monkestation/code/modules/temperature_overhaul/temperature_proc.dm b/monkestation/code/modules/temperature_overhaul/temperature_proc.dm new file mode 100644 index 000000000000..87b53b0a0b63 --- /dev/null +++ b/monkestation/code/modules/temperature_overhaul/temperature_proc.dm @@ -0,0 +1,121 @@ +#define THERMAL_PROTECTION_HEAD 0.3 +#define THERMAL_PROTECTION_CHEST 0.2 +#define THERMAL_PROTECTION_GROIN 0.10 +#define THERMAL_PROTECTION_LEG (0.075 * 2) +#define THERMAL_PROTECTION_FOOT (0.025 * 2) +#define THERMAL_PROTECTION_ARM (0.075 * 2) +#define THERMAL_PROTECTION_HAND (0.025 * 2) + +/** + * Get the insulation that is appropriate to the temperature you're being exposed to. + * All clothing, natural insulation, and traits are combined returning a single value. + * + * Args + * * temperature - what temperature is being exposed to this mob? + * some articles of clothing are only effective within a certain temperature range + * + * returns the percentage of protection as a value from 0 - 1 +**/ +/mob/living/proc/get_insulation(temperature = T20C) + // There is an occasional bug where the temperature is miscalculated in areas with small amounts of gas. + // This is necessary to ensure that does not affect this calculation. + // Space's temperature is 2.7K and most suits that are intended to protect against any cold, protect down to 2.0K. + temperature = max(temperature, TCMB) + + var/thermal_protection_flags = NONE + for(var/obj/item/worn in get_equipped_items()) + var/valid = FALSE + if(isnum(worn.max_heat_protection_temperature) && isnum(worn.min_cold_protection_temperature)) + valid = worn.max_heat_protection_temperature >= temperature && worn.min_cold_protection_temperature <= temperature + + else if (isnum(worn.max_heat_protection_temperature)) + valid = worn.max_heat_protection_temperature >= temperature + + else if (isnum(worn.min_cold_protection_temperature)) + valid = worn.min_cold_protection_temperature <= temperature + + if(valid) + thermal_protection_flags |= worn.body_parts_covered + + var/thermal_protection = temperature_insulation + if(thermal_protection_flags) + if(thermal_protection_flags & HEAD) + thermal_protection += THERMAL_PROTECTION_HEAD + if(thermal_protection_flags & CHEST) + thermal_protection += THERMAL_PROTECTION_CHEST + if(thermal_protection_flags & GROIN) + thermal_protection += THERMAL_PROTECTION_GROIN + if(thermal_protection_flags & LEGS) + thermal_protection += THERMAL_PROTECTION_LEG + if(thermal_protection_flags & FEET) + thermal_protection += THERMAL_PROTECTION_FOOT + if(thermal_protection_flags & ARMS) + thermal_protection += THERMAL_PROTECTION_ARM + if(thermal_protection_flags & HANDS) + thermal_protection += THERMAL_PROTECTION_HAND + + return min(1, thermal_protection) + +#undef THERMAL_PROTECTION_HEAD +#undef THERMAL_PROTECTION_CHEST +#undef THERMAL_PROTECTION_GROIN +#undef THERMAL_PROTECTION_LEG +#undef THERMAL_PROTECTION_FOOT +#undef THERMAL_PROTECTION_ARM +#undef THERMAL_PROTECTION_HAND + +/mob/living/proc/adjust_bodytemperature(amount = 0, min_temp = 0, max_temp = INFINITY, use_insulation = FALSE) + // apply insulation to the amount of change + if(use_insulation) + amount *= (1 - get_insulation(bodytemperature + amount)) + if(amount == 0) + return FALSE + if(amount == 0) + return 0 + amount = round(amount, 0.01) + + if(bodytemperature >= min_temp && bodytemperature <= max_temp) + var/old_temp = bodytemperature + bodytemperature = clamp(bodytemperature + amount, min_temp, max_temp) + SEND_SIGNAL(src, COMSIG_LIVING_BODY_TEMPERATURE_CHANGE, old_temp, bodytemperature) + // body_temperature_alerts() + return bodytemperature - old_temp + return 0 + +// Robot bodytemp unimplemented for now. Add overheating later >:3 +/mob/living/silicon/adjust_bodytemperature(amount, min_temp, max_temp, use_insulation) + return + +/** + * Get the temperature of the skin of the mob + * + * This is a weighted average of the body temperature and the temperature of the air around the mob, + * plus some other modifiers + */ +/mob/living/proc/get_skin_temperature() + var/area_temperature = get_temperature(loc?.return_air()) + if(!(mob_biotypes & MOB_ORGANIC) && !isipc(src)) + // non-organic mobs likely don't feel or regulate temperature + // so we can just report the area temp... probably + // there's an argument to be made for putting the cold blooded check here + return round(area_temperature, 0.01) + + // calculate skin temp based on a weight average between body temp and area temp plus a multiplier + // this weighting gives us about 34.4c for a 37c body temp in a 20c room which is about average + var/insulation = get_insulation(area_temperature) + // converting to celcius as it's easier to work with / multiply on + var/skin_temp = 1.1 * ((KELVIN_TO_CELCIUS(bodytemperature) * 2 + KELVIN_TO_CELCIUS(area_temperature) * (1 - insulation)) / (3 - insulation)) + + if(temperature_homeostasis_speed != 0) // not cold blooded + if(bodytemperature >= standard_body_temperature + 2 CELCIUS) + skin_temp *= 1.1 // vasodilation / sweating + if(bodytemperature <= standard_body_temperature + ((bodytemp_cold_damage_limit - standard_body_temperature) * 0.5)) + skin_temp *= 0.9 // vasoconstriction + + // back to kelvin + . = CELCIUS_TO_KELVIN(skin_temp) + // and if we're on fire just add a flat amount of heat + if(on_fire) + . += fire_stacks ** 2 KELVIN + + return . diff --git a/monkestation/code/modules/the_bird_inside_of_me/icons/armwings.dmi b/monkestation/code/modules/the_bird_inside_of_me/icons/armwings.dmi new file mode 100644 index 000000000000..52e17f5c7ed9 Binary files /dev/null and b/monkestation/code/modules/the_bird_inside_of_me/icons/armwings.dmi differ diff --git a/monkestation/code/modules/the_bird_inside_of_me/icons/ornithid_parts_greyscale.dmi b/monkestation/code/modules/the_bird_inside_of_me/icons/ornithid_parts_greyscale.dmi new file mode 100644 index 000000000000..7acbc9ed87a5 Binary files /dev/null and b/monkestation/code/modules/the_bird_inside_of_me/icons/ornithid_parts_greyscale.dmi differ diff --git a/monkestation/code/modules/the_bird_inside_of_me/icons/ornithidfeatures.dmi b/monkestation/code/modules/the_bird_inside_of_me/icons/ornithidfeatures.dmi new file mode 100644 index 000000000000..32ce5bb7de37 Binary files /dev/null and b/monkestation/code/modules/the_bird_inside_of_me/icons/ornithidfeatures.dmi differ diff --git a/monkestation/code/modules/the_bird_inside_of_me/language.dm b/monkestation/code/modules/the_bird_inside_of_me/language.dm new file mode 100644 index 000000000000..36add88dbb6b --- /dev/null +++ b/monkestation/code/modules/the_bird_inside_of_me/language.dm @@ -0,0 +1,9 @@ +/datum/language_holder/yangyu + understood_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/yangyu = list(LANGUAGE_ATOM), + ) + spoken_languages = list( + /datum/language/common = list(LANGUAGE_ATOM), + /datum/language/yangyu = list(LANGUAGE_ATOM), + ) diff --git a/monkestation/code/modules/the_bird_inside_of_me/organs.dm b/monkestation/code/modules/the_bird_inside_of_me/organs.dm new file mode 100644 index 000000000000..7782e7b09b78 --- /dev/null +++ b/monkestation/code/modules/the_bird_inside_of_me/organs.dm @@ -0,0 +1,123 @@ +/obj/item/organ/internal/tongue/ornithid + name = "avian tongue" + desc = "A seemingly normal looking tongue which causes ones voice to caw. However that works." + say_mod = "caws" + /// Our song datum. + var/datum/song/organ/song + /// How far away our song datum can be heard. + var/instrument_range = 12 + ///our music ability + var/datum/action/innate/singing/sing + ///static list of instruments we can play + var/list/static/allowed_instrument_ids = list("mothscream", "honk", "violin", "guitar", "piano", "recorder", "banjo", "r3grand","r3harpsi","crharpsi","crgrand1","crbright1", "crichugan", "crihamgan") + ///this is our spewer component + var/datum/component/particle_spewer/music_notes/music + +/obj/item/organ/internal/tongue/ornithid/Initialize(mapload) + . = ..() + song = new(src, allowed_instrument_ids, instrument_range) + RegisterSignal(src, COMSIG_INSTRUMENT_START, PROC_REF(start_sound_particles)) + RegisterSignal(src, COMSIG_INSTRUMENT_END, PROC_REF(stop_sound_particles)) + +/obj/item/organ/internal/tongue/ornithid/Destroy() + . = ..() + QDEL_NULL(song) + UnregisterSignal(src, list(COMSIG_INSTRUMENT_START, COMSIG_INSTRUMENT_END)) + +/obj/item/organ/internal/tongue/ornithid/Insert(mob/living/carbon/tongue_owner, special, drop_if_replaced) + . = ..() + if(QDELETED(sing)) + sing = new + sing.Grant(tongue_owner) + +/obj/item/organ/internal/tongue/ornithid/Remove(mob/living/carbon/tongue_owner, special) + . = ..() + sing?.Remove (tongue_owner) + song.stop_playing() + stop_sound_particles() + +/obj/item/organ/internal/tongue/ornithid/proc/start_sound_particles() + if(!music) + music = owner.AddComponent(/datum/component/particle_spewer/music_notes) + +/obj/item/organ/internal/tongue/ornithid/proc/stop_sound_particles() + qdel(owner?.GetComponent(/datum/component/particle_spewer/music_notes)) + music = null + +// subtype for organs, like ornithid tongues +/datum/song/organ + cares_about_distance = FALSE + +/datum/song/organ/updateDialog(mob/user) + var/obj/item/organ/owner = parent + var/mob/living/musician = owner?.owner + ui_interact(musician) + +/datum/song/organ/should_stop_playing(obj/player) + var/obj/item/organ/owner = parent + var/mob/living/musician = owner?.owner + return musician?.stat >= UNCONSCIOUS + +/datum/song/organ/do_hearcheck() + var/obj/item/organ/player = parent + last_hearcheck = world.time + var/list/old = hearing_mobs.Copy() + hearing_mobs.len = 0 + var/turf/source = get_turf(player.owner) + for(var/mob/M in get_hearers_in_view(instrument_range, player.owner)) + hearing_mobs[M] = get_dist(M, source) + var/list/exited = old - hearing_mobs + for(var/i in exited) + terminate_sound_mob(i) + +/datum/action/innate/singing + name = "Sing" + desc = "Mimic an instrument and sing." + check_flags = AB_CHECK_CONSCIOUS|AB_CHECK_IMMOBILE|AB_CHECK_INCAPACITATED + button_icon = 'icons/mob/actions/actions_items.dmi' + button_icon_state = "sing" + +/datum/action/innate/singing/Activate() + var/mob/living/carbon/human/human = owner + var/obj/item/organ/internal/tongue/ornithid/music_maker = human.get_organ_slot(ORGAN_SLOT_TONGUE) + if(!istype(music_maker)) + return + music_maker?.song.ui_interact(human) + + +/datum/component/particle_spewer/music_notes + icon_file = 'goon/icons/effects/particles.dmi' + particle_state = "beamed_eighth" + + unusual_description = "melody" + duration = 2.5 SECONDS + burst_amount = 2 + spawn_interval = 0.75 SECONDS + offsets = FALSE + +/datum/component/particle_spewer/music_notes/animate_particle(obj/effect/abstract/particle/spawned) + var/matrix/first = matrix() + + if(prob(30)) + spawned.icon_state = "eighth" + if(prob(25)) + spawned.icon_state = "quarter" + + spawned.pixel_x += rand(-24, 24) + spawned.pixel_y += rand(-6, 6) + first.Turn(rand(-90, 90)) + spawned.transform = first + + . = ..() + +/datum/component/particle_spewer/music_notes/adjust_animate_steps() + animate_holder.add_animation_step(list(transform = matrix(2, 2, MATRIX_SCALE), time = 0)) + animate_holder.set_transform_type(1, MATRIX_SCALE) + + animate_holder.add_animation_step(list(transform = "RANDOM", alpha = 220, time = 1)) + animate_holder.set_random_var(2, "transform", list(-90, 90)) + animate_holder.set_transform_type(2, MATRIX_ROTATE) + + animate_holder.add_animation_step(list(transform = matrix(), time = "RANDOM", pixel_y = 32, alpha = 1)) + animate_holder.set_parent_copy(3, "pixel_y") + animate_holder.set_random_var(3, "time", list(20, 30)) diff --git a/monkestation/code/modules/the_bird_inside_of_me/plummage.dm b/monkestation/code/modules/the_bird_inside_of_me/plummage.dm new file mode 100644 index 000000000000..6d06c789118d --- /dev/null +++ b/monkestation/code/modules/the_bird_inside_of_me/plummage.dm @@ -0,0 +1,46 @@ +// ear code here +/obj/item/organ/internal/ears/avian + name = "avian ears" + desc = "Senstive, much?" + // yes, this uses the default icon. Yellow TODO: make an organ sprite for this + damage_multiplier = 1.5 // felinids take 2x ear damage, ornithids have other things to worry about (pain increase) so they get 1.5x + +// end ear code. begin plumage code, because external organs are significantly fucking better to work in than internals when it comes to visuals + +/obj/item/organ/external/plumage + name = "Plumage" + desc = "Some feathers to ruffle. Seems the person who lost this definitely had theirs." + preference = "feature_avian_ears" + + icon = 'monkestation/code/modules/the_bird_inside_of_me/icons/ornithidfeatures.dmi' + + dna_block = DNA_AVIAN_EARS_BLOCK // putting this as a reminder to future c*ders, this used to be part of ears. + bodypart_overlay = /datum/bodypart_overlay/mutant/plumage + use_mob_sprite_as_obj_sprite = TRUE + slot = ORGAN_SLOT_EXTERNAL_FEATHERS + +/datum/bodypart_overlay/mutant/plumage + feature_key = "ears_avian" + layers = EXTERNAL_FRONT + color_source = ORGAN_COLOR_OVERRIDE + palette = /datum/color_palette/ornithids + palette_key = "plummage" + fallback_key = "feather_main" + +/datum/bodypart_overlay/mutant/plumage/get_global_feature_list() + return GLOB.avian_ears_list + +/datum/sprite_accessory/plumage + icon = 'monkestation/code/modules/the_bird_inside_of_me/icons/ornithidfeatures.dmi' + +/datum/sprite_accessory/plumage/hermes + name = "Hermes" + icon_state = "hermes" + +/datum/sprite_accessory/plumage/arched + name = "Arched" + icon_state = "arched" + +/* /datum/sprite_accessory/plumage/kresnik // similar to tails (originally!), this is commented out for the time being. + name = "Kresnik" + icon_state = "kresnik" */ diff --git a/monkestation/code/modules/the_bird_inside_of_me/prefs.dm b/monkestation/code/modules/the_bird_inside_of_me/prefs.dm new file mode 100644 index 000000000000..2eddde9bcc75 --- /dev/null +++ b/monkestation/code/modules/the_bird_inside_of_me/prefs.dm @@ -0,0 +1,166 @@ +/** + * Generates a basic body icon for a humanoid when given a list of bodyparts + * + * Arguments + * * bodypart_list - list of bodyparts to put on the body. + * The first bodypart in the list becomes the base of the icon, which in most cases doesn't matter, but may for layering. + * * skintone - (optional) skintone of the body. + * Not a hex color, but corresponds to human skintones. + * * dir - (optional) direction of all the icons + */ +/proc/get_basic_body_icon(list/bodypart_list, skintone = "caucasian1", icon_dir = NORTH) + var/icon/base_icon + for(var/obj/item/bodypart/other_bodypart as anything in bodypart_list) + var/icon/generated_icon = icon( + icon = UNLINT(initial(other_bodypart.icon_greyscale)), + icon_state = UNLINT("[initial(other_bodypart.limb_id)]_[initial(other_bodypart.body_zone)][initial(other_bodypart.is_dimorphic) ? "_m" : ""]"), + dir = icon_dir, + ) + generated_icon.Blend(skintone2hex(skintone), ICON_MULTIPLY) + if(isnull(base_icon)) + base_icon = generated_icon + else + base_icon.Blend(generated_icon, ICON_OVERLAY) + + return base_icon + +/proc/generate_ornithid_side_shots(list/sprite_accessories, key, list/sides) + var/list/values = list() + + var/icon/ornithid = icon('icons/mob/species/human/human_face.dmi', "head", EAST) + var/icon/eyes = icon('icons/mob/species/human/human_face.dmi', "eyes", EAST) + eyes.Blend(COLOR_RED, ICON_MULTIPLY) + + ornithid.Blend(eyes, ICON_OVERLAY) + + for (var/name in sprite_accessories) + + var/icon/final_icon = icon(ornithid) + + + final_icon.Crop(11, 20, 23, 32) + final_icon.Scale(32, 32) + final_icon.Blend(COLOR_BLUE_GRAY, ICON_MULTIPLY) + + values[name] = final_icon + + return values + +/datum/preference/choiced/ornithid_wings + main_feature_name = "Arm Wings" + savefile_key = "feature_arm_wings" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_FEATURES + relevant_external_organ = /obj/item/organ/external/wings/functional/arm_wings + should_generate_icons = TRUE + +/datum/preference/choiced/ornithid_wings/init_possible_values() + return assoc_to_keys_features(GLOB.arm_wings_list) + +/datum/preference/choiced/ornithid_wings/init_possible_values() + return possible_values_for_sprite_accessory_list_for_body_part( + GLOB.arm_wings_list, + "arm_wings", + list("FRONT"), + ) + +/datum/preference/choiced/ornithid_wings/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["arm_wings"] = value + +/datum/preference/choiced/ornithid_wings/compile_constant_data() + var/list/data = ..() + data[SUPPLEMENTAL_FEATURE_KEY] = list("feather_color", "feather_color_secondary", "feather_color_tri") + return data + +/datum/preference/color/feather_color + savefile_key = "feather_color" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES + relevant_inherent_trait = TRAIT_FEATHERED + +/datum/preference/color/feather_color_secondary + savefile_key = "feather_color_secondary" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES + relevant_inherent_trait = TRAIT_FEATHERED + allows_nulls = TRUE + default_null = TRUE + +/datum/preference/color/feather_color_tri + savefile_key = "feather_color_tri" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES + relevant_inherent_trait = TRAIT_FEATHERED + allows_nulls = TRUE + default_null = TRUE + +/datum/preference/color/plummage_color + savefile_key = "plummage_color" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES + relevant_inherent_trait = TRAIT_FEATHERED + allows_nulls = TRUE + default_null = TRUE + +/datum/preference/color/feather_tail_color + savefile_key = "feather_tail_color" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_SUPPLEMENTAL_FEATURES + relevant_inherent_trait = TRAIT_FEATHERED + allows_nulls = TRUE + default_null = TRUE + +#define X_TAIL_CROP 16 +#define Y_TAIL_CROP 5 + +/datum/preference/choiced/tail_avian + main_feature_name = "Avian Tail" + savefile_key = "feature_avian_tail" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_FEATURES + can_randomize = FALSE + relevant_external_organ = /obj/item/organ/external/tail/avian + should_generate_icons = TRUE + +/datum/preference/choiced/tail_avian/compile_constant_data() + var/list/data = ..() + data[SUPPLEMENTAL_FEATURE_KEY] = "feather_color_secondary" + return data + +/datum/preference/choiced/tail_avian/init_possible_values() + return possible_values_for_sprite_accessory_list_for_body_part( + GLOB.tails_list_avian, + "tail_avian", + list("FRONT", "BEHIND"), + ) + +/datum/preference/choiced/tail_avian/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["tail_avian"] = value + +/datum/preference/choiced/tail_avian/create_default_value() + return /datum/sprite_accessory/tails/avian::name + +#undef X_TAIL_CROP +#undef Y_TAIL_CROP + +/datum/preference/choiced/plumage + main_feature_name = "Plumage" + savefile_key = "feature_avian_ears" + savefile_identifier = PREFERENCE_CHARACTER + category = PREFERENCE_CATEGORY_FEATURES + can_randomize = FALSE + relevant_external_organ = /obj/item/organ/external/plumage + should_generate_icons = TRUE + +/datum/preference/choiced/plumage/init_possible_values() + return possible_values_for_sprite_accessory_list_for_body_part( + GLOB.avian_ears_list, + "ears_avian", + list("FRONT"), + ) + +/datum/preference/choiced/plumage/apply_to_human(mob/living/carbon/human/target, value) + target.dna.features["ears_avian"] = value + +/datum/preference/choiced/plumage/create_default_value() + return /datum/sprite_accessory/plumage::name diff --git a/monkestation/code/modules/the_bird_inside_of_me/species.dm b/monkestation/code/modules/the_bird_inside_of_me/species.dm new file mode 100644 index 000000000000..7d790cfba68a --- /dev/null +++ b/monkestation/code/modules/the_bird_inside_of_me/species.dm @@ -0,0 +1,168 @@ +/// GLOB list of armwings sprites / options +GLOBAL_LIST_EMPTY(arm_wings_list) +GLOBAL_LIST_EMPTY(arm_wingsopen_list) +/// GLOB list of other features (ears, tails) +GLOBAL_LIST_EMPTY(avian_ears_list) +GLOBAL_LIST_EMPTY(tails_list_avian) + +/datum/species/ornithid + // the biggest bird + name = "\improper Ornithid" + plural_form = "Ornithids" + id = SPECIES_ORNITHID + + inherent_traits = list( + TRAIT_NO_UNDERWEAR, + TRAIT_FEATHERED, + TRAIT_USES_SKINTONES, + ) + mutanttongue = /obj/item/organ/internal/tongue/ornithid + external_organs = list( + /obj/item/organ/external/wings/functional/arm_wings = "Monochrome", + /obj/item/organ/external/plumage = "Hermes", + /obj/item/organ/external/tail/avian = "Eagle", + ) + bodypart_overrides = list( + BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/ornithid, + BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/ornithid, + BODY_ZONE_HEAD = /obj/item/bodypart/head, // just because they are still *partially* human, or otherwise human resembling + BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/ornithid, + BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/ornithid, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/ornithid, + ) + species_pain_mod = 1.20 // Fuck it, this will fill a niche that isn't implemented yet. + changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_PRIDE | MIRROR_MAGIC | RACE_SWAP | ERT_SPAWN | SLIME_EXTRACT + digitigrade_customization = DIGITIGRADE_FORCED + + species_cookie = /obj/item/food/semki/healthy // humans get chocolate, lizards get meat. What do birds get? Seed. + meat = /obj/item/food/meat/slab/chicken + skinned_type = /obj/item/stack/sheet/animalhide/human + mutantliver = /obj/item/organ/internal/liver/ornithid + + inert_mutation = /datum/mutation/human/dwarfism + species_language_holder = /datum/language_holder/yangyu // doing this because yangyu is really just, mostly unused otherwise. + color_palette = /datum/color_palette/ornithids + +/datum/species/ornithid/prepare_human_for_preview(mob/living/carbon/human/human) + human.skin_tone = "asian1" + human.hairstyle = "Half-banged Hair" + human.set_haircolor(COLOR_BROWNER_BROWN) + human.update_body(TRUE) + +// defines limbs/bodyparts. + +/obj/item/bodypart/arm/left/ornithid + limb_id = SPECIES_ORNITHID + icon_greyscale = 'monkestation/code/modules/the_bird_inside_of_me/icons/ornithid_parts_greyscale.dmi' + unarmed_attack_verb = "slash" + unarmed_attack_effect = ATTACK_EFFECT_CLAW + unarmed_attack_sound = 'sound/weapons/slice.ogg' + unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' + + +/obj/item/bodypart/arm/right/ornithid + limb_id = SPECIES_ORNITHID + icon_greyscale = 'monkestation/code/modules/the_bird_inside_of_me/icons/ornithid_parts_greyscale.dmi' + unarmed_attack_verb = "slash" + unarmed_attack_effect = ATTACK_EFFECT_CLAW + unarmed_attack_sound = 'sound/weapons/slice.ogg' + unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' + +/obj/item/bodypart/chest/ornithid + acceptable_bodytype = BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE + +/obj/item/bodypart/leg/left/ornithid + limb_id = SPECIES_ORNITHID + digitigrade_id = SPECIES_ORNITHID + icon_greyscale = 'monkestation/code/modules/the_bird_inside_of_me/icons/ornithid_parts_greyscale.dmi' + bodytype = BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE + bodypart_traits = list(TRAIT_HARD_SOLES, TRAIT_NON_IMPORTANT_SHOE_BLOCK) + step_sounds = list( + 'sound/effects/footstep/hardclaw1.ogg', + 'sound/effects/footstep/hardclaw2.ogg', + 'sound/effects/footstep/hardclaw3.ogg', + 'sound/effects/footstep/hardclaw4.ogg', + 'sound/effects/footstep/hardclaw1.ogg', + ) + +/obj/item/bodypart/leg/right/ornithid + limb_id = SPECIES_ORNITHID + digitigrade_id = SPECIES_ORNITHID + icon_greyscale = 'monkestation/code/modules/the_bird_inside_of_me/icons/ornithid_parts_greyscale.dmi' + bodytype = BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE + bodypart_traits = list(TRAIT_HARD_SOLES, TRAIT_NON_IMPORTANT_SHOE_BLOCK) + step_sounds = list( + 'sound/effects/footstep/hardclaw1.ogg', + 'sound/effects/footstep/hardclaw2.ogg', + 'sound/effects/footstep/hardclaw3.ogg', + 'sound/effects/footstep/hardclaw4.ogg', + 'sound/effects/footstep/hardclaw1.ogg', + ) + +// section for lore/perk descs +/datum/species/ornithid/get_species_lore() + return list( + "Much to the chagrin of the collective, the term \"Ornithid\" is in effect, a dumping ground of the various human-derived avian animalids, making it the second most populous animalid group. \ + Several cultural and geneological groups can fall under this banner, with sometimes only those directly related to eachother baring any resemblance physically.", + + "while countless other groups exist, the three most common ornithid groups known to Nanotrasen are the conniving Izulukin, The wandering Vagrants, and The traditionalist Tengu.", + + "the Izulukin are an infamous bunch, being heavily overrepresented in privateer populations, always hungering for blood and gold. \ + above all else, however, the Izulukin are obsessed with \"Genetic Perfection\", always finding ways to eliminate maladaptive or \"non-beneficial\" genes. \ + this behavior is prevalent in their culture, with many izulukin activating latent genes to given themselves \"Super Powers\" so as to earn an edge in combat, and in culture.", + + "of all the Izulukin's activities, they are most known for their contracts with witches, warlocks, and other dark-mages, binding a living member to a mage, \ + until the bound member perishes, passing on to a chosen descendant should the contract owner perish themself. \ + In addition, another activity they are infamous for is their almost vampiric obsession with the blood of biological organisms, \ + harvesting it to be used in the production of various synthetic proteins, which form the core of their diet.", + + "The third most populous groups are the simply named Vagrants, a typical group of wanderers who have no true home accross the stars, \ + often working as traders, bounty hunters, and other nomadic professions. They are well known for a very effecient style of living, \ + mixing efficient equipment and armor with casual wear, leaving little scraps left to waste.", + + "The most populous of the three groups, the culture of the Tengu bares a striking resemblance to Edo Period Japan on earth, with their primary language, \ + Yangyu, appearing to be based upon Japanese. They have a rigid, class-based society, with one's cultural importance and percieved morality holding more importance than wealth; \ + which unsurprisingly, ends up funneled to the top regardless.", + + "While there are many \"Born\" Tengu, many are cultural immigrants from various portions of the galaxy, most notably those who have fled or been exiled from the Izulukin." + + ) + +/datum/species/ornithid/get_species_description() + return list( + "Ornithids are a collective group of various human descendant, or otherwise resembling, sentient avian beings.", + "Their most well known physical trait are their reduced weight, and feathery \"wings\" protuding from their arms, which they can use to fly.", + "There are countless various types and groups of Ornithids, with a variety of backgrounds both known and unknown by NT. " + ) + +/datum/species/ornithid/create_pref_unique_perks() + var/list/to_add = list() + + to_add += list( + list( + SPECIES_PERK_TYPE = SPECIES_POSITIVE_PERK, + SPECIES_PERK_ICON = "dove", + SPECIES_PERK_NAME = "Airborne", + SPECIES_PERK_DESC = "Is it a bird? is it a plane? Of course its a bird you dumbass, \ + Ornithids are lightweight winged avians, and can, as a result, fly.", + ), + list( + SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, + SPECIES_PERK_ICON = "feather", + SPECIES_PERK_NAME = "Lightweights", + SPECIES_PERK_DESC = "As a result of their reduced average weight, \ + Ornithids have a lower alcohol tolerance. Pansies.", + ), + list( + SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, + SPECIES_PERK_ICON = "note-medical", + SPECIES_PERK_NAME = "Hyper-Sensitive Nerves", + SPECIES_PERK_DESC = "Ornithids have incredibly sensistive nerves compared to their human counterparts, \ + Taking 1.2x pain, 1.5x damage to their ears, and get stunned for 2x longer when flying.", // the 2x stun length only applies when flying, and is inherited from functional wings. + ), + ) + return to_add + +/obj/item/organ/internal/liver/ornithid + name = "bird liver" + organ_traits = list(TRAIT_LIGHT_DRINKER) diff --git a/monkestation/code/modules/the_bird_inside_of_me/tails.dm b/monkestation/code/modules/the_bird_inside_of_me/tails.dm new file mode 100644 index 000000000000..db38d91cbd21 --- /dev/null +++ b/monkestation/code/modules/the_bird_inside_of_me/tails.dm @@ -0,0 +1,34 @@ + + +/obj/item/organ/external/tail/avian + name = "avian tail" + desc = "This tail belongs to an ornithid. Used to." + preference = "feature_avian_tail" + dna_block = DNA_AVIAN_TAIL_BLOCK + bodypart_overlay = /datum/bodypart_overlay/mutant/tail/avian + // I will NOT be adding wagging. for a variety of reasons, chief of which being I am NOT animating all of the sprites + // and because with how bird tails work, this would basically just be twerking. Fuck you. + +/datum/bodypart_overlay/mutant/tail/avian + feature_key = "tail_avian" + layers = EXTERNAL_BEHIND | EXTERNAL_FRONT + color_source = ORGAN_COLOR_OVERRIDE + palette = /datum/color_palette/ornithids + palette_key = "tail" + fallback_key = "feather_main" + +/datum/bodypart_overlay/mutant/tail/avian/get_global_feature_list() + return GLOB.tails_list_avian + +/datum/sprite_accessory/tails/avian + icon = 'monkestation/code/modules/the_bird_inside_of_me/icons/ornithidfeatures.dmi' + +/datum/sprite_accessory/tails/avian/eagle + name = "Eagle" + icon_state = "eagle" + +/datum/sprite_accessory/tails/avian/swallow + name = "Swallow" + icon_state = "swallow" + +// continue additional tails from here diff --git a/monkestation/code/modules/the_bird_inside_of_me/wings.dm b/monkestation/code/modules/the_bird_inside_of_me/wings.dm new file mode 100644 index 000000000000..4bdd33e48b9c --- /dev/null +++ b/monkestation/code/modules/the_bird_inside_of_me/wings.dm @@ -0,0 +1,102 @@ +// begin armwings code +/obj/item/organ/external/wings/functional/arm_wings + name = "Arm Wings" + desc = "They're wings, that go on your arm. Get your chicken wings jokes out now." + dna_block = DNA_ARM_WINGS_BLOCK + bodypart_overlay = /datum/bodypart_overlay/mutant/wings/functional/arm_wings + preference = "feature_arm_wings" + organ_traits = list(TRAIT_TACKLING_WINGED_ATTACKER) + //Yes, because this is a direct sub-type of functional wings, this means its stored on body, and yes, this means if one or both of the arms are dismembered, there will be floating feathers/wings. + //However, there is no "both arms" storage, and having one for each arm is sort of inefficient. Leaving very few methods that could fix this, most of which are harder than what I can do or necessitate a refactor of code. Too Bad! + +/obj/item/organ/external/wings/functional/arm_wings/can_fly(mob/living/carbon/human/human) + if(HAS_TRAIT(human, TRAIT_RESTRAINED)) + to_chat(human, span_warning("You are restrained! You cannot fly!")) + return FALSE + if(human.usable_hands < 2) + to_chat(human, span_warning("You need both of your hands to fly!")) + return FALSE + return ..() + +/datum/movespeed_modifier/arm_wing_flight + multiplicative_slowdown = -0.2 + movetypes = FLOATING|FLYING + +/obj/item/organ/external/wings/functional/arm_wings/toggle_flight(mob/living/carbon/human/human) + if(!HAS_TRAIT_FROM(human, TRAIT_MOVE_FLYING, SPECIES_FLIGHT_TRAIT)) + ADD_TRAIT(human, TRAIT_HANDS_BLOCKED, REF(src)) + human.add_movespeed_modifier(/datum/movespeed_modifier/arm_wing_flight) + else + REMOVE_TRAIT(human, TRAIT_HANDS_BLOCKED, REF(src)) + human.remove_movespeed_modifier(/datum/movespeed_modifier/arm_wing_flight) + return ..() + +/datum/sprite_accessory/arm_wings + icon = 'monkestation/code/modules/the_bird_inside_of_me/icons/armwings.dmi' + + +/datum/sprite_accessory/arm_wingsopen + icon = 'monkestation/code/modules/the_bird_inside_of_me/icons/armwings.dmi' + +/datum/sprite_accessory/arm_wings/monochrome + name = "Monochrome" + icon_state = "monochrome" + +/datum/sprite_accessory/arm_wings/monochrome_short + name = "Short Monochrome" + icon_state = "monochrome_short" + +/datum/sprite_accessory/arm_wings/fluffy + name = "Fluffy" + icon_state = "fluffy" + +/datum/sprite_accessory/arm_wings/tri_colored + name = "Tri-Colored Wings" + icon_state = "triple" + //layers = list("first" = "feather_main", "second" = "feather_secondary", "third" = "feather_tri") + +/datum/sprite_accessory/arm_wings/pursuant + name = "Pursuant" + icon_state = "pursuant" + +/datum/sprite_accessory/arm_wingsopen/monochrome + name = "Monochrome" + icon_state = "monochrome" + +/datum/sprite_accessory/arm_wingsopen/monochrome_short + name = "Short Monochrome" + icon_state = "monochrome_short" + +/datum/sprite_accessory/arm_wingsopen/pursuant + name = "Pursuant" + icon_state = "pursuant" + +/datum/sprite_accessory/arm_wingsopen/fluffy + name = "Fluffy" + icon_state = "fluffy" + +/datum/sprite_accessory/arm_wingsopen/tri_colored + name = "Tri-Colored Wings" + icon_state = "triple" + layers = list("first" = "feather_main", "second" = "feather_secondary", "third" = "feather_tri") + +/datum/bodypart_overlay/mutant/wings/functional/arm_wings + feature_key = "arm_wings" + layers = EXTERNAL_BEHIND | EXTERNAL_ADJACENT | EXTERNAL_FRONT + color_source = ORGAN_COLOR_OVERRIDE + + ///Feature render key for opened arm wings + open_feature_key = "arm_wingsopen" + palette = /datum/color_palette/ornithids + palette_key = "feather_main" + +/datum/bodypart_overlay/mutant/wings/functional/arm_wings/get_global_feature_list() + if(wings_open) + return GLOB.arm_wingsopen_list + else + return GLOB.arm_wings_list + +/datum/bodypart_overlay/mutant/wings/functional/arm_wings/can_draw_on_bodypart(mob/living/carbon/human/human) + if(!(human.wear_suit?.flags_inv & HIDEMUTWINGS)) + return TRUE + return FALSE diff --git a/monkestation/code/modules/the_fabled_dna_changes/dna.dm b/monkestation/code/modules/the_fabled_dna_changes/dna.dm new file mode 100644 index 000000000000..6dd56105bd8b --- /dev/null +++ b/monkestation/code/modules/the_fabled_dna_changes/dna.dm @@ -0,0 +1,43 @@ +/datum/dna + ///this is our list of color palettes we care about + ///this is typically just for species + var/list/color_palettes + +/datum/dna/New(mob/living/new_holder) + . = ..() + for(var/datum/species/listed_species as anything in typesof(/datum/species)) + if(!initial(listed_species.color_palette)) + continue + var/datum/species/created = new listed_species + color_palettes = list() + color_palettes += created.color_palette + var/datum/color_palette/new_palette = new created.color_palette + if(holder?.client?.prefs) + new_palette.apply_prefs(holder.client.prefs) + color_palettes[created.color_palette] = new_palette + + var/static/list/generic_colors = list(/datum/color_palette/generic_colors) + for(var/datum/color_palette/palette as anything in generic_colors) + color_palettes += palette + var/datum/color_palette/new_palette = new palette + if(holder?.client?.prefs) + new_palette.apply_prefs(holder.client.prefs) + color_palettes[palette] = new_palette + +/datum/dna/proc/apply_color_palettes(datum/preferences/applied) + for(var/datum/species/listed_species as anything in typesof(/datum/species)) + if(!initial(listed_species.color_palette)) + continue + var/datum/species/created = new listed_species + color_palettes = list() + color_palettes += created.color_palette + var/datum/color_palette/new_palette = new created.color_palette + new_palette.apply_prefs(applied) + color_palettes[created.color_palette] = new_palette + + var/static/list/generic_colors = list(/datum/color_palette/generic_colors) + for(var/datum/color_palette/palette as anything in generic_colors) + color_palettes += palette + var/datum/color_palette/new_palette = new palette + new_palette.apply_prefs(applied) + color_palettes[palette] = new_palette diff --git a/monkestation/code/modules/the_fabled_dna_changes/multi_colored_bodyoverlay.dm b/monkestation/code/modules/the_fabled_dna_changes/multi_colored_bodyoverlay.dm new file mode 100644 index 000000000000..e7f0f4ad838d --- /dev/null +++ b/monkestation/code/modules/the_fabled_dna_changes/multi_colored_bodyoverlay.dm @@ -0,0 +1,43 @@ +/datum/bodypart_overlay/mutant/get_overlay(layer, obj/item/bodypart/limb) + inherit_color(limb) + layer = bitflag_to_layer(layer) + if(sprite_datum.layers) + var/mutable_appearance/MA = mutable_appearance(layer = layer) + for(var/state in sprite_datum.layers) + var/mutable_appearance/returned = get_image(layer, limb, state) + color_image(returned, layer, limb, sprite_datum.layers[state]) + MA.overlays += returned + return MA + else + . = get_image(layer, limb) + color_image(., layer, limb) + +///Get the image we need to draw on the person. Called from get_overlay() which is called from _bodyparts.dm. Limb can be null +/datum/bodypart_overlay/mutant/get_image(image_layer, obj/item/bodypart/limb, layer_name) + if(!sprite_datum) + CRASH("Trying to call get_image() on [type] while it didn't have a sprite_datum. This shouldn't happen, report it as soon as possible.") + + var/gender = (limb?.limb_gender == FEMALE) ? "f" : "m" + var/list/icon_state_builder = list() + icon_state_builder += sprite_datum.gender_specific ? gender : "m" //Male is default because sprite accessories are so ancient they predate the concept of not hardcoding gender + if(layer_name) + icon_state_builder += layer_name + icon_state_builder += feature_key + icon_state_builder += get_base_icon_state() + icon_state_builder += mutant_bodyparts_layertext(image_layer) + + var/finished_icon_state = icon_state_builder.Join("_") + + var/mutable_appearance/appearance = mutable_appearance(sprite_datum.icon, finished_icon_state, layer = image_layer) + + if(sprite_datum.center) + center_image(appearance, sprite_datum.dimension_x, sprite_datum.dimension_y) + + return appearance + +/datum/bodypart_overlay/mutant/color_image(image/overlay, layer, obj/item/bodypart/limb, key_name) + if(!key_name) + overlay.color = sprite_datum.color_src ? draw_color : null + else + var/datum/color_palette/located = limb?.owner?.dna?.color_palettes[palette] + overlay.color = located.return_color(key_name, fallback_key) diff --git a/monkestation/code/modules/the_fabled_dna_changes/species_color_pallettes/_color_pallette.dm b/monkestation/code/modules/the_fabled_dna_changes/species_color_pallettes/_color_pallette.dm new file mode 100644 index 000000000000..cf83f9a104b1 --- /dev/null +++ b/monkestation/code/modules/the_fabled_dna_changes/species_color_pallettes/_color_pallette.dm @@ -0,0 +1,25 @@ +/datum/color_palette + var/default_color = "#FFFFFF" + +///override this if you need to check if the color can be applied +/datum/color_palette/proc/is_viable_color(color) + return TRUE + +///this is where we apply colors to our palette from our prefs +/datum/color_palette/proc/apply_prefs(datum/preferences/incoming) + CRASH("Please Override apply_prefs on your color palette") + +///this takes 2 inputs varname and mainvar. mainvar is optional but if varname is null trys to return maincolor +/datum/color_palette/proc/return_color(varname, mainvar) + if(!varname && !mainvar) + return default_color + + var/retrieved_var = vars[varname] + if(!retrieved_var) + if(mainvar) + retrieved_var = vars[mainvar] + if(retrieved_var) + return retrieved_var + return default_color + + return retrieved_var diff --git a/monkestation/code/modules/the_fabled_dna_changes/species_color_pallettes/generic_palette.dm b/monkestation/code/modules/the_fabled_dna_changes/species_color_pallettes/generic_palette.dm new file mode 100644 index 000000000000..eb948ad9fbc4 --- /dev/null +++ b/monkestation/code/modules/the_fabled_dna_changes/species_color_pallettes/generic_palette.dm @@ -0,0 +1,13 @@ +/datum/color_palette/generic_colors + var/hair_color + var/mutant_color + var/mutant_color_secondary + var/fur_color + var/ethereal_color + +/datum/color_palette/generic_colors/apply_prefs(datum/preferences/incoming) + hair_color = incoming.read_preference(/datum/preference/color/hair_color) + mutant_color = incoming.read_preference(/datum/preference/color/mutant_color) + mutant_color_secondary = incoming.read_preference(/datum/preference/color/mutant_color_secondary) + fur_color = incoming.read_preference(/datum/preference/color/fur_color) + ethereal_color = GLOB.color_list_ethereal[incoming.read_preference(/datum/preference/choiced/ethereal_color)] diff --git a/monkestation/code/modules/the_fabled_dna_changes/species_color_pallettes/ornithids.dm b/monkestation/code/modules/the_fabled_dna_changes/species_color_pallettes/ornithids.dm new file mode 100644 index 000000000000..9e7d108562d2 --- /dev/null +++ b/monkestation/code/modules/the_fabled_dna_changes/species_color_pallettes/ornithids.dm @@ -0,0 +1,17 @@ +/datum/color_palette/ornithids + default_color = COLOR_AMETHYST + + var/feather_main + var/feather_secondary + var/feather_tri + + var/tail + var/plummage + +/datum/color_palette/ornithids/apply_prefs(datum/preferences/incoming) + feather_main = incoming.read_preference(/datum/preference/color/feather_color) + feather_secondary = incoming.read_preference(/datum/preference/color/feather_color_secondary) + feather_tri = incoming.read_preference(/datum/preference/color/feather_color_tri) + plummage = incoming.read_preference(/datum/preference/color/plummage_color) + tail = incoming.read_preference(/datum/preference/color/feather_tail_color) + diff --git a/monkestation/code/modules/the_wolf_inside_of_me/bodyparts.dm b/monkestation/code/modules/the_wolf_inside_of_me/bodyparts.dm new file mode 100644 index 000000000000..e5d63be56107 --- /dev/null +++ b/monkestation/code/modules/the_wolf_inside_of_me/bodyparts.dm @@ -0,0 +1,130 @@ +///WEREWOLF +/obj/item/bodypart/head/werewolf + limb_id = SPECIES_WEREWOLF + icon_greyscale = 'monkestation/code/modules/the_wolf_inside_of_me/icons/werewolf_parts_greyscale.dmi' + is_dimorphic = FALSE + should_draw_greyscale = TRUE + +/obj/item/bodypart/head/werewolf/update_limb(dropping_limb, is_creating) + . = ..() + var/mob/living/carbon/human/wolf = owner + species_color = wolf.hair_color + draw_color = species_color + burn_modifier = 0.75 + brute_modifier = 0.25 + unarmed_attack_verb = "bite" + //grappled_attack_verb = "maul" + unarmed_attack_effect = ATTACK_EFFECT_BITE + unarmed_attack_sound = 'sound/weapons/bite.ogg' + unarmed_miss_sound = 'sound/weapons/bite.ogg' + unarmed_damage_low = 60 + unarmed_damage_high = 75 + //unarmed_effectiveness = 50 + dmg_overlay_type = null + biological_state = (BIO_FLESH|BIO_BLOODED) + head_flags = HEAD_EYESPRITES|HEAD_EYECOLOR|HEAD_EYEHOLES|HEAD_DEBRAIN|HEAD_HAIR + +/obj/item/bodypart/chest/werewolf + limb_id = SPECIES_WEREWOLF + icon_greyscale = 'monkestation/code/modules/the_wolf_inside_of_me/icons/werewolf_parts_greyscale.dmi' + is_dimorphic = TRUE + should_draw_greyscale = TRUE + +/obj/item/bodypart/chest/werewolf/update_limb(dropping_limb, is_creating) + . = ..() + var/mob/living/carbon/human/wolf = owner + species_color = wolf.hair_color + draw_color = species_color + burn_modifier = 0.75 + brute_modifier = 0.25 + dmg_overlay_type = null + biological_state = (BIO_FLESH|BIO_BLOODED) + bodypart_traits = list(TRAIT_NO_JUMPSUIT, TRAIT_IGNOREDAMAGESLOWDOWN, TRAIT_PUSHIMMUNE, TRAIT_STUNIMMUNE) + wing_types = null + acceptable_bodytype = BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE + +/obj/item/bodypart/arm/left/werewolf + limb_id = SPECIES_WEREWOLF + icon_greyscale = 'monkestation/code/modules/the_wolf_inside_of_me/icons/werewolf_parts_greyscale.dmi' + should_draw_greyscale = TRUE + +/obj/item/bodypart/arm/left/werewolf/update_limb(dropping_limb, is_creating) + . = ..() + var/mob/living/carbon/human/wolf = owner + species_color = wolf.hair_color + draw_color = species_color + unarmed_attack_verb = "slash" + //grappled_attack_verb = "lacerate" + unarmed_attack_effect = ATTACK_EFFECT_CLAW + unarmed_attack_sound = 'sound/weapons/slice.ogg' + unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' + unarmed_damage_low = 20 + unarmed_damage_high = 25 + //unarmed_effectiveness = 20 + burn_modifier = 0.75 + brute_modifier = 0.25 + dmg_overlay_type = null + hand_traits = list(TRAIT_CHUNKYFINGERS) + biological_state = (BIO_FLESH|BIO_BLOODED) + +/obj/item/bodypart/arm/right/werewolf + limb_id = SPECIES_WEREWOLF + icon_greyscale = 'monkestation/code/modules/the_wolf_inside_of_me/icons/werewolf_parts_greyscale.dmi' + should_draw_greyscale = TRUE + +/obj/item/bodypart/arm/right/werewolf/update_limb(dropping_limb, is_creating) + . = ..() + var/mob/living/carbon/human/wolf = owner + species_color = wolf.hair_color + draw_color = species_color + unarmed_attack_verb = "slash" + //grappled_attack_verb = "lacerate" + unarmed_attack_effect = ATTACK_EFFECT_CLAW + unarmed_attack_sound = 'sound/weapons/slice.ogg' + unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' + unarmed_damage_low = 20 + unarmed_damage_high = 25 + //unarmed_effectiveness = 20 + burn_modifier = 0.75 + brute_modifier = 0.25 + dmg_overlay_type = null + hand_traits = list(TRAIT_CHUNKYFINGERS) + biological_state = (BIO_FLESH|BIO_BLOODED) + +/obj/item/bodypart/leg/left/werewolf + limb_id = SPECIES_WEREWOLF + digitigrade_id = SPECIES_WEREWOLF + icon_greyscale = 'monkestation/code/modules/the_wolf_inside_of_me/icons/werewolf_parts_greyscale.dmi' + should_draw_greyscale = TRUE + bodytype = BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE + burn_modifier = 0.75 + brute_modifier = 0.25 + speed_modifier = 3 + dmg_overlay_type = null + //footstep_type = FOOTSTEP_MOB_CLAW + biological_state = (BIO_FLESH|BIO_BLOODED) + +/obj/item/bodypart/leg/left/werewolf/update_limb(dropping_limb, is_creating) + . = ..() + var/mob/living/carbon/human/wolf = owner + species_color = wolf.hair_color + draw_color = species_color + +/obj/item/bodypart/leg/right/werewolf + limb_id = SPECIES_WEREWOLF + digitigrade_id = SPECIES_WEREWOLF + icon_greyscale = 'monkestation/code/modules/the_wolf_inside_of_me/icons/werewolf_parts_greyscale.dmi' + should_draw_greyscale = TRUE + bodytype = BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE + burn_modifier = 0.75 + brute_modifier = 0.25 + speed_modifier = 3 + dmg_overlay_type = null + //footstep_type = FOOTSTEP_MOB_CLAW + biological_state = (BIO_FLESH|BIO_BLOODED) + +/obj/item/bodypart/leg/right/werewolf/update_limb(dropping_limb, is_creating) + . = ..() + var/mob/living/carbon/human/wolf = owner + species_color = wolf.hair_color + draw_color = species_color diff --git a/monkestation/code/modules/the_wolf_inside_of_me/icons/mutant_bodyparts.dmi b/monkestation/code/modules/the_wolf_inside_of_me/icons/mutant_bodyparts.dmi new file mode 100644 index 000000000000..8b9d547aa121 Binary files /dev/null and b/monkestation/code/modules/the_wolf_inside_of_me/icons/mutant_bodyparts.dmi differ diff --git a/monkestation/code/modules/the_wolf_inside_of_me/icons/werewolf_parts_greyscale.dmi b/monkestation/code/modules/the_wolf_inside_of_me/icons/werewolf_parts_greyscale.dmi new file mode 100644 index 000000000000..677d2081622e Binary files /dev/null and b/monkestation/code/modules/the_wolf_inside_of_me/icons/werewolf_parts_greyscale.dmi differ diff --git a/monkestation/code/modules/the_wolf_inside_of_me/organs.dm b/monkestation/code/modules/the_wolf_inside_of_me/organs.dm new file mode 100644 index 000000000000..7a844a52e742 --- /dev/null +++ b/monkestation/code/modules/the_wolf_inside_of_me/organs.dm @@ -0,0 +1,85 @@ +/obj/item/organ/internal/ears/werewolf + name = "wolf ears" + icon = 'icons/obj/clothing/head/costume.dmi' + icon_state = "kitty" + desc = "Allows the user to more easily hear whispers. The user becomes extra vulnerable to loud noises, however" + // Same sensitivity as felinid ears + damage_multiplier = 2 + +/* +/obj/item/organ/internal/ears/werewolf/Insert(mob/living/carbon/receiver, special, drop_if_replaced) + . = ..() + organ_traits = list(TRAIT_GOOD_HEARING) +*/ + +/obj/item/organ/internal/eyes/werewolf + name = "wolf eyes" + desc = "Large and powerful eyes." + sight_flags = SEE_MOBS + color_cutoffs = list(25, 5, 42) + +/obj/item/organ/internal/heart/werewolf + name = "massive heart" + desc = "An absolutely monstrous heart." + icon_state = "heart-on" + base_icon_state = "heart" + maxHealth = 2 * STANDARD_ORGAN_THRESHOLD +/obj/item/organ/internal/heart/wolf/Initialize(mapload) + . = ..() + transform = transform.Scale(1.5) + +/obj/item/organ/internal/liver/werewolf + + name = "Beastly liver" + desc = "A large monstrous liver." + icon_state = "liver" + ///Var for brute healing via blood + var/blood_brute_healing = 2.5 + ///Var for burn healing via blood + var/blood_burn_healing = 2.5 + + +/obj/item/organ/internal/liver/werewolf/handle_chemical(mob/living/carbon/organ_owner, datum/reagent/chem, seconds_per_tick, times_fired) + . = ..() + //parent returned COMSIG_MOB_STOP_REAGENT_CHECK or we are failing + if((. & COMSIG_MOB_STOP_REAGENT_CHECK) || (organ_flags & ORGAN_FAILING)) + return + if(istype(chem, /datum/reagent/silver)) + organ_owner.stamina?.adjust(7.5 * REM * seconds_per_tick) + organ_owner.adjustFireLoss(5.0 * REM * seconds_per_tick, updating_health = TRUE) + + +/obj/item/organ/internal/tongue/werewolf + name = "wolf tongue" + desc = "A large tongue that looks like a mix of a human's and a wolf's." + icon_state = "werewolf_tongue" + icon = 'monkestation/code/modules/the_wolf_inside_of_me/icons/mutant_bodyparts.dmi' + say_mod = "growls" + modifies_speech = TRUE + taste_sensitivity = 5 + //liked_foodtypes = GROSS | MEAT | RAW | GORE + //disliked_foodtypes = SUGAR + +/obj/item/organ/internal/tongue/werewolf/modify_speech(datum/source, list/speech_args) + var/message = speech_args[SPEECH_MESSAGE] + if(message[1] != "*") + + // all occurrences of characters "eiou" (case-insensitive) are replaced with "r" + message = replacetext(message, regex(@"[eiou]", "ig"), "r") + // all characters other than "zhrgbmna .!?-" (case-insensitive) are stripped + message = replacetext(message, regex(@"[^zhrgbmna.!?-\s]", "ig"), "") + // multiple spaces are replaced with a single (whitespace is trimmed) + message = replacetext(message, regex(@"(\s+)", "g"), " ") + + var/list/old_words = splittext(message, " ") + var/list/new_words = list() + for(var/word in old_words) + // lower-case "r" at the end of words replaced with "rh" + word = replacetext(word, regex(@"\lr\b"), "rh") + // an "a" or "A" by itself will be replaced with "hra" + word = replacetext(word, regex(@"\b[Aa]\b"), "hra") + new_words += word + + message = new_words.Join(" ") + message = capitalize(message) + speech_args[SPEECH_MESSAGE] = message diff --git a/monkestation/code/modules/the_wolf_inside_of_me/species.dm b/monkestation/code/modules/the_wolf_inside_of_me/species.dm new file mode 100644 index 000000000000..7c32d766edb8 --- /dev/null +++ b/monkestation/code/modules/the_wolf_inside_of_me/species.dm @@ -0,0 +1,71 @@ +/datum/species/werewolf + name = "werewolf" + id = SPECIES_WEREWOLF + inherent_traits = list( + TRAIT_NO_UNDERWEAR, + TRAIT_USES_SKINTONES, + TRAIT_NO_AUGMENTS, + TRAIT_IGNOREDAMAGESLOWDOWN, + TRAIT_PUSHIMMUNE, + TRAIT_STUNIMMUNE, + TRAIT_PRIMITIVE, + TRAIT_CAN_STRIP, + TRAIT_CHUNKYFINGERS, + + ) + mutanttongue = /obj/item/organ/internal/tongue/werewolf + mutantears = /obj/item/organ/internal/ears/werewolf + mutanteyes = /obj/item/organ/internal/eyes/werewolf + mutantbrain = /obj/item/organ/internal/brain/werewolf + mutantliver = /obj/item/organ/internal/liver/werewolf + external_organs = list( + /obj/item/organ/external/tail/cat = "Cat", + ) + skinned_type = /obj/item/stack/sheet/animalhide/human + changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT + no_equip_flags = ITEM_SLOT_MASK | ITEM_SLOT_OCLOTHING | ITEM_SLOT_GLOVES | ITEM_SLOT_FEET | ITEM_SLOT_ICLOTHING | ITEM_SLOT_SUITSTORE + + bodypart_overrides = list( + BODY_ZONE_HEAD = /obj/item/bodypart/head/werewolf, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/werewolf, + BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/werewolf, + BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/werewolf, + BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/werewolf, + BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/werewolf, + ) + +/obj/item/organ/internal/brain/werewolf/get_attacking_limb(mob/living/carbon/human/target) + name = "werewolf brain" + desc = "a strange mixture of a human and wolf brain" + organ_traits = list(TRAIT_PRIMITIVE, TRAIT_CAN_STRIP) + + if(target.body_position == LYING_DOWN) + return owner.get_bodypart(BODY_ZONE_HEAD) + return ..() + +/datum/species/werewolf/prepare_human_for_preview(mob/living/carbon/human/human) + human.hair_color = "#bb9966" // brown + human.hairstyle = "Business Hair" + +/datum/species/werewolf/get_species_description() + return "N/A" + +/datum/species/werewolf/create_pref_unique_perks() + var/list/to_add = list() + + to_add += list( + list( + SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, + SPECIES_PERK_ICON = "paw", + SPECIES_PERK_NAME = "Primal Primate", + SPECIES_PERK_DESC = "Werewolves are monstrous humans, and can't do most things a human can do. Computers are impossible, \ + complex machines are right out, and most clothes don't fit your larger form.", + ), + list( + SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, + SPECIES_PERK_ICON = "assistive-listening-systems", + SPECIES_PERK_NAME = "Sensitive Hearing", + SPECIES_PERK_DESC = "Werewolves are more sensitive to loud sounds, such as flashbangs.", + )) + + return to_add diff --git a/monkestation/code/modules/virology/disease/base_disease_folder/_base.dm b/monkestation/code/modules/virology/disease/base_disease_folder/_base.dm index fcb845a452ef..7223a5f4e577 100644 --- a/monkestation/code/modules/virology/disease/base_disease_folder/_base.dm +++ b/monkestation/code/modules/virology/disease/base_disease_folder/_base.dm @@ -208,7 +208,7 @@ GLOBAL_LIST_INIT(virusDB, list()) e.run_effect(mob, src) //fever is a reaction of the body's immune system to the infection. The higher the antibody concentration (and the disease still not cured), the higher the fever - if (mob.bodytemperature < BODYTEMP_HEAT_DAMAGE_LIMIT)//but we won't go all the way to burning up just because of a fever, probably + if (mob.bodytemperature < mob.bodytemp_heat_damage_limit - 15)//but we won't go all the way to burning up just because of a fever, probably var/fever = round((robustness / 100) * (immune_data[2] / 10) * (stage / max_stages)) switch (mob.mob_size) if (MOB_SIZE_TINY) diff --git a/monkestation/code/modules/virology/disease/symtoms/stage1.dm b/monkestation/code/modules/virology/disease/symtoms/stage1.dm index 570c72e4c377..1c2493f2c63f 100644 --- a/monkestation/code/modules/virology/disease/symtoms/stage1.dm +++ b/monkestation/code/modules/virology/disease/symtoms/stage1.dm @@ -357,6 +357,8 @@ Heal(mob, effectiveness) /datum/symptom/water_heal/proc/CanHeal(mob/living/M) + if(!M) + return 1 var/base = 0 if(M.fire_stacks < 0) M.adjust_fire_stacks(min(absorption_coeff, -M.fire_stacks)) @@ -476,13 +478,13 @@ if(prob(5)) to_chat(M, span_notice("You feel yourself absorbing plasma inside and around you...")) - var/target_temp = M.get_body_temp_normal() + var/target_temp = M.standard_body_temperature if(M.bodytemperature > target_temp) - M.adjust_bodytemperature(-20 * temp_rate * TEMPERATURE_DAMAGE_COEFFICIENT, target_temp) + M.adjust_bodytemperature(-2 * temp_rate * TEMPERATURE_DAMAGE_COEFFICIENT, target_temp) if(prob(5)) to_chat(M, span_notice("You feel less hot.")) - else if(M.bodytemperature < (M.get_body_temp_normal() + 1)) - M.adjust_bodytemperature(20 * temp_rate * TEMPERATURE_DAMAGE_COEFFICIENT, 0, target_temp) + else if(M.bodytemperature < (M.standard_body_temperature + 1)) + M.adjust_bodytemperature(2 * temp_rate * TEMPERATURE_DAMAGE_COEFFICIENT, 0, target_temp) if(prob(5)) to_chat(M, span_notice("You feel warmer.")) diff --git a/monkestation/code/modules/virology/disease/symtoms/stage2.dm b/monkestation/code/modules/virology/disease/symtoms/stage2.dm index 34aa5c17962f..f67d8a63f578 100644 --- a/monkestation/code/modules/virology/disease/symtoms/stage2.dm +++ b/monkestation/code/modules/virology/disease/symtoms/stage2.dm @@ -90,15 +90,13 @@ /datum/symptom/fridge/proc/set_body_temp(mob/living/mob) if(multiplier >= 3) // when unsafe the shivers can cause cold damage - mob.add_body_temperature_change("chills", -6 * power * multiplier) + mob.add_homeostasis_level(type, -6, 0.25 KELVIN * power) else - // Get the max amount of change allowed before going under cold damage limit, then cap the maximum allowed temperature change from safe chills to 5 over the cold damage limit - var/change_limit = min(mob.get_body_temp_cold_damage_limit() + 5 - mob.get_body_temp_normal(apply_change=FALSE), 0) - mob.add_body_temperature_change("chills", max(-6 * power * multiplier, change_limit)) + mob.add_homeostasis_level(type, -6 * power, 0.25 KELVIN * power) /datum/symptom/fridge/deactivate(mob/living/carbon/mob) if(mob) - mob.remove_body_temperature_change("chills") + mob.remove_homeostasis_level(type) /datum/symptom/hair name = "Hair Loss" diff --git a/monkestation/code/modules/virology/disease/symtoms/stage3.dm b/monkestation/code/modules/virology/disease/symtoms/stage3.dm index afe0808b87c6..a9cc37ecfb2b 100644 --- a/monkestation/code/modules/virology/disease/symtoms/stage3.dm +++ b/monkestation/code/modules/virology/disease/symtoms/stage3.dm @@ -462,7 +462,7 @@ GLOBAL_LIST_INIT(disease_hivemind_users, list()) var/not_passed = TRUE var/obj/item/organ/spawned_organ while(not_passed && fail_counter <= 10) - var/organ_type = pick(typesof(/obj/item/organ/internal)) + var/organ_type = pick(mob?.organs) spawned_organ = new organ_type(get_turf(mob)) if(spawned_organ.status != ORGAN_ORGANIC) qdel(spawned_organ) diff --git a/monkestation/code/modules/virology/immune_systems/_immune_system.dm b/monkestation/code/modules/virology/immune_systems/_immune_system.dm index 13901bb1662f..db38ba1c9ea9 100644 --- a/monkestation/code/modules/virology/immune_systems/_immune_system.dm +++ b/monkestation/code/modules/virology/immune_systems/_immune_system.dm @@ -41,7 +41,7 @@ antibodies[antibody] = rand(10, 30) * boost if(antibody in GLOB.blood_antigens) antibodies[antibody] = rand(10, 20) * boost - var/blood_type = host.has_dna()?.blood_type + var/blood_type = host.has_dna()?.human_blood_type if(blood_type) switch(antibody) if(ANTIGEN_O) diff --git a/monkestation/code/modules/virology/machines/floor_health_scanner.dm b/monkestation/code/modules/virology/machines/floor_health_scanner.dm index 939b1009bc9a..ceab3c6ee25d 100644 --- a/monkestation/code/modules/virology/machines/floor_health_scanner.dm +++ b/monkestation/code/modules/virology/machines/floor_health_scanner.dm @@ -1,9 +1,10 @@ /obj/machinery/health_scanner_floor - name = "floor scanner" + name = "Vitals Scanning Pad" desc = "Gives patients a brief medical overview by stepping on it." icon_state = "floor_scanner" icon = 'monkestation/code/modules/virology/icons/virology.dmi' + circuit = /obj/item/circuitboard/machine/vital_floor_scanner density = FALSE anchored = TRUE @@ -26,7 +27,9 @@ vis_contents += maptext_obj var/static/list/connections = list( + COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON = PROC_REF(on_entered), COMSIG_ATOM_ENTERED = PROC_REF(on_entered), + COMSIG_ATOM_EXITED = PROC_REF(on_exited), ) AddElement(/datum/element/connect_loc, connections) AddElement(/datum/element/elevation, 4) @@ -51,10 +54,17 @@ arrived.visual_masked_scan() maptext_obj.maptext = generate_maptext(arrived) + set_occupant(arrived) animate(maptext_obj, 0.25 SECONDS, maptext_y = 32, easing = BOUNCE_EASING) addtimer(CALLBACK(src, PROC_REF(clear_maptext)), 3 SECONDS) +/obj/machinery/health_scanner_floor/proc/on_exited(datum/source, atom/movable/departed) + SIGNAL_HANDLER + if(occupant != departed) + return + set_occupant(null) + /obj/machinery/health_scanner_floor/proc/clear_maptext() maptext_obj.maptext = null maptext_obj.maptext_y = 0 diff --git a/monkestation/icons/mob/anime/anime_bottom.dmi b/monkestation/icons/mob/anime/anime_bottom.dmi index 870e13fc46dd..9da4a806305f 100644 Binary files a/monkestation/icons/mob/anime/anime_bottom.dmi and b/monkestation/icons/mob/anime/anime_bottom.dmi differ diff --git a/monkestation/icons/mob/anime/anime_head.dmi b/monkestation/icons/mob/anime/anime_head.dmi index 2c3773ce7c7d..80e3ecb4feeb 100644 Binary files a/monkestation/icons/mob/anime/anime_head.dmi and b/monkestation/icons/mob/anime/anime_head.dmi differ diff --git a/monkestation/icons/mob/anime/anime_head32x48.dmi b/monkestation/icons/mob/anime/anime_head32x48.dmi index 3237d345d156..19f55db54c71 100644 Binary files a/monkestation/icons/mob/anime/anime_head32x48.dmi and b/monkestation/icons/mob/anime/anime_head32x48.dmi differ diff --git a/monkestation/icons/mob/anime/anime_middle.dmi b/monkestation/icons/mob/anime/anime_middle.dmi index 214b32d9d6f9..3765843911e8 100644 Binary files a/monkestation/icons/mob/anime/anime_middle.dmi and b/monkestation/icons/mob/anime/anime_middle.dmi differ diff --git a/monkestation/icons/mob/bandage.dmi b/monkestation/icons/mob/bandage.dmi new file mode 100644 index 000000000000..24b65c9c48ef Binary files /dev/null and b/monkestation/icons/mob/bandage.dmi differ diff --git a/monkestation/icons/mob/species/ethereal/ethereal_tail.dmi b/monkestation/icons/mob/species/ethereal/ethereal_tail.dmi index 3774c4c41b03..abbd8f730602 100644 Binary files a/monkestation/icons/mob/species/ethereal/ethereal_tail.dmi and b/monkestation/icons/mob/species/ethereal/ethereal_tail.dmi differ diff --git a/monkestation/icons/mob/species/ipc/ipc_antennas.dmi b/monkestation/icons/mob/species/ipc/ipc_antennas.dmi index 5880237edf04..63adaed38176 100644 Binary files a/monkestation/icons/mob/species/ipc/ipc_antennas.dmi and b/monkestation/icons/mob/species/ipc/ipc_antennas.dmi differ diff --git a/monkestation/icons/mob/species/simian/tails.dmi b/monkestation/icons/mob/species/simian/tails.dmi index 907cabbfd03f..67fa393fd1a7 100644 Binary files a/monkestation/icons/mob/species/simian/tails.dmi and b/monkestation/icons/mob/species/simian/tails.dmi differ diff --git a/monkestation/icons/obj/ranching/eggs.dmi b/monkestation/icons/obj/ranching/eggs.dmi index 714af45d0a5f..37aff01871d3 100644 Binary files a/monkestation/icons/obj/ranching/eggs.dmi and b/monkestation/icons/obj/ranching/eggs.dmi differ diff --git a/monkestation/sound/items/rip1.ogg b/monkestation/sound/items/rip1.ogg new file mode 100644 index 000000000000..ab0fabbb3d69 Binary files /dev/null and b/monkestation/sound/items/rip1.ogg differ diff --git a/monkestation/sound/items/rip2.ogg b/monkestation/sound/items/rip2.ogg new file mode 100644 index 000000000000..93a5cec50f8a Binary files /dev/null and b/monkestation/sound/items/rip2.ogg differ diff --git a/monkestation/sound/items/rip3.ogg b/monkestation/sound/items/rip3.ogg new file mode 100644 index 000000000000..82d93582923e Binary files /dev/null and b/monkestation/sound/items/rip3.ogg differ diff --git a/monkestation/sound/items/rip4.ogg b/monkestation/sound/items/rip4.ogg new file mode 100644 index 000000000000..32c594b688d7 Binary files /dev/null and b/monkestation/sound/items/rip4.ogg differ diff --git a/monkestation/sound/items/snip.ogg b/monkestation/sound/items/snip.ogg new file mode 100644 index 000000000000..9f499b9a2abe Binary files /dev/null and b/monkestation/sound/items/snip.ogg differ diff --git a/tgstation.dme b/tgstation.dme index 9c31e5566ae1..322097ccd16b 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -407,6 +407,7 @@ #include "code\__DEFINES\~monkestation\atmospherics.dm" #include "code\__DEFINES\~monkestation\atom_hud.dm" #include "code\__DEFINES\~monkestation\blackboard.dm" +#include "code\__DEFINES\~monkestation\blood_datums.dm" #include "code\__DEFINES\~monkestation\blueshift.dm" #include "code\__DEFINES\~monkestation\botany.dm" #include "code\__DEFINES\~monkestation\cargo.dm" @@ -590,6 +591,7 @@ #include "code\__HELPERS\~monkestation-helpers\announcements.dm" #include "code\__HELPERS\~monkestation-helpers\antags.dm" #include "code\__HELPERS\~monkestation-helpers\atoms.dm" +#include "code\__HELPERS\~monkestation-helpers\blood_datums.dm" #include "code\__HELPERS\~monkestation-helpers\clients.dm" #include "code\__HELPERS\~monkestation-helpers\cmp.dm" #include "code\__HELPERS\~monkestation-helpers\colors.dm" @@ -656,7 +658,6 @@ #include "code\_onclick\hud\alien_larva.dm" #include "code\_onclick\hud\blob_overmind.dm" #include "code\_onclick\hud\blobbernaut.dm" -#include "code\_onclick\hud\credits.dm" #include "code\_onclick\hud\drones.dm" #include "code\_onclick\hud\fullscreen.dm" #include "code\_onclick\hud\generic_dextrous.dm" @@ -1366,7 +1367,6 @@ #include "code\datums\elements\attack_equip.dm" #include "code\datums\elements\backblast.dm" #include "code\datums\elements\bane.dm" -#include "code\datums\elements\basic_body_temp_sensitive.dm" #include "code\datums\elements\basic_eating.dm" #include "code\datums\elements\beauty.dm" #include "code\datums\elements\bed_tucking.dm" @@ -4614,7 +4614,6 @@ #include "code\modules\mob\living\carbon\alien\adult\adult_update_icons.dm" #include "code\modules\mob\living\carbon\alien\adult\alien_powers.dm" #include "code\modules\mob\living\carbon\alien\adult\death.dm" -#include "code\modules\mob\living\carbon\alien\adult\life.dm" #include "code\modules\mob\living\carbon\alien\adult\queen.dm" #include "code\modules\mob\living\carbon\alien\adult\caste\drone.dm" #include "code\modules\mob\living\carbon\alien\adult\caste\hunter.dm" @@ -5466,6 +5465,7 @@ #include "code\modules\surgery\advanced\bioware\nerve_grounding.dm" #include "code\modules\surgery\advanced\bioware\nerve_splicing.dm" #include "code\modules\surgery\advanced\bioware\vein_threading.dm" +#include "code\modules\surgery\bodyparts\_arms.dm" #include "code\modules\surgery\bodyparts\_bodyparts.dm" #include "code\modules\surgery\bodyparts\digitigrade.dm" #include "code\modules\surgery\bodyparts\dismemberment.dm" @@ -5486,12 +5486,9 @@ #include "code\modules\surgery\organs\autosurgeon.dm" #include "code\modules\surgery\organs\ears.dm" #include "code\modules\surgery\organs\eyes.dm" -#include "code\modules\surgery\organs\heart.dm" #include "code\modules\surgery\organs\helpers.dm" -#include "code\modules\surgery\organs\liver.dm" #include "code\modules\surgery\organs\lungs.dm" #include "code\modules\surgery\organs\organ_internal.dm" -#include "code\modules\surgery\organs\tongue.dm" #include "code\modules\surgery\organs\vocal_cords.dm" #include "code\modules\surgery\organs\external\_external_organs.dm" #include "code\modules\surgery\organs\external\restyling.dm" @@ -5500,6 +5497,11 @@ #include "code\modules\surgery\organs\external\wings\functional_wings.dm" #include "code\modules\surgery\organs\external\wings\moth_wings.dm" #include "code\modules\surgery\organs\external\wings\wings.dm" +#include "code\modules\surgery\organs\internal\heart\_heart.dm" +#include "code\modules\surgery\organs\internal\liver\_liver.dm" +#include "code\modules\surgery\organs\internal\liver\liver_plasmamen.dm" +#include "code\modules\surgery\organs\internal\liver\liver_skeleton.dm" +#include "code\modules\surgery\organs\internal\tongue\_tongue.dm" #include "code\modules\surgery\organs\stomach\_stomach.dm" #include "code\modules\surgery\organs\stomach\stomach_ethereal.dm" #include "code\modules\tgchat\message.dm" @@ -5984,6 +5986,10 @@ #include "monkestation\code\game\turfs\open\water.dm" #include "monkestation\code\game\turfs\open\floor\misc_floor.dm" #include "monkestation\code\modules\_paperwork\paper_premade.dm" +#include "monkestation\code\modules\a_medical_day\internal_bleeding.dm" +#include "monkestation\code\modules\a_medical_day\lungless.dm" +#include "monkestation\code\modules\a_medical_day\surgery.dm" +#include "monkestation\code\modules\a_medical_day\thermics.dm" #include "monkestation\code\modules\a_ship_in_need_of_breaking\area.dm" #include "monkestation\code\modules\a_ship_in_need_of_breaking\scrap.dm" #include "monkestation\code\modules\a_ship_in_need_of_breaking\machines\console.dm" @@ -6024,11 +6030,13 @@ #include "monkestation\code\modules\aesthetics\objects\windows.dm" #include "monkestation\code\modules\aesthetics\subsystem\coloring.dm" #include "monkestation\code\modules\aesthetics\walls\iron.dm" +#include "monkestation\code\modules\and_roll_credits\_credits.dm" +#include "monkestation\code\modules\and_roll_credits\credits_subsystem.dm" +#include "monkestation\code\modules\and_roll_credits\episode_names.dm" #include "monkestation\code\modules\antagonists\_common\antag_datum.dm" #include "monkestation\code\modules\antagonists\_common\antag_hud.dm" #include "monkestation\code\modules\antagonists\abductor\abductor.dm" #include "monkestation\code\modules\antagonists\abductor\equipment\gear\abductor_items.dm" -#include "monkestation\code\modules\antagonists\abductor\equipment\glands\blood.dm" #include "monkestation\code\modules\antagonists\abductor\equipment\glands\plasma.dm" #include "monkestation\code\modules\antagonists\abductor\equipment\glands\slime.dm" #include "monkestation\code\modules\antagonists\abductor\equipment\glands\trauma.dm" @@ -6339,6 +6347,17 @@ #include "monkestation\code\modules\ballpit\ballpit.dm" #include "monkestation\code\modules\bitrunners\code\ability_disks.dm" #include "monkestation\code\modules\bitrunners\code\combat_gear_disks.dm" +#include "monkestation\code\modules\blood_datum\blood.dm" +#include "monkestation\code\modules\blood_datum\debilitated.dm" +#include "monkestation\code\modules\blood_datum\designs.dm" +#include "monkestation\code\modules\blood_datum\forensics_helpers.dm" +#include "monkestation\code\modules\blood_datum\stunning.dm" +#include "monkestation\code\modules\blood_datum\components\item_receiver.dm" +#include "monkestation\code\modules\blood_datum\components\limbless_aid.dm" +#include "monkestation\code\modules\blood_datum\elements\easy_ignite.dm" +#include "monkestation\code\modules\blood_datum\items\crutch.dm" +#include "monkestation\code\modules\blood_datum\vital_monitor\operating_table_additions.dm" +#include "monkestation\code\modules\blood_datum\vital_monitor\vital_reader.dm" #include "monkestation\code\modules\blood_for_the_blood_gods\fly_away.dm" #include "monkestation\code\modules\blood_for_the_blood_gods\particle.dm" #include "monkestation\code\modules\blood_for_the_blood_gods\slasher\__base_slasher_additions.dm" @@ -6771,11 +6790,13 @@ #include "monkestation\code\modules\buckshotroulette\projectiles\guns\ballistic\shotgun.dm" #include "monkestation\code\modules\bunny_wizard\outfits.dm" #include "monkestation\code\modules\bunny_wizard\wizard_items.dm" +#include "monkestation\code\modules\can_spessmen_feel_pain\bandage.dm" #include "monkestation\code\modules\can_spessmen_feel_pain\subsystem.dm" #include "monkestation\code\modules\can_spessmen_feel_pain\components\make_item_slow.dm" #include "monkestation\code\modules\can_spessmen_feel_pain\elements\temperature_pack.dm" #include "monkestation\code\modules\can_spessmen_feel_pain\pain\_base.dm" #include "monkestation\code\modules\can_spessmen_feel_pain\pain\bodyparts.dm" +#include "monkestation\code\modules\can_spessmen_feel_pain\pain\designs.dm" #include "monkestation\code\modules\can_spessmen_feel_pain\pain\effects.dm" #include "monkestation\code\modules\can_spessmen_feel_pain\pain\helpers.dm" #include "monkestation\code\modules\can_spessmen_feel_pain\pain\item_helpers.dm" @@ -6793,7 +6814,6 @@ #include "monkestation\code\modules\can_spessmen_feel_pain\pain\reagents\painkiller_related.dm" #include "monkestation\code\modules\can_spessmen_feel_pain\pain\reagents\painkillers.dm" #include "monkestation\code\modules\can_spessmen_feel_pain\pain\status_effects\anesthetics.dm" -#include "monkestation\code\modules\can_spessmen_feel_pain\pain\status_effects\fire_pain.dm" #include "monkestation\code\modules\can_spessmen_feel_pain\pain\status_effects\low_blood_pressure.dm" #include "monkestation\code\modules\can_spessmen_feel_pain\pain\status_effects\min_pain.dm" #include "monkestation\code\modules\can_spessmen_feel_pain\pain\status_effects\pain_limp.dm" @@ -7338,24 +7358,15 @@ #include "monkestation\code\modules\mob\living\carbon\human\species_type\abductors.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\android.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\arachnid.dm" -#include "monkestation\code\modules\mob\living\carbon\human\species_type\dullahan.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\ethereal.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\floran.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\flypeople.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\goblin.dm" -#include "monkestation\code\modules\mob\living\carbon\human\species_type\golems.dm" -#include "monkestation\code\modules\mob\living\carbon\human\species_type\humans.dm" -#include "monkestation\code\modules\mob\living\carbon\human\species_type\jellypeople.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\lizardpeople.dm" -#include "monkestation\code\modules\mob\living\carbon\human\species_type\monkeys.dm" -#include "monkestation\code\modules\mob\living\carbon\human\species_type\mothmen.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\plasmamen.dm" -#include "monkestation\code\modules\mob\living\carbon\human\species_type\podpeople.dm" -#include "monkestation\code\modules\mob\living\carbon\human\species_type\shadowpeople.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\simian.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\skeletons.dm" #include "monkestation\code\modules\mob\living\carbon\human\species_type\teratoma.dm" -#include "monkestation\code\modules\mob\living\carbon\human\species_type\zombies.dm" #include "monkestation\code\modules\mob\living\silicon\death.dm" #include "monkestation\code\modules\mob\living\simple_animal\megafauna\wendigo.dm" #include "monkestation\code\modules\mob\living\simple_animal\pets\bees.dm" @@ -7931,6 +7942,25 @@ #include "monkestation\code\modules\surgery\organs\internal\stomach.dm" #include "monkestation\code\modules\surgery\organs\internal\tongue.dm" #include "monkestation\code\modules\syndicate_ghostroles\listeningpost.dm" +#include "monkestation\code\modules\temperature_overhaul\exposure.dm" +#include "monkestation\code\modules\temperature_overhaul\homeostasis_level.dm" +#include "monkestation\code\modules\temperature_overhaul\living_procs.dm" +#include "monkestation\code\modules\temperature_overhaul\temperature_proc.dm" +#include "monkestation\code\modules\the_bird_inside_of_me\language.dm" +#include "monkestation\code\modules\the_bird_inside_of_me\organs.dm" +#include "monkestation\code\modules\the_bird_inside_of_me\plummage.dm" +#include "monkestation\code\modules\the_bird_inside_of_me\prefs.dm" +#include "monkestation\code\modules\the_bird_inside_of_me\species.dm" +#include "monkestation\code\modules\the_bird_inside_of_me\tails.dm" +#include "monkestation\code\modules\the_bird_inside_of_me\wings.dm" +#include "monkestation\code\modules\the_fabled_dna_changes\dna.dm" +#include "monkestation\code\modules\the_fabled_dna_changes\multi_colored_bodyoverlay.dm" +#include "monkestation\code\modules\the_fabled_dna_changes\species_color_pallettes\_color_pallette.dm" +#include "monkestation\code\modules\the_fabled_dna_changes\species_color_pallettes\generic_palette.dm" +#include "monkestation\code\modules\the_fabled_dna_changes\species_color_pallettes\ornithids.dm" +#include "monkestation\code\modules\the_wolf_inside_of_me\bodyparts.dm" +#include "monkestation\code\modules\the_wolf_inside_of_me\organs.dm" +#include "monkestation\code\modules\the_wolf_inside_of_me\species.dm" #include "monkestation\code\modules\trading\box_rolling.dm" #include "monkestation\code\modules\trading\lootbox_buying.dm" #include "monkestation\code\modules\trading\lootbox_clothing.dm" diff --git a/tgui/packages/tgui/interfaces/ColorPickerModal.tsx b/tgui/packages/tgui/interfaces/ColorPickerModal.tsx index ff7a79706dec..75e5082f0f36 100644 --- a/tgui/packages/tgui/interfaces/ColorPickerModal.tsx +++ b/tgui/packages/tgui/interfaces/ColorPickerModal.tsx @@ -9,6 +9,7 @@ import { useBackend, useLocalState } from '../backend'; import { Autofocus, Box, + Button, Flex, Section, Stack, @@ -45,7 +46,7 @@ type ColorPickerData = { }; export const ColorPickerModal = (_) => { - const { data } = useBackend(); + const { act, data } = useBackend(); const { timeout, message, @@ -84,6 +85,7 @@ export const ColorPickerModal = (_) => { + diff --git a/tgui/packages/tgui/interfaces/PersonalCrafting.tsx b/tgui/packages/tgui/interfaces/PersonalCrafting.tsx index bfea132ec0ef..7e4dd61b66d2 100644 --- a/tgui/packages/tgui/interfaces/PersonalCrafting.tsx +++ b/tgui/packages/tgui/interfaces/PersonalCrafting.tsx @@ -647,6 +647,43 @@ const FoodtypeContent = (props) => { const RecipeContentCompact = ({ item, craftable, busy, mode }) => { const { act, data } = useBackend(); + + // Function to handle pushing steps (unchanged) + const specialSteps = [ + 'Optional Steps', + 'End Optional Steps', + 'Exclusive Optional Steps', + 'End Exclusive Optional Steps', + 'Optional Step', + 'End Optional Step', + ]; + + const groupedSteps: string[] = []; + let previousStep = ''; + let duplicateCount = 0; + + const pushStep = (step: string, count: number) => { + const stepText = count > 1 ? `${step} x${count}` : step; + groupedSteps.push(stepText); + }; + + item.steps?.forEach((step) => { + const trimmedStep = step.trim(); + if (trimmedStep === previousStep) { + duplicateCount++; + } else { + if (duplicateCount > 0) { + pushStep(previousStep, duplicateCount); + } + previousStep = trimmedStep; + duplicateCount = 1; + } + }); + + if (duplicateCount > 0) { + pushStep(previousStep, duplicateCount); + } + return (
@@ -665,27 +702,31 @@ const RecipeContentCompact = ({ item, craftable, busy, mode }) => { {item.name} - {Array.from( - Object.keys(item.reqs).map((atom_id) => { - const name = data.atom_data[(atom_id as any) - 1]?.name; - const is_reagent = - data.atom_data[(atom_id as any) - 1]?.is_reagent; - const amount = item.reqs[atom_id]; - return is_reagent - ? `${name}\xa0${amount}u` - : amount > 1 - ? `${name}\xa0${amount}x` - : name; - }), - ).join(', ')} + {Array.isArray(item.reqs) && + Object.keys(item.reqs).length > 0 && + Object.keys(item.reqs) + .map((atom_id) => { + const name = data.atom_data?.[(atom_id as any) - 1]?.name; + const is_reagent = + data.atom_data?.[(atom_id as any) - 1]?.is_reagent; + const amount = item.reqs[atom_id]; + return is_reagent + ? `${name}\xa0${amount}u` + : amount > 1 + ? `${name}\xa0${amount}x` + : name; + }) + .join(', ')} {item.chem_catalysts && + Object.keys(item.chem_catalysts).length > 0 && ', ' + Object.keys(item.chem_catalysts) .map((atom_id) => { - const name = data.atom_data[(atom_id as any) - 1]?.name; + const name = + data.atom_data?.[(atom_id as any) - 1]?.name; const is_reagent = - data.atom_data[(atom_id as any) - 1]?.is_reagent; + data.atom_data?.[(atom_id as any) - 1]?.is_reagent; const amount = item.chem_catalysts[atom_id]; return is_reagent ? `${name}\xa0${amount}u` @@ -696,19 +737,24 @@ const RecipeContentCompact = ({ item, craftable, busy, mode }) => { .join(', ')} {item.tool_paths && + item.tool_paths.length > 0 && ', ' + item.tool_paths - .map((item) => data.atom_data[(item as any) - 1]?.name) + .map((item) => data.atom_data?.[(item as any) - 1]?.name) .join(', ')} + {item.machinery && + item.machinery.length > 0 && ', ' + item.machinery - .map((item) => data.atom_data[(item as any) - 1]?.name) + .map((item) => data.atom_data?.[(item as any) - 1]?.name) .join(', ')} + {item.structures && + item.structures.length > 0 && ', ' + item.structures - .map((item) => data.atom_data[(item as any) - 1]?.name) + .map((item) => data.atom_data?.[(item as any) - 1]?.name) .join(', ')} @@ -746,8 +792,8 @@ const RecipeContentCompact = ({ item, craftable, busy, mode }) => { ) : ( item.steps && ( ( - {step} + content={groupedSteps.map((step, index) => ( + {step} ))} > diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx index 45fb52341a86..4b595b16388f 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/CharacterPreferenceWindow.tsx @@ -86,7 +86,7 @@ export const CharacterPreferenceWindow = (props) => { diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx index d888bdf3d313..f15cbd6b51a4 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/MainPage.tsx @@ -83,8 +83,8 @@ const ChoicedSelection = (props: { name: string; catalog: FeatureChoicedServerData; selected: string; - supplementalFeature?: string; - supplementalValue?: unknown; + supplementalFeatures?: string[]; // Now an array of features + supplementalValues?: unknown[]; // Now an array of values onClose: () => void; onSelect: (value: string) => void; searchText: string; @@ -94,8 +94,8 @@ const ChoicedSelection = (props: { const { catalog, - supplementalFeature, - supplementalValue, + supplementalFeatures = [], + supplementalValues = [], searchText, setSearchText, } = props; @@ -108,10 +108,6 @@ const ChoicedSelection = (props: { return name; }); - const use_small_supplemental = - supplementalFeature && - (features[supplementalFeature].small_supplemental === true || - features[supplementalFeature].small_supplemental === undefined); return ( - {supplementalFeature && use_small_supplemental && ( - - - - )} - + {/* Handle small supplemental features */} + {supplementalFeatures.map((feature, index) => { + const use_small_supplemental = + features[feature]?.small_supplemental ?? true; + return ( + use_small_supplemental && ( + + + + ) + ); + })} - {supplementalFeature && !use_small_supplemental && ( - <> - - - Select {features[supplementalFeature].name} + {/* Handle larger supplemental features */} + {supplementalFeatures.map((feature, index) => { + const use_small_supplemental = + features[feature]?.small_supplemental ?? true; + return ( + !use_small_supplemental && ( + + + + Select {features[feature].name} + + + + + - - - - - - )} + ) + ); + })} @@ -320,7 +329,7 @@ const GenderButton = (props: { const MainFeature = (props: { catalog: FeatureChoicedServerData & { name: string; - supplemental_feature?: string; + supplemental_feature?: string | string[]; // Allow string or array of strings }; currentValue: string; isOpen: boolean; @@ -343,11 +352,24 @@ const MainFeature = (props: { setRandomization, } = props; - const supplementalFeature = catalog.supplemental_feature; + // Normalize supplementalFeature to always be an array + const supplementalFeatures = Array.isArray(catalog.supplemental_feature) + ? catalog.supplemental_feature + : catalog.supplemental_feature + ? [catalog.supplemental_feature] + : []; + + const supplementalValues = supplementalFeatures.map((feature) => + feature + ? data.character_preferences.supplemental_features[feature] + : undefined, + ); + let [searchText, setSearchText] = useLocalState( catalog.name + '_choiced_search', '', ); + const handleCloseInternal = () => { handleClose(); setSearchText(''); @@ -365,13 +387,8 @@ const MainFeature = (props: { name={catalog.name} catalog={catalog} selected={currentValue} - supplementalFeature={supplementalFeature} - supplementalValue={ - supplementalFeature && - data.character_preferences.supplemental_features[ - supplementalFeature - ] - } + supplementalFeatures={supplementalFeatures} // Pass array of features + supplementalValues={supplementalValues} // Pass array of values onClose={handleCloseInternal} onSelect={handleSelect} searchText={searchText} @@ -418,7 +435,6 @@ const MainFeature = (props: { position: 'absolute', right: '1px', }, - onOpen: (event) => { // We're a button inside a button. // Did you know that's against the W3C standard? :) diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/SpeciesPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/SpeciesPage.tsx index 9efb560a9ece..cefbf04223e5 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/SpeciesPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/SpeciesPage.tsx @@ -2,6 +2,7 @@ import { classes } from 'common/react'; import { useBackend } from '../../backend'; import { Box, + BlockQuote, Button, Divider, Icon, @@ -324,6 +325,23 @@ const SpeciesPageInner = (props: { + +
+
+ {currentSpecies.lore.map((text, index) => ( + + {text} + {index !== currentSpecies.lore.length - 1 && ( + <> +
+
+ + )} +
+ ))} +
+
+
diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts b/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts index 679216a9ca1f..b9b69f06c08b 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/data.ts @@ -40,6 +40,7 @@ export type Name = { export type Species = { name: string; desc: string; + lore: string[]; icon: string; use_skintones: BooleanLike; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/monkestation/ornithids.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/monkestation/ornithids.tsx new file mode 100644 index 000000000000..9dac1222e5c6 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/monkestation/ornithids.tsx @@ -0,0 +1,86 @@ +import { + Feature, + FeatureChoiced, + FeatureColorInput, + FeatureDropdownInput, +} from '../../base'; + +export const feature_arm_wings: FeatureChoiced = { + name: 'Arm Wings', + small_supplemental: false, + component: FeatureDropdownInput, +}; + +export const feather_color: Feature = { + name: 'Feather Color', + small_supplemental: true, + description: + "The color of your character's feathers. \ + (Armwings, Plumage).", + component: FeatureColorInput, +}; + +export const feather_color_secondary: Feature = { + name: 'Feather Color Secondary', + small_supplemental: true, + description: + "The color of your character's feathers. \ + (Armwings, Plumage).", + component: FeatureColorInput, +}; + +export const feather_color_tri: Feature = { + name: 'Feather Color Tri', + small_supplemental: true, + description: + "The color of your character's feathers. \ + (Armwings, Plumage).", + component: FeatureColorInput, +}; + +export const feather_tail_color: Feature = { + name: 'Tail Color', + small_supplemental: false, + description: + "The color of your character's tail feathers. \ + (Armwings, Plumage).", + component: FeatureColorInput, +}; + +export const plummage_color: Feature = { + name: 'Plummage Color', + small_supplemental: false, + description: + "The color of your character's plummage. \ + (Armwings, Plumage).", + component: FeatureColorInput, +}; +export const feature_avian_tail: FeatureChoiced = { + name: 'Tail', + small_supplemental: false, + component: FeatureDropdownInput, +}; + +export const feature_avian_ears: FeatureChoiced = { + name: 'Plumage', + small_supplemental: false, + component: FeatureDropdownInput, +}; + +export const feature_satyr_horns: FeatureChoiced = { + name: 'Satyr Horns', + small_supplemental: false, + component: FeatureDropdownInput, +}; + +export const feature_satyr_fluff: FeatureChoiced = { + name: 'Satyr Fluff', + small_supplemental: false, + component: FeatureDropdownInput, +}; + +export const feature_satyr_tail: FeatureChoiced = { + name: 'Tail', + small_supplemental: false, + component: FeatureDropdownInput, +};