diff --git a/_maps/RandomZLevels/museum.dmm b/_maps/RandomZLevels/museum.dmm index 7429c0b45382e..f40ecc09015c6 100644 --- a/_maps/RandomZLevels/museum.dmm +++ b/_maps/RandomZLevels/museum.dmm @@ -3147,6 +3147,7 @@ /obj/structure/transport/linear/tram/slow, /obj/structure/thermoplastic, /obj/effect/spawner/random/structure/closet_empty/crate/with_loot, +/obj/effect/spawner/random/maintenance/no_decals/five, /turf/open/chasm/true/no_smooth, /area/awaymission/museum) "Cc" = ( @@ -4988,7 +4989,7 @@ /obj/machinery/door/window/elevator/right/directional/south{ transport_linked_id = "museum_cargo" }, -/obj/effect/spawner/random/maintenance/seven, +/obj/effect/spawner/random/maintenance/no_decals/seven, /turf/open/chasm/true/no_smooth, /area/awaymission/museum) "Um" = ( @@ -5343,7 +5344,7 @@ "WJ" = ( /obj/structure/transport/linear/tram/slow, /obj/structure/thermoplastic, -/obj/effect/spawner/random/maintenance/seven, +/obj/effect/spawner/random/maintenance/no_decals/seven, /obj/item/storage/pill_bottle/maintenance_pill/full, /obj/effect/spawner/random/structure/closet_empty/crate/with_loot, /turf/open/chasm/true/no_smooth, diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index b2fad9e88d2b6..25141a232c003 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -5456,10 +5456,6 @@ /obj/effect/decal/cleanable/dirt, /turf/open/floor/plating, /area/station/security/tram) -"cgb" = ( -/obj/machinery/duct, -/turf/open/floor/iron/kitchen/small, -/area/station/security/prison/mess) "cgy" = ( /obj/effect/turf_decal/stripes/red/line{ dir = 4 @@ -11344,7 +11340,9 @@ /area/station/maintenance/starboard/aft) "ena" = ( /obj/effect/decal/cleanable/dirt, -/obj/structure/reagent_dispensers/plumbed, +/obj/structure/reagent_dispensers/plumbed{ + dir = 1 + }, /turf/open/floor/iron, /area/station/maintenance/department/medical/central) "enb" = ( @@ -14096,7 +14094,6 @@ "fls" = ( /obj/structure/cable, /obj/effect/decal/cleanable/dirt, -/obj/machinery/duct, /obj/effect/mapping_helpers/broken_floor, /obj/effect/decal/cleanable/glass/plastitanium, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -16053,6 +16050,12 @@ /obj/machinery/airalarm/directional/west, /turf/open/floor/iron/white, /area/station/medical/medbay/central) +"fRZ" = ( +/obj/structure/cable, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/turf/open/floor/plating, +/area/station/maintenance/fore/greater) "fSe" = ( /turf/closed/wall/rust, /area/station/cargo/miningfoundry) @@ -17810,7 +17813,6 @@ /obj/structure/cable, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/broken_floor, -/obj/machinery/duct, /obj/machinery/power/apc/auto_name/directional/west, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -24624,6 +24626,9 @@ "iSW" = ( /obj/structure/rack, /obj/item/clothing/gloves/boxing/yellow, +/obj/item/clothing/gloves/boxing/green{ + pixel_y = 4 + }, /turf/open/floor/plating, /area/station/maintenance/fore/greater) "iTn" = ( @@ -24697,8 +24702,7 @@ /turf/open/floor/plating, /area/station/engineering/atmos) "iUy" = ( -/obj/structure/rack, -/obj/item/clothing/gloves/boxing/green, +/obj/structure/reagent_dispensers/plumbed, /turf/open/floor/plating, /area/station/maintenance/fore/greater) "iUz" = ( @@ -27370,7 +27374,6 @@ "jPr" = ( /obj/structure/cable, /obj/effect/decal/cleanable/dirt, -/obj/machinery/duct, /obj/effect/mapping_helpers/broken_floor, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -28482,6 +28485,12 @@ /obj/item/storage/backpack/duffelbag, /turf/open/floor/plating, /area/station/maintenance/fore/greater) +"kld" = ( +/obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/duct, +/turf/open/floor/iron/kitchen/small, +/area/station/security/prison/mess) "klf" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/chair{ @@ -30608,7 +30617,6 @@ "kZo" = ( /obj/structure/cable, /obj/effect/decal/cleanable/dirt, -/obj/machinery/duct, /obj/effect/spawner/random/trash, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/broken_floor, @@ -32653,6 +32661,12 @@ /obj/structure/chair/stool/directional/south, /turf/open/floor/carpet/donk, /area/station/command/heads_quarters/qm) +"lHi" = ( +/obj/structure/cable, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/duct, +/turf/open/floor/iron/kitchen/small, +/area/station/security/prison/mess) "lHk" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -49391,7 +49405,9 @@ /area/station/maintenance/port/lesser) "row" = ( /obj/effect/decal/cleanable/dirt, -/obj/structure/reagent_dispensers/plumbed, +/obj/structure/reagent_dispensers/plumbed{ + dir = 4 + }, /turf/open/floor/plating, /area/station/maintenance/central/greater) "roz" = ( @@ -62899,6 +62915,7 @@ /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ dir = 8 }, +/obj/machinery/duct, /turf/open/floor/iron/kitchen/small, /area/station/security/prison/mess) "vEe" = ( @@ -89949,7 +89966,7 @@ qeP lrE oPV pId -ect +kld qRM vSx eGL @@ -90205,7 +90222,7 @@ uPr qeP lrE oPV -cgb +eHf vEb eHf qsR @@ -90463,7 +90480,7 @@ lub tBA oPV iNz -jDe +lHi jDe tSB eGL @@ -110124,7 +110141,7 @@ aJN tIE nFW iSW -rdh +fRZ liR jQL uwH diff --git a/_maps/map_files/Deathmatch/The_Brig.dmm b/_maps/map_files/Deathmatch/The_Brig.dmm index 15048da48e2b9..208b2c994737d 100644 --- a/_maps/map_files/Deathmatch/The_Brig.dmm +++ b/_maps/map_files/Deathmatch/The_Brig.dmm @@ -532,10 +532,6 @@ }, /turf/open/indestructible, /area/deathmatch) -"jB" = ( -/obj/machinery/light_switch/directional/west, -/turf/open/indestructible/dark, -/area/deathmatch) "jN" = ( /obj/structure/table, /obj/machinery/light/small/directional/north, @@ -894,10 +890,6 @@ }, /turf/open/indestructible, /area/deathmatch) -"oy" = ( -/obj/machinery/light_switch/directional/west, -/turf/open/floor/iron/grimy, -/area/deathmatch) "oA" = ( /obj/machinery/light/directional/north, /turf/open/indestructible, @@ -1162,13 +1154,6 @@ /obj/effect/decal/cleanable/oil/slippery, /turf/open/indestructible, /area/deathmatch) -"rN" = ( -/obj/effect/turf_decal/trimline/red/filled/line{ - dir = 4 - }, -/obj/machinery/light_switch/directional/east, -/turf/open/indestructible, -/area/deathmatch) "sb" = ( /obj/structure/closet{ name = "Evidence Closet 4" @@ -1526,9 +1511,6 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, -/obj/machinery/light_switch/directional/west{ - pixel_y = -12 - }, /obj/structure/extinguisher_cabinet/directional/west, /turf/open/indestructible/dark, /area/deathmatch) @@ -1683,7 +1665,6 @@ "yT" = ( /obj/effect/turf_decal/tile/red, /obj/machinery/light/directional/west, -/obj/machinery/light_switch/directional/west, /obj/effect/turf_decal/tile/red{ dir = 8 }, @@ -2344,16 +2325,6 @@ }, /turf/open/indestructible/dark, /area/deathmatch) -"Ii" = ( -/obj/effect/turf_decal/tile/red{ - dir = 1 - }, -/obj/effect/turf_decal/tile/red{ - dir = 8 - }, -/obj/machinery/light_switch/directional/east, -/turf/open/indestructible/dark, -/area/deathmatch) "Ik" = ( /obj/effect/turf_decal/trimline/red/filled/corner, /turf/open/indestructible, @@ -3022,11 +2993,6 @@ /obj/item/crowbar, /turf/open/indestructible, /area/deathmatch) -"RL" = ( -/obj/machinery/light_switch/directional/south, -/obj/structure/cable, -/turf/open/floor/carpet, -/area/deathmatch) "RR" = ( /obj/structure/cable, /obj/machinery/door/poddoor/preopen{ @@ -4117,7 +4083,7 @@ tH xi Am EP -Ii +tH Kh Rv UU @@ -4172,7 +4138,7 @@ yH uD xk Bf -jB +Ux JU YW yy @@ -4462,7 +4428,7 @@ Hz Ik Zv ad -oy +Pt Pt eD QG @@ -4563,7 +4529,7 @@ Cx ri yO cW -rN +Os Os Hp UQ @@ -4671,7 +4637,7 @@ cf cf YN aE -RL +cf Yh Wg qP diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm index d95f80e47138e..ed91e1bd69733 100644 --- a/_maps/map_files/NorthStar/north_star.dmm +++ b/_maps/map_files/NorthStar/north_star.dmm @@ -4573,6 +4573,10 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/white, /area/station/medical/psychology) +"bgq" = ( +/obj/machinery/bluespace_vendor/directional/west, +/turf/open/floor/iron/dark, +/area/station/hallway/floor2/fore) "bgr" = ( /obj/effect/decal/cleanable/dirt, /turf/open/floor/iron/dark/textured_corner, @@ -7446,6 +7450,12 @@ }, /turf/open/floor/iron/dark, /area/station/security/checkpoint/third) +"bQo" = ( +/obj/machinery/bluespace_vendor/directional/north, +/turf/open/floor/iron/dark/side{ + dir = 4 + }, +/area/station/hallway/floor4/aft) "bQv" = ( /obj/machinery/power/terminal{ dir = 4 @@ -8049,9 +8059,7 @@ /obj/machinery/atmospherics/pipe/heat_exchanging/manifold/layer2{ dir = 4 }, -/obj/machinery/atmospherics/components/unary/vent_scrubber{ - dir = 4 - }, +/obj/machinery/atmospherics/components/unary/vent_scrubber, /turf/open/floor/engine/vacuum, /area/station/science/ordnance/freezerchamber) "bYp" = ( @@ -10363,9 +10371,6 @@ /obj/effect/spawner/structure/window/hollow/plasma/middle{ dir = 4 }, -/obj/machinery/atmospherics/pipe/smart/simple/dark/visible{ - dir = 4 - }, /turf/open/floor/engine/vacuum, /area/station/science/ordnance/freezerchamber) "cBU" = ( @@ -16517,6 +16522,7 @@ dir = 8 }, /obj/item/storage/toolbox/emergency, +/obj/machinery/bluespace_vendor/directional/south, /turf/open/floor/iron/dark, /area/station/commons/storage/tools) "eir" = ( @@ -17584,6 +17590,7 @@ /area/station/security/office) "exv" = ( /obj/machinery/atmospherics/pipe/smart/manifold/purple/visible/layer2, +/obj/machinery/atmospherics/pipe/smart/simple/purple, /turf/open/floor/iron/dark, /area/station/science/ordnance/testlab) "exw" = ( @@ -22107,8 +22114,9 @@ /area/station/maintenance/floor3/starboard) "fLX" = ( /obj/structure/railing/corner, -/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible{ - dir = 4 +/obj/machinery/atmospherics/pipe/smart/simple/purple, +/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible/layer4{ + dir = 8 }, /turf/open/floor/iron/dark, /area/station/science/ordnance/testlab) @@ -22358,8 +22366,8 @@ /turf/open/floor/grass, /area/station/security/courtroom) "fPd" = ( -/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible{ - dir = 4 +/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible/layer4{ + dir = 8 }, /turf/open/floor/iron/dark, /area/station/science/ordnance/testlab) @@ -24907,6 +24915,13 @@ /obj/structure/sign/poster/official/random/directional/south, /turf/open/floor/iron/dark/side, /area/station/hallway/floor2/fore) +"gxE" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/structure/cable, +/obj/machinery/bluespace_vendor/directional/north, +/turf/open/floor/iron, +/area/station/hallway/floor1/aft) "gxH" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -32627,6 +32642,9 @@ /obj/structure/railing{ dir = 4 }, +/obj/machinery/atmospherics/components/unary/portables_connector/visible{ + dir = 1 + }, /turf/open/floor/iron/dark, /area/station/science/ordnance/testlab) "ixf" = ( @@ -39349,6 +39367,7 @@ dir = 1 }, /obj/effect/spawner/structure/window/hollow/plasma/middle, +/obj/machinery/atmospherics/pipe/smart/simple/purple, /turf/open/floor/engine/vacuum, /area/station/science/ordnance/freezerchamber) "kiA" = ( @@ -46081,6 +46100,13 @@ /obj/structure/flora/bush/flowers_yw/style_random, /turf/open/floor/grass, /area/station/science/genetics) +"lRw" = ( +/obj/machinery/atmospherics/pipe/smart/simple/dark/visible{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/smart/simple/purple, +/turf/open/floor/iron/dark, +/area/station/science/ordnance/testlab) "lRF" = ( /obj/effect/turf_decal/trimline/brown/filled/line{ dir = 1 @@ -47622,6 +47648,10 @@ dir = 4 }, /area/station/hallway/floor3/fore) +"mlc" = ( +/obj/machinery/atmospherics/components/unary/bluespace_sender, +/turf/open/floor/iron/dark, +/area/station/engineering/atmos/project) "mlg" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -54276,6 +54306,7 @@ /obj/structure/chair/sofa/bench/left{ dir = 4 }, +/obj/machinery/bluespace_vendor/directional/west, /turf/open/floor/iron/dark, /area/station/hallway/floor1/fore) "nTI" = ( @@ -54876,8 +54907,8 @@ /area/station/engineering/lobby) "obC" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible{ - dir = 4 +/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible/layer4{ + dir = 8 }, /turf/open/floor/iron/dark, /area/station/science/ordnance/testlab) @@ -64010,6 +64041,10 @@ /obj/structure/cable, /turf/open/floor/carpet/royalblue, /area/station/commons/dorms/room4) +"qwd" = ( +/obj/machinery/bluespace_vendor/directional/north, +/turf/open/floor/iron/dark, +/area/station/hallway/floor3/fore) "qwg" = ( /obj/structure/chair/comfy/brown{ dir = 1 @@ -74556,6 +74591,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/cable, /obj/machinery/camera/autoname/directional/south, +/obj/machinery/bluespace_vendor/directional/south, /turf/open/floor/iron/dark/side, /area/station/hallway/floor2/aft) "tjV" = ( @@ -81832,6 +81868,10 @@ /obj/machinery/duct, /turf/open/floor/pod/dark, /area/station/maintenance/floor2/port) +"vdT" = ( +/obj/machinery/bluespace_vendor/directional/north, +/turf/open/floor/engine, +/area/station/engineering/supermatter/room) "vdU" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/generic_maintenance_landmark, @@ -88679,6 +88719,12 @@ dir = 5 }, /area/station/security/prison) +"wLQ" = ( +/obj/machinery/atmospherics/pipe/layer_manifold/scrubbers/visible{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/station/science/ordnance/testlab) "wLV" = ( /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 @@ -90129,10 +90175,10 @@ "xgo" = ( /obj/machinery/door/firedoor/border_only, /obj/structure/railing, -/obj/machinery/atmospherics/components/unary/portables_connector/visible{ +/obj/effect/turf_decal/box/red, +/obj/machinery/atmospherics/components/unary/portables_connector/visible/layer4{ dir = 8 }, -/obj/effect/turf_decal/box/red, /turf/open/floor/iron/dark, /area/station/science/ordnance/testlab) "xgC" = ( @@ -136653,7 +136699,7 @@ bJU pYs uyu kbu -yhr +gxE eeQ mdR gpf @@ -141275,7 +141321,7 @@ qEw qEw qEw sAH -xgW +vdT kfo iZP kcB @@ -143054,7 +143100,7 @@ owI owI css lwc -vEN +mlc vEN tGq vmr @@ -178028,7 +178074,7 @@ kEI wwu sbI jtJ -qfv +bgq hat qfv lXq @@ -243052,7 +243098,7 @@ nVq nVq cyX wRJ -sJO +qwd mUs oJo oJo @@ -314996,7 +315042,7 @@ xpL qRI mKO rDL -fPd +wLQ jha nPE xVV @@ -316023,7 +316069,7 @@ rrs bYl kiw exv -wMU +lRw fLX ixd bDn @@ -321441,7 +321487,7 @@ txa txa txa nWW -kQk +bQo nQX kQk eOP diff --git a/code/__DEFINES/construction/structures.dm b/code/__DEFINES/construction/structures.dm index 453de8ebf0591..e52b82f248e4e 100644 --- a/code/__DEFINES/construction/structures.dm +++ b/code/__DEFINES/construction/structures.dm @@ -62,7 +62,7 @@ #define GEAR_SECURE 1 #define GEAR_LOOSE 2 -// Stationary gas tanks +//Stationary gas tanks #define TANK_FRAME 0 #define TANK_PLATING_UNSECURED 1 diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index d9514d735d0f1..90485367815f6 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -78,28 +78,30 @@ #define ALIEN_BODYPART "alien" #define LARVA_BODYPART "larva" -//Bodytype defines for how things can be worn, surgery, and other misc things. +//Bodytype defines for surgery, and other misc things. ///The limb is organic. #define BODYTYPE_ORGANIC (1<<0) ///The limb is robotic. #define BODYTYPE_ROBOTIC (1<<1) +///A placeholder bodytype for xeno larva, so their limbs cannot be attached to anything. +#define BODYTYPE_LARVA_PLACEHOLDER (1<<2) +///The limb is from a xenomorph. +#define BODYTYPE_ALIEN (1<<3) +///The limb is from a golem +#define BODYTYPE_GOLEM (1<<4) + +// Bodyshape defines for how things can be worn, i.e., what "shape" the mob sprite is ///The limb fits the human mold. This is not meant to be literal, if the sprite "fits" on a human, it is "humanoid", regardless of origin. -#define BODYTYPE_HUMANOID (1<<2) +#define BODYSHAPE_HUMANOID (1<<0) ///The limb fits the monkey mold. -#define BODYTYPE_MONKEY (1<<3) +#define BODYSHAPE_MONKEY (1<<1) ///The limb is digitigrade. -#define BODYTYPE_DIGITIGRADE (1<<4) +#define BODYSHAPE_DIGITIGRADE (1<<2) ///The limb is snouted. -#define BODYTYPE_SNOUTED (1<<5) -///A placeholder bodytype for xeno larva, so their limbs cannot be attached to anything. -#define BODYTYPE_LARVA_PLACEHOLDER (1<<6) -///The limb is from a xenomorph. -#define BODYTYPE_ALIEN (1<<7) -///The limb is from a golem -#define BODYTYPE_GOLEM (1<<8) +#define BODYSHAPE_SNOUTED (1<<3) -#define BODYTYPE_BIOSCRAMBLE_COMPATIBLE (BODYTYPE_HUMANOID | BODYTYPE_MONKEY | BODYTYPE_ALIEN) -#define BODYTYPE_CAN_BE_BIOSCRAMBLED(bodytype) (!(bodytype & BODYTYPE_ROBOTIC) && (bodytype & BODYTYPE_BIOSCRAMBLE_COMPATIBLE)) +#define BODYTYPE_BIOSCRAMBLE_INCOMPATIBLE (BODYTYPE_ROBOTIC | BODYTYPE_LARVA_PLACEHOLDER | BODYTYPE_GOLEM) +#define BODYTYPE_CAN_BE_BIOSCRAMBLED(bodytype) (!(bodytype & BODYTYPE_BIOSCRAMBLE_INCOMPATIBLE)) // Defines for Species IDs. Used to refer to the name of a species, for things like bodypart names or species preferences. #define SPECIES_ABDUCTOR "abductor" diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 648f86ff9999c..eef432fb2edfe 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -211,8 +211,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_BLOOD_DEFICIENCY "blood_deficiency" #define TRAIT_JOLLY "jolly" #define TRAIT_NOCRITDAMAGE "no_crit" -/// Prevents shovies against a dense object from knocking them down. -#define TRAIT_SHOVE_KNOCKDOWN_BLOCKED "shove_knockdown_blocked" +/// Prevents shovies and some strong blows such as unarmed punches and (unreliably) tackles the owner down +#define TRAIT_BRAWLING_KNOCKDOWN_BLOCKED "brawling_knockdown_blocked" +/// Prevents some severe head injuries being sustained from heavy collisions or blunt force injuries. +#define TRAIT_HEAD_INJURY_BLOCKED "head_injury_blocked" /// Prevents staggering. #define TRAIT_NO_STAGGER "no_stagger" /// Getting hit by thrown movables won't push you away diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 1d17aea8a76e8..4135428194b8f 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -374,10 +374,6 @@ DEFINE_BITFIELD(reaction_flags, list( DEFINE_BITFIELD(bodytype, list( "BODYTYPE_ORGANIC" = BODYTYPE_ORGANIC, "BODYTYPE_ROBOTIC" = BODYTYPE_ROBOTIC, - "BODYTYPE_HUMANOID" = BODYTYPE_HUMANOID, - "BODYTYPE_MONKEY" = BODYTYPE_MONKEY, - "BODYTYPE_DIGITIGRADE" = BODYTYPE_DIGITIGRADE, - "BODYTYPE_SNOUTED" = BODYTYPE_SNOUTED, "BODYTYPE_LARVA_PLACEHOLDER" = BODYTYPE_LARVA_PLACEHOLDER, "BODYTYPE_ALIEN" = BODYTYPE_ALIEN, "BODYTYPE_GOLEM" = BODYTYPE_GOLEM, @@ -386,15 +382,25 @@ DEFINE_BITFIELD(bodytype, list( DEFINE_BITFIELD(acceptable_bodytype, list( "BODYTYPE_ORGANIC" = BODYTYPE_ORGANIC, "BODYTYPE_ROBOTIC" = BODYTYPE_ROBOTIC, - "BODYTYPE_HUMANOID" = BODYTYPE_HUMANOID, - "BODYTYPE_MONKEY" = BODYTYPE_MONKEY, - "BODYTYPE_DIGITIGRADE" = BODYTYPE_DIGITIGRADE, - "BODYTYPE_SNOUTED" = BODYTYPE_SNOUTED, "BODYTYPE_LARVA_PLACEHOLDER" = BODYTYPE_LARVA_PLACEHOLDER, "BODYTYPE_ALIEN" = BODYTYPE_ALIEN, "BODYTYPE_GOLEM" = BODYTYPE_GOLEM, )) +DEFINE_BITFIELD(bodyshape, list( + "BODYSHAPE_HUMANOID" = BODYSHAPE_HUMANOID, + "BODYSHAPE_MONKEY" = BODYSHAPE_MONKEY, + "BODYSHAPE_DIGITIGRADE" = BODYSHAPE_DIGITIGRADE, + "BODYSHAPE_SNOUTED" = BODYSHAPE_SNOUTED, +)) + +DEFINE_BITFIELD(acceptable_bodyshape, list( + "BODYSHAPE_HUMANOID" = BODYSHAPE_HUMANOID, + "BODYSHAPE_MONKEY" = BODYSHAPE_MONKEY, + "BODYSHAPE_DIGITIGRADE" = BODYSHAPE_DIGITIGRADE, + "BODYSHAPE_SNOUTED" = BODYSHAPE_SNOUTED, +)) + DEFINE_BITFIELD(bodypart_flags, list( "BODYPART_UNREMOVABLE" = BODYPART_UNREMOVABLE, "BODYPART_PSEUDOPART" = BODYPART_PSEUDOPART, diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 83157bd6202a3..15715ebd0a050 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -140,6 +140,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BONSAI" = TRAIT_BONSAI, "TRAIT_BOOZE_SLIDER" = TRAIT_BOOZE_SLIDER, "TRAIT_BRAINWASHING" = TRAIT_BRAINWASHING, + "TRAIT_BRAWLING_KNOCKDOWN_BLOCKED" = TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, "TRAIT_BYPASS_EARLY_IRRADIATED_CHECK" = TRAIT_BYPASS_EARLY_IRRADIATED_CHECK, "TRAIT_BYPASS_MEASURES" = TRAIT_BYPASS_MEASURES, "TRAIT_CANNOT_BE_UNBUCKLED" = TRAIT_CANNOT_BE_UNBUCKLED, @@ -237,6 +238,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_HAS_CRANIAL_FISSURE" = TRAIT_HAS_CRANIAL_FISSURE, "TRAIT_HAS_MARKINGS" = TRAIT_HAS_MARKINGS, "TRAIT_HATED_BY_DOGS" = TRAIT_HATED_BY_DOGS, + "TRAIT_HEAD_INJURY_BLOCKED" = TRAIT_HEAD_INJURY_BLOCKED, "TRAIT_HEALS_FROM_CARP_RIFTS" = TRAIT_HEALS_FROM_CARP_RIFTS, "TRAIT_HEALS_FROM_CULT_PYLONS" = TRAIT_HEALS_FROM_CULT_PYLONS, "TRAIT_HEAR_THROUGH_DARKNESS" = TRAIT_HEAR_THROUGH_DARKNESS, @@ -399,7 +401,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_SHAVED" = TRAIT_SHAVED, "TRAIT_SHIFTY_EYES" = TRAIT_SHIFTY_EYES, "TRAIT_SHOCKIMMUNE" = TRAIT_SHOCKIMMUNE, - "TRAIT_SHOVE_KNOCKDOWN_BLOCKED" = TRAIT_SHOVE_KNOCKDOWN_BLOCKED, "TRAIT_SIGN_LANG" = TRAIT_SIGN_LANG, "TRAIT_PAPER_MASTER" = TRAIT_PAPER_MASTER, "TRAIT_SILENT_FOOTSTEPS" = TRAIT_SILENT_FOOTSTEPS, diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index c1f3850c331fc..d9a0118a06ded 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -390,7 +390,7 @@ glasses.add_mob_blood(src) update_worn_glasses() - if(!attacking_item.get_sharpness() && armor_block < 50) + if(!attacking_item.get_sharpness() && !HAS_TRAIT(src, TRAIT_HEAD_INJURY_BLOCKED)) if(prob(damage_done)) adjustOrganLoss(ORGAN_SLOT_BRAIN, 20) if(stat == CONSCIOUS) @@ -420,7 +420,7 @@ w_uniform.add_mob_blood(src) update_worn_undersuit() - if(stat == CONSCIOUS && !attacking_item.get_sharpness() && armor_block < 50) + if(stat == CONSCIOUS && !attacking_item.get_sharpness() && !HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) if(prob(damage_done)) visible_message( span_danger("[src] is knocked down!"), diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index ec79374cb4fdb..f46ab02433ddc 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -117,7 +117,7 @@ return FALSE return TRUE -/atom/ui_status(mob/user) +/atom/ui_status(mob/user, datum/ui_state/state) . = ..() //Check if both user and atom are at the same location if(!can_interact(user)) diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm index 0f7fe6ef142f2..144de535d5a84 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm @@ -8,7 +8,8 @@ . = ..() if(!controller.blackboard[targeting_strategy_key]) CRASH("No targeting strategy was supplied in the blackboard for [controller.pawn]") - + if(HAS_TRAIT(controller.pawn, TRAIT_HANDS_BLOCKED)) + return FALSE //Hiding location is priority var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key] if(QDELETED(target)) @@ -67,6 +68,8 @@ /datum/ai_behavior/basic_ranged_attack/setup(datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) . = ..() + if(HAS_TRAIT(controller.pawn, TRAIT_HANDS_BLOCKED)) + return FALSE var/atom/target = controller.blackboard[hiding_location_key] || controller.blackboard[target_key] if(QDELETED(target)) return FALSE diff --git a/code/datums/ai/monkey/monkey_controller.dm b/code/datums/ai/monkey/monkey_controller.dm index ecfedb86dafd5..215f0a96302f3 100644 --- a/code/datums/ai/monkey/monkey_controller.dm +++ b/code/datums/ai/monkey/monkey_controller.dm @@ -76,7 +76,8 @@ have ways of interacting with a specific mob and control it. return AI_CONTROLLER_INCOMPATIBLE var/mob/living/living_pawn = new_pawn - living_pawn.AddElement(/datum/element/relay_attackers) + if(!HAS_TRAIT(living_pawn, TRAIT_RELAYING_ATTACKER)) + living_pawn.AddElement(/datum/element/relay_attackers) RegisterSignal(new_pawn, COMSIG_ATOM_WAS_ATTACKED, PROC_REF(on_attacked)) RegisterSignal(new_pawn, COMSIG_LIVING_START_PULL, PROC_REF(on_startpulling)) RegisterSignal(new_pawn, COMSIG_LIVING_TRY_SYRINGE, PROC_REF(on_try_syringe)) diff --git a/code/datums/components/creamed.dm b/code/datums/components/creamed.dm index d1c76b4759dba..be536bb792d97 100644 --- a/code/datums/components/creamed.dm +++ b/code/datums/components/creamed.dm @@ -39,9 +39,9 @@ GLOBAL_LIST_INIT(creamable, typecacheof(list( qdel(src) return bodypart_overlay = new() - if(carbon_parent.bodytype & BODYTYPE_SNOUTED) //stupid, but external organ bodytypes are not stored on the limb + if(carbon_parent.bodyshape & BODYSHAPE_SNOUTED) //stupid, but external organ bodytypes are not stored on the limb bodypart_overlay.icon_state = "creampie_lizard" - else if(my_head.bodytype & BODYTYPE_MONKEY) + else if(my_head.bodyshape & BODYSHAPE_MONKEY) bodypart_overlay.icon_state = "creampie_monkey" else bodypart_overlay.icon_state = "creampie_human" diff --git a/code/datums/components/payment.dm b/code/datums/components/payment.dm index 005cd1fe03ea7..1220614e9c386 100644 --- a/code/datums/components/payment.dm +++ b/code/datums/components/payment.dm @@ -114,8 +114,7 @@ physical_cash_total -= total_cost if(physical_cash_total > 0) - var/obj/item/holochip/holochange = new /obj/item/holochip(user.loc) //Change is made in holocredits exclusively. - holochange.credits = physical_cash_total + var/obj/item/holochip/holochange = new /obj/item/holochip(user.loc, physical_cash_total) //Change is made in holocredits exclusively. holochange.name = "[holochange.credits] credit holochip" if(ishuman(user)) var/mob/living/carbon/human/paying_customer = user diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm index 7d724f1c9effa..d19ef45e4b648 100644 --- a/code/datums/components/tackle.dm +++ b/code/datums/components/tackle.dm @@ -400,7 +400,7 @@ defense_mod += 2 if(tackle_target.mob_negates_gravity()) defense_mod += 1 - if(HAS_TRAIT(tackle_target, TRAIT_SHOVE_KNOCKDOWN_BLOCKED)) // riot armor and such + if(HAS_TRAIT(tackle_target, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) // riot armor and such defense_mod += 5 var/obj/item/organ/external/tail/lizard/el_tail = tackle_target.get_organ_slot(ORGAN_SLOT_EXTERNAL_TAIL) @@ -451,7 +451,7 @@ attack_mod += 15 human_sacker.adjustStaminaLoss(100) //AHAHAHAHAHAHAHAHA - if(HAS_TRAIT(human_sacker, TRAIT_SHOVE_KNOCKDOWN_BLOCKED)) // tackling with riot specialized armor, like riot armor, is effective but tiring + if(HAS_TRAIT(human_sacker, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) // tackling with riot specialized armor, like riot armor, is effective but tiring attack_mod += 2 human_sacker.adjustStaminaLoss(20) @@ -499,14 +499,10 @@ 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 + if(HAS_TRAIT(user, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) + oopsie_mod -= 6 + if(HAS_TRAIT(user, TRAIT_HEAD_INJURY_BLOCKED)) + oopsie_mod -= 6 if(HAS_TRAIT(user, TRAIT_CLUMSY)) oopsie_mod += 6 //honk! diff --git a/code/datums/components/tactical.dm b/code/datums/components/tactical.dm index 4f9f00c0668b3..59df008b2b100 100644 --- a/code/datums/components/tactical.dm +++ b/code/datums/components/tactical.dm @@ -1,15 +1,19 @@ ///A simple component that replacess the user's appearance with that of the parent item when equipped. /datum/component/tactical - ///The allowed slot(s) for the effect. - var/allowed_slot + ///The allowed slots for the effect. + var/allowed_slots ///A cached of where the item is currently equipped. var/current_slot -/datum/component/tactical/Initialize(allowed_slot) +/datum/component/tactical/Initialize(allowed_slots) if(!isitem(parent)) return COMPONENT_INCOMPATIBLE - src.allowed_slot = allowed_slot + src.allowed_slots = allowed_slots + +/datum/component/tactical/Destroy() + unmodify() + return ..() /datum/component/tactical/RegisterWithParent() RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(modify)) @@ -24,32 +28,39 @@ )) unmodify() -/datum/component/tactical/Destroy() - unmodify() - return ..() - /datum/component/tactical/proc/modify(obj/item/source, mob/user, slot) SIGNAL_HANDLER + if(current_slot == slot) + return - if(allowed_slot && !(slot & allowed_slot)) + if(allowed_slots && !(slot & allowed_slots)) if(current_slot) unmodify(source, user) return RegisterSignal(parent, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(tactical_update)) RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(unmodify)) - RegisterSignal(parent, COMSIG_ATOM_UPDATED_ICON, PROC_REF(tactical_update)) + RegisterSignal(parent, COMSIG_ATOM_UPDATED_ICON, PROC_REF(on_icon_update)) RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) current_slot = slot + on_icon_update(source) + +/datum/component/tactical/proc/on_icon_update(obj/item/source) + SIGNAL_HANDLER + var/mob/user = source.loc + if(!istype(user)) + return + + user.remove_alt_appearance("sneaking_mission[REF(src)]") var/obj/item/master = parent var/image/image = image(master, loc = user) image.copy_overlays(master) image.override = TRUE image.layer = ABOVE_MOB_LAYER image.plane = FLOAT_PLANE - source.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/everyone, "sneaking_mission[REF(src)]", image) + user.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/everyone, "sneaking_mission[REF(src)]", image) /datum/component/tactical/proc/unmodify(obj/item/source, mob/user) SIGNAL_HANDLER @@ -60,10 +71,16 @@ if(!istype(user)) return - user.remove_alt_appearance("sneaking_mission[REF(src)]") + UnregisterSignal(source, list( + COMSIG_MOVABLE_Z_CHANGED, + COMSIG_ITEM_DROPPED, + COMSIG_MOVABLE_MOVED, + COMSIG_ATOM_UPDATED_ICON, + )) current_slot = null - UnregisterSignal(parent, list(COMSIG_MOVABLE_Z_CHANGED, COMSIG_ITEM_DROPPED, COMSIG_ATOM_UPDATED_ICON, COMSIG_MOVABLE_MOVED)) + user.remove_alt_appearance("sneaking_mission[REF(src)]") +///Checks if a mob is holding us, and if so we will modify our appearance to properly match w/ the mob. /datum/component/tactical/proc/tactical_update(obj/item/source) SIGNAL_HANDLER if(!ismob(source.loc)) diff --git a/code/datums/components/twohanded.dm b/code/datums/components/twohanded.dm index 464f1a58a07ff..45ee6697e5302 100644 --- a/code/datums/components/twohanded.dm +++ b/code/datums/components/twohanded.dm @@ -2,21 +2,32 @@ * Two Handed Component * * When applied to an item it will make it two handed - * + * Only one of the component can exist on an item. */ /datum/component/two_handed - dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS // Only one of the component can exist on an item - var/wielded = FALSE /// Are we holding the two handed item properly - var/force_multiplier = 0 /// The multiplier applied to force when wielded, does not work with force_wielded, and force_unwielded - var/force_wielded = 0 /// The force of the item when weilded - var/force_unwielded = 0 /// The force of the item when unweilded - var/wieldsound = FALSE /// Play sound when wielded - var/unwieldsound = FALSE /// Play sound when unwielded - var/attacksound = FALSE /// Play sound on attack when wielded - var/require_twohands = FALSE /// Does it have to be held in both hands - var/icon_wielded = FALSE /// The icon that will be used when wielded - var/obj/item/offhand/offhand_item = null /// Reference to the offhand created for the item - var/sharpened_increase = 0 /// The amount of increase recived from sharpening the item + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + /// Are we holding the two handed item properly + var/wielded = FALSE + /// The multiplier applied to force when wielded, does not work with force_wielded, and force_unwielded + var/force_multiplier = 0 + /// The force of the item when weilded + var/force_wielded = 0 + /// The force of the item when unweilded + var/force_unwielded = 0 + /// Boolean whether to play sound when wielded + var/wieldsound = FALSE + /// Boolean whether to play sound when unwielded + var/unwieldsound = FALSE + /// Boolean whether to play sound on attack, if wielded + var/attacksound = FALSE + /// Boolean on whether it has to be held in both hands + var/require_twohands = FALSE + /// The icon that will be used when wielded + var/icon_wielded = FALSE + /// Reference to the offhand created for the item + var/obj/item/offhand/offhand_item = null + /// The amount of increase recived from sharpening the item + var/sharpened_increase = 0 /// A callback on the parent to be called when the item is wielded var/datum/callback/wield_callback /// A callback on the parent to be called when the item is unwielded @@ -36,9 +47,18 @@ * * force_unwielded (optional) The force setting when the item is unwielded, do not use with force_multiplier * * icon_wielded (optional) The icon to be used when wielded */ -/datum/component/two_handed/Initialize(require_twohands=FALSE, wieldsound=FALSE, unwieldsound=FALSE, attacksound=FALSE, \ - force_multiplier=0, force_wielded=0, force_unwielded=0, icon_wielded=FALSE, \ - datum/callback/wield_callback, datum/callback/unwield_callback) +/datum/component/two_handed/Initialize( + require_twohands = FALSE, + wieldsound = FALSE, + unwieldsound = FALSE, + attacksound = FALSE, + force_multiplier = 0, + force_wielded = 0, + force_unwielded = 0, + icon_wielded = FALSE, + datum/callback/wield_callback, + datum/callback/unwield_callback, +) if(!isitem(parent)) return COMPONENT_INCOMPATIBLE @@ -63,9 +83,20 @@ return ..() // Inherit the new values passed to the component -/datum/component/two_handed/InheritComponent(datum/component/two_handed/new_comp, original, require_twohands, wieldsound, unwieldsound, attacksound, \ - force_multiplier, force_wielded, force_unwielded, icon_wielded, \ - datum/callback/wield_callback, datum/callback/unwield_callback) +/datum/component/two_handed/InheritComponent( + datum/component/two_handed/new_comp, + original, + require_twohands, + wieldsound, + unwieldsound, + attacksound, + force_multiplier, + force_wielded, + force_unwielded, + icon_wielded, + datum/callback/wield_callback, + datum/callback/unwield_callback, +) if(!original) return if(require_twohands) @@ -101,32 +132,19 @@ RegisterSignal(parent, COMSIG_ITEM_APPLY_FANTASY_BONUSES, PROC_REF(apply_fantasy_bonuses)) RegisterSignal(parent, COMSIG_ITEM_REMOVE_FANTASY_BONUSES, PROC_REF(remove_fantasy_bonuses)) -/datum/component/two_handed/proc/apply_fantasy_bonuses(obj/item/source, bonus) - SIGNAL_HANDLER - force_wielded = source.modify_fantasy_variable("force_wielded", force_wielded, bonus) - force_unwielded = source.modify_fantasy_variable("force_unwielded", force_unwielded, bonus) - if(wielded && ismob(source.loc)) - unwield(source.loc) - if(force_multiplier) - force_multiplier = source.modify_fantasy_variable("force_multiplier", force_multiplier, bonus/10, minimum = 1) - -/datum/component/two_handed/proc/remove_fantasy_bonuses(obj/item/source, bonus) - SIGNAL_HANDLER - force_wielded = source.reset_fantasy_variable("force_wielded", force_wielded) - force_unwielded = source.reset_fantasy_variable("force_unwielded", force_unwielded) - if(wielded && ismob(source.loc)) - unwield(source.loc) - force_multiplier = source.reset_fantasy_variable("force_multiplier", force_multiplier) - // Remove all siginals registered to the parent item /datum/component/two_handed/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_ITEM_EQUIPPED, - COMSIG_ITEM_DROPPED, - COMSIG_ITEM_ATTACK_SELF, - COMSIG_ITEM_ATTACK, - COMSIG_ATOM_UPDATE_ICON, - COMSIG_MOVABLE_MOVED, - COMSIG_ITEM_SHARPEN_ACT)) + UnregisterSignal(parent, list( + COMSIG_ITEM_EQUIPPED, + COMSIG_ITEM_DROPPED, + COMSIG_ITEM_ATTACK_SELF, + COMSIG_ITEM_ATTACK, + COMSIG_ATOM_UPDATE_ICON, + COMSIG_MOVABLE_MOVED, + COMSIG_ITEM_SHARPEN_ACT, + COMSIG_ITEM_APPLY_FANTASY_BONUSES, + COMSIG_ITEM_REMOVE_FANTASY_BONUSES, + )) /// Triggered on equip of the item containing the component /datum/component/two_handed/proc/on_equip(datum/source, mob/user, slot) @@ -365,9 +383,25 @@ sharpened_increase = min(amount, (max_amount - wielded_val)) return COMPONENT_BLOCK_SHARPEN_APPLIED +/datum/component/two_handed/proc/apply_fantasy_bonuses(obj/item/source, bonus) + SIGNAL_HANDLER + force_wielded = source.modify_fantasy_variable("force_wielded", force_wielded, bonus) + force_unwielded = source.modify_fantasy_variable("force_unwielded", force_unwielded, bonus) + if(wielded && ismob(source.loc)) + unwield(source.loc) + if(force_multiplier) + force_multiplier = source.modify_fantasy_variable("force_multiplier", force_multiplier, bonus/10, minimum = 1) + +/datum/component/two_handed/proc/remove_fantasy_bonuses(obj/item/source, bonus) + SIGNAL_HANDLER + force_wielded = source.reset_fantasy_variable("force_wielded", force_wielded) + force_unwielded = source.reset_fantasy_variable("force_unwielded", force_unwielded) + if(wielded && ismob(source.loc)) + unwield(source.loc) + force_multiplier = source.reset_fantasy_variable("force_multiplier", force_multiplier) + /** * The offhand dummy item for two handed items - * */ /obj/item/offhand name = "offhand" diff --git a/code/datums/elements/decals/blood.dm b/code/datums/elements/decals/blood.dm index ec09caed73d59..7984939cddc87 100644 --- a/code/datums/elements/decals/blood.dm +++ b/code/datums/elements/decals/blood.dm @@ -9,10 +9,14 @@ /datum/element/decal/blood/Detach(atom/source) UnregisterSignal(source, COMSIG_ATOM_GET_EXAMINE_NAME) + if(isitem(source)) + var/obj/item/source_item = source + REMOVE_KEEP_TOGETHER(source_item, type) return ..() /datum/element/decal/blood/generate_appearance(_icon, _icon_state, _dir, _plane, _layer, _color, _alpha, _smoothing, source) var/obj/item/I = source + ADD_KEEP_TOGETHER(I, type) var/icon = I.icon var/icon_state = I.icon_state if(!icon || !icon_state) diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index 823585a9d7369..99438be18cc02 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -277,7 +277,7 @@ /datum/wires/ui_host() return holder -/datum/wires/ui_status(mob/user) +/datum/wires/ui_status(mob/user, datum/ui_state/state) if(interactable(user)) return ..() return UI_CLOSE diff --git a/code/game/machinery/computer/arcade/arcade.dm b/code/game/machinery/computer/arcade/arcade.dm index b9e8bd9d1e9e4..91a10673dd6dd 100644 --- a/code/game/machinery/computer/arcade/arcade.dm +++ b/code/game/machinery/computer/arcade/arcade.dm @@ -71,8 +71,9 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( /obj/item/storage/box/party_poppers = 2)) /obj/machinery/computer/arcade - name = "random arcade" - desc = "random arcade machine" + name = "\proper the arcade cabinet which shouldn't exist" + desc = "This arcade cabinet has no games installed, and in fact, should not exist. \ + Report the location of this machine to your local diety." icon_state = "arcade" icon_keyboard = null icon_screen = "invaders" @@ -136,19 +137,21 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( new empprize(loc) explosion(src, devastation_range = -1, light_impact_range = 1+num_of_prizes, flame_range = 1+num_of_prizes) -/obj/machinery/computer/arcade/attackby(obj/item/O, mob/user, params) - if(istype(O, /obj/item/stack/arcadeticket)) - var/obj/item/stack/arcadeticket/T = O - var/amount = T.get_amount() - if(amount <2) - to_chat(user, span_warning("You need 2 tickets to claim a prize!")) - return - prizevend(user) - T.pay_tickets() - T.update_appearance() - O = T - to_chat(user, span_notice("You turn in 2 tickets to the [src] and claim a prize!")) - return +/obj/machinery/computer/arcade/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) + . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + return . + if(!istype(tool, /obj/item/stack/arcadeticket)) + return . + + var/obj/item/stack/arcadeticket/tickets = tool + if(!tickets.use(2)) + balloon_alert(user, "need 2 tickets!") + return ITEM_INTERACT_BLOCKING + + prizevend(user) + balloon_alert(user, "prize claimed") + return ITEM_INTERACT_SUCCESS // ** BATTLE ** // /obj/machinery/computer/arcade/battle diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index dd933ba5e041f..ea2fbb3eb8eda 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -9,6 +9,92 @@ /obj/structure/frame/computer/Initialize(mapload) . = ..() AddComponent(/datum/component/simple_rotation) + register_context() + update_appearance(UPDATE_ICON_STATE) + +/obj/structure/frame/computer/deconstruct(disassembled = TRUE) + if(!(obj_flags & NO_DECONSTRUCTION)) + var/atom/drop_loc = drop_location() + if(state == FRAME_COMPUTER_STATE_GLASSED) + if(disassembled) + new /obj/item/stack/sheet/glass(drop_loc, 2) + else + new /obj/item/shard(drop_loc) + new /obj/item/shard(drop_loc) + if(state >= FRAME_COMPUTER_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_loc, 5) + + return ..() + +/obj/structure/frame/computer/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = NONE + if(isnull(held_item)) + return + + switch(state) + if(FRAME_COMPUTER_STATE_EMPTY) + if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Un" : ""]anchor" + return CONTEXTUAL_SCREENTIP_SET + else if(anchored && istype(held_item, /obj/item/circuitboard/computer)) + context[SCREENTIP_CONTEXT_LMB] = "Install board" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_WELDER) + context[SCREENTIP_CONTEXT_LMB] = "Unweld frame" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Disassemble frame" + return CONTEXTUAL_SCREENTIP_SET + if(FRAME_COMPUTER_STATE_BOARD_INSTALLED) + if(held_item.tool_behaviour == TOOL_CROWBAR) + context[SCREENTIP_CONTEXT_LMB] = "Pry out board" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Secure board" + return CONTEXTUAL_SCREENTIP_SET + if(FRAME_COMPUTER_STATE_BOARD_SECURED) + if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Unsecure board" + return CONTEXTUAL_SCREENTIP_SET + else if(istype(held_item, /obj/item/stack/cable_coil)) + context[SCREENTIP_CONTEXT_LMB] = "Install cable" + return CONTEXTUAL_SCREENTIP_SET + if(FRAME_COMPUTER_STATE_WIRED) + if(held_item.tool_behaviour == TOOL_WIRECUTTER) + context[SCREENTIP_CONTEXT_LMB] = "Cut out cable" + return CONTEXTUAL_SCREENTIP_SET + else if(istype(held_item, /obj/item/stack/sheet/glass)) + context[SCREENTIP_CONTEXT_LMB] = "Install panel" + return CONTEXTUAL_SCREENTIP_SET + if(FRAME_COMPUTER_STATE_GLASSED) + if(held_item.tool_behaviour == TOOL_CROWBAR) + context[SCREENTIP_CONTEXT_LMB] = "Pry out glass" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Complete frame" + return CONTEXTUAL_SCREENTIP_SET + +/obj/structure/frame/computer/examine(user) + . = ..() + + switch(state) + if(FRAME_STATE_EMPTY) + . += span_notice("It can be [EXAMINE_HINT("wrenched")] [anchored ? "loose" : "in place"].") + if(anchored) + . += span_warning("It's missing a circuit board.") + . += span_notice("It can be [EXAMINE_HINT("welded")] or [EXAMINE_HINT("screwed")] apart.") + if(FRAME_COMPUTER_STATE_BOARD_INSTALLED) + . += span_warning("An [circuit.name] is installed and should be [EXAMINE_HINT("screwed")] in place.") + . += span_notice("The circuit board can be [EXAMINE_HINT("pried")] out.") + if(FRAME_COMPUTER_STATE_BOARD_SECURED) + . += span_warning("Its requires [EXAMINE_HINT("5 cable")] pieces to wire it.") + . += span_notice("The circuit board can be [EXAMINE_HINT("screwed")] loose.") + if(FRAME_COMPUTER_STATE_WIRED) + . += span_notice("The wires can be cut out with [EXAMINE_HINT("wire cutters")].") + . += span_warning("Its requires [EXAMINE_HINT("2 glass")] sheets to complete the screen.") + if(FRAME_COMPUTER_STATE_GLASSED) + . += span_notice("The screen can be [EXAMINE_HINT("pried")] out.") + . += span_notice("The moniter can be [EXAMINE_HINT("screwed")] to complete it") /obj/structure/frame/computer/circuit_added(obj/item/circuitboard/added) state = FRAME_COMPUTER_STATE_BOARD_INSTALLED @@ -22,7 +108,45 @@ if(state != FRAME_COMPUTER_STATE_EMPTY) balloon_alert(user, "circuit already installed!") return FALSE - return ..() + if(!anchored && istype(board)) + balloon_alert(user, "frame must be anchored!") + return FALSE + . = ..() + if(. && !by_hand) // Installing via RPED auto-secures it + state = FRAME_COMPUTER_STATE_BOARD_SECURED + update_appearance(UPDATE_ICON_STATE) + return . + +/obj/structure/frame/computer/install_parts_from_part_replacer(mob/living/user, obj/item/storage/part_replacer/replacer, no_sound = FALSE) + switch(state) + if(FRAME_COMPUTER_STATE_BOARD_SECURED) + var/obj/item/stack/cable_coil/cable = locate() in replacer + if(isnull(cable)) + return FALSE + + if(add_cabling(user, cable, time = 0)) + if(!no_sound) + replacer.play_rped_sound() + if(replacer.works_from_distance) + user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) + no_sound = TRUE + return install_parts_from_part_replacer(user, replacer, no_sound = no_sound) // Recursive call to handle the next part + + return FALSE + + if(FRAME_COMPUTER_STATE_WIRED) + var/obj/item/stack/sheet/glass/glass_sheets = locate() in replacer + if(isnull(glass_sheets)) + return FALSE + + if(add_glass(user, glass_sheets, time = 0)) + if(!no_sound) + replacer.play_rped_sound() + if(replacer.works_from_distance) + user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) + return TRUE + + return FALSE /obj/structure/frame/computer/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) . = ..() @@ -48,11 +172,9 @@ if(istype(tool, /obj/item/storage/part_replacer)) return install_parts_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING - return . - /obj/structure/frame/computer/screwdriver_act(mob/living/user, obj/item/tool) . = ..() - if(. != NONE) + if(. & ITEM_INTERACT_ANY_BLOCKER) return . switch(state) @@ -83,6 +205,9 @@ return ITEM_INTERACT_BLOCKING /obj/structure/frame/computer/crowbar_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + switch(state) if(FRAME_COMPUTER_STATE_BOARD_INSTALLED) tool.play_tool_sound(src) @@ -92,14 +217,12 @@ return ITEM_INTERACT_SUCCESS if(FRAME_COMPUTER_STATE_BOARD_SECURED) - if(!user.combat_mode) - balloon_alert(user, "unsecure the circuit!") - return ITEM_INTERACT_BLOCKING + balloon_alert(user, "unsecure the circuit!") + return ITEM_INTERACT_BLOCKING if(FRAME_COMPUTER_STATE_WIRED) - if(!user.combat_mode) - balloon_alert(user, "remove the wiring!") - return ITEM_INTERACT_BLOCKING + balloon_alert(user, "remove the wiring!") + return ITEM_INTERACT_BLOCKING if(FRAME_COMPUTER_STATE_GLASSED) tool.play_tool_sound(src) @@ -111,38 +234,34 @@ dropped_glass.add_fingerprint(user) return ITEM_INTERACT_SUCCESS -/obj/structure/frame/computer/install_parts_from_part_replacer(mob/living/user, obj/item/storage/part_replacer/replacer, no_sound = FALSE) - switch(state) - if(FRAME_COMPUTER_STATE_BOARD_SECURED) - var/obj/item/stack/cable_coil/cable = locate() in replacer - if(isnull(cable)) - return FALSE - - if(add_cabling(user, cable, time = 0)) - if(!no_sound) - replacer.play_rped_sound() - if(replacer.works_from_distance) - user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) - no_sound = TRUE - return install_parts_from_part_replacer(user, replacer, no_sound = no_sound) // Recursive call to handle the next part - - return FALSE +/obj/structure/frame/computer/wirecutter_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE - if(FRAME_COMPUTER_STATE_WIRED) - var/obj/item/stack/sheet/glass/glass_sheets = locate() in replacer - if(isnull(glass_sheets)) - return FALSE + if(state != FRAME_COMPUTER_STATE_WIRED) + return ITEM_INTERACT_BLOCKING - if(add_glass(user, glass_sheets, time = 0)) - if(!no_sound) - replacer.play_rped_sound() - if(replacer.works_from_distance) - user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) - return TRUE + tool.play_tool_sound(src) + balloon_alert(user, "cables removed") + state = FRAME_COMPUTER_STATE_BOARD_SECURED + update_appearance(UPDATE_ICON_STATE) - return FALSE + var/obj/item/stack/cable_coil/dropped_cables = new (drop_location(), 5) + if (!QDELETED(dropped_cables)) + dropped_cables.add_fingerprint(user) + return ITEM_INTERACT_SUCCESS +/** + * Adds cable to the computer to wire it + * Arguments + * + * * mob/living/user - the player who is adding the cable + * * obj/item/stack/cable_coil/cable - the cable we are trying to add + * * time - time taken to complete the operation + */ /obj/structure/frame/computer/proc/add_cabling(mob/living/user, obj/item/stack/cable_coil/cable, time = 2 SECONDS) + PRIVATE_PROC(TRUE) + if(state != FRAME_COMPUTER_STATE_BOARD_SECURED) return FALSE if(!cable.tool_start_check(user, amount = 5)) @@ -156,7 +275,17 @@ update_appearance(UPDATE_ICON_STATE) return TRUE +/** + * Adds glass sheets to the computer to complete the screen + * Arguments + * + * * mob/living/user - the player who is adding the glass + * * obj/item/stack/sheet/glass/glass - the glass we are trying to add + * * time - time taken to complete the operation + */ /obj/structure/frame/computer/proc/add_glass(mob/living/user, obj/item/stack/sheet/glass/glass, time = 2 SECONDS) + PRIVATE_PROC(TRUE) + if(state != FRAME_COMPUTER_STATE_WIRED) return FALSE if(!glass.tool_start_check(user, amount = 2)) @@ -171,22 +300,6 @@ update_appearance(UPDATE_ICON_STATE) return TRUE -/obj/structure/frame/computer/wirecutter_act(mob/living/user, obj/item/tool) - if(state != FRAME_COMPUTER_STATE_WIRED) - return NONE - - tool.play_tool_sound(src) - balloon_alert(user, "cables removed") - state = FRAME_COMPUTER_STATE_BOARD_SECURED - update_appearance(UPDATE_ICON_STATE) - var/obj/item/stack/cable_coil/dropped_cables = new (drop_location(), 5) - if (!QDELETED(dropped_cables)) - dropped_cables.add_fingerprint(user) - return ITEM_INTERACT_SUCCESS - -/obj/structure/frame/computer/AltClick(mob/user) - return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation - /obj/structure/frame/computer/finalize_construction(mob/living/user, obj/item/tool) tool.play_tool_sound(src) var/obj/machinery/new_machine = new circuit.build_path(loc) @@ -217,20 +330,6 @@ qdel(src) return TRUE -/obj/structure/frame/computer/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - var/atom/drop_loc = drop_location() - if(state == FRAME_COMPUTER_STATE_GLASSED) - if(disassembled) - new /obj/item/stack/sheet/glass(drop_loc, 2) - else - new /obj/item/shard(drop_loc) - new /obj/item/shard(drop_loc) - if(state >= FRAME_COMPUTER_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_loc, 5) - - return ..() - /// Helpers for rcd /obj/structure/frame/computer/rcd icon = 'icons/hud/radial.dmi' diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index a1a1fe0ada2a9..37514c142fe8a 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -76,7 +76,7 @@ ui = new(user, src, "CameraConsole", name) ui.open() -/obj/machinery/computer/security/ui_status(mob/user) +/obj/machinery/computer/security/ui_status(mob/user, datum/ui_state/state) . = ..() if(. == UI_DISABLED) return UI_CLOSE diff --git a/code/game/machinery/computer/records/medical.dm b/code/game/machinery/computer/records/medical.dm index 362c8468aa6f4..c4242ace958d5 100644 --- a/code/game/machinery/computer/records/medical.dm +++ b/code/game/machinery/computer/records/medical.dm @@ -65,6 +65,7 @@ quirk_notes = target.quirk_notes, rank = target.rank, species = target.species, + trim = target.trim, )) data["records"] = records diff --git a/code/game/machinery/computer/records/security.dm b/code/game/machinery/computer/records/security.dm index 3a929f7a298a0..27b8e75e545ef 100644 --- a/code/game/machinery/computer/records/security.dm +++ b/code/game/machinery/computer/records/security.dm @@ -128,6 +128,7 @@ note = target.security_note, rank = target.rank, species = target.species, + trim = target.trim, wanted_status = target.wanted_status, )) diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index 6a1d2d60f8c8d..8a5efc193ca9f 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -24,7 +24,7 @@ new /obj/item/stack/sheet/iron(drop_loc, 5) circuit?.forceMove(drop_loc) - qdel(src) + return ..() /// Called when circuit has been set to a new board /obj/structure/frame/proc/circuit_added(obj/item/circuitboard/added) @@ -97,13 +97,13 @@ return FALSE /obj/structure/frame/wrench_act(mob/living/user, obj/item/tool) + . = NONE switch(default_unfasten_wrench(user, tool, 4 SECONDS)) if(SUCCESSFUL_UNFASTEN) return ITEM_INTERACT_SUCCESS if(FAILED_UNFASTEN) return ITEM_INTERACT_BLOCKING - - return NONE + return . /obj/structure/frame/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) . = ..() @@ -196,421 +196,3 @@ */ /obj/structure/frame/proc/install_parts_from_part_replacer(mob/living/user, obj/item/storage/part_replacer/replacer, no_sound = FALSE) return FALSE - -/obj/structure/frame/machine - name = "machine frame" - desc = "The standard frame for most station appliances. Its appearance and function is controlled by the inserted board." - board_type = /obj/item/circuitboard/machine - /// List of all compnents inside the frame contributing to its construction - var/list/components - /// List of all components required to construct the frame - var/list/req_components - /// User-friendly list of names of required components - var/list/req_component_names - -/obj/structure/frame/machine/examine(user) - . = ..() - if(state != FRAME_STATE_BOARD_INSTALLED) - return . - - if(!length(req_components)) - . += span_info("It requires no components.") - return . - - if(!req_component_names) - stack_trace("[src]'s req_components list has items but its req_component_names list is null!") - return . - - var/list/nice_list = list() - for(var/component in req_components) - if(!ispath(component)) - stack_trace("An item in [src]'s req_components list is not a path!") - continue - if(!req_components[component]) - continue - - nice_list += list("[req_components[component]] [req_component_names[component]]\s") - . += span_info("It requires [english_list(nice_list, "no more components")].") - return . - -/** - * Collates the displayed names of the machine's components - * - * Arguments: - * * specific_parts - If true, the component should not use base name, but a specific tier - */ -/obj/structure/frame/machine/proc/update_namelist(specific_parts) - if(!req_components) - return - - req_component_names = list() - for(var/component_path in req_components) - if(!ispath(component_path)) - continue - - if(ispath(component_path, /obj/item/stack)) - var/obj/item/stack/stack_path = component_path - if(initial(stack_path.singular_name)) - req_component_names[component_path] = initial(stack_path.singular_name) - else - req_component_names[component_path] = initial(stack_path.name) - else if(ispath(component_path, /datum/stock_part)) - var/datum/stock_part/stock_part = component_path - var/obj/item/physical_object_type = initial(stock_part.physical_object_type) - - req_component_names[component_path] = initial(physical_object_type.name) - else if(ispath(component_path, /obj/item/stock_parts)) - var/obj/item/stock_parts/stock_part = component_path - - if(!specific_parts && initial(stock_part.base_name)) - req_component_names[component_path] = initial(stock_part.base_name) - else - req_component_names[component_path] = initial(stock_part.name) - else if(ispath(component_path, /obj/item)) - var/obj/item/part = component_path - - req_component_names[component_path] = initial(part.name) - else - stack_trace("Invalid component part [component_path] in [type], couldn't get its name") - req_component_names[component_path] = "[component_path] (this is a bug)" - -/obj/structure/frame/machine/proc/get_req_components_amt() - var/amt = 0 - for(var/path in req_components) - amt += req_components[path] - return amt - -/obj/structure/frame/machine/try_dissassemble(mob/living/user, obj/item/tool, disassemble_time) - if(anchored) - balloon_alert(user, "must be unsecured first!") - return FALSE - return ..() - -/obj/structure/frame/machine/install_board(mob/living/user, obj/item/circuitboard/machine/board, by_hand = TRUE) - if(state == FRAME_STATE_EMPTY) - balloon_alert(user, "needs wiring!") - return FALSE - if(state == FRAME_STATE_BOARD_INSTALLED) - balloon_alert(user, "circuit already installed!") - return FALSE - if(!anchored && istype(board) && board.needs_anchored) - balloon_alert(user, "frame must be anchored!") - return FALSE - - return ..() - -/obj/structure/frame/machine/circuit_added(obj/item/circuitboard/machine/added) - state = FRAME_STATE_BOARD_INSTALLED - update_appearance(UPDATE_ICON_STATE) - //add circuit board as the first component to the list of components - //required for part_replacer to locate it while exchanging parts - //so it does not early return in /obj/machinery/proc/exchange_parts - components = list(circuit) - req_components = added.req_components.Copy() - update_namelist(added.specific_parts) - -/obj/structure/frame/machine/circuit_removed(obj/item/circuitboard/machine/removed) - state = FRAME_STATE_WIRED - update_appearance(UPDATE_ICON_STATE) - -/obj/structure/frame/machine/install_parts_from_part_replacer(mob/living/user, obj/item/storage/part_replacer/replacer, no_sound = FALSE) - if(!length(replacer.contents) || !get_req_components_amt()) - return FALSE - - var/play_sound = FALSE - var/list/part_list = replacer.get_sorted_parts() //parts sorted in order of tier - for(var/path in req_components) - var/target_path - if(ispath(path, /datum/stock_part)) - var/datum/stock_part/datum_part = path - target_path = initial(datum_part.physical_object_base_type) - else - target_path = path - - var/obj/item/part - while(req_components[path] > 0 && (part = look_for(part_list, target_path, ispath(path, /obj/item/stack/ore/bluespace_crystal) ? /obj/item/stack/sheet/bluespace_crystal : null))) - part_list -= part - if(istype(part, /obj/item/stack)) - var/obj/item/stack/S = part - var/used_amt = min(round(S.get_amount()), req_components[path]) - var/stack_name = S.singular_name - if(!used_amt || !S.use(used_amt)) - continue - req_components[path] -= used_amt - // No balloon alert here so they can look back and see what they added - to_chat(user, span_notice("You add [used_amt] [stack_name] to [src].")) - play_sound = TRUE - else if(replacer.atom_storage.attempt_remove(part, src)) - var/stock_part_datum = GLOB.stock_part_datums_per_object[part.type] - if (!isnull(stock_part_datum)) - components += stock_part_datum - qdel(part) - else - components += part - part.forceMove(src) - req_components[path]-- - // No balloon alert here so they can look back and see what they added - to_chat(user, span_notice("You add [part] to [src].")) - play_sound = TRUE - - if(play_sound && !no_sound) - replacer.play_rped_sound() - if(replacer.works_from_distance) - user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) - return TRUE - -/** - * Attempts to add the passed part to the frame - * - * Requires no sanity check that the passed part is a stock part - * - * Arguments - * * user - the player - * * tool - the part to add - */ -/obj/structure/frame/machine/proc/add_part(mob/living/user, obj/item/tool) - for(var/stock_part_base in req_components) - if (req_components[stock_part_base] == 0) - continue - - var/stock_part_path - - if(ispath(stock_part_base, /obj/item)) - stock_part_path = stock_part_base - else if(ispath(stock_part_base, /datum/stock_part)) - var/datum/stock_part/stock_part_datum_type = stock_part_base - stock_part_path = initial(stock_part_datum_type.physical_object_type) - else - stack_trace("Bad stock part in req_components: [stock_part_base]") - continue - - //if we require an bluespace crystall and we have an full sheet of them we can allow that - if(ispath(stock_part_path, /obj/item/stack/ore/bluespace_crystal) && istype(tool, /obj/item/stack/sheet/bluespace_crystal)) - //allow it - pass() - else if(!istype(tool, stock_part_path)) - continue - - if(isstack(tool)) - var/obj/item/stack/S = tool - var/used_amt = min(round(S.get_amount()), req_components[stock_part_path]) - if(used_amt && S.use(used_amt)) - req_components[stock_part_path] -= used_amt - // No balloon alert here so they can look back and see what they added - to_chat(user, span_notice("You add [tool] to [src].")) - return - - // We might end up qdel'ing the part if it's a stock part datum. - // In practice, this doesn't have side effects to the name, - // but academically we should not be using an object after it's deleted. - var/part_name = "[tool]" - - if (ispath(stock_part_base, /datum/stock_part)) - // We can't just reuse stock_part_path here or its singleton, - // or else putting in a tier 2 part will deconstruct to a tier 1 part. - var/stock_part_datum = GLOB.stock_part_datums_per_object[tool.type] - if (isnull(stock_part_datum)) - stack_trace("tool.type] does not have an associated stock part datum!") - continue - - components += stock_part_datum - - // We regenerate the stock parts on deconstruct. - // This technically means we lose unique qualities of the stock part, but - // it's worth it for how dramatically this simplifies the code. - // The only place I can see it affecting anything is like...RPG qualities. :P - qdel(tool) - else if(user.transferItemToLoc(tool, src)) - components += tool - else - break - - // No balloon alert here so they can look back and see what they added - to_chat(user, span_notice("You add [part_name] to [src].")) - req_components[stock_part_base]-- - return TRUE - - balloon_alert(user, "can't add that!") - return FALSE - -/** - * Attempt to finalize the construction of the frame into a machine - * as according to our circuit and parts - * - * If successful, results in qdel'ing the frame and newing of a machine - * - * Arguments - * * user - the player - * * tool - the tool used to finalize the construction - */ -/obj/structure/frame/machine/finalize_construction(mob/living/user, obj/item/tool) - for(var/component in req_components) - if(req_components[component] > 0) - user.balloon_alert(user, "missing components!") - return FALSE - - tool.play_tool_sound(src) - var/obj/machinery/new_machine = new circuit.build_path(loc) - if(istype(new_machine)) - new_machine.clear_components() - // Set anchor state - new_machine.set_anchored(anchored) - // Prevent us from dropping stuff thanks to /Exited - var/obj/item/circuitboard/machine/leaving_circuit = circuit - circuit = null - // Assign the circuit & parts & move them all at once into the machine - // no need to seperatly move circuit board as its already part of the components list - new_machine.circuit = leaving_circuit - new_machine.component_parts = components - for (var/obj/new_part in components) - new_part.forceMove(new_machine) - //Inform machine that its finished & cleanup - new_machine.RefreshParts() - new_machine.on_construction(user) - components = null - qdel(src) - return TRUE - -/obj/structure/frame/machine/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) - . = ..() - if(. & ITEM_INTERACT_ANY_BLOCKER) - return . - - switch(state) - if(FRAME_STATE_EMPTY) - if(istype(tool, /obj/item/stack/cable_coil)) - if(!tool.tool_start_check(user, amount = 5)) - return ITEM_INTERACT_BLOCKING - - balloon_alert(user, "adding cables...") - if(!tool.use_tool(src, user, 2 SECONDS, volume = 50, amount = 5) || state != FRAME_STATE_EMPTY) - return ITEM_INTERACT_BLOCKING - - state = FRAME_STATE_WIRED - update_appearance(UPDATE_ICON_STATE) - return ITEM_INTERACT_SUCCESS - - if(FRAME_STATE_WIRED) - if(isnull(circuit) && istype(tool, /obj/item/storage/part_replacer)) - return install_circuit_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING - - if(FRAME_STATE_BOARD_INSTALLED) - if(istype(tool, /obj/item/storage/part_replacer)) - return install_parts_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING - - if(!user.combat_mode) - return add_part(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING - - return . - -/obj/structure/frame/machine/screwdriver_act(mob/living/user, obj/item/tool) - . = ..() - if(. & ITEM_INTERACT_ANY_BLOCKER) - return . - if(state != FRAME_STATE_BOARD_INSTALLED) - return . - - if(finalize_construction(user, tool)) - return ITEM_INTERACT_SUCCESS - - return ITEM_INTERACT_BLOCKING - -/obj/structure/frame/machine/can_be_unfasten_wrench(mob/user, silent) - . = ..() - if(. != SUCCESSFUL_UNFASTEN) - return . - - if(circuit?.needs_anchored) - balloon_alert(user, "circuit must be anchored!") - return FAILED_UNFASTEN - - return . - -/obj/structure/frame/machine/wirecutter_act(mob/living/user, obj/item/tool) - if(state != FRAME_STATE_WIRED) - return NONE - - balloon_alert(user, "removing cables...") - if(!tool.use_tool(src, user, 2 SECONDS, volume = 50) || state != FRAME_STATE_WIRED) - return ITEM_INTERACT_BLOCKING - - state = FRAME_STATE_EMPTY - update_appearance(UPDATE_ICON_STATE) - new /obj/item/stack/cable_coil(drop_location(), 5) - return ITEM_INTERACT_SUCCESS - -/obj/structure/frame/machine/crowbar_act(mob/living/user, obj/item/tool) - if(state != FRAME_STATE_BOARD_INSTALLED) - return NONE - - tool.play_tool_sound(src) - var/list/leftover_components = components.Copy() - circuit - dump_contents() - balloon_alert(user, "circuit board[length(leftover_components) ? " and components" : ""] removed") - // Circuit exited handles updating state - return ITEM_INTERACT_SUCCESS - -/obj/structure/frame/machine/Exited(atom/movable/gone, direction) - if(gone == circuit) - components -= circuit - return ..() - -/obj/structure/frame/machine/Destroy() - QDEL_LIST(components) - return ..() - -/** - * Returns the instance of path1 in list, else path2 in list - * - * Arguments - * * parts - the list of parts to search - * * path1 - the first path to search for - * * path2 - the second path to search for, if path1 is not found - */ -/obj/structure/frame/machine/proc/look_for(list/parts, path1, path2) - return (locate(path1) in parts) || (path2 ? (locate(path2) in parts) : null) - -/obj/structure/frame/machine/deconstruct(disassembled = TRUE) - if(!(obj_flags & NO_DECONSTRUCTION)) - if(state >= FRAME_STATE_WIRED) - new /obj/item/stack/cable_coil(drop_location(), 5) - dump_contents() - return ..() - -/obj/structure/frame/machine/dump_contents() - var/atom/drop_loc = drop_location() - - // We need a snowflake check for stack items since they don't exist anymore - for(var/component in circuit?.req_components) - if(!ispath(component, /obj/item/stack)) - continue - var/obj/item/stack/stack_path = component - var/stack_amount = circuit.req_components[component] - req_components[component] - if(stack_amount > 0) - new stack_path(drop_loc, stack_amount) - - // Rest of the stuff can just be spat out (this includes the circuitboard0) - for(var/component in components) - if(ismovable(component)) - var/atom/movable/atom_component = component - atom_component.forceMove(drop_loc) - - else if(istype(component, /datum/stock_part)) - var/datum/stock_part/stock_part_datum = component - var/physical_object_type = initial(stock_part_datum.physical_object_type) - new physical_object_type(drop_loc) - - else - stack_trace("Invalid component [component] was found in constructable frame") - - components = null - req_components = null - req_component_names = null - -/obj/structure/frame/machine/secured - state = FRAME_STATE_WIRED - anchored = TRUE - -/obj/structure/frame/machine/secured/Initialize(mapload) - . = ..() - update_appearance(UPDATE_ICON_STATE) diff --git a/code/game/machinery/dance_machine.dm b/code/game/machinery/dance_machine.dm index 098c887f2a2d1..9d19d0d9be98b 100644 --- a/code/game/machinery/dance_machine.dm +++ b/code/game/machinery/dance_machine.dm @@ -44,7 +44,7 @@ icon_state = "[base_icon_state][music_player.active_song_sound ? "-active" : null]" return ..() -/obj/machinery/jukebox/ui_status(mob/user) +/obj/machinery/jukebox/ui_status(mob/user, datum/ui_state/state) if(isobserver(user)) return ..() if(!anchored) diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 7ed48a4c9c5ce..05c0fe242461f 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -46,6 +46,7 @@ Possible to do for anyone motivated enough: max_integrity = 300 armor_type = /datum/armor/machinery_holopad circuit = /obj/item/circuitboard/machine/holopad + interaction_flags_atom = parent_type::interaction_flags_atom | INTERACT_ATOM_IGNORE_MOBILITY // Blue, dim light light_power = 0.8 light_color = LIGHT_COLOR_BLUE @@ -271,7 +272,7 @@ Possible to do for anyone motivated enough: return ..() -/obj/machinery/holopad/ui_status(mob/user) +/obj/machinery/holopad/ui_status(mob/user, datum/ui_state/state) if(!is_operational) return UI_CLOSE if(outgoing_call && !calling) diff --git a/code/game/machinery/machine_frame.dm b/code/game/machinery/machine_frame.dm new file mode 100644 index 0000000000000..a3c074937f0f7 --- /dev/null +++ b/code/game/machinery/machine_frame.dm @@ -0,0 +1,474 @@ +/obj/structure/frame/machine + name = "machine frame" + desc = "The standard frame for most station appliances. Its appearance and function is controlled by the inserted board." + board_type = /obj/item/circuitboard/machine + /// List of all compnents inside the frame contributing to its construction + var/list/components + /// List of all components required to construct the frame + var/list/req_components + /// User-friendly list of names of required components + var/list/req_component_names + +/obj/structure/frame/machine/Initialize(mapload) + . = ..() + register_context() + update_appearance(UPDATE_ICON_STATE) + +/obj/structure/frame/machine/Destroy() + QDEL_LIST(components) + return ..() + +/obj/structure/frame/machine/deconstruct(disassembled = TRUE) + if(!(obj_flags & NO_DECONSTRUCTION)) + if(state >= FRAME_STATE_WIRED) + new /obj/item/stack/cable_coil(drop_location(), 5) + dump_contents() + return ..() + +/obj/structure/frame/machine/try_dissassemble(mob/living/user, obj/item/tool, disassemble_time) + if(anchored) + balloon_alert(user, "must be unsecured first!") + return FALSE + return ..() + +/obj/structure/frame/machine/add_context(atom/source, list/context, obj/item/held_item, mob/user) + . = NONE + if(isnull(held_item)) + return + + switch(state) + if(FRAME_STATE_EMPTY) + if(istype(held_item, /obj/item/stack/cable_coil)) + context[SCREENTIP_CONTEXT_LMB] = "Wire Frame" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Un" : ""]anchor" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_WELDER) + context[SCREENTIP_CONTEXT_LMB] = "Unweld frame" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Disassemble frame" + return CONTEXTUAL_SCREENTIP_SET + if(FRAME_STATE_WIRED) + if(held_item.tool_behaviour == TOOL_WIRECUTTER) + context[SCREENTIP_CONTEXT_LMB] = "Cut wires" + return CONTEXTUAL_SCREENTIP_SET + else if(istype(held_item, board_type)) + context[SCREENTIP_CONTEXT_LMB] = "Insert board" + return CONTEXTUAL_SCREENTIP_SET + if(FRAME_STATE_BOARD_INSTALLED) + if(held_item.tool_behaviour == TOOL_CROWBAR) + context[SCREENTIP_CONTEXT_LMB] = "Pry out components" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_WRENCH) + if(!circuit.needs_anchored) + context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Un" : ""]anchor" + return CONTEXTUAL_SCREENTIP_SET + return NONE + else if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + var/needs_components = FALSE + for(var/component in req_components) + if(!req_components[component]) + continue + needs_components = TRUE + break + if(!needs_components) + context[SCREENTIP_CONTEXT_LMB] = "Complete frame" + return CONTEXTUAL_SCREENTIP_SET + else if(!istype(held_item, /obj/item/storage/part_replacer)) + for(var/component in req_components) + if(!req_components[component]) + continue + var/stock_part_path + if(ispath(component, /obj/item)) + stock_part_path = component + else if(ispath(component, /datum/stock_part)) + var/datum/stock_part/stock_part_datum_type = component + stock_part_path = initial(stock_part_datum_type.physical_object_type) + if(istype(held_item, stock_part_path)) + context[SCREENTIP_CONTEXT_LMB] = "Insert part" + return CONTEXTUAL_SCREENTIP_SET + +/obj/structure/frame/machine/examine(user) + . = ..() + if(!circuit?.needs_anchored) + . += span_notice("It can be [EXAMINE_HINT("anchored")] [anchored ? "loose" : "in place"]") + if(state == FRAME_STATE_EMPTY) + . += span_warning("It needs [EXAMINE_HINT("5 cable")] pieces to wire it.") + return + if(state == FRAME_STATE_WIRED) + . += span_info("Its wires can be cut with a [EXAMINE_HINT("wirecutter")].") + if(state != FRAME_STATE_BOARD_INSTALLED) + . += span_warning("Its missing a circuit board..") + return + if(!length(req_components)) + . += span_info("It requires no components.") + return + + var/list/nice_list = list() + for(var/component in req_components) + if(!req_components[component]) + continue + nice_list += list("[req_components[component]] [req_component_names[component]]\s") + . += span_info("It requires [english_list(nice_list, "no more components")].") + + . += span_info("All the components can be [EXAMINE_HINT("pried")] out.") + if(!length(nice_list)) + . += span_info("The frame can be [EXAMINE_HINT("screwed")] to complete it.") + +/obj/structure/frame/machine/dump_contents() + var/atom/drop_loc = drop_location() + + // We need a snowflake check for stack items since they don't exist anymore + for(var/component in circuit?.req_components) + if(!ispath(component, /obj/item/stack)) + continue + var/obj/item/stack/stack_path = component + var/stack_amount = circuit.req_components[component] - req_components[component] + if(stack_amount > 0) + new stack_path(drop_loc, stack_amount) + + // Rest of the stuff can just be spat out (this includes the circuitboard0) + for(var/component in components) + if(ismovable(component)) + var/atom/movable/atom_component = component + atom_component.forceMove(drop_loc) + + else if(istype(component, /datum/stock_part)) + var/datum/stock_part/stock_part_datum = component + var/physical_object_type = initial(stock_part_datum.physical_object_type) + new physical_object_type(drop_loc) + + else + stack_trace("Invalid component [component] was found in constructable frame") + + components = null + req_components = null + req_component_names = null + +/obj/structure/frame/machine/install_board(mob/living/user, obj/item/circuitboard/machine/board, by_hand = TRUE) + if(state == FRAME_STATE_EMPTY) + balloon_alert(user, "needs wiring!") + return FALSE + if(state == FRAME_STATE_BOARD_INSTALLED) + balloon_alert(user, "circuit already installed!") + return FALSE + if(!anchored && istype(board) && board.needs_anchored) + balloon_alert(user, "frame must be anchored!") + return FALSE + + return ..() + +/obj/structure/frame/machine/circuit_added(obj/item/circuitboard/machine/added) + state = FRAME_STATE_BOARD_INSTALLED + update_appearance(UPDATE_ICON_STATE) + + //add circuit board as the first component to the list of components + //required for part_replacer to locate it while exchanging parts + //so it does not early return in /obj/machinery/proc/exchange_parts + components = list(circuit) + req_components = added.req_components.Copy() + if(!req_components) + return + + //creates a list of names from all the required parts + req_component_names = list() + for(var/component_path in req_components) + if(!ispath(component_path)) + continue + + if(ispath(component_path, /obj/item/stack)) + var/obj/item/stack/stack_path = component_path + if(initial(stack_path.singular_name)) + req_component_names[component_path] = initial(stack_path.singular_name) + else + req_component_names[component_path] = initial(stack_path.name) + else if(ispath(component_path, /datum/stock_part)) + var/datum/stock_part/stock_part = component_path + var/obj/item/physical_object_type = initial(stock_part.physical_object_type) + + req_component_names[component_path] = initial(physical_object_type.name) + else if(ispath(component_path, /obj/item/stock_parts)) + var/obj/item/stock_parts/stock_part = component_path + + if(!added.specific_parts && initial(stock_part.base_name)) + req_component_names[component_path] = initial(stock_part.base_name) + else + req_component_names[component_path] = initial(stock_part.name) + else if(ispath(component_path, /obj/item)) + var/obj/item/part = component_path + + req_component_names[component_path] = initial(part.name) + else + stack_trace("Invalid component part [component_path] in [type], couldn't get its name") + req_component_names[component_path] = "[component_path] (this is a bug)" + +/obj/structure/frame/machine/circuit_removed(obj/item/circuitboard/machine/removed) + components -= removed + state = FRAME_STATE_WIRED + update_appearance(UPDATE_ICON_STATE) + +/** + * Returns the instance of path1 in list, else path2 in list + * + * Arguments + * * parts - the list of parts to search + * * path1 - the first path to search for + * * path2 - the second path to search for, if path1 is not found + */ +/obj/structure/frame/machine/proc/look_for(list/parts, path1, path2) + PRIVATE_PROC(TRUE) + + return (locate(path1) in parts) || (path2 ? (locate(path2) in parts) : null) + +/obj/structure/frame/machine/install_parts_from_part_replacer(mob/living/user, obj/item/storage/part_replacer/replacer, no_sound = FALSE) + if(!length(replacer.contents)) + return FALSE + var/amt = 0 + for(var/path in req_components) + amt += req_components[path] + if(!amt) + return FALSE + + var/play_sound = FALSE + var/list/part_list = replacer.get_sorted_parts() //parts sorted in order of tier + for(var/path in req_components) + var/target_path + if(ispath(path, /datum/stock_part)) + var/datum/stock_part/datum_part = path + target_path = initial(datum_part.physical_object_base_type) + else + target_path = path + + var/obj/item/part + while(req_components[path] > 0 && (part = look_for(part_list, target_path, ispath(path, /obj/item/stack/ore/bluespace_crystal) ? /obj/item/stack/sheet/bluespace_crystal : null))) + part_list -= part + if(istype(part, /obj/item/stack)) + var/obj/item/stack/S = part + var/used_amt = min(round(S.get_amount()), req_components[path]) + var/stack_name = S.singular_name + if(!used_amt || !S.use(used_amt)) + continue + req_components[path] -= used_amt + // No balloon alert here so they can look back and see what they added + to_chat(user, span_notice("You add [used_amt] [stack_name] to [src].")) + play_sound = TRUE + else if(replacer.atom_storage.attempt_remove(part, src)) + var/stock_part_datum = GLOB.stock_part_datums_per_object[part.type] + if (!isnull(stock_part_datum)) + components += stock_part_datum + qdel(part) + else + components += part + part.forceMove(src) + req_components[path]-- + // No balloon alert here so they can look back and see what they added + to_chat(user, span_notice("You add [part] to [src].")) + play_sound = TRUE + + if(play_sound && !no_sound) + replacer.play_rped_sound() + if(replacer.works_from_distance) + user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS) + return TRUE + +/obj/structure/frame/machine/can_be_unfasten_wrench(mob/user, silent) + . = ..() + if(. != SUCCESSFUL_UNFASTEN) + return . + + if(circuit?.needs_anchored) + balloon_alert(user, "frame must be anchored!") + return FAILED_UNFASTEN + + return . + +/obj/structure/frame/machine/screwdriver_act(mob/living/user, obj/item/tool) + . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + return . + if(state != FRAME_STATE_BOARD_INSTALLED) + return . + + if(finalize_construction(user, tool)) + return ITEM_INTERACT_SUCCESS + + return ITEM_INTERACT_BLOCKING + +/obj/structure/frame/machine/wirecutter_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + if(state != FRAME_STATE_WIRED) + return ITEM_INTERACT_BLOCKING + + balloon_alert(user, "removing cables...") + if(!tool.use_tool(src, user, 2 SECONDS, volume = 50) || state != FRAME_STATE_WIRED) + return ITEM_INTERACT_BLOCKING + + state = FRAME_STATE_EMPTY + update_appearance(UPDATE_ICON_STATE) + new /obj/item/stack/cable_coil(drop_location(), 5) + return ITEM_INTERACT_SUCCESS + +/obj/structure/frame/machine/crowbar_act(mob/living/user, obj/item/tool) + if(user.combat_mode) + return NONE + if(state != FRAME_STATE_BOARD_INSTALLED) + return ITEM_INTERACT_BLOCKING + + tool.play_tool_sound(src) + var/list/leftover_components = components.Copy() - circuit + dump_contents() + balloon_alert(user, "circuit board[length(leftover_components) ? " and components" : ""] removed") + // Circuit exited handles updating state + return ITEM_INTERACT_SUCCESS + +/** + * Attempts to add the passed part to the frame + * + * Requires no sanity check that the passed part is a stock part + * + * Arguments + * * user - the player + * * tool - the part to add + */ +/obj/structure/frame/machine/proc/add_part(mob/living/user, obj/item/tool) + PRIVATE_PROC(TRUE) + + for(var/stock_part_base in req_components) + if (req_components[stock_part_base] == 0) + continue + + var/stock_part_path + + if(ispath(stock_part_base, /obj/item)) + stock_part_path = stock_part_base + else if(ispath(stock_part_base, /datum/stock_part)) + var/datum/stock_part/stock_part_datum_type = stock_part_base + stock_part_path = initial(stock_part_datum_type.physical_object_type) + else + stack_trace("Bad stock part in req_components: [stock_part_base]") + continue + + //if we require an bluespace crystall and we have an full sheet of them we can allow that + if(ispath(stock_part_path, /obj/item/stack/ore/bluespace_crystal) && istype(tool, /obj/item/stack/sheet/bluespace_crystal)) + pass() //allow it + else if(!istype(tool, stock_part_path)) + continue + + if(isstack(tool)) + var/obj/item/stack/S = tool + var/used_amt = min(round(S.get_amount()), req_components[stock_part_path]) + if(used_amt && S.use(used_amt)) + req_components[stock_part_path] -= used_amt + // No balloon alert here so they can look back and see what they added + to_chat(user, span_notice("You add [tool] to [src].")) + return + + // We might end up qdel'ing the part if it's a stock part datum. + // In practice, this doesn't have side effects to the name, + // but academically we should not be using an object after it's deleted. + var/part_name = "[tool]" + + if (ispath(stock_part_base, /datum/stock_part)) + // We can't just reuse stock_part_path here or its singleton, + // or else putting in a tier 2 part will deconstruct to a tier 1 part. + var/stock_part_datum = GLOB.stock_part_datums_per_object[tool.type] + if (isnull(stock_part_datum)) + stack_trace("tool.type] does not have an associated stock part datum!") + continue + + components += stock_part_datum + + // We regenerate the stock parts on deconstruct. + // This technically means we lose unique qualities of the stock part, but + // it's worth it for how dramatically this simplifies the code. + // The only place I can see it affecting anything is like...RPG qualities. :P + qdel(tool) + else if(user.transferItemToLoc(tool, src)) + components += tool + else + break + + // No balloon alert here so they can look back and see what they added + to_chat(user, span_notice("You add [part_name] to [src].")) + req_components[stock_part_base]-- + return TRUE + + balloon_alert(user, "can't add that!") + return FALSE + +/obj/structure/frame/machine/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking) + . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + return . + + switch(state) + if(FRAME_STATE_EMPTY) + if(istype(tool, /obj/item/stack/cable_coil)) + if(!tool.tool_start_check(user, amount = 5)) + return ITEM_INTERACT_BLOCKING + + balloon_alert(user, "adding cables...") + if(!tool.use_tool(src, user, 2 SECONDS, volume = 50, amount = 5) || state != FRAME_STATE_EMPTY) + return ITEM_INTERACT_BLOCKING + + state = FRAME_STATE_WIRED + update_appearance(UPDATE_ICON_STATE) + return ITEM_INTERACT_SUCCESS + + if(FRAME_STATE_WIRED) + if(isnull(circuit) && istype(tool, /obj/item/storage/part_replacer)) + return install_circuit_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + + if(FRAME_STATE_BOARD_INSTALLED) + if(istype(tool, /obj/item/storage/part_replacer)) + return install_parts_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + + if(!user.combat_mode) + return add_part(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + + return . + +/** + * Attempt to finalize the construction of the frame into a machine + * as according to our circuit and parts + * + * If successful, results in qdel'ing the frame and newing of a machine + * + * Arguments + * * user - the player + * * tool - the tool used to finalize the construction + */ +/obj/structure/frame/machine/finalize_construction(mob/living/user, obj/item/tool) + for(var/component in req_components) + if(req_components[component] > 0) + user.balloon_alert(user, "missing components!") + return FALSE + + tool.play_tool_sound(src) + var/obj/machinery/new_machine = new circuit.build_path(loc) + if(istype(new_machine)) + new_machine.clear_components() + // Set anchor state + new_machine.set_anchored(anchored) + // Prevent us from dropping stuff thanks to /Exited + var/obj/item/circuitboard/machine/leaving_circuit = circuit + circuit = null + // Assign the circuit & parts & move them all at once into the machine + // no need to seperatly move circuit board as its already part of the components list + new_machine.circuit = leaving_circuit + new_machine.component_parts = components + for (var/obj/new_part in components) + new_part.forceMove(new_machine) + //Inform machine that its finished & cleanup + new_machine.RefreshParts() + new_machine.on_construction(user) + components = null + qdel(src) + return TRUE + +/obj/structure/frame/machine/secured + state = FRAME_STATE_WIRED + anchored = TRUE diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index d0c0744f19ecb..809171af1efa7 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -1168,7 +1168,7 @@ DEFINE_BITFIELD(turret_flags, list( if(properties["team_color"]) team_color = properties["team_color"] -/obj/machinery/porta_turret/lasertag/ui_status(mob/user) +/obj/machinery/porta_turret/lasertag/ui_status(mob/user, datum/ui_state/state) if(ishuman(user)) var/mob/living/carbon/human/H = user if(team_color == "blue" && istype(H.wear_suit, /obj/item/clothing/suit/redtag)) diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm index 2b8abcb17282f..075e927d65328 100644 --- a/code/game/objects/effects/misc.dm +++ b/code/game/objects/effects/misc.dm @@ -43,6 +43,10 @@ stack_trace("Warning: something tried to forceMove() a qdeleted [src]([type]) to non-null destination [destination]([destination.type])!") return ..() +/// Override to define loot blacklist behavior +/obj/effect/spawner/proc/can_spawn(atom/loot) + return TRUE + /obj/effect/list_container name = "list container" diff --git a/code/game/objects/effects/spawners/random/maintenance.dm b/code/game/objects/effects/spawners/random/maintenance.dm index 242613e403d6a..234b69e85716d 100644 --- a/code/game/objects/effects/spawners/random/maintenance.dm +++ b/code/game/objects/effects/spawners/random/maintenance.dm @@ -4,6 +4,13 @@ icon_state = "loot" // see code/_globalvars/lists/maintenance_loot.dm for loot table +/// A subtype of maintenance loot spawner that does not spawn any decals, for when you want to place them on chasm turfs and such +/// decals such as ashes will cause NeverShouldHaveComeHere() to fail on such turfs, which creates annoying rng based CI failures +/obj/effect/spawner/random/maintenance/no_decals + +/obj/effect/spawner/random/maintenance/no_decals/can_spawn(atom/loot) + return !istype(loot, /obj/effect/decal) + /obj/effect/spawner/random/maintenance/examine(mob/user) . = ..() . += span_info("This spawner has an effective loot count of [get_effective_lootcount()].") @@ -64,3 +71,31 @@ /obj/effect/spawner/random/maintenance/eight name = "8 x maintenance loot spawner" spawn_loot_count = 8 + +/obj/effect/spawner/random/maintenance/no_decals/two + name = "2 x maintenance loot spawner" + spawn_loot_count = 2 + +/obj/effect/spawner/random/maintenance/no_decals/three + name = "3 x maintenance loot spawner" + spawn_loot_count = 3 + +/obj/effect/spawner/random/maintenance/no_decals/four + name = "4 x maintenance loot spawner" + spawn_loot_count = 4 + +/obj/effect/spawner/random/maintenance/no_decals/five + name = "5 x maintenance loot spawner" + spawn_loot_count = 5 + +/obj/effect/spawner/random/maintenance/no_decals/six + name = "6 x maintenance loot spawner" + spawn_loot_count = 6 + +/obj/effect/spawner/random/maintenance/no_decals/seven + name = "7 x maintenance loot spawner" + spawn_loot_count = 7 + +/obj/effect/spawner/random/maintenance/no_decals/eight + name = "8 x maintenance loot spawner" + spawn_loot_count = 8 diff --git a/code/game/objects/effects/spawners/random/random.dm b/code/game/objects/effects/spawners/random/random.dm index e8653a30cfb0c..e518b9ad4717c 100644 --- a/code/game/objects/effects/spawners/random/random.dm +++ b/code/game/objects/effects/spawners/random/random.dm @@ -57,6 +57,9 @@ var/pixel_divider = FLOOR(16 / spawn_loot_split_pixel_offsets, 1) // 16 pixels offsets is max that should be allowed in any direction while((spawn_loot_count-loot_spawned) && loot.len) var/lootspawn = pick_weight_recursive(loot) + if(!can_spawn(lootspawn)) + loot.Remove(lootspawn) + continue if(!spawn_loot_double) loot.Remove(lootspawn) if(lootspawn && (spawn_scatter_radius == 0 || spawn_locations.len)) diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 04c0c57955335..d395905cd2631 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -1455,7 +1455,7 @@ /obj/item/card/id/advanced/chameleon/ui_state(mob/user) return GLOB.always_state -/obj/item/card/id/advanced/chameleon/ui_status(mob/user) +/obj/item/card/id/advanced/chameleon/ui_status(mob/user, datum/ui_state/state) var/target = theft_target?.resolve() if(!target) diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 395faaa5449c9..e7c4e8eadde9b 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -31,6 +31,7 @@ attack_verb_continuous = list("attacks", "colours") attack_verb_simple = list("attack", "colour") grind_results = list() + interaction_flags_atom = parent_type::interaction_flags_atom | INTERACT_ATOM_IGNORE_MOBILITY /// Icon state to use when capped var/icon_capped diff --git a/code/game/objects/items/credit_holochip.dm b/code/game/objects/items/credit_holochip.dm index eecef73fd4304..8e9fb78172f60 100644 --- a/code/game/objects/items/credit_holochip.dm +++ b/code/game/objects/items/credit_holochip.dm @@ -9,10 +9,13 @@ w_class = WEIGHT_CLASS_TINY var/credits = 0 -/obj/item/holochip/Initialize(mapload, amount) +/obj/item/holochip/Initialize(mapload, amount = 1) . = ..() if(amount) credits = amount + if(credits <= 0 && !mapload) + stack_trace("Holochip created with 0 or less credits in [get_area_name(src)]!") + return INITIALIZE_HINT_QDEL update_appearance() /obj/item/holochip/examine(mob/user) diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 67369d91a17e9..248955e0fa493 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -10,6 +10,7 @@ worn_icon_state = "radio" desc = "A basic handheld radio that communicates with local telecommunication networks." dog_fashion = /datum/dog_fashion/back + interaction_flags_atom = parent_type::interaction_flags_atom | INTERACT_ATOM_ALLOW_USER_LOCATION | INTERACT_ATOM_IGNORE_MOBILITY obj_flags = CONDUCTS_ELECTRICITY slot_flags = ITEM_SLOT_BELT diff --git a/code/game/objects/items/devices/scanners/t_scanner.dm b/code/game/objects/items/devices/scanners/t_scanner.dm index c9f1ae0fd9d92..555e6cc88619f 100644 --- a/code/game/objects/items/devices/scanners/t_scanner.dm +++ b/code/game/objects/items/devices/scanners/t_scanner.dm @@ -4,7 +4,6 @@ custom_price = PAYCHECK_LOWER * 0.7 icon = 'icons/obj/devices/scanner.dmi' icon_state = "t-ray0" - var/on = FALSE slot_flags = ITEM_SLOT_BELT w_class = WEIGHT_CLASS_SMALL inhand_icon_state = "electronic" @@ -12,6 +11,10 @@ lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT * 1.5) + /// Is this T-Ray scanner currently on? + var/on = FALSE + /// Will this T-Ray scanner shut off on de-equip? (Cyborgs only) + var/shut_off_on_unequip = TRUE /obj/item/t_scanner/suicide_act(mob/living/carbon/user) user.visible_message(span_suicide("[user] begins to emit terahertz-rays into [user.p_their()] brain with [src]! It looks like [user.p_theyre()] trying to commit suicide!")) @@ -29,6 +32,8 @@ toggle_on() /obj/item/t_scanner/cyborg_unequip(mob/user) + if(!shut_off_on_unequip) + return if(!on) return toggle_on() diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index ce1245098c860..3515e7f52c3ce 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -431,7 +431,7 @@ effective or pretty fucking useless. toolbox = null qdel(src) -/obj/machinery/porta_turret/syndicate/toolbox/ui_status(mob/user) +/obj/machinery/porta_turret/syndicate/toolbox/ui_status(mob/user, datum/ui_state/state) if(faction_check(user.faction, faction)) return ..() diff --git a/code/game/objects/items/food/meatslab.dm b/code/game/objects/items/food/meatslab.dm index c6b7d8110e7ee..c1b5a6a186f5f 100644 --- a/code/game/objects/items/food/meatslab.dm +++ b/code/game/objects/items/food/meatslab.dm @@ -340,7 +340,6 @@ icon_state = "meatwheat_clump" bite_consumption = 4 tastes = list("meat" = 1, "wheat" = 1) - foodtypes = GRAIN /obj/item/food/meat/slab/gorilla name = "gorilla meat" diff --git a/code/game/objects/items/food/misc.dm b/code/game/objects/items/food/misc.dm index 840d431bfa55e..0e598c6820296 100644 --- a/code/game/objects/items/food/misc.dm +++ b/code/game/objects/items/food/misc.dm @@ -246,6 +246,7 @@ w_class = WEIGHT_CLASS_BULKY tastes = list("cherry" = 1, "crepe" = 1) foodtypes = GRAIN | FRUIT | SUGAR + food_flags = FOOD_FINGER_FOOD crafting_complexity = FOOD_COMPLEXITY_5 /obj/item/food/branrequests diff --git a/code/game/objects/items/food/pie.dm b/code/game/objects/items/food/pie.dm index 46674fb735e94..e57759915208d 100644 --- a/code/game/objects/items/food/pie.dm +++ b/code/game/objects/items/food/pie.dm @@ -484,3 +484,30 @@ tastes = list("pie" = 1, "the far off year of 2010" = 1) foodtypes = GRAIN crafting_complexity = FOOD_COMPLEXITY_2 + +/obj/item/food/pie/bacid_pie + name = "battery acid pie" + desc = "Ooh it's a pie made of... battery acid? You suppose an ethereal could find some enjoyement in eating this." + icon_state = "bacid_pie" + food_reagents = list( + /datum/reagent/consumable/nutriment = 18, + /datum/reagent/consumable/liquidelectricity/enriched = 18 + ) + tastes = list("battery acid" = 2, "electricity" = 2, "a cyber world" = 2) + foodtypes = TOXIC + slice_type = /obj/item/food/pieslice/bacid_pie + yield = 4 + crafting_complexity = FOOD_COMPLEXITY_3 + + +/obj/item/food/pieslice/bacid_pie + name = "battery acid pie slice" + desc = "The battery acid filling has a concerningly appealing bright green color" + icon_state = "bacid_pie_slice" + food_reagents = list( + /datum/reagent/consumable/nutriment = 4.5, + /datum/reagent/consumable/liquidelectricity/enriched = 4.5 + ) + tastes = list("battery acid" = 1, "electricity" = 1, "a cyber world" = 1) + foodtypes = TOXIC + crafting_complexity = FOOD_COMPLEXITY_3 diff --git a/code/game/objects/items/kitchen.dm b/code/game/objects/items/kitchen.dm index 1e8a148e9b1e8..9a55b1cd57464 100644 --- a/code/game/objects/items/kitchen.dm +++ b/code/game/objects/items/kitchen.dm @@ -235,6 +235,13 @@ if(!target_mob.reagents || reagents.total_volume <= 0) return ..() + if(target_mob.is_mouth_covered(ITEM_SLOT_HEAD) || target_mob.is_mouth_covered(ITEM_SLOT_MASK)) + if(target_mob == user) + target_mob.balloon_alert(user, "can't eat with mouth covered!") + else + target_mob.balloon_alert(user, "[target_mob.p_their()] mouth is covered!") + return TRUE + if(target_mob == user) user.visible_message( span_notice("[user] scoops a spoonful into [user.p_their()] mouth."), diff --git a/code/game/objects/items/rcd/RCD.dm b/code/game/objects/items/rcd/RCD.dm index 7e14ca91b3ff1..9570614b400b3 100644 --- a/code/game/objects/items/rcd/RCD.dm +++ b/code/game/objects/items/rcd/RCD.dm @@ -521,7 +521,7 @@ ///How much charge is used up for each matter unit. var/mass_to_energy = 16 -/obj/item/construction/rcd/exosuit/ui_status(mob/user) +/obj/item/construction/rcd/exosuit/ui_status(mob/user, datum/ui_state/state) if(ismecha(owner)) return owner.ui_status(user) return UI_CLOSE diff --git a/code/game/objects/items/rcd/RCL.dm b/code/game/objects/items/rcd/RCL.dm index 9134a7ac1e537..1d966d37670f4 100644 --- a/code/game/objects/items/rcd/RCL.dm +++ b/code/game/objects/items/rcd/RCL.dm @@ -16,7 +16,7 @@ w_class = WEIGHT_CLASS_NORMAL var/max_amount = 90 var/active = FALSE - actions_types = list(/datum/action/item_action/rcl_col,/datum/action/item_action/rcl_gui,) + actions_types = list(/datum/action/item_action/rcl_col,/datum/action/item_action/rcl_gui) var/list/colors = list("red", "yellow", "green", "blue", "pink", "orange", "cyan", "white") var/current_color_index = 1 var/ghetto = FALSE diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index e92b4332846c6..367c619333e81 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -381,7 +381,7 @@ else return ..() -/obj/item/robot_suit/ui_status(mob/user) +/obj/item/robot_suit/ui_status(mob/user, datum/ui_state/state) if(isobserver(user)) return ..() var/obj/item/held_item = user.get_active_held_item() diff --git a/code/game/objects/items/stacks/tickets.dm b/code/game/objects/items/stacks/tickets.dm index 20e6843b97707..d1bd7681b8a8b 100644 --- a/code/game/objects/items/stacks/tickets.dm +++ b/code/game/objects/items/stacks/tickets.dm @@ -8,14 +8,9 @@ max_amount = 30 merge_type = /obj/item/stack/arcadeticket -/obj/item/stack/arcadeticket/Initialize(mapload, new_amount, merge = TRUE, list/mat_override=null, mat_amt=1) - . = ..() - update_appearance() - /obj/item/stack/arcadeticket/update_icon_state() . = ..() - var/amount = get_amount() - switch(amount) + switch(get_amount()) if(12 to INFINITY) icon_state = "arcade-ticket_4" if(6 to 12) @@ -25,10 +20,5 @@ else icon_state = "arcade-ticket" -/obj/item/stack/arcadeticket/proc/pay_tickets() - amount -= 2 - if (amount == 0) - qdel(src) - /obj/item/stack/arcadeticket/thirty amount = 30 diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm index ce848e92cbdd3..fb925cdb7dae8 100644 --- a/code/game/objects/structures/extinguisher.dm +++ b/code/game/objects/structures/extinguisher.dm @@ -110,7 +110,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/extinguisher_cabinet, 29) toggle_cabinet(user) /obj/structure/extinguisher_cabinet/attack_hand_secondary(mob/living/user) - if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS)) + if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING)) return ..() toggle_cabinet(user) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN diff --git a/code/modules/admin/fun_balloon.dm b/code/modules/admin/fun_balloon.dm index 873090118ab68..4d74f5425608f 100644 --- a/code/modules/admin/fun_balloon.dm +++ b/code/modules/admin/fun_balloon.dm @@ -54,7 +54,7 @@ /obj/effect/fun_balloon/sentience/ui_state(mob/user) return GLOB.admin_state -/obj/effect/fun_balloon/sentience/ui_status(mob/user) +/obj/effect/fun_balloon/sentience/ui_status(mob/user, datum/ui_state/state) if(popped) return UI_CLOSE if(isAdminObserver(user)) // ignore proximity if we're an admin diff --git a/code/modules/antagonists/abductor/machinery/console.dm b/code/modules/antagonists/abductor/machinery/console.dm index b76a25ca7203a..5bd5ce8c2ecfc 100644 --- a/code/modules/antagonists/abductor/machinery/console.dm +++ b/code/modules/antagonists/abductor/machinery/console.dm @@ -71,7 +71,7 @@ if(do_after(user,100, target = src)) TeleporterSend() -/obj/machinery/abductor/console/ui_status(mob/user) +/obj/machinery/abductor/console/ui_status(mob/user, datum/ui_state/state) if(!isabductor(user) && !isobserver(user)) return UI_CLOSE return ..() diff --git a/code/modules/antagonists/abductor/machinery/dispenser.dm b/code/modules/antagonists/abductor/machinery/dispenser.dm index 163b7515872d2..8d8f9e14b8954 100644 --- a/code/modules/antagonists/abductor/machinery/dispenser.dm +++ b/code/modules/antagonists/abductor/machinery/dispenser.dm @@ -22,7 +22,7 @@ gland_colors[i] = random_color() amounts[i] = rand(1,5) -/obj/machinery/abductor/gland_dispenser/ui_status(mob/user) +/obj/machinery/abductor/gland_dispenser/ui_status(mob/user, datum/ui_state/state) if(!isabductor(user) && !isobserver(user)) return UI_CLOSE return ..() diff --git a/code/modules/antagonists/abductor/machinery/experiment.dm b/code/modules/antagonists/abductor/machinery/experiment.dm index 333a03b45f8fc..711923daa442f 100644 --- a/code/modules/antagonists/abductor/machinery/experiment.dm +++ b/code/modules/antagonists/abductor/machinery/experiment.dm @@ -59,7 +59,7 @@ span_notice("You successfully break out of [src]!")) open_machine() -/obj/machinery/abductor/experiment/ui_status(mob/user) +/obj/machinery/abductor/experiment/ui_status(mob/user, datum/ui_state/state) if(user == occupant) return UI_CLOSE return ..() diff --git a/code/modules/antagonists/brother/brother.dm b/code/modules/antagonists/brother/brother.dm index 4c3fdb45dc98a..223664f0fa449 100644 --- a/code/modules/antagonists/brother/brother.dm +++ b/code/modules/antagonists/brother/brother.dm @@ -209,7 +209,7 @@ /datum/objective/convert_brother name = "convert brother" - explanation_text = "Convert someone else using your flash." + explanation_text = "Convert a brainwashable person using your flash. Any flash will work if you lose or break your starting flash." admin_grantable = FALSE martyr_compatible = TRUE diff --git a/code/modules/assembly/infrared.dm b/code/modules/assembly/infrared.dm index 0353744b298e0..478d500072136 100644 --- a/code/modules/assembly/infrared.dm +++ b/code/modules/assembly/infrared.dm @@ -181,7 +181,7 @@ . = ..() refreshBeam() -/obj/item/assembly/infra/ui_status(mob/user) +/obj/item/assembly/infra/ui_status(mob/user, datum/ui_state/state) if(is_secured(user)) return ..() return UI_CLOSE diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm index 5b6bf30668766..031a3f78eadeb 100644 --- a/code/modules/assembly/proximity.dm +++ b/code/modules/assembly/proximity.dm @@ -134,7 +134,7 @@ . += "prox_scanning" attached_overlays += "prox_scanning" -/obj/item/assembly/prox_sensor/ui_status(mob/user) +/obj/item/assembly/prox_sensor/ui_status(mob/user, datum/ui_state/state) if(is_secured(user)) return ..() return UI_CLOSE diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index 3823706358faf..5af89f10ec1b4 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -68,7 +68,7 @@ . = ..() holder?.update_appearance() -/obj/item/assembly/signaler/ui_status(mob/user) +/obj/item/assembly/signaler/ui_status(mob/user, datum/ui_state/state) if(is_secured(user)) return ..() return UI_CLOSE diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm index 1619f080abbe4..8366bb0f2b382 100644 --- a/code/modules/assembly/timer.dm +++ b/code/modules/assembly/timer.dm @@ -83,7 +83,7 @@ . += "timer_timing" attached_overlays += "timer_timing" -/obj/item/assembly/timer/ui_status(mob/user) +/obj/item/assembly/timer/ui_status(mob/user, datum/ui_state/state) if(is_secured(user)) return ..() return UI_CLOSE diff --git a/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm b/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm index dee1f93f4bf69..c8e93257b8064 100644 --- a/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm +++ b/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm @@ -185,7 +185,7 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) if(AIR_ALARM_BUILD_COMPLETE) . += span_notice("Right-click to [locked ? "unlock" : "lock"] the interface.") -/obj/machinery/airalarm/ui_status(mob/user) +/obj/machinery/airalarm/ui_status(mob/user, datum/ui_state/state) if(user.has_unlimited_silicon_privilege && aidisabled) to_chat(user, "AI control has been disabled.") else if(!shorted) diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm index ce70c93a558bb..be455ea6d4709 100644 --- a/code/modules/atmospherics/machinery/atmosmachinery.dm +++ b/code/modules/atmospherics/machinery/atmosmachinery.dm @@ -21,6 +21,7 @@ max_integrity = 200 obj_flags = CAN_BE_HIT armor_type = /datum/armor/machinery_atmospherics + interaction_flags_atom = parent_type::interaction_flags_atom | INTERACT_ATOM_IGNORE_MOBILITY ///Check if the object can be unwrenched var/can_unwrench = FALSE diff --git a/code/modules/atmospherics/machinery/components/components_base.dm b/code/modules/atmospherics/machinery/components/components_base.dm index 130c144d42439..e72d72b3d5955 100644 --- a/code/modules/atmospherics/machinery/components/components_base.dm +++ b/code/modules/atmospherics/machinery/components/components_base.dm @@ -213,7 +213,7 @@ // UI Stuff -/obj/machinery/atmospherics/components/ui_status(mob/user) +/obj/machinery/atmospherics/components/ui_status(mob/user, datum/ui_state/state) if(allowed(user)) return ..() to_chat(user, span_danger("Access denied.")) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/bluespace_sender.dm b/code/modules/atmospherics/machinery/components/unary_devices/bluespace_sender.dm index 269e0943004a2..7d2efbd932103 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/bluespace_sender.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/bluespace_sender.dm @@ -4,6 +4,7 @@ base_icon_state = "bluespace_sender" name = "Bluespace Gas Sender" desc = "Sends gases to the bluespace network to be shared with the connected vendors, who knows what's beyond!" + interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT density = TRUE max_integrity = 300 diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm index 5c894274619ad..46adfee054e6e 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm @@ -5,6 +5,8 @@ icon_state = "thermo_base" plane = GAME_PLANE + interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT + name = "Temperature control unit" desc = "Heats or cools gas in connected pipes." @@ -257,7 +259,7 @@ return ITEM_INTERACT_SUCCESS return -/obj/machinery/atmospherics/components/unary/thermomachine/ui_status(mob/user) +/obj/machinery/atmospherics/components/unary/thermomachine/ui_status(mob/user, datum/ui_state/state) if(interactive) return ..() return UI_CLOSE diff --git a/code/modules/cargo/packs/imports.dm b/code/modules/cargo/packs/imports.dm index bfb883f3f3406..7edfe9e2a9cf8 100644 --- a/code/modules/cargo/packs/imports.dm +++ b/code/modules/cargo/packs/imports.dm @@ -319,3 +319,20 @@ ) crate_name = "materials market crate" crate_type = /obj/structure/closet/crate/cargo + +/datum/supply_pack/imports/floortilecamo + name = "Floor-tile Camouflage Uniform" + desc = "Thank you for shopping from Camo-J's, our uniquely designed \ + floor-tile 'NT SCUM' styled camouflage fatigues is the ultimate \ + espionage uniform used by the very best. Providing the best \ + flexibility, with our latest Camo-tech threads. Perfect for \ + risky espionage hallway operations. Enjoy our product!" + hidden = TRUE + cost = CARGO_CRATE_VALUE * 6 + contains = list(/obj/item/clothing/under/syndicate/floortilecamo = 4, + /obj/item/clothing/mask/floortilebalaclava = 4, + /obj/item/clothing/gloves/combat/floortile = 4, + /obj/item/clothing/shoes/jackboots/floortile = 4 + ) + crate_name = "floortile camouflauge crate" + crate_type = /obj/structure/closet/crate/secure/weapon diff --git a/code/modules/clothing/gloves/combat.dm b/code/modules/clothing/gloves/combat.dm index 770308227163f..efc5bd40b0587 100644 --- a/code/modules/clothing/gloves/combat.dm +++ b/code/modules/clothing/gloves/combat.dm @@ -24,3 +24,9 @@ icon_state = "wizard" greyscale_colors = null inhand_icon_state = null + +/obj/item/clothing/gloves/combat/floortile + name = "floortile camouflage gloves" + desc = "Is it just me or is there a pair of gloves on the floor?" + icon_state = "ftc_gloves" + inhand_icon_state = "greyscale_gloves" diff --git a/code/modules/clothing/head/hardhat.dm b/code/modules/clothing/head/hardhat.dm index 8e52a8c525822..2129c598aae25 100644 --- a/code/modules/clothing/head/hardhat.dm +++ b/code/modules/clothing/head/hardhat.dm @@ -23,7 +23,7 @@ var/hat_type = "yellow" ///Whether the headlamp is on or off. var/on = FALSE - + clothing_traits = list(TRAIT_HEAD_INJURY_BLOCKED) /datum/armor/utility_hardhat melee = 15 @@ -216,6 +216,7 @@ light_color = "#fff2bf" worn_y_offset = 1 dog_fashion = /datum/dog_fashion/head/pumpkin/unlit + clothing_traits = list() /obj/item/clothing/head/utility/hardhat/pumpkinhead/set_light_on(new_value) . = ..() @@ -269,6 +270,6 @@ flags_inv = 0 armor_type = /datum/armor/none light_range = 1 //luminosity when on - + clothing_traits = list() dog_fashion = /datum/dog_fashion/head/reindeer diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 2960260255fbc..7741251f3f5b2 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -184,6 +184,7 @@ visor_flags_inv = HIDEFACE|HIDESNOUT flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF visor_flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF + clothing_traits = list(TRAIT_HEAD_INJURY_BLOCKED) /datum/armor/toggleable_riot melee = 50 @@ -247,6 +248,7 @@ strip_delay = 80 resistance_flags = FIRE_PROOF | ACID_PROOF dog_fashion = null + clothing_traits = list(TRAIT_HEAD_INJURY_BLOCKED) /datum/armor/helmet_swat melee = 40 @@ -394,6 +396,7 @@ flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH strip_delay = 80 dog_fashion = null + clothing_traits = list(TRAIT_HEAD_INJURY_BLOCKED) /datum/armor/helmet_knight melee = 50 diff --git a/code/modules/clothing/masks/boxing.dm b/code/modules/clothing/masks/boxing.dm index 9c947b53a9399..78ba0764b81ec 100644 --- a/code/modules/clothing/masks/boxing.dm +++ b/code/modules/clothing/masks/boxing.dm @@ -12,6 +12,21 @@ /obj/item/clothing/mask/balaclava/attack_self(mob/user) adjustmask(user) +/obj/item/clothing/mask/floortilebalaclava + name = "floortile balaclava" + desc = "The newest floortile camouflage balaclava used for hallway warfare. \ + The best breathability, flexibility and comfort. Designed by Camo-J's." + icon_state = "floortile_balaclava" + inhand_icon_state = "balaclava" + flags_inv = HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT + visor_flags_inv = HIDEFACE|HIDEFACIALHAIR|HIDESNOUT + alternate_worn_layer = LOW_FACEMASK_LAYER + w_class = WEIGHT_CLASS_SMALL + actions_types = list(/datum/action/item_action/adjust) + +/obj/item/clothing/mask/floortilebalaclava/attack_self(mob/user) + adjustmask(user) + /obj/item/clothing/mask/luchador name = "Luchador Mask" desc = "Worn by robust fighters, flying high to defeat their foes!" diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index cdfa38ba5d2d2..67b50fbe67213 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -469,7 +469,7 @@ var/true_price = round(price*profit_scaling) to_chat(user, span_notice("[selling ? "Sold" : "Getting the price of"] [I], value: [true_price] credits[I.contents.len ? " (exportable contents included)" : ""].[profit_scaling < 1 && selling ? "[round(price-true_price)] credit\s taken as processing fee\s." : ""]")) if(selling) - new /obj/item/holochip(get_turf(user),true_price) + new /obj/item/holochip(get_turf(user), true_price) else to_chat(user, span_warning("There is no export value for [I] or any items within it.")) diff --git a/code/modules/clothing/shoes/boots.dm b/code/modules/clothing/shoes/boots.dm index b359f94db3da5..dbfa4f8b3c40d 100644 --- a/code/modules/clothing/shoes/boots.dm +++ b/code/modules/clothing/shoes/boots.dm @@ -64,6 +64,12 @@ /obj/item/clothing/shoes/jackboots/sec icon_state = "jackboots_sec" +/obj/item/clothing/shoes/jackboots/floortile + name = "floortile camouflage jackboots" + desc = "Is it just me or is there a pair of jackboots on the floor?" + icon_state = "ftc_boots" + inhand_icon_state = null + /obj/item/clothing/shoes/winterboots name = "winter boots" desc = "Boots lined with 'synthetic' animal fur." diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index ef10536341e98..47bd32280ed89 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -282,7 +282,7 @@ armor_type = /datum/armor/armor_riot strip_delay = 80 equip_delay_other = 60 - clothing_traits = list(TRAIT_SHOVE_KNOCKDOWN_BLOCKED) + clothing_traits = list(TRAIT_BRAWLING_KNOCKDOWN_BLOCKED) /datum/armor/armor_riot melee = 50 @@ -386,7 +386,7 @@ max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT slowdown = 0.7 body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - clothing_traits = list(TRAIT_SHOVE_KNOCKDOWN_BLOCKED) + clothing_traits = list(TRAIT_BRAWLING_KNOCKDOWN_BLOCKED) //All of the armor below is mostly unused diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index 45152f7569ae5..20a117e112e48 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -151,7 +151,7 @@ if((supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION) && ishuman(user)) var/mob/living/carbon/human/wearer = user - if(wearer.bodytype & BODYTYPE_DIGITIGRADE) + if(wearer.bodyshape & BODYSHAPE_DIGITIGRADE) adjusted = DIGITIGRADE_STYLE update_appearance() diff --git a/code/modules/clothing/under/syndicate.dm b/code/modules/clothing/under/syndicate.dm index 20a5cda059202..3a27ee6c1ebb2 100644 --- a/code/modules/clothing/under/syndicate.dm +++ b/code/modules/clothing/under/syndicate.dm @@ -111,6 +111,15 @@ can_adjust = FALSE supports_variations_flags = NONE +/obj/item/clothing/under/syndicate/floortilecamo + name = "floortile camouflage fatigues" + desc = "The newest floortile camouflage fatigues used for hallway warfare. \ + The best breathability, flexibility and comfort. Designed by Camo-J's." + icon_state = "camofloortile" + inhand_icon_state = "gy_suit" + can_adjust = FALSE + supports_variations_flags = NONE + /obj/item/clothing/under/syndicate/soviet name = "Ratnik 5 tracksuit" desc = "Badly translated labels tell you to clean this in Vodka. Great for squatting in." diff --git a/code/modules/deathmatch/deathmatch_loadouts.dm b/code/modules/deathmatch/deathmatch_loadouts.dm index 480e1975fb91a..f994987427e86 100644 --- a/code/modules/deathmatch/deathmatch_loadouts.dm +++ b/code/modules/deathmatch/deathmatch_loadouts.dm @@ -17,6 +17,8 @@ if(!isnull(species_override)) user.set_species(species_override) + else if (istype(user.dna.species.outfit_important_for_life)) //plasmamen get lit on fire and die + user.set_species(/datum/species/human) for(var/datum/action/act as anything in granted_spells) var/datum/action/new_ability = new act(user) new_ability.Grant(user) @@ -31,7 +33,7 @@ name = "Deathmatch: Assistant loadout" display_name = "Assistant" desc = "A simple assistant loadout: greyshirt and a toolbox" - + l_hand = /obj/item/storage/toolbox/mechanical uniform = /obj/item/clothing/under/color/grey back = /obj/item/storage/backpack @@ -48,7 +50,7 @@ name = "Deathmatch: Operative" display_name = "Operative" desc = "A syndicate operative." - + uniform = /obj/item/clothing/under/syndicate shoes = /obj/item/clothing/shoes/combat gloves = /obj/item/clothing/gloves/combat @@ -59,7 +61,7 @@ name = "Deathmatch: Ranged Operative" display_name = "Ranged Operative" desc = "A syndicate operative with a gun and a knife." - + l_hand = /obj/item/gun/ballistic/automatic/pistol l_pocket = /obj/item/knife/combat backpack_contents = list(/obj/item/ammo_box/magazine/m9mm = 5) @@ -68,7 +70,7 @@ name = "Deathmatch: Melee Operative" display_name = "Melee Operative" desc = "A syndicate operative with multiple knives." - + gloves = /obj/item/clothing/gloves/tackler/combat/insulated suit = /obj/item/clothing/suit/armor/vest head = /obj/item/clothing/head/helmet @@ -80,7 +82,7 @@ name = "Deathmatch: Security Officer" display_name = "Security Officer" desc = "A security officer." - + uniform = /datum/outfit/job/security::uniform suit = /datum/outfit/job/security::suit suit_store = /datum/outfit/job/security::suit_store @@ -100,7 +102,7 @@ name = "DM: Instagib" display_name = "Instagib" desc = "Assistant with an instakill rifle." - + l_hand = /obj/item/gun/energy/laser/instakill /datum/outfit/deathmatch_loadout/operative/sniper @@ -143,7 +145,7 @@ name = "Deathmatch: Battler Base" display_name = "Battler" desc = "What is a battler whith out weapone?." - + shoes = /obj/item/clothing/shoes/combat uniform = /obj/item/clothing/under/syndicate gloves = /obj/item/clothing/gloves/combat @@ -154,14 +156,14 @@ name = "Deathmatch: Soldier" display_name = "Soldier" desc = "Ready for combat." - + l_hand = /obj/item/gun/ballistic/rifle/boltaction l_pocket = /obj/item/knife/combat uniform = /obj/item/clothing/under/syndicate/rus_army suit = /obj/item/clothing/suit/armor/vest head = /obj/item/clothing/head/helmet/rus_helmet gloves = /obj/item/clothing/gloves/tackler/combat/insulated - + backpack_contents = list( /obj/item/grenade/smokebomb = 2, /obj/item/ammo_box/strilka310 = 2, @@ -199,7 +201,7 @@ name = "Deathmatch: North Star" display_name = "North Star" desc = "flip flip flip" - + uniform = /obj/item/clothing/under/suit/carpskin head = /obj/item/clothing/head/fedora/carpskin gloves = /obj/item/clothing/gloves/rapid @@ -212,7 +214,7 @@ name = "Deathmatch: Janitor" display_name = "Janitor" desc = "Regular work" - + uniform = /obj/item/clothing/under/rank/civilian/janitor suit = /obj/item/clothing/suit/caution head = /obj/item/reagent_containers/cup/bucket @@ -229,7 +231,7 @@ name = "Deathmatch: Surgeon" display_name = "Surgeon" desc = "Treatment has come" - + uniform = /obj/item/clothing/under/rank/medical/scrubs/blue suit = /obj/item/clothing/suit/apron/surgical head = /obj/item/clothing/head/utility/surgerycap @@ -238,7 +240,7 @@ l_pocket = /obj/item/reagent_containers/hypospray/combat r_pocket = /obj/item/reagent_containers/hypospray/medipen/penthrite l_hand = /obj/item/chainsaw - + backpack_contents = list( /obj/item/storage/medkit/tactical, /obj/item/reagent_containers/hypospray/medipen/stimulants, @@ -248,7 +250,7 @@ name = "Deathmatch: Raider" display_name = "Raider" desc = "Not from Shadow Legends" - + l_hand = /obj/item/nullrod/claymore/chainsaw_sword r_pocket = /obj/item/switchblade uniform = /obj/item/clothing/under/costume/jabroni @@ -260,7 +262,7 @@ name = "DM: Clown" display_name = "Clown (Man Of Honk)" desc = "Who called this honking clown" - + uniform = /datum/outfit/job/clown::uniform belt = /datum/outfit/job/clown::belt shoes = /datum/outfit/job/clown::shoes @@ -285,7 +287,7 @@ name = "Deathmatch: Coder" display_name = "Coder" desc = "What" - + l_hand = /obj/item/toy/katana uniform = /obj/item/clothing/under/costume/schoolgirl suit = /obj/item/clothing/suit/costume/joker @@ -299,7 +301,7 @@ name = "Deathmatch: Engineer" display_name = "Engineer" desc = "Meet the engineer" - + l_hand = /obj/item/storage/toolbox/emergency/turret uniform = /obj/item/clothing/under/rank/engineering/engineer shoes = /obj/item/clothing/shoes/magboots @@ -311,7 +313,7 @@ name = "Deathmatch: Scientist" display_name = "Scientist" desc = "What a nerd" - + uniform = /obj/item/clothing/under/rank/rnd/scientist suit = /obj/item/clothing/suit/armor/reactive/stealth mask = /obj/item/clothing/mask/gas @@ -353,7 +355,7 @@ name = "Deathmatch: Ripper" display_name = "Ripper" desc = "Die die die!!!" - + l_hand = /obj/item/gun/ballistic/shotgun/hook r_hand = /obj/item/gun/ballistic/shotgun/hook uniform = /obj/item/clothing/under/costume/skeleton @@ -366,7 +368,7 @@ name = "Deathmatch: Cowboy" display_name = "Cowboy" desc = "Yeehaw partner" - + r_hand = /obj/item/clothing/mask/cigarette/cigar l_hand = /obj/item/melee/curator_whip l_pocket = /obj/item/lighter diff --git a/code/modules/deathmatch/deathmatch_lobby.dm b/code/modules/deathmatch/deathmatch_lobby.dm index a8169190fe8d6..e498f662b5e39 100644 --- a/code/modules/deathmatch/deathmatch_lobby.dm +++ b/code/modules/deathmatch/deathmatch_lobby.dm @@ -65,7 +65,7 @@ /datum/deathmatch_lobby/proc/find_spawns_and_start_delay(datum/lazy_template/source, list/atoms) SIGNAL_HANDLER for(var/thing in atoms) - if(istype(thing, /obj/effect/landmark/deathmatch_player_spawn)) + if(istype(thing, /obj/effect/landmark/deathmatch_player_spawn)) player_spawns += thing UnregisterSignal(source, COMSIG_LAZY_TEMPLATE_LOADED) @@ -147,10 +147,10 @@ if(players.len) var/list/winner_info = players[pick(players)] if(!isnull(winner_info["mob"])) - winner = winner_info["mob"] //only one should remain anyway but incase of a draw - + winner = winner_info["mob"] //only one should remain anyway but incase of a draw + announce(span_reallybig("THE GAME HAS ENDED.
THE WINNER IS: [winner ? winner.real_name : "no one"].")) - + for(var/ckey in players) var/mob/loser = players[ckey]["mob"] UnregisterSignal(loser, list(COMSIG_MOB_GHOSTIZED, COMSIG_QDELETING)) @@ -174,7 +174,7 @@ if(player_info["mob"] && player_info["mob"] == player) ckey = potential_ckey break - + if(!islist(players[ckey])) // if we STILL didnt find a good ckey return @@ -183,7 +183,7 @@ var/mob/dead/observer/ghost = !player.client ? player.get_ghost() : player.ghostize() //this doesnt work on those who used the ghost verb if(!isnull(ghost)) add_observer(ghost, (host == ckey)) - + announce(span_reallybig("[player.real_name] HAS DIED.
[players.len] REMAIN.")) if(!gibbed && !QDELING(player)) // for some reason dusting or deleting in chasm storage messes up tgui bad @@ -239,7 +239,7 @@ players[key]["host"] = TRUE break GLOB.deathmatch_game.passoff_lobby(ckey, host) - + remove_ckey_from_play(ckey) /datum/deathmatch_lobby/proc/join(mob/player) @@ -295,6 +295,11 @@ /datum/deathmatch_lobby/ui_state(mob/user) return GLOB.observer_state +/// fills the lobby with fake players for the sake of UI debug, can only be called via VV +/datum/deathmatch_lobby/proc/fakefill(count) + for(var/i = 1 to count) + players["[rand(1,999)]"] = list("mob" = usr, "host" = FALSE, "ready" = FALSE, "loadout" = pick(loadouts)) + /datum/deathmatch_lobby/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, null) if(!ui) @@ -314,7 +319,7 @@ .["admin"] = check_rights_for(user.client, R_ADMIN) .["global_chat"] = global_chat .["playing"] = playing - .["loadouts"] = list() + .["loadouts"] = list("Randomize") for (var/datum/outfit/deathmatch_loadout/loadout as anything in loadouts) .["loadouts"] += initial(loadout.display_name) .["map"] = list() @@ -371,6 +376,9 @@ return FALSE if (params["player"] != usr.ckey && host != usr.ckey) return FALSE + if (params["loadout"] == "Randomize") + players[params["player"]]["loadout"] = pick(loadouts) + return TRUE for (var/datum/outfit/deathmatch_loadout/possible_loadout as anything in loadouts) if (params["loadout"] != initial(possible_loadout.display_name)) continue diff --git a/code/modules/deathmatch/deathmatch_maps.dm b/code/modules/deathmatch/deathmatch_maps.dm index 60594d903bb02..d437bffbb3cd7 100644 --- a/code/modules/deathmatch/deathmatch_maps.dm +++ b/code/modules/deathmatch/deathmatch_maps.dm @@ -107,6 +107,7 @@ desc = "Choose your battler!" max_players = 10 allowed_loadouts = list( + /datum/outfit/deathmatch_loadout/battler/soldier, // First because its a good and easy loadout and is picked by default /datum/outfit/deathmatch_loadout/battler/bloodminer, /datum/outfit/deathmatch_loadout/battler/clown, /datum/outfit/deathmatch_loadout/battler/cowboy, @@ -117,7 +118,6 @@ /datum/outfit/deathmatch_loadout/battler/raider, /datum/outfit/deathmatch_loadout/battler/ripper, /datum/outfit/deathmatch_loadout/battler/scientist, - /datum/outfit/deathmatch_loadout/battler/soldier, /datum/outfit/deathmatch_loadout/battler/surgeon, /datum/outfit/deathmatch_loadout/battler/tgcoder, /datum/outfit/deathmatch_loadout/naked, diff --git a/code/modules/economy/holopay.dm b/code/modules/economy/holopay.dm index c9ce23ccb98de..4755df02fbdbf 100644 --- a/code/modules/economy/holopay.dm +++ b/code/modules/economy/holopay.dm @@ -137,7 +137,7 @@ ui = new(user, src, "HoloPay") ui.open() -/obj/structure/holopay/ui_status(mob/user) +/obj/structure/holopay/ui_status(mob/user, datum/ui_state/state) . = ..() if(!in_range(user, src) && !isobserver(user)) return UI_CLOSE diff --git a/code/modules/food_and_drinks/machinery/processor.dm b/code/modules/food_and_drinks/machinery/processor.dm index 0aa5532de13df..e1d027306eac6 100644 --- a/code/modules/food_and_drinks/machinery/processor.dm +++ b/code/modules/food_and_drinks/machinery/processor.dm @@ -69,8 +69,9 @@ var/cached_multiplier = (recipe.food_multiplier * rating_amount) for(var/i in 1 to cached_multiplier) var/atom/processed_food = new recipe.output(drop_location()) - processed_food.reagents.clear_reagents() - what.reagents.copy_to(processed_food, what.reagents.total_volume, multiplier = 1 / cached_multiplier) + if(processed_food.reagents && what.reagents) + processed_food.reagents.clear_reagents() + what.reagents.copy_to(processed_food, what.reagents.total_volume, multiplier = 1 / cached_multiplier) if(cached_mats) processed_food.set_custom_materials(cached_mats, 1 / cached_multiplier) diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm index 93851558cffe3..a9f1ad23d8e26 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pie.dm @@ -237,3 +237,11 @@ ) result = /obj/item/food/pie/asdfpie category = CAT_PIE + +/datum/crafting_recipe/food/bacid_pie + reqs = list( + /obj/item/food/pie/plain = 1, + /obj/item/stock_parts/cell = 2, + ) + result = /obj/item/food/pie/bacid_pie + category = CAT_PIE diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm index 00a52ab82a868..5b8ce2a930939 100644 --- a/code/modules/hydroponics/biogenerator.dm +++ b/code/modules/hydroponics/biogenerator.dm @@ -458,7 +458,7 @@ update_appearance(UPDATE_ICON) -/obj/machinery/biogenerator/ui_status(mob/user) +/obj/machinery/biogenerator/ui_status(mob/user, datum/ui_state/state) if(machine_stat & BROKEN || panel_open) return UI_CLOSE diff --git a/code/modules/hydroponics/grown/cereals.dm b/code/modules/hydroponics/grown/cereals.dm index 948a9d404c69e..2bcc2860458bb 100644 --- a/code/modules/hydroponics/grown/cereals.dm +++ b/code/modules/hydroponics/grown/cereals.dm @@ -89,7 +89,7 @@ gender = PLURAL bite_consumption_mod = 0.5 seed = /obj/item/seeds/wheat/meat - foodtypes = MEAT | GRAIN + foodtypes = MEAT grind_results = list(/datum/reagent/consumable/flour = 0, /datum/reagent/blood = 0) tastes = list("meatwheat" = 1) can_distill = FALSE diff --git a/code/modules/jobs/job_types/cook.dm b/code/modules/jobs/job_types/cook.dm index e96bae827fa9b..2be7bba5154d4 100644 --- a/code/modules/jobs/job_types/cook.dm +++ b/code/modules/jobs/job_types/cook.dm @@ -88,6 +88,17 @@ if(!visualsOnly) other_chefs.cooks++ +/datum/outfit/job/cook/post_equip(mob/living/carbon/human/user, visualsOnly = FALSE) + . = ..() + // Update PDA to match possible new trim. + var/obj/item/card/id/worn_id = user.wear_id + var/obj/item/modular_computer/pda/pda = user.get_item_by_slot(pda_slot) + if(!istype(worn_id) || !istype(pda)) + return + var/assignment = worn_id.get_trim_assignment() + if(!isnull(assignment)) + pda.imprint_id(user.real_name, assignment) + /datum/outfit/job/cook/get_types_to_preload() . = ..() . += /obj/item/clothing/suit/apron/chef diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm index 25d76bf0156d8..35a3a218f7b1a 100644 --- a/code/modules/jobs/job_types/security_officer.dm +++ b/code/modules/jobs/job_types/security_officer.dm @@ -117,6 +117,12 @@ GLOBAL_LIST_EMPTY(security_officer_distribution) SSid_access.apply_trim_to_card(worn_id, dep_trim) spawning.sec_hud_set_ID() + // Update PDA to match new trim. + var/obj/item/modular_computer/pda/pda = spawning.get_item_by_slot(ITEM_SLOT_BELT) + var/assignment = worn_id.get_trim_assignment() + if(istype(pda) && !isnull(assignment)) + pda.imprint_id(spawning.real_name, assignment) + var/spawn_point = pick(LAZYACCESS(GLOB.department_security_spawns, department)) if(!CONFIG_GET(flag/sec_start_brig) && (destination || spawn_point)) diff --git a/code/modules/library/admin_only.dm b/code/modules/library/admin_only.dm index 3e10617d9fe98..847f28070e6ac 100644 --- a/code/modules/library/admin_only.dm +++ b/code/modules/library/admin_only.dm @@ -80,7 +80,7 @@ page_count = round(max(bookcount - 1, 0) / BOOKS_PER_PAGE) //This is just floor() search_page = clamp(search_page, 0, page_count) -/obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker/ui_status(mob/user) +/obj/machinery/computer/libraryconsole/admin_only_do_not_map_in_you_fucker/ui_status(mob/user, datum/ui_state/state) if(!check_rights_for(user.client, R_BAN)) return UI_CLOSE if(!SSdbcore.Connect()) @@ -339,7 +339,7 @@ ui.set_autoupdate(FALSE) // Nothing is changing here brother ui.open() -/datum/admin_book_viewer/ui_status(mob/user) +/datum/admin_book_viewer/ui_status(mob/user, datum/ui_state/state) if(!check_rights_for(user.client, R_BAN)) return UI_CLOSE return UI_INTERACTIVE diff --git a/code/modules/library/skill_learning/skill_station.dm b/code/modules/library/skill_learning/skill_station.dm index 697b34d742e2d..b376501f758fd 100644 --- a/code/modules/library/skill_learning/skill_station.dm +++ b/code/modules/library/skill_learning/skill_station.dm @@ -10,7 +10,7 @@ occupant_typecache = list(/mob/living/carbon) //todo make occupant_typecache per type state_open = TRUE // Only opens UI when inside; also, you can use the machine while lying down (for paraplegics and the like) - interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_IGNORE_MOBILITY + interaction_flags_atom = parent_type::interaction_flags_atom | INTERACT_ATOM_IGNORE_MOBILITY circuit = /obj/item/circuitboard/machine/skill_station /// Currently implanting/removing var/working = FALSE diff --git a/code/modules/mining/equipment/mineral_scanner.dm b/code/modules/mining/equipment/mineral_scanner.dm index 484720e7159c7..92464c3c7d83a 100644 --- a/code/modules/mining/equipment/mineral_scanner.dm +++ b/code/modules/mining/equipment/mineral_scanner.dm @@ -49,6 +49,9 @@ /// The range of the scanner in tiles. var/range = 7 +/obj/item/t_scanner/adv_mining_scanner/cyborg + shut_off_on_unequip = FALSE + /obj/item/t_scanner/adv_mining_scanner/cyborg/Initialize(mapload) . = ..() toggle_on() 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 64cff6780dfb9..e9dc43837fff6 100644 --- a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm +++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm @@ -16,18 +16,19 @@ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID maxHealth = 220 health = 220 + initial_language_holder = /datum/language_holder/monkey response_help_continuous = "prods" response_help_simple = "prod" response_disarm_continuous = "challenges" response_disarm_simple = "challenge" response_harm_continuous = "thumps" response_harm_simple = "thump" - speed = 0.5 + speed = -0.1 melee_attack_cooldown = CLICK_CD_MELEE - melee_damage_lower = 15 - melee_damage_upper = 18 + melee_damage_lower = 25 + melee_damage_upper = 30 damage_coeff = list(BRUTE = 1, BURN = 1.5, TOX = 1.5, STAMINA = 0, OXY = 1.5) - obj_damage = 20 + obj_damage = 40 attack_verb_continuous = "pummels" attack_verb_simple = "pummel" attack_sound = 'sound/weapons/punch1.ogg' @@ -123,7 +124,7 @@ /// Gorillas are slower when carrying something /datum/movespeed_modifier/gorilla_standing blacklisted_movetypes = (FLYING|FLOATING) - multiplicative_slowdown = 0.5 + multiplicative_slowdown = 1.2 /// A smaller gorilla summoned via magic /mob/living/basic/gorilla/lesser diff --git a/code/modules/mob/living/carbon/alien/adult/queen.dm b/code/modules/mob/living/carbon/alien/adult/queen.dm index 1a08d2446d257..4387f7db3eca0 100644 --- a/code/modules/mob/living/carbon/alien/adult/queen.dm +++ b/code/modules/mob/living/carbon/alien/adult/queen.dm @@ -19,7 +19,7 @@ // as a wise man once wrote: "pull over that ass too fat" REMOVE_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) // that'd be a too cheeky shield bashing strat - ADD_TRAIT(src, TRAIT_SHOVE_KNOCKDOWN_BLOCKED, INNATE_TRAIT) + ADD_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, INNATE_TRAIT) AddComponent(/datum/component/seethrough_mob) /mob/living/carbon/alien/adult/royal/on_lying_down(new_lying_angle) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 7c036fe22390d..84fe6dd5edf41 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -85,12 +85,18 @@ span_userdanger("You violently crash into [victim][extra_speed ? " extra hard" : ""], but [victim] managed to block the worst of it!")) log_combat(src, victim, "crashed into and was blocked by") return + else if(HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) + victim.take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5) + victim.apply_damage(10 + 10 * extra_speed, STAMINA) + victim.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 2, 10 SECONDS) + visible_message(span_danger("[src] crashes into [victim][extra_speed ? " really hard" : ""], but [victim] was able to stay on their feet!"),\ + span_userdanger("You violently crash into [victim][extra_speed ? " extra hard" : ""], but [victim] managed to stay on their feet!")) else victim.Paralyze(2 SECONDS) victim.take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5) 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" : ""]!")) - log_combat(src, victim, "crashed into") + log_combat(src, victim, "crashed into") if(oof_noise) playsound(src,'sound/weapons/punch1.ogg',50,TRUE) @@ -1023,6 +1029,7 @@ set_usable_hands(usable_hands + 1) synchronize_bodytypes() + synchronize_bodyshapes() ///Proc to hook behavior on bodypart removals. Do not directly call. You're looking for [/obj/item/bodypart/proc/drop_limb()]. /mob/living/carbon/proc/remove_bodypart(obj/item/bodypart/old_bodypart, special) @@ -1049,6 +1056,7 @@ set_usable_hands(usable_hands - 1) synchronize_bodytypes() + synchronize_bodyshapes() ///Updates the bodypart speed modifier based on our bodyparts. /mob/living/carbon/proc/update_bodypart_speed_modifier() diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm index a8b7af95ae611..d3e57c4ec1df1 100644 --- a/code/modules/mob/living/carbon/carbon_defines.dm +++ b/code/modules/mob/living/carbon/carbon_defines.dm @@ -118,6 +118,9 @@ var/last_top_offset /// A bitfield of "bodytypes", updated by /obj/item/bodypart/proc/synchronize_bodytypes() - var/bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC + var/bodytype = BODYTYPE_ORGANIC + + /// A bitfield of "bodyshapes", updated by /obj/item/bodypart/proc/synchronize_bodyshapes() + var/bodyshape = BODYSHAPE_HUMANOID COOLDOWN_DECLARE(bleeding_message_cd) diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index 6b97a36bab399..e37048ca32fee 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -34,33 +34,25 @@ . += span_deadsay("It appears that [t_his] brain is missing...") 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" + for(var/obj/item/bodypart/bodypart as anything in bodyparts) + for(var/obj/item/embedded_item as anything in bodypart.embedded_objects) + if(embedded_item.isEmbedHarmless()) + msg += "[t_He] [t_has] [icon2html(embedded_item, user)] \a [embedded_item] stuck to [t_his] [bodypart.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" + msg += "[t_He] [t_has] [icon2html(embedded_item, user)] \a [embedded_item] embedded in [t_his] [bodypart.name]!\n" + for(var/datum/wound/bodypart_wound as anything in bodypart.wounds) + msg += "[bodypart_wound.get_examine_description(user)]\n" - for(var/X in disabled) - var/obj/item/bodypart/BP = X + for(var/obj/item/bodypart/disabled_limb as anything in get_disabled_limbs()) 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 = (disabled_limb.brute_dam >= disabled_limb.burn_dam) ? disabled_limb.heavy_brute_msg : disabled_limb.heavy_burn_msg + msg += "[t_His] [disabled_limb.name] is [damage_text]!\n" - for(var/t in missing) - if(t == BODY_ZONE_HEAD) - msg += "[span_deadsay("[t_His] [parse_zone(t)] is missing!")]\n" + for(var/obj/item/bodypart/missing_limb as anything in get_missing_limbs()) + if(missing_limb == BODY_ZONE_HEAD) + msg += "[span_deadsay("[t_His] [parse_zone(missing_limb)] is missing!")]\n" continue - msg += "[span_warning("[t_His] [parse_zone(t)] is missing!")]\n" + msg += "[span_warning("[t_His] [parse_zone(missing_limb)] is missing!")]\n" var/temp = getBruteLoss() diff --git a/code/modules/mob/living/carbon/human/_species.dm b/code/modules/mob/living/carbon/human/_species.dm index 3ac855061ed29..ff07ad2ef0e73 100644 --- a/code/modules/mob/living/carbon/human/_species.dm +++ b/code/modules/mob/living/carbon/human/_species.dm @@ -693,7 +693,7 @@ GLOBAL_LIST_EMPTY(features_by_species) working_shirt.pixel_y += height_offset standing += working_shirt - if(species_human.socks && species_human.num_legs >= 2 && !(species_human.bodytype & BODYTYPE_DIGITIGRADE)) + if(species_human.socks && species_human.num_legs >= 2 && !(species_human.bodyshape & BODYSHAPE_DIGITIGRADE)) var/datum/sprite_accessory/socks/socks = GLOB.socks_list[species_human.socks] if(socks) standing += mutable_appearance(socks.icon, socks.icon_state, -BODY_LAYER) @@ -911,7 +911,7 @@ GLOBAL_LIST_EMPTY(features_by_species) if(ITEM_SLOT_FEET) if(H.num_legs < 2) return FALSE - if((H.bodytype & BODYTYPE_DIGITIGRADE) && !(I.item_flags & IGNORE_DIGITIGRADE)) + if((H.bodyshape & BODYSHAPE_DIGITIGRADE) && !(I.item_flags & IGNORE_DIGITIGRADE)) if(!(I.supports_variations_flags & (CLOTHING_DIGITIGRADE_VARIATION|CLOTHING_DIGITIGRADE_VARIATION_NO_NEW_ICON))) if(!disable_warning) to_chat(H, span_warning("The footwear around here isn't compatible with your feet!")) @@ -942,7 +942,7 @@ GLOBAL_LIST_EMPTY(features_by_species) return equip_delay_self_check(I, H, bypass_equip_delay_self) if(ITEM_SLOT_ICLOTHING) var/obj/item/bodypart/chest = H.get_bodypart(BODY_ZONE_CHEST) - if(chest && (chest.bodytype & BODYTYPE_MONKEY)) + if(chest && (chest.bodyshape & BODYSHAPE_MONKEY)) if(!(I.supports_variations_flags & CLOTHING_MONKEY_VARIATION)) if(!disable_warning) to_chat(H, span_warning("[I] doesn't fit your [chest.name]!")) @@ -1201,13 +1201,15 @@ GLOBAL_LIST_EMPTY(features_by_species) log_combat(user, target, "punched") //If we rolled a punch high enough to hit our stun threshold, or our target is staggered and they have at least 40 damage+stamina loss, we knock them down - if((target.stat != DEAD) && prob(limb_accuracy) || (target.stat != DEAD) && staggered && (target.getStaminaLoss() + user.getBruteLoss()) >= 40) - target.visible_message(span_danger("[user] knocks [target] down!"), \ - span_userdanger("You're knocked down by [user]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, user) - to_chat(user, span_danger("You knock [target] down!")) - var/knockdown_duration = 4 SECONDS + (target.getStaminaLoss() + (target.getBruteLoss()*0.5))*0.8 //50 total damage = 4 second base stun + 4 second stun modifier = 8 second knockdown duration - target.apply_effect(knockdown_duration, EFFECT_KNOCKDOWN, armor_block) - log_combat(user, target, "got a stun punch with their previous punch") + //This does not work against opponents who are knockdown immune, such as from wearing riot armor. + if(!HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) + if((target.stat != DEAD) && prob(limb_accuracy) || (target.stat != DEAD) && staggered && (target.getStaminaLoss() + user.getBruteLoss()) >= 40) + target.visible_message(span_danger("[user] knocks [target] down!"), \ + span_userdanger("You're knocked down by [user]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, user) + to_chat(user, span_danger("You knock [target] down!")) + var/knockdown_duration = 4 SECONDS + (target.getStaminaLoss() + (target.getBruteLoss()*0.5))*0.8 //50 total damage = 4 second base stun + 4 second stun modifier = 8 second knockdown duration + target.apply_effect(knockdown_duration, EFFECT_KNOCKDOWN, armor_block) + log_combat(user, target, "got a stun punch with their previous punch") /datum/species/proc/disarm(mob/living/carbon/human/user, mob/living/carbon/human/target, datum/martial_art/attacker_style) if(user.body_position != STANDING_UP) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 1860fd0dd0917..89ad4700aad71 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -459,30 +459,34 @@ return FALSE if (target.stat == DEAD || HAS_TRAIT(target, TRAIT_FAKEDEATH)) - to_chat(src, span_warning("[target.name] is dead!")) + balloon_alert(src, "[target.p_they()] [target.p_are()] dead!") return FALSE if (is_mouth_covered()) - to_chat(src, span_warning("Remove your mask first!")) + balloon_alert(src, "remove your mask first!") return FALSE if (target.is_mouth_covered()) - to_chat(src, span_warning("Remove [p_their()] mask first!")) + balloon_alert(src, "remove [target.p_their()] mask first!") return FALSE - if (!get_organ_slot(ORGAN_SLOT_LUNGS)) - to_chat(src, span_warning("You have no lungs to breathe with, so you cannot perform CPR!")) + if(HAS_TRAIT_FROM(src, TRAIT_NOBREATH, DISEASE_TRAIT)) + to_chat(src, span_warning("you can't breathe!")) return FALSE - if (HAS_TRAIT(src, TRAIT_NOBREATH)) - to_chat(src, span_warning("You do not breathe, so you cannot perform CPR!")) + var/obj/item/organ/internal/lungs/human_lungs = get_organ_slot(ORGAN_SLOT_LUNGS) + if(isnull(human_lungs)) + balloon_alert(src, "you don't have lungs!") + return FALSE + if(human_lungs.organ_flags & ORGAN_FAILING) + balloon_alert(src, "your lungs are too damaged!") return FALSE visible_message(span_notice("[src] is trying to perform CPR on [target.name]!"), \ span_notice("You try to perform CPR on [target.name]... Hold still!")) if (!do_after(src, delay = panicking ? CPR_PANIC_SPEED : (3 SECONDS), target = target)) - to_chat(src, span_warning("You fail to perform CPR on [target]!")) + balloon_alert(src, "you fail to perform CPR!") return FALSE if (target.health > target.crit_threshold) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index b976b2952d406..6e1f9037018b6 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -146,7 +146,7 @@ return if(!(shove_flags & SHOVE_KNOCKDOWN_BLOCKED)) target.Knockdown(SHOVE_KNOCKDOWN_HUMAN) - if(!HAS_TRAIT(src, TRAIT_SHOVE_KNOCKDOWN_BLOCKED)) + if(!HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) Knockdown(SHOVE_KNOCKDOWN_COLLATERAL) target.visible_message(span_danger("[shover] shoves [target.name] into [name]!"), span_userdanger("You're shoved into [name] by [shover]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, src) 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 8d4b2d3110343..290fe4ce03b94 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -93,26 +93,26 @@ There are several things that need to be remembered: var/mutable_appearance/uniform_overlay //This is how non-humanoid clothing works. You check if the mob has the right bodyflag, and the clothing has the corresponding clothing flag. - //handled_by_bodytype is used to track whether or not we successfully used an alternate sprite. It's set to TRUE to ease up on copy-paste. + //handled_by_bodyshape is used to track whether or not we successfully used an alternate sprite. It's set to TRUE to ease up on copy-paste. //icon_file MUST be set to null by default, or it causes issues. - //handled_by_bodytype MUST be set to FALSE under the if(!icon_exists()) statement, or everything breaks. - //"override_file = handled_by_bodytype ? icon_file : null" MUST be added to the arguments of build_worn_icon() + //handled_by_bodyshape MUST be set to FALSE under the if(!icon_exists()) statement, or everything breaks. + //"override_file = handled_by_bodyshape ? icon_file : null" MUST be added to the arguments of build_worn_icon() //Friendly reminder that icon_exists(file, state, scream = TRUE) is your friend when debugging this code. - var/handled_by_bodytype = TRUE + var/handled_by_bodyshape = TRUE var/icon_file var/woman //BEGIN SPECIES HANDLING - if((bodytype & BODYTYPE_MONKEY) && (uniform.supports_variations_flags & CLOTHING_MONKEY_VARIATION)) + if((bodyshape & BODYSHAPE_MONKEY) && (uniform.supports_variations_flags & CLOTHING_MONKEY_VARIATION)) icon_file = MONKEY_UNIFORM_FILE - else if((bodytype & BODYTYPE_DIGITIGRADE) && (uniform.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION)) + else if((bodyshape & BODYSHAPE_DIGITIGRADE) && (uniform.supports_variations_flags & CLOTHING_DIGITIGRADE_VARIATION)) icon_file = DIGITIGRADE_UNIFORM_FILE //Female sprites have lower priority than digitigrade sprites - else if(dna.species.sexes && (bodytype & BODYTYPE_HUMANOID) && physique == FEMALE && !(uniform.female_sprite_flags & NO_FEMALE_UNIFORM)) //Agggggggghhhhh + else if(dna.species.sexes && (bodyshape & BODYSHAPE_HUMANOID) && physique == FEMALE && !(uniform.female_sprite_flags & NO_FEMALE_UNIFORM)) //Agggggggghhhhh woman = TRUE if(!icon_exists(icon_file, RESOLVE_ICON_STATE(uniform))) icon_file = DEFAULT_UNIFORM_FILE - handled_by_bodytype = FALSE + handled_by_bodyshape = FALSE //END SPECIES HANDLING uniform_overlay = uniform.build_worn_icon( @@ -121,7 +121,7 @@ There are several things that need to be remembered: isinhands = FALSE, female_uniform = woman ? uniform.female_sprite_flags : null, override_state = target_overlay, - override_file = handled_by_bodytype ? icon_file : null, + override_file = handled_by_bodyshape ? icon_file : null, ) var/obj/item/bodypart/chest/my_chest = get_bodypart(BODY_ZONE_CHEST) diff --git a/code/modules/mob/living/carbon/human/monkey.dm b/code/modules/mob/living/carbon/human/monkey.dm index d11e4f5208bc7..7a2e7bb74747d 100644 --- a/code/modules/mob/living/carbon/human/monkey.dm +++ b/code/modules/mob/living/carbon/human/monkey.dm @@ -2,7 +2,6 @@ icon_state = "monkey" //for mapping race = /datum/species/monkey ai_controller = /datum/ai_controller/monkey - faction = list(FACTION_NEUTRAL, FACTION_MONKEY) /mob/living/carbon/human/species/monkey/Initialize(mapload, cubespawned = FALSE, mob/spawner) if (cubespawned) 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 b67f3efb3ef17..4de716fe953d0 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -22,6 +22,7 @@ ) 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 + inherent_factions = list(FACTION_MONKEY) sexes = FALSE species_language_holder = /datum/language_holder/monkey diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 7f58c2e911d9c..286a3b30ed843 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -61,7 +61,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 @@ -77,17 +77,17 @@ 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(STAMINA) - damage_dealt = adjustStaminaLoss(damage_amount, forced = forced) + damage_dealt = -1 * adjustStaminaLoss(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/living_defense.dm b/code/modules/mob/living/living_defense.dm index 6c6be7eeb21ee..f0f3516ae7e0e 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -744,7 +744,7 @@ . |= SHOVE_CAN_MOVE if(!buckled) . |= SHOVE_CAN_HIT_SOMETHING - if(HAS_TRAIT(src, TRAIT_SHOVE_KNOCKDOWN_BLOCKED)) + if(HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) . |= SHOVE_KNOCKDOWN_BLOCKED ///Send the chat feedback message for shoving diff --git a/code/modules/mob/living/silicon/ai/robot_control.dm b/code/modules/mob/living/silicon/ai/robot_control.dm index c4cc256244c3f..d963fc77be62f 100644 --- a/code/modules/mob/living/silicon/ai/robot_control.dm +++ b/code/modules/mob/living/silicon/ai/robot_control.dm @@ -14,7 +14,7 @@ return FALSE return TRUE -/datum/robot_control/ui_status(mob/user) +/datum/robot_control/ui_status(mob/user, datum/ui_state/state) if(is_interactable(user)) return ..() return UI_CLOSE diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index e17ba69550d34..3cd9d45f5c107 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -75,7 +75,7 @@ TRAIT_MADNESS_IMMUNE, TRAIT_MARTIAL_ARTS_IMMUNE, TRAIT_NOFIRE_SPREAD, - TRAIT_SHOVE_KNOCKDOWN_BLOCKED, + TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, ) add_traits(traits_to_apply, ROUNDSTART_TRAIT) diff --git a/code/modules/mod/mod_paint.dm b/code/modules/mod/mod_paint.dm index 320276cd00d44..240c0897b33a1 100644 --- a/code/modules/mod/mod_paint.dm +++ b/code/modules/mod/mod_paint.dm @@ -68,7 +68,7 @@ QDEL_NULL(proxy_view) current_color = COLOR_MATRIX_IDENTITY -/obj/item/mod/paint/ui_status(mob/user) +/obj/item/mod/paint/ui_status(mob/user, datum/ui_state/state) if(check_menu(editing_mod, user)) return ..() return UI_CLOSE diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm index 4d8f8b4c6b703..81ef6ac0be17a 100644 --- a/code/modules/mod/mod_theme.dm +++ b/code/modules/mod/mod_theme.dm @@ -698,7 +698,7 @@ a few years out of date, leading to an overall lower capacity for modules." default_skin = "security" armor_type = /datum/armor/mod_theme_security - complexity_max = DEFAULT_MAX_COMPLEXITY - 3 + complexity_max = DEFAULT_MAX_COMPLEXITY - 2 slowdown_inactive = 1 slowdown_active = 0.5 allowed_suit_storage = list( @@ -1575,7 +1575,9 @@ anti-corrosion coated suit for high-ranking CentCom Officers, deploying pristine protective armor and \ advanced actuators, feeling practically weightless when turned on. Scraping the paint of this suit is \ counted as a war-crime and reason for immediate execution in over fifty Nanotrasen space stations. \ - The resemblance to a Gorlex Marauder helmet is purely coincidental." + The resemblance to a Gorlex Marauder helmet is purely coincidental. This is the newest V2 revision, which has \ + reflective reinforced-plasmaglass shielding weaved with advanced kevlar fibers. Sources say that some of the armor \ + is ripped straight from an Apocryphal MODsuit." default_skin = "corporate" armor_type = /datum/armor/mod_theme_corporate resistance_flags = FIRE_PROOF|ACID_PROOF @@ -1618,11 +1620,11 @@ ) /datum/armor/mod_theme_corporate - melee = 50 - bullet = 40 - laser = 50 + melee = 65 + bullet = 65 + laser = 55 energy = 50 - bomb = 50 + bomb = 60 bio = 100 fire = 100 acid = 100 diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm index 0933c7e8f185d..0659dd6208ba6 100644 --- a/code/modules/mod/mod_types.dm +++ b/code/modules/mod/mod_types.dm @@ -55,6 +55,7 @@ /obj/item/mod/module/flashlight, /obj/item/mod/module/tether, /obj/item/mod/module/magboot, + /obj/item/mod/module/headprotector, ) default_pins = list( /obj/item/mod/module/magboot, @@ -72,6 +73,7 @@ /obj/item/mod/module/magboot, /obj/item/mod/module/t_ray, /obj/item/mod/module/quick_carry, + /obj/item/mod/module/headprotector, ) default_pins = list( /obj/item/mod/module/magboot, @@ -87,6 +89,7 @@ /obj/item/mod/module/rad_protection, /obj/item/mod/module/flashlight, /obj/item/mod/module/jetpack, + /obj/item/mod/module/headprotector, ) default_pins = list( /obj/item/mod/module/magboot/advanced, @@ -153,6 +156,7 @@ /obj/item/mod/module/flashlight, /obj/item/mod/module/circuit, /obj/item/mod/module/t_ray, + /obj/item/mod/module/headprotector, ) /obj/item/mod/control/pre_equipped/security @@ -165,6 +169,7 @@ /obj/item/mod/module/criminalcapture, /obj/item/mod/module/dispenser/mirage, /obj/item/mod/module/quick_cuff, + /obj/item/mod/module/headprotector, ) /obj/item/mod/control/pre_equipped/safeguard @@ -179,6 +184,7 @@ /obj/item/mod/module/projectile_dampener, /obj/item/mod/module/pepper_shoulders, /obj/item/mod/module/quick_cuff, + /obj/item/mod/module/headprotector, ) default_pins = list( /obj/item/mod/module/jetpack, @@ -194,6 +200,7 @@ /obj/item/mod/module/jetpack/advanced, /obj/item/mod/module/pathfinder, /obj/item/mod/module/quick_cuff, + /obj/item/mod/module/headprotector, ) default_pins = list( /obj/item/mod/module/jetpack/advanced, diff --git a/code/modules/mod/modules/modules_antag.dm b/code/modules/mod/modules/modules_antag.dm index cf72f62d6c4a5..a35e39365b948 100644 --- a/code/modules/mod/modules/modules_antag.dm +++ b/code/modules/mod/modules/modules_antag.dm @@ -11,7 +11,7 @@ module_type = MODULE_TOGGLE active_power_cost = DEFAULT_CHARGE_DRAIN * 0.3 removable = FALSE - incompatible_modules = list(/obj/item/mod/module/armor_booster, /obj/item/mod/module/welding) + incompatible_modules = list(/obj/item/mod/module/armor_booster, /obj/item/mod/module/welding, /obj/item/mod/module/headprotector) cooldown_time = 0.5 SECONDS overlay_state_inactive = "module_armorbooster_off" overlay_state_active = "module_armorbooster_on" @@ -26,6 +26,8 @@ var/list/armor_mod = /datum/armor/mod_module_armor_boost /// List of parts of the suit that are spaceproofed, for giving them back the pressure protection. var/list/spaceproofed = list() + /// List of traits added when the mod is activated + var/list/traits_to_add = list(TRAIT_HEAD_INJURY_BLOCKED) /datum/armor/mod_module_armor_boost melee = 25 @@ -50,6 +52,7 @@ actual_speed_added = max(0, min(mod.slowdown_active, speed_added)) mod.slowdown -= actual_speed_added mod.wearer.update_equipment_speed_mods() + mod.wearer.add_traits(traits_to_add, MOD_TRAIT) var/list/parts = mod.mod_parts + mod for(var/obj/item/part as anything in parts) part.set_armor(part.get_armor().add_other_armor(armor_mod)) @@ -69,6 +72,7 @@ balloon_alert(mod.wearer, "armor retracts, EVA ready") mod.slowdown += actual_speed_added mod.wearer.update_equipment_speed_mods() + mod.wearer.remove_traits(traits_to_add, MOD_TRAIT) var/list/parts = mod.mod_parts + mod for(var/obj/item/part as anything in parts) part.set_armor(part.get_armor().subtract_other_armor(armor_mod)) @@ -483,12 +487,15 @@ /obj/item/mod/module/infiltrator name = "MOD infiltration core programs module" desc = "The primary stealth systems operating within the suit. Utilizing electromagnetic signals, \ - the wearer simply cannot be observed closely, or heard clearly by those around them." + the wearer simply cannot be observed closely, or heard clearly by those around them.\ + It also contains some dampening systems to help protect a user from blows to the head." icon_state = "infiltrator" complexity = 0 removable = FALSE idle_power_cost = DEFAULT_CHARGE_DRAIN * 0 - incompatible_modules = list(/obj/item/mod/module/infiltrator, /obj/item/mod/module/armor_booster, /obj/item/mod/module/welding) + incompatible_modules = list(/obj/item/mod/module/infiltrator, /obj/item/mod/module/armor_booster, /obj/item/mod/module/welding, /obj/item/mod/module/headprotector) + /// List of traits added when the suit is activated + var/list/traits_to_add = list(TRAIT_SILENT_FOOTSTEPS, TRAIT_UNKNOWN, TRAIT_HEAD_INJURY_BLOCKED) /obj/item/mod/module/infiltrator/on_install() mod.item_flags |= EXAMINE_SKIP @@ -497,11 +504,11 @@ mod.item_flags &= ~EXAMINE_SKIP /obj/item/mod/module/infiltrator/on_suit_activation() - mod.wearer.add_traits(list(TRAIT_SILENT_FOOTSTEPS, TRAIT_UNKNOWN), MOD_TRAIT) + mod.wearer.add_traits(traits_to_add, MOD_TRAIT) mod.helmet.flash_protect = FLASH_PROTECTION_WELDER /obj/item/mod/module/infiltrator/on_suit_deactivation(deleting = FALSE) - mod.wearer.remove_traits(list(TRAIT_SILENT_FOOTSTEPS, TRAIT_UNKNOWN), MOD_TRAIT) + mod.wearer.remove_traits(traits_to_add, MOD_TRAIT) if(deleting) return mod.helmet.flash_protect = initial(mod.helmet.flash_protect) diff --git a/code/modules/mod/modules/modules_engineering.dm b/code/modules/mod/modules/modules_engineering.dm index 9095bbd2c2467..fa746048e8201 100644 --- a/code/modules/mod/modules/modules_engineering.dm +++ b/code/modules/mod/modules/modules_engineering.dm @@ -204,6 +204,24 @@ rcd_scan(src, fade_time = 10 SECONDS) drain_power(use_power_cost) +///Safety-First Head Protection - Protects your brain matter from sudden impacts. +/obj/item/mod/module/headprotector + name = "MOD Safety-First Head Protection module" + desc = "A series of dampening plates are installed along the back and upper areas of \ + the helmet. These plates absorb abrupt kinetic shocks delivered to the skull. \ + The bulk of this module prevents it from being installed in any suit that is capable \ + of combat armor adjustments. However, the rudimentry nature of the module makes it \ + relatively easy to install into most other suits." + icon_state = "welding" + complexity = 1 + incompatible_modules = list(/obj/item/mod/module/armor_booster, /obj/item/mod/module/infiltrator) + +/obj/item/mod/module/constructor/on_suit_activation() + ADD_TRAIT(mod.wearer, TRAIT_HEAD_INJURY_BLOCKED, MOD_TRAIT) + +/obj/item/mod/module/constructor/on_suit_deactivation(deleting = FALSE) + REMOVE_TRAIT(mod.wearer, TRAIT_HEAD_INJURY_BLOCKED, MOD_TRAIT) + ///Mister - Sprays water over an area. /obj/item/mod/module/mister name = "MOD water mister module" diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm index 0b8c0299f04b9..f5033cea4f67e 100644 --- a/code/modules/mod/modules/modules_security.dm +++ b/code/modules/mod/modules/modules_security.dm @@ -587,10 +587,10 @@ incompatible_modules = list(/obj/item/mod/module/shove_blocker) /obj/item/mod/module/shove_blocker/on_suit_activation() - mod.wearer.add_traits(list(TRAIT_SHOVE_KNOCKDOWN_BLOCKED, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH), MOD_TRAIT) + mod.wearer.add_traits(list(TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH), MOD_TRAIT) /obj/item/mod/module/shove_blocker/on_suit_deactivation(deleting = FALSE) - mod.wearer.remove_traits(list(TRAIT_SHOVE_KNOCKDOWN_BLOCKED, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH), MOD_TRAIT) + mod.wearer.remove_traits(list(TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, TRAIT_NO_STAGGER, TRAIT_NO_THROW_HITPUSH), MOD_TRAIT) /obj/item/mod/module/shove_blocker/locked name = "superglued MOD bulwark module" diff --git a/code/modules/modular_computers/computers/item/pda.dm b/code/modules/modular_computers/computers/item/pda.dm index 38e64d6742c64..674520f1fb211 100644 --- a/code/modules/modular_computers/computers/item/pda.dm +++ b/code/modules/modular_computers/computers/item/pda.dm @@ -13,7 +13,7 @@ steel_sheet_cost = 2 custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT * 3, /datum/material/glass=SMALL_MATERIAL_AMOUNT, /datum/material/plastic=SMALL_MATERIAL_AMOUNT) - interaction_flags_atom = INTERACT_ATOM_ALLOW_USER_LOCATION | INTERACT_ATOM_IGNORE_MOBILITY + interaction_flags_atom = parent_type::interaction_flags_atom | INTERACT_ATOM_ALLOW_USER_LOCATION | INTERACT_ATOM_IGNORE_MOBILITY icon_state_menu = "menu" max_capacity = 64 diff --git a/code/modules/modular_computers/file_system/programs/secureye.dm b/code/modules/modular_computers/file_system/programs/secureye.dm index 2b3b8f6ea8c95..8eb3190afa589 100644 --- a/code/modules/modular_computers/file_system/programs/secureye.dm +++ b/code/modules/modular_computers/file_system/programs/secureye.dm @@ -88,7 +88,7 @@ cam_screen.display_to(user) user.client.register_map_obj(cam_background) -/datum/computer_file/program/secureye/ui_status(mob/user) +/datum/computer_file/program/secureye/ui_status(mob/user, datum/ui_state/state) . = ..() if(. == UI_DISABLED) return UI_CLOSE diff --git a/code/modules/pai/card.dm b/code/modules/pai/card.dm index da3bfe4e0ce14..c1a9c5a88ba04 100644 --- a/code/modules/pai/card.dm +++ b/code/modules/pai/card.dm @@ -92,7 +92,7 @@ ui = new(user, src, "PaiCard") ui.open() -/obj/item/pai_card/ui_status(mob/user) +/obj/item/pai_card/ui_status(mob/user, datum/ui_state/state) if(user in get_nested_locs(src)) return UI_INTERACTIVE return ..() diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index 1c1daaad51140..5aac6d93bc3a3 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -333,7 +333,7 @@ return . += span_warning("You cannot read it!") -/obj/item/paper/ui_status(mob/user,/datum/ui_state/state) +/obj/item/paper/ui_status(mob/user, datum/ui_state/state) // Are we on fire? Hard to read if so if(resistance_flags & ON_FIRE) return UI_CLOSE diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index a6cb83aafc0e1..e5a30474f8721 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -598,8 +598,7 @@ GLOBAL_LIST_INIT(paper_blanks, init_paper_blanks()) toner_cartridge.charges = 0 /obj/machinery/photocopier/MouseDrop_T(mob/target, mob/user) - check_ass() //Just to make sure that you can re-drag somebody onto it after they moved off. - if(!istype(target) || target.anchored || target.buckled || !Adjacent(target) || !user.can_perform_action(src) || target == ass || copier_blocked()) + if(!istype(target) || target.anchored || target.buckled || !Adjacent(target) || !user.can_perform_action(src, action_bitflags = ALLOW_RESTING) || target == ass || copier_blocked()) return add_fingerprint(user) if(target == user) diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm index c36d9c108e28c..ae120a6d3d70a 100644 --- a/code/modules/power/apc/apc_main.dm +++ b/code/modules/power/apc/apc_main.dm @@ -393,7 +393,7 @@ update_appearance() remote_control_user = null -/obj/machinery/power/apc/ui_status(mob/user) +/obj/machinery/power/apc/ui_status(mob/user, datum/ui_state/state) . = ..() if(!QDELETED(remote_control_user) && user == remote_control_user) . = UI_INTERACTIVE diff --git a/code/modules/reagents/chemistry/holder/ui_data.dm b/code/modules/reagents/chemistry/holder/ui_data.dm index bc8b3d6c713f6..39ceaaa06f002 100644 --- a/code/modules/reagents/chemistry/holder/ui_data.dm +++ b/code/modules/reagents/chemistry/holder/ui_data.dm @@ -9,7 +9,7 @@ ui.open() -/datum/reagents/ui_status(mob/user) +/datum/reagents/ui_status(mob/user, datum/ui_state/state) return UI_INTERACTIVE //please advise /datum/reagents/ui_state(mob/user) diff --git a/code/modules/reagents/chemistry/items.dm b/code/modules/reagents/chemistry/items.dm index 37d089aab4231..25f805acdaf1b 100644 --- a/code/modules/reagents/chemistry/items.dm +++ b/code/modules/reagents/chemistry/items.dm @@ -315,7 +315,7 @@ . = ..() INVOKE_ASYNC(src, PROC_REF(remove_thermometer), user) -/obj/item/thermometer/ui_status(mob/user) +/obj/item/thermometer/ui_status(mob/user, datum/ui_state/state) if(!(in_range(src, user))) return UI_CLOSE return UI_INTERACTIVE diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 25751c5903319..188fbfe622ec9 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -2409,7 +2409,8 @@ /datum/reagent/magillitis/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() if((ishuman(affected_mob)) && current_cycle > 10) - affected_mob.gorillize() + var/mob/living/basic/gorilla/new_gorilla = affected_mob.gorillize() + new_gorilla.AddComponent(/datum/component/regenerator, regeneration_delay = 12 SECONDS, brute_per_second = 1.5, outline_colour = COLOR_PALE_GREEN) /datum/reagent/growthserum name = "Growth Serum" diff --git a/code/modules/reagents/reagent_containers/cups/glassbottle.dm b/code/modules/reagents/reagent_containers/cups/glassbottle.dm index 83754dd571f3e..9deb658250856 100644 --- a/code/modules/reagents/reagent_containers/cups/glassbottle.dm +++ b/code/modules/reagents/reagent_containers/cups/glassbottle.dm @@ -82,7 +82,7 @@ var/obj/item/bodypart/affecting = user.zone_selected //Find what the player is aiming at var/armor_block = 0 //Get the target's armor values for normal attack damage. - var/armor_duration = 0 //The more force the bottle has, the longer the duration. + var/knockdown_effectiveness = 0 //The more force the bottle has, the longer the duration. //Calculating duration and calculating damage. if(ishuman(target)) @@ -95,23 +95,23 @@ if(istype(H.head, /obj/item/clothing/head) && affecting == BODY_ZONE_HEAD) headarmor = H.head.get_armor_rating(MELEE) //Calculate the knockdown duration for the target. - armor_duration = (bottle_knockdown_duration - headarmor) + force + knockdown_effectiveness = (bottle_knockdown_duration - headarmor) + force else //Only humans can have armor, right? armor_block = living_target.run_armor_check(affecting, MELEE) if(affecting == BODY_ZONE_HEAD) - armor_duration = bottle_knockdown_duration + force + knockdown_effectiveness = bottle_knockdown_duration + force //Apply the damage! armor_block = min(90,armor_block) living_target.apply_damage(force, BRUTE, affecting, armor_block) // You are going to knock someone down for longer if they are not wearing a helmet. var/head_attack_message = "" - if(affecting == BODY_ZONE_HEAD && iscarbon(target)) + if(affecting == BODY_ZONE_HEAD && iscarbon(target) && !HAS_TRAIT(target, TRAIT_HEAD_INJURY_BLOCKED)) head_attack_message = " on the head" - if(armor_duration) - living_target.apply_effect(min(armor_duration, 200) , EFFECT_KNOCKDOWN) + if(knockdown_effectiveness && prob(knockdown_effectiveness)) + living_target.apply_effect(min(knockdown_effectiveness, 200) , EFFECT_KNOCKDOWN) //Display an attack message. if(target != user) diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index 9f1486c3d6bdf..78ffff197bce8 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -326,6 +326,7 @@ name = "disposal unit" desc = "A pneumatic waste disposal unit." icon_state = "disposal" + interaction_flags_atom = parent_type::interaction_flags_atom | INTERACT_ATOM_IGNORE_MOBILITY // attack by item places it in to disposal /obj/machinery/disposal/bin/attackby(obj/item/I, mob/user, params) diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 08c31feb06e87..0081fe052eca7 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -2049,6 +2049,17 @@ category = list( RND_CATEGORY_MODSUIT_MODULES + RND_SUBCATEGORY_MODSUIT_MODULES_ENGINEERING ) +/datum/design/module/mod_head_protection + name = "Safety-First Head Protection Module" + id = "mod_safety" + materials = list( + /datum/material/iron =SMALL_MATERIAL_AMOUNT*5, + /datum/material/glass =HALF_SHEET_MATERIAL_AMOUNT, + ) + build_path = /obj/item/mod/module/headprotector + category = list( + RND_CATEGORY_MODSUIT_MODULES + RND_SUBCATEGORY_MODSUIT_MODULES_ENGINEERING + ) /datum/design/module/mod_t_ray name = "T-Ray Scanner Module" id = "mod_t_ray" diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index 4a02e368a8e06..acf17851eb34a 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -209,6 +209,7 @@ "mod_plating_standard", "mod_storage", "mod_welding", + "mod_safety", "mod_mouthhole", "mod_flashlight", "mod_longfall", diff --git a/code/modules/research/xenobiology/crossbreeding/_misc.dm b/code/modules/research/xenobiology/crossbreeding/_misc.dm index 8eb166bf8207f..7b85a878ec39b 100644 --- a/code/modules/research/xenobiology/crossbreeding/_misc.dm +++ b/code/modules/research/xenobiology/crossbreeding/_misc.dm @@ -175,6 +175,12 @@ Slimecrossing Items w_class = WEIGHT_CLASS_SMALL icon = 'icons/obj/science/slimecrossing.dmi' icon_state = "capturedevice" + ///traits we give and remove from the mob on exit and entry + var/static/list/traits_on_transfer = list( + TRAIT_IMMOBILIZED, + TRAIT_HANDS_BLOCKED, + TRAIT_AI_PAUSED, + ) /obj/item/capturedevice/attack(mob/living/pokemon, mob/user) if(length(contents)) @@ -211,11 +217,11 @@ Slimecrossing Items /obj/item/capturedevice/proc/store(mob/living/pokemon) pokemon.forceMove(src) - pokemon.add_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED), ABSTRACT_ITEM_TRAIT) + pokemon.add_traits(traits_on_transfer, ABSTRACT_ITEM_TRAIT) pokemon.cancel_camera() /obj/item/capturedevice/proc/release() for(var/mob/living/pokemon in contents) pokemon.forceMove(get_turf(loc)) - pokemon.remove_traits(list(TRAIT_IMMOBILIZED, TRAIT_HANDS_BLOCKED), ABSTRACT_ITEM_TRAIT) + pokemon.remove_traits(traits_on_transfer, ABSTRACT_ITEM_TRAIT) pokemon.cancel_camera() diff --git a/code/modules/security_levels/keycard_authentication.dm b/code/modules/security_levels/keycard_authentication.dm index 210a1d7dc9d9b..e4b2eaa6c2829 100644 --- a/code/modules/security_levels/keycard_authentication.dm +++ b/code/modules/security_levels/keycard_authentication.dm @@ -52,7 +52,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/keycard_auth, 26) data["bsa_unlock"] = GLOB.bsa_unlock return data -/obj/machinery/keycard_auth/ui_status(mob/user) +/obj/machinery/keycard_auth/ui_status(mob/user, datum/ui_state/state) if(isdrone(user)) return UI_CLOSE if(!isanimal_or_basicmob(user)) diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm index e5b8d5e87ff8a..d92402859911a 100644 --- a/code/modules/shuttle/special.dm +++ b/code/modules/shuttle/special.dm @@ -378,15 +378,13 @@ var/change = FALSE if(payees[AM] > 0) change = TRUE - var/obj/item/holochip/HC = new /obj/item/holochip(AM.loc) //Change is made in holocredits exclusively. - HC.credits = payees[AM] - HC.name = "[HC.credits] credit holochip" + var/obj/item/holochip/holocred = new /obj/item/holochip(AM.loc, payees[AM]) //Change is made in holocredits exclusively. if(ishuman(AM)) var/mob/living/carbon/human/H = AM - if(!H.put_in_hands(HC)) - AM.pulling = HC + if(!H.put_in_hands(holocred)) + AM.pulling = holocred else - AM.pulling = HC + AM.pulling = holocred payees[AM] -= payees[AM] say("Welcome to first class, [driver_holdout ? "[driver_holdout]" : "[AM]" ]![change ? " Here is your change." : ""]") diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index c81b691980ad9..58e91646c0fee 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -34,8 +34,10 @@ * Set to BIO_STANDARD_UNJOINTED because most species have both flesh bone and blood in their limbs. */ var/biological_state = BIO_STANDARD_UNJOINTED - ///A bitfield of bodytypes for clothing, surgery, and misc information - var/bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC + ///A bitfield of bodytypes for surgery, and misc information + var/bodytype = BODYTYPE_ORGANIC + ///A bitfield of bodyshapes for clothing and other sprite information + var/bodyshape = BODYSHAPE_HUMANOID ///Defines when a bodypart should not be changed. Example: BP_BLOCK_CHANGE_SPECIES prevents the limb from being overwritten on species gain var/change_exempt_flags = NONE ///Random flags that describe this bodypart diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index fcbde3c76712b..03f4cc98e1401 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -270,7 +270,7 @@ return FALSE var/obj/item/bodypart/chest/mob_chest = new_limb_owner.get_bodypart(BODY_ZONE_CHEST) - if(mob_chest && !(mob_chest.acceptable_bodytype & bodytype) && !special) + if(mob_chest && !(mob_chest.acceptable_bodytype & bodytype) && !(mob_chest.acceptable_bodyshape & bodyshape) && !special) return FALSE return TRUE diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm index 0373401d9047c..f1ea0c06645b4 100644 --- a/code/modules/surgery/bodyparts/head.dm +++ b/code/modules/surgery/bodyparts/head.dm @@ -212,7 +212,7 @@ husk_type = "monkey" icon_state = "default_monkey_head" limb_id = SPECIES_MONKEY - bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_MONKEY should_draw_greyscale = FALSE dmg_overlay_type = SPECIES_MONKEY is_dimorphic = FALSE @@ -229,7 +229,8 @@ px_y = 0 bodypart_flags = BODYPART_UNREMOVABLE max_damage = LIMB_MAX_HP_ALIEN_CORE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodytype = BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_HUMANOID /obj/item/bodypart/head/larva icon = 'icons/mob/human/species/alien/bodyparts.dmi' diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index 52671b5fbc16c..126bd3db33a4f 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -179,6 +179,16 @@ bodytype = all_limb_flags +/// Makes sure that the owner's bodyshape flags match the flags of all of it's parts and organs +/mob/living/carbon/proc/synchronize_bodyshapes() + var/all_limb_flags = NONE + for(var/obj/item/bodypart/limb as anything in bodyparts) + for(var/obj/item/organ/external/ext_organ in limb) + all_limb_flags |= ext_organ.external_bodyshapes + all_limb_flags |= limb.bodyshape + + bodyshape = all_limb_flags + /proc/skintone2hex(skin_tone) . = 0 switch(skin_tone) diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index be1a7828c2e99..776207a2ccee9 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -13,8 +13,10 @@ grind_results = null wound_resistance = 10 bodypart_trait_source = CHEST_TRAIT + ///The bodyshape(s) allowed to attach to this chest. + var/acceptable_bodyshape = BODYSHAPE_HUMANOID ///The bodytype(s) allowed to attach to this chest. - var/acceptable_bodytype = BODYTYPE_HUMANOID + var/acceptable_bodytype = ALL var/obj/item/cavity_item @@ -78,8 +80,8 @@ should_draw_greyscale = FALSE is_dimorphic = FALSE wound_resistance = -10 - bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC - acceptable_bodytype = BODYTYPE_MONKEY + bodyshape = BODYSHAPE_MONKEY + acceptable_bodyshape = BODYSHAPE_MONKEY dmg_overlay_type = SPECIES_MONKEY /obj/item/bodypart/chest/alien @@ -87,12 +89,13 @@ icon_static = 'icons/mob/human/species/alien/bodyparts.dmi' icon_state = "alien_chest" limb_id = BODYPART_ID_ALIEN - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodytype = BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_HUMANOID is_dimorphic = FALSE should_draw_greyscale = FALSE bodypart_flags = BODYPART_UNREMOVABLE max_damage = LIMB_MAX_HP_ALIEN_CORE - acceptable_bodytype = BODYTYPE_HUMANOID + acceptable_bodyshape = BODYSHAPE_HUMANOID wing_types = NONE /obj/item/bodypart/chest/larva @@ -245,7 +248,7 @@ icon_state = "default_monkey_l_arm" limb_id = SPECIES_MONKEY should_draw_greyscale = FALSE - bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_MONKEY wound_resistance = -10 px_x = -5 px_y = -3 @@ -260,7 +263,8 @@ icon_static = 'icons/mob/human/species/alien/bodyparts.dmi' icon_state = "alien_l_arm" limb_id = BODYPART_ID_ALIEN - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodytype = BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_HUMANOID px_x = 0 px_y = 0 bodypart_flags = BODYPART_UNREMOVABLE @@ -341,7 +345,7 @@ husk_type = "monkey" icon_state = "default_monkey_r_arm" limb_id = SPECIES_MONKEY - bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_MONKEY should_draw_greyscale = FALSE wound_resistance = -10 px_x = 5 @@ -357,7 +361,8 @@ icon_static = 'icons/mob/human/species/alien/bodyparts.dmi' icon_state = "alien_r_arm" limb_id = BODYPART_ID_ALIEN - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodytype = BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_HUMANOID px_x = 0 px_y = 0 bodypart_flags = BODYPART_UNREMOVABLE @@ -457,7 +462,7 @@ icon_state = "default_monkey_l_leg" limb_id = SPECIES_MONKEY should_draw_greyscale = FALSE - bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_MONKEY wound_resistance = -10 px_y = 4 dmg_overlay_type = SPECIES_MONKEY @@ -471,7 +476,8 @@ icon_static = 'icons/mob/human/species/alien/bodyparts.dmi' icon_state = "alien_l_leg" limb_id = BODYPART_ID_ALIEN - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodytype = BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_HUMANOID px_x = 0 px_y = 0 bodypart_flags = BODYPART_UNREMOVABLE @@ -547,7 +553,7 @@ icon_state = "default_monkey_r_leg" limb_id = SPECIES_MONKEY should_draw_greyscale = FALSE - bodytype = BODYTYPE_MONKEY | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_MONKEY wound_resistance = -10 px_y = 4 dmg_overlay_type = SPECIES_MONKEY @@ -561,7 +567,8 @@ icon_static = 'icons/mob/human/species/alien/bodyparts.dmi' icon_state = "alien_r_leg" limb_id = BODYPART_ID_ALIEN - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodytype = BODYTYPE_ALIEN | BODYTYPE_ORGANIC + bodyshape = BODYSHAPE_HUMANOID px_x = 0 px_y = 0 bodypart_flags = BODYPART_UNREMOVABLE diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm index 3f5e6972ed6b5..ca4b61228da42 100644 --- a/code/modules/surgery/bodyparts/robot_bodyparts.dm +++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm @@ -23,7 +23,8 @@ icon_state = "borg_l_arm" is_dimorphic = FALSE should_draw_greyscale = FALSE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + bodytype = BODYTYPE_ROBOTIC + bodyshape = BODYSHAPE_HUMANOID change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" @@ -56,7 +57,8 @@ icon_state = "borg_r_arm" is_dimorphic = FALSE should_draw_greyscale = FALSE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + bodytype = BODYTYPE_ROBOTIC + bodyshape = BODYSHAPE_HUMANOID change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" @@ -90,7 +92,8 @@ icon_state = "borg_l_leg" is_dimorphic = FALSE should_draw_greyscale = FALSE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + bodytype = BODYTYPE_ROBOTIC + bodyshape = BODYSHAPE_HUMANOID change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" @@ -137,7 +140,8 @@ icon_state = "borg_r_leg" is_dimorphic = FALSE should_draw_greyscale = FALSE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + bodytype = BODYTYPE_ROBOTIC + bodyshape = BODYSHAPE_HUMANOID change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" @@ -183,7 +187,8 @@ icon_state = "borg_chest" is_dimorphic = FALSE should_draw_greyscale = FALSE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + bodytype = BODYTYPE_ROBOTIC + bodyshape = BODYSHAPE_HUMANOID change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" @@ -357,7 +362,8 @@ icon_state = "borg_head" is_dimorphic = FALSE should_draw_greyscale = FALSE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ROBOTIC + bodytype = BODYTYPE_ROBOTIC + bodyshape = BODYSHAPE_HUMANOID change_exempt_flags = BP_BLOCK_CHANGE_SPECIES dmg_overlay_type = "robotic" diff --git a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm index 24178d9bd1610..8dccd4b4a2d5b 100644 --- a/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm +++ b/code/modules/surgery/bodyparts/species_parts/lizard_bodyparts.dm @@ -45,7 +45,7 @@ /obj/item/bodypart/leg/left/digitigrade icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi' limb_id = BODYPART_ID_DIGITIGRADE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE + bodyshape = BODYSHAPE_HUMANOID | BODYSHAPE_DIGITIGRADE /obj/item/bodypart/leg/left/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE) . = ..() @@ -71,7 +71,7 @@ /obj/item/bodypart/leg/right/digitigrade icon_greyscale = 'icons/mob/human/species/lizard/bodyparts.dmi' limb_id = BODYPART_ID_DIGITIGRADE - bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE + bodyshape = BODYSHAPE_HUMANOID | BODYSHAPE_DIGITIGRADE /obj/item/bodypart/leg/right/digitigrade/update_limb(dropping_limb = FALSE, is_creating = FALSE) . = ..() diff --git a/code/modules/surgery/organs/external/_external_organ.dm b/code/modules/surgery/organs/external/_external_organ.dm index 540c090d2e430..b58f08fe97d7e 100644 --- a/code/modules/surgery/organs/external/_external_organ.dm +++ b/code/modules/surgery/organs/external/_external_organ.dm @@ -25,6 +25,8 @@ var/use_mob_sprite_as_obj_sprite = FALSE ///Does this organ have any bodytypes to pass to it's bodypart_owner? var/external_bodytypes = NONE + ///Does this organ have any bodyshapes to pass to it's bodypart_owner? + var/external_bodyshapes = NONE ///Which flags does a 'modification tool' need to have to restyle us, if it all possible (located in code/_DEFINES/mobs) var/restyle_flags = NONE @@ -80,12 +82,15 @@ if(external_bodytypes) receiver.synchronize_bodytypes() + if(external_bodyshapes) + receiver.synchronize_bodyshapes() receiver.update_body_parts() /obj/item/organ/external/mob_remove(mob/living/carbon/organ_owner, special, moving) if(!special) organ_owner.synchronize_bodytypes() + organ_owner.synchronize_bodyshapes() organ_owner.update_body_parts() return ..() @@ -216,7 +221,7 @@ slot = ORGAN_SLOT_EXTERNAL_SNOUT preference = "feature_lizard_snout" - external_bodytypes = BODYTYPE_SNOUTED + external_bodyshapes = BODYSHAPE_SNOUTED dna_block = DNA_SNOUT_BLOCK restyle_flags = EXTERNAL_RESTYLE_FLESH diff --git a/code/modules/surgery/organs/internal/eyes/_eyes.dm b/code/modules/surgery/organs/internal/eyes/_eyes.dm index f066b308e7b0c..c174d12260806 100644 --- a/code/modules/surgery/organs/internal/eyes/_eyes.dm +++ b/code/modules/surgery/organs/internal/eyes/_eyes.dm @@ -446,7 +446,7 @@ /obj/item/organ/internal/eyes/robotic/glow/ui_state(mob/user) return GLOB.default_state -/obj/item/organ/internal/eyes/robotic/glow/ui_status(mob/user) +/obj/item/organ/internal/eyes/robotic/glow/ui_status(mob/user, datum/ui_state/state) if(!QDELETED(owner)) if(owner == user) return min( diff --git a/code/modules/surgery/prosthetic_replacement.dm b/code/modules/surgery/prosthetic_replacement.dm index 4b285d161bb06..818c7a788d953 100644 --- a/code/modules/surgery/prosthetic_replacement.dm +++ b/code/modules/surgery/prosthetic_replacement.dm @@ -55,7 +55,7 @@ if(ishuman(target)) var/mob/living/carbon/human/human_target = target var/obj/item/bodypart/chest/target_chest = human_target.get_bodypart(BODY_ZONE_CHEST) - if(!(bodypart_to_attach.bodytype & target_chest.acceptable_bodytype)) + if((!(bodypart_to_attach.bodyshape & target_chest.acceptable_bodyshape)) && (!(bodypart_to_attach.bodytype & target_chest.acceptable_bodytype))) to_chat(user, span_warning("[bodypart_to_attach] doesn't match the patient's morphology.")) return SURGERY_STEP_FAIL if(bodypart_to_attach.check_for_frankenstein(target)) diff --git a/code/modules/tgui/states.dm b/code/modules/tgui/states.dm index 16fa83445c508..92fa3b5b5c190 100644 --- a/code/modules/tgui/states.dm +++ b/code/modules/tgui/states.dm @@ -71,10 +71,9 @@ return UI_UPDATE return UI_INTERACTIVE -/mob/living/shared_ui_interaction(src_object) +/mob/living/shared_ui_interaction(atom/src_object) . = ..() - var/obj/item/object = src_object - if(!(mobility_flags & MOBILITY_UI) && !(object.interaction_flags_atom & INTERACT_ATOM_IGNORE_MOBILITY) && . == UI_INTERACTIVE) + if(!(mobility_flags & MOBILITY_UI) && !(src_object.interaction_flags_atom & INTERACT_ATOM_IGNORE_MOBILITY) && . == UI_INTERACTIVE) return UI_UPDATE /mob/living/silicon/ai/shared_ui_interaction(src_object) diff --git a/code/modules/transport/elevator/elev_panel.dm b/code/modules/transport/elevator/elev_panel.dm index 3e9e0e073c19f..24b6e0fa3175c 100644 --- a/code/modules/transport/elevator/elev_panel.dm +++ b/code/modules/transport/elevator/elev_panel.dm @@ -254,7 +254,7 @@ ui = new(user, src, "ElevatorPanel", name) ui.open() -/obj/machinery/elevator_control_panel/ui_status(mob/user) +/obj/machinery/elevator_control_panel/ui_status(mob/user, datum/ui_state/state) // We moved up a z-level, probably via the elevator itself, so don't preserve the UI. if(user.z != z) return UI_CLOSE diff --git a/code/modules/transport/tram/tram_controls.dm b/code/modules/transport/tram/tram_controls.dm index db8fe767155d2..435b47f9d1bfd 100644 --- a/code/modules/transport/tram/tram_controls.dm +++ b/code/modules/transport/tram/tram_controls.dm @@ -83,7 +83,7 @@ /obj/machinery/computer/tram_controls/ui_state(mob/user) return GLOB.not_incapacitated_state -/obj/machinery/computer/tram_controls/ui_status(mob/user,/datum/tgui/ui) +/obj/machinery/computer/tram_controls/ui_status(mob/user, datum/tgui/ui) var/datum/transport_controller/linear/tram/tram = transport_ref?.resolve() if(tram?.controller_active) diff --git a/code/modules/unit_tests/outfit_sanity.dm b/code/modules/unit_tests/outfit_sanity.dm index 683cba3b2fd5f..842f5f1f7ebe6 100644 --- a/code/modules/unit_tests/outfit_sanity.dm +++ b/code/modules/unit_tests/outfit_sanity.dm @@ -5,7 +5,9 @@ if (!outfit_item) { \ TEST_FAIL("[outfit.name]'s [#outfit_key] is invalid! Could not equip a [outfit.##outfit_key] into that slot."); \ } \ - outfit_item.on_outfit_equip(H, FALSE, ##slot_name); \ + else { \ + outfit_item.on_outfit_equip(H, FALSE, ##slot_name); \ + } \ } /// See #66313 and #60901. outfit_sanity used to runtime whenever you had two mergable sheets in either hand. Previously, this only had a 3% chance of occuring. Now 100%. diff --git a/code/modules/uplink/uplink_items/job.dm b/code/modules/uplink/uplink_items/job.dm index 8793bc0fbe8e3..3af8674e4fcf5 100644 --- a/code/modules/uplink/uplink_items/job.dm +++ b/code/modules/uplink/uplink_items/job.dm @@ -156,16 +156,17 @@ /datum/uplink_item/role_restricted/magillitis_serum name = "Magillitis Serum Autoinjector" desc = "A single-use autoinjector which contains an experimental serum that causes rapid muscular growth in Hominidae. \ - Side-affects may include hypertrichosis, violent outbursts, and an unending affinity for bananas." + Side-affects may include hypertrichosis, violent outbursts, and an unending affinity for bananas. \ + Now also contains regenerative chemicals to keep users healthy as they exercise their newfound muscles." item = /obj/item/reagent_containers/hypospray/medipen/magillitis cost = 15 restricted_roles = list(JOB_GENETICIST, JOB_RESEARCH_DIRECTOR) -/datum/uplink_item/role_restricted/gorillacubes - name = "Box of Gorilla Cubes" - desc = "A box with three Waffle Co. brand gorilla cubes. Eat big to get big. \ +/datum/uplink_item/role_restricted/gorillacube + name = "Gorilla Cube" + desc = "A Waffle Co. brand gorilla cube. Eat big to get big. \ Caution: Product may rehydrate when exposed to water." - item = /obj/item/storage/box/gorillacubes + item = /obj/item/food/monkeycube/gorilla cost = 6 restricted_roles = list(JOB_GENETICIST, JOB_RESEARCH_DIRECTOR) diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index 05b3470358f0d..e03847037c8db 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -457,9 +457,9 @@ . += span_notice("[icon2html(ME, user)] \A [ME].") if(mecha_flags & PANEL_OPEN) if(servo) - . += span_notice("Micro-servos reduce movement power usage by [100 - round(100 / servo.rating)]%") + . += span_notice("Servo reduces movement power usage by [100 - round(100 / servo.rating)]%") else - . += span_warning("It's missing a micro-servo.") + . += span_warning("It's missing a servo.") if(capacitor) . += span_notice("Capacitor increases armor against energy attacks by [capacitor.rating * 5].") else diff --git a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm index 335e8bc5a3e12..c0047eb91d7f0 100644 --- a/code/modules/vehicles/mecha/equipment/weapons/weapons.dm +++ b/code/modules/vehicles/mecha/equipment/weapons/weapons.dm @@ -552,6 +552,7 @@ range = MECHA_MELEE toolspeed = 0.8 mech_flags = EXOSUIT_MODULE_PADDY + projectiles_per_shot = 0 ///Chassis but typed for the cargo_hold var var/obj/vehicle/sealed/mecha/ripley/secmech ///Audio for using the hydraulic clamp @@ -570,10 +571,13 @@ secmech = null return ..() -/obj/item/mecha_parts/mecha_equipment/weapon/paddy_claw/action(mob/living/source, atom/target, list/modifiers) +/obj/item/mecha_parts/mecha_equipment/weapon/paddy_claw/action(mob/source, atom/target, list/modifiers) if(!secmech.cargo_hold) //We did try CRASH("Mech [chassis] has a claw device, but no internal storage. This should be impossible.") - if(ismob(target)) + if(!action_checks(target)) + return + if(isliving(target)) + . = ..() var/mob/living/mobtarget = target if(mobtarget.move_resist == MOVE_FORCE_OVERPOWERING) //No megafauna or bolted AIs, please. to_chat(source, "[span_warning("[src] is unable to lift [mobtarget].")]") @@ -596,11 +600,12 @@ carbontarget.update_handcuffed() return - if(!istype(target, /obj/machinery/door)) + if(istype(target, /obj/machinery/door)) + . = ..() + var/obj/machinery/door/target_door = target + playsound(chassis, clampsound, 50, FALSE, -6) + target_door.try_to_crowbar(src, source) return - var/obj/machinery/door/target_door = target - playsound(chassis, clampsound, 50, FALSE, -6) - target_door.try_to_crowbar(src, source) /obj/item/mecha_parts/mecha_equipment/weapon/paddy_claw/get_snowflake_data() return list( diff --git a/code/modules/vehicles/mecha/mecha_construction_paths.dm b/code/modules/vehicles/mecha/mecha_construction_paths.dm index 3287d66c7bf2c..9a05e3df696d6 100644 --- a/code/modules/vehicles/mecha/mecha_construction_paths.dm +++ b/code/modules/vehicles/mecha/mecha_construction_paths.dm @@ -197,24 +197,24 @@ "key" = /obj/item/stock_parts/servo, "action" = ITEM_MOVE_INSIDE, "back_key" = TOOL_SCREWDRIVER, - "desc" = "Scanning module is secured, the micro-servo can be added.", - "forward_message" = "added micro-servo", + "desc" = "Scanning module is secured, the servo can be added.", + "forward_message" = "added servo", "backward_message" = "unsecured capacitor" ), list( "key" = TOOL_SCREWDRIVER, "back_key" = TOOL_CROWBAR, - "desc" = "Micro-servo is installed, and can be screwed into place.", - "forward_message" = "secured micro-servo", - "backward_message" = "removed micro-servo" + "desc" = "Servo is installed, and can be screwed into place.", + "forward_message" = "secured servo", + "backward_message" = "removed servo" ), list( "key" = /obj/item/stock_parts/cell, "action" = ITEM_MOVE_INSIDE, "back_key" = TOOL_SCREWDRIVER, - "desc" = "Micro-servo is secured, and the power cell can be added.", + "desc" = "Servo is secured, and the power cell can be added.", "forward_message" = "added power cell", - "backward_message" = "unsecured micro-servo" + "backward_message" = "unsecured servo" ), list( "key" = TOOL_SCREWDRIVER, @@ -534,7 +534,7 @@ list( "key" = /obj/item/stock_parts/servo, "action" = ITEM_MOVE_INSIDE, - "desc" = "Humor micro-servo can be added!", + "desc" = "Humor servo can be added!", "forward_message" = "added smile" ), list( @@ -680,24 +680,24 @@ "key" = /obj/item/stock_parts/servo, "action" = ITEM_MOVE_INSIDE, "back_key" = TOOL_SCREWDRIVER, - "desc" = "Capacitor is secured, the micro-servo can be added.", - "forward_message" = "added micro-servo", + "desc" = "Capacitor is secured, the servo can be added.", + "forward_message" = "added servo", "backward_message" = "unsecured capacitor" ), list( "key" = TOOL_SCREWDRIVER, "back_key" = TOOL_CROWBAR, - "desc" = "Micro-servo is installed, and can be screwed into place.", - "forward_message" = "secured micro-servo", - "backward_message" = "removed micro-servo" + "desc" = "Servo is installed, and can be screwed into place.", + "forward_message" = "secured servo", + "backward_message" = "removed servo" ), list( "key" = /obj/item/stack/ore/bluespace_crystal, "amount" = 1, "back_key" = TOOL_SCREWDRIVER, - "desc" = "Micro-servo is secured, and the bluespace crystal can be added.", + "desc" = "Servo is secured, and the bluespace crystal can be added.", "forward_message" = "added bluespace crystal", - "backward_message" = "unsecured micro-servo" + "backward_message" = "unsecured servo" ), list( "key" = /obj/item/stack/cable_coil, diff --git a/code/modules/vehicles/mecha/mecha_movement.dm b/code/modules/vehicles/mecha/mecha_movement.dm index a77381fe97a87..aa86d57a0da8f 100644 --- a/code/modules/vehicles/mecha/mecha_movement.dm +++ b/code/modules/vehicles/mecha/mecha_movement.dm @@ -97,7 +97,7 @@ if(isnull(capacitor)) missing_parts += "capacitor" if(isnull(servo)) - missing_parts += "micro-servo" + missing_parts += "servo" if(length(missing_parts)) if(TIMER_COOLDOWN_FINISHED(src, COOLDOWN_MECHA_MESSAGE)) to_chat(occupants, "[icon2html(src, occupants)][span_warning("Missing [english_list(missing_parts)].")]") diff --git a/code/modules/vehicles/mecha/mecha_ui.dm b/code/modules/vehicles/mecha/mecha_ui.dm index 1bf5b8674a47d..712d5f0d712bf 100644 --- a/code/modules/vehicles/mecha/mecha_ui.dm +++ b/code/modules/vehicles/mecha/mecha_ui.dm @@ -9,7 +9,7 @@ ui.open() ui_view.display_to(user) -/obj/vehicle/sealed/mecha/ui_status(mob/user) +/obj/vehicle/sealed/mecha/ui_status(mob/user, datum/ui_state/state) if(contains(user)) return UI_INTERACTIVE return min( diff --git a/code/modules/wiremod/components/admin/proccall.dm b/code/modules/wiremod/components/admin/proccall.dm index 56baaee1447a5..b86e05e6c8a8b 100644 --- a/code/modules/wiremod/components/admin/proccall.dm +++ b/code/modules/wiremod/components/admin/proccall.dm @@ -88,7 +88,7 @@ . = list() .["possible_types"] = GLOB.wiremod_fundamental_types -/obj/item/circuit_component/proccall/ui_status(mob/user) +/obj/item/circuit_component/proccall/ui_status(mob/user, datum/ui_state/state) if(!check_rights_for(user.client, R_VAREDIT)) return UI_CLOSE return UI_INTERACTIVE diff --git a/code/modules/wiremod/core/integrated_circuit.dm b/code/modules/wiremod/core/integrated_circuit.dm index 0499a56dcd474..7dde89e511612 100644 --- a/code/modules/wiremod/core/integrated_circuit.dm +++ b/code/modules/wiremod/core/integrated_circuit.dm @@ -413,7 +413,7 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit) return FALSE return ..() -/obj/item/integrated_circuit/ui_status(mob/user) +/obj/item/integrated_circuit/ui_status(mob/user, datum/ui_state/state) . = ..() if (isobserver(user)) diff --git a/html/changelogs/AutoChangeLog-pr-81540.yml b/html/changelogs/AutoChangeLog-pr-81540.yml new file mode 100644 index 0000000000000..5157e6ceeb2aa --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-81540.yml @@ -0,0 +1,7 @@ +author: "IndieanaJones" +delete-after: True +changes: + - balance: "Gorillas are faster, stronger, but not bigger too. Note while holding an item, they are the same speed as they were prior." + - balance: "Gorillas now have the understanding of languages as monkeys do." + - balance: "The Gorilla Cube Box for traitors has been replaced with a singular gorilla cube. Due to the aforementioned changes, this singular gorilla should be as scary if not scarier than 3 gorillas were prior." + - balance: " Magillitis Serum Autoinjector now grants the resulting gorilla a slow passive regeneration effect which kicks in after not taking damage for 12 seconds." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81541.yml b/html/changelogs/AutoChangeLog-pr-81541.yml deleted file mode 100644 index b152c6498dbdb..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-81541.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "nevimer" -delete-after: True -changes: - - bugfix: "ForceEvent tgui panel search is more reliable." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81577.yml b/html/changelogs/AutoChangeLog-pr-81577.yml deleted file mode 100644 index 16702f1297aa8..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-81577.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "13spacemen" -delete-after: True -changes: - - refactor: "Bloody item overlays no longer use icon procs to generate the overlay" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81588.yml b/html/changelogs/AutoChangeLog-pr-81588.yml deleted file mode 100644 index fc9163ce3efcd..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-81588.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "13spacemen, Kapu1178" -delete-after: True -changes: - - refactor: "Footprint sprites are now based on your shoes and legs, shoes have priority" - - image: "Monkey legs now produce pawprints instead of footprints" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81589.yml b/html/changelogs/AutoChangeLog-pr-81589.yml deleted file mode 100644 index 4cdcda2320ac0..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-81589.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "JohnFulpWillard" -delete-after: True -changes: - - spellcheck: "Removed a double space in health analyzer's message telling you someone is deaf." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81595.yml b/html/changelogs/AutoChangeLog-pr-81595.yml deleted file mode 100644 index 9a9db0f69a221..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-81595.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - rscdel: "Deletes Mythril Coins from random coin spawners" - - rscdel: "Replaces Mythril sheets in icebox vent fishing with Runite sheets" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81596.yml b/html/changelogs/AutoChangeLog-pr-81596.yml new file mode 100644 index 0000000000000..fdd8366297830 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-81596.yml @@ -0,0 +1,4 @@ +author: "Melbert" +delete-after: True +changes: + - bugfix: "The Paddy's Claw should be properly unusable in situations which it should be properly unusable." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81597.yml b/html/changelogs/AutoChangeLog-pr-81597.yml deleted file mode 100644 index 87369c39be1f8..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-81597.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "00-Steven" -delete-after: True -changes: - - bugfix: "Chefs (not to be confused with cooks) actually display as being a part of service on the crew monitor." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81599.yml b/html/changelogs/AutoChangeLog-pr-81599.yml new file mode 100644 index 0000000000000..84bf337648e9f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-81599.yml @@ -0,0 +1,4 @@ +author: "TJatPBnJ" +delete-after: True +changes: + - balance: "Power crepes are now finger food" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81605.yml b/html/changelogs/AutoChangeLog-pr-81605.yml new file mode 100644 index 0000000000000..7f6f91ac658e2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-81605.yml @@ -0,0 +1,4 @@ +author: "ArcaneMusic" +delete-after: True +changes: + - bugfix: "Fixed instances where holochip/holocredits would spawn with a total of zero credits contained within." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81606.yml b/html/changelogs/AutoChangeLog-pr-81606.yml deleted file mode 100644 index 02bee239288bd..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-81606.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "JohnFulpWillard" -delete-after: True -changes: - - refactor: "Holographic mobs now gives better feedback to players and should more consistently not give any drops." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81627.yml b/html/changelogs/AutoChangeLog-pr-81627.yml new file mode 100644 index 0000000000000..8961474bf7f5d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-81627.yml @@ -0,0 +1,4 @@ +author: "vinylspiders" +delete-after: True +changes: + - bugfix: "fixes cardboard cutouts not updating when held and using the crayon on them to change their appearance, and fixes the alt_appearance being added to the cutout instead of the mob holding it" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81629.yml b/html/changelogs/AutoChangeLog-pr-81629.yml new file mode 100644 index 0000000000000..d7c9aa58f9c5c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-81629.yml @@ -0,0 +1,5 @@ +author: "mc-oofert" +delete-after: True +changes: + - rscadd: "Added an option to deathmatch loadout dropdown that allows you to pick a random loadout" + - bugfix: "In deathmatch, plasmamen are made humans and the UI supports more players" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81637.yml b/html/changelogs/AutoChangeLog-pr-81637.yml new file mode 100644 index 0000000000000..1e735fde35982 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-81637.yml @@ -0,0 +1,4 @@ +author: "00-Steven" +delete-after: True +changes: + - bugfix: "Medical/security records now show an icon based on the registered trim, rather than showing a question mark for records with customized titles." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81638.yml b/html/changelogs/AutoChangeLog-pr-81638.yml new file mode 100644 index 0000000000000..c6d7b9e46333d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-81638.yml @@ -0,0 +1,4 @@ +author: "00-Steven" +delete-after: True +changes: + - bugfix: "Newscasters no longer say \"No wanted issue posted. Have a secure day.\" when there is, in fact, an active wanted issue currently posted." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81641.yml b/html/changelogs/AutoChangeLog-pr-81641.yml new file mode 100644 index 0000000000000..37efab9484f10 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-81641.yml @@ -0,0 +1,6 @@ +author: "JohnFulpWillard" +delete-after: True +changes: + - qol: "You can use atmos machines, holopads, crayons, spray cans, and disposal bins while floored." + - bugfix: "You can close extinguisher cabinets while floored." + - bugfix: "You can climb onto a photocopier from the floor." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81661.yml b/html/changelogs/AutoChangeLog-pr-81661.yml new file mode 100644 index 0000000000000..13a28048d7be8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-81661.yml @@ -0,0 +1,4 @@ +author: "Singul0" +delete-after: True +changes: + - bugfix: "The say TGUI would recognize :g (changeling hivemind) prefix. and give a visual indicator in it that you are talking in the right channel" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81662.yml b/html/changelogs/AutoChangeLog-pr-81662.yml new file mode 100644 index 0000000000000..ab75566b57e30 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-81662.yml @@ -0,0 +1,4 @@ +author: "13spacemen" +delete-after: True +changes: + - bugfix: "Blood overlays on items no longer leak onto other objects" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81671.yml b/html/changelogs/AutoChangeLog-pr-81671.yml new file mode 100644 index 0000000000000..853a56fb32e7a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-81671.yml @@ -0,0 +1,4 @@ +author: "Ben10Omintrix" +delete-after: True +changes: + - bugfix: "fixes pokemon ai still being active when inside the pokeball" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-81684.yml b/html/changelogs/AutoChangeLog-pr-81684.yml new file mode 100644 index 0000000000000..d75725dd9ce89 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-81684.yml @@ -0,0 +1,4 @@ +author: "mc-oofert" +delete-after: True +changes: + - bugfix: "You may no longer make deathmatch arenas dark with a lightswitch." \ No newline at end of file diff --git a/html/changelogs/archive/2024-02.yml b/html/changelogs/archive/2024-02.yml index de87de3d7f2b0..3209584f8c161 100644 --- a/html/changelogs/archive/2024-02.yml +++ b/html/changelogs/archive/2024-02.yml @@ -643,3 +643,92 @@ - rscadd: Machine frames can now be deconstructed with screwdrivers, and computer frames can now be deconstructed with welding torches. Welders are faster. - bugfix: Organs have the blood DNA of their owns on them again +2024-02-23: + 00-Steven: + - bugfix: Chefs (not to be confused with cooks) actually display as being a part + of service on the crew monitor. + 13spacemen: + - refactor: Bloody item overlays no longer use icon procs to generate the overlay + 13spacemen, Kapu1178: + - refactor: Footprint sprites are now based on your shoes and legs, shoes have priority + - image: Monkey legs now produce pawprints instead of footprints + JohnFulpWillard: + - refactor: Holographic mobs now gives better feedback to players and should more + consistently not give any drops. + - spellcheck: Removed a double space in health analyzer's message telling you someone + is deaf. + Melbert: + - bugfix: You can now take our your anger upon arcade cabinets upon losing (they + can be hit again) + - rscdel: Deletes Mythril Coins from random coin spawners + - rscdel: Replaces Mythril sheets in icebox vent fishing with Runite sheets + SgtHunk: + - bugfix: The Summon Simians spell will now properly check for monkey faction, allowing + people who are monkeys to not be mauled. + nevimer: + - bugfix: ForceEvent tgui panel search is more reliable. +2024-02-24: + 00-Steven: + - bugfix: Chef and department security have the assignment on their ID imprinted + onto their PDA by default, instead of defaulting to Cook/Security Officer and + requiring you to do so manually. + A.C.M.O.: + - qol: CPR can be administered by species which do not need to breathe, so long + as they have functional lungs. + ArcaneMusic: + - bugfix: Mining cyborgs now keep the state of their mining scanner when stored, + without shutting off. + Echriser: + - bugfix: you can no longer feed people with covered mouths using spoons or ladles + JohnFulpWillard: + - bugfix: Alien larvas' examine text no longer tells you they are missing arms and + legs. + Melbert: + - bugfix: Cyborgs spark and spit out oil when smacked again. Among other things. + vinylspiders: + - bugfix: fixes spurious CI failure in museum + - code_imp: adds a blacklist feature to spawners +2024-02-25: + bigfatbananacyclops: + - rscadd: floortile camouflage suit, boots, gloves and crate containing the former + items +2024-02-26: + 00-Steven: + - bugfix: Disabled the popsicle stick maximizer. (Producing popsicle sticks actually + deletes the input logs.) + 13spacemen: + - refactor: Bodytypes to do with character sprite shape now have their own bodyshape + var, all sprite handling is done with bodyshape and not bodytype anymore + Cheshify: + - bugfix: meatwheat is now firmly made out of meat, instead of sometimes being wheat + and sometimes being meat and sometimes being both. + - bugfix: The North Star finally has a bluespace gas sender system. + Derpguy3: + - bugfix: Three stationary water tanks on Birdshot which supplied a sink in the + bar, a sink in the medical storage and a sink in the perma-brig's kitchen are + now properly rotated and connected with the plumbing. + - bugfix: The unisex showers on Birdshot have been given a water tank for its plumbing. + EEASAS: + - balance: buffs corporate modsuit(centcom only) + Higgin: + - qol: Blood Brother convert objective now explains who you can convert and what + to do if you mess up with your flash. + MrDas: + - spellcheck: The tier of servo in mech construction is no longer explicitly stated. + necromanceranne: + - balance: Nanotrasen, in direct response to the increasing danger posed by wannabe + martial artists and rioters in the fringes of the Spinward Sector, have upgraded + the impact dampeners found in their riot armor. Staff have also started to rediscover + the value of medieval armor; it isn't particularly easy to topple a knight in + a suit of plate with just your fists. + - balance: Melee-focused armor is now more able to protect you from various RNG-based + knockdowns, such as critical hits from punches (as well as the ones applied + through the staggered status), shoves, critical hits with a blunt weapon to + the chest, and body throws. + - balance: Melee-focused helmets also protect you from head injuries, such as bottle + smashes, accidentally hitting something dense during a tackle, and critical + hits from a blunt weapon to the head. + - balance: Bottlesmash knockdowns are less reliable in general. + - rscadd: A new module, the Safety-First Head Protection module, protects you from + head trauma! Available in most modsuits expected to take hits to the head often. + And from roundstart exofabricators. diff --git a/icons/mob/clothing/feet.dmi b/icons/mob/clothing/feet.dmi index 3a6faaf1ef8e6..5bd3005ab8e58 100644 Binary files a/icons/mob/clothing/feet.dmi and b/icons/mob/clothing/feet.dmi differ diff --git a/icons/mob/clothing/hands.dmi b/icons/mob/clothing/hands.dmi index a99bff784cee0..d0e5093d459c5 100644 Binary files a/icons/mob/clothing/hands.dmi and b/icons/mob/clothing/hands.dmi differ diff --git a/icons/mob/clothing/mask.dmi b/icons/mob/clothing/mask.dmi index 24e8622344e4e..db1259996c867 100644 Binary files a/icons/mob/clothing/mask.dmi and b/icons/mob/clothing/mask.dmi differ diff --git a/icons/mob/clothing/under/syndicate.dmi b/icons/mob/clothing/under/syndicate.dmi index 57e0cf14a3a76..0e9d8dfc91b02 100644 Binary files a/icons/mob/clothing/under/syndicate.dmi and b/icons/mob/clothing/under/syndicate.dmi differ diff --git a/icons/obj/clothing/gloves.dmi b/icons/obj/clothing/gloves.dmi index 2a5fea8c20bb6..d8a2fc0bd13cd 100644 Binary files a/icons/obj/clothing/gloves.dmi and b/icons/obj/clothing/gloves.dmi differ diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi index 1dd2ac7d71c7e..568c059a54d78 100644 Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ diff --git a/icons/obj/clothing/shoes.dmi b/icons/obj/clothing/shoes.dmi index 104812240fec6..0acc23d128217 100644 Binary files a/icons/obj/clothing/shoes.dmi and b/icons/obj/clothing/shoes.dmi differ diff --git a/icons/obj/clothing/under/syndicate.dmi b/icons/obj/clothing/under/syndicate.dmi index ffa19bd0d6257..de712a41f6b3f 100644 Binary files a/icons/obj/clothing/under/syndicate.dmi and b/icons/obj/clothing/under/syndicate.dmi differ diff --git a/icons/obj/food/piecake.dmi b/icons/obj/food/piecake.dmi index 8474ba29fe9f8..e6c0a71022d50 100644 Binary files a/icons/obj/food/piecake.dmi and b/icons/obj/food/piecake.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 3f560e3208ab5..5df1d8c26f7cb 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1954,6 +1954,7 @@ #include "code\game\machinery\launch_pad.dm" #include "code\game\machinery\lightswitch.dm" #include "code\game\machinery\limbgrower.dm" +#include "code\game\machinery\machine_frame.dm" #include "code\game\machinery\mass_driver.dm" #include "code\game\machinery\mechlaunchpad.dm" #include "code\game\machinery\medical_kiosk.dm" diff --git a/tgui/packages/tgui-say/constants.ts b/tgui/packages/tgui-say/constants.ts index 3033154e50999..0c3d7943c2676 100644 --- a/tgui/packages/tgui-say/constants.ts +++ b/tgui/packages/tgui-say/constants.ts @@ -21,6 +21,7 @@ export const RADIO_PREFIXES = { ':b ': 'io', ':c ': 'Cmd', ':e ': 'Engi', + ':g ': 'Cling', ':m ': 'Med', ':n ': 'Sci', ':o ': 'AI', diff --git a/tgui/packages/tgui-say/styles/colors.scss b/tgui/packages/tgui-say/styles/colors.scss index 475d8b25b26ef..ded5ffeeb9729 100644 --- a/tgui/packages/tgui-say/styles/colors.scss +++ b/tgui/packages/tgui-say/styles/colors.scss @@ -10,6 +10,7 @@ $_channel_map: ( 'Admin': #ffbbff, 'AI': #d65d95, 'CCom': #2681a5, + 'Cling': #4c701f, 'Cmd': #fcdf03, 'Engi': #f37746, 'Hive': #855d85, diff --git a/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx b/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx index 6c1a2221a4d70..2e9b80181873f 100644 --- a/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx +++ b/tgui/packages/tgui/interfaces/DeathmatchLobby.tsx @@ -44,11 +44,11 @@ type Data = { export const DeathmatchLobby = (props) => { const { act, data } = useBackend(); return ( - + - -
+ +
@@ -148,6 +148,7 @@ export const DeathmatchLobby = (props) => { {data.map.desc} + Maximum Play Time: {`${data.map.time / 600}min`}
diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/RecordTabs.tsx b/tgui/packages/tgui/interfaces/MedicalRecords/RecordTabs.tsx index fc190385e7bb7..23aafd99a6105 100644 --- a/tgui/packages/tgui/interfaces/MedicalRecords/RecordTabs.tsx +++ b/tgui/packages/tgui/interfaces/MedicalRecords/RecordTabs.tsx @@ -90,7 +90,7 @@ const CrewTab = (props: { record: MedicalRecord }) => { const { act, data } = useBackend(); const { assigned_view } = data; const { record } = props; - const { crew_ref, name, rank } = record; + const { crew_ref, name, trim } = record; /** Sets the record to preview */ const selectRecord = (record: MedicalRecord) => { @@ -109,7 +109,7 @@ const CrewTab = (props: { record: MedicalRecord }) => { selected={selectedRecord?.crew_ref === crew_ref} > - {name} + {name} ); diff --git a/tgui/packages/tgui/interfaces/MedicalRecords/types.ts b/tgui/packages/tgui/interfaces/MedicalRecords/types.ts index 369cad0747e62..878f81ab65e2c 100644 --- a/tgui/packages/tgui/interfaces/MedicalRecords/types.ts +++ b/tgui/packages/tgui/interfaces/MedicalRecords/types.ts @@ -26,6 +26,7 @@ export type MedicalRecord = { quirk_notes: string; rank: string; species: string; + trim: string; }; export type MedicalNote = { diff --git a/tgui/packages/tgui/interfaces/Newscaster.jsx b/tgui/packages/tgui/interfaces/Newscaster.jsx index 431e7d606e624..b3a30eb2bdd85 100644 --- a/tgui/packages/tgui/interfaces/Newscaster.jsx +++ b/tgui/packages/tgui/interfaces/Newscaster.jsx @@ -326,9 +326,11 @@ const NewscasterWantedScreen = (props) => { ) : ( - {wanted.active - ? 'Please contact your local security officer if spotted.' - : 'No wanted issue posted. Have a secure day.'} + {wanted.map((activeWanted) => + activeWanted.active + ? 'Please contact your local security officer if spotted.' + : 'No wanted issue posted. Have a secure day.', + )} )} diff --git a/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx b/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx index d6e3d431ba4a6..492321b3d3a07 100644 --- a/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx +++ b/tgui/packages/tgui/interfaces/SecurityRecords/RecordTabs.tsx @@ -91,7 +91,7 @@ const CrewTab = (props: { record: SecurityRecord }) => { const { act, data } = useBackend(); const { assigned_view } = data; const { record } = props; - const { crew_ref, name, rank, wanted_status } = record; + const { crew_ref, name, trim, wanted_status } = record; /** Chooses a record */ const selectRecord = (record: SecurityRecord) => { @@ -112,7 +112,7 @@ const CrewTab = (props: { record: SecurityRecord }) => { selected={isSelected} > - {name} + {name} ); diff --git a/tgui/packages/tgui/interfaces/SecurityRecords/types.ts b/tgui/packages/tgui/interfaces/SecurityRecords/types.ts index d090ecc5b58e1..2c54ab880bd0a 100644 --- a/tgui/packages/tgui/interfaces/SecurityRecords/types.ts +++ b/tgui/packages/tgui/interfaces/SecurityRecords/types.ts @@ -23,6 +23,7 @@ export type SecurityRecord = { note: string; rank: string; species: string; + trim: string; wanted_status: string; voice: string; };