diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1cca14f83b6..2862dce1b98 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -85,6 +85,10 @@ # CONTRIBUTORS +# Fikou + +/code/modules/mod/ @Fikou + # Ghilker /code/__DEFINES/atmospherics/ @Ghilker diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_engioutpost.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_engioutpost.dmm index b0cbfb21334..b267f1945b5 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_surface_engioutpost.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_surface_engioutpost.dmm @@ -6,7 +6,7 @@ /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors) "ac" = ( -/obj/effect/mob_spawn/corpse/human/engineer/rig, +/obj/effect/mob_spawn/corpse/human/engineer/mod, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors) "ad" = ( @@ -367,7 +367,7 @@ /turf/open/floor/plating/snowed/icemoon, /area/icemoon/surface/outdoors) "bz" = ( -/obj/item/clothing/suit/space/hardsuit/engine, +/obj/item/mod/control/pre_equipped/engineering, /turf/open/floor/plating/asteroid/snow/icemoon, /area/icemoon/surface/outdoors) "bA" = ( @@ -719,7 +719,7 @@ /area/icemoon/surface/outdoors) "cU" = ( /obj/structure/cable, -/obj/effect/mob_spawn/corpse/human/engineer/rig, +/obj/effect/mob_spawn/corpse/human/engineer/mod, /turf/open/floor/plating/icemoon, /area/icemoon/surface/outdoors) "cV" = ( diff --git a/_maps/RandomRuins/SpaceRuins/forgottenship.dmm b/_maps/RandomRuins/SpaceRuins/forgottenship.dmm index ec22fac110e..fca66cdb68c 100644 --- a/_maps/RandomRuins/SpaceRuins/forgottenship.dmm +++ b/_maps/RandomRuins/SpaceRuins/forgottenship.dmm @@ -494,7 +494,8 @@ /obj/structure/closet/crate/secure/gear{ req_one_access_txt = "150" }, -/obj/item/clothing/suit/space/hardsuit/cybersun, +/obj/item/clothing/head/helmet/space/syndicate/black/engie, +/obj/item/clothing/suit/space/syndicate/black/engie, /turf/open/floor/pod/dark, /area/ruin/space/has_grav/powered/syndicate_forgotten_vault) "bC" = ( diff --git a/_maps/RandomRuins/SpaceRuins/oldstation.dmm b/_maps/RandomRuins/SpaceRuins/oldstation.dmm index e9985ea32ac..027a57eed99 100644 --- a/_maps/RandomRuins/SpaceRuins/oldstation.dmm +++ b/_maps/RandomRuins/SpaceRuins/oldstation.dmm @@ -4042,8 +4042,7 @@ /turf/open/floor/iron, /area/ruin/space/has_grav/ancientstation/sec) "kd" = ( -/obj/structure/table/reinforced, -/obj/item/clothing/suit/space/hardsuit/ancient, +/obj/machinery/mod_installer, /turf/open/floor/iron/white, /area/ruin/space/has_grav/ancientstation/proto) "ke" = ( @@ -4835,7 +4834,6 @@ /turf/open/floor/iron, /area/ruin/space/has_grav/ancientstation) "mm" = ( -/obj/structure/table/reinforced, /obj/machinery/power/supermatter_crystal/shard, /obj/structure/closet/crate/engineering{ name = "supermatter shard crate" diff --git a/_maps/RandomZLevels/Academy.dmm b/_maps/RandomZLevels/Academy.dmm index 3b78753b8e3..f53c59a6903 100644 --- a/_maps/RandomZLevels/Academy.dmm +++ b/_maps/RandomZLevels/Academy.dmm @@ -2493,7 +2493,7 @@ "lk" = ( /obj/structure/safe/floor, /obj/item/gun/magic/wand/fireball, -/obj/item/clothing/suit/space/hardsuit/wizard, +/obj/item/mod/control/pre_equipped/enchanted, /turf/open/floor/wood, /area/awaymission/academy/headmaster) "ll" = ( diff --git a/_maps/RandomZLevels/spacebattle.dmm b/_maps/RandomZLevels/spacebattle.dmm index b809c7720d5..afb1a48d1b6 100644 --- a/_maps/RandomZLevels/spacebattle.dmm +++ b/_maps/RandomZLevels/spacebattle.dmm @@ -46,7 +46,7 @@ /area/awaymission/spacebattle/syndicate2) "am" = ( /obj/structure/table/reinforced, -/obj/item/clothing/suit/space/hardsuit/syndi, +/obj/item/mod/control/pre_equipped/nuclear, /turf/open/floor/mineral/plastitanium/red, /area/awaymission/spacebattle/syndicate2) "an" = ( @@ -126,7 +126,7 @@ /area/awaymission/spacebattle/syndicate2) "aI" = ( /obj/structure/table/reinforced, -/obj/item/clothing/suit/space/hardsuit/syndi, +/obj/item/mod/control/pre_equipped/nuclear, /turf/open/floor/mineral/plastitanium/red, /area/awaymission/spacebattle/syndicate3) "aJ" = ( @@ -224,7 +224,7 @@ /area/awaymission/spacebattle/syndicate3) "be" = ( /obj/structure/table/reinforced, -/obj/item/clothing/suit/space/hardsuit/syndi, +/obj/item/mod/control/pre_equipped/nuclear, /turf/open/floor/mineral/plastitanium/red, /area/awaymission/spacebattle/syndicate1) "bf" = ( @@ -900,7 +900,7 @@ /turf/open/floor/iron, /area/awaymission/spacebattle/cruiser) "dX" = ( -/obj/effect/mob_spawn/corpse/human/engineer/rig/gunner{ +/obj/effect/mob_spawn/corpse/human/engineer/mod{ mob_name = "Andrew Thorn"; name = "Andrew Thorn" }, @@ -1063,7 +1063,7 @@ /turf/open/floor/mineral/plastitanium/red, /area/awaymission/spacebattle/syndicate1) "eH" = ( -/obj/effect/mob_spawn/corpse/human/engineer/rig/gunner{ +/obj/effect/mob_spawn/corpse/human/engineer/mod{ mob_name = "Peter West"; name = "Peter West" }, @@ -1176,7 +1176,7 @@ /turf/open/floor/iron, /area/awaymission/spacebattle/cruiser) "fa" = ( -/obj/effect/mob_spawn/corpse/human/engineer/rig/gunner{ +/obj/effect/mob_spawn/corpse/human/engineer/mod{ mob_name = "Eric Abnett"; name = "Eric Abnett" }, @@ -1761,7 +1761,7 @@ /turf/open/floor/iron, /area/awaymission/spacebattle/cruiser) "gO" = ( -/obj/effect/mob_spawn/corpse/human/engineer/rig/gunner{ +/obj/effect/mob_spawn/corpse/human/engineer/mod{ name = "Jeremy Tailor" }, /obj/effect/decal/cleanable/blood, @@ -1863,7 +1863,7 @@ /turf/open/floor/wood, /area/awaymission/spacebattle/cruiser) "hh" = ( -/obj/effect/mob_spawn/corpse/human/engineer/rig/gunner{ +/obj/effect/mob_spawn/corpse/human/engineer/mod{ mob_name = "Dan Hedricks"; name = "Dan Hedricks" }, @@ -1914,8 +1914,7 @@ /area/awaymission/spacebattle/cruiser) "hq" = ( /obj/structure/rack, -/obj/item/clothing/suit/space/hardsuit, -/obj/item/clothing/head/helmet/space/hardsuit, +/obj/item/mod/control/pre_equipped/standard, /turf/open/floor/iron, /area/awaymission/spacebattle/cruiser) "hr" = ( @@ -2010,7 +2009,7 @@ /turf/open/floor/wood, /area/awaymission/spacebattle/cruiser) "hL" = ( -/obj/effect/mob_spawn/corpse/human/engineer/rig/gunner{ +/obj/effect/mob_spawn/corpse/human/engineer/mod{ mob_name = "William Gannon"; name = "William Gannon" }, @@ -2342,7 +2341,7 @@ /turf/closed/wall/mineral/plasma, /area/awaymission/spacebattle/secret) "jo" = ( -/obj/item/clothing/suit/space/hardsuit/wizard, +/obj/item/mod/control/pre_equipped/enchanted, /turf/open/floor/vault/alien, /area/awaymission/spacebattle/secret) "jp" = ( diff --git a/_maps/RandomZLevels/wildwest.dmm b/_maps/RandomZLevels/wildwest.dmm index 6ac6052630f..731b129e888 100644 --- a/_maps/RandomZLevels/wildwest.dmm +++ b/_maps/RandomZLevels/wildwest.dmm @@ -125,7 +125,7 @@ /turf/open/floor/engine/cult, /area/awaymission/wildwest/vault) "aK" = ( -/obj/effect/mob_spawn/corpse/human/miner/rig, +/obj/effect/mob_spawn/corpse/human/miner/mod, /turf/open/floor/engine/cult, /area/awaymission/wildwest/vault) "aL" = ( @@ -204,7 +204,7 @@ /turf/open/floor/plating, /area/awaymission/wildwest/refine) "bi" = ( -/obj/effect/mob_spawn/corpse/human/miner/rig, +/obj/effect/mob_spawn/corpse/human/miner/mod, /obj/effect/mine/sound/bwoink, /turf/open/floor/plating/ironsand, /area/awaymission/wildwest/mines) @@ -236,7 +236,7 @@ /turf/open/floor/wood, /area/awaymission/wildwest/mines) "bq" = ( -/obj/effect/mob_spawn/corpse/human/miner/rig, +/obj/effect/mob_spawn/corpse/human/miner/mod, /turf/open/floor/plating, /area/awaymission/wildwest/refine) "br" = ( @@ -584,7 +584,7 @@ /turf/open/floor/wood, /area/awaymission/wildwest/gov) "cM" = ( -/obj/effect/mob_spawn/corpse/human/miner/rig, +/obj/effect/mob_spawn/corpse/human/miner/mod, /turf/open/floor/wood, /area/awaymission/wildwest/gov) "cN" = ( @@ -776,7 +776,7 @@ }, /area/awaymission/wildwest/gov) "dy" = ( -/obj/effect/mob_spawn/corpse/human/miner/rig, +/obj/effect/mob_spawn/corpse/human/miner/mod, /turf/open/floor/wood, /area/awaymission/wildwest/mines) "dz" = ( @@ -1100,7 +1100,7 @@ /area/awaymission/wildwest/mines) "eL" = ( /obj/effect/decal/cleanable/blood/splatter, -/obj/effect/mob_spawn/corpse/human/miner/rig, +/obj/effect/mob_spawn/corpse/human/miner/mod, /turf/open/floor/carpet, /area/awaymission/wildwest/mines) "eN" = ( @@ -1450,7 +1450,7 @@ /area/awaymission/wildwest/mines) "fR" = ( /obj/effect/mine/sound/bwoink, -/obj/effect/mob_spawn/corpse/human/miner/rig, +/obj/effect/mob_spawn/corpse/human/miner/mod, /turf/open/floor/wood, /area/awaymission/wildwest/mines) "fS" = ( @@ -1520,7 +1520,7 @@ /turf/open/floor/iron/airless, /area/space/nearstation) "ge" = ( -/obj/effect/mob_spawn/corpse/human/miner/rig, +/obj/effect/mob_spawn/corpse/human/miner/mod, /turf/open/floor/iron, /area/awaymission/wildwest/refine) "gf" = ( diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 173a1763086..4c990ebfb46 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -7636,27 +7636,13 @@ /obj/structure/cable, /turf/open/floor/plating, /area/security/warden) -"bFQ" = ( +"bFR" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 }, /obj/item/radio/intercom/directional/north, /turf/open/floor/iron, /area/security/warden) -"bFR" = ( -/obj/machinery/suit_storage_unit/security, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/iron/dark, -/area/security/warden) "bFT" = ( /obj/effect/landmark/start/ai, /obj/item/radio/intercom/directional/west{ @@ -7890,26 +7876,15 @@ /area/security/warden) "bHJ" = ( /obj/structure/cable, +/turf/open/floor/iron, +/area/security/warden) +"bHK" = ( +/obj/structure/cable, /obj/effect/turf_decal/stripes/line{ dir = 4 }, /turf/open/floor/iron, /area/security/warden) -"bHK" = ( -/obj/structure/tank_dispenser/oxygen, -/obj/structure/cable, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/iron/dark, -/area/security/warden) "bHL" = ( /obj/machinery/computer/crew{ dir = 4 @@ -8155,26 +8130,15 @@ /turf/open/floor/iron/dark, /area/security/warden) "bJD" = ( +/obj/machinery/suit_storage_unit/security, +/turf/open/floor/iron, +/area/security/warden) +"bJE" = ( /obj/effect/turf_decal/stripes/line{ dir = 4 }, /turf/open/floor/iron, /area/security/warden) -"bJE" = ( -/obj/machinery/suit_storage_unit/security, -/obj/machinery/light/small/directional/south, -/obj/effect/turf_decal/tile/neutral{ - dir = 1 - }, -/obj/effect/turf_decal/tile/neutral, -/obj/effect/turf_decal/tile/neutral{ - dir = 4 - }, -/obj/effect/turf_decal/tile/neutral{ - dir = 8 - }, -/turf/open/floor/iron/dark, -/area/security/warden) "bJF" = ( /obj/structure/chair/office{ dir = 8 @@ -19391,8 +19355,8 @@ /obj/effect/turf_decal/tile/neutral{ dir = 4 }, -/obj/structure/tank_holder/oxygen, /obj/machinery/airalarm/directional/north, +/obj/machinery/recharge_station, /turf/open/floor/iron, /area/medical/medbay/central) "cYe" = ( @@ -21065,6 +21029,7 @@ /area/command/heads_quarters/cmo) "deJ" = ( /obj/effect/turf_decal/tile/neutral, +/obj/structure/tank_holder/oxygen, /turf/open/floor/iron, /area/medical/medbay/central) "deK" = ( @@ -21072,6 +21037,8 @@ /obj/item/paper_bin, /obj/item/pen, /obj/effect/turf_decal/tile/neutral, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/thermal_regulator, /turf/open/floor/iron, /area/medical/medbay/central) "deN" = ( @@ -25408,6 +25375,15 @@ }, /obj/structure/table/reinforced, /obj/effect/turf_decal/bot, +/obj/item/mod/construction/core{ + pixel_x = -4 + }, +/obj/item/mod/construction/core{ + pixel_x = 4 + }, +/obj/item/mod/construction/core{ + pixel_y = 4 + }, /turf/open/floor/iron, /area/science/robotics/lab) "dzH" = ( @@ -49861,6 +49837,21 @@ /obj/structure/cable, /turf/open/floor/iron/grimy, /area/command/heads_quarters/hos) +"iTL" = ( +/obj/structure/cable, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/structure/tank_dispenser/oxygen, +/turf/open/floor/iron/dark, +/area/security/warden) "iTT" = ( /obj/structure/table/reinforced, /obj/effect/turf_decal/bot, @@ -57398,9 +57389,6 @@ /area/science/misc_lab/range) "kYz" = ( /obj/machinery/light/small/directional/east, -/obj/structure/toilet{ - dir = 8 - }, /obj/machinery/newscaster/directional/north, /obj/machinery/button/door/directional/south{ id = "Arrivals_Toilet3"; @@ -57409,6 +57397,7 @@ specialfunctions = 4 }, /obj/effect/turf_decal/bot, +/obj/machinery/recharge_station, /turf/open/floor/iron, /area/commons/toilet/restrooms) "kYC" = ( @@ -61277,10 +61266,11 @@ c_tag = "Engineering - Shared Storage"; name = "engineering camera" }, -/obj/structure/table/reinforced, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, +/obj/machinery/recharge_station, +/obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/engineering/storage_shared) "lTG" = ( @@ -63448,6 +63438,21 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron, /area/science/research) +"myc" = ( +/obj/machinery/light/small/directional/south, +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/machinery/recharge_station, +/turf/open/floor/iron/dark, +/area/security/warden) "myi" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -73198,6 +73203,9 @@ }, /obj/effect/turf_decal/bot, /obj/machinery/newscaster/directional/east, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/thermal_regulator, +/obj/item/mod/module/magboot, /turf/open/floor/iron, /area/engineering/storage) "oYq" = ( @@ -79505,7 +79513,6 @@ /turf/open/floor/iron/white/corner, /area/engineering/atmos) "qOr" = ( -/obj/item/kirbyplants/random, /obj/effect/turf_decal/tile/neutral{ dir = 1 }, @@ -79516,6 +79523,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, +/obj/machinery/recharge_station, /turf/open/floor/iron/dark, /area/command/meeting_room/council) "qOv" = ( @@ -88464,6 +88472,20 @@ }, /turf/open/floor/iron, /area/engineering/atmos) +"tlC" = ( +/obj/effect/turf_decal/tile/neutral{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral, +/obj/effect/turf_decal/tile/neutral{ + dir = 4 + }, +/obj/effect/turf_decal/tile/neutral{ + dir = 8 + }, +/obj/machinery/recharge_station, +/turf/open/floor/iron/dark, +/area/security/warden) "tlE" = ( /obj/machinery/door/window/eastright{ name = "Hydroponics Delivery"; @@ -94507,7 +94529,6 @@ /turf/open/floor/iron/dark, /area/service/kitchen) "uQe" = ( -/obj/structure/chair/stool/directional/south, /obj/machinery/light/directional/west, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -94516,6 +94537,7 @@ dir = 8 }, /obj/machinery/firealarm/directional/west, +/obj/machinery/suit_storage_unit/medical, /turf/open/floor/iron, /area/medical/medbay/central) "uQf" = ( @@ -160142,7 +160164,7 @@ swl swl swl guL -bFQ +bJD bHJ bJD bLs @@ -160656,9 +160678,9 @@ vhn dRo upI guL -bFL -bFP -bFL +tlC +iTL +myc bLs bNs bPz @@ -160913,9 +160935,9 @@ hhH eQk fZP guL -aad -aaa -aad +bFL +bFP +bFL bLs bNt bPA diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index cde038d80b4..1e60e6c4d0c 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -383,6 +383,7 @@ /turf/open/floor/iron/dark, /area/ai_monitored/security/armory) "abN" = ( +/obj/machinery/recharge_station, /turf/open/floor/iron/dark, /area/ai_monitored/security/armory) "acd" = ( @@ -5542,6 +5543,8 @@ /obj/item/clothing/gloves/color/yellow, /obj/item/clothing/gloves/color/yellow, /obj/structure/cable, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/thermal_regulator, /obj/item/stock_parts/cell/emproof{ pixel_x = -4; pixel_y = -1 @@ -6972,6 +6975,16 @@ /obj/effect/turf_decal/tile/red{ dir = 4 }, +/obj/item/mod/construction/core{ + pixel_x = -4 + }, +/obj/item/mod/construction/core{ + pixel_x = 4 + }, +/obj/item/mod/construction/core{ + pixel_y = 4 + }, +/obj/structure/table, /turf/open/floor/iron/white, /area/science/robotics/lab) "biP" = ( @@ -22320,6 +22333,7 @@ /area/science/robotics/lab) "hym" = ( /obj/machinery/computer/security/telescreen/entertainment/directional/south, +/obj/machinery/recharge_station, /turf/open/floor/wood, /area/command/meeting_room) "hyo" = ( @@ -33790,6 +33804,7 @@ /obj/effect/turf_decal/tile/yellow{ dir = 1 }, +/obj/machinery/recharge_station, /turf/open/floor/iron, /area/engineering/lobby) "nuM" = ( @@ -37743,7 +37758,7 @@ /obj/machinery/firealarm/directional/south, /obj/structure/cable, /obj/effect/turf_decal/trimline/blue/filled/line, -/obj/item/kirbyplants/random, +/obj/machinery/recharge_station, /turf/open/floor/iron/white, /area/medical/cryo) "ptZ" = ( diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index e83ca923e7e..b327e5f2907 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -9649,6 +9649,12 @@ /obj/machinery/ecto_sniffer{ pixel_x = -6 }, +/obj/item/mod/construction/core{ + pixel_x = -4 + }, +/obj/item/mod/construction/core{ + pixel_x = 4 + }, /turf/open/floor/iron/dark, /area/science/robotics/lab) "aXj" = ( @@ -28969,12 +28975,12 @@ /turf/open/floor/iron, /area/hallway/primary/fore) "ehz" = ( -/obj/machinery/portable_atmospherics/canister/oxygen, /obj/effect/turf_decal/delivery, /obj/effect/turf_decal/tile/neutral{ dir = 8 }, /obj/effect/turf_decal/tile/neutral, +/obj/machinery/recharge_station, /turf/open/floor/iron/dark, /area/engineering/main) "ehK" = ( @@ -29722,12 +29728,6 @@ /turf/open/floor/iron, /area/security/office) "euH" = ( -/obj/structure/table/glass, -/obj/item/paper_bin{ - pixel_x = -4; - pixel_y = 4 - }, -/obj/item/pen, /obj/effect/turf_decal/tile/blue{ dir = 4 }, @@ -29741,6 +29741,7 @@ dir = 1 }, /obj/machinery/firealarm/directional/west, +/obj/machinery/recharge_station, /turf/open/floor/iron/showroomfloor, /area/medical/storage) "evh" = ( @@ -53524,6 +53525,8 @@ /obj/item/electronics/apc, /obj/item/stack/cable_coil, /obj/item/stack/cable_coil, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/thermal_regulator, /turf/open/floor/iron/dark, /area/engineering/main) "mWt" = ( @@ -54735,12 +54738,13 @@ /turf/open/floor/iron/dark, /area/command/bridge) "nyV" = ( -/obj/item/kirbyplants, /obj/effect/turf_decal/tile/neutral{ dir = 4 }, /obj/effect/turf_decal/tile/neutral, /obj/structure/extinguisher_cabinet/directional/west, +/obj/machinery/recharge_station, +/obj/effect/turf_decal/bot, /turf/open/floor/iron/dark, /area/security/courtroom) "nzm" = ( @@ -69894,6 +69898,9 @@ /obj/structure/disposalpipe/segment{ dir = 5 }, +/obj/item/kirbyplants{ + icon_state = "plant-02" + }, /turf/open/floor/iron, /area/security/office) "sZj" = ( @@ -70256,10 +70263,6 @@ /turf/open/floor/iron, /area/maintenance/disposal/incinerator) "tfS" = ( -/obj/item/storage/box/donkpockets{ - pixel_x = 3; - pixel_y = 5 - }, /obj/structure/table/glass, /obj/effect/turf_decal/tile/neutral{ dir = 1 @@ -70268,6 +70271,12 @@ dir = 4 }, /obj/structure/mirror/directional/south, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/thermal_regulator, +/obj/item/storage/box/donkpockets{ + pixel_x = 3; + pixel_y = 5 + }, /turf/open/floor/iron/dark, /area/medical/storage) "tgp" = ( @@ -75953,10 +75962,8 @@ /obj/effect/turf_decal/tile/red{ dir = 1 }, -/obj/item/kirbyplants{ - icon_state = "plant-05" - }, /obj/machinery/airalarm/directional/south, +/obj/machinery/recharge_station, /turf/open/floor/iron, /area/commons/fitness/recreation) "vpk" = ( @@ -78211,15 +78218,12 @@ /obj/effect/turf_decal/tile/neutral{ dir = 4 }, -/obj/item/kirbyplants{ - icon_state = "plant-02"; - pixel_y = 3 - }, /obj/structure/extinguisher_cabinet/directional/west, /obj/structure/cable, /obj/effect/turf_decal/tile/red{ dir = 4 }, +/obj/machinery/recharge_station, /turf/open/floor/iron, /area/security/office) "wjW" = ( diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 2bd449c9d1c..699fbc544ef 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -6868,6 +6868,7 @@ /area/hallway/primary/central) "brd" = ( /obj/effect/turf_decal/trimline/blue/filled/line, +/obj/machinery/suit_storage_unit/medical, /turf/open/floor/iron/white, /area/medical/storage) "bro" = ( @@ -11434,6 +11435,8 @@ name = "First Aid Supplies"; req_access_txt = "5" }, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/thermal_regulator, /turf/open/floor/iron/dark, /area/medical/storage) "cwB" = ( @@ -29162,6 +29165,16 @@ name = "Robotics Privacy Control"; req_access_txt = "29" }, +/obj/item/mod/construction/core{ + pixel_x = -4 + }, +/obj/item/mod/construction/core{ + pixel_x = 4 + }, +/obj/item/mod/construction/core{ + pixel_y = 4 + }, +/obj/structure/closet/crate, /turf/open/floor/iron/dark, /area/science/robotics/lab) "icG" = ( @@ -45259,6 +45272,7 @@ /area/command/heads_quarters/cmo) "nLF" = ( /obj/machinery/light/directional/west, +/obj/machinery/recharge_station, /turf/open/floor/iron/dark, /area/security/office) "nLW" = ( @@ -53875,6 +53889,7 @@ /obj/effect/turf_decal/tile/yellow{ dir = 8 }, +/obj/machinery/recharge_station, /turf/open/floor/iron/dark/corner{ dir = 1 }, @@ -62861,6 +62876,8 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/thermal_regulator, /turf/open/floor/iron/dark/corner{ dir = 1 }, @@ -66540,6 +66557,7 @@ /obj/structure/disposalpipe/segment{ dir = 6 }, +/obj/machinery/recharge_station, /turf/open/floor/carpet, /area/command/heads_quarters/captain/private) "vpy" = ( diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index 99e0efda1e6..30d137dc3d1 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -14955,7 +14955,7 @@ /area/centcom/supplypod/loading/two) "Sh" = ( /obj/structure/table/reinforced, -/obj/item/clothing/suit/space/hardsuit/deathsquad{ +/obj/item/mod/control/pre_equipped/corporate{ pixel_y = 5 }, /obj/item/clothing/gloves/combat, diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 7fae52e02c8..13392071e1a 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -2129,12 +2129,12 @@ /turf/open/floor/iron, /area/security/prison) "ana" = ( -/obj/effect/turf_decal/trimline/yellow/filled/corner, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/disposalpipe/segment{ dir = 4 }, /obj/structure/cable/layer3, +/obj/effect/turf_decal/trimline/yellow/filled/line, /turf/open/floor/iron, /area/engineering/engine_smes) "anb" = ( @@ -6038,6 +6038,16 @@ dir = 6 }, /obj/machinery/firealarm/directional/east, +/obj/item/mod/construction/core{ + pixel_x = -4 + }, +/obj/item/mod/construction/core{ + pixel_x = 4 + }, +/obj/item/mod/construction/core{ + pixel_y = 4 + }, +/obj/structure/table, /turf/open/floor/iron, /area/science/robotics/lab) "aIc" = ( @@ -6101,6 +6111,7 @@ dir = 5 }, /obj/machinery/firealarm/directional/north, +/obj/machinery/suit_storage_unit/medical, /turf/open/floor/iron/white, /area/medical/storage) "aIm" = ( @@ -14902,10 +14913,13 @@ /turf/open/floor/carpet, /area/commons/dorms) "dHW" = ( -/obj/effect/turf_decal/trimline/yellow/filled/line{ - dir = 10 +/obj/effect/turf_decal/bot{ + dir = 1 }, -/turf/open/floor/iron, +/obj/structure/table, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/thermal_regulator, +/turf/open/floor/iron/dark, /area/engineering/engine_smes) "dHX" = ( /obj/effect/turf_decal/trimline/red/filled/line{ @@ -16237,21 +16251,15 @@ /turf/open/floor/iron/cafeteria, /area/commons/locker) "efY" = ( -/obj/structure/table, -/obj/item/clothing/gloves/color/yellow, -/obj/item/clothing/gloves/color/yellow, -/obj/item/clothing/gloves/color/yellow, -/obj/item/clothing/gloves/color/yellow, -/obj/item/clothing/gloves/color/yellow, -/obj/item/storage/box/lights/mixed, -/obj/item/stack/cable_coil, -/obj/item/stock_parts/cell/emproof, -/obj/item/stock_parts/cell/emproof, /obj/machinery/camera/emp_proof{ c_tag = "Engineering - SMES Misc"; dir = 10; network = list("ss13","engineering") }, +/obj/effect/turf_decal/bot{ + dir = 1 + }, +/obj/machinery/recharge_station, /turf/open/floor/iron/dark, /area/engineering/engine_smes) "egh" = ( @@ -18505,13 +18513,11 @@ /turf/open/floor/iron/dark, /area/ai_monitored/turret_protected/aisat_interior) "eUc" = ( -/obj/effect/turf_decal/trimline/yellow/filled/corner{ - dir = 8 - }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/structure/disposalpipe/segment{ dir = 4 }, +/obj/effect/turf_decal/trimline/yellow/filled/line, /turf/open/floor/iron, /area/engineering/engine_smes) "eUe" = ( @@ -19114,6 +19120,7 @@ dir = 4 }, /obj/machinery/light/directional/east, +/obj/machinery/recharge_station, /turf/open/floor/iron, /area/security/office) "fgr" = ( @@ -32662,6 +32669,8 @@ name = "Medbay Requests Console" }, /obj/structure/closet/l3closet, +/obj/item/mod/module/plasma_stabilizer, +/obj/item/mod/module/thermal_regulator, /turf/open/floor/iron/white, /area/medical/storage) "kgz" = ( @@ -37839,10 +37848,20 @@ /turf/closed/wall/r_wall, /area/science/xenobiology) "mkS" = ( -/obj/effect/turf_decal/trimline/yellow/filled/line{ - dir = 6 +/obj/structure/table, +/obj/item/clothing/gloves/color/yellow, +/obj/item/clothing/gloves/color/yellow, +/obj/item/clothing/gloves/color/yellow, +/obj/item/clothing/gloves/color/yellow, +/obj/item/clothing/gloves/color/yellow, +/obj/item/storage/box/lights/mixed, +/obj/item/stack/cable_coil, +/obj/item/stock_parts/cell/emproof, +/obj/item/stock_parts/cell/emproof, +/obj/effect/turf_decal/bot{ + dir = 1 }, -/turf/open/floor/iron, +/turf/open/floor/iron/dark, /area/engineering/engine_smes) "mlb" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/visible, @@ -39024,6 +39043,7 @@ /obj/effect/turf_decal/trimline/blue/filled/line{ dir = 10 }, +/obj/machinery/recharge_station, /turf/open/floor/iron/white, /area/medical/medbay/central) "mLo" = ( @@ -50241,8 +50261,8 @@ /turf/open/floor/carpet, /area/cargo/miningdock) "qVF" = ( -/obj/effect/landmark/event_spawn, /obj/structure/cable, +/obj/machinery/recharge_station, /turf/open/floor/plating, /area/command/bridge) "qVO" = ( @@ -67030,6 +67050,7 @@ "xlC" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/effect/landmark/event_spawn, /turf/open/floor/plating, /area/command/bridge) "xlD" = ( diff --git a/code/__DEFINES/ai.dm b/code/__DEFINES/ai.dm index 8737eaa7506..a375c1c7be8 100644 --- a/code/__DEFINES/ai.dm +++ b/code/__DEFINES/ai.dm @@ -99,6 +99,13 @@ ///Amount of successful hits in a row this item has had #define BB_CURSED_THROW_ATTEMPT_COUNT "BB_cursed_throw_attempt_count" +///Mob the MOD is trying to attach to +#define BB_MOD_TARGET "BB_mod_target" +///The implant the AI was created from +#define BB_MOD_IMPLANT "BB_mod_implant" +///Range for a MOD AI controller. +#define MOD_AI_RANGE 100 + ///Vending machine AI controller blackboard keys #define BB_VENDING_CURRENT_TARGET "BB_vending_current_target" #define BB_VENDING_TILT_COOLDOWN "BB_vending_tilt_cooldown" diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm index ecbef6ca7e7..a76ae514236 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm @@ -72,8 +72,10 @@ #define COMSIG_MOVABLE_CHANGE_DUCT_LAYER "movable_change_duct_layer" ///Called when a movable is teleported from `do_teleport()`: (destination, channel) #define COMSIG_MOVABLE_TELEPORTED "movable_teleported" - /// from /mob/living/can_z_move, sent to whatever the mob is buckled to. Only ridable movables should be ridden up or down btw. #define COMSIG_BUCKLED_CAN_Z_MOVE "ridden_pre_can_z_move" #define COMPONENT_RIDDEN_STOP_Z_MOVE 1 #define COMPONENT_RIDDEN_ALLOW_Z_MOVE 2 +/// from base of atom/movable/Process_Spacemove(): (movement_dir) +#define COMSIG_MOVABLE_SPACEMOVE "spacemove" + #define COMSIG_MOVABLE_STOP_SPACEMOVE (1<<0) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm index d907751b67e..9a4542f9d8c 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_carbon.dm @@ -76,3 +76,6 @@ #define COMSIG_HUMAN_EARLY_UNARMED_ATTACK "human_early_unarmed_attack" ///from mob/living/carbon/human/UnarmedAttack(): (atom/target, proximity, modifiers) #define COMSIG_HUMAN_MELEE_UNARMED_ATTACK "human_melee_unarmed_attack" +//from /mob/living/carbon/human/proc/check_shields(): (atom/hit_by, damage, attack_text, attack_type, armour_penetration) +#define COMSIG_HUMAN_CHECK_SHIELDS "human_check_shields" + #define SHIELD_BLOCK (1<<0) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index 9f5cf2bfd7f..34f06d7b64a 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -77,3 +77,8 @@ #define COMSIG_LIVING_SLAM_TABLE "living_slam_table" ///(NOT on humans) from mob/living/*/UnarmedAttack(): (atom/target, proximity, modifiers) #define COMSIG_LIVING_UNARMED_ATTACK "living_unarmed_attack" +///From base of mob/living/MobBump() (mob/living) +#define COMSIG_LIVING_MOB_BUMP "living_mob_bump" +///From base of mob/living/ZImpactDamage() (mob/living, levels, turf/t) +#define COMSIG_LIVING_Z_IMPACT "living_z_impact" + #define NO_Z_IMPACT_DAMAGE (1<<0) diff --git a/code/__DEFINES/dcs/signals/signals_mod.dm b/code/__DEFINES/dcs/signals/signals_mod.dm new file mode 100644 index 00000000000..4c8ec4d6ded --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_mod.dm @@ -0,0 +1,7 @@ +//MODsuit signals +/// Called when a module is selected to be the active one from on_select() +#define COMSIG_MOD_MODULE_SELECTED "mod_module_selected" +/// Called when a MOD activation is called from toggle_activate(mob/user) +#define COMSIG_MOD_ACTIVATE "mod_activate" + /// Cancels the suit's activation + #define MOD_CANCEL_ACTIVATE (1 << 0) diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index 20e767f9a13..65b7a57a1a0 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -149,30 +149,7 @@ /// The index of the entry in 'afk_thefts' with the time it happened #define AFK_THEFT_TIME 3 -//Allowed equipment lists for security vests and hardsuits. - -GLOBAL_LIST_INIT(advanced_hardsuit_allowed, typecacheof(list( - /obj/item/ammo_box, - /obj/item/ammo_casing, - /obj/item/flashlight, - /obj/item/gun, - /obj/item/melee/baton, - /obj/item/reagent_containers/spray/pepper, - /obj/item/restraints/handcuffs, - /obj/item/tank/internals, - ))) - -GLOBAL_LIST_INIT(security_hardsuit_allowed, typecacheof(list( - /obj/item/ammo_box, - /obj/item/ammo_casing, - /obj/item/flashlight, - /obj/item/gun/ballistic, - /obj/item/gun/energy, - /obj/item/melee/baton, - /obj/item/reagent_containers/spray/pepper, - /obj/item/restraints/handcuffs, - /obj/item/tank/internals, - ))) +//Allowed equipment lists for security vests. GLOBAL_LIST_INIT(detective_vest_allowed, typecacheof(list( /obj/item/ammo_box, diff --git a/code/__DEFINES/mod.dm b/code/__DEFINES/mod.dm new file mode 100644 index 00000000000..03163497d42 --- /dev/null +++ b/code/__DEFINES/mod.dm @@ -0,0 +1,31 @@ +/// Default value for the max_complexity var on MODsuits +#define DEFAULT_MAX_COMPLEXITY 15 + +/// Default cell drain per process on MODsuits +#define DEFAULT_CELL_DRAIN 5 + +/// Passive module, just acts when put in naturally. +#define MODULE_PASSIVE 0 +/// Usable module, does something when you press a button. +#define MODULE_USABLE 1 +/// Toggle module, you turn it on/off and it does stuff. +#define MODULE_TOGGLE 2 +/// Actively usable module, you may only have one selected at a time. +#define MODULE_ACTIVE 3 + +//Defines used by the theme for clothing flags and similar +#define HELMET_LAYER "helmet_layer" +#define HELMET_FLAGS "helmet_flags" +#define CHESTPLATE_FLAGS "chestplate_flags" +#define GAUNTLETS_FLAGS "gauntlets_flags" +#define BOOTS_FLAGS "boots_flags" + +#define UNSEALED_CLOTHING "unsealed_clothing" +#define SEALED_CLOTHING "sealed_clothing" +#define UNSEALED_INVISIBILITY "unsealed_invisibility" +#define SEALED_INVISIBILITY "sealed_invisibility" +#define UNSEALED_COVER "unsealed_cover" +#define SEALED_COVER "sealed_cover" + +/// Global list of all /datum/mod_theme +GLOBAL_LIST_INIT(mod_themes, setup_mod_themes()) diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index 43638bd6584..c5bd4927cc7 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -37,6 +37,8 @@ #define EXAMINE_SKIP (1<<15) // Makes the Examine proc not read out this item. #define XENOMORPH_HOLDABLE (1<<16) // A Xenomorph can hold this item. #define NO_PIXEL_RANDOM_DROP (1<<17) //if dropped, it wont have a randomized pixel_x/pixel_y +///Can be equipped on digitigrade legs. +#define IGNORE_DIGITIGRADE (1<<18) // Flags for the clothing_flags var on /obj/item/clothing @@ -50,7 +52,6 @@ #define THICKMATERIAL (1<<7) //prevents syringes, parapens and hypos if the external suit or helmet (if targeting head) has this flag. Example: space suits, biosuit, bombsuits, thick suits that cover your body. #define VOICEBOX_TOGGLABLE (1<<8) // The voicebox in this clothing can be toggled. #define VOICEBOX_DISABLED (1<<9) // The voicebox is currently turned off. -#define SCAN_REAGENTS (1<<10) // Allows helmets, masks and glasses to scan reagents. #define BLOCKS_SHOVE_KNOCKDOWN (1<<11) // Prevents shovies against a dense object from knocking the wearer down. #define SNUG_FIT (1<<12) //Prevents knock-off from things like hat-throwing. #define ANTI_TINFOIL_MANEUVER (1<<13) //Hats with negative effects when worn (i.e the tinfoil hat). diff --git a/code/__DEFINES/projectiles.dm b/code/__DEFINES/projectiles.dm index aecd71092ac..12ba1d90545 100644 --- a/code/__DEFINES/projectiles.dm +++ b/code/__DEFINES/projectiles.dm @@ -1,6 +1,4 @@ -GLOBAL_LIST_EMPTY_TYPED(proj_by_path_key, /obj/projectile) // A list of projectile objects, which are keyed by their path - // check_pierce() return values /// Default behavior: hit and delete self #define PROJECTILE_PIERCE_NONE 0 diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 3786d5167be..fe2a85eeffa 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -197,6 +197,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_NODISMEMBER "dismember_immunity" #define TRAIT_NOFIRE "nonflammable" #define TRAIT_NOFIRE_SPREAD "no_fire_spreading" +/// Prevents plasmamen from self-igniting +#define TRAIT_NOSELFIGNITION "no_selfignition" #define TRAIT_NOGUNS "no_guns" #define TRAIT_NOHUNGER "no_hunger" #define TRAIT_NOMETABOLISM "no_metabolism" @@ -214,6 +216,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_NOBREATH "no_breath" #define TRAIT_ANTIMAGIC "anti_magic" #define TRAIT_HOLY "holy" +/// Like antimagic, but doesn't block the user from casting +#define TRAIT_ANTIMAGIC_NO_SELFBLOCK "anti_magic_no_selfblock" #define TRAIT_DEPRESSION "depression" #define TRAIT_JOLLY "jolly" #define TRAIT_NOCRITDAMAGE "no_crit" @@ -236,10 +240,20 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_PRESENT_VISION "present-vision" #define TRAIT_DISK_VERIFIER "disk-verifier" #define TRAIT_NOMOBSWAP "no-mob-swap" +/// Gives us turf, mob and object vision through walls #define TRAIT_XRAY_VISION "xray_vision" +/// Gives us mob vision through walls and slight night vision +#define TRAIT_THERMAL_VISION "thermal_vision" +/// Gives us turf vision through walls and slight night vision +#define TRAIT_MESON_VISION "meson_vision" +/// Gives us Night vision +#define TRAIT_TRUE_NIGHT_VISION "true_night_vision" +/// Negates our gravity, letting us move normally on floors in 0-g +#define TRAIT_NEGATES_GRAVITY "negates_gravity" +/// Lets us scan reagents +#define TRAIT_REAGENT_SCANNER "reagent_scanner" /// Can weave webs into cloth #define TRAIT_WEB_WEAVER "web_weaver" -#define TRAIT_THERMAL_VISION "thermal_vision" #define TRAIT_ABDUCTOR_TRAINING "abductor-training" #define TRAIT_ABDUCTOR_SCIENTIST_TRAINING "abductor-scientist-training" #define TRAIT_SURGEON "surgeon" @@ -717,9 +731,11 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define PAI_FOLDED "pai-folded" /// Trait applied to brain mobs when they lack external aid for locomotion, such as being inside a mech. #define BRAIN_UNAIDED "brain-unaided" +/// Trait applied by MODsuits. +#define MOD_TRAIT "mod" /// Trait applied by element #define ELEMENT_TRAIT(source) "element_trait_[source]" -/// Trait granted by [/obj/item/clothing/head/helmet/space/hardsuit/berserker] +/// Trait granted by the berserker hood. #define BERSERK_TRAIT "berserk_trait" /// Trait granted by [/obj/item/rod_of_asclepius] #define HIPPOCRATIC_OATH_TRAIT "hippocratic_oath" diff --git a/code/__DEFINES/wiremod.dm b/code/__DEFINES/wiremod.dm index 4277380c055..dcfb2c3ce0b 100644 --- a/code/__DEFINES/wiremod.dm +++ b/code/__DEFINES/wiremod.dm @@ -82,7 +82,7 @@ // Shells /// Whether a circuit is stuck on a shell and cannot be removed (by a user) -#define SHELL_FLAG_CIRCUIT_FIXED (1<<0) +#define SHELL_FLAG_CIRCUIT_UNREMOVABLE (1<<0) /// Whether the shell needs to be anchored for the circuit to be on. #define SHELL_FLAG_REQUIRE_ANCHOR (1<<1) @@ -93,6 +93,9 @@ /// Whether the shell allows actions to be peformed on a shell if the action fails. This will additionally block the messages from being displayed. #define SHELL_FLAG_ALLOW_FAILURE_ACTION (1<<3) +/// Whether a circuit is not able to be modified +#define SHELL_FLAG_CIRCUIT_UNMODIFIABLE (1<<5) + // Shell capacities. These can be converted to configs very easily later #define SHELL_CAPACITY_TINY 12 #define SHELL_CAPACITY_SMALL 25 diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 206fdb14672..6806e169c6d 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -60,8 +60,6 @@ init_crafting_recipes(GLOB.crafting_recipes) - init_subtypes_w_path_keys(/obj/projectile, GLOB.proj_by_path_key) - /// Inits the crafting recipe list, sorting crafting recipe requirements in the process. /proc/init_crafting_recipes(list/crafting_recipes) for(var/path in subtypesof(/datum/crafting_recipe)) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index cdf7766fe90..5da614dd693 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -89,7 +89,6 @@ DEFINE_BITFIELD(clothing_flags, list( "LAVAPROTECT" = LAVAPROTECT, "MASKINTERNALS" = MASKINTERNALS, "NOSLIP" = NOSLIP, - "SCAN_REAGENTS" = SCAN_REAGENTS, "SNUG_FIT" = SNUG_FIT, "STOPSPRESSUREDAMAGE" = STOPSPRESSUREDAMAGE, "THICKMATERIAL" = THICKMATERIAL, diff --git a/code/_globalvars/lists/maintenance_loot.dm b/code/_globalvars/lists/maintenance_loot.dm index 66b33dfd670..b20cae5f00f 100644 --- a/code/_globalvars/lists/maintenance_loot.dm +++ b/code/_globalvars/lists/maintenance_loot.dm @@ -202,6 +202,7 @@ GLOBAL_LIST_INIT(uncommon_loot, list(//uncommon: useful items /obj/item/storage/box/clown = 1, /obj/item/seeds/kronkus = 1, /obj/item/seeds/odious_puffball = 1, + /obj/item/mod/construction/broken_core = 1, ) = 8, list(//medical and chemicals diff --git a/code/_globalvars/traumas.dm b/code/_globalvars/traumas.dm index 7827a1d2952..8a664d14f67 100644 --- a/code/_globalvars/traumas.dm +++ b/code/_globalvars/traumas.dm @@ -150,9 +150,6 @@ GLOBAL_LIST_INIT(phobia_objs, list( /obj/item/clothing/head/helmet/abductor, /obj/item/clothing/suit/armor/abductor/vest, /obj/item/melee/baton/abductor, /obj/item/storage/belt/military/abductor, /obj/item/gun/energy/alien, /obj/item/abductor/silencer, /obj/item/abductor/gizmo, /obj/item/clothing/under/rank/centcom/officer, - /obj/item/clothing/suit/space/hardsuit/ert, /obj/item/clothing/suit/space/hardsuit/ert/sec, - /obj/item/clothing/suit/space/hardsuit/ert/engi, /obj/item/clothing/suit/space/hardsuit/ert/med, - /obj/item/clothing/suit/space/hardsuit/deathsquad, /obj/item/clothing/head/helmet/space/hardsuit/deathsquad, /obj/machinery/door/airlock/centcom, /obj/machinery/atmospherics/miner, /obj/item/toy/figure/captain, /obj/item/toy/figure/ce, /obj/item/toy/figure/dsquad, /obj/item/toy/figure/hop, /obj/item/toy/figure/hos, /obj/item/toy/figure/rd, /obj/item/toy/figure/cmo, /obj/item/stamp/captain, /obj/item/stamp/hop, /obj/item/stamp/hos, /obj/item/stamp/ce, @@ -189,13 +186,11 @@ GLOBAL_LIST_INIT(phobia_objs, list( )), "the supernatural" = typecacheof(list(/obj/structure/destructible/cult, /obj/item/tome, - /obj/item/melee/cultblade, /obj/item/cult_bastard, - /obj/item/restraints/legcuffs/bola/cult, /obj/item/clothing/suit/space/hardsuit/cult, + /obj/item/melee/cultblade, /obj/item/cult_bastard, /obj/item/restraints/legcuffs/bola/cult, /obj/item/clothing/suit/hooded/cultrobes, /obj/item/clothing/head/hooded/cult_hoodie, /obj/effect/rune, /obj/item/stack/sheet/runed_metal, /obj/machinery/door/airlock/cult, /obj/narsie, /obj/item/soulstone, /obj/item/clothing/suit/wizrobe, /obj/item/clothing/head/wizard, /obj/item/spellbook, /obj/item/staff, - /obj/item/clothing/suit/space/hardsuit/shielded/wizard, /obj/item/clothing/suit/space/hardsuit/wizard, /obj/item/gun/magic/staff, /obj/item/gun/magic/wand, /obj/item/nullrod, /obj/item/clothing/under/rank/civilian/chaplain, /obj/item/gun/magic/staff, /obj/item/gun/magic/wand, /obj/item/scrying, /obj/item/necromantic_stone, diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm index 4424efca14d..c67a45136a7 100644 --- a/code/_onclick/hud/radial.dm +++ b/code/_onclick/hud/radial.dm @@ -111,6 +111,8 @@ GLOBAL_LIST_EMPTY(radial_menus) else py_shift = 32 restrict_to_dir(NORTH) //I was going to parse screen loc here but that's more effort than it's worth. + else if(hudfix_method && AM.loc) + anchor = get_atom_on_turf(anchor) //Sets defaults //These assume 45 deg min_angle diff --git a/code/datums/action.dm b/code/datums/action.dm index 9b8b3aad25f..aa6c985ba49 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -163,6 +163,7 @@ return sharers += WEAKREF(freeloader) freeloader.client.screen += button + freeloader.actions += src freeloader.update_action_buttons() //Removes our action button from the screen of another player @@ -174,6 +175,7 @@ sharers -= freeloader_reference break freeloader.client.screen -= button + freeloader.actions -= src freeloader.update_action_buttons() //Presets for item actions @@ -354,8 +356,8 @@ background_icon_state = "bg_demon" /datum/action/item_action/berserk_mode/Trigger() - if(istype(target, /obj/item/clothing/head/helmet/space/hardsuit/berserker)) - var/obj/item/clothing/head/helmet/space/hardsuit/berserker/berzerk = target + if(istype(target, /obj/item/clothing/head/hooded/berserker)) + var/obj/item/clothing/head/hooded/berserker/berzerk = target if(berzerk.berserk_active) to_chat(owner, span_warning("You are already berserk!")) return diff --git a/code/datums/ai/objects/mod.dm b/code/datums/ai/objects/mod.dm new file mode 100644 index 00000000000..ced2ffceb6f --- /dev/null +++ b/code/datums/ai/objects/mod.dm @@ -0,0 +1,48 @@ +/// An AI controller for the MODsuit pathfinder module. It's activated by implant and attaches itself to the user. +/datum/ai_controller/mod + blackboard = list( + BB_MOD_TARGET, + BB_MOD_IMPLANT, + ) + max_target_distance = MOD_AI_RANGE //a little spicy but its one specific item that summons it, and it doesnt run otherwise + ai_movement = /datum/ai_movement/jps + ///ID card generated from the suit's required access. Used for pathing. + var/obj/item/card/id/advanced/id_card + +/datum/ai_controller/mod/TryPossessPawn(atom/new_pawn) + if(!istype(new_pawn, /obj/item/mod/control)) + return AI_CONTROLLER_INCOMPATIBLE + var/obj/item/mod/control/mod = new_pawn + id_card = new /obj/item/card/id/advanced/simple_bot() + if(length(mod.req_access)) + id_card.set_access(mod.req_access) + return ..() //Run parent at end + +/datum/ai_controller/mod/UnpossessPawn(destroy) + QDEL_NULL(id_card) + return ..() //Run parent at end + +/datum/ai_controller/mod/SelectBehaviors(delta_time) + current_behaviors = list() + if(blackboard[BB_MOD_TARGET] && blackboard[BB_MOD_IMPLANT]) + queue_behavior(/datum/ai_behavior/mod_attach) + +/datum/ai_controller/mod/get_access() + return id_card + +/datum/ai_behavior/mod_attach + behavior_flags = AI_BEHAVIOR_REQUIRE_MOVEMENT|AI_BEHAVIOR_MOVE_AND_PERFORM + +/datum/ai_behavior/mod_attach/perform(delta_time, datum/ai_controller/controller) + . = ..() + if(!controller.pawn.Adjacent(controller.blackboard[BB_MOD_TARGET])) + return + var/obj/item/implant/mod/implant = controller.blackboard[BB_MOD_IMPLANT] + implant.module.attach(controller.blackboard[BB_MOD_TARGET]) + finish_action(controller, TRUE) + +/datum/ai_behavior/mod_attach/finish_action(datum/ai_controller/controller, succeeded) + . = ..() + controller.blackboard[BB_MOD_TARGET] = null + var/obj/item/implant/mod/implant = controller.blackboard[BB_MOD_IMPLANT] + implant.end_recall(succeeded) diff --git a/code/datums/components/crafting/recipes.dm b/code/datums/components/crafting/recipes.dm index 2629d7602af..ba0b15a4ac8 100644 --- a/code/datums/components/crafting/recipes.dm +++ b/code/datums/components/crafting/recipes.dm @@ -1215,6 +1215,18 @@ ) category = CAT_MISC +/datum/crafting_recipe/mod_core + name = "MOD core" + result = /obj/item/mod/construction/core + tool_behaviors = list(TOOL_SCREWDRIVER) + time = 10 SECONDS + reqs = list(/obj/item/stack/cable_coil = 5, + /obj/item/stack/rods = 2, + /obj/item/stack/sheet/glass = 1, + /obj/item/organ/heart/ethereal = 1 + ) + category = CAT_MISC + /datum/crafting_recipe/alcohol_burner name = "Alcohol burner" result = /obj/item/burner diff --git a/code/datums/components/overlay_lighting.dm b/code/datums/components/overlay_lighting.dm index 046835ea049..9fd0e0a4f5a 100644 --- a/code/datums/components/overlay_lighting.dm +++ b/code/datums/components/overlay_lighting.dm @@ -249,6 +249,7 @@ RegisterSignal(new_holder, COMSIG_LIGHT_EATER_QUEUE, .proc/on_light_eater) if(directional) RegisterSignal(new_holder, COMSIG_ATOM_DIR_CHANGE, .proc/on_holder_dir_change) + set_direction(new_holder.dir) if(overlay_lighting_flags & LIGHTING_ON) add_dynamic_lumi() make_luminosity_update() diff --git a/code/datums/components/shell.dm b/code/datums/components/shell.dm index c7c7c751b95..e976450a262 100644 --- a/code/datums/components/shell.dm +++ b/code/datums/components/shell.dm @@ -40,12 +40,13 @@ attach_circuit(starting_circuit) /datum/component/shell/RegisterWithParent() - RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/on_attack_by) RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine) RegisterSignal(parent, COMSIG_ATOM_ATTACK_GHOST, .proc/on_attack_ghost) - if(!(shell_flags & SHELL_FLAG_CIRCUIT_FIXED)) - RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER), .proc/on_screwdriver_act) + if(!(shell_flags & SHELL_FLAG_CIRCUIT_UNMODIFIABLE)) RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_MULTITOOL), .proc/on_multitool_act) + RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/on_attack_by) + if(!(shell_flags & SHELL_FLAG_CIRCUIT_UNREMOVABLE)) + RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER), .proc/on_screwdriver_act) RegisterSignal(parent, COMSIG_OBJ_DECONSTRUCT, .proc/on_object_deconstruct) if(shell_flags & SHELL_FLAG_REQUIRE_ANCHOR) RegisterSignal(parent, COMSIG_MOVABLE_SET_ANCHORED, .proc/on_set_anchored) @@ -110,7 +111,7 @@ return if(attached_circuit.admin_only) return - if(shell_flags & SHELL_FLAG_CIRCUIT_FIXED) + if(shell_flags & SHELL_FLAG_CIRCUIT_UNREMOVABLE) return remove_circuit() @@ -175,7 +176,7 @@ if(attached_circuit) if(attached_circuit.owner_id && item == attached_circuit.owner_id.resolve()) set_locked(!locked) - source.balloon_alert(attacker, "[locked? "locked" : "unlocked"] [source]") + source.balloon_alert(attacker, "[locked ? "locked" : "unlocked"] [source]") return COMPONENT_NO_AFTERATTACK if(!attached_circuit.owner_id && istype(item, /obj/item/card/id)) @@ -304,7 +305,7 @@ return locked = FALSE attached_circuit = circuitboard - if(!(shell_flags & SHELL_FLAG_CIRCUIT_FIXED) && !circuitboard.admin_only) + if(!(shell_flags & SHELL_FLAG_CIRCUIT_UNREMOVABLE) && !circuitboard.admin_only) RegisterSignal(circuitboard, COMSIG_MOVABLE_MOVED, .proc/on_circuit_moved) if(shell_flags & SHELL_FLAG_REQUIRE_ANCHOR) RegisterSignal(circuitboard, COMSIG_CIRCUIT_PRE_POWER_USAGE, .proc/override_power_usage) @@ -320,7 +321,7 @@ if(shell_flags & SHELL_FLAG_REQUIRE_ANCHOR) attached_circuit.on = parent_atom.anchored - if((shell_flags & SHELL_FLAG_CIRCUIT_FIXED) || circuitboard.admin_only) + if((shell_flags & SHELL_FLAG_CIRCUIT_UNREMOVABLE) || circuitboard.admin_only) circuitboard.moveToNullspace() else if(circuitboard.loc != parent_atom) circuitboard.forceMove(parent_atom) @@ -364,7 +365,7 @@ if(attached_circuit.locked) source.balloon_alert(user, "circuit is locked!") return COMSIG_CANCEL_USB_CABLE_ATTACK - + usb_cable.attached_circuit = attached_circuit return COMSIG_USB_CABLE_CONNECTED_TO_CIRCUIT @@ -375,7 +376,7 @@ * * user - The user to check if they are authorized */ /datum/component/shell/proc/is_authorized(mob/user) - if(shell_flags & SHELL_FLAG_CIRCUIT_FIXED) + if((shell_flags & SHELL_FLAG_CIRCUIT_UNREMOVABLE) && (shell_flags & SHELL_FLAG_CIRCUIT_UNMODIFIABLE)) return FALSE if(attached_circuit?.admin_only) diff --git a/code/datums/components/shielded.dm b/code/datums/components/shielded.dm index 2ae447d2d09..d314899171c 100644 --- a/code/datums/components/shielded.dm +++ b/code/datums/components/shielded.dm @@ -1,5 +1,5 @@ /** - * The shielded component causes the parent item to nullify a certain number of attacks against the wearer, see: shielded hardsuits. + * The shielded component causes the parent item to nullify a certain number of attacks against the wearer, see: shielded vests. */ /datum/component/shielded @@ -23,6 +23,8 @@ var/shield_inhand = FALSE /// Should the shield lose charges equal to the damage dealt by a hit? var/lose_multiple_charges = FALSE + /// The item we use for recharging + var/recharge_path /// The cooldown tracking when we were last hit COOLDOWN_DECLARE(recently_hit_cd) /// The cooldown tracking when we last replenished a charge @@ -30,7 +32,7 @@ /// A callback for the sparks/message that play when a charge is used, see [/datum/component/shielded/proc/default_run_hit_callback] var/datum/callback/on_hit_effects -/datum/component/shielded/Initialize(max_charges = 3, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, shield_icon_file = 'icons/effects/effects.dmi', shield_icon = "shield-old", shield_inhand = FALSE, run_hit_callback) +/datum/component/shielded/Initialize(max_charges = 3, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, recharge_path = null, starting_charges = null, shield_icon_file = 'icons/effects/effects.dmi', shield_icon = "shield-old", shield_inhand = FALSE, run_hit_callback) if(!isitem(parent) || max_charges <= 0) return COMPONENT_INCOMPATIBLE @@ -39,12 +41,15 @@ src.charge_increment_delay = charge_increment_delay src.charge_recovery = charge_recovery src.lose_multiple_charges = lose_multiple_charges + src.recharge_path = recharge_path src.shield_icon_file = shield_icon_file src.shield_icon = shield_icon src.shield_inhand = shield_inhand src.on_hit_effects = run_hit_callback || CALLBACK(src, .proc/default_run_hit_callback) - - current_charges = max_charges + if(isnull(starting_charges)) + current_charges = max_charges + else + current_charges = starting_charges if(recharge_start_delay) START_PROCESSING(SSdcs, src) @@ -62,9 +67,18 @@ RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/lost_wearer) RegisterSignal(parent, COMSIG_ITEM_HIT_REACT, .proc/on_hit_react) RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/check_recharge_rune) + var/atom/shield = parent + if(ismob(shield.loc)) + var/mob/holder = shield.loc + if(holder.is_holding(parent) && !shield_inhand) + return + set_wearer(holder) /datum/component/shielded/UnregisterFromParent() UnregisterSignal(parent, list(COMSIG_ITEM_EQUIPPED, COMSIG_ITEM_DROPPED, COMSIG_ITEM_HIT_REACT, COMSIG_PARENT_ATTACKBY)) + var/atom/shield = parent + if(shield.loc == wearer) + lost_wearer(src, wearer) // Handle recharging, if we want to /datum/component/shielded/process(delta_time) @@ -96,12 +110,7 @@ if(slot == ITEM_SLOT_HANDS && !shield_inhand) lost_wearer(source, user) return - - wearer = user - RegisterSignal(wearer, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/on_update_overlays) - RegisterSignal(wearer, COMSIG_PARENT_QDELETING, .proc/lost_wearer) - if(current_charges) - wearer.update_appearance(UPDATE_ICON) + set_wearer(source, user) /// Either we've been dropped or our wearer has been QDEL'd. Either way, they're no longer our problem /datum/component/shielded/proc/lost_wearer(datum/source, mob/user) @@ -112,6 +121,13 @@ wearer.update_appearance(UPDATE_ICON) wearer = null +/datum/component/shielded/proc/set_wearer(mob/user) + wearer = user + RegisterSignal(wearer, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/on_update_overlays) + RegisterSignal(wearer, COMSIG_PARENT_QDELETING, .proc/lost_wearer) + if(current_charges) + wearer.update_appearance(UPDATE_ICON) + /// Used to draw the shield overlay on the wearer /datum/component/shielded/proc/on_update_overlays(atom/parent_atom, list/overlays) SIGNAL_HANDLER @@ -141,8 +157,6 @@ INVOKE_ASYNC(src, .proc/actually_run_hit_callback, owner, attack_text, current_charges) if(!recharge_start_delay) // if recharge_start_delay is 0, we don't recharge - if(!current_charges) // obviously if someone ever adds a manual way to replenish charges, change this - qdel(src) return START_PROCESSING(SSdcs, src) // if we DO recharge, start processing so we can do that @@ -158,16 +172,13 @@ if(current_charges <= 0) owner.visible_message(span_warning("[owner]'s shield overloads!")) -/datum/component/shielded/proc/check_recharge_rune(datum/source, obj/item/wizard_armour_charge/recharge_rune, mob/living/user) +/datum/component/shielded/proc/check_recharge_rune(datum/source, obj/item/recharge_rune, mob/living/user) SIGNAL_HANDLER - if(!istype(recharge_rune)) + if(!istype(recharge_rune, recharge_path)) return . = COMPONENT_NO_AFTERATTACK - if(!istype(parent, /obj/item/clothing/suit/space/hardsuit/shielded/wizard)) - to_chat(user, span_warning("The rune can only be used on battlemage armour!")) - return - current_charges += recharge_rune.restored_charges + adjust_charge(charge_recovery) to_chat(user, span_notice("You charge \the [parent]. It can now absorb [current_charges] hits.")) qdel(recharge_rune) diff --git a/code/datums/components/storage/storage.dm b/code/datums/components/storage/storage.dm index 398533798bd..d620fbbf1c1 100644 --- a/code/datums/components/storage/storage.dm +++ b/code/datums/components/storage/storage.dm @@ -524,8 +524,8 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) //Tries to dump content /datum/component/storage/proc/dump_content_at(atom/dest_object, mob/M) var/atom/A = parent - var/atom/dump_destination = dest_object.get_dumping_location() - if(A.Adjacent(M) && dump_destination && M.Adjacent(dump_destination)) + var/atom/dump_destination = get_dumping_location(dest_object) + if(M.CanReach(A) && dump_destination && M.CanReach(dump_destination)) if(locked) to_chat(M, span_warning("[parent] seems to be locked!")) return FALSE @@ -534,6 +534,12 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) return TRUE return FALSE +/datum/component/storage/proc/get_dumping_location(atom/dest_object) + var/datum/component/storage/storage = dest_object.GetComponent(/datum/component/storage) + if(storage) + return storage.real_location() + return dest_object.get_dumping_location() + //This proc is called when you want to place an item into the storage item. /datum/component/storage/proc/attackby(datum/source, obj/item/I, mob/M, params) SIGNAL_HANDLER diff --git a/code/datums/components/tackle.dm b/code/datums/components/tackle.dm index d7977276079..dd5d0fcaf07 100644 --- a/code/datums/components/tackle.dm +++ b/code/datums/components/tackle.dm @@ -271,11 +271,10 @@ if(ishuman(target)) var/mob/living/carbon/human/T = target - var/suit_slot = T.get_item_by_slot(ITEM_SLOT_OCLOTHING) if(isnull(T.wear_suit) && isnull(T.w_uniform)) // who honestly puts all of their effort into tackling a naked guy? defense_mod += 2 - if(suit_slot && (istype(suit_slot,/obj/item/clothing/suit/space/hardsuit))) + if(T.mob_negates_gravity()) defense_mod += 1 if(T.is_shove_knockdown_blocked()) // riot armor and such defense_mod += 5 diff --git a/code/datums/holocall.dm b/code/datums/holocall.dm index 0ab1c620dbe..1f2ea0dcc51 100644 --- a/code/datums/holocall.dm +++ b/code/datums/holocall.dm @@ -352,20 +352,20 @@ /datum/preset_holoimage/engineer outfit_type = /datum/outfit/job/engineer -/datum/preset_holoimage/engineer/rig - outfit_type = /datum/outfit/job/engineer/gloved/rig +/datum/preset_holoimage/engineer/mod + outfit_type = /datum/outfit/job/engineer/mod /datum/preset_holoimage/engineer/ce outfit_type = /datum/outfit/job/ce -/datum/preset_holoimage/engineer/ce/rig - outfit_type = /datum/outfit/job/engineer/gloved/rig +/datum/preset_holoimage/engineer/ce/mod + outfit_type = /datum/outfit/job/ce/mod /datum/preset_holoimage/engineer/atmos outfit_type = /datum/outfit/job/atmos -/datum/preset_holoimage/engineer/atmos/rig - outfit_type = /datum/outfit/job/engineer/gloved/rig +/datum/preset_holoimage/engineer/atmos/mod + outfit_type = /datum/outfit/job/atmos/mod /datum/preset_holoimage/researcher outfit_type = /datum/outfit/job/scientist @@ -455,14 +455,14 @@ DELAY 10 SAY Oh, shit! DELAY 10 - PRESET /datum/preset_holoimage/engineer/atmos/rig + PRESET /datum/preset_holoimage/engineer/atmos/mod LANGUAGE /datum/language/narsie NAME Unknown SAY RISE, MY LORD!! DELAY 10 LANGUAGE /datum/language/common NAME Plastic - PRESET /datum/preset_holoimage/engineer/rig + PRESET /datum/preset_holoimage/engineer/mod SAY Fuck, fuck, fuck! DELAY 20 SAY It's loose! CALL THE FUCKING SHUTT- diff --git a/code/datums/outfit.dm b/code/datums/outfit.dm index 74dc943f2ec..e4bfd513faf 100644 --- a/code/datums/outfit.dm +++ b/code/datums/outfit.dm @@ -114,9 +114,6 @@ */ var/list/skillchips = null - /// Should the toggle helmet proc be called on the helmet during equip - var/toggle_helmet = TRUE - ///Should we preload some of this job's items? var/preload = FALSE @@ -153,6 +150,14 @@ //to be overridden for toggling internals, id binding, access etc return +#define EQUIP_OUTFIT_ITEM(item_path, slot_name) if(##item_path) { \ + H.equip_to_slot_or_del(SSwardrobe.provide_type(##item_path), ##slot_name, TRUE); \ + var/obj/item/outfit_item = H.get_item_by_slot(##slot_name); \ + if (outfit_item && outfit_item.type == ##item_path) { \ + outfit_item.on_outfit_equip(H, visualsOnly, ##slot_name); \ + } \ +} + /** * Equips all defined types and paths to the mob passed in * @@ -166,37 +171,38 @@ //Start with uniform,suit,backpack for additional slots if(uniform) - H.equip_to_slot_or_del(SSwardrobe.provide_type(uniform, H), ITEM_SLOT_ICLOTHING, TRUE) + EQUIP_OUTFIT_ITEM(uniform, ITEM_SLOT_ICLOTHING) if(suit) - H.equip_to_slot_or_del(SSwardrobe.provide_type(suit, H), ITEM_SLOT_OCLOTHING, TRUE) - if(back) - H.equip_to_slot_or_del(SSwardrobe.provide_type(back, H), ITEM_SLOT_BACK, TRUE) + EQUIP_OUTFIT_ITEM(suit, ITEM_SLOT_OCLOTHING) if(belt) - H.equip_to_slot_or_del(SSwardrobe.provide_type(belt, H), ITEM_SLOT_BELT, TRUE) + EQUIP_OUTFIT_ITEM(belt, ITEM_SLOT_BELT) if(gloves) - H.equip_to_slot_or_del(SSwardrobe.provide_type(gloves, H), ITEM_SLOT_GLOVES, TRUE) + EQUIP_OUTFIT_ITEM(gloves, ITEM_SLOT_GLOVES) if(shoes) - H.equip_to_slot_or_del(SSwardrobe.provide_type(shoes, H), ITEM_SLOT_FEET, TRUE) + EQUIP_OUTFIT_ITEM(shoes, ITEM_SLOT_FEET) if(head) - H.equip_to_slot_or_del(SSwardrobe.provide_type(head, H), ITEM_SLOT_HEAD, TRUE) + EQUIP_OUTFIT_ITEM(head, ITEM_SLOT_HEAD) if(mask) - H.equip_to_slot_or_del(SSwardrobe.provide_type(mask, H), ITEM_SLOT_MASK, TRUE) + EQUIP_OUTFIT_ITEM(mask, ITEM_SLOT_MASK) if(neck) - H.equip_to_slot_or_del(SSwardrobe.provide_type(neck, H), ITEM_SLOT_NECK, TRUE) + EQUIP_OUTFIT_ITEM(neck, ITEM_SLOT_NECK) if(ears) - H.equip_to_slot_or_del(SSwardrobe.provide_type(ears, H), ITEM_SLOT_EARS, TRUE) + EQUIP_OUTFIT_ITEM(ears, ITEM_SLOT_EARS) if(glasses) - H.equip_to_slot_or_del(SSwardrobe.provide_type(glasses, H), ITEM_SLOT_EYES, TRUE) + EQUIP_OUTFIT_ITEM(glasses, ITEM_SLOT_EYES) + if(back) + EQUIP_OUTFIT_ITEM(back, ITEM_SLOT_BACK) if(id) - H.equip_to_slot_or_del(SSwardrobe.provide_type(id, H), ITEM_SLOT_ID, TRUE) //We don't provide ids (Fix this?) + EQUIP_OUTFIT_ITEM(id, ITEM_SLOT_ID) if(!visualsOnly && id_trim && H.wear_id) var/obj/item/card/id/id_card = H.wear_id id_card.registered_age = H.age if(id_trim) if(!SSid_access.apply_trim_to_card(id_card, id_trim)) WARNING("Unable to apply trim [id_trim] to [id_card] in outfit [name].") + if(suit_store) - H.equip_to_slot_or_del(SSwardrobe.provide_type(suit_store, H), ITEM_SLOT_SUITSTORE, TRUE) + EQUIP_OUTFIT_ITEM(suit_store, ITEM_SLOT_SUITSTORE) if(undershirt) H.undershirt = initial(undershirt.name) @@ -215,9 +221,9 @@ if(!visualsOnly) // Items in pockets or backpack don't show up on mob's icon. if(l_pocket) - H.equip_to_slot_or_del(SSwardrobe.provide_type(l_pocket, H), ITEM_SLOT_LPOCKET, TRUE) + EQUIP_OUTFIT_ITEM(l_pocket, ITEM_SLOT_LPOCKET) if(r_pocket) - H.equip_to_slot_or_del(SSwardrobe.provide_type(r_pocket, H), ITEM_SLOT_RPOCKET, TRUE) + EQUIP_OUTFIT_ITEM(r_pocket, ITEM_SLOT_RPOCKET) if(box) if(!backpack_contents) @@ -231,11 +237,7 @@ if(!isnum(number))//Default to 1 number = 1 for(var/i in 1 to number) - H.equip_to_slot_or_del(SSwardrobe.provide_type(path, H), ITEM_SLOT_BACKPACK, TRUE) - - if(!H.head && toggle_helmet && istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit)) - var/obj/item/clothing/suit/space/hardsuit/HS = H.wear_suit - HS.ToggleHelmet() + EQUIP_OUTFIT_ITEM(path, ITEM_SLOT_BACKPACK) post_equip(H, visualsOnly) @@ -267,6 +269,8 @@ H.update_body() return TRUE +#undef EQUIP_OUTFIT_ITEM + /** * Apply a fingerprint from the passed in human to all items in the outfit * @@ -364,7 +368,6 @@ .["name"] = name .["uniform"] = uniform .["suit"] = suit - .["toggle_helmet"] = toggle_helmet .["back"] = back .["belt"] = belt .["gloves"] = gloves @@ -392,7 +395,6 @@ name = target.name uniform = target.uniform suit = target.suit - toggle_helmet = target.toggle_helmet back = target.back belt = target.belt gloves = target.gloves @@ -431,7 +433,6 @@ name = outfit_data["name"] uniform = text2path(outfit_data["uniform"]) suit = text2path(outfit_data["suit"]) - toggle_helmet = outfit_data["toggle_helmet"] back = text2path(outfit_data["back"]) belt = text2path(outfit_data["belt"]) gloves = text2path(outfit_data["gloves"]) diff --git a/code/datums/wires/mod.dm b/code/datums/wires/mod.dm new file mode 100644 index 00000000000..b5805557eaf --- /dev/null +++ b/code/datums/wires/mod.dm @@ -0,0 +1,57 @@ +/datum/wires/mod + holder_type = /obj/item/mod/control + proper_name = "MOD control unit" + +/datum/wires/mod/New(atom/holder) + wires = list(WIRE_HACK, WIRE_DISABLE, WIRE_SHOCK, WIRE_INTERFACE) + add_duds(2) + ..() + +/datum/wires/mod/interactable(mob/user) + if(!..()) + return FALSE + var/obj/item/mod/control/mod = holder + return mod.open + +/datum/wires/mod/get_status() + var/obj/item/mod/control/mod = holder + var/list/status = list() + status += "The orange light is [mod.seconds_electrified ? "on" : "off"]." + status += "The red light is [mod.malfunctioning ? "off" : "blinking"]." + status += "The green light is [mod.locked ? "on" : "off"]." + status += "The yellow light is [mod.interface_break ? "off" : "on"]." + return status + +/datum/wires/mod/on_pulse(wire) + var/obj/item/mod/control/mod = holder + switch(wire) + if(WIRE_HACK) + mod.locked = !mod.locked + if(WIRE_DISABLE) + mod.malfunctioning = TRUE + if(WIRE_SHOCK) + mod.seconds_electrified = MACHINE_DEFAULT_ELECTRIFY_TIME + if(WIRE_INTERFACE) + mod.interface_break = !mod.interface_break + +/datum/wires/mod/on_cut(wire, mend) + var/obj/item/mod/control/mod = holder + switch(wire) + if(WIRE_HACK) + if(!mend) + mod.req_access = list() + if(WIRE_DISABLE) + mod.malfunctioning = !mend + if(WIRE_SHOCK) + if(mend) + mod.seconds_electrified = MACHINE_NOT_ELECTRIFIED + else + mod.seconds_electrified = MACHINE_ELECTRIFIED_PERMANENT + if(WIRE_INTERFACE) + mod.interface_break = !mend + +/datum/wires/mod/ui_act(action, params) + var/obj/item/mod/control/mod = holder + if(!issilicon(usr) && mod.seconds_electrified && mod.shock(usr)) + return FALSE + return ..() diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 07c02ec6231..606f9bcf981 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1002,7 +1002,7 @@ return TRUE ///Get the best place to dump the items contained in the source storage item? -/atom/proc/get_dumping_location(obj/item/storage/source,mob/user) +/atom/proc/get_dumping_location() return null /** diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index e3a1d5e5312..b6b3e747912 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -936,6 +936,9 @@ * * movement_dir - 0 when stopping or any dir when trying to move */ /atom/movable/proc/Process_Spacemove(movement_dir = 0) + if(SEND_SIGNAL(src, COMSIG_MOVABLE_SPACEMOVE, movement_dir) & COMSIG_MOVABLE_STOP_SPACEMOVE) + return TRUE + if(has_gravity(src)) return TRUE diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 1c7a13e771f..d997d777e2e 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -432,7 +432,7 @@ /obj/machinery/door/morgue icon = 'icons/obj/doors/doormorgue.dmi' -/obj/machinery/door/get_dumping_location(obj/item/storage/source,mob/user) +/obj/machinery/door/get_dumping_location() return null /obj/machinery/door/proc/lock() diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 8892d0486e4..9f61fb74699 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -1,6 +1,6 @@ /obj/machinery/recharge_station - name = "cyborg recharging station" - desc = "This device recharges cyborgs and resupplies them with materials." + name = "recharging station" + desc = "This device recharges energy dependent lifeforms, like cyborgs, ethereals and MODsuit users." icon = 'icons/obj/objects.dmi' icon_state = "borgcharger0" density = FALSE diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index d554796931a..46151d3194e 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -15,6 +15,7 @@ var/obj/item/clothing/suit/space/suit = null var/obj/item/clothing/head/helmet/space/helmet = null var/obj/item/clothing/mask/mask = null + var/obj/item/mod/control/mod = null var/obj/item/storage = null // if you add more storage slots, update cook() to clear their radiation too. @@ -24,6 +25,8 @@ var/helmet_type = null /// What type of breathmask the unit starts with when spawned. var/mask_type = null + /// What type of MOD the unit starts with when spawned. + var/mod_type = null /// What type of additional item the unit starts with when spawned. var/storage_type = null @@ -58,79 +61,65 @@ mask_type = /obj/item/clothing/mask/breath /obj/machinery/suit_storage_unit/captain - suit_type = /obj/item/clothing/suit/space/hardsuit/swat/captain mask_type = /obj/item/clothing/mask/gas/atmos/captain storage_type = /obj/item/tank/jetpack/oxygen/captain + mod_type = /obj/item/mod/control/pre_equipped/magnate /obj/machinery/suit_storage_unit/centcom - suit_type = /obj/item/clothing/suit/space/hardsuit/swat/centcom mask_type = /obj/item/clothing/mask/gas/atmos/centcom storage_type = /obj/item/tank/jetpack/oxygen/captain + mod_type = /obj/item/mod/control/pre_equipped/corporate /obj/machinery/suit_storage_unit/engine - suit_type = /obj/item/clothing/suit/space/hardsuit/engine mask_type = /obj/item/clothing/mask/breath + mod_type = /obj/item/mod/control/pre_equipped/engineering /obj/machinery/suit_storage_unit/atmos - suit_type = /obj/item/clothing/suit/space/hardsuit/atmos mask_type = /obj/item/clothing/mask/gas/atmos storage_type = /obj/item/watertank/atmos + mod_type = /obj/item/mod/control/pre_equipped/atmospheric /obj/machinery/suit_storage_unit/ce - suit_type = /obj/item/clothing/suit/space/hardsuit/engine/elite mask_type = /obj/item/clothing/mask/breath - storage_type= /obj/item/clothing/shoes/magboots/advance + storage_type = /obj/item/clothing/shoes/magboots/advance + mod_type = /obj/item/mod/control/pre_equipped/advanced /obj/machinery/suit_storage_unit/security - suit_type = /obj/item/clothing/suit/space/hardsuit/security mask_type = /obj/item/clothing/mask/gas/sechailer + mod_type = /obj/item/mod/control/pre_equipped/security /obj/machinery/suit_storage_unit/hos - suit_type = /obj/item/clothing/suit/space/hardsuit/security/hos mask_type = /obj/item/clothing/mask/gas/sechailer storage_type = /obj/item/tank/internals/oxygen + mod_type = /obj/item/mod/control/pre_equipped/safeguard /obj/machinery/suit_storage_unit/mining suit_type = /obj/item/clothing/suit/hooded/explorer mask_type = /obj/item/clothing/mask/gas/explorer /obj/machinery/suit_storage_unit/mining/eva - suit_type = /obj/item/clothing/suit/space/hardsuit/mining + suit_type = null mask_type = /obj/item/clothing/mask/breath + mod_type = /obj/item/mod/control/pre_equipped/mining -/obj/machinery/suit_storage_unit/cmo - suit_type = /obj/item/clothing/suit/space/hardsuit/medical +/obj/machinery/suit_storage_unit/medical mask_type = /obj/item/clothing/mask/breath/medical storage_type = /obj/item/tank/internals/oxygen + mod_type = /obj/item/mod/control/pre_equipped/medical + +/obj/machinery/suit_storage_unit/cmo + mask_type = /obj/item/clothing/mask/breath/medical + storage_type = /obj/item/tank/internals/oxygen + mod_type = /obj/item/mod/control/pre_equipped/rescue /obj/machinery/suit_storage_unit/rd - suit_type = /obj/item/clothing/suit/space/hardsuit/rd mask_type = /obj/item/clothing/mask/breath + mod_type = /obj/item/mod/control/pre_equipped/research /obj/machinery/suit_storage_unit/syndicate - suit_type = /obj/item/clothing/suit/space/hardsuit/syndi mask_type = /obj/item/clothing/mask/gas/syndicate storage_type = /obj/item/tank/jetpack/oxygen/harness - -/obj/machinery/suit_storage_unit/ert/command - suit_type = /obj/item/clothing/suit/space/hardsuit/ert - mask_type = /obj/item/clothing/mask/breath - storage_type = /obj/item/tank/internals/emergency_oxygen/double - -/obj/machinery/suit_storage_unit/ert/security - suit_type = /obj/item/clothing/suit/space/hardsuit/ert/sec - mask_type = /obj/item/clothing/mask/breath - storage_type = /obj/item/tank/internals/emergency_oxygen/double - -/obj/machinery/suit_storage_unit/ert/engineer - suit_type = /obj/item/clothing/suit/space/hardsuit/ert/engi - mask_type = /obj/item/clothing/mask/breath - storage_type = /obj/item/tank/internals/emergency_oxygen/double - -/obj/machinery/suit_storage_unit/ert/medical - suit_type = /obj/item/clothing/suit/space/hardsuit/ert/med - mask_type = /obj/item/clothing/mask/breath - storage_type = /obj/item/tank/internals/emergency_oxygen/double + mod_type = /obj/item/mod/control/pre_equipped/nuclear /obj/machinery/suit_storage_unit/radsuit name = "radiation suit storage unit" @@ -156,6 +145,8 @@ helmet = new helmet_type(src) if(mask_type) mask = new mask_type(src) + if(mod_type) + mod = new mod_type(src) if(storage_type) storage = new storage_type(src) update_appearance() @@ -164,6 +155,7 @@ QDEL_NULL(suit) QDEL_NULL(helmet) QDEL_NULL(mask) + QDEL_NULL(mod) QDEL_NULL(storage) return ..() @@ -174,7 +166,7 @@ . += "[base_icon_state]_panel" if(state_open) . += "[base_icon_state]_open" - if(suit) + if(suit || mod) . += "[base_icon_state]_suit" if(helmet) . += "[base_icon_state]_helm" @@ -212,6 +204,7 @@ helmet = null suit = null mask = null + mod = null storage = null set_occupant(null) @@ -230,6 +223,7 @@ "suit" = create_silhouette_of(/obj/item/clothing/suit/space/eva), "helmet" = create_silhouette_of(/obj/item/clothing/head/helmet/space/eva), "mask" = create_silhouette_of(/obj/item/clothing/mask/breath), + "mod" = create_silhouette_of(/obj/item/mod), "storage" = create_silhouette_of(/obj/item/tank/internals/oxygen), ) @@ -388,14 +382,11 @@ if(uv_super) visible_message(span_warning("[src]'s door creaks open with a loud whining noise. A cloud of foul black smoke escapes from its chamber.")) playsound(src, 'sound/machines/airlock_alien_prying.ogg', 50, TRUE) - helmet = null - qdel(helmet) - suit = null - qdel(suit) // Delete everything but the occupant. - mask = null - qdel(mask) - storage = null - qdel(storage) + QDEL_NULL(helmet) + QDEL_NULL(suit) + QDEL_NULL(mask) + QDEL_NULL(mod) + QDEL_NULL(storage) // The wires get damaged too. wires.cut_all() else @@ -415,6 +406,9 @@ if(mask) things_to_clear += mask things_to_clear += mask.get_all_contents() + if(mod) + things_to_clear += mod + things_to_clear += mod.get_all_contents() if(storage) things_to_clear += storage things_to_clear += storage.get_all_contents() @@ -429,16 +423,23 @@ dump_inventory_contents() /obj/machinery/suit_storage_unit/process(delta_time) - if(!suit) + var/obj/item/stock_parts/cell/cell + if(suit) + if(!istype(suit)) + return + if(!suit.cell) + return + cell = suit.cell + else if(mod) + if(!istype(mod)) + return + if(!mod.cell) + return + cell = mod.cell + else return - if(!istype(suit, /obj/item/clothing/suit/space)) - return - if(!suit.cell) - return - - var/obj/item/stock_parts/cell/C = suit.cell use_power(charge_rate * delta_time) - C.give(charge_rate * delta_time) + cell.give(charge_rate * delta_time) /obj/machinery/suit_storage_unit/proc/shock(mob/user, prb) if(!prob(prb)) @@ -513,6 +514,13 @@ if(!user.transferItemToLoc(I, src)) return mask = I + else if(istype(I, /obj/item/mod/control)) + if(mod) + to_chat(user, span_warning("The unit already contains a MOD!")) + return + if(!user.transferItemToLoc(I, src)) + return + mod = I else if(storage) to_chat(user, span_warning("The auxiliary storage compartment is full!")) diff --git a/code/game/objects/effects/spawners/random/exotic.dm b/code/game/objects/effects/spawners/random/exotic.dm index 581bfc26fbb..8847f390989 100644 --- a/code/game/objects/effects/spawners/random/exotic.dm +++ b/code/game/objects/effects/spawners/random/exotic.dm @@ -34,7 +34,7 @@ name = "syndie cosmetic spawner" icon_state = "syndicate" spawn_loot_count = 2 - loot = list( // A selection of cosmetic syndicate items. Just a couple. No hardsuits or weapons. + loot = list( // A selection of cosmetic syndicate items. Just a couple. No space suits or weapons. /obj/effect/spawner/random/clothing/syndie = 8, /obj/item/storage/fancy/cigarettes/cigpack_syndicate = 1, /obj/effect/spawner/random/entertainment/cigarette_pack = 1, diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 7f6de7d5d3c..e30b395b8b4 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1247,3 +1247,7 @@ attack_basic_mob /obj/item/proc/on_offer_taken(mob/living/carbon/offerer, mob/living/carbon/taker) if(SEND_SIGNAL(src, COMSIG_ITEM_OFFER_TAKEN, offerer, taker) & COMPONENT_OFFER_INTERRUPT) return TRUE + +/// Special stuff you want to do when an outfit equips this item. +/obj/item/proc/on_outfit_equip(mob/living/carbon/human/outfit_wearer, visuals_only, item_slot) + return diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm index a434ee31080..70de22a709e 100644 --- a/code/game/objects/items/RCD.dm +++ b/code/game/objects/items/RCD.dm @@ -287,36 +287,46 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window()) return COOLDOWN_START(src, destructive_scan_cooldown, RCD_DESTRUCTIVE_SCAN_COOLDOWN) + rcd_scan(src) - playsound(src, 'sound/items/rcdscan.ogg', 50, vary = TRUE, pressure_affected = FALSE) +/** + * Global proc that generates RCD hologram in a range. + * + * Arguments: + * * source - The atom the scans originate from + * * scan_range - The range of turfs we grab from the source + * * fade_time - The time for RCD holograms to fade + */ +/proc/rcd_scan(atom/source, scan_range = RCD_DESTRUCTIVE_SCAN_RANGE, fade_time = RCD_HOLOGRAM_FADE_TIME) + playsound(source, 'sound/items/rcdscan.ogg', 50, vary = TRUE, pressure_affected = FALSE) - var/turf/source_turf = get_turf(src) - for (var/turf/open/surrounding_turf in RANGE_TURFS(RCD_DESTRUCTIVE_SCAN_RANGE, source_turf)) + var/turf/source_turf = get_turf(source) + for(var/turf/open/surrounding_turf in RANGE_TURFS(scan_range, source_turf)) var/rcd_memory = surrounding_turf.rcd_memory - if (!rcd_memory) + if(!rcd_memory) continue var/skip_to_next_turf = FALSE - for (var/atom/content_of_turf as anything in surrounding_turf.contents) + for(var/atom/content_of_turf as anything in surrounding_turf.contents) if (content_of_turf.density) skip_to_next_turf = TRUE break - if (skip_to_next_turf) + if(skip_to_next_turf) continue var/hologram_icon - switch (rcd_memory) - if (RCD_MEMORY_WALL) + switch(rcd_memory) + if(RCD_MEMORY_WALL) hologram_icon = GLOB.icon_holographic_wall - if (RCD_MEMORY_WINDOWGRILLE) + if(RCD_MEMORY_WINDOWGRILLE) hologram_icon = GLOB.icon_holographic_window - var/obj/effect/rcd_hologram/hologram = new (surrounding_turf) + var/obj/effect/rcd_hologram/hologram = new(surrounding_turf) hologram.icon = hologram_icon - animate(hologram, alpha = 0, time = RCD_HOLOGRAM_FADE_TIME, easing = CIRCULAR_EASING | EASE_IN) + animate(hologram, alpha = 0, time = fade_time, easing = CIRCULAR_EASING | EASE_IN) /obj/effect/rcd_hologram name = "hologram" diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index edb06c9cca1..bd275a2861e 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -24,7 +24,7 @@ var/powered = FALSE //if there's a cell in the defib with enough power for a revive, blocks paddles from reviving otherwise var/obj/item/shockpaddles/paddles var/obj/item/stock_parts/cell/high/cell - var/combat = FALSE //if true, revive through hardsuits, allow for combat shocking + var/combat = FALSE //if true, revive through space suits, allow for combat shocking var/cooldown_duration = 5 SECONDS//how long does it take to recharge /// The icon state for the paddle overlay, not applied if null var/paddle_state = "defibunit-paddles" diff --git a/code/game/objects/items/devices/aicard.dm b/code/game/objects/items/devices/aicard.dm index de58c0d2c03..5e06898bac8 100644 --- a/code/game/objects/items/devices/aicard.dm +++ b/code/game/objects/items/devices/aicard.dm @@ -27,18 +27,20 @@ user.visible_message(span_suicide("[user] is trying to upload [user.p_them()]self into [src]! That's not going to work out well!")) return BRUTELOSS -/obj/item/aicard/afterattack(atom/target, mob/user, proximity) - . = ..() - if(!proximity || !target) - return +/obj/item/aicard/pre_attack(atom/target, mob/living/user, params) if(AI) //AI is on the card, implies user wants to upload it. - log_combat(user, AI, "uploaded", src, "to [target].") + var/our_ai = AI target.transfer_ai(AI_TRANS_FROM_CARD, user, AI, src) + if(!AI) + log_combat(user, our_ai, "uploaded", src, "to [target].") + return TRUE else //No AI on the card, therefore the user wants to download one. target.transfer_ai(AI_TRANS_TO_CARD, user, null, src) if(AI) log_combat(user, AI, "carded", src) + return TRUE update_appearance() //Whatever happened, update the card's state (icon, name) to match. + return ..() /obj/item/aicard/update_icon_state() if(!AI) diff --git a/code/game/objects/items/hand_items.dm b/code/game/objects/items/hand_items.dm index 5fef308d3c9..0df35d15eb2 100644 --- a/code/game/objects/items/hand_items.dm +++ b/code/game/objects/items/hand_items.dm @@ -481,7 +481,7 @@ return FALSE /** - * To get around shielded hardsuits & such being set off by kisses when they shouldn't, we take a page from hallucination projectiles + * To get around shielded modsuits & such being set off by kisses when they shouldn't, we take a page from hallucination projectiles * and simply fake our on hit effects. This lets kisses remain incorporeal without having to make some new trait for this one niche situation. * This fake hit only happens if we can deal damage and if we hit a living thing. Otherwise, we just do normal on hit effects. */ diff --git a/code/game/objects/items/singularityhammer.dm b/code/game/objects/items/singularityhammer.dm index 5232dd53353..3bf15d05eaa 100644 --- a/code/game/objects/items/singularityhammer.dm +++ b/code/game/objects/items/singularityhammer.dm @@ -55,20 +55,16 @@ var/atom/movable/A = X if(A == wielder) continue - if(A && !A.anchored && !ishuman(X) && !isobserver(X)) + if(isliving(A)) + var/mob/living/vortexed_mob = A + if(vortexed_mob.mob_negates_gravity()) + continue + else + vortexed_mob.Paralyze(2 SECONDS) + if(!A.anchored && !isobserver(A)) step_towards(A,pull) step_towards(A,pull) step_towards(A,pull) - else if(ishuman(X)) - var/mob/living/carbon/human/H = X - if(istype(H.shoes, /obj/item/clothing/shoes/magboots)) - var/obj/item/clothing/shoes/magboots/M = H.shoes - if(M.magpulse) - continue - H.apply_effect(20, EFFECT_PARALYZE, 0) - step_towards(H,pull) - step_towards(H,pull) - step_towards(H,pull) /obj/item/singularityhammer/afterattack(atom/A as mob|obj|turf|area, mob/living/user, proximity) . = ..() diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index 4dcdad95f96..a0b88d2b639 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -642,12 +642,12 @@ new /obj/item/grenade/c4/x4(src) /obj/item/storage/backpack/duffelbag/syndie/firestarter - desc = "A large duffel bag containing a New Russian pyro backpack sprayer, Elite hardsuit, a Stechkin APS pistol, minibomb, ammo, and other equipment." + desc = "A large duffel bag containing a New Russian pyro backpack sprayer, Elite MODsuit, a Stechkin APS pistol, minibomb, ammo, and other equipment." /obj/item/storage/backpack/duffelbag/syndie/firestarter/PopulateContents() new /obj/item/clothing/under/syndicate/soviet(src) new /obj/item/watertank/op(src) - new /obj/item/clothing/suit/space/hardsuit/syndi/elite(src) + new /obj/item/mod/control/pre_equipped/elite(src) new /obj/item/gun/ballistic/automatic/pistol/aps(src) new /obj/item/ammo_box/magazine/m9mm_aps/fire(src) new /obj/item/ammo_box/magazine/m9mm_aps/fire(src) diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm index 16b53830d4f..733db662e7b 100644 --- a/code/game/objects/items/storage/boxes.dm +++ b/code/game/objects/items/storage/boxes.dm @@ -1590,7 +1590,7 @@ desc = "Despite his nickname, this wildlife expert was mainly known as a passionate environmentalist and conservationist, often coming in contact with dangerous wildlife to teach about the beauty of nature." /obj/item/storage/box/hero/carphunter/PopulateContents() - new /obj/item/clothing/suit/space/hardsuit/carp/old(src) + new /obj/item/clothing/suit/hooded/carp_costume/spaceproof/old(src) new /obj/item/clothing/mask/gas/carp(src) new /obj/item/knife/hunting(src) new /obj/item/storage/box/papersack/meat(src) diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm index da7bbfb183e..f4dfa226af9 100644 --- a/code/game/objects/items/storage/storage.dm +++ b/code/game/objects/items/storage/storage.dm @@ -9,9 +9,6 @@ /// SANTA IS EVIL var/preload = FALSE -/obj/item/storage/get_dumping_location(obj/item/storage/source,mob/user) - return src - /obj/item/storage/Initialize(mapload) . = ..() PopulateContents() diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index 90a67b1e751..9c8c45733d3 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -142,7 +142,7 @@ new /obj/item/clothing/under/suit/black_really(src) if(KIT_NUKEOPS_METAGAME) - new /obj/item/clothing/suit/space/hardsuit/syndi(src) // 8 tc + new /obj/item/mod/control/pre_equipped/nuclear(src) // 8 tc new /obj/item/gun/ballistic/shotgun/bulldog/unrestricted(src) // 8 tc new /obj/item/implanter/explosive(src) // 2 tc new /obj/item/ammo_box/magazine/m12g(src) // 2 tc @@ -193,7 +193,7 @@ if(KIT_WHITE_WHALE_HOLY_GRAIL) //Unique items that don't appear anywhere else new /obj/item/gun/ballistic/rifle/boltaction/harpoon(src) new /obj/item/storage/bag/harpoon_quiver(src) - new /obj/item/clothing/suit/space/hardsuit/carp(src) + new /obj/item/clothing/suit/hooded/carp_costume/spaceproof(src) new /obj/item/clothing/mask/gas/carp(src) new /obj/item/grenade/spawnergrenade/spesscarp(src) diff --git a/code/game/objects/items/tanks/jetpack.dm b/code/game/objects/items/tanks/jetpack.dm index f40c0043c2f..3e3eb90e583 100644 --- a/code/game/objects/items/tanks/jetpack.dm +++ b/code/game/objects/items/tanks/jetpack.dm @@ -24,6 +24,20 @@ QDEL_NULL(ion_trail) return ..() +/obj/item/tank/jetpack/item_action_slot_check(slot) + if(slot == ITEM_SLOT_BACK) + return TRUE + +/obj/item/tank/jetpack/equipped(mob/user, slot, initial) + . = ..() + if(on && slot != ITEM_SLOT_BACK) + turn_off(user) + +/obj/item/tank/jetpack/dropped(mob/user, silent) + . = ..() + if(on) + turn_off(user) + /obj/item/tank/jetpack/populate_gas() if(gas_type) var/datum/gas_mixture/our_mix = return_air() @@ -65,6 +79,7 @@ ion_trail.start() RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/move_react) RegisterSignal(user, COMSIG_MOVABLE_PRE_MOVE, .proc/pre_move_react) + RegisterSignal(user, COMSIG_MOVABLE_SPACEMOVE, .proc/spacemove_react) if(full_speed) user.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) return TRUE @@ -78,7 +93,7 @@ if(user) UnregisterSignal(user, COMSIG_MOVABLE_MOVED) UnregisterSignal(user, COMSIG_MOVABLE_PRE_MOVE) - + UnregisterSignal(user, COMSIG_MOVABLE_SPACEMOVE) user.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) /obj/item/tank/jetpack/proc/move_react(mob/user) @@ -102,6 +117,12 @@ SIGNAL_HANDLER ion_trail.oldposition = get_turf(src) +/obj/item/tank/jetpack/proc/spacemove_react(mob/user, movement_dir) + SIGNAL_HANDLER + + if(on && (movement_dir || stabilizers)) + return COMSIG_MOVABLE_STOP_SPACEMOVE + /obj/item/tank/jetpack/proc/allow_thrust(num, mob/living/user) if((num < 0.005 || air_contents.total_moles() < num)) turn_off(user) @@ -136,7 +157,7 @@ worn_icon_state = "jetpack-improvised" volume = 20 //normal jetpacks have 70 volume gas_type = null //it starts empty - full_speed = FALSE //moves at hardsuit jetpack speeds + full_speed = FALSE //moves at modsuit jetpack speeds /obj/item/tank/jetpack/improvised/allow_thrust(num, mob/living/user) if(rand(0,250) == 0) @@ -190,132 +211,3 @@ inhand_icon_state = "jetpack-black" distribute_pressure = 0 gas_type = /datum/gas/carbon_dioxide - - -/obj/item/tank/jetpack/suit - name = "hardsuit jetpack upgrade" - desc = "A modular, compact set of thrusters designed to integrate with a hardsuit. It is fueled by a tank inserted into the suit's storage compartment." - icon_state = "jetpack-mining" - inhand_icon_state = "jetpack-black" - w_class = WEIGHT_CLASS_NORMAL - actions_types = list(/datum/action/item_action/toggle_jetpack, /datum/action/item_action/jetpack_stabilization) - volume = 1 - slot_flags = null - gas_type = null - full_speed = FALSE - var/datum/gas_mixture/tempair_contents - var/obj/item/tank/internals/tank = null - var/mob/living/carbon/human/active_user = null - var/obj/item/clothing/suit/space/hardsuit/active_hardsuit = null - - -/obj/item/tank/jetpack/suit/Initialize(mapload) - . = ..() - STOP_PROCESSING(SSobj, src) - tempair_contents = air_contents - - -/obj/item/tank/jetpack/suit/Destroy() - if(on) - turn_off() - return ..() - - -/obj/item/tank/jetpack/suit/attack_self() - return - -/obj/item/tank/jetpack/suit/cycle(mob/user) - if(!istype(loc, /obj/item/clothing/suit/space/hardsuit)) - to_chat(user, span_warning("\The [src] must be connected to a hardsuit!")) - return - - var/mob/living/carbon/human/H = user - if(!istype(H.s_store, /obj/item/tank/internals)) - to_chat(user, span_warning("You need a tank in your suit storage!")) - return - return ..() - - -/obj/item/tank/jetpack/suit/turn_on(mob/user) - if(!istype(loc, /obj/item/clothing/suit/space/hardsuit) || !ishuman(loc.loc) || loc.loc != user) - return FALSE - active_user = user - tank = active_user.s_store - air_contents = tank.return_air() - . = ..() - if(!.) - active_user = null - tank = null - air_contents = null - return - active_hardsuit = loc - RegisterSignal(active_hardsuit, COMSIG_MOVABLE_MOVED, .proc/on_hardsuit_moved) - RegisterSignal(src, COMSIG_MOVABLE_MOVED, .proc/on_moved) - RegisterSignal(active_user, COMSIG_PARENT_QDELETING, .proc/on_user_del) - START_PROCESSING(SSobj, src) - - -/obj/item/tank/jetpack/suit/turn_off(mob/user) - STOP_PROCESSING(SSobj, src) - UnregisterSignal(src, COMSIG_MOVABLE_MOVED) - if(active_hardsuit) - UnregisterSignal(active_hardsuit, COMSIG_MOVABLE_MOVED) - active_hardsuit = null - if(active_user) - UnregisterSignal(user, COMSIG_PARENT_QDELETING) - active_user = null - tank = null - air_contents = tempair_contents - return ..() - - -/obj/item/tank/jetpack/suit/process() - var/mob/living/carbon/human/H = loc.loc - if(!tank || tank != H.s_store) - turn_off(active_user) - return - excited = TRUE - ..() - - -/// Called when the jetpack moves, presumably away from the hardsuit. -/obj/item/tank/jetpack/suit/proc/on_moved(atom/movable/source, atom/old_loc, movement_dir, forced, list/atom/old_locs) - SIGNAL_HANDLER - if(istype(loc, /obj/item/clothing/suit/space/hardsuit) && ishuman(loc.loc) && loc.loc == active_user) - UnregisterSignal(active_hardsuit, COMSIG_MOVABLE_MOVED) - active_hardsuit = loc - RegisterSignal(loc, COMSIG_MOVABLE_MOVED, .proc/on_hardsuit_moved) - return - turn_off(active_user) - - -/// Called when the hardsuit loc moves, presumably away from the human user. -/obj/item/tank/jetpack/suit/proc/on_hardsuit_moved(atom/movable/source, atom/old_loc, movement_dir, forced, list/atom/old_locs) - SIGNAL_HANDLER - turn_off(active_user) - - -/// Called when the human wearing the suit that contains this jetpack is deleted. -/obj/item/tank/jetpack/suit/proc/on_user_del(mob/living/carbon/human/source, force) - SIGNAL_HANDLER - turn_off(active_user) - - -//Return a jetpack that the mob can use -//Back worn jetpacks, hardsuit internal packs, and so on. -//Used in Process_Spacemove() and wherever you want to check for/get a jetpack - -/mob/proc/get_jetpack() - return - -/mob/living/carbon/get_jetpack() - var/obj/item/tank/jetpack/J = back - if(istype(J)) - return J - -/mob/living/carbon/human/get_jetpack() - var/obj/item/tank/jetpack/J = ..() - if(!istype(J) && istype(wear_suit, /obj/item/clothing/suit/space/hardsuit)) - var/obj/item/clothing/suit/space/hardsuit/C = wear_suit - J = C.jetpack - return J diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 49073c2a1bd..ed6f73425b6 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -206,7 +206,7 @@ if(!anchored || current_size >= STAGE_FIVE) step_towards(src,S) -/obj/get_dumping_location(datum/component/storage/source,mob/user) +/obj/get_dumping_location() return get_turf(src) /** diff --git a/code/game/objects/structures/crates_lockers/closets/gimmick.dm b/code/game/objects/structures/crates_lockers/closets/gimmick.dm index 0f89b5ffd39..93327f47127 100644 --- a/code/game/objects/structures/crates_lockers/closets/gimmick.dm +++ b/code/game/objects/structures/crates_lockers/closets/gimmick.dm @@ -48,8 +48,8 @@ new /obj/item/clothing/mask/gas/sechailer/swat(src) new /obj/item/clothing/shoes/combat/swat(src) new /obj/item/clothing/shoes/combat/swat(src) - new /obj/item/clothing/suit/space/hardsuit/deathsquad(src) - new /obj/item/clothing/suit/space/hardsuit/deathsquad(src) + new /obj/item/mod/control/pre_equipped/apocryphal(src) + new /obj/item/mod/control/pre_equipped/apocryphal(src) new /obj/item/clothing/under/syndicate/tacticool(src) new /obj/item/clothing/under/syndicate/tacticool(src) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm index 57d483afa7a..fc7e127f09f 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/engineering.dm @@ -7,7 +7,6 @@ ..() new /obj/item/storage/bag/garment/engineering_chief (src) - new /obj/item/tank/jetpack/suit(src) new /obj/item/cartridge/ce(src) new /obj/item/radio/headset/heads/ce(src) new /obj/item/megaphone/command(src) diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm index b460d7aa3bd..ebd6b8bf4c0 100644 --- a/code/game/objects/structures/false_walls.dm +++ b/code/game/objects/structures/false_walls.dm @@ -125,7 +125,7 @@ new mineral(loc) qdel(src) -/obj/structure/falsewall/get_dumping_location(obj/item/storage/source,mob/user) +/obj/structure/falsewall/get_dumping_location() return null /obj/structure/falsewall/examine_status(mob/user) //So you can't detect falsewalls by examine. diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 4eeab22191d..700442fa3a1 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -328,7 +328,7 @@ C.add_delayedload(C.newavail() * 0.0375) // you can gain up to 3.5 via the 4x upgrades power is halved by the pole so thats 2x then 1X then .5X for 3.5x the 3 bounces shock. return ..() -/obj/structure/grille/get_dumping_location(datum/component/storage/source,mob/user) +/obj/structure/grille/get_dumping_location() return null /obj/structure/grille/broken // Pre-broken grilles for map placement diff --git a/code/game/objects/structures/icemoon/cave_entrance.dm b/code/game/objects/structures/icemoon/cave_entrance.dm index 19151e34f1c..4a4767f13a4 100644 --- a/code/game/objects/structures/icemoon/cave_entrance.dm +++ b/code/game/objects/structures/icemoon/cave_entrance.dm @@ -137,7 +137,7 @@ GLOBAL_LIST_INIT(ore_probability, list( var/loot = rand(1, 28) switch(loot) if(1) - new /obj/item/clothing/suit/space/hardsuit/cult(loc) + new /obj/item/clothing/suit/hooded/cultrobes/hardened(loc) if(2) new /obj/item/clothing/glasses/godeye(loc) if(3) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index cb420a32423..5e544149c35 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -362,7 +362,7 @@ /obj/structure/window/atmos_expose(datum/gas_mixture/air, exposed_temperature) take_damage(round(air.return_volume() / 100), BURN, 0, 0) -/obj/structure/window/get_dumping_location(obj/item/storage/source,mob/user) +/obj/structure/window/get_dumping_location() return null /obj/structure/window/CanAStarPass(obj/item/card/id/ID, to_dir, atom/movable/caller) diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm index acc031f04e1..8ec4fac0274 100644 --- a/code/game/turfs/closed/walls.dm +++ b/code/game/turfs/closed/walls.dm @@ -270,7 +270,7 @@ if(.) ChangeTurf(/turf/closed/wall/mineral/cult) -/turf/closed/wall/get_dumping_location(obj/item/storage/source, mob/user) +/turf/closed/wall/get_dumping_location() return null /turf/closed/wall/acid_act(acidpwr, acid_volume) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 27c746b392e..cb5c3fdc475 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -650,7 +650,6 @@ GLOBAL_PROTECT(admin_verbs_hideable) if(robeless) new_spell.clothes_req = FALSE - new_spell.cult_req = FALSE if(spell_recipient.mind) spell_recipient.mind.AddSpell(new_spell) diff --git a/code/modules/admin/verbs/SDQL2/SDQL_spells/spell_edit_menu.dm b/code/modules/admin/verbs/SDQL2/SDQL_spells/spell_edit_menu.dm index 5ed20708263..33973d44a74 100644 --- a/code/modules/admin/verbs/SDQL2/SDQL_spells/spell_edit_menu.dm +++ b/code/modules/admin/verbs/SDQL2/SDQL_spells/spell_edit_menu.dm @@ -33,7 +33,6 @@ GLOBAL_LIST_INIT_TYPED(sdql_spells, /obj/effect/proc_holder/spell, list()) "charge_type", "clothes_req", "cone_level", - "cult_req", "deactive_msg", "desc", "drawmessage", @@ -211,7 +210,6 @@ GLOBAL_LIST_INIT_TYPED(sdql_spells, /obj/effect/proc_holder/spell, list()) If this is set to anything else, the variable with the appropriate name will be modified.", "holder_var_amount" = "The amount of damage taken, the duration of status effect inflicted, or the change made to any other variable.", "clothes_req" = "Whether the user has to be wearing wizard robes to cast the spell.", - "cult_req" = "Whether the user has to be wearing cult robes to cast the spell.", "human_req" = "Whether the user has to be a human to cast the spell. Redundant when clothes_req is true.", "nonabstract_req" = "If this is true, the spell cannot be cast by brains and pAIs.", "stat_allowed" = "Whether the spell can be cast if the user is unconscious or dead.", diff --git a/code/modules/antagonists/changeling/powers/strained_muscles.dm b/code/modules/antagonists/changeling/powers/strained_muscles.dm index efe31f928d4..b315ec715d6 100644 --- a/code/modules/antagonists/changeling/powers/strained_muscles.dm +++ b/code/modules/antagonists/changeling/powers/strained_muscles.dm @@ -1,10 +1,10 @@ //Strained Muscles: Temporary speed boost at the cost of rapid damage -//Limited because of hardsuits and such; ideally, used for a quick getaway +//Limited because of space suits and such; ideally, used for a quick getaway /datum/action/changeling/strained_muscles name = "Strained Muscles" desc = "We evolve the ability to reduce the acid buildup in our muscles, allowing us to move much faster." - helptext = "The strain will make us tired, and we will rapidly become fatigued. Standard weight restrictions, like hardsuits, still apply. Cannot be used in lesser form." + helptext = "The strain will make us tired, and we will rapidly become fatigued. Standard weight restrictions, like space suits, still apply. Cannot be used in lesser form." button_icon_state = "strained_muscles" chemical_cost = 0 dna_cost = 1 diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm index 4073b2062a9..1e6f88dda75 100644 --- a/code/modules/antagonists/cult/cult_items.dm +++ b/code/modules/antagonists/cult/cult_items.dm @@ -390,28 +390,34 @@ Striking a noncultist, however, will tear their flesh."} armor = list(MELEE = 50, BULLET = 30, LASER = 50,ENERGY = 50, BOMB = 25, BIO = 10, FIRE = 10, ACID = 10) flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT -/obj/item/clothing/head/helmet/space/hardsuit/cult +/obj/item/clothing/suit/hooded/cultrobes/hardened + name = "\improper Nar'Sien hardened armor" + desc = "A heavily-armored exosuit worn by warriors of the Nar'Sien cult. It can withstand hard vacuum." + icon_state = "cult_armor" + inhand_icon_state = "cult_armor" + w_class = WEIGHT_CLASS_BULKY + allowed = list(/obj/item/tome, /obj/item/melee/cultblade, /obj/item/tank/internals) + armor = list(MELEE = 50, BULLET = 40, LASER = 50, ENERGY = 60, BOMB = 50, BIO = 30, FIRE = 100, ACID = 100) + hoodtype = /obj/item/clothing/head/hooded/cult_hoodie/hardened + clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL + flags_inv = HIDEGLOVES | HIDESHOES | HIDEJUMPSUIT + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT + resistance_flags = NONE + +/obj/item/clothing/head/hooded/cult_hoodie/hardened name = "\improper Nar'Sien hardened helmet" desc = "A heavily-armored helmet worn by warriors of the Nar'Sien cult. It can withstand hard vacuum." icon_state = "cult_helmet" inhand_icon_state = "cult_helmet" armor = list(MELEE = 50, BULLET = 40, LASER = 50, ENERGY = 60, BOMB = 50, BIO = 30, FIRE = 100, ACID = 100) - light_system = NO_LIGHT_SUPPORT - light_range = 0 - actions_types = list() - -/obj/item/clothing/suit/space/hardsuit/cult - name = "\improper Nar'Sien hardened armor" - icon_state = "cult_armor" - inhand_icon_state = "cult_armor" - desc = "A heavily-armored exosuit worn by warriors of the Nar'Sien cult. It can withstand hard vacuum." - w_class = WEIGHT_CLASS_BULKY - allowed = list(/obj/item/tome, /obj/item/melee/cultblade, /obj/item/tank/internals/) - armor = list(MELEE = 50, BULLET = 40, LASER = 50, ENERGY = 60, BOMB = 50, BIO = 30, FIRE = 100, ACID = 100) - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/cult - -/obj/item/clothing/suit/space/hardsuit/cult/real - slowdown = 0 + clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SNUG_FIT | PLASMAMAN_HELMET_EXEMPT + flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR|HIDESNOUT + min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT + max_heat_protection_temperature = SPACE_HELM_MAX_TEMP_PROTECT + flash_protect = FLASH_PROTECTION_WELDER + flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF + resistance_flags = NONE /obj/item/sharpener/cult name = "eldritch whetstone" diff --git a/code/modules/antagonists/cult/cult_structures.dm b/code/modules/antagonists/cult/cult_structures.dm index c6e717da1db..2adcb4937f1 100644 --- a/code/modules/antagonists/cult/cult_structures.dm +++ b/code/modules/antagonists/cult/cult_structures.dm @@ -149,7 +149,7 @@ var/list/pickedtype = list() switch(choice) if("Nar'Sien Hardened Armor") - pickedtype += /obj/item/clothing/suit/space/hardsuit/cult/real + pickedtype += /obj/item/clothing/suit/hooded/cultrobes/hardened if("Flagellant's Robe") pickedtype += /obj/item/clothing/suit/hooded/cultrobes/berserker if("Eldritch Longsword") diff --git a/code/modules/antagonists/nukeop/clownop.dm b/code/modules/antagonists/nukeop/clownop.dm index df9530fb9e4..8ccd6347596 100644 --- a/code/modules/antagonists/nukeop/clownop.dm +++ b/code/modules/antagonists/nukeop/clownop.dm @@ -68,13 +68,21 @@ /datum/outfit/clown_operative name = "Clown Operative (Preview only)" - suit = /obj/item/clothing/suit/space/hardsuit/syndi - gloves = /obj/item/clothing/gloves/color/black + back = /obj/item/mod/control/pre_equipped/syndicate_empty mask = /obj/item/clothing/mask/gas/clown_hat +/datum/outfit/clown_operative/post_equip(mob/living/carbon/human/H, visualsOnly) + var/obj/item/mod/module/armor_booster/booster = locate() in H.back + booster.active = TRUE + H.update_inv_back() + /datum/outfit/clown_operative_elite name = "Clown Operative (Elite, Preview only)" - suit = /obj/item/clothing/suit/space/hardsuit/syndi/elite - gloves = /obj/item/clothing/gloves/color/black + back = /obj/item/mod/control/pre_equipped/syndicate_empty/elite mask = /obj/item/clothing/mask/gas/clown_hat + +/datum/outfit/clown_operative_elite/post_equip(mob/living/carbon/human/H, visualsOnly) + var/obj/item/mod/module/armor_booster/elite/booster = locate() in H.back + booster.active = TRUE + H.update_inv_back() diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index 660da61aad5..21873bd387d 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -172,18 +172,24 @@ /datum/outfit/nuclear_operative name = "Nuclear Operative (Preview only)" - suit = /obj/item/clothing/suit/space/hardsuit/syndi - head = /obj/item/clothing/head/helmet/space/hardsuit/syndi + back = /obj/item/mod/control/pre_equipped/syndicate_empty + +/datum/outfit/nuclear_operative/post_equip(mob/living/carbon/human/H, visualsOnly) + var/obj/item/mod/module/armor_booster/booster = locate() in H.back + booster.active = TRUE + H.update_inv_back() /datum/outfit/nuclear_operative_elite name = "Nuclear Operative (Elite, Preview only)" - suit = /obj/item/clothing/suit/space/hardsuit/syndi/elite - head = /obj/item/clothing/head/helmet/space/hardsuit/syndi/elite + back = /obj/item/mod/control/pre_equipped/syndicate_empty/elite l_hand = /obj/item/modular_computer/tablet/nukeops r_hand = /obj/item/shield/energy /datum/outfit/nuclear_operative_elite/post_equip(mob/living/carbon/human/H, visualsOnly) + var/obj/item/mod/module/armor_booster/elite/booster = locate() in H.back + booster.active = TRUE + H.update_inv_back() var/obj/item/shield/energy/shield = locate() in H.held_items shield.icon_state = "[shield.base_icon_state]1" H.update_inv_hands() diff --git a/code/modules/antagonists/nukeop/outfits.dm b/code/modules/antagonists/nukeop/outfits.dm index 3513b0d3783..e33689b1a93 100644 --- a/code/modules/antagonists/nukeop/outfits.dm +++ b/code/modules/antagonists/nukeop/outfits.dm @@ -54,12 +54,11 @@ glasses = /obj/item/clothing/glasses/night mask = /obj/item/clothing/mask/gas/syndicate - suit = /obj/item/clothing/suit/space/hardsuit/syndi + back = /obj/item/mod/control/pre_equipped/nuclear r_pocket = /obj/item/tank/internals/emergency_oxygen/engi internals_slot = ITEM_SLOT_RPOCKET belt = /obj/item/storage/belt/military r_hand = /obj/item/gun/ballistic/shotgun/bulldog backpack_contents = list(/obj/item/storage/box/survival/syndie=1,\ - /obj/item/tank/jetpack/oxygen/harness=1,\ /obj/item/gun/ballistic/automatic/pistol=1,\ /obj/item/knife/combat/survival) diff --git a/code/modules/antagonists/wizard/equipment/spellbook.dm b/code/modules/antagonists/wizard/equipment/spellbook.dm index b1728f7ad60..0b012c7ef13 100644 --- a/code/modules/antagonists/wizard/equipment/spellbook.dm +++ b/code/modules/antagonists/wizard/equipment/spellbook.dm @@ -342,14 +342,14 @@ name = "Buy Item" refundable = FALSE buy_word = "Summon" - var/item_path= null + var/item_path = null /datum/spellbook_entry/item/Buy(mob/living/carbon/human/user,obj/item/spellbook/book) - new item_path(get_turf(user)) + var/atom/spawned_path = new item_path(get_turf(user)) log_spellbook("[key_name(user)] bought [src] for [cost] points") SSblackbox.record_feedback("tally", "wizard_spell_learned", 1, name) - return TRUE + return spawned_path /datum/spellbook_entry/item/staffchange name = "Staff of Change" @@ -424,16 +424,34 @@ /datum/spellbook_entry/item/armor name = "Mastercrafted Armor Set" - desc = "An artefact suit of armor that allows you to cast spells while providing more protection against attacks and the void of space." - item_path = /obj/item/clothing/suit/space/hardsuit/wizard + desc = "An artefact suit of armor that allows you to cast spells while providing more protection against attacks and the void of space, also grants a battlemage shield." + item_path = /obj/item/mod/control/pre_equipped/enchanted category = "Defensive" -/datum/spellbook_entry/item/armor/Buy(mob/living/carbon/human/user,obj/item/spellbook/book) +/datum/spellbook_entry/item/armor/Buy(mob/living/carbon/human/user, obj/item/spellbook/book) . = ..() - if(.) - new /obj/item/tank/internals/oxygen(get_turf(user)) //i need to BREATHE - new /obj/item/clothing/shoes/sandal/magic(get_turf(user)) //In case they've lost them. - new /obj/item/clothing/gloves/combat/wizard(get_turf(user))//To complete the outfit + if(!.) + return + var/obj/item/mod/control/mod = . + var/obj/item/mod/module/storage/storage = locate() in mod.modules + var/obj/item/back = user.back + if(back) + if(!user.dropItemToGround(back)) + return + for(var/obj/item/item as anything in back.contents) + item.forceMove(storage) + if(!user.equip_to_slot_if_possible(mod, mod.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE)) + return + if(!user.dropItemToGround(user.wear_suit) || !user.dropItemToGround(user.head)) + return + mod.quick_activation() + +/datum/spellbook_entry/item/battlemage_charge + name = "Battlemage Armour Charges" + desc = "A powerful defensive rune, it will grant eight additional charges to a battlemage shield." + item_path = /obj/item/wizard_armour_charge + category = "Defensive" + cost = 1 /datum/spellbook_entry/item/contract name = "Contract of Apprenticeship" @@ -484,26 +502,6 @@ desc = "A hammer that creates an intensely powerful field of gravity where it strikes, pulling everything nearby to the point of impact." item_path = /obj/item/singularityhammer -/datum/spellbook_entry/item/battlemage - name = "Battlemage Armour" - desc = "An ensorceled suit of armour, protected by a powerful shield. The shield can completely negate sixteen attacks before being permanently depleted." - item_path = /obj/item/clothing/suit/space/hardsuit/shielded/wizard - limit = 1 - category = "Defensive" - -/datum/spellbook_entry/item/battlemage/Buy(mob/living/carbon/human/user,obj/item/spellbook/book) - . = ..() - if(.) - new /obj/item/clothing/shoes/sandal/magic(get_turf(user)) //In case they've lost them. - new /obj/item/clothing/gloves/combat/wizard(get_turf(user))//To complete the outfit - -/datum/spellbook_entry/item/battlemage_charge - name = "Battlemage Armour Charges" - desc = "A powerful defensive rune, it will grant eight additional charges to a suit of battlemage armour." - item_path = /obj/item/wizard_armour_charge - category = "Defensive" - cost = 1 - /datum/spellbook_entry/item/warpwhistle name = "Warp Whistle" desc = "A strange whistle that will transport you to a distant safe place on the station. There is a window of vulnerability at the beginning of every use." diff --git a/code/modules/awaymissions/mission_code/stationCollision.dm b/code/modules/awaymissions/mission_code/stationCollision.dm index 64475f45b78..23edb44f689 100644 --- a/code/modules/awaymissions/mission_code/stationCollision.dm +++ b/code/modules/awaymissions/mission_code/stationCollision.dm @@ -132,6 +132,6 @@ GLOBAL_VAR_INIT(sc_safecode5, "[rand(0,9)]") l_set = 1 new /obj/item/gun/energy/mindflayer(src) new /obj/item/soulstone(src) - new /obj/item/clothing/suit/space/hardsuit/cult(src) + new /obj/item/clothing/suit/hooded/cultrobes/hardened(src) //new /obj/item/teleportation_scroll(src) new /obj/item/stack/ore/diamond(src) diff --git a/code/modules/capture_the_flag/ctf_classes.dm b/code/modules/capture_the_flag/ctf_classes.dm index b63fe79ca8f..58ea6fd105b 100644 --- a/code/modules/capture_the_flag/ctf_classes.dm +++ b/code/modules/capture_the_flag/ctf_classes.dm @@ -5,7 +5,6 @@ ears = /obj/item/radio/headset uniform = /obj/item/clothing/under/syndicate suit = /obj/item/clothing/suit/armor/vest/ctf - toggle_helmet = FALSE // see the whites of their eyes shoes = /obj/item/clothing/shoes/combat gloves = /obj/item/clothing/gloves/combat id = /obj/item/card/id/away diff --git a/code/modules/cargo/blackmarket/blackmarket_items/clothing.dm b/code/modules/cargo/blackmarket/blackmarket_items/clothing.dm index 71257566b73..536e2861659 100644 --- a/code/modules/cargo/blackmarket/blackmarket_items/clothing.dm +++ b/code/modules/cargo/blackmarket/blackmarket_items/clothing.dm @@ -59,16 +59,6 @@ stock_max = 2 availability_prob = 70 -/datum/blackmarket_item/clothing/combatmedic_suit - name = "Combat Medic hardsuit" - desc = "A discarded combat medic hardsuit, found in the ruins of a carpet bombed xeno hive. Definately used, but as sturdy as an anchor." - item = /obj/item/clothing/suit/space/hardsuit/combatmedic - - price_min = 5500 - price_max = 7000 - stock_max = 1 - availability_prob = 10 - /datum/blackmarket_item/clothing/rocket_boots name = "Rocket Boots" desc = "We found a pair of jump boots and overclocked the hell out of them. No liability for grevious harm to or with a body." diff --git a/code/modules/cargo/exports/lavaland.dm b/code/modules/cargo/exports/lavaland.dm index 28caad93e68..e6dd51e1a3b 100644 --- a/code/modules/cargo/exports/lavaland.dm +++ b/code/modules/cargo/exports/lavaland.dm @@ -19,7 +19,7 @@ /obj/item/knife/envy, /obj/item/gun/ballistic/revolver/russian/soul, /obj/item/veilrender/vealrender, - /obj/item/clothing/suit/space/hardsuit/berserker, + /obj/item/clothing/suit/hooded/berserker, /obj/item/freeze_cube, /obj/item/soulstone/anybody/mining, /obj/item/clothing/gloves/gauntlets, @@ -48,7 +48,7 @@ /obj/item/mayhem, /obj/item/gun/magic/staff/spellblade, /obj/item/storm_staff, - /obj/item/clothing/suit/space/hardsuit/hostile_environment, + /obj/item/clothing/suit/hooded/hostile_environment, ) /datum/export/lavaland/megafauna/total_printout(datum/export_report/ex, notes = TRUE) //in the unlikely case a miner feels like selling megafauna loot diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index 2d514019bbb..b516f980b93 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -1456,6 +1456,18 @@ /obj/item/construction/plumbing/research) crate_name = "cytology supplies crate" +/datum/supply_pack/science/mod_core + name = "MOD core Crate" + desc = "Three cores, perfect for any MODsuit construction! Naturally harvestedâ„¢, of course." + cost = CARGO_CRATE_VALUE * 3 + access = ACCESS_ROBOTICS + access_view = ACCESS_ROBOTICS + contains = list(/obj/item/mod/construction/core, + /obj/item/mod/construction/core, + /obj/item/mod/construction/core) + crate_name = "MOD core crate" + crate_type = /obj/structure/closet/crate/secure/science + ////////////////////////////////////////////////////////////////////////////// /////////////////////////////// Service ////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// diff --git a/code/modules/client/preferences/mod_select.dm b/code/modules/client/preferences/mod_select.dm new file mode 100644 index 00000000000..c80c8b4c694 --- /dev/null +++ b/code/modules/client/preferences/mod_select.dm @@ -0,0 +1,23 @@ +/// Switches between mouse buttons for MODsuit active modules +/datum/preference/choiced/mod_select + category = PREFERENCE_CATEGORY_GAME_PREFERENCES + savefile_key = "mod_select" + savefile_identifier = PREFERENCE_PLAYER + +/datum/preference/choiced/mod_select/init_possible_values() + return list(MIDDLE_CLICK, ALT_CLICK) + +/datum/preference/choiced/mod_select/create_default_value() + return MIDDLE_CLICK + +/datum/preference/choiced/mod_select/apply_to_client_updated(client/client, value) + if(!ishuman(client.mob)) + return + var/mob/living/carbon/human/client_owner = client.mob + if(!istype(client_owner.back, /obj/item/mod/control)) + return + var/obj/item/mod/control/mod = client_owner.back + if(!mod.selected_module) + return + UnregisterSignal(mod.wearer, mod.selected_module.used_signal) + mod.selected_module.update_signal(value) diff --git a/code/modules/clothing/chameleon.dm b/code/modules/clothing/chameleon.dm index 6a568f00ba3..0fce9fff197 100644 --- a/code/modules/clothing/chameleon.dm +++ b/code/modules/clothing/chameleon.dm @@ -117,19 +117,15 @@ if(done) break - //hardsuit helmets/suit hoods - if(O.toggle_helmet && (ispath(O.suit, /obj/item/clothing/suit/space/hardsuit) || ispath(O.suit, /obj/item/clothing/suit/hooded)) && ishuman(user)) + //suit hoods + if(ishuman(user)) var/mob/living/carbon/human/H = user //make sure they are actually wearing the suit, not just holding it, and that they have a chameleon hat if(istype(H.wear_suit, /obj/item/clothing/suit/chameleon) && istype(H.head, /obj/item/clothing/head/chameleon)) var/helmet_type - if(ispath(O.suit, /obj/item/clothing/suit/space/hardsuit)) - var/obj/item/clothing/suit/space/hardsuit/hardsuit = O.suit - helmet_type = initial(hardsuit.helmettype) - else + if(ispath(O.suit, /obj/item/clothing/suit/hooded)) var/obj/item/clothing/suit/hooded/hooded = O.suit helmet_type = initial(hooded.hoodtype) - if(helmet_type) var/obj/item/clothing/head/chameleon/hat = H.head hat.chameleon_action.update_look(user, helmet_type) diff --git a/code/modules/clothing/glasses/_glasses.dm b/code/modules/clothing/glasses/_glasses.dm index dbd8fd13a01..9cafb97563e 100644 --- a/code/modules/clothing/glasses/_glasses.dm +++ b/code/modules/clothing/glasses/_glasses.dm @@ -142,11 +142,11 @@ desc = "A pair of snazzy goggles used to protect against chemical spills. Fitted with an analyzer for scanning items and reagents." icon_state = "purple" inhand_icon_state = "glasses" - clothing_flags = SCAN_REAGENTS //You can see reagents while wearing science goggles actions_types = list(/datum/action/item_action/toggle_research_scanner) glass_colour_type = /datum/client_colour/glass_colour/purple resistance_flags = ACID_PROOF armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, FIRE = 80, ACID = 100) + clothing_traits = list(TRAIT_REAGENT_SCANNER) /obj/item/clothing/glasses/science/item_action_slot_check(slot) if(slot == ITEM_SLOT_EYES) @@ -297,14 +297,13 @@ name = "beer goggles" icon_state = "sunhudbeer" desc = "A pair of sunglasses outfitted with apparatus to scan reagents, as well as providing an innate understanding of liquid viscosity while in motion." - clothing_flags = SCAN_REAGENTS - clothing_traits = list(TRAIT_BOOZE_SLIDER) + clothing_traits = list(TRAIT_BOOZE_SLIDER, TRAIT_REAGENT_SCANNER) /obj/item/clothing/glasses/sunglasses/chemical name = "science glasses" icon_state = "sunhudsci" desc = "A pair of tacky purple sunglasses that allow the wearer to recognize various chemical compounds with only a glance." - clothing_flags = SCAN_REAGENTS + clothing_traits = list(TRAIT_REAGENT_SCANNER) /obj/item/clothing/glasses/sunglasses/gar name = "black gar glasses" @@ -527,8 +526,8 @@ flash_protect = FLASH_PROTECTION_WELDER lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE glass_colour_type = FALSE - clothing_flags = SCAN_REAGENTS vision_flags = SEE_TURFS + clothing_traits = list(TRAIT_REAGENT_SCANNER) var/list/hudlist = list(DATA_HUD_MEDICAL_ADVANCED, DATA_HUD_DIAGNOSTIC_ADVANCED, DATA_HUD_SECURITY_ADVANCED) var/xray = FALSE diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 00fae051a17..fbbea43d1b8 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -523,14 +523,13 @@ AddElement(/datum/element/update_icon_updates_onmob) /obj/item/clothing/head/helmet/update_icon_state() - var/state = "[initial(icon_state)]" if(attached_light) + var/state = "[initial(icon_state)]" if(attached_light.on) state += "-flight-on" //"helmet-flight-on" // "helmet-cam-flight-on" else state += "-flight" //etc. - - icon_state = state + icon_state = state return ..() /obj/item/clothing/head/helmet/ui_action_click(mob/user, action) diff --git a/code/modules/clothing/outfits/ert.dm b/code/modules/clothing/outfits/ert.dm index cc937807cff..d998848f747 100644 --- a/code/modules/clothing/outfits/ert.dm +++ b/code/modules/clothing/outfits/ert.dm @@ -13,7 +13,6 @@ gloves = /obj/item/clothing/gloves/combat mask = /obj/item/clothing/mask/gas/sechailer shoes = /obj/item/clothing/shoes/combat/swat - toggle_helmet = FALSE /datum/outfit/centcom/ert/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) if(visualsOnly) @@ -34,13 +33,13 @@ name = "ERT Commander" id = /obj/item/card/id/advanced/centcom/ert - suit = /obj/item/clothing/suit/space/hardsuit/ert - suit_store = /obj/item/gun/energy/e_gun - back = /obj/item/storage/backpack/ert + suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/responsory/commander + l_hand = /obj/item/gun/energy/e_gun backpack_contents = list( /obj/item/melee/baton/security/loaded = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) belt = /obj/item/storage/belt/security/full glasses = /obj/item/clothing/glasses/hud/security/sunglasses l_pocket = /obj/item/switchblade @@ -61,7 +60,7 @@ /obj/item/gun/energy/pulse/pistol/loyalpin = 1, /obj/item/melee/baton/security/loaded = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) glasses = /obj/item/clothing/glasses/thermal/eyepatch l_pocket = /obj/item/melee/energy/sword/saber @@ -69,14 +68,14 @@ name = "ERT Security" id = /obj/item/card/id/advanced/centcom/ert/security - suit = /obj/item/clothing/suit/space/hardsuit/ert/sec - suit_store = /obj/item/gun/energy/e_gun/stun - back = /obj/item/storage/backpack/ert/security + suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/responsory/security + l_hand = /obj/item/gun/energy/e_gun/stun backpack_contents = list( /obj/item/melee/baton/security/loaded = 1, /obj/item/storage/box/handcuffs = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) belt = /obj/item/storage/belt/security/full glasses = /obj/item/clothing/glasses/hud/security/sunglasses gloves = /obj/item/clothing/gloves/tackler/combat/insulated @@ -94,31 +93,31 @@ /datum/outfit/centcom/ert/security/alert name = "ERT Security - High Alert" - belt = /obj/item/gun/energy/pulse/carbine/loyalpin + l_hand = /obj/item/gun/energy/pulse/carbine/loyalpin backpack_contents = list( /obj/item/melee/baton/security/loaded = 1, /obj/item/storage/belt/security/full = 1, /obj/item/storage/box/handcuffs = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) /datum/outfit/centcom/ert/medic name = "ERT Medic" id = /obj/item/card/id/advanced/centcom/ert/medical - suit = /obj/item/clothing/suit/space/hardsuit/ert/med - suit_store = /obj/item/gun/energy/e_gun - back = /obj/item/storage/backpack/ert/medical + suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/responsory/medic backpack_contents = list( /obj/item/gun/medbeam = 1, /obj/item/melee/baton/security/loaded = 1, /obj/item/reagent_containers/hypospray/combat = 1, /obj/item/storage/box/hug/plushes = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) belt = /obj/item/storage/belt/medical glasses = /obj/item/clothing/glasses/hud/health l_hand = /obj/item/storage/firstaid/regular + r_hand = /obj/item/gun/energy/e_gun /datum/outfit/centcom/ert/medic/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) ..() @@ -140,22 +139,22 @@ /obj/item/reagent_containers/hypospray/combat/nanites = 1, /obj/item/storage/box/hug/plushes = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) mask = /obj/item/clothing/mask/gas/sechailer/swat /datum/outfit/centcom/ert/engineer name = "ERT Engineer" id = /obj/item/card/id/advanced/centcom/ert/engineer - suit = /obj/item/clothing/suit/space/hardsuit/ert/engi - suit_store = /obj/item/gun/energy/e_gun - back = /obj/item/storage/backpack/ert/engineer + suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/responsory/engineer + l_hand = /obj/item/gun/energy/e_gun backpack_contents = list( /obj/item/construction/rcd/loaded/upgraded = 1, /obj/item/melee/baton/security/loaded = 1, /obj/item/pipe_dispenser = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) belt = /obj/item/storage/belt/utility/full/powertools glasses = /obj/item/clothing/glasses/meson/engine l_pocket = /obj/item/rcd_ammo/large @@ -179,7 +178,7 @@ /obj/item/melee/baton/security/loaded = 1, /obj/item/pipe_dispenser = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) /datum/outfit/centcom/centcom_official name = "CentCom Official" @@ -191,7 +190,7 @@ backpack_contents = list( /obj/item/stamp/centcom = 1, /obj/item/storage/box/survival = 1, -) + ) belt = /obj/item/gun/energy/e_gun ears = /obj/item/radio/headset/headset_cent glasses = /obj/item/clothing/glasses/sunglasses @@ -219,49 +218,51 @@ /datum/outfit/centcom/ert/commander/inquisitor name = "Inquisition Commander" - suit = /obj/item/clothing/suit/space/hardsuit/ert/paranormal + suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/responsory/inquisitory/commander + r_hand = /obj/item/nullrod/scythe/talking/chainsword backpack_contents = list( /obj/item/storage/box/survival = 1, -) - l_hand = /obj/item/nullrod/scythe/talking/chainsword + ) /datum/outfit/centcom/ert/security/inquisitor name = "Inquisition Security" - suit = /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor - suit_store = /obj/item/gun/energy/e_gun/stun + suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/responsory/inquisitory/security backpack_contents = list( /obj/item/construction/rcd/loaded = 1, /obj/item/melee/baton/security/loaded = 1, /obj/item/storage/box/handcuffs = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) /datum/outfit/centcom/ert/medic/inquisitor name = "Inquisition Medic" - suit = /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor + suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/responsory/inquisitory/medic backpack_contents = list( /obj/item/gun/medbeam = 1, /obj/item/melee/baton/security/loaded = 1, /obj/item/storage/box/survival/engineer = 1, /obj/item/reagent_containers/hypospray/combat = 1, /obj/item/reagent_containers/hypospray/combat/heresypurge = 1, -) + ) /datum/outfit/centcom/ert/chaplain name = "ERT Chaplain" id = /obj/item/card/id/advanced/centcom/ert/chaplain - suit = /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor // Chap role always gets this suit - suit_store = /obj/item/gun/energy/e_gun - back = /obj/item/storage/backpack/cultpack + suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/responsory/chaplain + l_hand = /obj/item/gun/energy/e_gun + belt = /obj/item/storage/belt/soulstone + glasses = /obj/item/clothing/glasses/hud/health backpack_contents = list( /obj/item/nullrod = 1, /obj/item/storage/box/survival/engineer = 1, -) - belt = /obj/item/storage/belt/soulstone - glasses = /obj/item/clothing/glasses/hud/health + ) /datum/outfit/centcom/ert/chaplain/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) ..() @@ -274,19 +275,20 @@ /datum/outfit/centcom/ert/chaplain/inquisitor name = "Inquisition Chaplain" + back = /obj/item/mod/control/pre_equipped/responsory/inquisitory/chaplain backpack_contents = list( /obj/item/grenade/chem_grenade/holy = 1, /obj/item/nullrod = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) belt = /obj/item/storage/belt/soulstone/full/chappy /datum/outfit/centcom/ert/janitor name = "ERT Janitor" id = /obj/item/card/id/advanced/centcom/ert/janitor - suit = /obj/item/clothing/suit/space/hardsuit/ert/jani - back = /obj/item/storage/backpack/ert/janitor + suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/responsory/janitor backpack_contents = list( /obj/item/grenade/clusterbuster/cleaner = 1, /obj/item/melee/baton/security/loaded = 1, @@ -294,7 +296,7 @@ /obj/item/reagent_containers/glass/bucket = 1, /obj/item/storage/box/lights/mixed = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) belt = /obj/item/storage/belt/janitor/full glasses = /obj/item/clothing/glasses/night l_pocket = /obj/item/grenade/chem_grenade/cleaner @@ -319,21 +321,21 @@ /obj/item/melee/baton/security/loaded = 1, /obj/item/storage/box/lights/mixed = 1, /obj/item/storage/box/survival/engineer = 1, -) - l_hand = /obj/item/reagent_containers/spray/chemsprayer/janitor + ) + r_hand = /obj/item/reagent_containers/spray/chemsprayer/janitor /datum/outfit/centcom/ert/clown name = "ERT Clown" id = /obj/item/card/id/advanced/centcom/ert/clown - suit = /obj/item/clothing/suit/space/hardsuit/ert/clown - back = /obj/item/storage/backpack/ert/clown + suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/responsory/clown backpack_contents = list( /obj/item/gun/ballistic/revolver/reverse = 1, /obj/item/melee/energy/sword/bananium = 1, /obj/item/shield/energy/bananium = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) belt = /obj/item/storage/belt/champion glasses = /obj/item/clothing/glasses/trickblindfold mask = /obj/item/clothing/mask/gas/clown_hat @@ -362,7 +364,7 @@ back = /obj/item/storage/backpack/satchel backpack_contents = list( /obj/item/storage/box/survival = 1, -) + ) belt = /obj/item/melee/baton ears = /obj/item/radio/headset/headset_cent glasses = /obj/item/clothing/glasses/sunglasses @@ -412,12 +414,13 @@ uniform = /obj/item/clothing/under/misc/overalls suit = /obj/item/clothing/suit/apron suit_store = null + back = /obj/item/storage/backpack/ert/janitor backpack_contents = list( /obj/item/mop/advanced = 1, /obj/item/reagent_containers/glass/bucket = 1, /obj/item/storage/box/lights/mixed = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) belt = /obj/item/storage/belt/janitor/full glasses = /obj/item/clothing/glasses/meson mask = /obj/item/clothing/mask/bandana/blue @@ -431,11 +434,12 @@ uniform = /obj/item/clothing/under/misc/bouncer suit = /obj/item/clothing/suit/armor/vest suit_store = null + back = /obj/item/storage/backpack/ert/security backpack_contents = list( /obj/item/clothing/head/helmet/police = 1, /obj/item/storage/box/handcuffs = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) belt = /obj/item/melee/baton/telescopic l_pocket = /obj/item/assembly/flash r_pocket = /obj/item/storage/wallet @@ -446,6 +450,7 @@ uniform = /obj/item/clothing/under/rank/engineering/engineer/hazard suit = /obj/item/clothing/suit/hazardvest suit_store = null + back = /obj/item/storage/backpack/ert/engineer backpack_contents = list( /obj/item/construction/rcd/loaded = 1, /obj/item/etherealballdeployer = 1, @@ -454,7 +459,7 @@ /obj/item/stack/sheet/iron/fifty = 1, /obj/item/stack/sheet/plasteel/twenty = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) head = /obj/item/clothing/head/hardhat/weldhat mask = /obj/item/clothing/mask/gas/atmos l_hand = /obj/item/areaeditor/blueprints @@ -465,11 +470,12 @@ uniform = /obj/item/clothing/under/rank/civilian/clown suit = /obj/item/clothing/suit/chameleon suit_store = null + back = /obj/item/storage/backpack/ert/clown backpack_contents = list( /obj/item/instrument/piano_synth = 1, /obj/item/shield/energy/bananium = 1, /obj/item/storage/box/survival/engineer = 1, -) + ) glasses = /obj/item/clothing/glasses/chameleon head = /obj/item/clothing/head/chameleon @@ -479,11 +485,12 @@ uniform = /obj/item/clothing/under/misc/coordinator suit = /obj/item/clothing/suit/coordinator suit_store = null + back = /obj/item/storage/backpack/ert backpack_contents = list( /obj/item/food/cake/birthday = 1, /obj/item/storage/box/fireworks = 3, /obj/item/storage/box/survival/engineer = 1, -) + ) belt = /obj/item/storage/belt/sabre head = /obj/item/clothing/head/coordinator l_pocket = /obj/item/knife/kitchen @@ -495,9 +502,8 @@ id = /obj/item/card/id/advanced/black/deathsquad id_trim = /datum/id_trim/centcom/deathsquad uniform = /obj/item/clothing/under/rank/centcom/commander - suit = /obj/item/clothing/suit/space/hardsuit/deathsquad - suit_store = /obj/item/tank/internals/emergency_oxygen/double - back = /obj/item/storage/backpack/security + suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/apocryphal backpack_contents = list( /obj/item/ammo_box/a357 = 1, /obj/item/flashlight = 1, @@ -505,7 +511,7 @@ /obj/item/storage/box/flashbangs = 1, /obj/item/storage/box/survival/engineer = 1, /obj/item/storage/firstaid/regular = 1, -) + ) belt = /obj/item/gun/ballistic/revolver/mateba ears = /obj/item/radio/headset/headset_cent/alt glasses = /obj/item/clothing/glasses/hud/toggle/thermal @@ -518,7 +524,7 @@ skillchips = list( /obj/item/skillchip/disk_verifier, -) + ) /datum/outfit/centcom/death_commando/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE) if(visualsOnly) @@ -593,7 +599,7 @@ /obj/item/reagent_containers/hypospray/combat = 1, /obj/item/storage/firstaid/regular = 1, /obj/item/storage/firstaid/advanced = 1, -) + ) belt = /obj/item/storage/belt/medical/paramedic glasses = /obj/item/clothing/glasses/hud/health/sunglasses diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm index df9747d7ba7..6bac6232fa5 100644 --- a/code/modules/clothing/outfits/standard.dm +++ b/code/modules/clothing/outfits/standard.dm @@ -406,14 +406,13 @@ head = /obj/item/clothing/head/helmet/space/chronos mask = /obj/item/clothing/mask/breath -/datum/outfit/debug //Debug objs plus hardsuit +/datum/outfit/debug //Debug objs plus MODsuit name = "Debug outfit" id = /obj/item/card/id/advanced/debug uniform = /obj/item/clothing/under/misc/patriotsuit - suit = /obj/item/clothing/suit/space/hardsuit/syndi/elite/debug suit_store = /obj/item/tank/internals/oxygen - back = /obj/item/storage/backpack/holding + back = /obj/item/mod/control/pre_equipped/debug backpack_contents = list( /obj/item/melee/energy/axe = 1, /obj/item/storage/part_replacer/bluespace/tier4 = 1, @@ -443,9 +442,8 @@ id = /obj/item/card/id/advanced/debug uniform = /obj/item/clothing/under/misc/patriotsuit - suit = /obj/item/clothing/suit/space/hardsuit/syndi/elite/admin suit_store = /obj/item/tank/internals/oxygen - back = /obj/item/storage/backpack/holding + back = /obj/item/mod/control/pre_equipped/administrative backpack_contents = list( /obj/item/melee/energy/axe = 1, /obj/item/storage/part_replacer/bluespace/tier4 = 1, diff --git a/code/modules/clothing/shoes/_shoes.dm b/code/modules/clothing/shoes/_shoes.dm index b6a5045792c..4deb34d5536 100644 --- a/code/modules/clothing/shoes/_shoes.dm +++ b/code/modules/clothing/shoes/_shoes.dm @@ -98,9 +98,6 @@ var/mob/M = loc M.update_inv_shoes() -/obj/item/proc/negates_gravity() - return FALSE - /** * adjust_laces adjusts whether our shoes (assuming they can_be_tied) and tied, untied, or knotted * diff --git a/code/modules/clothing/shoes/magboots.dm b/code/modules/clothing/shoes/magboots.dm index 826eba73157..746c57d9b7e 100644 --- a/code/modules/clothing/shoes/magboots.dm +++ b/code/modules/clothing/shoes/magboots.dm @@ -11,6 +11,17 @@ equip_delay_other = 70 resistance_flags = FIRE_PROOF +/obj/item/clothing/shoes/magboots/equipped(mob/user, slot) + . = ..() + if(slot == ITEM_SLOT_FEET) + update_gravity_trait(user) + else + REMOVE_TRAIT(user, TRAIT_NEGATES_GRAVITY, type) + +/obj/item/clothing/shoes/magboots/dropped(mob/user) + . = ..() + REMOVE_TRAIT(user, TRAIT_NEGATES_GRAVITY, type) + /obj/item/clothing/shoes/magboots/verb/toggle() set name = "Toggle Magboots" set category = "Object" @@ -19,7 +30,6 @@ return attack_self(usr) - /obj/item/clothing/shoes/magboots/attack_self(mob/user) if(magpulse) clothing_flags &= ~NOSLIP @@ -30,18 +40,22 @@ magpulse = !magpulse icon_state = "[magboot_state][magpulse]" to_chat(user, span_notice("You [magpulse ? "enable" : "disable"] the mag-pulse traction system.")) + update_gravity_trait(user) user.update_inv_shoes() //so our mob-overlays update user.update_gravity(user.has_gravity()) user.update_equipment_speed_mods() //we want to update our speed so we arent running at max speed in regular magboots update_action_buttons() -/obj/item/clothing/shoes/magboots/negates_gravity() - return clothing_flags & NOSLIP - /obj/item/clothing/shoes/magboots/examine(mob/user) . = ..() . += "Its mag-pulse traction system appears to be [magpulse ? "enabled" : "disabled"]." +///Adds/removes the gravity negation trait from the wearer depending on if the magpulse system is turned on. +/obj/item/clothing/shoes/magboots/proc/update_gravity_trait(mob/user) + if(magpulse) + ADD_TRAIT(user, TRAIT_NEGATES_GRAVITY, type) + else + REMOVE_TRAIT(user, TRAIT_NEGATES_GRAVITY, type) /obj/item/clothing/shoes/magboots/advance desc = "Advanced magnetic boots that have a lighter magnetic pull, placing less burden on the wearer." diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm deleted file mode 100644 index ebe13b69953..00000000000 --- a/code/modules/clothing/spacesuits/hardsuit.dm +++ /dev/null @@ -1,1067 +0,0 @@ -/// How much damage you take from an emp when wearing a hardsuit -#define HARDSUIT_EMP_BURN 2 // a very orange number - - //Baseline hardsuits -/obj/item/clothing/head/helmet/space/hardsuit - name = "hardsuit helmet" - desc = "A special helmet designed for work in a hazardous, low-pressure environment. Has radiation shielding." - icon_state = "hardsuit0-engineering" - inhand_icon_state = "eng_helm" - max_integrity = 300 - armor = list(MELEE = 10, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 10, BIO = 100, FIRE = 50, ACID = 75) - light_system = MOVABLE_LIGHT_DIRECTIONAL - light_range = 4 - light_power = 1 - light_on = FALSE - var/basestate = "hardsuit" - var/on = FALSE - var/obj/item/clothing/suit/space/hardsuit/suit - var/hardsuit_type = "engineering" //Determines used sprites: hardsuit[on]-[type] - actions_types = list(/datum/action/item_action/toggle_helmet_light) - flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF - visor_flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH | PEPPERPROOF - -/obj/item/clothing/head/helmet/space/hardsuit/Destroy() - . = ..() - if(!QDELETED(suit)) - qdel(suit) - suit = null - -/obj/item/clothing/head/helmet/space/hardsuit/attack_self(mob/user) - on = !on - icon_state = "[basestate][on]-[hardsuit_type]" - user.update_inv_head() //so our mob-overlays update - - set_light_on(on) - - update_action_buttons() - -/obj/item/clothing/head/helmet/space/hardsuit/dropped(mob/user) - ..() - if(suit) - suit.RemoveHelmet() - -/obj/item/clothing/head/helmet/space/hardsuit/item_action_slot_check(slot) - if(slot == ITEM_SLOT_HEAD) - return 1 - -/obj/item/clothing/head/helmet/space/hardsuit/equipped(mob/user, slot) - ..() - if(slot != ITEM_SLOT_HEAD) - if(suit) - suit.RemoveHelmet() - else - qdel(src) - -/obj/item/clothing/head/helmet/space/hardsuit/proc/display_visor_message(msg) - var/mob/wearer = loc - if(msg && ishuman(wearer)) - wearer.show_message("[icon2html(src, wearer)][span_robot("[msg]")]", MSG_VISUAL) - -/obj/item/clothing/head/helmet/space/hardsuit/emp_act(severity) - . = ..() - display_visor_message("[severity > 1 ? "Light" : "Strong"] electromagnetic pulse detected!") - - -/obj/item/clothing/suit/space/hardsuit - name = "hardsuit" - desc = "A special suit that protects against hazardous, low pressure environments. Has radiation shielding." - icon_state = "hardsuit-engineering" - inhand_icon_state = "eng_hardsuit" - max_integrity = 300 - armor = list(MELEE = 10, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 10, BIO = 100, FIRE = 50, ACID = 75, WOUND = 10) - allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/t_scanner, /obj/item/construction/rcd, /obj/item/pipe_dispenser) - siemens_coefficient = 0 - var/obj/item/clothing/head/helmet/space/hardsuit/helmet - actions_types = list(/datum/action/item_action/toggle_spacesuit, /datum/action/item_action/toggle_helmet) - var/helmettype = /obj/item/clothing/head/helmet/space/hardsuit - var/obj/item/tank/jetpack/suit/jetpack = null - var/hardsuit_type - /// Whether the helmet is on. - var/helmet_on = FALSE - -/obj/item/clothing/suit/space/hardsuit/Initialize(mapload) - if(jetpack && ispath(jetpack)) - jetpack = new jetpack(src) - . = ..() - -/obj/item/clothing/suit/space/hardsuit/attack_self(mob/user) - user.changeNext_move(CLICK_CD_MELEE) - ..() - -/obj/item/clothing/suit/space/hardsuit/examine(mob/user) - . = ..() - if(!helmet && helmettype) - . += span_notice("The helmet on [src] seems to be malfunctioning. Its light bulb needs to be replaced.") - -/obj/item/clothing/suit/space/hardsuit/attackby(obj/item/I, mob/user, params) - if(istype(I, /obj/item/tank/jetpack/suit)) - if(jetpack) - to_chat(user, span_warning("[src] already has a jetpack installed.")) - return - if(src == user.get_item_by_slot(ITEM_SLOT_OCLOTHING)) //Make sure the player is not wearing the suit before applying the upgrade. - to_chat(user, span_warning("You cannot install the upgrade to [src] while wearing it.")) - return - - if(user.transferItemToLoc(I, src)) - jetpack = I - to_chat(user, span_notice("You successfully install the jetpack into [src].")) - return - else if(!cell_cover_open && I.tool_behaviour == TOOL_SCREWDRIVER) - if(!jetpack) - to_chat(user, span_warning("[src] has no jetpack installed.")) - return - if(src == user.get_item_by_slot(ITEM_SLOT_OCLOTHING)) - to_chat(user, span_warning("You cannot remove the jetpack from [src] while wearing it.")) - return - - jetpack.turn_off(user) - jetpack.forceMove(drop_location()) - jetpack = null - to_chat(user, span_notice("You successfully remove the jetpack from [src].")) - return - else if(istype(I, /obj/item/light) && helmettype) - if(src == user.get_item_by_slot(ITEM_SLOT_OCLOTHING)) - to_chat(user, span_warning("You cannot replace the bulb in the helmet of [src] while wearing it.")) - return - if(helmet) - to_chat(user, span_warning("The helmet of [src] does not require a new bulb.")) - return - var/obj/item/light/L = I - if(L.status) - to_chat(user, span_warning("This bulb is too damaged to use as a replacement!")) - return - if(do_after(user, 5 SECONDS, src)) - qdel(I) - helmet = new helmettype(src) - to_chat(user, span_notice("You have successfully repaired [src]'s helmet.")) - new /obj/item/light/bulb/broken(drop_location()) - return ..() - -/obj/item/clothing/suit/space/hardsuit/equipped(mob/user, slot) - ..() - if(jetpack) - if(slot == ITEM_SLOT_OCLOTHING) - for(var/X in jetpack.actions) - var/datum/action/A = X - A.Grant(user) - -/obj/item/clothing/suit/space/hardsuit/dropped(mob/user) - ..() - if(isatom(jetpack)) - for(var/X in jetpack.actions) - var/datum/action/A = X - A.Remove(user) - -/obj/item/clothing/suit/space/hardsuit/item_action_slot_check(slot) - if(slot == ITEM_SLOT_OCLOTHING) //we only give the mob the ability to toggle the helmet if he's wearing the hardsuit. - return 1 - -/// Burn the person inside the hard suit just a little, the suit got really hot for a moment -/obj/item/clothing/suit/space/emp_act(severity) - . = ..() - var/mob/living/carbon/human/user = src.loc - if(istype(user)) - user.apply_damage(HARDSUIT_EMP_BURN, BURN, spread_damage=TRUE) - to_chat(user, span_warning("You feel \the [src] heat up from the EMP burning you slightly.")) - - // Chance to scream - if (user.stat < UNCONSCIOUS && prob(10)) - user.emote("scream") - - //Engineering -/obj/item/clothing/head/helmet/space/hardsuit/engine - name = "engineering hardsuit helmet" - desc = "A special helmet designed for work in a hazardous, low-pressure environment. Has radiation shielding." - icon_state = "hardsuit0-engineering" - inhand_icon_state = "eng_helm" - armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 10, BIO = 100, FIRE = 100, ACID = 75, WOUND = 10) - hardsuit_type = "engineering" - resistance_flags = FIRE_PROOF - -/obj/item/clothing/head/helmet/space/hardsuit/engine/Initialize(mapload) - . = ..() - AddElement(/datum/element/radiation_protected_clothing) - -/obj/item/clothing/suit/space/hardsuit/engine - name = "engineering hardsuit" - desc = "A special suit that protects against hazardous, low pressure environments. Has radiation shielding." - icon_state = "hardsuit-engineering" - inhand_icon_state = "eng_hardsuit" - armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 10, BIO = 100, FIRE = 100, ACID = 75, WOUND = 10) - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/engine - resistance_flags = FIRE_PROOF - -/obj/item/clothing/suit/space/hardsuit/engine/Initialize(mapload) - . = ..() - AddElement(/datum/element/radiation_protected_clothing) - -/obj/item/clothing/suit/space/hardsuit/engine/equipped(mob/user, slot) - . = ..() - AddComponent(/datum/component/geiger_sound) - -/obj/item/clothing/suit/space/hardsuit/engine/dropped() - . = ..() - qdel(GetComponent(/datum/component/geiger_sound)) - - //Atmospherics -/obj/item/clothing/head/helmet/space/hardsuit/atmos - name = "atmospherics hardsuit helmet" - desc = "A modified engineering hardsuit for work in a hazardous, low pressure environment. The radiation shielding plates were removed to allow for improved thermal protection instead." - icon_state = "hardsuit0-atmospherics" - inhand_icon_state = "atmo_helm" - hardsuit_type = "atmospherics" - armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 10, BIO = 100, FIRE = 100, ACID = 75, WOUND = 10) - heat_protection = HEAD //Uncomment to enable firesuit protection - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - -/obj/item/clothing/suit/space/hardsuit/atmos - name = "atmospherics hardsuit" - desc = "A modified engineering hardsuit for work in a hazardous, low pressure environment. The radiation shielding plates were removed to allow for improved thermal protection instead." - icon_state = "hardsuit-atmospherics" - inhand_icon_state = "atmo_hardsuit" - armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 10, BIO = 100, FIRE = 100, ACID = 75, WOUND = 10) - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS //Uncomment to enable firesuit protection - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/atmos - -/obj/item/clothing/suit/space/hardsuit/atmos/equipped(mob/user, slot) - . = ..() - AddComponent(/datum/component/geiger_sound) - -/obj/item/clothing/suit/space/hardsuit/atmos/dropped() - . = ..() - qdel(GetComponent(/datum/component/geiger_sound)) - - //Chief Engineer's hardsuit -/obj/item/clothing/head/helmet/space/hardsuit/engine/elite - name = "advanced hardsuit helmet" - desc = "An advanced helmet designed for work in a hazardous, low pressure environment. Shines with a high polish." - icon_state = "hardsuit0-white" - inhand_icon_state = "ce_helm" - hardsuit_type = "white" - armor = list(MELEE = 40, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 50, BIO = 100, FIRE = 100, ACID = 90, WOUND = 10) - heat_protection = HEAD - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - -/obj/item/clothing/suit/space/hardsuit/engine/elite - icon_state = "hardsuit-white" - name = "advanced hardsuit" - desc = "An advanced suit that protects against hazardous, low pressure environments. Shines with a high polish." - inhand_icon_state = "ce_hardsuit" - armor = list(MELEE = 40, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 50, BIO = 100, FIRE = 100, ACID = 90, WOUND = 10) - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/engine/elite - jetpack = /obj/item/tank/jetpack/suit - cell = /obj/item/stock_parts/cell/super - - //Mining hardsuit -/obj/item/clothing/head/helmet/space/hardsuit/mining - name = "mining hardsuit helmet" - desc = "A special helmet designed for work in a hazardous, low pressure environment. Has reinforced plating for wildlife encounters and dual floodlights." - icon_state = "hardsuit0-mining" - inhand_icon_state = "mining_helm" - hardsuit_type = "mining" - max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT - resistance_flags = FIRE_PROOF - heat_protection = HEAD - armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 50, BIO = 100, FIRE = 50, ACID = 75, WOUND = 15) - light_range = 7 - -/obj/item/clothing/head/helmet/space/hardsuit/mining/Initialize(mapload) - . = ..() - AddComponent(/datum/component/armor_plate) - RegisterSignal(src, COMSIG_ARMOR_PLATED, .proc/upgrade_icon) - -/obj/item/clothing/head/helmet/space/hardsuit/mining/proc/upgrade_icon(datum/source, amount, maxamount) - SIGNAL_HANDLER - - if(amount) - name = "reinforced [initial(name)]" - hardsuit_type = "mining_goliath" - if(amount == maxamount) - hardsuit_type = "mining_goliath_full" - icon_state = "hardsuit[on]-[hardsuit_type]" - set_light_color(LIGHT_COLOR_FLARE) - if(ishuman(loc)) - var/mob/living/carbon/human/wearer = loc - if(wearer.head == src) - wearer.update_inv_head() - -/obj/item/clothing/suit/space/hardsuit/mining - name = "mining hardsuit" - desc = "A special suit that protects against hazardous, low pressure environments. Has reinforced plating for wildlife encounters." - icon_state = "hardsuit-mining" - inhand_icon_state = "mining_hardsuit" - hardsuit_type = "mining" - max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT - resistance_flags = FIRE_PROOF - armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 50, BIO = 100, FIRE = 50, ACID = 75, WOUND = 15) - allowed = list( - /obj/item/flashlight, - /obj/item/gun/energy/kinetic_accelerator, - /obj/item/mining_scanner, - /obj/item/pickaxe, - /obj/item/resonator, - /obj/item/t_scanner/adv_mining_scanner, - /obj/item/tank/internals, - ) - - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/mining - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - -/obj/item/clothing/suit/space/hardsuit/mining/Initialize(mapload) - . = ..() - AddComponent(/datum/component/armor_plate) - RegisterSignal(src, COMSIG_ARMOR_PLATED, .proc/upgrade_icon) - -/obj/item/clothing/suit/space/hardsuit/mining/proc/upgrade_icon(datum/source, amount, maxamount) - SIGNAL_HANDLER - - if(amount) - name = "reinforced [initial(name)]" - hardsuit_type = "mining_goliath" - if(amount == maxamount) - hardsuit_type = "mining_goliath_full" - icon_state = "hardsuit-[hardsuit_type]" - if(ishuman(loc)) - var/mob/living/carbon/human/wearer = loc - if(wearer.wear_suit == src) - wearer.update_inv_wear_suit() - - //Syndicate hardsuit -/obj/item/clothing/head/helmet/space/hardsuit/syndi - name = "blood-red hardsuit helmet" - desc = "A dual-mode advanced helmet designed for work in special operations. It is in EVA mode. Property of Gorlex Marauders." - alt_desc = "A dual-mode advanced helmet designed for work in special operations. It is in combat mode. Property of Gorlex Marauders." - icon_state = "hardsuit1-syndi" - inhand_icon_state = "syndie_helm" - hardsuit_type = "syndi" - armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 40, BOMB = 35, BIO = 100, FIRE = 50, ACID = 90, WOUND = 25) - on = TRUE - var/obj/item/clothing/suit/space/hardsuit/syndi/linkedsuit = null - actions_types = list(/datum/action/item_action/toggle_helmet_mode) - visor_flags_inv = HIDEMASK|HIDEEYES|HIDEFACE|HIDEFACIALHAIR|HIDESNOUT - visor_flags = STOPSPRESSUREDAMAGE - -/obj/item/clothing/head/helmet/space/hardsuit/syndi/Initialize(mapload) - . = ..() - if(istype(loc, /obj/item/clothing/suit/space/hardsuit/syndi)) - linkedsuit = loc - -/obj/item/clothing/head/helmet/space/hardsuit/syndi/attack_self(mob/user) //Toggle Helmet - if(!isturf(user.loc)) - to_chat(user, span_warning("You cannot toggle your helmet while in this [user.loc]!") ) - return - on = !on - if(on || force) - to_chat(user, span_notice("You switch your hardsuit to EVA mode, sacrificing speed for space protection.")) - name = initial(name) - desc = initial(desc) - set_light_on(TRUE) - clothing_flags |= visor_flags - flags_cover |= HEADCOVERSEYES | HEADCOVERSMOUTH - flags_inv |= visor_flags_inv - cold_protection |= HEAD - else - to_chat(user, span_notice("You switch your hardsuit to combat mode and can now run at full speed.")) - name += " (combat)" - desc = alt_desc - set_light_on(FALSE) - clothing_flags &= ~visor_flags - flags_cover &= ~(HEADCOVERSEYES | HEADCOVERSMOUTH) - flags_inv &= ~visor_flags_inv - cold_protection &= ~HEAD - update_appearance() - playsound(src.loc, 'sound/mecha/mechmove03.ogg', 50, TRUE) - toggle_hardsuit_mode(user) - if(iscarbon(user)) - var/mob/living/carbon/C = user - C.head_update(src, forced = 1) - icon_state = "hardsuit[on]-[hardsuit_type]" - user.update_inv_head() - update_action_buttons() - -/obj/item/clothing/head/helmet/space/hardsuit/syndi/proc/toggle_hardsuit_mode(mob/user) //Helmet Toggles Suit Mode - if(linkedsuit) - if(on) - linkedsuit.name = initial(linkedsuit.name) - linkedsuit.desc = initial(linkedsuit.desc) - linkedsuit.slowdown = initial(linkedsuit.slowdown) - linkedsuit.clothing_flags |= STOPSPRESSUREDAMAGE - linkedsuit.cold_protection |= CHEST | GROIN | LEGS | FEET | ARMS | HANDS - else - linkedsuit.name += " (combat)" - linkedsuit.desc = linkedsuit.alt_desc - linkedsuit.slowdown = 0 - linkedsuit.clothing_flags &= ~STOPSPRESSUREDAMAGE - linkedsuit.cold_protection &= ~(CHEST | GROIN | LEGS | FEET | ARMS | HANDS) - - linkedsuit.icon_state = "hardsuit[on]-[hardsuit_type]" - linkedsuit.update_appearance() - user.update_inv_wear_suit() - user.update_inv_w_uniform() - user.update_equipment_speed_mods() - - -/obj/item/clothing/suit/space/hardsuit/syndi - name = "blood-red hardsuit" - desc = "A dual-mode advanced hardsuit designed for work in special operations. It is in EVA mode. Property of Gorlex Marauders." - alt_desc = "A dual-mode advanced hardsuit designed for work in special operations. It is in combat mode. Property of Gorlex Marauders." - icon_state = "hardsuit1-syndi" - inhand_icon_state = "syndie_hardsuit" - hardsuit_type = "syndi" - w_class = WEIGHT_CLASS_NORMAL - armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 40, BOMB = 35, BIO = 100, FIRE = 50, ACID = 90, WOUND = 25) - allowed = list(/obj/item/gun, /obj/item/ammo_box,/obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/melee/energy/sword/saber, /obj/item/restraints/handcuffs, /obj/item/tank/internals) - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/syndi - jetpack = /obj/item/tank/jetpack/suit - cell = /obj/item/stock_parts/cell/hyper - -//Elite Syndie suit -/obj/item/clothing/head/helmet/space/hardsuit/syndi/elite - name = "elite syndicate hardsuit helmet" - desc = "An elite version of the syndicate helmet, with improved armour and fireproofing. It is in EVA mode. Property of Gorlex Marauders." - alt_desc = "An elite version of the syndicate helmet, with improved armour and fireproofing. It is in combat mode. Property of Gorlex Marauders." - icon_state = "hardsuit1-syndielite" - hardsuit_type = "syndielite" - armor = list(MELEE = 60, BULLET = 60, LASER = 50, ENERGY = 60, BOMB = 55, BIO = 100, FIRE = 100, ACID = 100, WOUND = 25) - heat_protection = HEAD - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - resistance_flags = FIRE_PROOF | ACID_PROOF - -/obj/item/clothing/head/helmet/space/hardsuit/syndi/elite/debug - -/obj/item/clothing/head/helmet/space/hardsuit/syndi/elite/admin - name = "jannie hardsuit helmet" - armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, FIRE = 100, ACID = 100, WOUND = 100) - -/obj/item/clothing/suit/space/hardsuit/syndi/elite - name = "elite syndicate hardsuit" - desc = "An elite version of the syndicate hardsuit, with improved armour and fireproofing. It is in travel mode." - alt_desc = "An elite version of the syndicate hardsuit, with improved armour and fireproofing. It is in combat mode." - icon_state = "hardsuit1-syndielite" - hardsuit_type = "syndielite" - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/syndi/elite - armor = list(MELEE = 60, BULLET = 60, LASER = 50, ENERGY = 60, BOMB = 55, BIO = 100, FIRE = 100, ACID = 100, WOUND = 25) - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - resistance_flags = FIRE_PROOF | ACID_PROOF - cell = /obj/item/stock_parts/cell/bluespace - -/obj/item/clothing/suit/space/hardsuit/syndi/elite/debug - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/syndi/elite/debug - -/obj/item/clothing/suit/space/hardsuit/syndi/elite/admin //the hardsuit to end all other hardsuits - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/syndi/elite/admin - name = "jannie hardsuit" - slowdown = 0 - armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, FIRE = 100, ACID = 100, WOUND = 100) - cell = /obj/item/stock_parts/cell/infinite - clothing_flags = BLOCKS_SHOVE_KNOCKDOWN - strip_delay = 1000 - equip_delay_other = 1000 - -//The Owl Hardsuit -/obj/item/clothing/head/helmet/space/hardsuit/syndi/owl - name = "owl hardsuit helmet" - desc = "A dual-mode advanced helmet designed for any crime-fighting situation. It is in travel mode." - alt_desc = "A dual-mode advanced helmet designed for any crime-fighting situation. It is in combat mode." - icon_state = "hardsuit1-owl" - inhand_icon_state = "s_helmet" - hardsuit_type = "owl" - visor_flags_inv = 0 - visor_flags = 0 - on = FALSE - -/obj/item/clothing/suit/space/hardsuit/syndi/owl - name = "owl hardsuit" - desc = "A dual-mode advanced hardsuit designed for any crime-fighting situation. It is in travel mode." - alt_desc = "A dual-mode advanced hardsuit designed for any crime-fighting situation. It is in combat mode." - icon_state = "hardsuit1-owl" - inhand_icon_state = "s_suit" - hardsuit_type = "owl" - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/syndi/owl - - - //Wizard hardsuit -/obj/item/clothing/head/helmet/space/hardsuit/wizard - name = "gem-encrusted hardsuit helmet" - desc = "A bizarre gem-encrusted helmet that radiates magical energies." - icon_state = "hardsuit0-wiz" - inhand_icon_state = "wiz_helm" - hardsuit_type = "wiz" - resistance_flags = FIRE_PROOF | ACID_PROOF //No longer shall our kind be foiled by lone chemists with spray bottles! - armor = list(MELEE = 40, BULLET = 40, LASER = 40, ENERGY = 50, BOMB = 35, BIO = 100, FIRE = 100, ACID = 100, WOUND = 30) - heat_protection = HEAD //Uncomment to enable firesuit protection - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - -/obj/item/clothing/suit/space/hardsuit/wizard - name = "gem-encrusted hardsuit" - desc = "A bizarre gem-encrusted suit that radiates magical energies." - icon_state = "hardsuit-wiz" - inhand_icon_state = "wiz_hardsuit" - w_class = WEIGHT_CLASS_NORMAL - resistance_flags = FIRE_PROOF | ACID_PROOF - armor = list(MELEE = 40, BULLET = 40, LASER = 40, ENERGY = 50, BOMB = 35, BIO = 100, FIRE = 100, ACID = 100, WOUND = 30) - allowed = list(/obj/item/teleportation_scroll, /obj/item/tank/internals) - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS //Uncomment to enable firesuit protection - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/wizard - cell = /obj/item/stock_parts/cell/hyper - slowdown = 0 //you're spending 2 wizard points on this thing, the least it could do is not make you a sitting duck - -/obj/item/clothing/suit/space/hardsuit/wizard/Initialize(mapload) - . = ..() - AddComponent(/datum/component/anti_magic, TRUE, FALSE, FALSE, ITEM_SLOT_OCLOTHING, INFINITY, FALSE) - - - //Medical hardsuit -/obj/item/clothing/head/helmet/space/hardsuit/medical - name = "medical hardsuit helmet" - desc = "A special helmet designed for work in a hazardous, low pressure environment. Built with lightweight materials for extra comfort, but does not protect the eyes from intense light." - icon_state = "hardsuit0-medical" - inhand_icon_state = "medical_helm" - hardsuit_type = "medical" - flash_protect = FLASH_PROTECTION_NONE - armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 10, BIO = 100, FIRE = 60, ACID = 75, WOUND = 10) - clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SCAN_REAGENTS | SNUG_FIT - -/obj/item/clothing/suit/space/hardsuit/medical - name = "medical hardsuit" - desc = "A special suit that protects against hazardous, low pressure environments. Built with lightweight materials for easier movement." - icon_state = "hardsuit-medical" - inhand_icon_state = "medical_hardsuit" - allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/storage/firstaid, /obj/item/healthanalyzer, /obj/item/stack/medical) - armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 10, BIO = 100, FIRE = 60, ACID = 75, WOUND = 10) - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/medical - slowdown = 0.5 - - //Research Director hardsuit -/obj/item/clothing/head/helmet/space/hardsuit/rd - name = "prototype hardsuit helmet" - desc = "A prototype helmet designed for research in a hazardous, low pressure environment. Scientific data flashes across the visor." - icon_state = "hardsuit0-rd" - hardsuit_type = "rd" - resistance_flags = ACID_PROOF | FIRE_PROOF - max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT - armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 100, BIO = 100, FIRE = 60, ACID = 80, WOUND = 15) - var/explosion_detection_dist = 21 - clothing_flags = STOPSPRESSUREDAMAGE | THICKMATERIAL | SCAN_REAGENTS | SNUG_FIT - actions_types = list(/datum/action/item_action/toggle_helmet_light, /datum/action/item_action/toggle_research_scanner) - -/obj/item/clothing/head/helmet/space/hardsuit/rd/Initialize(mapload) - . = ..() - RegisterSignal(SSdcs, COMSIG_GLOB_EXPLOSION, .proc/sense_explosion) - -/obj/item/clothing/head/helmet/space/hardsuit/rd/equipped(mob/living/carbon/human/user, slot) - ..() - if (slot == ITEM_SLOT_HEAD) - var/datum/atom_hud/DHUD = GLOB.huds[DATA_HUD_DIAGNOSTIC_BASIC] - DHUD.add_hud_to(user) - -/obj/item/clothing/head/helmet/space/hardsuit/rd/dropped(mob/living/carbon/human/user) - ..() - if (user.head == src) - var/datum/atom_hud/DHUD = GLOB.huds[DATA_HUD_DIAGNOSTIC_BASIC] - DHUD.remove_hud_from(user) - -/obj/item/clothing/head/helmet/space/hardsuit/rd/proc/sense_explosion(datum/source, turf/epicenter, devastation_range, heavy_impact_range, - light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range) - SIGNAL_HANDLER - - var/turf/T = get_turf(src) - if(T?.z != epicenter.z) - return - if(get_dist(epicenter, T) > explosion_detection_dist) - return - display_visor_message("Explosion detected! Epicenter: [devastation_range], Outer: [heavy_impact_range], Shock: [light_impact_range]") - -/obj/item/clothing/suit/space/hardsuit/rd - name = "prototype hardsuit" - desc = "A prototype suit that protects against hazardous, low pressure environments. Fitted with extensive plating for handling explosives and dangerous research materials." - icon_state = "hardsuit-rd" - inhand_icon_state = "hardsuit-rd" - resistance_flags = ACID_PROOF | FIRE_PROOF - max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT //Same as an emergency firesuit. Not ideal for extended exposure. - allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/gun/energy/wormhole_projector, - /obj/item/hand_tele, /obj/item/aicard) - armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 100, BIO = 100, FIRE = 60, ACID = 80, WOUND = 15) - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/rd - cell = /obj/item/stock_parts/cell/super - - //Security hardsuit -/obj/item/clothing/head/helmet/space/hardsuit/security - name = "security hardsuit helmet" - desc = "A special helmet designed for work in a hazardous, low pressure environment. Has an additional layer of armor." - icon_state = "hardsuit0-sec" - inhand_icon_state = "sec_helm" - hardsuit_type = "sec" - armor = list(MELEE = 35, BULLET = 15, LASER = 30,ENERGY = 40, BOMB = 10, BIO = 100, FIRE = 75, ACID = 75, WOUND = 20) - - -/obj/item/clothing/suit/space/hardsuit/security - icon_state = "hardsuit-sec" - name = "security hardsuit" - desc = "A special suit that protects against hazardous, low pressure environments. Has an additional layer of armor." - inhand_icon_state = "sec_hardsuit" - armor = list(MELEE = 35, BULLET = 15, LASER = 30, ENERGY = 40, BOMB = 10, BIO = 100, FIRE = 75, ACID = 75, WOUND = 20) - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/security - -/obj/item/clothing/suit/space/hardsuit/security/Initialize(mapload) - . = ..() - allowed = GLOB.security_hardsuit_allowed - - //Head of Security hardsuit -/obj/item/clothing/head/helmet/space/hardsuit/security/hos - name = "head of security's hardsuit helmet" - desc = "A special bulky helmet designed for work in a hazardous, low pressure environment. Has an additional layer of armor." - icon_state = "hardsuit0-hos" - hardsuit_type = "hos" - armor = list(MELEE = 45, BULLET = 25, LASER = 30, ENERGY = 40, BOMB = 25, BIO = 100, FIRE = 95, ACID = 95, WOUND = 25) - - -/obj/item/clothing/suit/space/hardsuit/security/hos - icon_state = "hardsuit-hos" - name = "head of security's hardsuit" - desc = "A special bulky suit that protects against hazardous, low pressure environments. Has an additional layer of armor." - armor = list(MELEE = 45, BULLET = 25, LASER = 30, ENERGY = 40, BOMB = 25, BIO = 100, FIRE = 95, ACID = 95, WOUND = 25) - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/security/hos - jetpack = /obj/item/tank/jetpack/suit - cell = /obj/item/stock_parts/cell/super - - //SWAT MKII -/obj/item/clothing/head/helmet/space/hardsuit/swat - name = "\improper MK.II SWAT Helmet" - icon_state = "swat2helm" - inhand_icon_state = "swat2helm" - desc = "A tactical SWAT helmet MK.II." - armor = list(MELEE = 40, BULLET = 50, LASER = 50, ENERGY = 60, BOMB = 50, BIO = 100, FIRE = 100, ACID = 100, WOUND = 15) - resistance_flags = FIRE_PROOF | ACID_PROOF - flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT //we want to see the mask //this makes the hardsuit not fireproof you genius - heat_protection = HEAD - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - actions_types = list() - -/obj/item/clothing/head/helmet/space/hardsuit/swat/attack_self() - -/obj/item/clothing/suit/space/hardsuit/swat - name = "\improper MK.II SWAT Suit" - desc = "A MK.II SWAT suit with streamlined joints and armor made out of superior materials, insulated against intense heat if worn with the complementary gas mask. The most advanced tactical armor available." - icon_state = "swat2" - inhand_icon_state = "swat2" - armor = list(MELEE = 40, BULLET = 50, LASER = 50, ENERGY = 60, BOMB = 50, BIO = 100, FIRE = 100, ACID = 100, WOUND = 15) - resistance_flags = FIRE_PROOF | ACID_PROOF - heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT //this needed to be added a long fucking time ago - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/swat - -// SWAT and Captain get EMP Protection -/obj/item/clothing/suit/space/hardsuit/swat/Initialize(mapload) - . = ..() - allowed = GLOB.security_hardsuit_allowed - - //Captain -/obj/item/clothing/head/helmet/space/hardsuit/swat/captain - name = "captain's SWAT helmet" - icon_state = "capspace" - inhand_icon_state = "capspacehelmet" - desc = "A tactical MK.II SWAT helmet boasting better protection and a reasonable fashion sense." - -/obj/item/clothing/suit/space/hardsuit/swat/captain - name = "captain's SWAT suit" - desc = "A MK.II SWAT suit with streamlined joints and armor made out of superior materials, insulated against intense heat with the complementary gas mask. The most advanced tactical armor available. Usually reserved for heavy hitter corporate security, this one has a regal finish in Nanotrasen company colors. Better not let the assistants get a hold of it." - icon_state = "caparmor" - inhand_icon_state = "capspacesuit" - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/swat/captain - cell = /obj/item/stock_parts/cell/super - - //Clown -/obj/item/clothing/head/helmet/space/hardsuit/clown - name = "cosmohonk hardsuit helmet" - desc = "A special helmet designed for work in a hazardous, low-humor environment. Has radiation shielding." - icon_state = "hardsuit0-clown" - inhand_icon_state = "hardsuit0-clown" - armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 10, BIO = 100, FIRE = 60, ACID = 30) - hardsuit_type = "clown" - -/obj/item/clothing/suit/space/hardsuit/clown - name = "cosmohonk hardsuit" - desc = "A special suit that protects against hazardous, low humor environments. Has radiation shielding. Only a true clown can wear it." - icon_state = "hardsuit-clown" - inhand_icon_state = "clown_hardsuit" - armor = list(MELEE = 30, BULLET = 5, LASER = 10, ENERGY = 20, BOMB = 10, BIO = 100, FIRE = 60, ACID = 30) - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/clown - -/obj/item/clothing/suit/space/hardsuit/clown/mob_can_equip(mob/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE) - if(!..() || !ishuman(M)) - return FALSE - if(is_clown_job(M.mind.assigned_role)) - return TRUE - else - return FALSE - - //Old Prototype -/obj/item/clothing/head/helmet/space/hardsuit/ancient - name = "prototype RIG hardsuit helmet" - desc = "Early prototype RIG hardsuit helmet, designed to quickly shift over a user's head. Design constraints of the helmet mean it has no inbuilt cameras, thus it restricts the users visability." - icon_state = "hardsuit0-ancient" - inhand_icon_state = "anc_helm" - armor = list(MELEE = 30, BULLET = 5, LASER = 5, ENERGY = 15, BOMB = 50, BIO = 100, FIRE = 100, ACID = 75) - hardsuit_type = "ancient" - resistance_flags = FIRE_PROOF - -/obj/item/clothing/suit/space/hardsuit/ancient - name = "prototype RIG hardsuit" - desc = "Prototype powered RIG hardsuit. Provides excellent protection from the elements of space while being comfortable to move around in, thanks to the powered locomotives. Remains very bulky however." - icon_state = "hardsuit-ancient" - inhand_icon_state = "anc_hardsuit" - armor = list(MELEE = 30, BULLET = 5, LASER = 5, ENERGY = 15, BOMB = 50, BIO = 100, FIRE = 100, ACID = 75) - slowdown = 3 - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ancient - resistance_flags = FIRE_PROOF - var/footstep = 1 - var/mob/listeningTo - -/obj/item/clothing/suit/space/hardsuit/ancient/proc/on_mob_move() - SIGNAL_HANDLER - var/mob/living/carbon/human/H = loc - if(!istype(H) || H.wear_suit != src) - return - if(footstep > 1) - playsound(src, 'sound/effects/servostep.ogg', 100, TRUE) - footstep = 0 - else - footstep++ - -/obj/item/clothing/suit/space/hardsuit/ancient/equipped(mob/user, slot) - . = ..() - if(slot != ITEM_SLOT_OCLOTHING) - if(listeningTo) - UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) - return - if(listeningTo == user) - return - if(listeningTo) - UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) - RegisterSignal(user, COMSIG_MOVABLE_MOVED, .proc/on_mob_move) - listeningTo = user - -/obj/item/clothing/suit/space/hardsuit/ancient/dropped() - . = ..() - if(listeningTo) - UnregisterSignal(listeningTo, COMSIG_MOVABLE_MOVED) - -/obj/item/clothing/suit/space/hardsuit/ancient/Destroy() - listeningTo = null - return ..() - - //Deathsquad -/obj/item/clothing/head/helmet/space/hardsuit/deathsquad - name = "MK.III SWAT Helmet" - desc = "An advanced tactical space helmet." - icon_state = "deathsquad" - inhand_icon_state = "deathsquad" - armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 60, BOMB = 100, BIO = 100, FIRE = 100, ACID = 100, WOUND = 20) - strip_delay = 130 - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - resistance_flags = FIRE_PROOF | ACID_PROOF - actions_types = list() - -/obj/item/clothing/head/helmet/space/hardsuit/deathsquad/attack_self(mob/user) - return - -/obj/item/clothing/suit/space/hardsuit/deathsquad - name = "MK.III SWAT Suit" - desc = "A prototype designed to replace the ageing MK.II SWAT suit. Based on the streamlined MK.II model, the traditional ceramic and graphene plate construction was replaced with plasteel, allowing superior armor against most threats. There's room for some kind of energy projection device on the back." - icon_state = "deathsquad" - inhand_icon_state = "swat_suit" - allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals, /obj/item/knife/combat) - armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 60, BOMB = 100, BIO = 100, FIRE = 100, ACID = 100, WOUND = 20) - strip_delay = 130 - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - resistance_flags = FIRE_PROOF | ACID_PROOF - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/deathsquad - dog_fashion = /datum/dog_fashion/back/deathsquad - cell = /obj/item/stock_parts/cell/bluespace - - //Emergency Response Team suits -/obj/item/clothing/head/helmet/space/hardsuit/ert - name = "emergency response team commander helmet" - desc = "The integrated helmet of an ERT hardsuit, this one has blue highlights." - icon_state = "hardsuit0-ert_commander" - inhand_icon_state = "hardsuit0-ert_commander" - hardsuit_type = "ert_commander" - armor = list(MELEE = 65, BULLET = 50, LASER = 50, ENERGY = 60, BOMB = 50, BIO = 100, FIRE = 80, ACID = 80) - strip_delay = 130 - light_range = 7 - resistance_flags = FIRE_PROOF - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - -/obj/item/clothing/head/helmet/space/hardsuit/ert/Initialize(mapload) - . = ..() - ADD_TRAIT(src, TRAIT_NODROP, LOCKED_HELMET_TRAIT) - -/obj/item/clothing/suit/space/hardsuit/ert - name = "emergency response team commander hardsuit" - desc = "The standard issue hardsuit of the ERT, this one has blue highlights. Offers superb protection against environmental hazards." - icon_state = "ert_command" - inhand_icon_state = "ert_command" - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert - allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/restraints/handcuffs, /obj/item/tank/internals) - armor = list(MELEE = 65, BULLET = 50, LASER = 50, ENERGY = 60, BOMB = 50, BIO = 100, FIRE = 80, ACID = 80) - slowdown = 0 - strip_delay = 130 - resistance_flags = FIRE_PROOF - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - cell = /obj/item/stock_parts/cell/bluespace - -// ERT suit's gets EMP Protection -/obj/item/clothing/suit/space/hardsuit/ert/Initialize(mapload) - . = ..() - AddElement(/datum/element/empprotection, EMP_PROTECT_CONTENTS) - - //ERT Security -/obj/item/clothing/head/helmet/space/hardsuit/ert/sec - name = "emergency response team security helmet" - desc = "The integrated helmet of an ERT hardsuit, this one has red highlights." - icon_state = "hardsuit0-ert_security" - inhand_icon_state = "hardsuit0-ert_security" - hardsuit_type = "ert_security" - -/obj/item/clothing/suit/space/hardsuit/ert/sec - name = "emergency response team security hardsuit" - desc = "The standard issue hardsuit of the ERT, this one has red highlights. Offers superb protection against environmental hazards." - icon_state = "ert_security" - inhand_icon_state = "ert_security" - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/sec - - //ERT Engineering -/obj/item/clothing/head/helmet/space/hardsuit/ert/engi - name = "emergency response team engineering helmet" - desc = "The integrated helmet of an ERT hardsuit, this one has orange highlights." - icon_state = "hardsuit0-ert_engineer" - inhand_icon_state = "hardsuit0-ert_engineer" - hardsuit_type = "ert_engineer" - -/obj/item/clothing/suit/space/hardsuit/ert/engi - name = "emergency response team engineering hardsuit" - desc = "The standard issue hardsuit of the ERT, this one has orange highlights. Offers superb protection against environmental hazards." - icon_state = "ert_engineer" - inhand_icon_state = "ert_engineer" - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/engi - - //ERT Medical -/obj/item/clothing/head/helmet/space/hardsuit/ert/med - name = "emergency response team medical helmet" - desc = "The integrated helmet of an ERT hardsuit, this one has white highlights." - icon_state = "hardsuit0-ert_medical" - inhand_icon_state = "hardsuit0-ert_medical" - hardsuit_type = "ert_medical" - -/obj/item/clothing/suit/space/hardsuit/ert/med - name = "emergency response team medical hardsuit" - desc = "The standard issue hardsuit of the ERT, this one has white highlights. Offers superb protection against environmental hazards." - icon_state = "ert_medical" - inhand_icon_state = "ert_medical" - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/med - - //ERT Janitor -/obj/item/clothing/head/helmet/space/hardsuit/ert/jani - name = "emergency response team janitorial helmet" - desc = "The integrated helmet of an ERT hardsuit, this one has purple highlights." - icon_state = "hardsuit0-ert_janitor" - inhand_icon_state = "hardsuit0-ert_janitor" - hardsuit_type = "ert_janitor" - -/obj/item/clothing/suit/space/hardsuit/ert/jani - name = "emergency response team janitorial hardsuit" - desc = "The standard issue hardsuit of the ERT, this one has purple highlights. Offers superb protection against environmental hazards. This one has extra clips for holding various janitorial tools." - icon_state = "ert_janitor" - inhand_icon_state = "ert_janitor" - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/jani - allowed = list(/obj/item/tank/internals, /obj/item/storage/bag/trash, /obj/item/melee/flyswatter, /obj/item/mop, /obj/item/holosign_creator, /obj/item/reagent_containers/glass/bucket, /obj/item/reagent_containers/spray/chemsprayer/janitor) - - //ERT Clown -/obj/item/clothing/head/helmet/space/hardsuit/ert/clown - name = "emergency response team clown helmet" - desc = "The integrated helmet of an ERT hardsuit, this one is colourful!" - icon_state = "hardsuit0-ert_clown" - inhand_icon_state = "hardsuit0-ert_clown" - hardsuit_type = "ert_clown" - -/obj/item/clothing/suit/space/hardsuit/ert/clown - name = "emergency response team clown hardsuit" - desc = "The non-standard issue hardsuit of the ERT, this one is colourful! Offers superb protection against environmental hazards. Does not offer superb protection against a ravaging crew." - icon_state = "ert_clown" - inhand_icon_state = "ert_clown" - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/clown - allowed = list(/obj/item/tank/internals, /obj/item/bikehorn, /obj/item/instrument, /obj/item/food/grown/banana, /obj/item/grown/bananapeel) - - //Paranormal ERT -/obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal - name = "paranormal response team helmet" - desc = "A helmet worn by those who deal with paranormal threats for a living." - icon_state = "hardsuit0-prt" - inhand_icon_state = "hardsuit0-prt" - hardsuit_type = "prt" - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - actions_types = list() - resistance_flags = FIRE_PROOF - -/obj/item/clothing/suit/space/hardsuit/ert/paranormal - name = "paranormal response team hardsuit" - desc = "Powerful wards are built into this hardsuit, protecting the user from all manner of paranormal threats." - icon_state = "knight_grey" - inhand_icon_state = "knight_grey" - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - resistance_flags = FIRE_PROOF - -/obj/item/clothing/suit/space/hardsuit/ert/paranormal/Initialize(mapload) - . = ..() - AddComponent(/datum/component/anti_magic, TRUE, TRUE, TRUE, ITEM_SLOT_OCLOTHING) - - //Inquisitor -/obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor - name = "inquisitor's hardsuit" - icon_state = "hardsuit-inq" - inhand_icon_state = "hardsuit-inq" - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/inquisitor - -/obj/item/clothing/head/helmet/space/hardsuit/ert/paranormal/inquisitor - name = "inquisitor's helmet" - icon_state = "hardsuit0-inq" - inhand_icon_state = "hardsuit0-inq" - hardsuit_type = "inq" - -//Carpsuit, bestsuit, lovesuit -/obj/item/clothing/head/helmet/space/hardsuit/carp - name = "carp helmet" - desc = "Spaceworthy and it looks like a space carp's head, smells like one too." - icon_state = "carp_helm" - inhand_icon_state = "syndicate" - armor = list(MELEE = -20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 60, ACID = 75) //As whimpy as a space carp - light_system = NO_LIGHT_SUPPORT - light_range = 0 //luminosity when on - actions_types = list() - flags_inv = HIDEEARS|HIDEHAIR|HIDEFACIALHAIR //facial hair will clip with the helm, this'll need a dynamic_fhair_suffix at some point. - -/obj/item/clothing/head/helmet/space/hardsuit/carp/Initialize(mapload) - . = ..() - ADD_TRAIT(src, TRAIT_NODROP, LOCKED_HELMET_TRAIT) - -/obj/item/clothing/suit/space/hardsuit/carp - name = "carp space suit" - desc = "A slimming piece of dubious space carp technology, you suspect it won't stand up to hand-to-hand blows." - icon_state = "carp_suit" - inhand_icon_state = "space_suit_syndicate" - slowdown = 0 //Space carp magic, never stop believing - armor = list(MELEE = -20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 60, ACID = 75) //As whimpy whimpy whoo - allowed = list(/obj/item/tank/internals, /obj/item/gun/ballistic/rifle/boltaction/harpoon) //I'm giving you a hint here - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/carp - -/obj/item/clothing/head/helmet/space/hardsuit/carp/equipped(mob/living/carbon/human/user, slot) - ..() - if (slot == ITEM_SLOT_HEAD) - user.faction |= "carp" - -/obj/item/clothing/head/helmet/space/hardsuit/carp/dropped(mob/living/carbon/human/user) - ..() - if (user.head == src) - user.faction -= "carp" - -/obj/item/clothing/suit/space/hardsuit/carp/old - name = "battered carp space suit" - desc = "It's covered in bite marks and scratches, yet seems to be still perfectly functional." - slowdown = 1 - -//Combat medic -/obj/item/clothing/head/helmet/space/hardsuit/combatmedic - name = "endemic combat medic helmet" - desc = "The integrated helmet of the combat medic hardsuit, this has a bright, glowing facemask." - icon_state = "hardsuit0-combatmedic" - inhand_icon_state = "hardsuit0-combatmedic" - armor = list(MELEE = 35, BULLET = 10, LASER = 20, ENERGY = 30, BOMB = 5, BIO = 100, FIRE = 65, ACID = 75) - hardsuit_type = "combatmedic" - -/obj/item/clothing/suit/space/hardsuit/combatmedic - name = "endemic combat medic hardsuit" - desc = "The standard issue hardsuit of infectious disease officers, before the formation of ERT teams. This model is labeled 'Veradux'." - icon_state = "combatmedic" - inhand_icon_state = "combatmedic" - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/combatmedic - armor = list(MELEE = 35, BULLET = 10, LASER = 20, ENERGY = 30, BOMB = 5, BIO = 100, FIRE = 65, ACID = 75) - allowed = list(/obj/item/gun, /obj/item/melee/baton, /obj/item/circular_saw, /obj/item/tank/internals, /obj/item/storage/box/pillbottles,\ - /obj/item/storage/firstaid, /obj/item/stack/medical/gauze, /obj/item/stack/medical/suture, /obj/item/stack/medical/mesh, /obj/item/storage/bag/chemistry) - -/////////////SHIELDED////////////////////////////////// - -/obj/item/clothing/suit/space/hardsuit/shielded - name = "shielded hardsuit" - desc = "A hardsuit with built in energy shielding. Will rapidly recharge when not under fire." - icon_state = "hardsuit-hos" - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/security/hos - allowed = null - armor = list(MELEE = 30, BULLET = 15, LASER = 30, ENERGY = 40, BOMB = 10, BIO = 100, FIRE = 100, ACID = 100, WOUND = 15) - resistance_flags = FIRE_PROOF | ACID_PROOF - -/obj/item/clothing/suit/space/hardsuit/shielded/setup_shielding() - AddComponent(/datum/component/shielded, max_charges = 3, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, shield_icon = "shield-old") - -/obj/item/clothing/head/helmet/space/hardsuit/shielded - resistance_flags = FIRE_PROOF | ACID_PROOF - -//////Syndicate Version -/obj/item/clothing/suit/space/hardsuit/shielded/syndi - name = "blood-red hardsuit" - desc = "An advanced hardsuit with built in energy shielding." - icon_state = "hardsuit1-syndi" - inhand_icon_state = "syndie_hardsuit" - hardsuit_type = "syndi" - armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 40, BOMB = 35, BIO = 100, FIRE = 100, ACID = 100, WOUND = 30) - allowed = list(/obj/item/gun, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/melee/baton, /obj/item/melee/energy/sword/saber, /obj/item/restraints/handcuffs, /obj/item/tank/internals) - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/shielded/syndi - slowdown = 0 - jetpack = /obj/item/tank/jetpack/suit - -/obj/item/clothing/suit/space/hardsuit/shielded/syndi/setup_shielding() - AddComponent(/datum/component/shielded, max_charges = 3, recharge_start_delay = 20 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, shield_icon = "shield-red") - -/obj/item/clothing/head/helmet/space/hardsuit/shielded/syndi - name = "blood-red hardsuit helmet" - desc = "An advanced hardsuit helmet with built in energy shielding." - icon_state = "hardsuit1-syndi" - inhand_icon_state = "syndie_helm" - hardsuit_type = "syndi" - armor = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 40, BOMB = 35, BIO = 100, FIRE = 100, ACID = 100, WOUND = 30) - -///SWAT version -/obj/item/clothing/suit/space/hardsuit/shielded/swat - name = "death commando spacesuit" - desc = "An advanced hardsuit favored by commandos for use in special operations." - icon_state = "deathsquad" - inhand_icon_state = "swat_suit" - hardsuit_type = "syndi" - armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 60, BOMB = 100, BIO = 100, FIRE = 100, ACID = 100, WOUND = 30) - strip_delay = 130 - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/shielded/swat - dog_fashion = /datum/dog_fashion/back/deathsquad - -/obj/item/clothing/suit/space/hardsuit/shielded/swat/setup_shielding() - AddComponent(/datum/component/shielded, max_charges = 4, recharge_start_delay = 1.5 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, shield_icon = "shield-old") - -/obj/item/clothing/head/helmet/space/hardsuit/shielded/swat - name = "death commando helmet" - desc = "A tactical helmet with built in energy shielding." - icon_state = "deathsquad" - inhand_icon_state = "deathsquad" - hardsuit_type = "syndi" - armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 60, BOMB = 100, BIO = 100, FIRE = 100, ACID = 100, WOUND = 30) - strip_delay = 130 - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - actions_types = list() - -#undef HARDSUIT_EMP_BURN diff --git a/code/modules/clothing/spacesuits/plasmamen.dm b/code/modules/clothing/spacesuits/plasmamen.dm index f49724e4ff3..1b17c81d805 100644 --- a/code/modules/clothing/spacesuits/plasmamen.dm +++ b/code/modules/clothing/spacesuits/plasmamen.dm @@ -33,7 +33,7 @@ new /obj/effect/particle_effect/water(get_turf(H)) -//I just want the light feature of the hardsuit helmet +//I just want the light feature of helmets /obj/item/clothing/head/helmet/space/plasmaman name = "plasma envirosuit helmet" desc = "A special containment helmet that allows plasma-based lifeforms to exist safely in an oxygenated environment. It is space-worthy, and may be worn in tandem with other EVA gear." @@ -259,7 +259,7 @@ icon_state = "atmos_envirohelm" inhand_icon_state = "atmos_envirohelm" armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 100, ACID = 75) - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT // Same protection as the Atmospherics hardsuit Helmet + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT // Same protection as the Atmospherics Hardhat /obj/item/clothing/head/helmet/space/plasmaman/chief_engineer name = "chief engineer's plasma envirosuit helmet" @@ -267,7 +267,7 @@ icon_state = "ce_envirohelm" inhand_icon_state = "ce_envirohelm" armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 100, ACID = 75) - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT // Same protection as the CE's hardsuit Helmet + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT // Same protection as the Atmospherics Hardhat /obj/item/clothing/head/helmet/space/plasmaman/cargo diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index d2efd992502..f09b0f07f83 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -230,23 +230,6 @@ //All of the armor below is mostly unused -/obj/item/clothing/head/helmet/space/hardsuit/swat/centcom - name = "\improper CentCom SWAT helmet" - icon = 'icons/obj/clothing/hats.dmi' - worn_icon = 'icons/mob/clothing/head.dmi' - worn_icon_state = "centcomspace" - icon_state = "centcomspace" - inhand_icon_state = "centcomspacehelmet" - desc = "A tactical MK.II SWAT helmet boasting better protection and a reasonable fashion sense." - -/obj/item/clothing/suit/space/hardsuit/swat/centcom - name = "\improper CentCom SWAT armor" - desc = "A MK.II SWAT suit with streamlined joints and armor made out of superior materials, insulated against intense heat with the complementary gas mask. Usually given to station Captains, this one has been painted CC green with complimentary gold accents." - icon_state = "centcom" - inhand_icon_state = "centcomspacesuit" - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/swat/centcom - cell = /obj/item/stock_parts/cell/super - /obj/item/clothing/suit/armor/heavy name = "heavy armor" desc = "A heavily armored suit that protects against moderate damage." diff --git a/code/modules/clothing/suits/costume.dm b/code/modules/clothing/suits/costume.dm index 23d11381e7f..90d223f40a6 100644 --- a/code/modules/clothing/suits/costume.dm +++ b/code/modules/clothing/suits/costume.dm @@ -242,6 +242,47 @@ if (user.head == src) user.faction -= "carp" +/obj/item/clothing/suit/hooded/carp_costume/spaceproof + name = "carp space suit" + desc = "A slimming piece of dubious space carp technology, you suspect it won't stand up to hand-to-hand blows." + icon_state = "carp_suit" + inhand_icon_state = "space_suit_syndicate" + armor = list(MELEE = -20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 60, ACID = 75) //As whimpy whimpy whoo + allowed = list(/obj/item/tank/internals, /obj/item/gun/ballistic/rifle/boltaction/harpoon) //I'm giving you a hint here + flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT + cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT + heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT + clothing_flags = STOPSPRESSUREDAMAGE|THICKMATERIAL + body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + hoodtype = /obj/item/clothing/head/hooded/carp_hood/spaceproof + resistance_flags = NONE + +/obj/item/clothing/head/hooded/carp_hood/spaceproof + name = "carp helmet" + desc = "Spaceworthy and it looks like a space carp's head, smells like one too." + icon_state = "carp_helm" + armor = list(MELEE = -20, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 60, ACID = 75) //As whimpy as a space carp + flags_inv = HIDEEARS|HIDEHAIR|HIDEFACIALHAIR //facial hair will clip with the helm, this'll need a dynamic_fhair_suffix at some point. + min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT + heat_protection = HEAD + max_heat_protection_temperature = SPACE_HELM_MAX_TEMP_PROTECT + clothing_flags = STOPSPRESSUREDAMAGE|THICKMATERIAL|SNUG_FIT|PLASMAMAN_HELMET_EXEMPT + body_parts_covered = HEAD + resistance_flags = NONE + flash_protect = FLASH_PROTECTION_WELDER + flags_cover = HEADCOVERSEYES|HEADCOVERSMOUTH|PEPPERPROOF + +/obj/item/clothing/head/hooded/carp_hood/spaceproof/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_NODROP, LOCKED_HELMET_TRAIT) + +/obj/item/clothing/suit/hooded/carp_costume/spaceproof/old + name = "battered carp space suit" + desc = "It's covered in bite marks and scratches, yet seems to be still perfectly functional." + slowdown = 1 + /obj/item/clothing/suit/hooded/ian_costume //It's Ian, rub his bell- oh god what happened to his inside parts? name = "corgi costume" desc = "A costume that looks like someone made a human-like corgi, it won't guarantee belly rubs." diff --git a/code/modules/clothing/suits/toggles.dm b/code/modules/clothing/suits/toggles.dm index cd318eaa238..c684738c6a9 100644 --- a/code/modules/clothing/suits/toggles.dm +++ b/code/modules/clothing/suits/toggles.dm @@ -114,83 +114,3 @@ /obj/item/clothing/suit/toggle/Initialize(mapload) . = ..() AddComponent(/datum/component/toggle_icon, toggle_noun) - -//Hardsuit toggle code -/obj/item/clothing/suit/space/hardsuit/Initialize(mapload) - MakeHelmet() - . = ..() - -/obj/item/clothing/suit/space/hardsuit/Destroy() - if(!QDELETED(helmet)) - helmet.suit = null - qdel(helmet) - helmet = null - if (isatom(jetpack)) - QDEL_NULL(jetpack) - return ..() - -/obj/item/clothing/head/helmet/space/hardsuit/Destroy() - if(suit) - suit.helmet = null - return ..() - -/obj/item/clothing/suit/space/hardsuit/proc/MakeHelmet() - if(!helmettype) - return - if(!helmet) - var/obj/item/clothing/head/helmet/space/hardsuit/W = new helmettype(src) - W.suit = src - helmet = W - -/obj/item/clothing/suit/space/hardsuit/ui_action_click() - ..() - ToggleHelmet() - -/obj/item/clothing/suit/space/hardsuit/equipped(mob/user, slot) - if(!helmettype) - return - if(slot != ITEM_SLOT_OCLOTHING) - RemoveHelmet() - ..() - -/obj/item/clothing/suit/space/hardsuit/proc/RemoveHelmet() - if(!helmet) - return - helmet_on = FALSE - if(ishuman(helmet.loc)) - var/mob/living/carbon/H = helmet.loc - if(helmet.on) - helmet.attack_self(H) - H.transferItemToLoc(helmet, src, TRUE) - H.update_inv_wear_suit() - to_chat(H, span_notice("The helmet on the hardsuit disengages.")) - playsound(src.loc, 'sound/mecha/mechmove03.ogg', 50, TRUE) - else - helmet.forceMove(src) - -/obj/item/clothing/suit/space/hardsuit/dropped() - ..() - RemoveHelmet() - -/obj/item/clothing/suit/space/hardsuit/proc/ToggleHelmet() - var/mob/living/carbon/human/H = src.loc - if(!helmettype) - return - if(!helmet) - to_chat(H, span_warning("The helmet's lightbulb seems to be damaged! You'll need a replacement bulb.")) - return - if(!helmet_on) - if(ishuman(src.loc)) - if(H.wear_suit != src) - to_chat(H, span_warning("You must be wearing [src] to engage the helmet!")) - return - if(H.head) - to_chat(H, span_warning("You're already wearing something on your head!")) - return - else if(H.equip_to_slot_if_possible(helmet,ITEM_SLOT_HEAD,0,0,1)) - to_chat(H, span_notice("You engage the helmet on the hardsuit.")) - helmet_on = TRUE - H.update_inv_wear_suit() - playsound(src.loc, 'sound/mecha/mechmove03.ogg', 50, TRUE) - else - RemoveHelmet() diff --git a/code/modules/clothing/suits/wiz_robe.dm b/code/modules/clothing/suits/wiz_robe.dm index 48cf0cc0fb5..d1dd9720a40 100644 --- a/code/modules/clothing/suits/wiz_robe.dm +++ b/code/modules/clothing/suits/wiz_robe.dm @@ -171,43 +171,9 @@ robe_charge = TRUE to_chat(usr, span_notice("The robe hums, its internal magic supply restored.")) - -//Shielded Armour - -/obj/item/clothing/suit/space/hardsuit/shielded/wizard - name = "battlemage armour" - desc = "Not all wizards are afraid of getting up close and personal." - icon_state = "battlemage" - inhand_icon_state = "battlemage" - min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT - max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard - armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 30, BOMB = 20, BIO = 20, FIRE = 100, ACID = 100) - slowdown = 0 - resistance_flags = FIRE_PROOF | ACID_PROOF - -/obj/item/clothing/suit/space/hardsuit/shielded/wizard/setup_shielding() - AddComponent(/datum/component/shielded, max_charges = 15, recharge_start_delay = 0 SECONDS, charge_increment_delay = 1 SECONDS, charge_recovery = 1, lose_multiple_charges = FALSE, shield_icon = "shield-red") - -/obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard - name = "battlemage helmet" - desc = "A suitably impressive helmet." - icon_state = "battlemage" - inhand_icon_state = "battlemage" - min_cold_protection_temperature = ARMOR_MIN_TEMP_PROTECT - max_heat_protection_temperature = ARMOR_MAX_TEMP_PROTECT - armor = list(MELEE = 30, BULLET = 20, LASER = 20, ENERGY = 30, BOMB = 20, BIO = 20, FIRE = 100, ACID = 100) - actions_types = null //No inbuilt light - resistance_flags = FIRE_PROOF | ACID_PROOF - -/obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard/attack_self(mob/user) - return - // The actual code for this is handled in the shielded component, see [/datum/component/shielded/proc/check_recharge_rune] /obj/item/wizard_armour_charge name = "battlemage shield charges" desc = "A powerful rune that will increase the number of hits a suit of battlemage armour can take before failing.." icon = 'icons/effects/effects.dmi' icon_state = "electricity2" - /// How many charges get restored - var/restored_charges = 8 diff --git a/code/modules/food_and_drinks/kitchen_machinery/griddle.dm b/code/modules/food_and_drinks/kitchen_machinery/griddle.dm index 44b096a2d3c..32375d92e8a 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/griddle.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/griddle.dm @@ -128,7 +128,7 @@ return TRUE ///Override to prevent storage dumping onto the griddle until I figure out how to navigate the mess that is storage code to allow me to nicely move the dumped objects onto the griddle. -/obj/machinery/griddle/get_dumping_location(obj/item/storage/source, mob/user) +/obj/machinery/griddle/get_dumping_location() return /obj/machinery/griddle/process(delta_time) diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 235dbc0fc71..b8533a6d160 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -258,21 +258,22 @@ var/pda_slot = ITEM_SLOT_BELT /datum/outfit/job/pre_equip(mob/living/carbon/human/H, visualsOnly = FALSE) - switch(H.backpack) - if(GBACKPACK) - back = /obj/item/storage/backpack //Grey backpack - if(GSATCHEL) - back = /obj/item/storage/backpack/satchel //Grey satchel - if(GDUFFELBAG) - back = /obj/item/storage/backpack/duffelbag //Grey Duffel bag - if(LSATCHEL) - back = /obj/item/storage/backpack/satchel/leather //Leather Satchel - if(DSATCHEL) - back = satchel //Department satchel - if(DDUFFELBAG) - back = duffelbag //Department duffel bag - else - back = backpack //Department backpack + if(ispath(back, /obj/item/storage/backpack)) + switch(H.backpack) + if(GBACKPACK) + back = /obj/item/storage/backpack //Grey backpack + if(GSATCHEL) + back = /obj/item/storage/backpack/satchel //Grey satchel + if(GDUFFELBAG) + back = /obj/item/storage/backpack/duffelbag //Grey Duffel bag + if(LSATCHEL) + back = /obj/item/storage/backpack/satchel/leather //Leather Satchel + if(DSATCHEL) + back = satchel //Department satchel + if(DDUFFELBAG) + back = duffelbag //Department duffel bag + else + back = backpack //Department backpack //converts the uniform string into the path we'll wear, whether it's the skirt or regular variant var/holder diff --git a/code/modules/jobs/job_types/atmospheric_technician.dm b/code/modules/jobs/job_types/atmospheric_technician.dm index 42b167e1b56..81693357262 100644 --- a/code/modules/jobs/job_types/atmospheric_technician.dm +++ b/code/modules/jobs/job_types/atmospheric_technician.dm @@ -59,10 +59,10 @@ box = /obj/item/storage/box/survival/engineer pda_slot = ITEM_SLOT_LPOCKET -/datum/outfit/job/atmos/rig - name = "Atmospheric Technician (Hardsuit)" +/datum/outfit/job/atmos/mod + name = "Atmospheric Technician (MODsuit)" - suit = /obj/item/clothing/suit/space/hardsuit/atmos suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/atmospheric mask = /obj/item/clothing/mask/gas/atmos internals_slot = ITEM_SLOT_SUITSTORE diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index 4fae7c9756b..1aadb1e8205 100755 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -104,9 +104,11 @@ return celestial_charter.name_type = special_charter -/datum/outfit/job/captain/hardsuit - name = "Captain (Hardsuit)" +/datum/outfit/job/captain/mod + name = "Captain (MODsuit)" - suit = /obj/item/clothing/suit/space/hardsuit/swat/captain suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/magnate + suit = null + head = null mask = /obj/item/clothing/mask/gas/atmos/captain diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm index 776004c0e41..b0770527209 100644 --- a/code/modules/jobs/job_types/chief_engineer.dm +++ b/code/modules/jobs/job_types/chief_engineer.dm @@ -79,15 +79,14 @@ skillchips = list(/obj/item/skillchip/job/engineer) pda_slot = ITEM_SLOT_LPOCKET -/datum/outfit/job/ce/rig - name = "Chief Engineer (Hardsuit)" +/datum/outfit/job/ce/mod + name = "Chief Engineer (MODsuit)" - suit = /obj/item/clothing/suit/space/hardsuit/engine/elite suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/advanced glasses = /obj/item/clothing/glasses/meson/engine gloves = /obj/item/clothing/gloves/color/yellow head = null mask = /obj/item/clothing/mask/breath shoes = /obj/item/clothing/shoes/magboots/advance - internals_slot = ITEM_SLOT_SUITSTORE diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm index 6fb21354df7..191afcee0b2 100644 --- a/code/modules/jobs/job_types/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -79,10 +79,12 @@ ) skillchips = list(/obj/item/skillchip/entrails_reader) -/datum/outfit/job/cmo/hardsuit - name = "Chief Medical Officer (Hardsuit)" +/datum/outfit/job/cmo/mod + name = "Chief Medical Officer (MODsuit)" - suit = /obj/item/clothing/suit/space/hardsuit/medical suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/rescue + suit = null mask = /obj/item/clothing/mask/breath/medical r_pocket = /obj/item/flashlight/pen/paramedic + internals_slot = ITEM_SLOT_SUITSTORE diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm index e459e831264..74e1eee38af 100644 --- a/code/modules/jobs/job_types/head_of_security.dm +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -77,9 +77,11 @@ ) implants = list(/obj/item/implant/mindshield) -/datum/outfit/job/hos/hardsuit - name = "Head of Security (Hardsuit)" +/datum/outfit/job/hos/mod + name = "Head of Security (MODsuit)" - suit = /obj/item/clothing/suit/space/hardsuit/security/hos suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/safeguard + suit = null + head = null mask = /obj/item/clothing/mask/gas/sechailer diff --git a/code/modules/jobs/job_types/medical_doctor.dm b/code/modules/jobs/job_types/medical_doctor.dm index a54bdd5fcf0..6b59fed04c7 100644 --- a/code/modules/jobs/job_types/medical_doctor.dm +++ b/code/modules/jobs/job_types/medical_doctor.dm @@ -59,3 +59,13 @@ box = /obj/item/storage/box/survival/medical chameleon_extras = /obj/item/gun/syringe skillchips = list(/obj/item/skillchip/entrails_reader) + +/datum/outfit/job/doctor/mod + name = "Medical Doctor (MODsuit)" + + suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/medical + suit = null + mask = /obj/item/clothing/mask/breath/medical + r_pocket = /obj/item/flashlight/pen + internals_slot = ITEM_SLOT_SUITSTORE diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm index c1c89f4891b..0013f3e3906 100644 --- a/code/modules/jobs/job_types/research_director.dm +++ b/code/modules/jobs/job_types/research_director.dm @@ -75,11 +75,12 @@ chameleon_extras = /obj/item/stamp/rd skillchips = list(/obj/item/skillchip/job/research_director) -/datum/outfit/job/rd/rig - name = "Research Director (Hardsuit)" +/datum/outfit/job/rd/mod + name = "Research Director (MODsuit)" - suit = /obj/item/clothing/suit/space/hardsuit/rd suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/research + suit = null mask = /obj/item/clothing/mask/breath l_hand = null internals_slot = ITEM_SLOT_SUITSTORE diff --git a/code/modules/jobs/job_types/roboticist.dm b/code/modules/jobs/job_types/roboticist.dm index 2c712b103ed..b1dcf025d1d 100644 --- a/code/modules/jobs/job_types/roboticist.dm +++ b/code/modules/jobs/job_types/roboticist.dm @@ -58,3 +58,11 @@ pda_slot = ITEM_SLOT_LPOCKET skillchips = list(/obj/item/skillchip/job/roboticist) + +/datum/outfit/job/roboticist/mod + name = "Roboticist (MODsuit)" + suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/standard + suit = null + mask = /obj/item/clothing/mask/breath + internals_slot = ITEM_SLOT_SUITSTORE diff --git a/code/modules/jobs/job_types/shaft_miner.dm b/code/modules/jobs/job_types/shaft_miner.dm index 45d1809e811..0ddf62e9d9e 100644 --- a/code/modules/jobs/job_types/shaft_miner.dm +++ b/code/modules/jobs/job_types/shaft_miner.dm @@ -78,7 +78,8 @@ var/obj/item/clothing/suit/hooded/S = H.wear_suit S.ToggleHood() -/datum/outfit/job/miner/equipped/hardsuit - name = "Shaft Miner (Equipment + Hardsuit)" - suit = /obj/item/clothing/suit/space/hardsuit/mining +/datum/outfit/job/miner/equipped/mod + name = "Shaft Miner (Equipment + MODsuit)" + back = /obj/item/mod/control/pre_equipped/mining + suit = null mask = /obj/item/clothing/mask/breath diff --git a/code/modules/jobs/job_types/station_engineer.dm b/code/modules/jobs/job_types/station_engineer.dm index ba44eac06a0..868e6c4f9e4 100644 --- a/code/modules/jobs/job_types/station_engineer.dm +++ b/code/modules/jobs/job_types/station_engineer.dm @@ -67,17 +67,11 @@ gloves = /obj/item/clothing/gloves/color/yellow -/datum/outfit/job/engineer/gloved/rig - name = "Station Engineer (Hardsuit)" +/datum/outfit/job/engineer/mod + name = "Station Engineer (MODsuit)" - suit = /obj/item/clothing/suit/space/hardsuit/engine suit_store = /obj/item/tank/internals/oxygen + back = /obj/item/mod/control/pre_equipped/engineering head = null mask = /obj/item/clothing/mask/breath internals_slot = ITEM_SLOT_SUITSTORE - -/datum/outfit/job/engineer/gloved/gunner - id_trim = /datum/id_trim/job/station_engineer/gunner - -/datum/outfit/job/engineer/gloved/rig/gunner - id_trim = /datum/id_trim/job/station_engineer/gunner diff --git a/code/modules/mining/lavaland/megafauna_loot.dm b/code/modules/mining/lavaland/megafauna_loot.dm index 8034abe8ca6..03ef28533e2 100644 --- a/code/modules/mining/lavaland/megafauna_loot.dm +++ b/code/modules/mining/lavaland/megafauna_loot.dm @@ -260,23 +260,26 @@ user.log_message("activated a bottle of mayhem", LOG_ATTACK) qdel(src) -/obj/item/clothing/suit/space/hardsuit/hostile_environment +/obj/item/clothing/suit/hooded/hostile_environment name = "H.E.C.K. suit" desc = "Hostile Environment Cross-Kinetic Suit: A suit designed to withstand the wide variety of hazards from Lavaland. It wasn't enough for its last owner." icon_state = "hostile_env" - inhand_icon_state = "hostile_env" - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT - resistance_flags = FIRE_PROOF | LAVA_PROOF | ACID_PROOF - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/hostile_environment - slowdown = 0 + hoodtype = /obj/item/clothing/head/hooded/hostile_environment armor = list(MELEE = 70, BULLET = 40, LASER = 10, ENERGY = 20, BOMB = 50, BIO = 100, FIRE = 100, ACID = 100) + cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT + heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + clothing_flags = THICKMATERIAL + resistance_flags = FIRE_PROOF|LAVA_PROOF|ACID_PROOF allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/resonator, /obj/item/mining_scanner, /obj/item/t_scanner/adv_mining_scanner, /obj/item/gun/energy/kinetic_accelerator, /obj/item/pickaxe) -/obj/item/clothing/suit/space/hardsuit/hostile_environment/Initialize(mapload) +/obj/item/clothing/suit/hooded/hostile_environment/Initialize(mapload) . = ..() AddElement(/datum/element/radiation_protected_clothing) -/obj/item/clothing/suit/space/hardsuit/hostile_environment/process(delta_time) +/obj/item/clothing/suit/hooded/hostile_environment/process(delta_time) . = ..() var/mob/living/carbon/wearer = loc if(istype(wearer) && DT_PROB(1, delta_time)) //cursed by bubblegum @@ -286,45 +289,47 @@ else to_chat(wearer, span_warning("[pick("You hear faint whispers.","You smell ash.","You feel hot.","You hear a roar in the distance.")]")) -/obj/item/clothing/head/helmet/space/hardsuit/hostile_environment +/obj/item/clothing/head/hooded/hostile_environment name = "H.E.C.K. helmet" desc = "Hostile Environiment Cross-Kinetic Helmet: A helmet designed to withstand the wide variety of hazards from Lavaland. It wasn't enough for its last owner." - icon_state = "hardsuit0-heck" - inhand_icon_state = "hostile_env" - hardsuit_type = "heck" + icon_state = "hostile_env" w_class = WEIGHT_CLASS_NORMAL - max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT armor = list(MELEE = 70, BULLET = 40, LASER = 10, ENERGY = 20, BOMB = 50, BIO = 100, FIRE = 100, ACID = 100) - resistance_flags = FIRE_PROOF | LAVA_PROOF | ACID_PROOF + cold_protection = HEAD + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT + heat_protection = HEAD + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + clothing_flags = SNUG_FIT|THICKMATERIAL + resistance_flags = FIRE_PROOF|LAVA_PROOF|ACID_PROOF actions_types = list() -/obj/item/clothing/head/helmet/space/hardsuit/hostile_environment/Initialize(mapload) +/obj/item/clothing/head/hooded/hostile_environment/Initialize(mapload) . = ..() update_appearance() AddComponent(/datum/component/butchering, 5, 150, null, null, null, TRUE, CALLBACK(src, .proc/consume)) AddElement(/datum/element/radiation_protected_clothing) -/obj/item/clothing/head/helmet/space/hardsuit/hostile_environment/equipped(mob/user, slot, initial = FALSE) +/obj/item/clothing/head/hooded/hostile_environment/equipped(mob/user, slot, initial = FALSE) . = ..() RegisterSignal(user, COMSIG_HUMAN_EARLY_UNARMED_ATTACK, .proc/butcher_target) var/datum/component/butchering/butchering = GetComponent(/datum/component/butchering) butchering.butchering_enabled = TRUE to_chat(user, span_notice("You feel a bloodlust. You can now butcher corpses with your bare arms.")) -/obj/item/clothing/head/helmet/space/hardsuit/hostile_environment/dropped(mob/user, silent = FALSE) +/obj/item/clothing/head/hooded/hostile_environment/dropped(mob/user, silent = FALSE) . = ..() UnregisterSignal(user, COMSIG_HUMAN_EARLY_UNARMED_ATTACK) var/datum/component/butchering/butchering = GetComponent(/datum/component/butchering) butchering.butchering_enabled = FALSE to_chat(user, span_notice("You lose your bloodlust.")) -/obj/item/clothing/head/helmet/space/hardsuit/hostile_environment/proc/butcher_target(mob/user, atom/target, proximity) +/obj/item/clothing/head/hooded/hostile_environment/proc/butcher_target(mob/user, atom/target, proximity) SIGNAL_HANDLER if(!isliving(target)) return return SEND_SIGNAL(src, COMSIG_ITEM_ATTACK, target, user) -/obj/item/clothing/head/helmet/space/hardsuit/hostile_environment/proc/consume(mob/living/user, mob/living/butchered) +/obj/item/clothing/head/hooded/hostile_environment/proc/consume(mob/living/user, mob/living/butchered) if(butchered.mob_biotypes & (MOB_ROBOTIC | MOB_SPIRIT)) return var/health_consumed = butchered.maxHealth * 0.1 @@ -333,13 +338,13 @@ var/datum/client_colour/color = user.add_client_colour(/datum/client_colour/bloodlust) QDEL_IN(color, 1 SECONDS) -/obj/item/clothing/head/helmet/space/hardsuit/hostile_environment/update_overlays() +/obj/item/clothing/head/hooded/hostile_environment/update_overlays() . = ..() var/mutable_appearance/glass_overlay = mutable_appearance(icon, "hostile_env_glass") glass_overlay.appearance_flags = RESET_COLOR . += glass_overlay -/obj/item/clothing/head/helmet/space/hardsuit/hostile_environment/worn_overlays(mutable_appearance/standing, isinhands) +/obj/item/clothing/head/hooded/hostile_environment/worn_overlays(mutable_appearance/standing, isinhands) . = ..() if(!isinhands) var/mutable_appearance/glass_overlay = mutable_appearance('icons/mob/clothing/head.dmi', "hostile_env_glass") diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index a8821eeb89d..556d8267b85 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -54,7 +54,7 @@ if(10) new /obj/item/ship_in_a_bottle(src) if(11) - new /obj/item/clothing/suit/space/hardsuit/berserker(src) + new /obj/item/clothing/suit/hooded/berserker(src) if(12) new /obj/item/jacobs_ladder(src) if(13) @@ -112,7 +112,7 @@ name = "bubblegum chest" /obj/structure/closet/crate/necropolis/bubblegum/PopulateContents() - new /obj/item/clothing/suit/space/hardsuit/hostile_environment(src) + new /obj/item/clothing/suit/hooded/hostile_environment(src) var/loot = rand(1,2) switch(loot) if(1) diff --git a/code/modules/mining/lavaland/tendril_loot.dm b/code/modules/mining/lavaland/tendril_loot.dm index 4a4e258661e..ccc5be638fd 100644 --- a/code/modules/mining/lavaland/tendril_loot.dm +++ b/code/modules/mining/lavaland/tendril_loot.dm @@ -581,29 +581,25 @@ A.attackby(src, H) return COMPONENT_CANCEL_ATTACK_CHAIN -/obj/item/clothing/suit/space/hardsuit/berserker - name = "berserker hardsuit" - desc = "Voices echo from the hardsuit, driving the user insane." - icon_state = "hardsuit-berserker" - inhand_icon_state = "hardsuit-berserker" - slowdown = 0 - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/berserker +/obj/item/clothing/suit/hooded/berserker + name = "berserker armor" + desc = "Voices echo from the armor, driving the user insane. Is not space-proof." + icon_state = "berserker" + hoodtype = /obj/item/clothing/head/hooded/berserker armor = list(MELEE = 30, BULLET = 30, LASER = 10, ENERGY = 20, BOMB = 50, BIO = 100, FIRE = 100, ACID = 100) + cold_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT + heat_protection = CHEST|GROIN|LEGS|FEET|ARMS|HANDS max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + body_parts_covered = CHEST|GROIN|LEGS|FEET|ARMS|HANDS resistance_flags = FIRE_PROOF + clothing_flags = THICKMATERIAL allowed = list(/obj/item/flashlight, /obj/item/tank/internals, /obj/item/pickaxe, /obj/item/spear, /obj/item/organ/regenerative_core/legion, /obj/item/knife, /obj/item/kinetic_crusher, /obj/item/resonator, /obj/item/melee/cleaving_saw) - -/obj/item/clothing/suit/space/hardsuit/berserker/Initialize(mapload) +/obj/item/clothing/suit/hooded/berserker/Initialize(mapload) . = ..() AddComponent(/datum/component/anti_magic, TRUE, TRUE, TRUE, ITEM_SLOT_OCLOTHING) -/obj/item/clothing/suit/space/hardsuit/berserker/RemoveHelmet() - var/obj/item/clothing/head/helmet/space/hardsuit/berserker/helm = helmet - if(helm?.berserk_active) - return - return ..() - #define MAX_BERSERK_CHARGE 100 #define PROJECTILE_HIT_MULTIPLIER 1.5 #define DAMAGE_TO_CHARGE_SCALE 0.75 @@ -611,30 +607,32 @@ #define BERSERK_MELEE_ARMOR_ADDED 50 #define BERSERK_ATTACK_SPEED_MODIFIER 0.25 -/obj/item/clothing/head/helmet/space/hardsuit/berserker +/obj/item/clothing/head/hooded/berserker name = "berserker helmet" desc = "Peering into the eyes of the helmet is enough to seal damnation." - icon_state = "hardsuit0-berserker" - inhand_icon_state = "hardsuit0-berserker" - hardsuit_type = "berserker" + icon_state = "berserker" armor = list(MELEE = 30, BULLET = 30, LASER = 10, ENERGY = 20, BOMB = 50, BIO = 100, FIRE = 100, ACID = 100) actions_types = list(/datum/action/item_action/berserk_mode) + cold_protection = HEAD + min_cold_protection_temperature = FIRE_SUIT_MIN_TEMP_PROTECT + heat_protection = HEAD max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT resistance_flags = FIRE_PROOF + clothing_flags = SNUG_FIT|THICKMATERIAL /// Current charge of berserk, goes from 0 to 100 var/berserk_charge = 0 /// Status of berserk var/berserk_active = FALSE -/obj/item/clothing/head/helmet/space/hardsuit/berserker/Initialize(mapload) +/obj/item/clothing/head/hooded/berserker/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_NODROP, LOCKED_HELMET_TRAIT) -/obj/item/clothing/head/helmet/space/hardsuit/berserker/examine() +/obj/item/clothing/head/hooded/berserker/examine() . = ..() . += span_notice("Berserk mode is [berserk_charge]% charged.") -/obj/item/clothing/head/helmet/space/hardsuit/berserker/process(delta_time) +/obj/item/clothing/head/hooded/berserker/process(delta_time) . = ..() if(berserk_active) berserk_charge = clamp(berserk_charge - CHARGE_DRAINED_PER_SECOND * delta_time, 0, MAX_BERSERK_CHARGE) @@ -642,11 +640,11 @@ if(ishuman(loc)) end_berserk(loc) -/obj/item/clothing/head/helmet/space/hardsuit/berserker/dropped(mob/user) +/obj/item/clothing/head/hooded/berserker/dropped(mob/user) . = ..() end_berserk(user) -/obj/item/clothing/head/helmet/space/hardsuit/berserker/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) +/obj/item/clothing/head/hooded/berserker/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) if(berserk_active) return var/berserk_value = damage * DAMAGE_TO_CHARGE_SCALE @@ -657,12 +655,12 @@ to_chat(owner, span_notice("Berserk mode is fully charged.")) balloon_alert(owner, "berserk charged") -/obj/item/clothing/head/helmet/space/hardsuit/berserker/IsReflect() +/obj/item/clothing/head/hooded/berserker/IsReflect() if(berserk_active) return TRUE /// Starts berserk, giving the wearer 50 melee armor, doubled attacking speed, NOGUNS trait, adding a color and giving them the berserk movespeed modifier -/obj/item/clothing/head/helmet/space/hardsuit/berserker/proc/berserk_mode(mob/living/carbon/human/user) +/obj/item/clothing/head/hooded/berserker/proc/berserk_mode(mob/living/carbon/human/user) to_chat(user, span_warning("You enter berserk mode.")) playsound(user, 'sound/magic/staff_healing.ogg', 50) user.add_movespeed_modifier(/datum/movespeed_modifier/berserk) @@ -672,11 +670,15 @@ ADD_TRAIT(user, TRAIT_NOGUNS, BERSERK_TRAIT) ADD_TRAIT(src, TRAIT_NODROP, BERSERK_TRAIT) berserk_active = TRUE + START_PROCESSING(SSobj, src) /// Ends berserk, reverting the changes from the proc [berserk_mode] -/obj/item/clothing/head/helmet/space/hardsuit/berserker/proc/end_berserk(mob/living/carbon/human/user) +/obj/item/clothing/head/hooded/berserker/proc/end_berserk(mob/living/carbon/human/user) if(!berserk_active) return + berserk_active = FALSE + if(QDELETED(user)) + return to_chat(user, span_warning("You exit berserk mode.")) playsound(user, 'sound/magic/summonitems_generic.ogg', 50) user.remove_movespeed_modifier(/datum/movespeed_modifier/berserk) @@ -685,7 +687,7 @@ user.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, COLOR_BUBBLEGUM_RED) REMOVE_TRAIT(user, TRAIT_NOGUNS, BERSERK_TRAIT) REMOVE_TRAIT(src, TRAIT_NODROP, BERSERK_TRAIT) - berserk_active = FALSE + STOP_PROCESSING(SSobj, src) #undef MAX_BERSERK_CHARGE #undef PROJECTILE_HIT_MULTIPLIER diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm index f1a57e08bd8..183a743fb28 100644 --- a/code/modules/mining/machine_vending.dm +++ b/code/modules/mining/machine_vending.dm @@ -28,6 +28,7 @@ new /datum/data/mining_equipment("Explorer's Webbing", /obj/item/storage/belt/mining, 500), new /datum/data/mining_equipment("Point Transfer Card", /obj/item/card/mining_point_card, 500), new /datum/data/mining_equipment("Survival Medipen", /obj/item/reagent_containers/hypospray/medipen/survival, 500), + new /datum/data/mining_equipment("Mining Plates", /obj/item/mod/construction/armor/mining, 500), new /datum/data/mining_equipment("Brute First-Aid Kit", /obj/item/storage/firstaid/brute, 600), new /datum/data/mining_equipment("Tracking Implant Kit", /obj/item/storage/box/minertracker, 600), new /datum/data/mining_equipment("Jaunter", /obj/item/wormhole_jaunter, 750), @@ -40,9 +41,7 @@ new /datum/data/mining_equipment("Lazarus Injector", /obj/item/lazarus_injector, 1000), new /datum/data/mining_equipment("Silver Pickaxe", /obj/item/pickaxe/silver, 1000), new /datum/data/mining_equipment("Mining Conscription Kit", /obj/item/storage/backpack/duffelbag/mining_conscript, 1500), - new /datum/data/mining_equipment("Jetpack Upgrade", /obj/item/tank/jetpack/suit, 2000), new /datum/data/mining_equipment("Space Cash", /obj/item/stack/spacecash/c1000, 2000), - new /datum/data/mining_equipment("Mining Hardsuit", /obj/item/clothing/suit/space/hardsuit/mining, 2000), new /datum/data/mining_equipment("Diamond Pickaxe", /obj/item/pickaxe/diamond, 2000), new /datum/data/mining_equipment("Super Resonator", /obj/item/resonator/upgraded, 2500), new /datum/data/mining_equipment("Jump Boots", /obj/item/clothing/shoes/bhop, 2500), diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 888b5329b4e..46bed10c732 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -583,12 +583,20 @@ if(!isnull(G.lighting_alpha)) lighting_alpha = min(lighting_alpha, G.lighting_alpha) + if(HAS_TRAIT(src, TRAIT_TRUE_NIGHT_VISION)) + lighting_alpha = min(lighting_alpha, LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE) + see_in_dark = max(see_in_dark, 8) + + if(HAS_TRAIT(src, TRAIT_MESON_VISION)) + sight |= SEE_TURFS + lighting_alpha = min(lighting_alpha, LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE) + if(HAS_TRAIT(src, TRAIT_THERMAL_VISION)) - sight |= (SEE_MOBS) + sight |= SEE_MOBS lighting_alpha = min(lighting_alpha, LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE) if(HAS_TRAIT(src, TRAIT_XRAY_VISION)) - sight |= (SEE_TURFS|SEE_MOBS|SEE_OBJS) + sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS see_in_dark = max(see_in_dark, 8) if(see_override) diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm index 64f1e97f855..419c203b60c 100644 --- a/code/modules/mob/living/carbon/carbon_movement.dm +++ b/code/modules/mob/living/carbon/carbon_movement.dm @@ -6,22 +6,6 @@ ..() return loc.handle_slip(src, knockdown_amount, O, lube, paralyze, force_drop) -/mob/living/carbon/Process_Spacemove(movement_dir = 0) - if(!isturf(loc)) - return FALSE - - // Do we have a jetpack implant (and is it on)? - var/obj/item/organ/cyberimp/chest/thrusters/T = getorganslot(ORGAN_SLOT_THRUSTERS) - if(istype(T) && movement_dir && T.on) - return TRUE - - var/obj/item/tank/jetpack/J = get_jetpack() - if(istype(J) && (movement_dir || J.stabilizers) && J.on) - return TRUE - - if(..()) - return TRUE - /mob/living/carbon/Move(NewLoc, direct) . = ..() if(. && !(movement_type & FLOATING)) //floating is easy diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index d73c40b342b..7d26e1384ee 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -51,7 +51,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) ///Travel to the bottom of the contents chain, expanding it out for(var/i = 1; i <= length(items_to_check); i++) //Needs to be a c style loop since it can expand var/obj/item/checking = items_to_check[i] - if(!checking) //Nulls in the list, depressing + if(QDELETED(checking)) //Nulls in the list, depressing continue if(!isitem(checking)) //What the fuck are you on to_nuke += checking diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 4fecdd7f4b3..4fd3ef2f344 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -444,7 +444,7 @@ threatcount += 2 //Check for dresscode violations - if(istype(head, /obj/item/clothing/head/wizard) || istype(head, /obj/item/clothing/head/helmet/space/hardsuit/wizard)) + if(istype(head, /obj/item/clothing/head/wizard)) threatcount += 2 //Check for nonhuman scum diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 68c3ea5868d..8e1fa3a5155 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -137,6 +137,8 @@ var/final_block_chance = head.block_chance - (clamp((armour_penetration-head.armour_penetration)/2,0,100)) + block_chance_modifier if(head.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type)) return TRUE + if(SEND_SIGNAL(src, COMSIG_HUMAN_CHECK_SHIELDS, AM, damage, attack_text, attack_type, armour_penetration) & SHIELD_BLOCK) + return TRUE return FALSE /mob/living/carbon/human/proc/check_block() diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index ef3ecc9c666..6a37aa34634 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -111,17 +111,6 @@ . = ..() . += "[dna.species.type]" -/mob/living/carbon/human/can_see_reagents() - . = ..() - if(.) //No need to run through all of this if it's already true. - return - if(isclothing(glasses) && (glasses.clothing_flags & SCAN_REAGENTS)) - return TRUE - if(isclothing(head) && (head.clothing_flags & SCAN_REAGENTS)) - return TRUE - if(isclothing(wear_mask) && (wear_mask.clothing_flags & SCAN_REAGENTS)) - return TRUE - /// When we're joining the game in [/mob/dead/new_player/proc/create_character], we increment our scar slot then store the slot in our mind datum. /mob/living/carbon/human/proc/increment_scar_slot() var/check_ckey = ckey || client?.ckey diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 257f5d6cb33..d37a5a216f2 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -26,22 +26,8 @@ return FALSE return ..() -/mob/living/carbon/human/experience_pressure_difference() - playsound(src, 'sound/effects/space_wind.ogg', 50, TRUE) - if(shoes && istype(shoes, /obj/item/clothing)) - var/obj/item/clothing/S = shoes - if (S.clothing_flags & NOSLIP) - return 0 - return ..() - -/mob/living/carbon/human/mob_has_gravity() - . = ..() - if(!.) - if(mob_negates_gravity()) - . = 1 - /mob/living/carbon/human/mob_negates_gravity() - return ((shoes?.negates_gravity()) || (dna.species.negates_gravity(src))) + return dna.species.negates_gravity(src) || ..() /mob/living/carbon/human/Move(NewLoc, direct) . = ..() diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index 92c7214273c..eec9dff8ec0 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -321,7 +321,8 @@ if(equip_to_slot_if_possible(thing, slot_type)) update_inv_hands() return - if(!SEND_SIGNAL(equipped_item, COMSIG_CONTAINS_STORAGE)) // not a storage item + var/datum/component/storage/storage = equipped_item.GetComponent(/datum/component/storage) + if(!storage) if(!thing) equipped_item.attack_hand(src) else @@ -331,10 +332,11 @@ if(!SEND_SIGNAL(equipped_item, COMSIG_TRY_STORAGE_INSERT, thing, src)) to_chat(src, span_warning("You can't fit [thing] into your [equipped_item.name]!")) return - if(!equipped_item.contents.len) // nothing to take out + var/atom/real_location = storage.real_location() + if(!real_location.contents.len) // nothing to take out to_chat(src, span_warning("There's nothing in your [equipped_item.name] to take out!")) return - var/obj/item/stored = equipped_item.contents[equipped_item.contents.len] + var/obj/item/stored = real_location.contents[real_location.contents.len] if(!stored || stored.on_found(src)) return stored.attack_hand(src) // take out thing from item in storage slot diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 53950856192..d5b8fb27a55 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1089,7 +1089,7 @@ GLOBAL_LIST_EMPTY(features_by_species) if(ITEM_SLOT_FEET) if(H.num_legs < 2) return FALSE - if(DIGITIGRADE in species_traits) + if((DIGITIGRADE in species_traits) && !(I.item_flags & IGNORE_DIGITIGRADE)) if(!disable_warning) to_chat(H, span_warning("The footwear around here isn't compatible with your feet!")) return FALSE diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm index 9daefaae303..d0e5f9164af 100644 --- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm +++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm @@ -64,7 +64,7 @@ if(environment.gases[/datum/gas/hypernoblium] && (environment.gases[/datum/gas/hypernoblium][MOLES]) >= 5) if(H.on_fire && H.fire_stacks > 0) H.adjust_fire_stacks(-10 * delta_time) - else if(!HAS_TRAIT(H, TRAIT_NOFIRE)) + else if(!HAS_TRAIT(H, TRAIT_NOFIRE) && !HAS_TRAIT(H, TRAIT_NOSELFIGNITION)) if(environment.gases[/datum/gas/oxygen] && (environment.gases[/datum/gas/oxygen][MOLES]) >= 1) //Same threshhold that extinguishes fire H.adjust_fire_stacks(0.25 * delta_time) if(!H.on_fire && H.fire_stacks > 0) diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index 65637bb1a51..3f8447ade8c 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -182,7 +182,7 @@ return /mob/living/proc/handle_gravity(delta_time, times_fired) - var/gravity = mob_has_gravity() + var/gravity = has_gravity() update_gravity(gravity) if(gravity > STANDARD_GRAVITY) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 2fab908f62c..1132f45ea84 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -49,6 +49,8 @@ return ..() /mob/living/proc/ZImpactDamage(turf/T, levels) + if(SEND_SIGNAL(src, COMSIG_LIVING_Z_IMPACT, levels, T) & NO_Z_IMPACT_DAMAGE) + return visible_message(span_danger("[src] crashes into [T] with a sickening noise!"), \ span_userdanger("You crash into [T] with a sickening noise!")) adjustBruteLoss((levels * 5) ** 1.5) @@ -79,6 +81,7 @@ //Called when we bump onto a mob /mob/living/proc/MobBump(mob/M) + SEND_SIGNAL(src, COMSIG_LIVING_MOB_BUMP, M) //Even if we don't push/swap places, we "touched" them, so spread fire spreadFire(M) @@ -883,7 +886,8 @@ return pick("trails_1", "trails_2") /mob/living/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0) - if(buckled) + playsound(src, 'sound/effects/space_wind.ogg', 50, TRUE) + if(buckled || mob_negates_gravity()) return if(client && client.move_delay >= world.time + world.tick_lag*2) pressure_resistance_prob_delta -= 30 @@ -1289,13 +1293,6 @@ G.Recall() to_chat(G, span_holoparasite("Your summoner has changed form!")) -/mob/living/anti_magic_check(magic = TRUE, holy = FALSE, tinfoil = FALSE, chargecost = 1, self = FALSE) - . = ..() - if(.) - return - if((magic && HAS_TRAIT(src, TRAIT_ANTIMAGIC)) || (holy && HAS_TRAIT(src, TRAIT_HOLY))) - return src - /mob/living/proc/fakefireextinguish() return diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 560a1fc0565..207d0ef67ac 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -39,7 +39,7 @@ var/requires_power = POWER_REQ_ALL var/can_be_carded = TRUE var/icon/holo_icon //Default is assigned when AI is created. - var/obj/vehicle/sealed/mecha/controlled_mech //For controlled_mech a mech, to determine whether to relaymove or use the AI eye. + var/obj/controlled_equipment //A piece of equipment, to determine whether to relaymove or use the AI eye. var/radio_enabled = TRUE //Determins if a carded AI can speak with its built in radio or not. radiomod = ";" //AIs will, by default, state their laws on the internal radio. ///Used as a fake multitoool in tcomms machinery @@ -221,7 +221,7 @@ malfhack = null current = null Bot = null - controlled_mech = null + controlled_equipment = null linked_core = null apc_override = null return ..() @@ -452,7 +452,7 @@ log_game("Warning: possible href exploit by [key_name(usr)] - attempted control of a mecha without can_dominate_mechs or a control beacon in the mech.") return - if(controlled_mech) + if(controlled_equipment) to_chat(src, span_warning("You are already loaded into an onboard computer!")) return if(!GLOB.cameranet.checkCameraVis(M)) diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm index 78ff18cfb82..635042926b7 100644 --- a/code/modules/mob/living/silicon/ai/life.dm +++ b/code/modules/mob/living/silicon/ai/life.dm @@ -3,7 +3,7 @@ return //Being dead doesn't mean your temperature never changes - update_gravity(mob_has_gravity()) + update_gravity(has_gravity()) handle_status_effects(delta_time, times_fired) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index a69342e0d09..f217d953e06 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -718,7 +718,6 @@ hat_offset = model.hat_offset - magpulse = model.magpulsing INVOKE_ASYNC(src, .proc/updatename) diff --git a/code/modules/mob/living/silicon/robot/robot_defines.dm b/code/modules/mob/living/silicon/robot/robot_defines.dm index bf71a7e97c3..f8cee801b3d 100644 --- a/code/modules/mob/living/silicon/robot/robot_defines.dm +++ b/code/modules/mob/living/silicon/robot/robot_defines.dm @@ -105,8 +105,6 @@ ///So they can initialize sparks whenever/N var/datum/effect_system/spark_spread/spark_system - ///Magboot-like effect. - var/magpulse = FALSE ///Jetpack-like effect. var/ionpulse = FALSE ///Jetpack-like effect. @@ -209,7 +207,7 @@ playstyle_string = "You are a Syndicate medical cyborg!
\ You are armed with powerful medical tools to aid you in your mission: help the operatives secure the nuclear authentication disk. \ Your hypospray will produce Restorative Nanites, a wonder-drug that will heal most types of bodily damages, including clone and brain damage. It also produces morphine for offense. \ - Your defibrillator paddles can revive operatives through their hardsuits, or can be used on harm intent to shock enemies! \ + Your defibrillator paddles can revive operatives through their suits, or can be used on harm intent to shock enemies! \ Your energy saw functions as a circular saw, but can be activated to deal more damage, and your operative pinpointer will find and locate fellow nuclear operatives. \ Help the operatives secure the disk at all costs!" set_model = /obj/item/robot_model/syndicate_medical diff --git a/code/modules/mob/living/silicon/robot/robot_model.dm b/code/modules/mob/living/silicon/robot/robot_model.dm index 22e35e15822..60ff35bf0d3 100644 --- a/code/modules/mob/living/silicon/robot/robot_model.dm +++ b/code/modules/mob/living/silicon/robot/robot_model.dm @@ -37,8 +37,6 @@ var/list/model_traits = null ///List of radio channels added to the cyborg var/list/radio_channels = list() - ///Do we have a magboot effect - var/magpulsing = FALSE ///Do we clean when we move var/clean_on_move = FALSE ///Whether the borg loses tool slots with damage. @@ -330,7 +328,7 @@ emag_modules = list(/obj/item/borg/stun) cyborg_base_icon = "engineer" model_select_icon = "engineer" - magpulsing = TRUE + model_traits = list(TRAIT_NEGATES_GRAVITY) hat_offset = -4 /obj/item/robot_model/janitor @@ -631,8 +629,7 @@ cyborg_base_icon = "synd_engi" model_select_icon = "malf" - model_traits = list(TRAIT_PUSHIMMUNE) - magpulsing = TRUE + model_traits = list(TRAIT_PUSHIMMUNE, TRAIT_NEGATES_GRAVITY) hat_offset = -4 canDispose = TRUE diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm index 59f480110c5..9a417298cd0 100644 --- a/code/modules/mob/living/silicon/robot/robot_movement.dm +++ b/code/modules/mob/living/silicon/robot/robot_movement.dm @@ -5,13 +5,3 @@ if(ionpulse()) return TRUE return FALSE - -/mob/living/silicon/robot/mob_negates_gravity() - return magpulse - -/mob/living/silicon/robot/mob_has_gravity() - return ..() || mob_negates_gravity() - -/mob/living/silicon/robot/experience_pressure_difference(pressure_difference, direction) - if(!magpulse) - return ..() diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm index 371fb598590..964440f21dc 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm @@ -180,6 +180,7 @@ diag_hud.add_to_hud(src) ADD_TRAIT(src, TRAIT_VENTCRAWLER_ALWAYS, INNATE_TRAIT) + ADD_TRAIT(src, TRAIT_NEGATES_GRAVITY, INNATE_TRAIT) listener = new(list(ALARM_ATMOS, ALARM_FIRE, ALARM_POWER), list(z)) RegisterSignal(listener, COMSIG_ALARM_TRIGGERED, .proc/alarm_triggered) @@ -353,15 +354,6 @@ if(affect_silicon) return ..() -/mob/living/simple_animal/drone/mob_negates_gravity() - return TRUE - -/mob/living/simple_animal/drone/mob_has_gravity() - return ..() || mob_negates_gravity() - -/mob/living/simple_animal/drone/experience_pressure_difference(pressure_difference, direction) - return - /mob/living/simple_animal/drone/bee_friendly() // Why would bees pay attention to drones? return TRUE diff --git a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm index 06601d82694..9e8613161b1 100644 --- a/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm +++ b/code/modules/mob/living/simple_animal/friendly/drone/extra_drone_types.dm @@ -27,7 +27,7 @@ "2. Kill.\n"+\ "3. Destroy." default_storage = /obj/item/uplink - default_hatmask = /obj/item/clothing/head/helmet/space/hardsuit/syndi + default_hatmask = /obj/item/clothing/head/helmet/swat hacked = TRUE shy = FALSE flavortext = null @@ -39,7 +39,6 @@ /mob/living/simple_animal/drone/syndrone/badass name = "Badass Syndrone" - default_hatmask = /obj/item/clothing/head/helmet/space/hardsuit/syndi/elite default_storage = /obj/item/uplink/nuclear /mob/living/simple_animal/drone/syndrone/badass/Initialize(mapload) diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm index c50190ea19a..d9766da229b 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -86,7 +86,7 @@ return ..() /mob/living/simple_animal/hostile/giant_spider/mob_negates_gravity() - return ..() || (locate(/obj/structure/spider/stickyweb) in loc) + return (locate(/obj/structure/spider/stickyweb) in loc) || ..() /** * # Spider Hunter diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index d46398dbe2e..fc27fa3d478 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -882,7 +882,7 @@ GLOBAL_LIST_INIT(strippable_parrot_items, create_strippable_list(list( /mob/living/simple_animal/parrot/poly name = "Poly" desc = "Poly the Parrot. An expert on quantum cracker theory." - speak = list("Poly wanna cracker!", ":e Check the crystal, you chucklefucks!",":e Wire the solars, you lazy bums!",":e WHO TOOK THE DAMN HARDSUITS?",":e OH GOD ITS ABOUT TO DELAMINATE CALL THE SHUTTLE") + speak = list("Poly wanna cracker!", ":e Check the crystal, you chucklefucks!",":e Wire the solars, you lazy bums!",":e WHO TOOK THE DAMN MODSUITS?",":e OH GOD ITS ABOUT TO DELAMINATE CALL THE SHUTTLE") gold_core_spawnable = NO_SPAWN speak_chance = 3 var/memory_saved = FALSE diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 638ab8c18aa..38fd5b9aaac 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -928,7 +928,7 @@ return pick(protection_sources) else return src - if((magic && HAS_TRAIT(src, TRAIT_ANTIMAGIC)) || (holy && HAS_TRAIT(src, TRAIT_HOLY))) + if((magic && HAS_TRAIT(src, TRAIT_ANTIMAGIC)) || (!self && magic && HAS_TRAIT(src, TRAIT_ANTIMAGIC_NO_SELFBLOCK)) || (holy && HAS_TRAIT(src, TRAIT_HOLY))) return src /** diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 3cbca636baa..047e6926f3a 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -525,7 +525,7 @@ ///Can the mob see reagents inside of containers? /mob/proc/can_see_reagents() - return stat == DEAD || has_unlimited_silicon_privilege //Dead guys and silicons can always see reagents + return stat == DEAD || has_unlimited_silicon_privilege || HAS_TRAIT(src, TRAIT_REAGENT_SCANNER) //Dead guys and silicons can always see reagents ///Can this mob hold items /mob/proc/can_hold_items(obj/item/I) diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index ef38f2fbd8f..c158541d20b 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -320,19 +320,15 @@ continue . = AM -/** - * Returns true if a mob has gravity - * - * I hate that this exists - */ -/mob/proc/mob_has_gravity() - return has_gravity() +/mob/has_gravity() + return mob_negates_gravity() || ..() /** * Does this mob ignore gravity */ /mob/proc/mob_negates_gravity() - return FALSE + var/turf/turf = get_turf(src) + return !isgroundlessturf(turf) && HAS_TRAIT(src, TRAIT_NEGATES_GRAVITY) /// Called when this mob slips over, override as needed /mob/proc/slip(knockdown_amount, obj/O, lube, paralyze, force_drop) diff --git a/code/modules/mob_spawn/corpses/job_corpses.dm b/code/modules/mob_spawn/corpses/job_corpses.dm index 102edc13292..7294f85a569 100644 --- a/code/modules/mob_spawn/corpses/job_corpses.dm +++ b/code/modules/mob_spawn/corpses/job_corpses.dm @@ -26,11 +26,8 @@ outfit = /datum/outfit/job/engineer/gloved icon_state = "corpseengineer" -/obj/effect/mob_spawn/corpse/human/engineer/rig - outfit = /datum/outfit/job/engineer/gloved/rig - -/obj/effect/mob_spawn/corpse/human/engineer/rig/gunner - outfit = /datum/outfit/job/engineer/gloved/rig/gunner +/obj/effect/mob_spawn/corpse/human/engineer/mod + outfit = /datum/outfit/job/engineer/mod /obj/effect/mob_spawn/corpse/human/clown name = "Clown" @@ -47,8 +44,8 @@ outfit = /datum/outfit/job/miner icon_state = "corpseminer" -/obj/effect/mob_spawn/corpse/human/miner/rig - outfit = /datum/outfit/job/miner/equipped/hardsuit +/obj/effect/mob_spawn/corpse/human/miner/mod + outfit = /datum/outfit/job/miner/equipped/mod /obj/effect/mob_spawn/corpse/human/miner/explorer outfit = /datum/outfit/job/miner/equipped diff --git a/code/modules/mob_spawn/corpses/mob_corpses.dm b/code/modules/mob_spawn/corpses/mob_corpses.dm index 6ba2e92aa0e..4ab68c746d8 100644 --- a/code/modules/mob_spawn/corpses/mob_corpses.dm +++ b/code/modules/mob_spawn/corpses/mob_corpses.dm @@ -29,12 +29,11 @@ /datum/outfit/syndicatecommandocorpse name = "Syndicate Commando Corpse" uniform = /obj/item/clothing/under/syndicate - suit = /obj/item/clothing/suit/space/hardsuit/syndi shoes = /obj/item/clothing/shoes/combat gloves = /obj/item/clothing/gloves/tackler/combat/insulated ears = /obj/item/radio/headset mask = /obj/item/clothing/mask/gas/syndicate - back = /obj/item/tank/jetpack/oxygen + back = /obj/item/mod/control/pre_equipped/nuclear r_pocket = /obj/item/tank/internals/emergency_oxygen id = /obj/item/card/id/advanced/chameleon id_trim = /datum/id_trim/chameleon/operative @@ -49,12 +48,11 @@ /datum/outfit/syndicatestormtroopercorpse name = "Syndicate Stormtrooper Corpse" uniform = /obj/item/clothing/under/syndicate - suit = /obj/item/clothing/suit/space/hardsuit/syndi/elite shoes = /obj/item/clothing/shoes/combat gloves = /obj/item/clothing/gloves/tackler/combat ears = /obj/item/radio/headset mask = /obj/item/clothing/mask/gas/syndicate - back = /obj/item/tank/jetpack/oxygen/harness + back = /obj/item/mod/control/pre_equipped/elite id = /obj/item/card/id/advanced/chameleon id_trim = /datum/id_trim/chameleon/operative diff --git a/code/modules/mod/mod_actions.dm b/code/modules/mod/mod_actions.dm new file mode 100644 index 00000000000..2c27879e798 --- /dev/null +++ b/code/modules/mod/mod_actions.dm @@ -0,0 +1,71 @@ +/datum/action/item_action/mod + background_icon_state = "bg_tech_blue" + icon_icon = 'icons/mob/actions/actions_mod.dmi' + check_flags = AB_CHECK_CONSCIOUS + var/obj/item/mod/control/mod + +/datum/action/item_action/mod/New(Target) + ..() + mod = Target + +/datum/action/item_action/mod/Grant(mob/M) + if(owner) + Share(M) + return + ..() + +/datum/action/item_action/mod/Remove(mob/M) + var/mob_to_grant + for(var/datum/weakref/reference as anything in sharers) + var/mob/freeloader = reference.resolve() + if(!freeloader) + continue + mob_to_grant = freeloader + break + ..() + if(mob_to_grant) + Grant(mob_to_grant) + +/datum/action/item_action/mod/deploy + name = "Deploy MODsuit" + desc = "Deploy/Conceal a part of the MODsuit." + button_icon_state = "deploy" + +/datum/action/item_action/mod/deploy/Trigger() + if(!IsAvailable()) + return FALSE + mod.choose_deploy(usr) + return TRUE + +/datum/action/item_action/mod/activate + name = "Activate MODsuit" + desc = "Activate/Deactivate the MODsuit." + button_icon_state = "activate" + +/datum/action/item_action/mod/activate/Trigger() + if(!IsAvailable()) + return FALSE + mod.toggle_activate(usr) + return TRUE + +/datum/action/item_action/mod/module + name = "Toggle Module" + desc = "Toggle a MODsuit module." + button_icon_state = "module" + +/datum/action/item_action/mod/module/Trigger() + if(!IsAvailable()) + return FALSE + mod.quick_module(usr) + return TRUE + +/datum/action/item_action/mod/panel + name = "MODsuit Panel" + desc = "Open the MODsuit's panel." + button_icon_state = "panel" + +/datum/action/item_action/mod/panel/Trigger() + if(!IsAvailable()) + return FALSE + mod.ui_interact(usr) + return TRUE diff --git a/code/modules/mod/mod_activation.dm b/code/modules/mod/mod_activation.dm new file mode 100644 index 00000000000..f7869dc2278 --- /dev/null +++ b/code/modules/mod/mod_activation.dm @@ -0,0 +1,217 @@ +#define MOD_ACTIVATION_STEP_TIME 2 SECONDS +#define MOD_ACTIVATION_STEP_FLAGS IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE|IGNORE_HELD_ITEM|IGNORE_INCAPACITATED + +/// Creates a radial menu from which the user chooses parts of the suit to deploy/retract. Repeats until all parts are extended or retracted. +/obj/item/mod/control/proc/choose_deploy(mob/user) + if(!length(mod_parts)) + return + var/list/display_names = list() + var/list/items = list() + for(var/obj/item/piece as anything in mod_parts) + display_names[piece.name] = REF(piece) + var/image/piece_image = image(icon = piece.icon, icon_state = piece.icon_state) + items += list(piece.name = piece_image) + var/pick = show_radial_menu(user, src, items, custom_check = FALSE, require_near = TRUE, tooltips = TRUE) + if(!pick) + return + var/part_reference = display_names[pick] + var/obj/item/part = locate(part_reference) in mod_parts + if(!istype(part) || user.incapacitated()) + return + if(active || activating) + balloon_alert(user, "deactivate the suit first!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return + var/parts_to_check = mod_parts - part + if(part.loc == src) + deploy(user, part) + for(var/obj/item/piece as anything in parts_to_check) + if(piece.loc != src) + continue + choose_deploy(user) + break + else + conceal(user, part) + for(var/obj/item/piece as anything in parts_to_check) + if(piece.loc == src) + continue + choose_deploy(user) + break + +/// Deploys a part of the suit onto the user. +/obj/item/mod/control/proc/deploy(mob/user, part) + var/obj/item/piece = part + if(piece == gauntlets && wearer.gloves) + gauntlets.overslot = wearer.gloves + wearer.transferItemToLoc(gauntlets.overslot, gauntlets, force = TRUE) + if(piece == boots && wearer.shoes) + boots.overslot = wearer.shoes + wearer.transferItemToLoc(boots.overslot, boots, force = TRUE) + if(wearer.equip_to_slot_if_possible(piece, piece.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE)) + ADD_TRAIT(piece, TRAIT_NODROP, MOD_TRAIT) + if(!user) + return TRUE + wearer.visible_message(span_notice("[wearer]'s [piece] deploy[piece.p_s()] with a mechanical hiss."), + span_notice("[piece] deploy[piece.p_s()] with a mechanical hiss."), + span_hear("You hear a mechanical hiss.")) + playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + return TRUE + else if(piece.loc != src) + if(!user) + return FALSE + balloon_alert(user, "[piece] already deployed!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + else + if(!user) + return FALSE + balloon_alert(user, "bodypart clothed!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE + +/// Retract a part of the suit from the user +/obj/item/mod/control/proc/conceal(mob/user, part) + var/obj/item/piece = part + REMOVE_TRAIT(piece, TRAIT_NODROP, MOD_TRAIT) + wearer.transferItemToLoc(piece, src, force = TRUE) + if(piece == gauntlets) + gauntlets.show_overslot() + if(piece == boots) + boots.show_overslot() + if(!user) + return + wearer.visible_message(span_notice("[wearer]'s [piece] retract[piece.p_s()] back into [src] with a mechanical hiss."), + span_notice("[piece] retract[piece.p_s()] back into [src] with a mechanical hiss."), + span_hear("You hear a mechanical hiss.")) + playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + +/// Starts the activation sequence, where parts of the suit activate one by one until the whole suit is on +/obj/item/mod/control/proc/toggle_activate(mob/user, force_deactivate = FALSE) + if(!wearer) + if(!force_deactivate) + balloon_alert(user, "put suit on back!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE + if(!force_deactivate && (SEND_SIGNAL(src, COMSIG_MOD_ACTIVATE, user) & MOD_CANCEL_ACTIVATE)) + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE + for(var/obj/item/part as anything in mod_parts) + if(!force_deactivate && part.loc == src) + balloon_alert(user, "deploy all parts first!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE + if(locked && !active && !allowed(user) && !force_deactivate) + balloon_alert(user, "access insufficient!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE + if(!cell?.charge && !force_deactivate) + balloon_alert(user, "suit not powered!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE + if(open && !force_deactivate) + balloon_alert(user, "close the suit panel!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE + if(activating) + if(!force_deactivate) + balloon_alert(user, "suit already [active ? "shutting down" : "starting up"]!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE + for(var/obj/item/mod/module/module as anything in modules) + if(!module.active) + continue + module.on_deactivation() + activating = TRUE + to_chat(wearer, span_notice("MODsuit [active ? "shutting down" : "starting up"].")) + if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, wearer, MOD_ACTIVATION_STEP_FLAGS)) + to_chat(wearer, span_notice("[boots] [active ? "relax their grip on your legs" : "seal around your feet"].")) + playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + seal_part(boots, seal = !active) + if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, wearer, MOD_ACTIVATION_STEP_FLAGS)) + to_chat(wearer, span_notice("[gauntlets] [active ? "become loose around your fingers" : "tighten around your fingers and wrists"].")) + playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + seal_part(gauntlets, seal = !active) + if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, wearer, MOD_ACTIVATION_STEP_FLAGS)) + to_chat(wearer, span_notice("[chestplate] [active ? "releases your chest" : "cinches tightly against your chest"].")) + playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + seal_part(chestplate,seal = !active) + if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, wearer, MOD_ACTIVATION_STEP_FLAGS)) + to_chat(wearer, span_notice("[helmet] hisses [active ? "open" : "closed"].")) + playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + seal_part(helmet, seal = !active) + if(do_after(wearer, MOD_ACTIVATION_STEP_TIME, wearer, MOD_ACTIVATION_STEP_FLAGS)) + to_chat(wearer, span_notice("Systems [active ? "shut down. Parts unsealed. Goodbye" : "started up. Parts sealed. Welcome"], [wearer].")) + if(ai) + to_chat(ai, span_notice("SYSTEMS [active ? "DEACTIVATED. GOODBYE" : "ACTIVATED. WELCOME"]: \"[ai]\"")) + finish_activation(on = !active) + if(active) + playsound(src, 'sound/machines/synth_yes.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, frequency = 6000) + SEND_SOUND(wearer, sound('sound/mecha/nominal.ogg',volume=50)) + else + playsound(src, 'sound/machines/synth_no.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE, frequency = 6000) + activating = FALSE + return TRUE + +///Seals or unseals the given part +/obj/item/mod/control/proc/seal_part(obj/item/clothing/part, seal) + if(seal) + part.clothing_flags |= part.visor_flags + part.flags_inv |= part.visor_flags_inv + part.flags_cover |= part.visor_flags_cover + part.heat_protection = initial(part.heat_protection) + part.cold_protection = initial(part.cold_protection) + else + part.flags_cover &= ~part.visor_flags_cover + part.flags_inv &= ~part.visor_flags_inv + part.clothing_flags &= ~part.visor_flags + part.heat_protection = NONE + part.cold_protection = NONE + if(part == boots) + boots.icon_state = "[skin]-boots[seal ? "-sealed" : ""]" + wearer.update_inv_shoes() + if(part == gauntlets) + gauntlets.icon_state = "[skin]-gauntlets[seal ? "-sealed" : ""]" + wearer.update_inv_gloves() + if(part == chestplate) + chestplate.icon_state = "[skin]-chestplate[seal ? "-sealed" : ""]" + wearer.update_inv_wear_suit() + wearer.update_inv_w_uniform() + if(part == helmet) + helmet.icon_state = "[skin]-helmet[seal ? "-sealed" : ""]" + if(seal) + helmet.alternate_worn_layer = null + else + helmet.alternate_worn_layer = helmet.alternate_layer + wearer.update_inv_head() + wearer.update_inv_wear_mask() + wearer.update_hair() + +/// Finishes the suit's activation, starts processing +/obj/item/mod/control/proc/finish_activation(on) + icon_state = "[skin]-control[on ? "-sealed" : ""]" + slowdown = on ? slowdown_active : slowdown_inactive + if(on) + for(var/obj/item/mod/module/module as anything in modules) + module.on_suit_activation() + START_PROCESSING(SSobj, src) + else + for(var/obj/item/mod/module/module as anything in modules) + module.on_suit_deactivation() + STOP_PROCESSING(SSobj, src) + wearer.update_equipment_speed_mods() + active = on + wearer.update_inv_back() + +/// Quickly deploys all the suit parts and if successful, seals them and turns on the suit. Intended mostly for outfits. +/obj/item/mod/control/proc/quick_activation() + var/seal = TRUE + for(var/obj/item/part in mod_parts) + if(!deploy(null, part)) + seal = FALSE + if(!seal) + return + for(var/obj/item/part in mod_parts) + seal_part(part, seal = TRUE) + finish_activation(on = TRUE) + +#undef MOD_ACTIVATION_STEP_TIME +#undef MOD_ACTIVATION_STEP_FLAGS diff --git a/code/modules/mod/mod_ai.dm b/code/modules/mod/mod_ai.dm new file mode 100644 index 00000000000..f470fb8046c --- /dev/null +++ b/code/modules/mod/mod_ai.dm @@ -0,0 +1,88 @@ +/obj/item/mod/control/transfer_ai(interaction, mob/user, mob/living/silicon/ai/intAI, obj/item/aicard/card) + . = ..() + if(!.) + return + if(!open) //mod must be open + balloon_alert(user, "suit must be open to transfer!") + return + switch(interaction) + if(AI_TRANS_TO_CARD) + if(!ai) + balloon_alert(user, "no AI in suit!") + return + balloon_alert(user, "transferring to card...") + if(!do_after(user, 5 SECONDS, target = src)) + balloon_alert(user, "interrupted!") + return + intAI = ai + intAI.ai_restore_power()//So the AI initially has power. + intAI.control_disabled = TRUE + intAI.radio_enabled = FALSE + intAI.disconnect_shell() + intAI.forceMove(card) + card.AI = intAI + for(var/datum/action/action as anything in actions) + if(action.owner == intAI) + action.Remove(intAI) + else + action.Unshare(intAI) + intAI.controlled_equipment = null + intAI.remote_control = null + balloon_alert(intAI, "transferred to a card") + balloon_alert(user, "AI transferred to card") + ai = null + + if(AI_TRANS_FROM_CARD) //Using an AI card to upload to the suit. + intAI = card.AI + if(!intAI) + balloon_alert(user, "no AI in card!") + return + if(intAI.deployed_shell) //Recall AI if shelled so it can be checked for a client + intAI.disconnect_shell() + if(intAI.stat || !intAI.client) + balloon_alert(user, "AI unresponsive!") + return + balloon_alert(user, "transferring to suit...") + if(!do_after(user, 5 SECONDS, target = src)) + balloon_alert(user, "interrupted!") + return + balloon_alert(user, "AI transferred to suit") + ai_enter_mod(intAI) + card.AI = null + +/obj/item/mod/control/proc/ai_enter_mod(mob/living/silicon/ai/new_ai) + new_ai.control_disabled = FALSE + new_ai.radio_enabled = TRUE + new_ai.ai_restore_power() + new_ai.cancel_camera() + new_ai.controlled_equipment = src + new_ai.remote_control = src + new_ai.forceMove(src) + ai = new_ai + balloon_alert(new_ai, "transferred to a suit") + for(var/datum/action/action as anything in actions) + action.Grant(new_ai) + +#define MOVE_DELAY 2 +#define WEARER_DELAY 1 +#define LONE_DELAY 5 +#define CELL_PER_STEP DEFAULT_CELL_DRAIN * 2.5 + +/obj/item/mod/control/relaymove(mob/user, direction) + if((!active && wearer) || !cell || cell.charge < CELL_PER_STEP || user != ai || !COOLDOWN_FINISHED(src, cooldown_mod_move) || (wearer?.pulledby?.grab_state > GRAB_PASSIVE)) + return FALSE + var/timemodifier = MOVE_DELAY * (ISDIAGONALDIR(direction) ? SQRT_2 : 1) * (wearer ? WEARER_DELAY : LONE_DELAY) + COOLDOWN_START(src, cooldown_mod_move, movedelay * timemodifier + slowdown) + playsound(src, 'sound/mecha/mechmove01.ogg', 25, TRUE) + cell.charge = max(0, cell.charge - CELL_PER_STEP) + if(ismovable(wearer?.loc)) + return wearer.loc.relaymove(wearer, direction) + if(wearer && !wearer.Process_Spacemove(direction)) + return FALSE + var/atom/movable/mover = wearer || src + return step(mover, direction) + +#undef MOVE_DELAY +#undef WEARER_DELAY +#undef LONE_DELAY +#undef CELL_PER_STEP diff --git a/code/modules/mod/mod_clothes.dm b/code/modules/mod/mod_clothes.dm new file mode 100644 index 00000000000..37045015d66 --- /dev/null +++ b/code/modules/mod/mod_clothes.dm @@ -0,0 +1,123 @@ +/obj/item/clothing/head/helmet/space/mod + name = "MOD helmet" + desc = "A helmet for a MODsuit." + icon = 'icons/obj/mod.dmi' + icon_state = "helmet" + worn_icon = 'icons/mob/mod.dmi' + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 25, ACID = 25, WOUND = 10) + body_parts_covered = HEAD + heat_protection = HEAD + cold_protection = HEAD + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT + clothing_flags = THICKMATERIAL + resistance_flags = NONE + flash_protect = FLASH_PROTECTION_NONE + clothing_flags = SNUG_FIT + flags_inv = HIDEFACIALHAIR + flags_cover = NONE + visor_flags = THICKMATERIAL|STOPSPRESSUREDAMAGE + visor_flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT + visor_flags_cover = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF + var/alternate_layer = NECK_LAYER + var/obj/item/mod/control/mod + +/obj/item/clothing/head/helmet/space/mod/Destroy() + if(!QDELETED(mod)) + mod.helmet = null + mod.mod_parts -= src + QDEL_NULL(mod) + return ..() + +/obj/item/clothing/suit/armor/mod + name = "MOD chestplate" + desc = "A chestplate for a MODsuit." + icon = 'icons/obj/mod.dmi' + icon_state = "chestplate" + worn_icon = 'icons/mob/mod.dmi' + blood_overlay_type = "armor" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 25, ACID = 25, WOUND = 10) + body_parts_covered = CHEST|GROIN + heat_protection = CHEST|GROIN + cold_protection = CHEST|GROIN + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT + clothing_flags = THICKMATERIAL + visor_flags = STOPSPRESSUREDAMAGE + visor_flags_inv = HIDEJUMPSUIT + allowed = list(/obj/item/flashlight, /obj/item/tank/internals) + resistance_flags = NONE + var/obj/item/mod/control/mod + +/obj/item/clothing/suit/armor/mod/Destroy() + if(!QDELETED(mod)) + mod.chestplate = null + mod.mod_parts -= src + QDEL_NULL(mod) + return ..() + +/obj/item/clothing/gloves/mod + name = "MOD gauntlets" + desc = "A pair of gauntlets for a MODsuit." + icon = 'icons/obj/mod.dmi' + icon_state = "gauntlets" + worn_icon = 'icons/mob/mod.dmi' + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 25, ACID = 25, WOUND = 10) + body_parts_covered = HANDS|ARMS + heat_protection = HANDS|ARMS + cold_protection = HANDS|ARMS + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT + clothing_flags = THICKMATERIAL + resistance_flags = NONE + var/obj/item/mod/control/mod + var/obj/item/clothing/overslot + +/obj/item/clothing/gloves/mod/Destroy() + if(!QDELETED(mod)) + mod.gauntlets = null + mod.mod_parts -= src + QDEL_NULL(mod) + return ..() + +/// Replaces these gloves on the wearer with the overslot ones + +/obj/item/clothing/gloves/mod/proc/show_overslot() + if(!overslot) + return + if(!mod.wearer.equip_to_slot_if_possible(overslot, overslot.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE)) + mod.wearer.dropItemToGround(overslot, force = TRUE, silent = TRUE) + overslot = null + +/obj/item/clothing/shoes/mod + name = "MOD boots" + desc = "A pair of boots for a MODsuit." + icon = 'icons/obj/mod.dmi' + icon_state = "boots" + worn_icon = 'icons/mob/mod.dmi' + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 25, ACID = 25, WOUND = 10) + body_parts_covered = FEET|LEGS + heat_protection = FEET|LEGS + cold_protection = FEET|LEGS + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT + clothing_flags = THICKMATERIAL + resistance_flags = NONE + item_flags = IGNORE_DIGITIGRADE + var/obj/item/mod/control/mod + var/obj/item/clothing/overslot + +/obj/item/clothing/shoes/mod/Destroy() + if(!QDELETED(mod)) + mod.boots = null + mod.mod_parts -= src + QDEL_NULL(mod) + return ..() + +/// Replaces these shoes on the wearer with the overslot ones +/obj/item/clothing/shoes/mod/proc/show_overslot() + if(!overslot) + return + if(!mod.wearer.equip_to_slot_if_possible(overslot, overslot.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE)) + mod.wearer.dropItemToGround(overslot, force = TRUE, silent = TRUE) + overslot = null diff --git a/code/modules/mod/mod_construction.dm b/code/modules/mod/mod_construction.dm new file mode 100644 index 00000000000..4916f8b6bc1 --- /dev/null +++ b/code/modules/mod/mod_construction.dm @@ -0,0 +1,278 @@ +/obj/item/mod/construction + desc = "A part used in MOD construction." + inhand_icon_state = "rack_parts" + +/obj/item/mod/construction/helmet + name = "MOD helmet" + icon_state = "helmet" + +/obj/item/mod/construction/chestplate + name = "MOD chestplate" + icon_state = "chestplate" + +/obj/item/mod/construction/gauntlets + name = "MOD gauntlets" + icon_state = "gauntlets" + +/obj/item/mod/construction/boots + name = "MOD boots" + icon_state = "boots" + +/obj/item/mod/construction/core + name = "MOD core" + icon_state = "mod-core" + desc = "Growing in the most lush, fertile areas of the planet Sprout, there is a crystal known as the Heartbloom. \ + These rare, organic piezoelectric crystals are of incredible cultural significance to the artist castes of the Ethereals, \ + owing to their appearance; which is exactly similar to that of an Ethereal's heart. \n\ + Which one you have in your suit is unclear, but either way, \ + it's been repurposed to be an internal power source for a Modular Outerwear Device." + +/obj/item/mod/construction/broken_core + name = "broken MOD core" + icon_state = "mod-core-broken" + desc = "An internal power source for a Modular Outerwear Device. You don't seem to be able to source any power from this one, though." + +/obj/item/mod/construction/broken_core/examine(mob/user) + . = ..() + . += span_notice("You could repair it with a screwdriver...") + +/obj/item/mod/construction/broken_core/screwdriver_act(mob/living/user, obj/item/tool) + . = ..() + if(!tool.use_tool(src, user, 5 SECONDS, volume = 30)) + return + new /obj/item/mod/construction/core(drop_location()) + qdel(src) + +/obj/item/mod/construction/armor + name = "MOD armor plates" + desc = "Armor plates used to finish a MOD." + icon_state = "standard-armor" + var/datum/mod_theme/theme = /datum/mod_theme + +/obj/item/mod/construction/armor/Initialize(mapload) + . = ..() + var/datum/mod_theme/used_theme = GLOB.mod_themes[theme] + name = "MOD [used_theme.name] armor plates" + desc = "[desc] [used_theme.desc]" + icon_state = "[used_theme.default_skin]-armor" + +/obj/item/mod/construction/armor/engineering + theme = /datum/mod_theme/engineering + +/obj/item/mod/construction/armor/atmospheric + theme = /datum/mod_theme/atmospheric + +/obj/item/mod/construction/armor/mining + theme = /datum/mod_theme/mining + +/obj/item/mod/construction/armor/medical + theme = /datum/mod_theme/medical + +/obj/item/mod/construction/armor/security + theme = /datum/mod_theme/security + +/obj/item/mod/construction/armor/cosmohonk + theme = /datum/mod_theme/cosmohonk + +/obj/item/mod/paint + name = "MOD paint kit" + desc = "This kit will repaint your MODsuit to something unique." + icon = 'icons/obj/mod.dmi' + icon_state = "paintkit" + +#define START_STEP "start" +#define CORE_STEP "core" +#define SCREWED_CORE_STEP "screwed_core" +#define HELMET_STEP "helmet" +#define CHESTPLATE_STEP "chestplate" +#define GAUNTLETS_STEP "gauntlets" +#define BOOTS_STEP "boots" +#define WRENCHED_ASSEMBLY_STEP "wrenched_assembly" +#define SCREWED_ASSEMBLY_STEP "screwed_assembly" + +/obj/item/mod/construction/shell + name = "MOD shell" + icon_state = "mod-construction_start" + desc = "A MOD shell." + var/obj/item/core + var/obj/item/helmet + var/obj/item/chestplate + var/obj/item/gauntlets + var/obj/item/boots + var/step = START_STEP + +/obj/item/mod/construction/shell/examine(mob/user) + . = ..() + var/display_text + switch(step) + if(START_STEP) + display_text = "It looks like it's missing a MOD core..." + if(CORE_STEP) + display_text = "The core seems loose..." + if(SCREWED_CORE_STEP) + display_text = "It looks like it's missing a helmet..." + if(HELMET_STEP) + display_text = "It looks like it's missing a chestplate..." + if(CHESTPLATE_STEP) + display_text = "It looks like it's missing gauntlets..." + if(GAUNTLETS_STEP) + display_text = "It looks like it's missing boots..." + if(BOOTS_STEP) + display_text = "The assembly seems unsecured..." + if(WRENCHED_ASSEMBLY_STEP) + display_text = "The assembly seems loose..." + if(SCREWED_ASSEMBLY_STEP) + display_text = "All it's missing is external armor..." + . += span_notice(display_text) + +/obj/item/mod/construction/shell/attackby(obj/item/part, mob/user, params) + . = ..() + switch(step) + if(START_STEP) + if(!istype(part, /obj/item/mod/construction/core)) + return + if(!user.transferItemToLoc(part, src)) + balloon_alert(user, "core stuck to your hand!") + return + playsound(src, 'sound/machines/click.ogg', 30, TRUE) + balloon_alert(user, "core inserted") + core = part + step = CORE_STEP + if(CORE_STEP) + if(part.tool_behaviour == TOOL_SCREWDRIVER) //Construct + if(part.use_tool(src, user, 0, volume=30)) + balloon_alert(user, "core screwed") + step = SCREWED_CORE_STEP + else if(part.tool_behaviour == TOOL_CROWBAR) //Deconstruct + if(part.use_tool(src, user, 0, volume=30)) + core.forceMove(drop_location()) + balloon_alert(user, "core taken out") + step = START_STEP + if(SCREWED_CORE_STEP) + if(istype(part, /obj/item/mod/construction/helmet)) //Construct + if(!user.transferItemToLoc(part, src)) + balloon_alert(user, "helmet stuck to your hand!") + return + playsound(src, 'sound/machines/click.ogg', 30, TRUE) + balloon_alert(user, "helmet added") + helmet = part + step = HELMET_STEP + else if(part.tool_behaviour == TOOL_SCREWDRIVER) //Deconstruct + if(part.use_tool(src, user, 0, volume=30)) + balloon_alert(user, "core unscrewed") + step = CORE_STEP + if(HELMET_STEP) + if(istype(part, /obj/item/mod/construction/chestplate)) //Construct + if(!user.transferItemToLoc(part, src)) + balloon_alert(user, "chestplate stuck to your hand!") + return + playsound(src, 'sound/machines/click.ogg', 30, TRUE) + balloon_alert(user, "chestplate added") + chestplate = part + step = CHESTPLATE_STEP + else if(part.tool_behaviour == TOOL_CROWBAR) //Deconstruct + if(part.use_tool(src, user, 0, volume=30)) + helmet.forceMove(drop_location()) + balloon_alert(user, "helmet removed") + helmet = null + step = SCREWED_CORE_STEP + if(CHESTPLATE_STEP) + if(istype(part, /obj/item/mod/construction/gauntlets)) //Construct + if(!user.transferItemToLoc(part, src)) + balloon_alert(user, "gauntlets stuck to your hand!") + return + playsound(src, 'sound/machines/click.ogg', 30, TRUE) + balloon_alert(user, "gauntlets added") + gauntlets = part + step = GAUNTLETS_STEP + else if(part.tool_behaviour == TOOL_CROWBAR) //Deconstruct + if(part.use_tool(src, user, 0, volume=30)) + chestplate.forceMove(drop_location()) + balloon_alert(user, "chestplate removed") + chestplate = null + step = HELMET_STEP + if(GAUNTLETS_STEP) + if(istype(part, /obj/item/mod/construction/boots)) //Construct + if(!user.transferItemToLoc(part, src)) + balloon_alert(user, "boots added") + return + playsound(src, 'sound/machines/click.ogg', 30, TRUE) + balloon_alert(user, "You fit [part] onto [src].") + boots = part + step = BOOTS_STEP + else if(part.tool_behaviour == TOOL_CROWBAR) //Deconstruct + if(part.use_tool(src, user, 0, volume=30)) + gauntlets.forceMove(drop_location()) + balloon_alert(user, "gauntlets removed") + gauntlets = null + step = CHESTPLATE_STEP + if(BOOTS_STEP) + if(part.tool_behaviour == TOOL_WRENCH) //Construct + if(part.use_tool(src, user, 0, volume=30)) + balloon_alert(user, "assembly secured") + step = WRENCHED_ASSEMBLY_STEP + else if(part.tool_behaviour == TOOL_CROWBAR) //Deconstruct + if(part.use_tool(src, user, 0, volume=30)) + boots.forceMove(drop_location()) + balloon_alert(user, "boots removed") + boots = null + step = GAUNTLETS_STEP + if(WRENCHED_ASSEMBLY_STEP) + if(part.tool_behaviour == TOOL_SCREWDRIVER) //Construct + if(part.use_tool(src, user, 0, volume=30)) + balloon_alert(user, "assembly screwed") + step = SCREWED_ASSEMBLY_STEP + else if(part.tool_behaviour == TOOL_WRENCH) //Deconstruct + if(part.use_tool(src, user, 0, volume=30)) + balloon_alert(user, "assembly unsecured") + step = BOOTS_STEP + if(SCREWED_ASSEMBLY_STEP) + if(istype(part, /obj/item/mod/construction/armor)) //Construct + var/obj/item/mod/construction/armor/external_armor = part + if(!user.transferItemToLoc(part, src)) + return + playsound(src, 'sound/machines/click.ogg', 30, TRUE) + balloon_alert(user, "suit finished") + var/obj/item/modsuit = new /obj/item/mod/control(drop_location(), external_armor.theme) + qdel(src) + user.put_in_hands(modsuit) + else if(part.tool_behaviour == TOOL_SCREWDRIVER) //Construct + if(part.use_tool(src, user, 0, volume=30)) + balloon_alert(user, "assembly unscrewed") + step = SCREWED_ASSEMBLY_STEP + update_icon_state() + +/obj/item/mod/construction/shell/update_icon_state() + . = ..() + icon_state = "mod-construction_[step]" + +/obj/item/mod/construction/shell/Destroy() + QDEL_NULL(core) + QDEL_NULL(helmet) + QDEL_NULL(chestplate) + QDEL_NULL(gauntlets) + QDEL_NULL(boots) + return ..() + +/obj/item/mod/construction/shell/handle_atom_del(atom/deleted_atom) + if(deleted_atom == core) + core = null + if(deleted_atom == helmet) + helmet = null + if(deleted_atom == chestplate) + chestplate = null + if(deleted_atom == gauntlets) + gauntlets = null + if(deleted_atom == boots) + boots = null + return ..() + +#undef START_STEP +#undef CORE_STEP +#undef SCREWED_CORE_STEP +#undef HELMET_STEP +#undef CHESTPLATE_STEP +#undef GAUNTLETS_STEP +#undef BOOTS_STEP +#undef WRENCHED_ASSEMBLY_STEP +#undef SCREWED_ASSEMBLY_STEP diff --git a/code/modules/mod/mod_control.dm b/code/modules/mod/mod_control.dm new file mode 100644 index 00000000000..8ca7dc8573f --- /dev/null +++ b/code/modules/mod/mod_control.dm @@ -0,0 +1,559 @@ +/// MODsuits, trade-off between armor and utility +/obj/item/mod + name = "Base MOD" + desc = "You should not see this, yell at a coder!" + icon = 'icons/obj/mod.dmi' + icon_state = "standard-control" + worn_icon = 'icons/mob/mod.dmi' + +/obj/item/mod/control + name = "MOD control unit" + desc = "The control unit of a Modular Outerwear Device, a powered, back-mounted suit that protects against various environments." + icon_state = "control" + inhand_icon_state = "mod_control" + w_class = WEIGHT_CLASS_BULKY + slot_flags = ITEM_SLOT_BACK + strip_delay = 10 SECONDS + slowdown = 2 + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 25, ACID = 25, WOUND = 10) + actions_types = list(/datum/action/item_action/mod/deploy, /datum/action/item_action/mod/activate, /datum/action/item_action/mod/module, /datum/action/item_action/mod/panel) + resistance_flags = NONE + max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT + min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT + permeability_coefficient = 0.01 + siemens_coefficient = 0.5 + alternate_worn_layer = BODY_FRONT_LAYER + /// The MOD's theme, decides on some stuff like armor and statistics. + var/datum/mod_theme/theme = /datum/mod_theme + /// Looks of the MOD. + var/skin = "standard" + /// Theme of the MOD TGUI + var/ui_theme = "ntos" + /// If the suit is deployed and turned on. + var/active = FALSE + /// If the suit wire/module hatch is open. + var/open = FALSE + /// If the suit is ID locked. + var/locked = FALSE + /// If the suit is malfunctioning. + var/malfunctioning = FALSE + /// If the suit is currently activating/deactivating. + var/activating = FALSE + /// How long the MOD is electrified for. + var/seconds_electrified = MACHINE_NOT_ELECTRIFIED + /// If the suit interface is broken. + var/interface_break = FALSE + /// How much module complexity can this MOD carry. + var/complexity_max = DEFAULT_MAX_COMPLEXITY + /// How much module complexity this MOD is carrying. + var/complexity = 0 + /// Power usage of the MOD. + var/cell_drain = DEFAULT_CELL_DRAIN + /// Slowdown of the MOD when not active. + var/slowdown_inactive = 2 + /// Slowdown of the MOD when active. + var/slowdown_active = 1 + /// MOD cell. + var/obj/item/stock_parts/cell/cell + /// MOD helmet. + var/obj/item/clothing/head/helmet/space/mod/helmet + /// MOD chestplate. + var/obj/item/clothing/suit/armor/mod/chestplate + /// MOD gauntlets. + var/obj/item/clothing/gloves/mod/gauntlets + /// MOD boots. + var/obj/item/clothing/shoes/mod/boots + /// List of parts (helmet, chestplate, gauntlets, boots). + var/list/mod_parts = list() + /// Modules the MOD should spawn with. + var/list/initial_modules = list() + /// Modules the MOD currently possesses. + var/list/modules = list() + /// Currently used module. + var/obj/item/mod/module/selected_module + /// AI mob inhabiting the MOD. + var/mob/living/silicon/ai/ai + /// Delay between moves as AI. + var/movedelay = 0 + /// Cooldown for AI moves. + COOLDOWN_DECLARE(cooldown_mod_move) + /// Person wearing the MODsuit. + var/mob/living/carbon/human/wearer + +/obj/item/mod/control/Initialize(mapload, new_theme, new_skin) + . = ..() + if(new_theme) + theme = new_theme + theme = GLOB.mod_themes[theme] + slowdown_inactive = theme.slowdown_inactive + slowdown_active = theme.slowdown_active + slowdown = slowdown_inactive + complexity_max = theme.complexity_max + skin = new_skin || theme.default_skin + ui_theme = theme.ui_theme + cell_drain = theme.cell_drain + initial_modules += theme.inbuilt_modules + wires = new /datum/wires/mod(src) + if(length(req_access)) + locked = TRUE + if(ispath(cell)) + cell = new cell(src) + helmet = new /obj/item/clothing/head/helmet/space/mod(src) + helmet.mod = src + mod_parts += helmet + chestplate = new /obj/item/clothing/suit/armor/mod(src) + chestplate.mod = src + mod_parts += chestplate + gauntlets = new /obj/item/clothing/gloves/mod(src) + gauntlets.mod = src + mod_parts += gauntlets + boots = new /obj/item/clothing/shoes/mod(src) + boots.mod = src + mod_parts += boots + var/list/all_parts = mod_parts.Copy() + src + for(var/obj/item/piece as anything in all_parts) + piece.name = "[theme.name] [piece.name]" + piece.desc = "[piece.desc] [theme.desc]" + piece.armor = getArmor(arglist(theme.armor)) + piece.resistance_flags = theme.resistance_flags + piece.heat_protection = NONE + piece.cold_protection = NONE + piece.max_heat_protection_temperature = theme.max_heat_protection_temperature + piece.min_cold_protection_temperature = theme.min_cold_protection_temperature + piece.permeability_coefficient = theme.permeability_coefficient + piece.siemens_coefficient = theme.siemens_coefficient + piece.icon_state = "[skin]-[initial(piece.icon_state)]" + update_flags() + for(var/obj/item/mod/module/module as anything in initial_modules) + module = new module(src) + install(module) + RegisterSignal(src, COMSIG_ATOM_EXITED, .proc/on_exit) + movedelay = CONFIG_GET(number/movedelay/run_delay) + +/obj/item/mod/control/Destroy() + if(active) + STOP_PROCESSING(SSobj, src) + var/atom/deleting_atom + if(!QDELETED(helmet)) + deleting_atom = helmet + helmet.mod = null + helmet = null + mod_parts -= deleting_atom + qdel(deleting_atom) + if(!QDELETED(chestplate)) + deleting_atom = chestplate + chestplate.mod = null + chestplate = null + mod_parts -= deleting_atom + qdel(deleting_atom) + if(!QDELETED(gauntlets)) + deleting_atom = gauntlets + gauntlets.mod = null + gauntlets = null + mod_parts -= deleting_atom + qdel(deleting_atom) + if(!QDELETED(boots)) + deleting_atom = boots + boots.mod = null + boots = null + mod_parts -= deleting_atom + qdel(deleting_atom) + for(var/obj/item/mod/module/module as anything in modules) + module.mod = null + modules -= module + QDEL_NULL(wires) + QDEL_NULL(cell) + return ..() + +/obj/item/mod/control/process(delta_time) + if(seconds_electrified > MACHINE_NOT_ELECTRIFIED) + seconds_electrified-- + if((!cell || !cell.charge) && active && !activating) + power_off() + return PROCESS_KILL + var/malfunctioning_charge_drain = 0 + if(malfunctioning) + malfunctioning_charge_drain = rand(1,20) + cell.charge = max(0, cell.charge - (cell_drain + malfunctioning_charge_drain)*delta_time) + update_cell_alert() + for(var/obj/item/mod/module/module as anything in modules) + if(malfunctioning && module.active && DT_PROB(5, delta_time)) + module.on_deactivation() + module.on_process(delta_time) + +/obj/item/mod/control/equipped(mob/user, slot) + ..() + if(slot == ITEM_SLOT_BACK) + set_wearer(user) + else if(wearer) + unset_wearer() + +/obj/item/mod/control/dropped(mob/user) + . = ..() + if(wearer) + unset_wearer() + +/obj/item/mod/control/item_action_slot_check(slot) + if(slot == ITEM_SLOT_BACK) + return TRUE + +/obj/item/mod/control/allow_attack_hand_drop(mob/user) + var/mob/living/carbon/carbon_user = user + if(!istype(carbon_user) || src != carbon_user.back) + return ..() + for(var/obj/item/part in mod_parts) + if(part.loc != src) + balloon_alert(carbon_user, "retract parts first!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, FALSE, SILENCED_SOUND_EXTRARANGE) + return FALSE + +/obj/item/mod/control/MouseDrop(atom/over_object) + if(src != wearer?.back || !istype(over_object, /atom/movable/screen/inventory/hand)) + return ..() + for(var/obj/item/part in mod_parts) + if(part.loc != src) + balloon_alert(wearer, "retract parts first!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, FALSE, SILENCED_SOUND_EXTRARANGE) + return + if(!wearer.incapacitated()) + var/atom/movable/screen/inventory/hand/ui_hand = over_object + if(wearer.putItemFromInventoryInHandIfPossible(src, ui_hand.held_index)) + add_fingerprint(usr) + return ..() + +/obj/item/mod/control/attack_hand(mob/user) + if(seconds_electrified && cell?.charge) + if(shock(user)) + return + if(open && loc == user) + if(!cell) + balloon_alert(user, "no cell!") + return + balloon_alert(user, "removing cell...") + if(!do_after(user, 1.5 SECONDS, target = src)) + balloon_alert(user, "interrupted!") + return + balloon_alert(user, "cell removed") + playsound(src, 'sound/machines/click.ogg', 50, TRUE, SILENCED_SOUND_EXTRARANGE) + if(!user.put_in_hands(cell)) + cell.forceMove(drop_location()) + update_cell_alert() + return + return ..() + +/obj/item/mod/control/screwdriver_act(mob/living/user, obj/item/screwdriver) + if(..()) + return TRUE + if(active || activating || ai_controller) + balloon_alert(user, "deactivate suit first!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE + balloon_alert(user, "[open ? "closing" : "opening"] panel...") + screwdriver.play_tool_sound(src, 100) + if(screwdriver.use_tool(src, user, 1 SECONDS)) + if(active || activating) + balloon_alert(user, "deactivate suit first!") + screwdriver.play_tool_sound(src, 100) + balloon_alert(user, "panel [open ? "closed" : "opened"]") + open = !open + else + balloon_alert(user, "interrupted!") + return TRUE + +/obj/item/mod/control/crowbar_act(mob/living/user, obj/item/crowbar) + . = ..() + if(!open) + balloon_alert(user, "open the panel first!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE + if(!allowed(user)) + balloon_alert(user, "insufficient access!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return + if(length(modules)) + var/list/removable_modules = list() + for(var/obj/item/mod/module/module as anything in modules) + if(!module.removable) + continue + removable_modules += module + var/obj/item/mod/module/module_to_remove = tgui_input_list(user, "Which module to remove?", "Module Removal", removable_modules) + if(!module_to_remove?.mod) + return FALSE + uninstall(module_to_remove) + module_to_remove.forceMove(drop_location()) + crowbar.play_tool_sound(src, 100) + return TRUE + balloon_alert(user, "no modules!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE + +/obj/item/mod/control/attackby(obj/item/attacking_item, mob/living/user, params) + if(istype(attacking_item, /obj/item/mod/module)) + if(!open) + balloon_alert(user, "open the panel first!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE + install(attacking_item, user) + return TRUE + else if(istype(attacking_item, /obj/item/stock_parts/cell)) + if(!open) + balloon_alert(user, "open the panel first!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE + if(cell) + balloon_alert(user, "cell already installed!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return FALSE + attacking_item.forceMove(src) + cell = attacking_item + balloon_alert(user, "cell installed") + playsound(src, 'sound/machines/click.ogg', 50, TRUE, SILENCED_SOUND_EXTRARANGE) + update_cell_alert() + return TRUE + else if(is_wire_tool(attacking_item) && open) + wires.interact(user) + return TRUE + else if(istype(attacking_item, /obj/item/mod/paint)) + if(active || activating) + balloon_alert(user, "suit is active!") + else if(paint(user, attacking_item)) + balloon_alert(user, "suit painted") + else + balloon_alert(user, "not painted!") + return TRUE + else if(open && attacking_item.GetID()) + update_access(user, attacking_item) + return TRUE + return ..() + +/obj/item/mod/control/get_cell() + if(open) + return cell + +/obj/item/mod/control/GetAccess() + if(ai_controller) + return req_access.Copy() + else + return ..() + +/obj/item/mod/control/emag_act(mob/user) + locked = !locked + balloon_alert(user, "[locked ? "locked" : "unlocked"]") + +/obj/item/mod/control/emp_act(severity) + . = ..() + to_chat(wearer, span_notice("[severity > 1 ? "Light" : "Strong"] electromagnetic pulse detected!")) + if(!active || !wearer || . & EMP_PROTECT_CONTENTS) + return + selected_module = null + wearer.apply_damage(10 / severity, BURN, spread_damage=TRUE) + to_chat(wearer, span_danger("You feel [src] heat up from the EMP, burning you slightly.")) + if (wearer.stat < UNCONSCIOUS && prob(10)) + wearer.emote("scream") + +/obj/item/mod/control/on_outfit_equip(mob/living/carbon/human/outfit_wearer, visuals_only, item_slot) + if(visuals_only) + set_wearer(outfit_wearer) //we need to set wearer manually since it doesnt call equipped + quick_activation() + +/obj/item/mod/control/doStrip(mob/stripper, mob/owner) + if(active && !toggle_activate(stripper, force_deactivate = TRUE)) + return + for(var/obj/item/part in mod_parts) + conceal(null, part) + return ..() + +/obj/item/mod/control/worn_overlays(mutable_appearance/standing, isinhands = FALSE, icon_file) + . = ..() + if(!active) + return + for(var/obj/item/mod/module/module as anything in modules) + var/list/module_icons = module.generate_worn_overlay(standing) + if(!length(module_icons)) + continue + . += module_icons + +/obj/item/mod/control/proc/set_wearer(mob/user) + wearer = user + RegisterSignal(wearer, COMSIG_ATOM_EXITED, .proc/on_exit) + RegisterSignal(wearer, COMSIG_PROCESS_BORGCHARGER_OCCUPANT, .proc/on_borg_charge) + update_cell_alert() + for(var/obj/item/mod/module/module as anything in modules) + module.on_equip() + +/obj/item/mod/control/proc/unset_wearer() + for(var/obj/item/mod/module/module as anything in modules) + module.on_unequip() + UnregisterSignal(wearer, list(COMSIG_ATOM_EXITED, COMSIG_PROCESS_BORGCHARGER_OCCUPANT)) + wearer.clear_alert("mod_charge") + wearer = null + +/obj/item/mod/control/proc/update_flags() + var/list/used_skin = theme.skins[skin] + for(var/obj/item/clothing/part as anything in mod_parts) + var/used_category + if(part == helmet) + used_category = HELMET_FLAGS + helmet.alternate_worn_layer = used_skin[HELMET_LAYER] + helmet.alternate_layer = used_skin[HELMET_LAYER] + if(part == chestplate) + used_category = CHESTPLATE_FLAGS + if(part == gauntlets) + used_category = GAUNTLETS_FLAGS + if(part == boots) + used_category = BOOTS_FLAGS + var/list/category = used_skin[used_category] + part.clothing_flags = category[UNSEALED_CLOTHING] || NONE + part.visor_flags = category[SEALED_CLOTHING] || NONE + part.flags_inv = category[UNSEALED_INVISIBILITY] || NONE + part.visor_flags_inv = category[SEALED_INVISIBILITY] || NONE + part.flags_cover = category[UNSEALED_COVER] || NONE + part.visor_flags_cover = category[SEALED_COVER] || NONE + +/obj/item/mod/control/proc/quick_module(mob/user) + if(!length(modules)) + return + var/list/display_names = list() + var/list/items = list() + for(var/obj/item/mod/module/module as anything in modules) + if(module.module_type == MODULE_PASSIVE) + continue + display_names[module.name] = REF(module) + var/image/module_image = image(icon = module.icon, icon_state = module.icon_state) + items += list(module.name = module_image) + if(!length(items)) + return + var/pick = show_radial_menu(user, src, items, custom_check = FALSE, require_near = TRUE) + if(!pick) + return + var/module_reference = display_names[pick] + var/obj/item/mod/module/selected_module = locate(module_reference) in modules + if(!istype(selected_module) || user.incapacitated()) + return + selected_module.on_select() + +/obj/item/mod/control/proc/paint(mob/user, obj/item/paint) + if(length(theme.skins) <= 1) + return FALSE + var/list/skins = list() + for(var/mod_skin in theme.skins) + skins[mod_skin] = image(icon = icon, icon_state = "[mod_skin]-control") + var/pick = show_radial_menu(user, src, skins, custom_check = FALSE, require_near = TRUE) + if(!pick || !user.is_holding(paint)) + return FALSE + skin = pick + var/list/skin_updating = mod_parts.Copy() + src + for(var/obj/item/piece as anything in skin_updating) + piece.icon_state = "[skin]-[initial(piece.icon_state)]" + update_flags() + wearer?.regenerate_icons() + return TRUE + +/obj/item/mod/control/proc/shock(mob/living/user) + if(!istype(user) || cell?.charge < 1) + return FALSE + do_sparks(5, TRUE, src) + var/check_range = TRUE + return electrocute_mob(user, cell, src, 0.7, check_range) + +/obj/item/mod/control/proc/install(module, mob/user) + var/obj/item/mod/module/new_module = module + for(var/obj/item/mod/module/old_module as anything in modules) + if(is_type_in_list(new_module, old_module.incompatible_modules) || is_type_in_list(old_module, new_module.incompatible_modules)) + if(user) + balloon_alert(user, "[new_module] incompatible with [old_module]!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return + if(is_type_in_list(module, theme.module_blacklist)) + if(user) + balloon_alert(user, "[src] doesn't accept [new_module]!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return + var/complexity_with_module = complexity + complexity_with_module += new_module.complexity + if(complexity_with_module > complexity_max) + if(user) + balloon_alert(user, "[new_module] would make [src] too complex!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return + new_module.forceMove(src) + modules += new_module + complexity += new_module.complexity + new_module.mod = src + new_module.on_install() + if(wearer) + new_module.on_equip() + if(user) + balloon_alert(user, "[new_module] added") + playsound(src, 'sound/machines/click.ogg', 50, TRUE, SILENCED_SOUND_EXTRARANGE) + +/obj/item/mod/control/proc/uninstall(module) + var/obj/item/mod/module/old_module = module + modules -= old_module + complexity -= old_module.complexity + if(active) + old_module.on_suit_deactivation() + if(old_module.active) + old_module.on_deactivation() + if(wearer) + old_module.on_unequip() + old_module.on_uninstall() + old_module.mod = null + +/obj/item/mod/control/proc/update_access(mob/user, obj/item/card/id/card) + if(!allowed(user)) + balloon_alert(user, "insufficient access!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return + req_access = card.access.Copy() + balloon_alert(user, "access updated") + +/obj/item/mod/control/proc/update_cell_alert() + if(!wearer) + return + if(!cell) + wearer.throw_alert("mod_charge", /atom/movable/screen/alert/nocell) + return + var/remaining_cell = cell.charge/cell.maxcharge + switch(remaining_cell) + if(0.75 to INFINITY) + wearer.clear_alert("mod_charge") + if(0.5 to 0.75) + wearer.throw_alert("mod_charge", /atom/movable/screen/alert/lowcell, 1) + if(0.25 to 0.5) + wearer.throw_alert("mod_charge", /atom/movable/screen/alert/lowcell, 2) + if(0.01 to 0.25) + wearer.throw_alert("mod_charge", /atom/movable/screen/alert/lowcell, 3) + else + wearer.throw_alert("mod_charge", /atom/movable/screen/alert/emptycell) + +/obj/item/mod/control/proc/power_off() + balloon_alert(wearer, "no power!") + toggle_activate(wearer, force_deactivate = TRUE) + +/obj/item/mod/control/proc/on_exit(datum/source, atom/movable/part, direction) + SIGNAL_HANDLER + + if(part.loc == src) + return + if(part == cell) + cell = null + update_cell_alert() + return + if(part.loc == wearer) + return + if(modules.Find(part)) + uninstall(part) + return + if(mod_parts.Find(part)) + conceal(wearer, part) + if(active) + INVOKE_ASYNC(src, .proc/toggle_activate, wearer, TRUE) + return + +/obj/item/mod/control/proc/on_borg_charge(datum/source, amount) + SIGNAL_HANDLER + + if(!cell) + return + cell.give(amount) diff --git a/code/modules/mod/mod_theme.dm b/code/modules/mod/mod_theme.dm new file mode 100644 index 00000000000..174cc1bab32 --- /dev/null +++ b/code/modules/mod/mod_theme.dm @@ -0,0 +1,854 @@ +/// Global proc that sets up all MOD themes as singletons in a list and returns it. +/proc/setup_mod_themes() + . = list() + for(var/path in typesof(/datum/mod_theme)) + var/datum/mod_theme/new_theme = new path() + .[path] = new_theme + +/// MODsuit theme, instanced once and then used by MODsuits to grab various statistics. +/datum/mod_theme + /// Theme name for the MOD. + var/name = "standard" + /// Description added to the MOD. + var/desc = "A civilian class suit by Nakamura Engineering, doesn't offer much other than slightly quicker movement." + /// Default skin of the MOD. + var/default_skin = "standard" + /// Armor shared across the MOD pieces. + var/armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 100, FIRE = 25, ACID = 25, WOUND = 10) + /// Resistance flags shared across the MOD pieces. + var/resistance_flags = NONE + /// Max heat protection shared across the MOD pieces. + var/max_heat_protection_temperature = SPACE_SUIT_MAX_TEMP_PROTECT + /// Max cold protection shared across the MOD pieces. + var/min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT + /// Permeability shared across the MOD pieces. + var/permeability_coefficient = 0.01 + /// Siemens shared across the MOD pieces. + var/siemens_coefficient = 0.5 + /// How much modules can the MOD carry without malfunctioning. + var/complexity_max = DEFAULT_MAX_COMPLEXITY + /// How much battery power the MOD uses by just being on + var/cell_drain = DEFAULT_CELL_DRAIN + /// Slowdown of the MOD when not active. + var/slowdown_inactive = 1.25 + /// Slowdown of the MOD when active. + var/slowdown_active = 0.75 + /// Theme used by the MOD TGUI. + var/ui_theme = "ntos" + /// List of inbuilt modules. These are different from the pre-equipped suits, you should mainly use these for unremovable modules with 0 complexity. + var/list/inbuilt_modules = list() + /// Modules blacklisted from the MOD. + var/list/module_blacklist = list() + /// List of skins with their appropriate clothing flags. + var/list/skins = list( + "standard" = list( + HELMET_LAYER = NECK_LAYER, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + "civilian" = list( + HELMET_LAYER = null, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/engineering + name = "engineering" + desc = "An engineer-fit suit with heat and shock resistance. Nakamura Engineering's classic." + default_skin = "engineering" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 100, FIRE = 100, ACID = 25, WOUND = 10) + resistance_flags = FIRE_PROOF + max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT + siemens_coefficient = 0 + slowdown_inactive = 1.5 + slowdown_active = 1 + skins = list( + "engineering" = list( + HELMET_LAYER = NECK_LAYER, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/atmospheric + name = "atmospheric" + desc = "An atmospheric-resistant suit by Nakamura Engineering, offering extreme heat resistance compared to the engineer suit." + default_skin = "atmospheric" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 100, FIRE = 100, ACID = 75, WOUND = 10) + resistance_flags = FIRE_PROOF + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + slowdown_inactive = 1.5 + slowdown_active = 1 + skins = list( + "atmospheric" = list( + HELMET_LAYER = NECK_LAYER, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDESNOUT, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR, + UNSEALED_COVER = HEADCOVERSMOUTH, + SEALED_COVER = HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/advanced + name = "advanced" + desc = "An advanced version of Nakamura Engineering's classic suit, shining with a white, acid and fire resistant polish." + default_skin = "advanced" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 100, FIRE = 100, ACID = 90, WOUND = 10) + resistance_flags = FIRE_PROOF + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + siemens_coefficient = 0 + slowdown_inactive = 1 + slowdown_active = 0.5 + inbuilt_modules = list(/obj/item/mod/module/magboot/advanced) + skins = list( + "advanced" = list( + HELMET_LAYER = NECK_LAYER, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/mining + name = "mining" + desc = "A high-power Nanotrasen mining suit, supporting more complexity at a bigger drain." + default_skin = "mining" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 100, FIRE = 100, ACID = 75, WOUND = 15) + resistance_flags = FIRE_PROOF + max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT + cell_drain = DEFAULT_CELL_DRAIN * 2 + complexity_max = DEFAULT_MAX_COMPLEXITY + 5 + skins = list( + "mining" = list( + HELMET_LAYER = null, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, + SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/medical + name = "medical" + desc = "A lightweight suit by DeForest Medical Corporation, allows for easier movement." + default_skin = "medical" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 100, FIRE = 60, ACID = 75, WOUND = 10) + cell_drain = DEFAULT_CELL_DRAIN * 1.5 + slowdown_inactive = 1 + slowdown_active = 0.5 + skins = list( + "medical" = list( + HELMET_LAYER = NECK_LAYER, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + "corpsman" = list( + HELMET_LAYER = NECK_LAYER, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/rescue + name = "rescue" + desc = "An advanced version of DeForest Medical Corporation's medical suit, designed for quick rescue of bodies from the most dangerous environments." + default_skin = "rescue" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 100, FIRE = 100, ACID = 100, WOUND = 10) + resistance_flags = FIRE_PROOF|ACID_PROOF + max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT + cell_drain = DEFAULT_CELL_DRAIN * 1.5 + slowdown_inactive = 0.75 + slowdown_active = 0.25 + inbuilt_modules = list(/obj/item/mod/module/quick_carry/advanced) + skins = list( + "rescue" = list( + HELMET_LAYER = NECK_LAYER, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/research + name = "research" + desc = "A private military EOD suit by Aussec Armory, intended for explosive research. Bulky, but expansive." + default_skin = "research" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 100, BIO = 100, FIRE = 100, ACID = 100, WOUND = 15) + resistance_flags = FIRE_PROOF|ACID_PROOF + max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT + complexity_max = DEFAULT_MAX_COMPLEXITY + 5 + slowdown_inactive = 2 + slowdown_active = 1.5 + inbuilt_modules = list(/obj/item/mod/module/reagent_scanner/advanced) + skins = list( + "research" = list( + HELMET_LAYER = null, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/security + name = "security" + desc = "An Apadyne Technologies security suit, offering shock protection and quicker speed, at the cost of carrying capacity." + default_skin = "security" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 100, FIRE = 75, ACID = 75, WOUND = 20) + siemens_coefficient = 0 + complexity_max = DEFAULT_MAX_COMPLEXITY - 5 + slowdown_inactive = 1 + slowdown_active = 0.5 + skins = list( + "security" = list( + HELMET_LAYER = null, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, + SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE, + UNSEALED_COVER = HEADCOVERSMOUTH, + SEALED_COVER = HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/safeguard + name = "safeguard" + desc = "An Apadyne Technologies advanced security suit, offering greater speed and fire protection than the standard security model." + default_skin = "safeguard" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 25, BIO = 100, FIRE = 100, ACID = 95, WOUND = 25) + resistance_flags = FIRE_PROOF + max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT + siemens_coefficient = 0 + complexity_max = DEFAULT_MAX_COMPLEXITY - 5 + slowdown_inactive = 0.75 + slowdown_active = 0.25 + skins = list( + "safeguard" = list( + HELMET_LAYER = null, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/magnate + name = "magnate" + desc = "A fancy, very protective suit for Nanotrasen's captains. Shock, fire and acid-proof while also having a large capacity and high speed." + default_skin = "magnate" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 100, FIRE = 100, ACID = 100, WOUND = 20) + resistance_flags = FIRE_PROOF|ACID_PROOF + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + siemens_coefficient = 0 + complexity_max = DEFAULT_MAX_COMPLEXITY + 5 + slowdown_inactive = 0.75 + slowdown_active = 0.25 + skins = list( + "magnate" = list( + HELMET_LAYER = NECK_LAYER, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/cosmohonk + name = "cosmohonk" + desc = "A suit by Honk Ltd. Protects against low humor environments. Most of the tech went to lower the power cost." + default_skin = "cosmohonk" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 10, BIO = 100, FIRE = 60, ACID = 30, WOUND = 5) + cell_drain = DEFAULT_CELL_DRAIN * 0.25 + slowdown_inactive = 1.75 + slowdown_active = 1.25 + skins = list( + "cosmohonk" = list( + HELMET_LAYER = NECK_LAYER, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, + SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/syndicate + name = "syndicate" + desc = "A suit designed by Gorlex Marauders, offering armor ruled illegal in most of Spinward Stellar." + default_skin = "syndicate" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 35, BIO = 100, FIRE = 50, ACID = 90, WOUND = 25) + max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT + siemens_coefficient = 0 + slowdown_inactive = 1 + slowdown_active = 0.5 + ui_theme = "syndicate" + inbuilt_modules = list(/obj/item/mod/module/armor_booster) + skins = list( + "syndicate" = list( + HELMET_LAYER = NECK_LAYER, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/elite + name = "elite" + desc = "An elite suit upgraded by Cybersun Industries, offering upgraded armor values." + default_skin = "elite" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 55, BIO = 100, FIRE = 100, ACID = 100, WOUND = 25) + resistance_flags = FIRE_PROOF|ACID_PROOF + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + siemens_coefficient = 0 + slowdown_inactive = 0.75 + slowdown_active = 0.25 + ui_theme = "syndicate" + inbuilt_modules = list(/obj/item/mod/module/armor_booster/elite) + skins = list( + "elite" = list( + HELMET_LAYER = null, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/enchanted + name = "enchanted" + desc = "The Wizard Federation's relatively low-tech MODsuit. Is very protective, though." + default_skin = "enchanted" + armor = list(MELEE = 40, BULLET = 40, LASER = 40, ENERGY = 50, BOMB = 35, BIO = 100, FIRE = 100, ACID = 100, WOUND = 30) + resistance_flags = FIRE_PROOF|ACID_PROOF + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + siemens_coefficient = 0 + complexity_max = DEFAULT_MAX_COMPLEXITY - 5 + slowdown_inactive = 0.75 + slowdown_active = 0.25 + ui_theme = "wizard" + inbuilt_modules = list(/obj/item/mod/module/anti_magic/wizard) + skins = list( + "enchanted" = list( + HELMET_LAYER = null, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/prototype + name = "prototype" + desc = "A prototype modular suit powered by locomotives. While it is comfortable and has a big capacity, it remains very bulky and power-inefficient." + default_skin = "prototype" + armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 50, BIO = 100, FIRE = 100, ACID = 75, WOUND = 5) + resistance_flags = FIRE_PROOF + complexity_max = DEFAULT_MAX_COMPLEXITY + 10 + slowdown_inactive = 2.5 + slowdown_active = 2 + ui_theme = "hackerman" + inbuilt_modules = list(/obj/item/mod/module/kinesis) + skins = list( + "prototype" = list( + HELMET_LAYER = null, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/responsory + name = "responsory" + desc = "A high-speed rescue suit by Nanotrasen, intended for its' emergency response teams." + default_skin = "responsory" + armor = list(MELEE = 35, BULLET = 30, LASER = 30, ENERGY = 40, BOMB = 50, BIO = 100, FIRE = 100, ACID = 90, WOUND = 15) + resistance_flags = FIRE_PROOF + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + siemens_coefficient = 0 + slowdown_inactive = 0.5 + slowdown_active = 0 + skins = list( + "responsory" = list( + HELMET_LAYER = NECK_LAYER, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT, + SEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + "inquisitory" = list( + HELMET_LAYER = null, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT, + UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/apocryphal + name = "apocryphal" + desc = "A high-tech, only technically legal, armored suit created by a collaboration effort between Nanotrasen and Apadyne Technologies." + default_skin = "apocryphal" + armor = list(MELEE = 80, BULLET = 80, LASER = 50, ENERGY = 60, BOMB = 100, BIO = 100, FIRE = 100, ACID = 100, WOUND = 25) + resistance_flags = FIRE_PROOF|ACID_PROOF + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + siemens_coefficient = 0 + complexity_max = DEFAULT_MAX_COMPLEXITY + 10 + skins = list( + "apocryphal" = list( + HELMET_LAYER = null, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEEARS|HIDEHAIR, + SEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEMASK|HIDEEYES|HIDEFACE|HIDESNOUT, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/corporate + name = "corporate" + desc = "A fancy, high-tech suit for Nanotrasen's high ranking officers." + default_skin = "corporate" + armor = list(MELEE = 35, BULLET = 40, LASER = 40, ENERGY = 50, BOMB = 50, BIO = 100, FIRE = 100, ACID = 100, WOUND = 15) + resistance_flags = FIRE_PROOF|ACID_PROOF + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + siemens_coefficient = 0 + slowdown_inactive = 0.5 + slowdown_active = 0 + skins = list( + "corporate" = list( + HELMET_LAYER = null, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, + SEALED_INVISIBILITY = HIDEMASK|HIDEEYES|HIDEFACE, + SEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/debug + name = "debug" + desc = "Strangely nostalgic." + default_skin = "debug" + armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 100, BIO = 100, FIRE = 100, ACID = 100, WOUND = 0) + resistance_flags = FIRE_PROOF|ACID_PROOF + max_heat_protection_temperature = FIRE_SUIT_MAX_TEMP_PROTECT + complexity_max = 50 + slowdown_inactive = 0.5 + slowdown_active = 0 + skins = list( + "debug" = list( + HELMET_LAYER = null, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE, + UNSEALED_COVER = HEADCOVERSMOUTH, + SEALED_COVER = HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL, + SEALED_CLOTHING = STOPSPRESSUREDAMAGE, + ), + ), + ) + +/datum/mod_theme/administrative + name = "administrative" + desc = "A suit made of adminium. Who comes up with these stupid mineral names?" + default_skin = "debug" + armor = list(MELEE = 100, BULLET = 100, LASER = 100, ENERGY = 100, BOMB = 100, BIO = 100, FIRE = 100, ACID = 100, WOUND = 100) + resistance_flags = INDESTRUCTIBLE|LAVA_PROOF|FIRE_PROOF|UNACIDABLE|ACID_PROOF + max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT + complexity_max = 1000 + cell_drain = DEFAULT_CELL_DRAIN * 0 + slowdown_inactive = 0 + slowdown_active = 0 + skins = list( + "debug" = list( + HELMET_LAYER = null, + HELMET_FLAGS = list( + UNSEALED_CLOTHING = SNUG_FIT|THICKMATERIAL|STOPSPRESSUREDAMAGE, + UNSEALED_INVISIBILITY = HIDEFACIALHAIR|HIDEEARS|HIDEHAIR|HIDESNOUT, + SEALED_INVISIBILITY = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE, + UNSEALED_COVER = HEADCOVERSMOUTH|HEADCOVERSEYES|PEPPERPROOF, + ), + CHESTPLATE_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE|BLOCKS_SHOVE_KNOCKDOWN, + SEALED_INVISIBILITY = HIDEJUMPSUIT, + ), + GAUNTLETS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + ), + BOOTS_FLAGS = list( + UNSEALED_CLOTHING = THICKMATERIAL|STOPSPRESSUREDAMAGE, + ), + ), + ) diff --git a/code/modules/mod/mod_types.dm b/code/modules/mod/mod_types.dm new file mode 100644 index 00000000000..af482e50f43 --- /dev/null +++ b/code/modules/mod/mod_types.dm @@ -0,0 +1,157 @@ +/obj/item/mod/control/pre_equipped + cell = /obj/item/stock_parts/cell/high + var/applied_skin + +/obj/item/mod/control/pre_equipped/Initialize(mapload, new_theme, new_skin) + new_skin = applied_skin + return ..() + +/obj/item/mod/control/pre_equipped/standard + initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/flashlight) + +/obj/item/mod/control/pre_equipped/engineering + theme = /datum/mod_theme/engineering + initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/rad_protection, /obj/item/mod/module/flashlight, /obj/item/mod/module/magboot) + +/obj/item/mod/control/pre_equipped/atmospheric + theme = /datum/mod_theme/atmospheric + initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/rad_protection, /obj/item/mod/module/flashlight, /obj/item/mod/module/t_ray) + +/obj/item/mod/control/pre_equipped/advanced + theme = /datum/mod_theme/advanced + cell = /obj/item/stock_parts/cell/super + initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/welding, /obj/item/mod/module/rad_protection, /obj/item/mod/module/jetpack, /obj/item/mod/module/flashlight) + +/obj/item/mod/control/pre_equipped/mining + theme = /datum/mod_theme/mining + cell = /obj/item/stock_parts/cell/high/plus + initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/welding, /obj/item/mod/module/orebag, /obj/item/mod/module/flashlight, /obj/item/mod/module/magboot, /obj/item/mod/module/drill) + +/obj/item/mod/control/pre_equipped/medical + theme = /datum/mod_theme/medical + initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/flashlight, /obj/item/mod/module/health_analyzer, /obj/item/mod/module/quick_carry) + +/obj/item/mod/control/pre_equipped/rescue + theme = /datum/mod_theme/rescue + cell = /obj/item/stock_parts/cell/super + initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/flashlight, /obj/item/mod/module/health_analyzer, /obj/item/mod/module/injector) + +/obj/item/mod/control/pre_equipped/research + theme = /datum/mod_theme/research + cell = /obj/item/stock_parts/cell/super + initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/welding, /obj/item/mod/module/flashlight, /obj/item/mod/module/circuit, /obj/item/mod/module/t_ray) + +/obj/item/mod/control/pre_equipped/security + theme = /datum/mod_theme/security + initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/flashlight, /obj/item/mod/module/holster) + +/obj/item/mod/control/pre_equipped/safeguard + theme = /datum/mod_theme/safeguard + cell = /obj/item/stock_parts/cell/super + initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/welding, /obj/item/mod/module/flashlight, /obj/item/mod/module/jetpack, /obj/item/mod/module/holster) + +/obj/item/mod/control/pre_equipped/magnate + theme = /datum/mod_theme/magnate + cell = /obj/item/stock_parts/cell/hyper + initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/welding, /obj/item/mod/module/holster, /obj/item/mod/module/pathfinder) + +/obj/item/mod/control/pre_equipped/traitor + theme = /datum/mod_theme/syndicate + cell = /obj/item/stock_parts/cell/super + initial_modules = list(/obj/item/mod/module/storage/syndicate, /obj/item/mod/module/welding, /obj/item/mod/module/tether, /obj/item/mod/module/pathfinder, /obj/item/mod/module/flashlight, /obj/item/mod/module/dna_lock) + +/obj/item/mod/control/pre_equipped/nuclear + theme = /datum/mod_theme/syndicate + cell = /obj/item/stock_parts/cell/hyper + initial_modules = list(/obj/item/mod/module/storage/syndicate, /obj/item/mod/module/welding, /obj/item/mod/module/jetpack, /obj/item/mod/module/visor/thermal, /obj/item/mod/module/flashlight, /obj/item/mod/module/holster) + +/obj/item/mod/control/pre_equipped/elite + theme = /datum/mod_theme/elite + cell = /obj/item/stock_parts/cell/bluespace + initial_modules = list(/obj/item/mod/module/storage/syndicate, /obj/item/mod/module/welding, /obj/item/mod/module/emp_shield, /obj/item/mod/module/jetpack, /obj/item/mod/module/visor/thermal, /obj/item/mod/module/flashlight, /obj/item/mod/module/holster) + +/obj/item/mod/control/pre_equipped/enchanted + theme = /datum/mod_theme/enchanted + cell = /obj/item/stock_parts/cell/crystal_cell/wizard + initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/energy_shield/wizard, /obj/item/mod/module/emp_shield) + +/obj/item/mod/control/pre_equipped/prototype + theme = /datum/mod_theme/prototype + cell = /obj/item/stock_parts/cell/high/plus + initial_modules = list(/obj/item/mod/module/storage, /obj/item/mod/module/welding, /obj/item/mod/module/rad_protection, /obj/item/mod/module/flashlight, /obj/item/mod/module/tether) + +/obj/item/mod/control/pre_equipped/responsory + theme = /datum/mod_theme/responsory + cell = /obj/item/stock_parts/cell/hyper + initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/welding, /obj/item/mod/module/emp_shield, /obj/item/mod/module/flashlight, /obj/item/mod/module/holster) + var/insignia_type = /obj/item/mod/module/insignia + +/obj/item/mod/control/pre_equipped/responsory/Initialize(mapload, new_theme, new_skin) + initial_modules.Insert(1, insignia_type) + return ..() + +/obj/item/mod/control/pre_equipped/responsory/commander + insignia_type = /obj/item/mod/module/insignia/commander + +/obj/item/mod/control/pre_equipped/responsory/security + insignia_type = /obj/item/mod/module/insignia/security + +/obj/item/mod/control/pre_equipped/responsory/engineer + insignia_type = /obj/item/mod/module/insignia/engineer + +/obj/item/mod/control/pre_equipped/responsory/medic + insignia_type = /obj/item/mod/module/insignia/medic + +/obj/item/mod/control/pre_equipped/responsory/janitor + insignia_type = /obj/item/mod/module/insignia/janitor + +/obj/item/mod/control/pre_equipped/responsory/clown + insignia_type = /obj/item/mod/module/insignia/clown + +/obj/item/mod/control/pre_equipped/responsory/chaplain + insignia_type = /obj/item/mod/module/insignia/chaplain + +/obj/item/mod/control/pre_equipped/responsory/inquisitory + initial_modules = list(/obj/item/mod/module/storage/large_capacity, /obj/item/mod/module/anti_magic, /obj/item/mod/module/welding, /obj/item/mod/module/emp_shield, /obj/item/mod/module/flashlight, /obj/item/mod/module/holster) + applied_skin = "inquisitory" + +/obj/item/mod/control/pre_equipped/responsory/inquisitory/commander + insignia_type = /obj/item/mod/module/insignia/commander + +/obj/item/mod/control/pre_equipped/responsory/inquisitory/security + insignia_type = /obj/item/mod/module/insignia/security + +/obj/item/mod/control/pre_equipped/responsory/inquisitory/medic + insignia_type = /obj/item/mod/module/insignia/medic + +/obj/item/mod/control/pre_equipped/responsory/inquisitory/chaplain + insignia_type = /obj/item/mod/module/insignia/chaplain + +/obj/item/mod/control/pre_equipped/apocryphal + theme = /datum/mod_theme/apocryphal + cell = /obj/item/stock_parts/cell/bluespace + initial_modules = list(/obj/item/mod/module/storage/bluespace, /obj/item/mod/module/welding, /obj/item/mod/module/emp_shield, /obj/item/mod/module/jetpack, /obj/item/mod/module/holster) + +/obj/item/mod/control/pre_equipped/corporate + theme = /datum/mod_theme/corporate + cell = /obj/item/stock_parts/cell/bluespace + initial_modules = list(/obj/item/mod/module/storage/bluespace, /obj/item/mod/module/holster) + +/obj/item/mod/control/pre_equipped/debug + theme = /datum/mod_theme/debug + cell = /obj/item/stock_parts/cell/bluespace + initial_modules = list(/obj/item/mod/module/storage/bluespace, /obj/item/mod/module/welding, /obj/item/mod/module/flashlight, /obj/item/mod/module/bikehorn, /obj/item/mod/module/rad_protection, /obj/item/mod/module/tether, /obj/item/mod/module/injector) //one of every type of module, for testing if they all work correctly + +/obj/item/mod/control/pre_equipped/administrative + theme = /datum/mod_theme/administrative + cell = /obj/item/stock_parts/cell/infinite/abductor + initial_modules = list(/obj/item/mod/module/storage/bluespace, /obj/item/mod/module/welding, /obj/item/mod/module/stealth/ninja, /obj/item/mod/module/quick_carry/advanced, /obj/item/mod/module/magboot/advanced, /obj/item/mod/module/jetpack) + +//these exist for the prefs menu +/obj/item/mod/control/pre_equipped/syndicate_empty + theme = /datum/mod_theme/syndicate + +/obj/item/mod/control/pre_equipped/syndicate_empty/elite + theme = /datum/mod_theme/elite + +INITIALIZE_IMMEDIATE(/obj/item/mod/control/pre_equipped/syndicate_empty) diff --git a/code/modules/mod/mod_ui.dm b/code/modules/mod/mod_ui.dm new file mode 100644 index 00000000000..1e719e93ebe --- /dev/null +++ b/code/modules/mod/mod_ui.dm @@ -0,0 +1,80 @@ +/obj/item/mod/control/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "MODsuit", name) + ui.open() + +/obj/item/mod/control/ui_data() + var/data = list() + data["interface_break"] = interface_break + data["malfunctioning"] = malfunctioning + data["open"] = open + data["active"] = active + data["locked"] = locked + data["complexity"] = complexity + data["selected_module"] = selected_module?.name + data["wearer_name"] = wearer ? (wearer.get_authentification_name("Unknown") || "Unknown") : "No Occupant" + data["wearer_job"] = wearer ? wearer.get_assignment("Unknown", "Unknown", FALSE) : "No Job" + data["AI"] = ai?.name + data["cell"] = cell?.name + data["charge"] = cell ? round(cell.percent(), 1) : 0 + data["modules"] = list() + for(var/obj/item/mod/module/module as anything in modules) + var/list/module_data = list( + name = module.name, + description = module.desc, + module_type = module.module_type, + active = module.active, + idle_power = module.idle_power_cost, + active_power = module.active_power_cost, + use_power = module.use_power_cost, + complexity = module.complexity, + cooldown_time = module.cooldown_time, + cooldown = round(COOLDOWN_TIMELEFT(module, cooldown_timer), 1 SECONDS), + id = module.tgui_id, + ref = REF(module), + configuration_data = module.get_configuration() + ) + module_data += module.add_ui_data() + data["modules"] += list(module_data) + return data + +/obj/item/mod/control/ui_static_data(mob/user) + var/data = list() + data["ui_theme"] = ui_theme + data["control"] = name + data["complexity_max"] = complexity_max + data["helmet"] = helmet?.name + data["chestplate"] = chestplate?.name + data["gauntlets"] = gauntlets?.name + data["boots"] = boots?.name + return data + +/obj/item/mod/control/ui_act(action, params) + . = ..() + if(.) + return + if(!allowed(usr) && locked) + balloon_alert(usr, "insufficient access!") + playsound(src, 'sound/machines/scanbuzz.ogg', 25, TRUE, SILENCED_SOUND_EXTRARANGE) + return + if(malfunctioning && prob(75)) + balloon_alert(usr, "button malfunctions!") + return + switch(action) + if("lock") + locked = !locked + balloon_alert(usr, "[locked ? "locked" : "unlocked"]!") + if("activate") + toggle_activate(usr) + if("select") + var/obj/item/mod/module/module = locate(params["ref"]) in modules + if(!module) + return + module.on_select() + if("configure") + var/obj/item/mod/module/module = locate(params["ref"]) in modules + if(!module) + return + module.configure_edit(params["key"], params["value"]) + return TRUE diff --git a/code/modules/mod/modules/_module.dm b/code/modules/mod/modules/_module.dm new file mode 100644 index 00000000000..a310f955373 --- /dev/null +++ b/code/modules/mod/modules/_module.dm @@ -0,0 +1,252 @@ +/obj/item/mod/module + name = "MOD module" + icon_state = "module" + /// If it can be removed + var/removable = TRUE + /// If it's passive, togglable, usable or active + var/module_type = MODULE_PASSIVE + /// Is the module active + var/active = FALSE + /// How much space it takes up in the MOD + var/complexity = 0 + /// Power use when idle + var/idle_power_cost = DEFAULT_CELL_DRAIN * 0 + /// Power use when active + var/active_power_cost = DEFAULT_CELL_DRAIN * 0 + /// Power use when used, we call it manually + var/use_power_cost = DEFAULT_CELL_DRAIN * 0 + /// ID used by their TGUI + var/tgui_id + /// Linked MODsuit + var/obj/item/mod/control/mod + /// If we're an active module, what item are we? + var/obj/item/device + /// Overlay given to the user when the module is inactive + var/overlay_state_inactive + /// Overlay given to the user when the module is active + var/overlay_state_active + /// Overlay given to the user when the module is used, lasts until cooldown finishes + var/overlay_state_use + /// What modules are we incompatible with? + var/list/incompatible_modules = list() + /// Cooldown after use + var/cooldown_time = 0 + /// The mouse button needed to use this module + var/used_signal + /// Timer for the cooldown + COOLDOWN_DECLARE(cooldown_timer) + +/obj/item/mod/module/Initialize(mapload) + . = ..() + if(module_type != MODULE_ACTIVE) + return + if(ispath(device)) + device = new device(src) + ADD_TRAIT(device, TRAIT_NODROP, MOD_TRAIT) + RegisterSignal(device, COMSIG_PARENT_PREQDELETED, .proc/on_device_deletion) + RegisterSignal(src, COMSIG_ATOM_EXITED, .proc/on_exit) + +/obj/item/mod/module/Destroy() + mod?.uninstall(src) + if(device) + UnregisterSignal(device, COMSIG_PARENT_PREQDELETED) + QDEL_NULL(device) + return ..() + +/obj/item/mod/module/examine(mob/user) + . = ..() + if(HAS_TRAIT(user, TRAIT_DIAGNOSTIC_HUD)) + . += span_notice("Complexity level: [complexity]") + +/// Called from MODsuit's install() proc, so when the module is installed. +/obj/item/mod/module/proc/on_install() + return + +/// Called from MODsuit's uninstall() proc, so when the module is uninstalled. +/obj/item/mod/module/proc/on_uninstall() + return + +/// Called when the MODsuit is activated +/obj/item/mod/module/proc/on_suit_activation() + return + +/// Called when the MODsuit is deactivated +/obj/item/mod/module/proc/on_suit_deactivation() + return + +/// Called when the MODsuit is equipped +/obj/item/mod/module/proc/on_equip() + return + +/// Called when the MODsuit is unequipped +/obj/item/mod/module/proc/on_unequip() + return + +/// Called when the module is selected from the TGUI +/obj/item/mod/module/proc/on_select() + if(!mod.active || mod.activating || module_type == MODULE_PASSIVE) + return + if(module_type != MODULE_USABLE) + if(active) + on_deactivation() + else + on_activation() + else + on_use() + SEND_SIGNAL(mod, COMSIG_MOD_MODULE_SELECTED) + +/// Called when the module is activated +/obj/item/mod/module/proc/on_activation() + if(!COOLDOWN_FINISHED(src, cooldown_timer)) + balloon_alert(mod.wearer, "on cooldown!") + return FALSE + if(!mod.active || mod.activating || !mod.cell?.charge) + balloon_alert(mod.wearer, "unpowered!") + return FALSE + if(module_type == MODULE_ACTIVE) + if(mod.selected_module && !mod.selected_module.on_deactivation()) + return + mod.selected_module = src + if(device) + if(mod.wearer.put_in_hands(device)) + balloon_alert(mod.wearer, "[device] extended") + RegisterSignal(mod.wearer, COMSIG_ATOM_EXITED, .proc/on_exit) + else + balloon_alert(mod.wearer, "can't extend [device]!") + return + else + var/used_button = mod.wearer.client?.prefs.read_preference(/datum/preference/choiced/mod_select) || MIDDLE_CLICK + update_signal(used_button) + balloon_alert(mod.wearer, "[src] activated, [used_button]-click to use") + active = TRUE + COOLDOWN_START(src, cooldown_timer, cooldown_time) + mod.wearer.update_inv_back() + return TRUE + +/// Called when the module is deactivated +/obj/item/mod/module/proc/on_deactivation() + active = FALSE + if(module_type == MODULE_ACTIVE) + mod.selected_module = null + if(device) + mod.wearer.transferItemToLoc(device, src, TRUE) + balloon_alert(mod.wearer, "[device] retracted") + UnregisterSignal(mod.wearer, COMSIG_ATOM_EXITED) + else + balloon_alert(mod.wearer, "[src] deactivated") + UnregisterSignal(mod.wearer, used_signal) + used_signal = null + mod.wearer.update_inv_back() + return TRUE + +/// Called when the module is used +/obj/item/mod/module/proc/on_use() + if(!COOLDOWN_FINISHED(src, cooldown_timer)) + return FALSE + if(!check_power(use_power_cost)) + return FALSE + COOLDOWN_START(src, cooldown_timer, cooldown_time) + addtimer(CALLBACK(mod.wearer, /mob.proc/update_inv_back), cooldown_time) + mod.wearer.update_inv_back() + return TRUE + +/// Called when an activated module without a device is used +/obj/item/mod/module/proc/on_select_use(atom/target) + mod.wearer.face_atom(target) + if(!on_use()) + return FALSE + return TRUE + +/// Called when an activated module without a device is active and the user alt/middle-clicks +/obj/item/mod/module/proc/on_special_click(mob/source, atom/target) + SIGNAL_HANDLER + on_select_use(target) + return COMSIG_MOB_CANCEL_CLICKON + +/// Called on the MODsuit's process +/obj/item/mod/module/proc/on_process(delta_time) + if(active) + if(!drain_power(active_power_cost * delta_time)) + on_deactivation() + return FALSE + on_active_process(delta_time) + else + drain_power(idle_power_cost * delta_time) + return TRUE + +/// Called on the MODsuit's process if it is an active module +/obj/item/mod/module/proc/on_active_process(delta_time) + return + +/// Drains power from the suit cell +/obj/item/mod/module/proc/drain_power(amount) + if(!check_power(amount)) + return FALSE + mod.cell.charge = max(0, mod.cell.charge - amount) + return TRUE + +/obj/item/mod/module/proc/check_power(amount) + if(!mod.cell || (mod.cell.charge < amount)) + return FALSE + return TRUE + +/// Adds additional things to the MODsuit ui_data() +/obj/item/mod/module/proc/add_ui_data() + return list() + +/// Creates a list of configuring options for this module +/obj/item/mod/module/proc/get_configuration() + return list() + +/// Generates an element of the get_configuration list with a display name, type and value +/obj/item/mod/module/proc/add_ui_configuration(display_name, type, value, list/values) + return list("display_name" = display_name, "type" = type, "value" = value, "values" = values) + +/// Receives configure edits from the TGUI and edits the vars +/obj/item/mod/module/proc/configure_edit(key, value) + return + +/// Called when the device moves to a different place on active modules +/obj/item/mod/module/proc/on_exit(datum/source, atom/movable/part, direction) + SIGNAL_HANDLER + + if(!active) + return + if(part.loc == src) + return + if(part.loc == mod.wearer) + return + if(part == device) + on_deactivation() + +/// Called when the device gets deleted on active modules +/obj/item/mod/module/proc/on_device_deletion(datum/source) + SIGNAL_HANDLER + + if(source == device) + device = null + qdel(src) + +/// Generates an icon to be used for the suit's worn overlays +/obj/item/mod/module/proc/generate_worn_overlay(mutable_appearance/standing) + . = list() + var/used_overlay + if(overlay_state_use && !COOLDOWN_FINISHED(src, cooldown_timer)) + used_overlay = overlay_state_use + else if(overlay_state_active && active) + used_overlay = overlay_state_active + else if(overlay_state_inactive) + used_overlay = overlay_state_inactive + else + return + var/mutable_appearance/module_icon = mutable_appearance('icons/mob/mod.dmi', used_overlay, layer = standing.layer + 0.1) + . += module_icon + +/// Updates the signal used by active modules to be activated +/obj/item/mod/module/proc/update_signal(value) + switch(value) + if(MIDDLE_CLICK) + mod.selected_module.used_signal = COMSIG_MOB_MIDDLECLICKON + if(ALT_CLICK) + mod.selected_module.used_signal = COMSIG_MOB_ALTCLICKON + RegisterSignal(mod.wearer, mod.selected_module.used_signal, /obj/item/mod/module.proc/on_special_click) diff --git a/code/modules/mod/modules/modules.dm b/code/modules/mod/modules/modules.dm new file mode 100644 index 00000000000..db59418a810 --- /dev/null +++ b/code/modules/mod/modules/modules.dm @@ -0,0 +1,1773 @@ +/obj/item/mod/module/storage + name = "MOD storage module" + desc = "What amounts to a series of integrated storage compartments and specialized pockets installed across \ + the surface of the suit, useful for storing various bits, and or bobs." + icon_state = "storage" + complexity = 3 + incompatible_modules = list(/obj/item/mod/module/storage) + var/datum/component/storage/concrete/storage + var/max_w_class = WEIGHT_CLASS_NORMAL + var/max_combined_w_class = 15 + var/max_items = 7 + +/obj/item/mod/module/storage/Initialize(mapload) + . = ..() + storage = AddComponent(/datum/component/storage/concrete) + storage.max_w_class = max_w_class + storage.max_combined_w_class = max_combined_w_class + storage.max_items = max_items + storage.allow_big_nesting = TRUE + SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, TRUE) + +/obj/item/mod/module/storage/on_install() + var/datum/component/storage/modstorage = mod.AddComponent(/datum/component/storage, storage) + modstorage.max_w_class = max_w_class + modstorage.max_combined_w_class = max_combined_w_class + modstorage.max_items = max_items + SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, FALSE) + +/obj/item/mod/module/storage/on_uninstall() + var/datum/component/storage/modstorage = mod.GetComponent(/datum/component/storage) + storage.slaves -= modstorage + qdel(modstorage) + SEND_SIGNAL(src, COMSIG_TRY_STORAGE_SET_LOCKSTATE, TRUE) + +/obj/item/mod/module/storage/large_capacity + name = "MOD expanded storage module" + desc = "Reverse engineered by Nakamura Engineering from Donk Corporation designs, this system of hidden compartments \ + is entirely within the suit, distributing items and weight evenly to ensure a comfortable experience for the user; \ + whether smuggling, or simply hauling." + icon_state = "storage_large" + max_combined_w_class = 21 + max_items = 14 + +/obj/item/mod/module/storage/syndicate + name = "MOD syndicate storage module" + desc = "A storage system using nanotechnology developed by Cybersun Industries, these compartments use \ + esoteric technology to compress the physical matter of items put inside of them, \ + essentially shrinking items for much easier and more portable storage." + icon_state = "storage_syndi" + max_combined_w_class = 30 + max_items = 21 + +/obj/item/mod/module/storage/bluespace + name = "MOD bluespace storage module" + desc = "A storage system developed by Nanotrasen, these compartments employ \ + miniaturized bluespace pockets for the ultimate in storage technology; regardless of the weight of objects put inside." + icon_state = "storage_large" + max_w_class = WEIGHT_CLASS_GIGANTIC + max_combined_w_class = 60 + max_items = 21 + +/obj/item/mod/module/visor + name = "MOD visor module" + desc = "A heads-up display installed into the visor of the suit. They say these also let you see behind you." + module_type = MODULE_TOGGLE + complexity = 2 + active_power_cost = DEFAULT_CELL_DRAIN*0.3 + incompatible_modules = list(/obj/item/mod/module/visor) + cooldown_time = 0.5 SECONDS + var/hud_type + var/list/visor_traits = list() + +/obj/item/mod/module/visor/on_activation() + . = ..() + if(!.) + return + if(hud_type) + var/datum/atom_hud/hud = GLOB.huds[hud_type] + hud.add_hud_to(mod.wearer) + for(var/trait in visor_traits) + ADD_TRAIT(mod.wearer, trait, MOD_TRAIT) + mod.wearer.update_sight() + +/obj/item/mod/module/visor/on_deactivation() + . = ..() + if(!.) + return + if(hud_type) + var/datum/atom_hud/hud = GLOB.huds[hud_type] + hud.remove_hud_from(mod.wearer) + for(var/trait in visor_traits) + REMOVE_TRAIT(mod.wearer, trait, MOD_TRAIT) + mod.wearer.update_sight() + +/obj/item/mod/module/visor/medhud + name = "MOD medical visor module" + desc = "A heads-up display installed into the visor of the suit. This cross-references suit sensor data with a modern \ + biological scanning suite, allowing the user to visualize the current health of organic lifeforms, as well as \ + access data such as patient files in a convenient readout. They say these also let you see behind you." + icon_state = "medhud_visor" + hud_type = DATA_HUD_MEDICAL_ADVANCED + visor_traits = list(TRAIT_MEDICAL_HUD) + +/obj/item/mod/module/visor/diaghud + name = "MOD diagnostic visor module" + desc = "A heads-up display installed into the visor of the suit. This uses a series of advanced sensors to access data \ + from advanced machinery, exosuits, and other devices, allowing the user to visualize current power levels \ + and integrity of such. They say these also let you see behind you." + icon_state = "diaghud_visor" + hud_type = DATA_HUD_DIAGNOSTIC_ADVANCED + visor_traits = list(TRAIT_DIAGNOSTIC_HUD) + +/obj/item/mod/module/visor/sechud + name = "MOD security visor module" + desc = "A heads-up display installed into the visor of the suit. This module is a heavily-retrofitted targeting system, \ + plugged into various criminal databases to be able to view arrest records, command simple security-oriented robots, \ + and generally know who to shoot. They say these also let you see behind you." + icon_state = "sechud_visor" + hud_type = DATA_HUD_SECURITY_ADVANCED + visor_traits = list(TRAIT_SECURITY_HUD) + +/obj/item/mod/module/visor/meson + name = "MOD meson visor module" + desc = "A heads-up display installed into the visor of the suit. This module is based off well-loved meson scanner \ + technology, used by construction workers and miners across the galaxy to see basic structural and terrain layouts \ + through walls, regardless of lighting conditions. They say these also let you see behind you." + icon_state = "meson_visor" + visor_traits = list(TRAIT_MESON_VISION, TRAIT_SUPERMATTER_MADNESS_IMMUNE) + +/obj/item/mod/module/visor/thermal + name = "MOD thermal visor module" + desc = "A heads-up display installed into the visor of the suit. This uses a small IR scanner to detect and identify \ + the thermal radiation output of objects near the user. While it can detect the heat output of even something as \ + small as a rodent, it still produces irritating red overlay. They say these also let you see behind you." + icon_state = "thermal_visor" + visor_traits = list(TRAIT_THERMAL_VISION) + +/obj/item/mod/module/visor/night + name = "MOD night visor module" + desc = "A heads-up display installed into the visor of the suit. Typical for both civilian and military applications, \ + this allows the user to perceive their surroundings while in complete darkness, enhancing the view by tenfold; \ + yet brightening everything into a spooky green glow. They say these also let you see behind you." + icon_state = "night_visor" + visor_traits = list(TRAIT_TRUE_NIGHT_VISION) + +/obj/item/mod/module/welding + name = "MOD welding protection module" + desc = "A module installed into the visor of the suit, this projects a \ + polarized, holographic overlay in front of the user's eyes. It's rated high enough for \ + immunity against extremities such as spot and arc welding, solar eclipses, and handheld flashlights." + icon_state = "welding" + complexity = 1 + incompatible_modules = list(/obj/item/mod/module/welding) + overlay_state_inactive = "module_welding" + +/obj/item/mod/module/welding/on_suit_activation() + mod.helmet.flash_protect = FLASH_PROTECTION_WELDER + +/obj/item/mod/module/welding/on_suit_deactivation() + mod.helmet.flash_protect = initial(mod.helmet.flash_protect) + +/obj/item/mod/module/t_ray + name = "MOD t-ray scan module" + desc = "A module installed into the visor of the suit, allowing the user to use a pulse of terahertz radiation \ + to essentially echolocate things beneath the floor, mostly cables and pipes. \ + A staple of atmospherics work, and counter-smuggling work." + icon_state = "tray" + module_type = MODULE_TOGGLE + complexity = 2 + active_power_cost = DEFAULT_CELL_DRAIN * 0.2 + incompatible_modules = list(/obj/item/mod/module/t_ray) + cooldown_time = 0.5 SECONDS + var/range = 2 + +/obj/item/mod/module/t_ray/on_active_process(delta_time) + t_ray_scan(mod.wearer, 8, range) + +#define HEALTH_SCAN "Health" +#define WOUND_SCAN "Wound" +#define CHEM_SCAN "Chemical" + +/obj/item/mod/module/health_analyzer + name = "MOD health analyzer module" + desc = "A module installed into the glove of the suit. This is a high-tech biological scanning suite, \ + allowing the user indepth information on the vitals and injuries of others even at a distance, \ + all with the flick of the wrist. Data is displayed in a convenient package on HUD in the helmet, \ + but it's up to you to do something with it." + icon_state = "health" + module_type = MODULE_ACTIVE + complexity = 2 + use_power_cost = DEFAULT_CELL_DRAIN + incompatible_modules = list(/obj/item/mod/module/health_analyzer) + cooldown_time = 0.5 SECONDS + var/mode = HEALTH_SCAN + var/static/list/modes = list(HEALTH_SCAN, WOUND_SCAN, CHEM_SCAN) + +/obj/item/mod/module/health_analyzer/on_select_use(atom/target) + . = ..() + if(!.) + return + if(!isliving(target)) + return + switch(mode) + if(HEALTH_SCAN) + healthscan(mod.wearer, target) + if(WOUND_SCAN) + woundscan(mod.wearer, target) + if(CHEM_SCAN) + chemscan(mod.wearer, target) + drain_power(use_power_cost) + +/obj/item/mod/module/health_analyzer/get_configuration() + . = ..() + .["mode"] = add_ui_configuration("Scan Mode", "list", mode, modes) + +/obj/item/mod/module/health_analyzer/configure_edit(key, value) + switch(key) + if("mode") + mode = value + +#undef HEALTH_SCAN +#undef WOUND_SCAN +#undef CHEM_SCAN + +/obj/item/mod/module/stealth + name = "MOD prototype cloaking module" + desc = "A complete retrofitting of the suit, this is a form of visual concealment tech employing esoteric technology \ + to bend light around the user, as well as mimetic materials to make the surface of the suit match the \ + surroundings based off sensor data. For some reason, this tech is rarely seen." + icon_state = "cloak" + module_type = MODULE_TOGGLE + complexity = 4 + active_power_cost = DEFAULT_CELL_DRAIN * 2 + use_power_cost = DEFAULT_CELL_DRAIN * 10 + incompatible_modules = list(/obj/item/mod/module/stealth) + cooldown_time = 5 SECONDS + var/bumpoff = TRUE + var/stealth_alpha = 50 + +/obj/item/mod/module/stealth/on_activation() + . = ..() + if(!.) + return + if(bumpoff) + RegisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP, .proc/unstealth) + RegisterSignal(mod.wearer, COMSIG_HUMAN_MELEE_UNARMED_ATTACK, .proc/on_unarmed_attack) + RegisterSignal(mod.wearer, COMSIG_ATOM_BULLET_ACT, .proc/on_bullet_act) + RegisterSignal(mod.wearer, list(COMSIG_ITEM_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED), .proc/unstealth) + animate(mod.wearer, alpha = stealth_alpha, time = 1.5 SECONDS) + drain_power(use_power_cost) + +/obj/item/mod/module/stealth/on_deactivation() + . = ..() + if(!.) + return + if(bumpoff) + UnregisterSignal(mod.wearer, COMSIG_LIVING_MOB_BUMP) + UnregisterSignal(mod.wearer, list(COMSIG_HUMAN_MELEE_UNARMED_ATTACK, COMSIG_ITEM_ATTACK, COMSIG_PARENT_ATTACKBY, COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_BULLET_ACT, COMSIG_ATOM_HITBY, COMSIG_ATOM_HULK_ATTACK, COMSIG_ATOM_ATTACK_PAW, COMSIG_CARBON_CUFF_ATTEMPTED)) + animate(mod.wearer, alpha = 255, time = 1.5 SECONDS) + +/obj/item/mod/module/stealth/proc/unstealth(datum/source) + SIGNAL_HANDLER + + to_chat(mod.wearer, span_warning("[src] gets discharged from contact!")) + do_sparks(2, TRUE, src) + drain_power(use_power_cost) + on_deactivation() + +/obj/item/mod/module/stealth/proc/on_unarmed_attack(datum/source, atom/target) + SIGNAL_HANDLER + + if(!isliving(target)) + return + unstealth(source) + +/obj/item/mod/module/stealth/proc/on_bullet_act(datum/source, obj/projectile/projectile) + SIGNAL_HANDLER + + if(projectile.nodamage) + return + unstealth(source) + +/obj/item/mod/module/stealth/ninja + name = "MOD advanced cloaking module" + desc = "The latest in stealth technology, this module is a definite upgrade over previous versions. \ + The field has been tuned to be even more responsive and fast-acting, with enough stability to \ + continue operation of the field even if the user bumps into others. \ + The draw on the power cell has been reduced drastically, \ + making this perfect for activities like standing near sentry turrets for extended periods of time." + icon_state = "cloak_ninja" + bumpoff = FALSE + stealth_alpha = 20 + active_power_cost = DEFAULT_CELL_DRAIN + use_power_cost = DEFAULT_CELL_DRAIN * 5 + cooldown_time = 3 SECONDS + +/obj/item/mod/module/jetpack + name = "MOD ion jetpack module" + desc = "A series of electric thrusters installed across the suit, this is a module highly anticipated by trainee Engineers. \ + Rather than using gasses for combustion thrust, these jets are capable of accelerating ions using \ + charge from the suit's cell. Some say this isn't Nakamura Engineering's first foray into jet-enabled suits." + icon_state = "jetpack" + module_type = MODULE_TOGGLE + complexity = 3 + active_power_cost = DEFAULT_CELL_DRAIN * 0.5 + use_power_cost = DEFAULT_CELL_DRAIN + incompatible_modules = list(/obj/item/mod/module/jetpack) + cooldown_time = 0.5 SECONDS + overlay_state_inactive = "module_jetpack" + overlay_state_active = "module_jetpack_on" + var/stabilizers = FALSE + var/full_speed = FALSE + var/datum/effect_system/trail_follow/ion/ion_trail + +/obj/item/mod/module/jetpack/Initialize(mapload) + . = ..() + ion_trail = new + ion_trail.auto_process = FALSE + ion_trail.set_up(src) + +/obj/item/mod/module/jetpack/Destroy() + QDEL_NULL(ion_trail) + return ..() + +/obj/item/mod/module/jetpack/on_activation() + . = ..() + if(!.) + return + ion_trail.start() + RegisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, .proc/move_react) + RegisterSignal(mod.wearer, COMSIG_MOVABLE_PRE_MOVE, .proc/pre_move_react) + RegisterSignal(mod.wearer, COMSIG_MOVABLE_SPACEMOVE, .proc/spacemove_react) + if(full_speed) + mod.wearer.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) + +/obj/item/mod/module/jetpack/on_deactivation(mob/user) + . = ..() + if(!.) + return + ion_trail.stop() + UnregisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED) + UnregisterSignal(mod.wearer, COMSIG_MOVABLE_PRE_MOVE) + UnregisterSignal(mod.wearer, COMSIG_MOVABLE_SPACEMOVE) + if(full_speed) + mod.wearer.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/fullspeed) + +/obj/item/mod/module/jetpack/get_configuration() + . = ..() + .["stabilizers"] = add_ui_configuration("Stabilizers", "bool", stabilizers) + +/obj/item/mod/module/jetpack/configure_edit(key, value) + switch(key) + if("stabilizers") + stabilizers = text2num(value) + +/obj/item/mod/module/jetpack/proc/move_react(mob/user) + SIGNAL_HANDLER + + if(!active)//If jet dont work, it dont work + return + if(!isturf(mod.wearer.loc))//You can't use jet in nowhere or from mecha/closet + return + if(!(mod.wearer.movement_type & FLOATING) || mod.wearer.buckled)//You don't want use jet in gravity or while buckled. + return + if(mod.wearer.pulledby)//You don't must use jet if someone pull you + return + if(mod.wearer.throwing)//You don't must use jet if you thrown + return + if(user.client && length(user.client.keys_held & user.client.movement_keys))//You use jet when press keys. yes. + allow_thrust() + +/obj/item/mod/module/jetpack/proc/pre_move_react(mob/user) + SIGNAL_HANDLER + + ion_trail.oldposition = get_turf(src) + +/obj/item/mod/module/jetpack/proc/spacemove_react(mob/user, movement_dir) + SIGNAL_HANDLER + + if(active && (stabilizers || movement_dir)) + return COMSIG_MOVABLE_STOP_SPACEMOVE + +/obj/item/mod/module/jetpack/proc/allow_thrust() + if(!drain_power(use_power_cost)) + return + ion_trail.generate_effect() + return TRUE + +/obj/item/mod/module/magboot + name = "MOD magnetic stability module" + desc = "These are powerful electromagnets fitted into the suit's boots, allowing users both \ + excellent traction no matter the condition indoors, and to essentially hitch a ride on the exterior of a hull. \ + However, these basic models do not feature computerized systems to automatically toggle them on and off, \ + so numerous users report a certain stickiness to their steps." + icon_state = "magnet" + module_type = MODULE_TOGGLE + complexity = 2 + active_power_cost = DEFAULT_CELL_DRAIN * 0.5 + incompatible_modules = list(/obj/item/mod/module/magboot) + cooldown_time = 0.5 SECONDS + var/slowdown_active = 0.5 + +/obj/item/mod/module/magboot/on_activation() + . = ..() + if(!.) + return + ADD_TRAIT(mod.wearer, TRAIT_NEGATES_GRAVITY, MOD_TRAIT) + ADD_TRAIT(mod.wearer, TRAIT_NOSLIPWATER, MOD_TRAIT) + mod.slowdown += slowdown_active + mod.wearer.update_gravity(mod.wearer.has_gravity()) + mod.wearer.update_equipment_speed_mods() + +/obj/item/mod/module/magboot/on_deactivation() + . = ..() + if(!.) + return + REMOVE_TRAIT(mod.wearer, TRAIT_NEGATES_GRAVITY, MOD_TRAIT) + REMOVE_TRAIT(mod.wearer, TRAIT_NOSLIPWATER, MOD_TRAIT) + mod.slowdown -= slowdown_active + mod.wearer.update_gravity(mod.wearer.has_gravity()) + mod.wearer.update_equipment_speed_mods() + +/obj/item/mod/module/magboot/advanced + name = "MOD advanced magnetic stability module" + removable = FALSE + complexity = 0 + slowdown_active = 0 + +/obj/item/mod/module/holster + name = "MOD holster module" + desc = "Based off typical storage compartments, this system allows the suit to holster a \ + standard firearm across its surface and allow for extremely quick retrieval. \ + While some users prefer the chest, others the forearm for quick deployment, \ + some law enforcement prefer the holster to extend from the thigh." + icon_state = "holster" + module_type = MODULE_USABLE + complexity = 2 + use_power_cost = DEFAULT_CELL_DRAIN * 0.5 + incompatible_modules = list(/obj/item/mod/module/holster) + cooldown_time = 0.5 SECONDS + var/obj/item/gun/holstered + +/obj/item/mod/module/holster/on_use() + . = ..() + if(!.) + return + if(!holstered) + var/obj/item/gun/holding = mod.wearer.get_active_held_item() + if(!holding) + balloon_alert(mod.wearer, "nothing to holster!") + return + if(!istype(holding) || holding.w_class > WEIGHT_CLASS_BULKY) + balloon_alert(mod.wearer, "it doesn't fit!") + return + if(mod.wearer.transferItemToLoc(holding, src, FALSE, FALSE)) + holstered = holding + balloon_alert(mod.wearer, "weapon holstered") + playsound(src, 'sound/weapons/gun/revolver/empty.ogg', 100, TRUE) + drain_power(use_power_cost) + else if(mod.wearer.put_in_active_hand(holstered, FALSE, TRUE)) + balloon_alert(mod.wearer, "weapon drawn") + holstered = null + playsound(src, 'sound/weapons/gun/revolver/empty.ogg', 100, TRUE) + drain_power(use_power_cost) + else + balloon_alert(mod.wearer, "holster full!") + +/obj/item/mod/module/holster/on_uninstall() + if(holstered) + holstered.forceMove(drop_location()) + holstered = null + +/obj/item/mod/module/holster/Destroy() + QDEL_NULL(holstered) + return ..() + +/obj/item/mod/module/tether + name = "MOD emergency tether module" + desc = "A custom-built grappling-hook powered by a winch capable of hauling the user. \ + While some older models of cargo-oriented grapples have capacities of a few tons, \ + these are only capable of working in zero-gravity environments, a blessing to some Engineers." + icon_state = "tether" + module_type = MODULE_ACTIVE + complexity = 3 + use_power_cost = DEFAULT_CELL_DRAIN + incompatible_modules = list(/obj/item/mod/module/tether) + cooldown_time = 1.5 SECONDS + +/obj/item/mod/module/tether/on_use() + if(mod.wearer.has_gravity(get_turf(src))) + balloon_alert(mod.wearer, "too much gravity!") + playsound(src, 'sound/weapons/gun/general/dry_fire.ogg', 25, TRUE) + return FALSE + return ..() + +/obj/item/mod/module/tether/on_select_use(atom/target) + . = ..() + if(!.) + return + var/obj/projectile/tether = new /obj/projectile/tether(mod.wearer.loc) + tether.preparePixelProjectile(target, mod.wearer) + tether.firer = mod.wearer + INVOKE_ASYNC(tether, /obj/projectile.proc/fire) + drain_power(use_power_cost) + +/obj/projectile/tether + name = "tether" + icon_state = "tether_projectile" + icon = 'icons/obj/mod.dmi' + pass_flags = PASSTABLE + damage = 0 + nodamage = TRUE + range = 10 + hitsound = 'sound/weapons/batonextend.ogg' + hitsound_wall = 'sound/weapons/batonextend.ogg' + var/line + +/obj/projectile/tether/fire(setAngle) + if(firer) + line = firer.Beam(src, "line", 'icons/obj/mod.dmi') + ..() + +/obj/projectile/tether/on_hit(atom/target) + . = ..() + if(firer) + firer.throw_at(target, 10, 1, firer, FALSE, FALSE, null, MOVE_FORCE_NORMAL, TRUE) + +/obj/projectile/tether/Destroy() + QDEL_NULL(line) + return ..() + +/obj/item/mod/module/mouthhole + name = "MOD eating apparatus module" + desc = "A favorite by Miners, this modification to the helmet utilizes a nanotechnology barrier infront of the mouth \ + to allow eating and drinking while retaining protection and atmosphere. \ + However, it will do nothing to improve the taste of a goliath steak." + icon_state = "apparatus" + complexity = 1 + incompatible_modules = list(/obj/item/mod/module/mouthhole) + overlay_state_inactive = "module_apparatus" + var/former_flags = NONE + var/former_visor_flags = NONE + +/obj/item/mod/module/mouthhole/on_install() + former_flags = mod.helmet.flags_cover + former_visor_flags = mod.helmet.visor_flags_cover + mod.helmet.flags_cover &= ~HEADCOVERSMOUTH + mod.helmet.visor_flags_cover &= ~HEADCOVERSMOUTH + +/obj/item/mod/module/mouthhole/on_uninstall() + if(!(former_flags & HEADCOVERSMOUTH)) + mod.helmet.flags_cover |= HEADCOVERSMOUTH + if(!(former_visor_flags & HEADCOVERSMOUTH)) + mod.helmet.visor_flags_cover |= HEADCOVERSMOUTH + +/obj/item/mod/module/rad_protection + name = "MOD radiation protection module" + desc = "A module utilizing polymers and reflective shielding to protect the user against ionizing radiation; \ + a common danger in space. This comes with software to notify the wearer that they're even in a radioactive area, \ + giving a voice to an otherwise silent killer." + icon_state = "radshield" + complexity = 2 + idle_power_cost = DEFAULT_CELL_DRAIN * 0.3 + incompatible_modules = list(/obj/item/mod/module/rad_protection) + tgui_id = "rad_counter" + var/perceived_threat_level + +/obj/item/mod/module/rad_protection/on_suit_activation() + AddComponent(/datum/component/geiger_sound) + ADD_TRAIT(mod.wearer, TRAIT_BYPASS_EARLY_IRRADIATED_CHECK, MOD_TRAIT) + RegisterSignal(mod.wearer, COMSIG_IN_RANGE_OF_IRRADIATION, .proc/on_pre_potential_irradiation) + for(var/obj/item/part in mod.mod_parts) + ADD_TRAIT(part, TRAIT_RADIATION_PROTECTED_CLOTHING, MOD_TRAIT) + +/obj/item/mod/module/rad_protection/on_suit_deactivation() + qdel(GetComponent(/datum/component/geiger_sound)) + REMOVE_TRAIT(mod.wearer, TRAIT_BYPASS_EARLY_IRRADIATED_CHECK, MOD_TRAIT) + UnregisterSignal(mod.wearer, COMSIG_IN_RANGE_OF_IRRADIATION) + for(var/obj/item/part in mod.mod_parts) + REMOVE_TRAIT(part, TRAIT_RADIATION_PROTECTED_CLOTHING, MOD_TRAIT) + +/obj/item/mod/module/rad_protection/add_ui_data() + . = ..() + .["userradiated"] = mod.wearer ? HAS_TRAIT(mod.wearer, TRAIT_IRRADIATED) : 0 + .["usertoxins"] = mod.wearer ? mod.wearer.getToxLoss() : 0 + .["threatlevel"] = perceived_threat_level + +/obj/item/mod/module/rad_protection/proc/on_pre_potential_irradiation(datum/source, datum/radiation_pulse_information/pulse_information, insulation_to_target) + SIGNAL_HANDLER + + perceived_threat_level = get_perceived_radiation_danger(pulse_information, insulation_to_target) + addtimer(VARSET_CALLBACK(src, perceived_threat_level, null), TIME_WITHOUT_RADIATION_BEFORE_RESET, TIMER_UNIQUE | TIMER_OVERRIDE) + +/obj/item/mod/module/emp_shield + name = "MOD EMP shield module" + desc = "A field inhibitor installed into the suit, protecting it against feedback such as \ + electromagnetic pulses that would otherwise damage the electronic systems of the suit or devices on the wearer. \ + However, it will take from the suit's power to do so. Luckily, your PDA already has one of these." + icon_state = "empshield" + complexity = 1 + idle_power_cost = DEFAULT_CELL_DRAIN * 0.3 + incompatible_modules = list(/obj/item/mod/module/emp_shield) + +/obj/item/mod/module/emp_shield/on_install() + mod.AddElement(/datum/element/empprotection, EMP_PROTECT_SELF|EMP_PROTECT_WIRES|EMP_PROTECT_CONTENTS) + +/obj/item/mod/module/emp_shield/on_uninstall() + mod.RemoveElement(/datum/element/empprotection, EMP_PROTECT_SELF|EMP_PROTECT_WIRES|EMP_PROTECT_CONTENTS) + +/obj/item/mod/module/flashlight + name = "MOD flashlight module" + desc = "A simple pair of flashlights installed on the left and right sides of the helmet, \ + useful for providing light in a variety of ranges and colors. \ + Some survivalists prefer the color green for their illumination, for reasons unknown." + icon_state = "flashlight" + module_type = MODULE_TOGGLE + complexity = 1 + active_power_cost = DEFAULT_CELL_DRAIN * 0.3 + incompatible_modules = list(/obj/item/mod/module/flashlight) + cooldown_time = 0.5 SECONDS + overlay_state_inactive = "module_light" + light_system = MOVABLE_LIGHT_DIRECTIONAL + light_color = COLOR_WHITE + light_range = 3 + light_power = 1 + light_on = FALSE + var/base_power = DEFAULT_CELL_DRAIN * 0.1 + var/min_range = 2 + var/max_range = 5 + +/obj/item/mod/module/flashlight/on_activation() + . = ..() + if(!.) + return + set_light_flags(light_flags | LIGHT_ATTACHED) + set_light_on(active) + active_power_cost = base_power * light_range + +/obj/item/mod/module/flashlight/on_deactivation() + . = ..() + if(!.) + return + set_light_flags(light_flags & ~LIGHT_ATTACHED) + set_light_on(active) + +/obj/item/mod/module/flashlight/on_process(delta_time) + . = ..() + if(!.) + return + active_power_cost = base_power * light_range + +/obj/item/mod/module/flashlight/generate_worn_overlay(mutable_appearance/standing) + . = ..() + if(!active) + return + var/mutable_appearance/light_icon = mutable_appearance('icons/mob/mod.dmi', "module_light_on", layer = standing.layer + 0.2) + light_icon.appearance_flags = RESET_COLOR + light_icon.color = light_color + . += light_icon + +/obj/item/mod/module/flashlight/get_configuration() + . = ..() + .["light_color"] = add_ui_configuration("Light Color", "color", light_color) + .["light_range"] = add_ui_configuration("Light Range", "number", light_range) + +/obj/item/mod/module/flashlight/configure_edit(key, value) + switch(key) + if("light_color") + value = input(usr, "Pick new light color", "Flashlight Color") as color|null + if(!value) + return + if(is_color_dark(value, 50)) + balloon_alert(mod.wearer, "too dark!") + return + set_light_color(value) + mod.wearer.update_inv_back() + if("light_range") + set_light_range(clamp(value, min_range, max_range)) + +/obj/item/mod/module/reagent_scanner + name = "MOD reagent scanner module" + desc = "A module based off research-oriented Nanotrasen HUDs, this is capable of scanning the contents of \ + containers and projecting the information in an easy-to-read format on the wearer's display. \ + It cannot detect flavors, so that's up to you." + icon_state = "scanner" + module_type = MODULE_TOGGLE + complexity = 1 + active_power_cost = DEFAULT_CELL_DRAIN * 0.2 + incompatible_modules = list(/obj/item/mod/module/reagent_scanner) + cooldown_time = 0.5 SECONDS + +/obj/item/mod/module/reagent_scanner/on_activation() + . = ..() + if(!.) + return + ADD_TRAIT(mod.wearer, TRAIT_REAGENT_SCANNER, MOD_TRAIT) + +/obj/item/mod/module/reagent_scanner/on_deactivation() + . = ..() + if(!.) + return + REMOVE_TRAIT(mod.wearer, TRAIT_REAGENT_SCANNER, MOD_TRAIT) + +/obj/item/mod/module/reagent_scanner/advanced + name = "MOD advanced reagent scanner module" + complexity = 0 + removable = FALSE + var/explosion_detection_dist = 21 + +/obj/item/mod/module/reagent_scanner/advanced/on_activation() + . = ..() + if(!.) + return + mod.wearer.research_scanner++ + RegisterSignal(SSdcs, COMSIG_GLOB_EXPLOSION, .proc/sense_explosion) + +/obj/item/mod/module/reagent_scanner/advanced/on_deactivation() + . = ..() + if(!.) + return + mod.wearer.research_scanner-- + RegisterSignal(SSdcs, COMSIG_GLOB_EXPLOSION) + +/obj/item/mod/module/reagent_scanner/advanced/proc/sense_explosion(datum/source, turf/epicenter, + devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range) + SIGNAL_HANDLER + var/turf/wearer_turf = get_turf(mod.wearer) + if(wearer_turf.z != epicenter.z) + return + if(get_dist(epicenter, wearer_turf) > explosion_detection_dist) + return + to_chat(mod.wearer, span_notice("Explosion detected! Epicenter: [devastation_range], Outer: [heavy_impact_range], Shock: [light_impact_range]")) + + +/obj/item/mod/module/dispenser + name = "MOD burger dispenser module" + desc = "A rare piece of technology reverse-engineered from a prototype found in a Donk Corporation vessel. \ + This can draw incredible amounts of power from the suit's cell to create edible organic matter in the \ + palm of the wearer's glove; however, research seemed to have entirely stopped at burgers. \ + Notably, all attempts to get it to dispense Earl Grey tea have failed." + icon_state = "dispenser" + module_type = MODULE_USABLE + complexity = 3 + use_power_cost = DEFAULT_CELL_DRAIN * 2 + incompatible_modules = list(/obj/item/mod/module/dispenser) + cooldown_time = 5 SECONDS + var/dispense_type = /obj/item/food/burger/plain + var/dispense_time = 0 SECONDS + +/obj/item/mod/module/dispenser/on_use() + . = ..() + if(!.) + return + if(dispense_time && !do_after(mod.wearer, dispense_time, target = mod)) + balloon_alert(mod.wearer, "interrupted!") + return + var/obj/item/dispensed = new dispense_type(mod.wearer.loc) + mod.wearer.put_in_hands(dispensed) + balloon_alert(mod.wearer, "[dispensed] dispensed") + playsound(src, 'sound/machines/click.ogg', 100, TRUE) + drain_power(use_power_cost) + +/obj/item/mod/module/gps + name = "MOD internal GPS module" + desc = "This module uses common Nanotrasen technology to calculate the user's position anywhere in space, \ + down to the exact coordinates. This information is fed to a central database viewable from the device itself, \ + though using it to help people is up to you." + icon_state = "gps" + module_type = MODULE_ACTIVE + complexity = 1 + active_power_cost = DEFAULT_CELL_DRAIN * 0.3 + device = /obj/item/gps/mod + incompatible_modules = list(/obj/item/mod/module/gps) + cooldown_time = 0.5 SECONDS + +/obj/item/gps/mod + name = "MOD internal GPS" + desc = "Common Nanotrasen technology that calcaulates the user's position from anywhere in space, down to their coordinates." + icon_state = "gps-b" + gpstag = "MOD0" + +/obj/item/mod/module/constructor + name = "MOD constructor module" + desc = "This module entirely occupies the wearer's forearm, notably causing conflict with \ + advanced arm servos meant to carry crewmembers. However, it functions as an \ + extremely advanced construction hologram scanner, as well as containing the \ + latest engineering schematics combined with inbuilt memory to help the user build walls." + icon_state = "constructor" + module_type = MODULE_USABLE + complexity = 2 + idle_power_cost = DEFAULT_CELL_DRAIN * 0.2 + use_power_cost = DEFAULT_CELL_DRAIN * 2 + incompatible_modules = list(/obj/item/mod/module/constructor, /obj/item/mod/module/quick_carry) + cooldown_time = 11 SECONDS + +/obj/item/mod/module/constructor/on_suit_activation() + ADD_TRAIT(mod.wearer, TRAIT_QUICK_BUILD, MOD_TRAIT) + +/obj/item/mod/module/constructor/on_suit_deactivation() + REMOVE_TRAIT(mod.wearer, TRAIT_QUICK_BUILD, MOD_TRAIT) + +/obj/item/mod/module/constructor/on_use() + . = ..() + if(!.) + return + rcd_scan(src, fade_time = 10 SECONDS) + drain_power(use_power_cost) + +/obj/item/mod/module/quick_carry + name = "MOD quick carry module" + desc = "A suite of advanced servos, redirecting power from the suit's arms to help carry the wounded; \ + or simply for fun. However, Nanotrasen has locked the module's ability to assist in hand-to-hand combat." + icon_state = "carry" + complexity = 1 + idle_power_cost = DEFAULT_CELL_DRAIN * 0.3 + incompatible_modules = list(/obj/item/mod/module/quick_carry, /obj/item/mod/module/constructor) + +/obj/item/mod/module/quick_carry/on_suit_activation() + ADD_TRAIT(mod.wearer, TRAIT_QUICK_CARRY, MOD_TRAIT) + +/obj/item/mod/module/quick_carry/on_suit_deactivation() + REMOVE_TRAIT(mod.wearer, TRAIT_QUICK_CARRY, MOD_TRAIT) + +/obj/item/mod/module/quick_carry/advanced + name = "MOD advanced quick carry module" + removable = FALSE + complexity = 0 + +/obj/item/mod/module/quick_carry/on_suit_activation() + ADD_TRAIT(mod.wearer, TRAIT_QUICKER_CARRY, MOD_TRAIT) + ADD_TRAIT(mod.wearer, TRAIT_FASTMED, MOD_TRAIT) + +/obj/item/mod/module/quick_carry/on_suit_deactivation() + REMOVE_TRAIT(mod.wearer, TRAIT_QUICKER_CARRY, MOD_TRAIT) + REMOVE_TRAIT(mod.wearer, TRAIT_FASTMED, MOD_TRAIT) + +/obj/item/mod/module/longfall + name = "MOD longfall module" + desc = "Useful for protecting both the suit and the wearer, \ + utilizing commonplace systems to convert the possible damage from a fall into kinetic charge, \ + as well as internal gyroscopes to ensure the user's safe falling. \ + Useful for mining, monorail tracks, or even skydiving!" + icon_state = "longfall" + complexity = 1 + use_power_cost = DEFAULT_CELL_DRAIN * 5 + incompatible_modules = list(/obj/item/mod/module/longfall) + +/obj/item/mod/module/longfall/on_suit_activation() + RegisterSignal(mod.wearer, COMSIG_LIVING_Z_IMPACT, .proc/z_impact_react) + +/obj/item/mod/module/longfall/on_suit_deactivation() + UnregisterSignal(mod.wearer, COMSIG_LIVING_Z_IMPACT) + +/obj/item/mod/module/longfall/proc/z_impact_react(datum/source, levels, turf/fell_on) + if(!drain_power(use_power_cost*levels)) + return + new /obj/effect/temp_visual/mook_dust(fell_on) + mod.wearer.Stun(levels * 1 SECONDS) + to_chat(mod.wearer, span_notice("[src] protects you from the damage!")) + return NO_Z_IMPACT_DAMAGE + +/obj/item/mod/module/thermal_regulator + name = "MOD thermal regulator module" + desc = "Advanced climate control, using an inner body glove interwoven with thousands of tiny, \ + flexible cooling lines. This circulates coolant at various user-controlled temperatures, \ + ensuring they're comfortable; even if they're some that like it hot." + icon_state = "regulator" + module_type = MODULE_TOGGLE + complexity = 2 + active_power_cost = DEFAULT_CELL_DRAIN * 0.3 + incompatible_modules = list(/obj/item/mod/module/thermal_regulator) + cooldown_time = 0.5 SECONDS + var/temperature_setting = BODYTEMP_NORMAL + var/min_temp = 293.15 + var/max_temp = 318.15 + +/obj/item/mod/module/thermal_regulator/get_configuration() + . = ..() + .["temperature_setting"] = add_ui_configuration("Temperature", "number", temperature_setting - T0C) + +/obj/item/mod/module/thermal_regulator/configure_edit(key, value) + switch(key) + if("temperature_setting") + temperature_setting = clamp(value + T0C, min_temp, max_temp) + +/obj/item/mod/module/thermal_regulator/on_active_process(delta_time) + mod.wearer.adjust_bodytemperature(get_temp_change_amount((temperature_setting - mod.wearer.bodytemperature), 0.08 * delta_time)) + +/obj/item/mod/module/injector + name = "MOD injector module" + desc = "A module installed into the wrist of the suit, this functions as a high-capacity syringe, \ + with a tip fine enough to locate the emergency injection ports on any suit of armor, \ + penetrating it with ease. Even yours." + icon_state = "injector" + module_type = MODULE_ACTIVE + complexity = 1 + active_power_cost = DEFAULT_CELL_DRAIN * 0.3 + device = /obj/item/reagent_containers/syringe/mod + incompatible_modules = list(/obj/item/mod/module/injector) + cooldown_time = 0.5 SECONDS + +/obj/item/reagent_containers/syringe/mod + name = "MOD injector syringe" + desc = "A high-capacity syringe, with a tip fine enough to locate \ + the emergency injection ports on any suit of armor, penetrating it with ease. Even yours." + icon_state = "mod_0" + base_icon_state = "mod" + amount_per_transfer_from_this = 30 + possible_transfer_amounts = list(5, 10, 15, 20, 30) + volume = 30 + inject_flags = INJECT_CHECK_PENETRATE_THICK + +/obj/item/mod/module/circuit + name = "MOD circuit adapter module" + desc = "A popular aftermarket module, seen in wide varieties with wide applications by those across the galaxy. \ + This is able to fit any sort of integrated circuit, hooking it into controls in the suit and displaying information \ + to the HUD. Useful for universal translation, or perhaps as a calculator." + module_type = MODULE_USABLE + complexity = 3 + idle_power_cost = DEFAULT_CELL_DRAIN * 0.5 + incompatible_modules = list(/obj/item/mod/module/circuit) + cooldown_time = 0.5 SECONDS + var/obj/item/integrated_circuit/circuit + +/obj/item/mod/module/circuit/Initialize(mapload) + . = ..() + circuit = new() + AddComponent(/datum/component/shell, \ + list(new /obj/item/circuit_component/mod()), \ + capacity = SHELL_CAPACITY_LARGE, \ + shell_flags = SHELL_FLAG_CIRCUIT_UNREMOVABLE, \ + starting_circuit = circuit, \ + ) + +/obj/item/mod/module/circuit/on_install() + circuit.set_cell(mod.cell) + +/obj/item/mod/module/circuit/on_uninstall() + circuit.set_cell(mod.cell) + +/obj/item/mod/module/circuit/on_suit_activation() + circuit.set_on(TRUE) + +/obj/item/mod/module/circuit/on_suit_deactivation() + circuit.set_on(FALSE) + +/obj/item/mod/module/circuit/on_use() + . = ..() + if(!.) + return + circuit.interact(mod.wearer) + +/obj/item/circuit_component/mod + display_name = "MOD" + desc = "Used to send and receive signals from a MODsuit." + + var/obj/item/mod/module/attached_module + + var/datum/port/input/module_to_select + var/datum/port/input/toggle_suit + var/datum/port/input/select_module + + var/datum/port/output/wearer + var/datum/port/output/selected_module + +/obj/item/circuit_component/mod/populate_ports() + // Input Signals + module_to_select = add_input_port("Module to Select", PORT_TYPE_STRING) + toggle_suit = add_input_port("Toggle Suit", PORT_TYPE_SIGNAL) + select_module = add_input_port("Select Module", PORT_TYPE_SIGNAL) + // States + wearer = add_output_port("Wearer", PORT_TYPE_ATOM) + selected_module = add_output_port("Selected Module", PORT_TYPE_ATOM) + +/obj/item/circuit_component/mod/register_shell(atom/movable/shell) + if(istype(shell, /obj/item/mod/module)) + attached_module = shell + RegisterSignal(attached_module, COMSIG_MOVABLE_MOVED, .proc/on_move) + +/obj/item/circuit_component/mod/unregister_shell(atom/movable/shell) + UnregisterSignal(attached_module, COMSIG_MOVABLE_MOVED) + attached_module = null + +/obj/item/circuit_component/mod/input_received(datum/port/input/port) + var/obj/item/mod/module/module + for(var/obj/item/mod/module/potential_module as anything in attached_module.mod.modules) + if(potential_module.name == module_to_select.value) + module = potential_module + if(COMPONENT_TRIGGERED_BY(toggle_suit, port)) + INVOKE_ASYNC(attached_module.mod, /obj/item/mod/control.proc/toggle_activate, attached_module.mod.wearer) + if(module && COMPONENT_TRIGGERED_BY(select_module, port)) + INVOKE_ASYNC(module, /obj/item/mod/module.proc/on_select) + +/obj/item/circuit_component/mod/proc/on_move(atom/movable/source, atom/old_loc, dir, forced) + SIGNAL_HANDLER + if(istype(source.loc, /obj/item/mod/control)) + RegisterSignal(source.loc, COMSIG_MOD_MODULE_SELECTED, .proc/on_module_select) + RegisterSignal(source.loc, COMSIG_ITEM_EQUIPPED, .proc/equip_check) + equip_check() + else if(istype(old_loc, /obj/item/mod/control)) + UnregisterSignal(old_loc, list(COMSIG_MOD_MODULE_SELECTED, COMSIG_ITEM_EQUIPPED)) + selected_module.set_output(null) + wearer.set_output(null) + +/obj/item/circuit_component/mod/proc/on_module_select() + SIGNAL_HANDLER + selected_module.set_output(attached_module.mod.selected_module) + +/obj/item/circuit_component/mod/proc/equip_check() + SIGNAL_HANDLER + + if(!attached_module.mod?.wearer) + return + wearer.set_output(attached_module.mod.wearer) + +/obj/item/mod/module/clamp + name = "MOD hydraulic clamp module" + desc = "A series of actuators installed into both arms of the suit, boasting a lifting capacity of almost a ton. \ + However, this design has been locked by Nanotrasen to be primarily utilized for lifting various crates. \ + A lot of people would say that loading cargo is a dull job, but you could not disagree more." + icon_state = "clamp" + module_type = MODULE_ACTIVE + complexity = 3 + use_power_cost = DEFAULT_CELL_DRAIN + incompatible_modules = list(/obj/item/mod/module/clamp) + cooldown_time = 0.5 SECONDS + var/max_crates = 5 + var/list/stored_crates = list() + +/obj/item/mod/module/clamp/on_select_use(atom/target) + . = ..() + if(!.) + return + if(!mod.wearer.Adjacent(target)) + return + if(istype(target, /obj/structure/closet/crate)) + var/atom/movable/picked_crate = target + if(length(stored_crates) >= max_crates) + balloon_alert(mod.wearer, "too many crates!") + return + if(!do_after(mod.wearer, 1 SECONDS, target = target)) + balloon_alert(mod.wearer, "interrupted!") + return + stored_crates += picked_crate + picked_crate.forceMove(src) + balloon_alert(mod.wearer, "picked up [picked_crate]") + playsound(src, 'sound/mecha/hydraulic.ogg', 25, TRUE) + drain_power(use_power_cost) + else if(length(stored_crates)) + var/turf/target_turf = get_turf(target) + if(target_turf.is_blocked_turf()) + return + if(!do_after(mod.wearer, 1 SECONDS, target = target)) + balloon_alert(mod.wearer, "interrupted!") + return + if(target_turf.is_blocked_turf()) + return + var/atom/movable/dropped_crate = pop(stored_crates) + dropped_crate.forceMove(target_turf) + balloon_alert(mod.wearer, "dropped [dropped_crate]") + playsound(src, 'sound/mecha/hydraulic.ogg', 25, TRUE) + drain_power(use_power_cost) + +/obj/item/mod/module/bikehorn + name = "MOD bike horn module" + desc = "A shoulder-mounted piece of heavy sonic artillery, this module uses the finest femto-manipulator technology to \ + precisely deliver an almost lethal squeeze to... a bike horn, producing a significantly memorable sound." + icon_state = "bikehorn" + module_type = MODULE_USABLE + complexity = 1 + use_power_cost = DEFAULT_CELL_DRAIN + incompatible_modules = list(/obj/item/mod/module/bikehorn) + cooldown_time = 1 SECONDS + +/obj/item/mod/module/bikehorn/on_use() + . = ..() + if(!.) + return + playsound(src, 'sound/items/bikehorn.ogg', 100, FALSE) + drain_power(use_power_cost) + +/obj/item/mod/module/drill + name = "MOD drill module" + desc = "An integrated drill, typically extending over the user's hand. While useful for drilling through rock, \ + your drill is surely the one that both pierces and creates the heavens." + icon_state = "drill" + module_type = MODULE_ACTIVE + complexity = 2 + use_power_cost = DEFAULT_CELL_DRAIN + incompatible_modules = list(/obj/item/mod/module/drill) + cooldown_time = 0.5 SECONDS + +/obj/item/mod/module/drill/on_activation() + . = ..() + if(!.) + return + RegisterSignal(mod.wearer, COMSIG_MOVABLE_BUMP, .proc/bump_mine) + +/obj/item/mod/module/drill/on_deactivation() + . = ..() + if(!.) + return + UnregisterSignal(mod.wearer, COMSIG_MOVABLE_BUMP) + +/obj/item/mod/module/drill/on_select_use(atom/target) + . = ..() + if(!.) + return + if(!mod.wearer.Adjacent(target)) + return + if(istype(target, /turf/closed/mineral)) + var/turf/closed/mineral/mineral_turf = target + mineral_turf.gets_drilled(mod.wearer) + drain_power(use_power_cost) + +/obj/item/mod/module/drill/proc/bump_mine(mob/living/carbon/human/bumper, atom/bumped_into, proximity) + SIGNAL_HANDLER + if(!istype(bumped_into, /turf/closed/mineral) || !drain_power(use_power_cost)) + return + var/turf/closed/mineral/mineral_turf = bumped_into + mineral_turf.gets_drilled(mod.wearer) + return COMPONENT_CANCEL_ATTACK_CHAIN + +/obj/item/mod/module/orebag + name = "MOD ore bag module" + desc = "An integrated ore storage system installed into the suit, \ + this utilizes precise electromagnets and storage compartments to automatically collect and deposit ore. \ + It's recommended by Nakamura Engineering to actually deposit that ore at local refineries." + icon_state = "ore" + module_type = MODULE_USABLE + complexity = 2 + use_power_cost = DEFAULT_CELL_DRAIN * 0.2 + incompatible_modules = list(/obj/item/mod/module/orebag) + cooldown_time = 0.5 SECONDS + var/list/ores = list() + +/obj/item/mod/module/orebag/on_equip() + RegisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED, .proc/ore_pickup) + +/obj/item/mod/module/orebag/on_unequip() + UnregisterSignal(mod.wearer, COMSIG_MOVABLE_MOVED) + +/obj/item/mod/module/orebag/proc/ore_pickup(atom/movable/source, atom/old_loc, dir, forced) + SIGNAL_HANDLER + + for(var/obj/item/stack/ore/ore in get_turf(mod.wearer)) + INVOKE_ASYNC(src, .proc/move_ore, ore) + playsound(src, "rustle", 50, TRUE) + +/obj/item/mod/module/orebag/proc/move_ore(obj/item/stack/ore) + for(var/obj/item/stack/stored_ore as anything in ores) + if(!ore.can_merge(stored_ore)) + continue + ore.merge(stored_ore) + if(QDELETED(ore)) + return + break + ore.forceMove(src) + ores += ore + +/obj/item/mod/module/orebag/on_use() + . = ..() + if(!.) + return + for(var/obj/item/ore as anything in ores) + ore.forceMove(mod.drop_location()) + ores -= ore + drain_power(use_power_cost) + +/obj/item/mod/module/microwave_beam + name = "MOD microwave beam module" + desc = "An oddly domestic device, this module is installed into the user's palm, \ + hooking up with culinary scanners located in the helmet to blast food with precise microwave radiation, \ + allowing them to cook food from a distance, with the greatest of ease. Not recommended for use against grapes." + icon_state = "microwave_beam" + module_type = MODULE_ACTIVE + complexity = 2 + use_power_cost = DEFAULT_CELL_DRAIN * 5 + incompatible_modules = list(/obj/item/mod/module/microwave_beam) + cooldown_time = 10 SECONDS + +/obj/item/mod/module/microwave_beam/on_select_use(atom/target) + . = ..() + if(!.) + return + if(!istype(target, /obj/item)) + return + if(!isturf(target.loc)) + balloon_alert(mod.wearer, "must be on the floor!") + return + var/obj/item/microwave_target = target + var/datum/effect_system/spark_spread/spark_effect = new() + spark_effect.set_up(2, 1, mod.wearer) + spark_effect.start() + mod.wearer.Beam(target,icon_state="lightning[rand(1,12)]", time = 5) + if(microwave_target.microwave_act()) + playsound(src, 'sound/machines/microwave/microwave-end.ogg', 50, FALSE) + else + balloon_alert(mod.wearer, "can't be microwaved!") + var/datum/effect_system/spark_spread/spark_effect_two = new() + spark_effect_two.set_up(2, 1, microwave_target) + spark_effect_two.start() + drain_power(use_power_cost) + +/obj/item/mod/module/organ_thrower + name = "MOD organ thrower module" + desc = "A device recovered from a crashed Interdyne Pharmaceuticals vessel, \ + this module has been unearthed for better or for worse. \ + It's an arm-mounted device utilizing technology similar to modern-day part replacers, \ + capable of storing and inserting organs into open patients. \ + It's recommended by the DeForest Medical Corporation to not inform patients it has been used." + icon_state = "organ_thrower" + module_type = MODULE_ACTIVE + complexity = 2 + use_power_cost = DEFAULT_CELL_DRAIN + incompatible_modules = list(/obj/item/mod/module/organ_thrower) + cooldown_time = 0.5 SECONDS + var/max_organs = 5 + var/organ_list = list() + +/obj/item/mod/module/organ_thrower/on_select_use(atom/target) + . = ..() + if(!.) + return + var/mob/living/carbon/human/wearer_human = mod.wearer + if(istype(target, /obj/item/organ)) + if(!wearer_human.Adjacent(target)) + return + var/atom/movable/organ = target + if(length(organ_list) >= max_organs) + balloon_alert(mod.wearer, "too many organs!") + return + organ_list += organ + organ.forceMove(src) + balloon_alert(mod.wearer, "picked up [organ]") + playsound(src, 'sound/mecha/hydraulic.ogg', 25, TRUE) + drain_power(use_power_cost) + return + if(!length(organ_list)) + return + var/atom/movable/fired_organ = pop(organ_list) + var/obj/projectile/organ/projectile = new /obj/projectile/organ(mod.wearer.loc, fired_organ) + projectile.preparePixelProjectile(target, mod.wearer) + projectile.firer = mod.wearer + playsound(src, 'sound/mecha/hydraulic.ogg', 25, TRUE) + INVOKE_ASYNC(projectile, /obj/projectile.proc/fire) + drain_power(use_power_cost) + +/obj/projectile/organ + name = "organ" + damage = 0 + nodamage = TRUE + hitsound = 'sound/effects/attackblob.ogg' + hitsound_wall = 'sound/effects/attackblob.ogg' + var/obj/item/organ/organ + +/obj/projectile/organ/Initialize(mapload, obj/item/stored_organ) + . = ..() + if(!stored_organ) + return INITIALIZE_HINT_QDEL + appearance = stored_organ.appearance + stored_organ.forceMove(src) + organ = stored_organ + +/obj/projectile/organ/Destroy() + organ = null + return ..() + +/obj/projectile/organ/on_hit(atom/target) + . = ..() + if(!ishuman(target)) + organ.forceMove(drop_location()) + organ = null + return + var/mob/living/carbon/human/organ_receiver = target + var/succeed = FALSE + if(organ_receiver.surgeries.len) + for(var/datum/surgery/procedure as anything in organ_receiver.surgeries) + if(procedure.location != organ.zone) + continue + if(!istype(procedure, /datum/surgery/organ_manipulation)) + continue + var/datum/surgery_step/surgery_step = procedure.get_surgery_step() + if(!istype(surgery_step, /datum/surgery_step/manipulate_organs)) + continue + succeed = TRUE + break + if(succeed) + var/list/organs_to_boot_out = organ_receiver.getorganslot(organ.slot) + for(var/obj/item/organ/organ_evacced as anything in organs_to_boot_out) + if(organ_evacced.organ_flags & ORGAN_UNREMOVABLE) + continue + organ_evacced.Remove(target) + organ_evacced.forceMove(get_turf(target)) + organ.Insert(target) + else + organ.forceMove(drop_location()) + organ = null + +/obj/item/mod/module/pathfinder + name = "MOD pathfinder module" + desc = "This module, brought to you by Nakamura Engineering, has two components. \ + The first component is a series of thrusters and a computerized location subroutine installed into the \ + very control unit of the suit, allowing it flight at highway speeds, \ + and to be able to locate the second part of the system; \ + a pathfinding implant installed into the base of the user's spine, \ + broadcasting their location to the suit and allowing them to recall it to their back at any time. \ + Nakamura Engineering swears up and down there's airbrakes." + icon_state = "pathfinder" + complexity = 2 + use_power_cost = DEFAULT_CELL_DRAIN * 10 + incompatible_modules = list(/obj/item/mod/module/pathfinder) + var/obj/item/implant/mod/implant + +/obj/item/mod/module/pathfinder/Initialize(mapload) + . = ..() + implant = new(src) + +/obj/item/mod/module/pathfinder/Destroy() + implant = null + return ..() + +/obj/item/mod/module/pathfinder/examine(mob/user) + . = ..() + if(implant) + . += span_notice("Use it on a human to implant them.") + else + . += span_warning("The implant is missing.") + +/obj/item/mod/module/pathfinder/attack(mob/living/target, mob/living/user, params) + if(!ishuman(target) || !implant) + return + if(!do_after(user, 1.5 SECONDS, target = target)) + balloon_alert(user, "interrupted!") + return + if(!implant.implant(target, user)) + balloon_alert(user, "can't implant!") + return + if(target == user) + to_chat(user, span_notice("You implant yourself with [implant].")) + else + target.visible_message(span_notice("[user] implants [target]."), span_notice("[user] implants you with [implant].")) + playsound(src, 'sound/effects/spray.ogg', 30, TRUE, -6) + icon_state = "pathfinder_empty" + implant = null + +/obj/item/mod/module/pathfinder/proc/attach(mob/living/user) + if(!ishuman(user)) + return + var/mob/living/carbon/human/human_user = user + if(human_user.back && !human_user.dropItemToGround(human_user.back)) + return + if(!human_user.equip_to_slot_if_possible(mod, mod.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE)) + return + human_user.update_action_buttons(TRUE) + balloon_alert(human_user, "[mod] attached") + playsound(mod, 'sound/machines/ping.ogg', 50, TRUE) + drain_power(use_power_cost) + +/obj/item/implant/mod + name = "MOD pathfinder implant" + desc = "Lets you recall a MODsuit to you at any time." + actions_types = list(/datum/action/item_action/mod_recall) + var/obj/item/mod/module/pathfinder/module + var/image/jet_icon + +/obj/item/implant/mod/Initialize(mapload) + . = ..() + if(!istype(loc, /obj/item/mod/module/pathfinder)) + return INITIALIZE_HINT_QDEL + module = loc + jet_icon = image(icon = 'icons/obj/mod.dmi', icon_state = "mod_jet", layer = LOW_ITEM_LAYER) + +/obj/item/implant/mod/Destroy() + if(module?.mod?.ai_controller) + end_recall(successful = FALSE) + module = null + jet_icon = null + return ..() + +/obj/item/implant/mod/get_data() + var/dat = {"Implant Specifications:
+ Name: Nakamura Engineering Pathfinder Implant
+ Implant Details: Allows for the recall of a Modular Outerwear Device by the implant owner at any time.
"} + return dat + +/obj/item/implant/mod/proc/recall() + if(!module?.mod) + balloon_alert(imp_in, "no connected suit!") + return FALSE + if(module.mod.open) + balloon_alert(imp_in, "suit is open!") + return FALSE + if(module.mod.ai_controller) + balloon_alert(imp_in, "already in transit!") + return FALSE + if(ismob(get_atom_on_turf(module.mod))) + balloon_alert(imp_in, "already on someone!") + return FALSE + if(module.z != z || get_dist(imp_in, module.mod) > MOD_AI_RANGE) + balloon_alert(imp_in, "too far away!") + return FALSE + var/datum/ai_controller/mod_ai = new /datum/ai_controller/mod(module.mod) + module.mod.ai_controller = mod_ai + mod_ai.current_movement_target = imp_in + mod_ai.blackboard[BB_MOD_TARGET] = imp_in + mod_ai.blackboard[BB_MOD_IMPLANT] = src + module.mod.interaction_flags_item &= ~INTERACT_ITEM_ATTACK_HAND_PICKUP + module.mod.AddElement(/datum/element/movetype_handler) + ADD_TRAIT(module.mod, TRAIT_MOVE_FLYING, MOD_TRAIT) + animate(module.mod, 0.2 SECONDS, pixel_x = base_pixel_y, pixel_y = base_pixel_y) + module.mod.add_overlay(jet_icon) + RegisterSignal(module.mod, COMSIG_MOVABLE_MOVED, .proc/on_move) + balloon_alert(imp_in, "suit recalled") + return TRUE + +/obj/item/implant/mod/proc/end_recall(successful = TRUE) + if(!module?.mod) + return + QDEL_NULL(module.mod.ai_controller) + module.mod.interaction_flags_item |= INTERACT_ITEM_ATTACK_HAND_PICKUP + REMOVE_TRAIT(module.mod, TRAIT_MOVE_FLYING, MOD_TRAIT) + module.mod.RemoveElement(/datum/element/movetype_handler) + module.mod.cut_overlay(jet_icon) + module.mod.transform = matrix() + UnregisterSignal(module.mod, COMSIG_MOVABLE_MOVED) + if(!successful) + balloon_alert(imp_in, "suit lost connection!") + +/obj/item/implant/mod/proc/on_move(atom/movable/source, atom/old_loc, dir, forced) + SIGNAL_HANDLER + + var/matrix/mod_matrix = matrix() + mod_matrix.Turn(get_angle(source, imp_in)) + source.transform = mod_matrix + +/datum/action/item_action/mod_recall + name = "Recall MOD" + desc = "Recall a MODsuit anyplace, anytime." + check_flags = AB_CHECK_CONSCIOUS + background_icon_state = "bg_tech_blue" + icon_icon = 'icons/mob/actions/actions_mod.dmi' + button_icon_state = "recall" + COOLDOWN_DECLARE(recall_cooldown) + var/obj/item/implant/mod/implant + +/datum/action/item_action/mod_recall/New(Target) + ..() + implant = Target + +/datum/action/item_action/mod_recall/Trigger() + . = ..() + if(!.) + return + if(!COOLDOWN_FINISHED(src, recall_cooldown)) + implant.balloon_alert(implant.imp_in, "on cooldown!") + return + if(implant.recall()) + COOLDOWN_START(src, recall_cooldown, 15 SECONDS) + +/obj/item/mod/module/dna_lock + name = "MOD DNA lock module" + desc = "A module which engages with the various locks and seals tied to the suit's systems, \ + enabling it to only be worn by someone corresponding with the user's exact DNA profile; \ + however, this incredibly sensitive module is shorted out by EMPs. Luckily, cloning has been outlawed." + icon_state = "dnalock" + module_type = MODULE_USABLE + complexity = 2 + use_power_cost = DEFAULT_CELL_DRAIN * 3 + incompatible_modules = list(/obj/item/mod/module/dna_lock) + cooldown_time = 0.5 SECONDS + var/dna = null + +/obj/item/mod/module/dna_lock/on_install() + RegisterSignal(mod, COMSIG_MOD_ACTIVATE, .proc/on_mod_activation) + RegisterSignal(mod, COMSIG_ATOM_EMP_ACT, .proc/on_emp) + RegisterSignal(mod, COMSIG_ATOM_EMAG_ACT, .proc/on_emag) + +/obj/item/mod/module/dna_lock/on_uninstall() + UnregisterSignal(mod, COMSIG_MOD_ACTIVATE) + UnregisterSignal(mod, COMSIG_ATOM_EMP_ACT) + UnregisterSignal(mod, COMSIG_ATOM_EMAG_ACT) + +/obj/item/mod/module/dna_lock/on_use() + . = ..() + if(!.) + return + dna = mod.wearer.dna.unique_enzymes + balloon_alert(mod.wearer, "dna updated") + drain_power(use_power_cost) + +/obj/item/mod/module/dna_lock/emp_act(severity) + . = ..() + if(. & EMP_PROTECT_SELF) + return + on_emp(src, severity) + +/obj/item/mod/module/dna_lock/emag_act(mob/user, obj/item/card/emag/emag_card) + . = ..() + on_emag(src, user, emag_card) + +/obj/item/mod/module/dna_lock/proc/on_emp(datum/source, severity) + SIGNAL_HANDLER + + dna = null + +/obj/item/mod/module/dna_lock/proc/on_emag(datum/source, mob/user, obj/item/card/emag/emag_card) + SIGNAL_HANDLER + + dna = null + +/obj/item/mod/module/dna_lock/proc/on_mod_activation(datum/source) + SIGNAL_HANDLER + + if(!dna || (mod.wearer.has_dna() && mod.wearer.dna.unique_enzymes == dna)) + return + balloon_alert(mod.wearer, "dna locked!") + return MOD_CANCEL_ACTIVATE + +/obj/item/mod/module/armor_booster + name = "MOD armor booster module" + desc = "A retrofitted series of retractable armor plates, allowing the suit to function as essentially power armor, \ + giving the user incredible protection against conventional firearms, or everyday attacks in close-quarters. \ + However, the additional plating cannot deploy alongside parts of the suit used for vacuum sealing, \ + so this extra armor provides zero ability for extravehicular activity while deployed." + icon_state = "armor_booster" + module_type = MODULE_TOGGLE + active_power_cost = DEFAULT_CELL_DRAIN * 0.3 + removable = FALSE + incompatible_modules = list(/obj/item/mod/module/armor_booster) + cooldown_time = 0.5 SECONDS + overlay_state_inactive = "module_armorbooster_off" + overlay_state_active = "module_armorbooster_on" + var/remove_pressure_protection = TRUE + var/added_slowdown = -0.5 + var/list/armor_values = list(MELEE = 40, BULLET = 50, LASER = 30, ENERGY = 40) + var/list/spaceproofed = list() + +/obj/item/mod/module/armor_booster/generate_worn_overlay(mutable_appearance/standing) + overlay_state_inactive = "[initial(overlay_state_inactive)]-[mod.skin]" + overlay_state_active = "[initial(overlay_state_active)]-[mod.skin]" + return ..() + +/obj/item/mod/module/armor_booster/on_activation() + . = ..() + if(!.) + return + playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + mod.slowdown += added_slowdown + mod.wearer.update_equipment_speed_mods() + var/list/parts = mod.mod_parts + mod + for(var/obj/item/part as anything in parts) + part.armor = part.armor.modifyRating(arglist(armor_values)) + if(!remove_pressure_protection || !isclothing(part)) + continue + var/obj/item/clothing/clothing_part = part + if(clothing_part.clothing_flags & STOPSPRESSUREDAMAGE) + clothing_part.clothing_flags &= ~STOPSPRESSUREDAMAGE + clothing_part.heat_protection = NONE + clothing_part.cold_protection = NONE + spaceproofed[clothing_part] = TRUE + +/obj/item/mod/module/armor_booster/on_deactivation() + . = ..() + if(!.) + return + playsound(src, 'sound/mecha/mechmove03.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + mod.slowdown -= added_slowdown + mod.wearer.update_equipment_speed_mods() + var/list/parts = mod.mod_parts + mod + var/list/removed_armor = armor_values.Copy() + for(var/armor_type in removed_armor) + removed_armor[armor_type] = -removed_armor[armor_type] + for(var/obj/item/part as anything in parts) + part.armor = part.armor.modifyRating(arglist(removed_armor)) + if(!remove_pressure_protection || !isclothing(part)) + continue + var/obj/item/clothing/clothing_part = part + if(spaceproofed[clothing_part]) + clothing_part.clothing_flags |= STOPSPRESSUREDAMAGE + clothing_part.heat_protection = initial(clothing_part.heat_protection) + clothing_part.cold_protection = initial(clothing_part.cold_protection) + spaceproofed = list() + +/obj/item/mod/module/armor_booster/elite + name = "MOD elite armor booster module" + armor_values = list(MELEE = 60, BULLET = 60, LASER = 50, ENERGY = 60) + added_slowdown = -0.25 + +/obj/item/mod/module/energy_shield + name = "MOD energy shield module" + desc = "A personal, protective forcefield typically seen in military applications. \ + This advanced deflector shield is essentially a scaled down version of those seen on starships, \ + and the power cost can be an easy indicator of this. However, it is capable of blocking nearly any incoming attack, \ + though with its' low amount of separate charges, the user remains mortal." + icon_state = "energy_shield" + complexity = 3 + idle_power_cost = DEFAULT_CELL_DRAIN * 0.5 + use_power_cost = DEFAULT_CELL_DRAIN * 2 + incompatible_modules = list(/obj/item/mod/module/energy_shield) + var/max_charges = 3 + var/recharge_start_delay = 20 SECONDS + var/charge_increment_delay = 1 SECONDS + var/charge_recovery = 1 + var/lose_multiple_charges = FALSE + var/recharge_path = null + var/shield_icon_file = 'icons/effects/effects.dmi' + var/shield_icon = "shield-red" + var/charges + +/obj/item/mod/module/energy_shield/Initialize(mapload) + . = ..() + charges = max_charges + +/obj/item/mod/module/energy_shield/on_suit_activation() + mod.AddComponent(/datum/component/shielded, max_charges = max_charges, recharge_start_delay = recharge_start_delay, charge_increment_delay = charge_increment_delay, \ + charge_recovery = charge_recovery, lose_multiple_charges = lose_multiple_charges, recharge_path = recharge_path, starting_charges = charges, shield_icon_file = shield_icon_file, shield_icon = shield_icon) + RegisterSignal(mod.wearer, COMSIG_HUMAN_CHECK_SHIELDS, .proc/shield_reaction) + +/obj/item/mod/module/energy_shield/on_suit_deactivation() + var/datum/component/shielded/shield = mod.GetComponent(/datum/component/shielded) + charges = shield.current_charges + qdel(shield) + UnregisterSignal(mod.wearer, COMSIG_HUMAN_CHECK_SHIELDS) + +/obj/item/mod/module/energy_shield/proc/shield_reaction(mob/living/carbon/human/owner, atom/movable/hitby, damage = 0, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0) + if(SEND_SIGNAL(mod, COMSIG_ITEM_HIT_REACT, owner, hitby, attack_text, 0, damage, attack_type) & COMPONENT_HIT_REACTION_BLOCK) + drain_power(use_power_cost) + return SHIELD_BLOCK + return NONE + +/obj/item/mod/module/energy_shield/wizard + name = "MOD battlemage shield module" + desc = "The caster wielding this spell gains a visible barrier around them, channeling arcane power through \ + specialized runes engraved onto the surface of the suit to generate a wall of force. \ + This shield can perfectly nullify attacks ranging from high-caliber rifles to magic missiles, \ + though can also be drained by more mundane attacks. It will not protect the caster from social ridicule." + icon_state = "battlemage_shield" + idle_power_cost = DEFAULT_CELL_DRAIN * 0 //magic + use_power_cost = DEFAULT_CELL_DRAIN * 0 //magic too + max_charges = 15 + recharge_start_delay = 0 SECONDS + charge_recovery = 8 + shield_icon_file = 'icons/effects/magic.dmi' + shield_icon = "mageshield" + recharge_path = /obj/item/wizard_armour_charge + +/obj/item/mod/module/plasma_stabilizer + name = "MOD plasma stabilizer module" + desc = "This system essentially forms an atmosphere of its' own inside the suit, \ + safely ejecting oxygen from the inside and allowing the wearer, a plasmaman, \ + to have their internal plasma circulate around them somewhat like a sauna. \ + This prevents them from self-igniting, and leads to greater comfort overall. \ + The purple glass of the visor seems to be constructed for nostalgic purposes." + icon_state = "plasma_stabilizer" + complexity = 1 + idle_power_cost = DEFAULT_CELL_DRAIN * 0.3 + incompatible_modules = list(/obj/item/mod/module/plasma_stabilizer) + overlay_state_inactive = "module_plasma" + +/obj/item/mod/module/plasma_stabilizer/on_equip() + ADD_TRAIT(mod.wearer, TRAIT_NOSELFIGNITION, MOD_TRAIT) + +/obj/item/mod/module/plasma_stabilizer/on_unequip() + REMOVE_TRAIT(mod.wearer, TRAIT_NOSELFIGNITION, MOD_TRAIT) + +/obj/item/mod/module/anti_magic + name = "MOD magic nullifier module" + desc = "A series of obsidian rods installed into critical points around the suit, \ + vibrated at a certain low frequency to enable them to resonate. \ + This creates a low-range, yet strong, magic nullification field around the user, \ + aided by a full replacement of the suit's normal coolant with holy water. \ + Spells will spall right off this field, though it'll do nothing to help others believe you about all this." + icon_state = "magic_nullifier" + removable = FALSE + incompatible_modules = list(/obj/item/mod/module/anti_magic) + +/obj/item/mod/module/anti_magic/on_suit_activation() + ADD_TRAIT(mod.wearer, TRAIT_ANTIMAGIC, MOD_TRAIT) + ADD_TRAIT(mod.wearer, TRAIT_HOLY, MOD_TRAIT) + +/obj/item/mod/module/anti_magic/on_suit_deactivation() + REMOVE_TRAIT(mod.wearer, TRAIT_ANTIMAGIC, MOD_TRAIT) + REMOVE_TRAIT(mod.wearer, TRAIT_HOLY, MOD_TRAIT) + +/obj/item/mod/module/anti_magic/wizard + name = "MOD magic neutralizer module" + desc = "The caster wielding this spell gains an invisible barrier around them, channeling arcane power through \ + specialized runes engraved onto the surface of the suit to generate anti-magic field. \ + The field will neutralize all magic that comes into contact with the user. \ + It will not protect the caster from social ridicule." + icon_state = "magic_neutralizer" + +/obj/item/mod/module/anti_magic/wizard/on_suit_activation() + ADD_TRAIT(mod.wearer, TRAIT_ANTIMAGIC_NO_SELFBLOCK, MOD_TRAIT) + +/obj/item/mod/module/anti_magic/wizard/on_suit_deactivation() + REMOVE_TRAIT(mod.wearer, TRAIT_ANTIMAGIC_NO_SELFBLOCK, MOD_TRAIT) + +/obj/item/mod/module/kinesis //TODO POST-MERGE MAKE NOT SUCK ASS, MAKE BALLER AS FUCK + name = "MOD kinesis module" + desc = "A modular plug-in to the forearm, this module was presumed lost for many years, \ + despite the suits it used to be mounted on still seeing some circulation. \ + This piece of technology allows the user to generate precise anti-gravity fields, \ + letting them move objects as small as a titanium rod to as large as industrial machinery. \ + Oddly enough, it doesn't seem to work on living creatures." + icon_state = "kinesis" +// module_type = MODULE_ACTIVE + module_type = MODULE_TOGGLE +// complexity = 3 + complexity = 0 + active_power_cost = DEFAULT_CELL_DRAIN*0.75 +// use_power_cost = DEFAULT_CELL_DRAIN*3 + removable = FALSE + incompatible_modules = list(/obj/item/mod/module/kinesis) + cooldown_time = 0.5 SECONDS + var/has_tk = FALSE + +/obj/item/mod/module/kinesis/on_activation() + . = ..() + if(!.) + return + if(mod.wearer.dna.check_mutation(TK)) + has_tk = TRUE + else + mod.wearer.dna.add_mutation(TK) + +/obj/item/mod/module/kinesis/on_deactivation() + . = ..() + if(!.) + return + if(has_tk) + has_tk = FALSE + return + mod.wearer.dna.remove_mutation(TK) + +/obj/item/mod/module/insignia + name = "MOD insignia module" + desc = "Despite the existence of IFF systems, radio communique, and modern methods of deductive reasoning involving \ + the wearer's own eyes, colorful paint jobs remain a popular way for different factions in the galaxy to display who \ + they are. This system utilizes a series of tiny moving paint sprayers to both apply and remove different \ + color patterns to and from the suit." + icon_state = "insignia" + removable = FALSE + incompatible_modules = list(/obj/item/mod/module/insignia) + overlay_state_inactive = "insignia" + +/obj/item/mod/module/insignia/generate_worn_overlay(mutable_appearance/standing) + overlay_state_inactive = "[initial(overlay_state_inactive)]-[mod.skin]" + . = ..() + for(var/mutable_appearance/appearance as anything in .) + appearance.color = color + +/obj/item/mod/module/insignia/commander + color = "#4980a5" + +/obj/item/mod/module/insignia/security + color = "#b30d1e" + +/obj/item/mod/module/insignia/engineer + color = "#e9c80e" + +/obj/item/mod/module/insignia/medic + color = "#ebebf5" + +/obj/item/mod/module/insignia/janitor + color = "#7925c7" + +/obj/item/mod/module/insignia/clown + color = "#ff1fc7" + +/obj/item/mod/module/insignia/chaplain + color = "#f0a00c" diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm index f192dedc27a..27bd102d790 100644 --- a/code/modules/power/cell.dm +++ b/code/modules/power/cell.dm @@ -426,6 +426,10 @@ . = ..() charge = 50000 +/obj/item/stock_parts/cell/crystal_cell/wizard + desc = "A very high power cell made from crystallized magic." + chargerate = 5000 + /obj/item/stock_parts/cell/inducer_supply maxcharge = 5000 charge = 5000 diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index de4e694822e..d31e279e245 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -399,7 +399,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne var/mob/M = i if(M.z != z && !(SSmapping.level_trait(z, ZTRAITS_STATION) && SSmapping.level_trait(M.z, ZTRAITS_STATION))) continue - M.update_gravity(M.mob_has_gravity()) + M.update_gravity(M.has_gravity()) if(M.client) shake_camera(M, 15, 1) M.playsound_local(T, null, 100, 1, 0.5, S = alert_sound) diff --git a/code/modules/projectiles/ammunition/_ammunition.dm b/code/modules/projectiles/ammunition/_ammunition.dm index c9b2451448b..d834594dbd0 100644 --- a/code/modules/projectiles/ammunition/_ammunition.dm +++ b/code/modules/projectiles/ammunition/_ammunition.dm @@ -65,16 +65,16 @@ */ /obj/item/ammo_casing/proc/add_notes_ammo() // Try to get a projectile to derive stats from - var/obj/projectile/exam_proj = GLOB.proj_by_path_key[projectile_type] - if(!istype(exam_proj) || pellets == 0) + var/obj/projectile/exam_proj = projectile_type + if(!ispath(exam_proj) || pellets == 0) return var/list/readout = list() // No dividing by 0 - if(exam_proj.damage > 0) - readout += "Most monkeys our legal team subjected to these [span_warning(caliber)] rounds succumbed to their wounds after [span_warning("[HITS_TO_CRIT(exam_proj.damage * pellets)] shot\s")] at point-blank, taking [span_warning("[pellets] shot\s")] per round" - if(exam_proj.stamina > 0) - readout += "[!readout.len ? "Most monkeys" : "More fortunate monkeys"] collapsed from exhaustion after [span_warning("[HITS_TO_CRIT(exam_proj.stamina * pellets)] impact\s")] of these [span_warning("[caliber]")] rounds" + if(initial(exam_proj.damage) > 0) + readout += "Most monkeys our legal team subjected to these [span_warning(caliber)] rounds succumbed to their wounds after [span_warning("[HITS_TO_CRIT(initial(exam_proj.damage) * pellets)] shot\s")] at point-blank, taking [span_warning("[pellets] shot\s")] per round" + if(initial(exam_proj.stamina) > 0) + readout += "[!readout.len ? "Most monkeys" : "More fortunate monkeys"] collapsed from exhaustion after [span_warning("[HITS_TO_CRIT(initial(exam_proj.stamina) * pellets)] impact\s")] of these [span_warning("[caliber]")] rounds" if(!readout.len) // Everything else failed, give generic text return "Our legal team has determined the offensive nature of these [span_warning(caliber)] rounds to be esoteric" return readout.Join("\n") // Sending over a single string, rather than the whole list diff --git a/code/modules/projectiles/ammunition/special/syringe.dm b/code/modules/projectiles/ammunition/special/syringe.dm index 529609efe17..59f5f3b3177 100644 --- a/code/modules/projectiles/ammunition/special/syringe.dm +++ b/code/modules/projectiles/ammunition/special/syringe.dm @@ -18,7 +18,7 @@ S.reagents.trans_to(loaded_projectile, S.reagents.total_volume, transfered_by = user) loaded_projectile.name = S.name var/obj/projectile/bullet/dart/D = loaded_projectile - D.piercing = S.proj_piercing + D.inject_flags = S.inject_flags SG.syringes.Remove(S) qdel(S) else if(istype(loc, /obj/item/mecha_parts/mecha_equipment/medical/syringe_gun)) @@ -27,7 +27,7 @@ var/obj/projectile/bullet/dart/shot_dart = loaded_projectile syringe_gun.reagents.trans_to(shot_dart, min(loaded_syringe.volume, syringe_gun.reagents.total_volume), transfered_by = user) shot_dart.name = loaded_syringe.name - shot_dart.piercing = loaded_syringe.proj_piercing + shot_dart.inject_flags = loaded_syringe.inject_flags LAZYREMOVE(syringe_gun.syringes, loaded_syringe) qdel(loaded_syringe) return ..() diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 44c2e2e96fd..5d959c5265b 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -79,14 +79,14 @@ readout += "\nStandard models of this projectile weapon have [span_warning("[ammo_type.len] mode\s")]" readout += "Our heroic interns have shown that one can theoretically stay standing after..." for(var/obj/item/ammo_casing/energy/for_ammo as anything in ammo_type) - exam_proj = GLOB.proj_by_path_key[for_ammo?.projectile_type] - if(!istype(exam_proj)) + exam_proj = for_ammo.projectile_type + if(!ispath(exam_proj)) continue - if(exam_proj.damage > 0) // Don't divide by 0!!!!! - readout += "[span_warning("[HITS_TO_CRIT(exam_proj.damage * for_ammo.pellets)] shot\s")] on [span_warning("[for_ammo.select_name]")] mode before collapsing from [exam_proj.damage_type == STAMINA ? "immense pain" : "their wounds"]." - if(exam_proj.stamina > 0) // In case a projectile does damage AND stamina damage (Energy Crossbow) - readout += "[span_warning("[HITS_TO_CRIT(exam_proj.stamina * for_ammo.pellets)] shot\s")] on [span_warning("[for_ammo.select_name]")] mode before collapsing from immense pain." + if(initial(exam_proj.damage) > 0) // Don't divide by 0!!!!! + readout += "[span_warning("[HITS_TO_CRIT(initial(exam_proj.damage) * for_ammo.pellets)] shot\s")] on [span_warning("[for_ammo.select_name]")] mode before collapsing from [initial(exam_proj.damage_type) == STAMINA ? "immense pain" : "their wounds"]." + if(initial(exam_proj.stamina) > 0) // In case a projectile does damage AND stamina damage (Energy Crossbow) + readout += "[span_warning("[HITS_TO_CRIT(initial(exam_proj.stamina) * for_ammo.pellets)] shot\s")] on [span_warning("[for_ammo.select_name]")] mode before collapsing from immense pain." else readout += "a theoretically infinite number of shots on [span_warning("[for_ammo.select_name]")] mode." diff --git a/code/modules/projectiles/projectile/bullets/dart_syringe.dm b/code/modules/projectiles/projectile/bullets/dart_syringe.dm index b54f1dcdfa4..1f853127858 100644 --- a/code/modules/projectiles/projectile/bullets/dart_syringe.dm +++ b/code/modules/projectiles/projectile/bullets/dart_syringe.dm @@ -4,7 +4,7 @@ damage = 6 embedding = null shrapnel_type = null - var/piercing = FALSE + var/inject_flags = null /obj/projectile/bullet/dart/Initialize(mapload) . = ..() @@ -14,7 +14,7 @@ if(iscarbon(target)) var/mob/living/carbon/M = target if(blocked != 100) // not completely blocked - if(M.can_inject(target_zone = def_zone, injection_flags = piercing ? INJECT_CHECK_PENETRATE_THICK : null)) // Pass the hit zone to see if it can inject by whether it hit the head or the body. + if(M.can_inject(target_zone = def_zone, injection_flags = inject_flags)) // Pass the hit zone to see if it can inject by whether it hit the head or the body. ..() reagents.trans_to(M, reagents.total_volume, methods = INJECT) return BULLET_ACT_HIT @@ -47,4 +47,4 @@ reagents.flags &= ~NO_REACT /obj/projectile/bullet/dart/piercing - piercing = TRUE + inject_flags = INJECT_CHECK_PENETRATE_THICK diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index de70a25b598..b783a54d2b2 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -110,7 +110,7 @@ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' amount_per_transfer_from_this = 15 volume = 15 - ignore_flags = 1 //so you can medipen through hardsuits + ignore_flags = 1 //so you can medipen through spacesuits reagent_flags = DRAWABLE flags_1 = null list_reagents = list(/datum/reagent/medicine/epinephrine = 10, /datum/reagent/toxin/formaldehyde = 3, /datum/reagent/medicine/coagulant = 2) @@ -279,7 +279,7 @@ /obj/item/reagent_containers/hypospray/medipen/magillitis name = "experimental autoinjector" - desc = "A custom-frame needle injector with a small single-use reservoir, containing an experimental serum. Unlike the more common medipen frame, it cannot pierce through protective armor or hardsuits, nor can the chemical inside be extracted." + desc = "A custom-frame needle injector with a small single-use reservoir, containing an experimental serum. Unlike the more common medipen frame, it cannot pierce through protective armor or space suits, nor can the chemical inside be extracted." icon_state = "gorillapen" inhand_icon_state = "gorillapen" base_icon_state = "gorillapen" diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index b0007c4b5bb..88368910ee5 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -10,12 +10,12 @@ amount_per_transfer_from_this = 5 possible_transfer_amounts = list(5, 10, 15) volume = 15 - var/busy = FALSE // needed for delayed drawing of blood - var/proj_piercing = 0 //does it pierce through thick clothes when shot with syringe gun custom_materials = list(/datum/material/iron=10, /datum/material/glass=20) reagent_flags = TRANSPARENT custom_price = PAYCHECK_EASY * 0.5 sharpness = SHARP_POINTY + /// Flags used by the injection + var/inject_flags = NONE /obj/item/reagent_containers/syringe/Initialize(mapload) . = ..() @@ -25,8 +25,6 @@ return /obj/item/reagent_containers/syringe/proc/try_syringe(atom/target, mob/user, proximity) - if(busy) - return FALSE if(!proximity) return FALSE if(!target.reagents) @@ -34,7 +32,7 @@ if(isliving(target)) var/mob/living/living_target = target - if(!living_target.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE)) + if(!living_target.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE|inject_flags)) return FALSE // chance of monkey retaliation @@ -64,12 +62,12 @@ if(isliving(target)) var/mob/living/living_target = target - if(!living_target.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE)) + if(!living_target.try_inject(user, injection_flags = INJECT_TRY_SHOW_ERROR_MESSAGE|inject_flags)) return if(living_target != user) living_target.visible_message(span_danger("[user] is trying to inject [living_target]!"), \ span_userdanger("[user] is trying to inject you!")) - if(!do_mob(user, living_target, CHEM_INTERACT_DELAY(3 SECONDS, user), extra_checks = CALLBACK(living_target, /mob/living/proc/try_inject, user, null, INJECT_TRY_SHOW_ERROR_MESSAGE))) + if(!do_mob(user, living_target, CHEM_INTERACT_DELAY(3 SECONDS, user), extra_checks = CALLBACK(living_target, /mob/living/proc/try_inject, user, null, INJECT_TRY_SHOW_ERROR_MESSAGE|inject_flags))) return if(!reagents.total_volume) return @@ -99,13 +97,10 @@ if(target != user) target.visible_message(span_danger("[user] is trying to take a blood sample from [target]!"), \ span_userdanger("[user] is trying to take a blood sample from you!")) - busy = TRUE - if(!do_mob(user, target, CHEM_INTERACT_DELAY(3 SECONDS, user), extra_checks = CALLBACK(living_target, /mob/living/proc/try_inject, user, null, INJECT_TRY_SHOW_ERROR_MESSAGE))) - busy = FALSE + if(!do_mob(user, target, CHEM_INTERACT_DELAY(3 SECONDS, user), extra_checks = CALLBACK(living_target, /mob/living/proc/try_inject, user, null, INJECT_TRY_SHOW_ERROR_MESSAGE|inject_flags))) return SECONDARY_ATTACK_CONTINUE_CHAIN if(reagents.total_volume >= reagents.maximum_volume) return SECONDARY_ATTACK_CONTINUE_CHAIN - busy = FALSE if(living_target.transfer_blood_to(src, drawn_amount)) user.visible_message(span_notice("[user] takes a blood sample from [living_target].")) else @@ -234,7 +229,7 @@ base_icon_state = "piercing" volume = 10 possible_transfer_amounts = list(5, 10) - proj_piercing = 1 + inject_flags = INJECT_CHECK_PENETRATE_THICK /obj/item/reagent_containers/syringe/spider_extract name = "spider extract syringe" diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm index 3eb67e147a6..5db499a188a 100644 --- a/code/modules/recycling/disposal/bin.dm +++ b/code/modules/recycling/disposal/bin.dm @@ -255,7 +255,7 @@ AM.forceMove(T) ..() -/obj/machinery/disposal/get_dumping_location(obj/item/storage/source,mob/user) +/obj/machinery/disposal/get_dumping_location() return src //How disposal handles getting a storage dump from a storage object diff --git a/code/modules/religion/rites.dm b/code/modules/religion/rites.dm index ff63cc18930..f453e023342 100644 --- a/code/modules/religion/rites.dm +++ b/code/modules/religion/rites.dm @@ -167,7 +167,7 @@ /datum/religion_rites/fireproof/invoke_effect(mob/living/user, atom/religious_tool) ..() if(!QDELETED(chosen_clothing) && get_turf(religious_tool) == chosen_clothing.loc) //check if the same clothing is still there - if(istype(chosen_clothing,/obj/item/clothing/suit/hooded) || istype(chosen_clothing,/obj/item/clothing/suit/space/hardsuit )) + if(istype(chosen_clothing,/obj/item/clothing/suit/hooded)) for(var/obj/item/clothing/head/integrated_helmet in chosen_clothing.contents) //check if the clothing has a hood/helmet integrated and fireproof it if there is one. apply_fireproof(integrated_helmet) apply_fireproof(chosen_clothing) diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm index 8608baaf914..babd4407d2f 100644 --- a/code/modules/research/designs/mechfabricator_designs.dm +++ b/code/modules/research/designs/mechfabricator_designs.dm @@ -887,7 +887,7 @@ category = list("Cyborg Upgrade Modules") /datum/design/boris_ai_controller - name = "B.O.R.I.S. AI-Cyborg Remote Control Module" + name = "B.O.R.I.S. AI-Cyborg Remote Control" id = "borg_ai_control" build_type = MECHFAB build_path = /obj/item/borg/upgrade/ai @@ -969,3 +969,336 @@ construction_time = 100 build_path = /obj/item/assembly/flash/handheld category = list("Misc") + +//MODsuit stuff + +/datum/design/mod_shell + name = "MOD shell" + desc = "A 'Nakamura Engineering' designed shell for a Modular Suit." + id = "mod_shell" + build_type = MECHFAB + materials = list(/datum/material/iron = 10000, /datum/material/plasma = 5000) + construction_time = 25 SECONDS + build_path = /obj/item/mod/construction/shell + category = list("MOD Construction") + +/datum/design/mod_helmet + name = "MOD helmet" + desc = "A 'Nakamura Engineering' designed helmet for a Modular Suit." + id = "mod_helmet" + build_type = MECHFAB + materials = list(/datum/material/iron = 5000) + construction_time = 10 SECONDS + build_path = /obj/item/mod/construction/helmet + category = list("MOD Construction") + +/datum/design/mod_chestplate + name = "MOD chestplate" + desc = "A 'Nakamura Engineering' designed chestplate for a Modular Suit." + id = "mod_chestplate" + build_type = MECHFAB + materials = list(/datum/material/iron = 5000) + construction_time = 10 SECONDS + build_path = /obj/item/mod/construction/chestplate + category = list("MOD Construction") + +/datum/design/mod_gauntlets + name = "MOD gauntlets" + desc = "'Nakamura Engineering' designed gauntlets for a Modular Suit." + id = "mod_gauntlets" + build_type = MECHFAB + materials = list(/datum/material/iron = 5000) + construction_time = 10 SECONDS + build_path = /obj/item/mod/construction/gauntlets + category = list("MOD Construction") + +/datum/design/mod_boots + name = "MOD boots" + desc = "'Nakamura Engineering' designed boots for a Modular Suit." + id = "mod_boots" + build_type = MECHFAB + materials = list(/datum/material/iron = 5000) + construction_time = 10 SECONDS + build_path = /obj/item/mod/construction/boots + category = list("MOD Construction") + +/datum/design/mod_armor + name = "MOD armor" + desc = "External armor for a Modular Suit." + id = "mod_armor_standard" + build_type = MECHFAB|PROTOLATHE + materials = list(/datum/material/iron = 6000, /datum/material/glass = 3000, /datum/material/plasma = 1000) + construction_time = 15 SECONDS + build_path = /obj/item/mod/construction/armor + category = list("MOD Construction", "Equipment") + research_icon = 'icons/obj/mod.dmi' + research_icon_state = "standard-armor" + +/datum/design/mod_armor/New() + . = ..() + var/obj/item/mod/construction/armor/armor_type = build_path + var/datum/mod_theme/theme = GLOB.mod_themes[initial(armor_type.theme)] + name = "MOD [theme.name] armor" + desc = "External armor for a Modular Suit. [theme.desc]" + +/datum/design/mod_armor/engineering + id = "mod_armor_engineering" + build_path = /obj/item/mod/construction/armor/engineering + materials = list(/datum/material/iron = 6000, /datum/material/gold = 2000, /datum/material/glass = 1000, /datum/material/plasma = 1000) + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING + research_icon_state = "engineering-armor" + +/datum/design/mod_armor/atmospheric + id = "mod_armor_atmospheric" + build_path = /obj/item/mod/construction/armor/atmospheric + materials = list(/datum/material/iron = 6000, /datum/material/titanium = 2000, /datum/material/glass = 1000, /datum/material/plasma = 1000) + departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING + research_icon_state = "atmospheric-armor" + +/datum/design/mod_armor/medical + id = "mod_armor_medical" + build_path = /obj/item/mod/construction/armor/medical + materials = list(/datum/material/iron = 6000, /datum/material/silver = 2000, /datum/material/glass = 1000, /datum/material/plasma = 1000) + departmental_flags = DEPARTMENTAL_FLAG_MEDICAL + research_icon_state = "medical-armor" + +/datum/design/mod_armor/security + id = "mod_armor_security" + build_path = /obj/item/mod/construction/armor/security + materials = list(/datum/material/iron = 6000, /datum/material/uranium = 2000, /datum/material/glass = 1000, /datum/material/plasma = 1000) + departmental_flags = DEPARTMENTAL_FLAG_SECURITY + research_icon_state = "security-armor" + +/datum/design/mod_armor/cosmohonk + id = "mod_armor_cosmohonk" + build_path = /obj/item/mod/construction/armor/cosmohonk + materials = list(/datum/material/iron = 6000, /datum/material/bananium = 2000, /datum/material/glass = 1000, /datum/material/plasma = 1000) + departmental_flags = DEPARTMENTAL_FLAG_SERVICE + research_icon_state = "cosmohonk-armor" + +/datum/design/mod_paint_kit + name = "MOD paint kit" + desc = "A paint kit for Modular Suits." + id = "mod_paint_kit" + build_type = MECHFAB + materials = list(/datum/material/iron = 1000, /datum/material/plastic = 500) + construction_time = 5 SECONDS + build_path = /obj/item/mod/paint + category = list("Misc") + +/datum/design/module + name = "MOD Module" + build_type = MECHFAB + construction_time = 1 SECONDS + materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000) + build_path = /obj/item/mod/module + category = list("MOD Modules") + +/datum/design/module/New() + . = ..() + var/obj/item/mod/module/module = build_path + desc = "[initial(module.desc)] It uses [initial(module.complexity)] complexity." + +/datum/design/module/mod_storage + name = "MOD Module: Storage" + id = "mod_storage" + materials = list(/datum/material/iron = 2500, /datum/material/glass = 500) + build_path = /obj/item/mod/module/storage + +/datum/design/module/mod_visor_medhud + name = "MOD Module: Medical Visor" + id = "mod_visor_medhud" + materials = list(/datum/material/silver = 500, /datum/material/glass = 1000) + build_path = /obj/item/mod/module/visor/medhud + +/datum/design/module/mod_visor_diaghud + name = "MOD Module: Diagnostic Visor" + id = "mod_visor_diaghud" + materials = list(/datum/material/gold = 500, /datum/material/glass = 1000) + build_path = /obj/item/mod/module/visor/diaghud + +/datum/design/module/mod_visor_sechud + name = "MOD Module: Security Visor" + id = "mod_visor_sechud" + materials = list(/datum/material/titanium = 500, /datum/material/glass = 1000) + build_path = /obj/item/mod/module/visor/sechud + +/datum/design/module/mod_visor_meson + name = "MOD Module: Meson Visor" + id = "mod_visor_meson" + materials = list(/datum/material/uranium = 500, /datum/material/glass = 1000) + build_path = /obj/item/mod/module/visor/meson + +/datum/design/module/mod_visor_welding + name = "MOD Module: Welding Protection" + id = "mod_welding" + materials = list(/datum/material/iron = 500, /datum/material/glass = 500) + build_path = /obj/item/mod/module/welding + +/datum/design/module/mod_t_ray + name = "MOD Module: T-Ray Scanner" + id = "mod_t_ray" + materials = list(/datum/material/iron = 500, /datum/material/glass = 1000) + build_path = /obj/item/mod/module/t_ray + +/datum/design/module/mod_health_analyzer + name = "MOD Module: Health Analyzer" + id = "mod_health_analyzer" + materials = list(/datum/material/iron = 500, /datum/material/glass = 1000) + build_path = /obj/item/mod/module/health_analyzer + +/datum/design/module/mod_stealth + name = "MOD Module: Cloak" + id = "mod_stealth" + materials = list(/datum/material/iron = 1000, /datum/material/bluespace = 500) + build_path = /obj/item/mod/module/stealth + +/datum/design/module/mod_jetpack + name = "MOD Module: Ion Jetpack" + id = "mod_jetpack" + materials = list(/datum/material/iron = 1500, /datum/material/plasma = 1000) + build_path = /obj/item/mod/module/jetpack + +/datum/design/module/mod_magboot + name = "MOD Module: Magnetic Stabilizator" + id = "mod_magboot" + materials = list(/datum/material/iron = 1000, /datum/material/gold = 500) + build_path = /obj/item/mod/module/magboot + +/datum/design/module/mod_holster + name = "MOD Module: Holster" + id = "mod_holster" + materials = list(/datum/material/iron = 1500, /datum/material/glass = 500) + build_path = /obj/item/mod/module/holster + +/datum/design/module/mod_tether + name = "MOD Module: Emergency Tether" + id = "mod_tether" + materials = list(/datum/material/iron = 1000, /datum/material/silver = 500) + build_path = /obj/item/mod/module/tether + +/datum/design/module/mod_mouthhole + name = "MOD Module: Eating Apparatus" + id = "mod_mouthhole" + materials = list(/datum/material/iron = 1500) + build_path = /obj/item/mod/module/mouthhole + +/datum/design/module/mod_rad_protection + name = "MOD Module: Radiation Protection" + id = "mod_rad_protection" + materials = list(/datum/material/iron = 1000, /datum/material/uranium = 1000) + build_path = /obj/item/mod/module/rad_protection + +/datum/design/module/mod_emp_shield + name = "MOD Module: EMP Shield" + id = "mod_emp_shield" + materials = list(/datum/material/iron = 1000, /datum/material/plasma = 1000) + build_path = /obj/item/mod/module/emp_shield + +/datum/design/module/mod_flashlight + name = "MOD Module: Flashlight" + id = "mod_flashlight" + materials = list(/datum/material/iron = 500, /datum/material/glass = 1000) + build_path = /obj/item/mod/module/flashlight + +/datum/design/module/mod_reagent_scanner + name = "MOD Module: Reagent Scanner" + id = "mod_reagent_scanner" + materials = list(/datum/material/glass = 1000) + build_path = /obj/item/mod/module/reagent_scanner + +/datum/design/module/mod_gps + name = "MOD Module: Internal GPS" + id = "mod_gps" + materials = list(/datum/material/iron = 500, /datum/material/glass = 500) + build_path = /obj/item/mod/module/gps + +/datum/design/module/mod_constructor + name = "MOD Module: Constructor" + id = "mod_constructor" + materials = list(/datum/material/iron = 1000, /datum/material/titanium = 500) + build_path = /obj/item/mod/module/constructor + +/datum/design/module/mod_quick_carry + name = "MOD Module: Quick Carry" + id = "mod_quick_carry" + materials = list(/datum/material/iron = 1000, /datum/material/titanium = 500) + build_path = /obj/item/mod/module/quick_carry + +/datum/design/module/mod_longfall + name = "MOD Module: Longfall" + id = "mod_longfall" + materials = list(/datum/material/iron = 1000) + build_path = /obj/item/mod/module/longfall + +/datum/design/module/mod_thermal_regulator + name = "MOD Module: Thermal Regulator" + id = "mod_thermal_regulator" + materials = list(/datum/material/iron = 500, /datum/material/glass = 1000) + build_path = /obj/item/mod/module/thermal_regulator + +/datum/design/module/mod_injector + name = "MOD Module: Injector" + id = "mod_injector" + materials = list(/datum/material/iron = 1000, /datum/material/diamond = 500) + build_path = /obj/item/mod/module/injector + +/datum/design/module/mod_microwave_beam + name = "MOD Module: Microwave Beam" + id = "mod_microwave_beam" + materials = list(/datum/material/iron = 1000, /datum/material/uranium = 500) + build_path = /obj/item/mod/module/microwave_beam + +/datum/design/module/mod_bikehorn + name = "MOD Module: Bike Horn" + id = "mod_bikehorn" + materials = list(/datum/material/plastic = 500, /datum/material/iron = 500) + build_path = /obj/item/mod/module/bikehorn + +/datum/design/module/mod_clamp + name = "MOD Module: Crate Clamp" + id = "mod_clamp" + materials = list(/datum/material/iron = 2000) + build_path = /obj/item/mod/module/clamp + +/datum/design/module/mod_drill + name = "MOD Module: Drill" + id = "mod_drill" + materials = list(/datum/material/silver = 1000, /datum/material/iron = 2000) + build_path = /obj/item/mod/module/drill + +/datum/design/module/mod_orebag + name = "MOD Module: Ore Bag" + id = "mod_orebag" + materials = list(/datum/material/iron = 1500) + build_path = /obj/item/mod/module/orebag + +/datum/design/module/mod_organ_thrower + name = "MOD Module: Organ Thrower" + id = "mod_organ_thrower" + materials = list(/datum/material/iron = 1000, /datum/material/glass = 1000) + build_path = /obj/item/mod/module/organ_thrower + +/datum/design/module/mod_pathfinder + name = "MOD Module: Pathfinder" + id = "mod_pathfinder" + materials = list(/datum/material/uranium = 1000, /datum/material/iron = 1000) + build_path = /obj/item/mod/module/pathfinder + +/datum/design/module/mod_dna_lock + name = "MOD Module: DNA Lock" + id = "mod_dna_lock" + materials = list(/datum/material/diamond = 500, /datum/material/glass = 1000) + build_path = /obj/item/mod/module/dna_lock + +/datum/design/module/mod_circuit + name = "MOD Module: Circuit Adapter" + id = "mod_circuit" + materials = list(/datum/material/glass = 2000) + build_path = /obj/item/mod/module/circuit + +/datum/design/module/mod_plasma_stabilizer + name = "MOD Module: Plasma Stabilizer" + id = "mod_plasma" + materials = list(/datum/material/plasma = 1000, /datum/material/glass = 1000) + build_path = /obj/item/mod/module/plasma_stabilizer diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm index d99cb469eea..9ce890c9399 100644 --- a/code/modules/research/techweb/all_nodes.dm +++ b/code/modules/research/techweb/all_nodes.dm @@ -112,6 +112,28 @@ "ripleyupgrade", ) +/datum/techweb_node/mod_basic + id = "mod" + starting_node = TRUE + display_name = "Basic Modular Suits" + description = "Specialized back mounted power suits with various different modules." + design_ids = list( + "mod_armor_standard", + "mod_boots", + "mod_chestplate", + "mod_gauntlets", + "mod_helmet", + "mod_paint_kit", + "mod_shell", + "mod_storage", + "mod_welding", + "mod_mouthhole", + "mod_flashlight", + "mod_longfall", + "mod_thermal_regulator", + "mod_plasma", + ) + /datum/techweb_node/mech_tools id = "mech_tools" starting_node = TRUE @@ -691,6 +713,7 @@ "dispenser_shell", "door_shell", "gun_shell", + "mod_circuit", "money_bot_shell", "scanner_gate_shell", "scanner_shell", @@ -1419,6 +1442,96 @@ ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) +//MODsuit tech + +/datum/techweb_node/mod_advanced + id = "mod_advanced" + display_name = "Advanced Modular Suits" + description = "More advanced modules, to improve modular suits." + prereq_ids = list("robotics") + design_ids = list( + "mod_visor_diaghud", + "mod_stealth", + "mod_holster", + "mod_gps", + "mod_reagent_scanner", + "mod_clamp", + "mod_drill", + "mod_orebag", + "mod_pathfinder", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + +/datum/techweb_node/mod_engineering + id = "mod_engineering" + display_name = "Engineering Modular Suits" + description = "Engineering suits, for powered engineers." + prereq_ids = list("mod_advanced", "engineering") + design_ids = list( + "mod_armor_engineering", + "mod_visor_meson", + "mod_t_ray", + "mod_magboot", + "mod_tether", + "mod_constructor", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + +/datum/techweb_node/mod_advanced_engineering + id = "mod_advanced_engineering" + display_name = "Advanced Engineering Modular Suits" + description = "Advanced Engineering suits, for advanced powered engineers." + prereq_ids = list("mod_engineering", "adv_engi") + design_ids = list( + "mod_armor_atmospheric", + "mod_jetpack", + "mod_rad_protection", + "mod_emp_shield", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 3500) + +/datum/techweb_node/mod_medical + id = "mod_medical" + display_name = "Medical Modular Suits" + description = "Medical suits for quick rescue purposes." + prereq_ids = list("mod_advanced", "biotech") + design_ids = list( + "mod_armor_medical", + "mod_visor_medhud", + "mod_health_analyzer", + "mod_quick_carry", + "mod_injector", + "mod_organ_thrower", + "mod_dna_lock", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + +/datum/techweb_node/mod_security + id = "mod_security" + display_name = "Security Modular Suits" + description = "Security suits for space crime handling." + prereq_ids = list("mod_advanced", "sec_basic") + design_ids = list( + "mod_armor_security", + "mod_visor_sechud", + "mod_stealth", + "mod_holster", + "mod_pathfinder", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + +/datum/techweb_node/mod_entertainment + id = "mod_entertainment" + display_name = "Entertainment Modular Suits" + description = "Powered suits for protection against low-humor environments." + prereq_ids = list("mod_advanced", "clown") + design_ids = list( + "mod_armor_cosmohonk", + "mod_bikehorn", + "mod_microwave_beam", + ) + research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 2500) + ////////////////////////mech technology//////////////////////// /datum/techweb_node/adv_mecha id = "adv_mecha" diff --git a/code/modules/ruins/spaceruin_code/forgottenship.dm b/code/modules/ruins/spaceruin_code/forgottenship.dm index 030f98d3234..0aef05406f7 100644 --- a/code/modules/ruins/spaceruin_code/forgottenship.dm +++ b/code/modules/ruins/spaceruin_code/forgottenship.dm @@ -125,31 +125,6 @@ GLOBAL_VAR_INIT(fscpassword, generate_password()) ambientsounds = list('sound/ambience/ambitech2.ogg', 'sound/ambience/ambitech3.ogg') area_flags = NOTELEPORT | UNIQUE_AREA - //Cybersun hardsuit - -/obj/item/clothing/head/helmet/space/hardsuit/cybersun - name = "Cybersun hardsuit helmet" - desc = "Prototype hardsuit helmet with experimental armor plates, protecting from laser-based weapons very well, while giving limited protection against anything else." - icon_state = "cybersun" - inhand_icon_state = "cybersun" - hardsuit_type = "cybersun" - armor = list(MELEE = 30, BULLET = 40, LASER = 55, ENERGY = 55, BOMB = 30, BIO = 100, FIRE = 60, ACID = 60) - strip_delay = 600 - actions_types = list() - - -/obj/item/clothing/suit/space/hardsuit/cybersun - icon_state = "cybersun" - inhand_icon_state = "cybersun" - hardsuit_type = "cybersun" - name = "Cybersun hardsuit" - desc = "Prototype hardsuit with experimental armor plates, protecting from laser-based weapons very well, while giving limited protection against anything else." - armor = list(MELEE = 30, BULLET = 40, LASER = 55, ENERGY = 55, BOMB = 30, BIO = 100, FIRE = 60, ACID = 60) - slowdown = 0 - helmettype = /obj/item/clothing/head/helmet/space/hardsuit/cybersun - actions_types = list(/datum/action/item_action/toggle_helmet, /datum/action/item_action/toggle_spacesuit) - jetpack = /obj/item/tank/jetpack/suit - //Special NT NPCs /mob/living/simple_animal/hostile/nanotrasen/ranged/assault diff --git a/code/modules/ruins/spaceruin_code/oldstation.dm b/code/modules/ruins/spaceruin_code/oldstation.dm index d0aba170752..a3a6371ad75 100644 --- a/code/modules/ruins/spaceruin_code/oldstation.dm +++ b/code/modules/ruins/spaceruin_code/oldstation.dm @@ -9,11 +9,15 @@ info = "*Damage Report*

Alpha Station - Destroyed

Beta Station - Catastrophic Damage. Medical, destroyed. Atmospherics, partially destroyed. Engine Core, destroyed.

Charlie Station - Multiple asteroid impacts, no loss in air pressure.

Delta Station - Intact. WARNING: Unknown force occupying Delta Station. Intent unknown. Species unknown. Numbers unknown.

Recommendation - Reestablish station powernet via solar array. Reestablish station atmospherics system to restore air." /obj/item/paper/fluff/ruins/oldstation/protosuit - name = "B01-RIG Hardsuit Report" - info = "*Prototype Hardsuit*

The B01-RIG Hardsuit is a prototype powered exoskeleton. Based off a recovered pre-void war era united Earth government powered military \ - exosuit, the RIG Hardsuit is a breakthrough in Hardsuit technology, and is the first post-void war era Hardsuit that can be safely used by an operator.

The B01 however suffers \ - a myriad of constraints. It is slow and bulky to move around, it lacks any significant armor plating against direct attacks and its internal heads up display is unfinished, \ - resulting in the user being unable to see long distances.

The B01 is unlikely to see any form of mass production, but will serve as a base for future Hardsuit developments." + name = "B01-MOD modular suit Report" + info = "*Prototype MODsuit*

This is a prototype powered exoskeleton, a design not seen in hundreds of years, \ + the first post-void war era modular suit to ever be safely utilized by an operator. \ + This ancient clunker is still functional, though it's missing several modern-day luxuries from \ + updated Nakamura Engineering designs. Primarily, the suit's myoelectric suit layer is entirely non-existant, \ + and the servos do very little to help distribute the weight evenly across the wearer's body, \ + making it slow and bulky to move in. Additionally, the armor plating never finished production aside from the shoulders, \ + forearms, and helmet; making it useless against direct attacks. The internal heads-up display is rendered entirely in \ + monochromatic cyan, leaving the user unable to see long distances. However, the way the helmet retracts is pretty cool." /obj/item/paper/fluff/ruins/oldstation/protohealth name = "Health Analyser Report" @@ -41,7 +45,7 @@ /obj/item/paper/fluff/ruins/oldstation/protoinv name = "Laboratory Inventory" - info = "*Inventory*

(1) Prototype Hardsuit

(1)Health Analyser

(1)Prototype Energy Gun

(1)Singularity Generation Disk

DO NOT REMOVE WITHOUT \ + info = "*Inventory*

(1) Prototype MODsuit

(1)Health Analyser

(1)Prototype Energy Gun

(1)Singularity Generation Disk

DO NOT REMOVE WITHOUT \ THE CAPTAIN AND RESEARCH DIRECTOR'S AUTHORISATION" /obj/item/paper/fluff/ruins/oldstation/report @@ -66,3 +70,116 @@ I have no fucking idea what they are, all I know is that they don't like me. On occasion I hear them hissing and clawing on the airlock... good idea I barricaded the way in. Bad news: the transit tube is still broken, the damn engineers never fixed it. \ So basically, I'm stuck here until someone comes to rescue us. And I have no food or water.
If you're reading this, I'm probably dead. These things have taken over part of Delta station, and I think they somehow came from the AI core... \ Whatever you do, DON'T OPEN THE FIRELOCKS unless you have something to kill them. Look in security, maybe there might be some gear left in there.

So hungry... I don't want to go out like this..." + +/obj/machinery/mod_installer + name = "modular outerwear device installator" + desc = "An ancient machine that mounts a MOD unit onto the occupant." + icon = 'icons/obj/machines/mod_installer.dmi' + icon_state = "mod_installer" + base_icon_state = "mod_installer" + layer = ABOVE_WINDOW_LAYER + use_power = IDLE_POWER_USE + anchored = TRUE + density = TRUE + obj_flags = NO_BUILD // Becomes undense when the door is open + idle_power_usage = 50 + active_power_usage = 300 + + var/busy = FALSE + var/busy_icon_state + + var/obj/item/mod/control/mod_unit = /obj/item/mod/control/pre_equipped/prototype + + COOLDOWN_DECLARE(message_cooldown) + +/obj/machinery/mod_installer/Initialize(mapload) + . = ..() + occupant_typecache = typecacheof(/mob/living/carbon/human) + if(ispath(mod_unit)) + mod_unit = new mod_unit() + +/obj/machinery/mod_installer/Destroy() + QDEL_NULL(mod_unit) + return ..() + +/obj/machinery/mod_installer/proc/set_busy(status, working_icon) + busy = status + busy_icon_state = working_icon + update_appearance() + +/obj/machinery/mod_installer/proc/play_install_sound() + playsound(src, 'sound/items/rped.ogg', 30, FALSE) + +/obj/machinery/mod_installer/update_icon_state() + icon_state = busy ? busy_icon_state : "[base_icon_state][state_open ? "_open" : null]" + return ..() + +/obj/machinery/mod_installer/update_overlays() + var/list/overlays = ..() + if(machine_stat & (NOPOWER|BROKEN)) + return overlays + overlays += busy ? "red" : "green" + return overlays + +/obj/machinery/mod_installer/proc/start_process() + if(machine_stat & (NOPOWER|BROKEN)) + return + if(!occupant || !mod_unit || busy) + return + set_busy(TRUE, "[initial(icon_state)]_raising") + addtimer(CALLBACK(src, .proc/set_busy, TRUE, "[initial(icon_state)]_active"), 2.5 SECONDS) + addtimer(CALLBACK(src, .proc/play_install_sound), 2.5 SECONDS) + addtimer(CALLBACK(src, .proc/set_busy, TRUE, "[initial(icon_state)]_falling"), 5 SECONDS) + addtimer(CALLBACK(src, .proc/complete_process), 7.5 SECONDS) + +/obj/machinery/mod_installer/proc/complete_process() + set_busy(FALSE) + var/mob/living/carbon/human/human_occupant = occupant + if(!istype(human_occupant)) + return + if(!human_occupant.dropItemToGround(human_occupant.back)) + return + if(!human_occupant.equip_to_slot_if_possible(mod_unit, mod_unit.slot_flags, qdel_on_fail = FALSE, disable_warning = TRUE)) + return + human_occupant.update_action_buttons(TRUE) + playsound(src, 'sound/machines/ping.ogg', 30, FALSE) + if(!human_occupant.dropItemToGround(human_occupant.wear_suit) || !human_occupant.dropItemToGround(human_occupant.head)) + open_machine() + return + mod_unit.quick_activation() + open_machine() + +/obj/machinery/mod_installer/open_machine() + if(state_open) + return FALSE + ..() + return TRUE + +/obj/machinery/mod_installer/close_machine(mob/living/carbon/user) + if(!state_open) + return FALSE + ..() + addtimer(CALLBACK(src, .proc/start_process), 1 SECONDS) + return TRUE + +/obj/machinery/mod_installer/relaymove(mob/living/user, direction) + var/message + if(busy) + message = "it won't budge!" + else if(user.stat != CONSCIOUS) + message = "you don't have the energy!" + if(!isnull(message)) + if (COOLDOWN_FINISHED(src, message_cooldown)) + COOLDOWN_START(src, message_cooldown, 5 SECONDS) + balloon_alert(user, message) + return + open_machine() + +/obj/machinery/mod_installer/interact(mob/user) + if(state_open) + close_machine(null, user) + return + else if(busy) + balloon_alert(user, "it's locked!") + return + open_machine() diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm index ec8e9392954..c18ce60b5b7 100644 --- a/code/modules/spells/spell.dm +++ b/code/modules/spells/spell.dm @@ -120,7 +120,6 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th var/holder_var_amount = 20 //same. The amount adjusted with the mob's var when the spell is used var/clothes_req = TRUE //see if it requires clothes - var/cult_req = FALSE //SPECIAL SNOWFLAKE clothes required for cult only spells var/human_req = FALSE //spell can only be cast by humans var/nonabstract_req = FALSE //spell can only be cast by mobs that are physical entities var/stat_allowed = FALSE //see if it requires being conscious/alive, need to set to 1 for ghostpells @@ -198,27 +197,19 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th var/mob/living/carbon/human/H = user - var/static/list/casting_clothes = typecacheof(list(/obj/item/clothing/suit/wizrobe, - /obj/item/clothing/suit/space/hardsuit/wizard, - /obj/item/clothing/head/wizard, - /obj/item/clothing/head/helmet/space/hardsuit/wizard, - /obj/item/clothing/suit/space/hardsuit/shielded/wizard, - /obj/item/clothing/head/helmet/space/hardsuit/shielded/wizard)) - + var/static/list/casting_clothes = typecacheof(list(/obj/item/clothing/suit/wizrobe, /obj/item/clothing/head/wizard)) if(clothes_req) //clothes check - if(!is_type_in_typecache(H.wear_suit, casting_clothes)) + var/passes_req = FALSE + if(istype(H.back, /obj/item/mod/control)) + var/obj/item/mod/control/mod = H.back + if(istype(mod.theme, /datum/mod_theme/enchanted)) + passes_req = TRUE + if(!passes_req && !is_type_in_typecache(H.wear_suit, casting_clothes)) to_chat(H, span_warning("You don't feel strong enough without your robe!")) return FALSE - if(!is_type_in_typecache(H.head, casting_clothes)) + if(!passes_req && !is_type_in_typecache(H.head, casting_clothes)) to_chat(H, span_warning("You don't feel strong enough without your hat!")) return FALSE - if(cult_req) //CULT_REQ CLOTHES CHECK - if(!istype(H.wear_suit, /obj/item/clothing/suit/magusred) && !istype(H.wear_suit, /obj/item/clothing/suit/space/hardsuit/cult)) - to_chat(H, span_warning("You don't feel strong enough without your armor.")) - return FALSE - if(!istype(H.head, /obj/item/clothing/head/magus) && !istype(H.head, /obj/item/clothing/head/helmet/space/hardsuit/cult)) - to_chat(H, span_warning("You don't feel strong enough without your helmet.")) - return FALSE else if(clothes_req || human_req) to_chat(user, span_warning("This spell can only be cast by humans!")) @@ -595,11 +586,6 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th else VV_DROPDOWN_OPTION(VV_HK_SPELL_UNSET_ROBELESS, "Unset Robeless") - if(cult_req) - VV_DROPDOWN_OPTION(VV_HK_SPELL_SET_CULT, "Set Cult Robeless") - else - VV_DROPDOWN_OPTION(VV_HK_SPELL_UNSET_CULT, "Unset Cult Robeless") - if(human_req) VV_DROPDOWN_OPTION(VV_HK_SPELL_UNSET_HUMANONLY, "Unset Require Humanoid Mob") else @@ -618,12 +604,6 @@ GLOBAL_LIST_INIT(spells, typesof(/obj/effect/proc_holder/spell)) //needed for th if(href_list[VV_HK_SPELL_UNSET_ROBELESS]) clothes_req = TRUE return - if(href_list[VV_HK_SPELL_SET_CULT]) - cult_req = FALSE - return - if(href_list[VV_HK_SPELL_UNSET_CULT]) - cult_req = TRUE - return if(href_list[VV_HK_SPELL_UNSET_HUMANONLY]) human_req = FALSE return diff --git a/code/modules/spells/spell_types/rightandwrong.dm b/code/modules/spells/spell_types/rightandwrong.dm index ffd84018dac..e6533ad4d56 100644 --- a/code/modules/spells/spell_types/rightandwrong.dm +++ b/code/modules/spells/spell_types/rightandwrong.dm @@ -74,7 +74,6 @@ GLOBAL_LIST_INIT(summoned_magic, list( /obj/item/gun/magic/staff/door, /obj/item/scrying, /obj/item/warpwhistle, - /obj/item/clothing/suit/space/hardsuit/shielded/wizard, /obj/item/immortality_talisman, /obj/item/melee/ghost_sword)) @@ -89,7 +88,6 @@ GLOBAL_LIST_INIT(summoned_special_magic, list( //everything above except for single use spellbooks, because they are counted separately (and are for basic bitches anyways) GLOBAL_LIST_INIT(summoned_magic_objectives, list( /obj/item/antag_spawner/contract, - /obj/item/clothing/suit/space/hardsuit/shielded/wizard, /obj/item/gun/magic, /obj/item/immortality_talisman, /obj/item/melee/ghost_sword, diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm index 7e5d3c2884e..8efe0b5d929 100644 --- a/code/modules/surgery/bodyparts/helpers.dm +++ b/code/modules/surgery/bodyparts/helpers.dm @@ -247,5 +247,5 @@ else uniform.adjusted = DIGITIGRADE_STYLE leg_owner.update_inv_w_uniform() - if(leg_owner.shoes && !swap_back) + if(leg_owner.shoes && !(leg_owner.shoes.item_flags & IGNORE_DIGITIGRADE) && !swap_back) leg_owner.dropItemToGround(leg_owner.shoes) diff --git a/code/modules/surgery/organs/augments_chest.dm b/code/modules/surgery/organs/augments_chest.dm index a75a11e77a2..7d3f569911a 100644 --- a/code/modules/surgery/organs/augments_chest.dm +++ b/code/modules/surgery/organs/augments_chest.dm @@ -155,15 +155,17 @@ on = TRUE ion_trail.start() RegisterSignal(owner, COMSIG_MOVABLE_MOVED, .proc/move_react) - owner.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/cybernetic) RegisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE, .proc/pre_move_react) + RegisterSignal(owner, COMSIG_MOVABLE_SPACEMOVE, .proc/spacemove_react) + owner.add_movespeed_modifier(/datum/movespeed_modifier/jetpack/cybernetic) if(!silent) to_chat(owner, span_notice("You turn your thrusters set on.")) else ion_trail.stop() UnregisterSignal(owner, COMSIG_MOVABLE_MOVED) - owner.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/cybernetic) UnregisterSignal(owner, COMSIG_MOVABLE_PRE_MOVE) + UnregisterSignal(owner, COMSIG_MOVABLE_SPACEMOVE) + owner.remove_movespeed_modifier(/datum/movespeed_modifier/jetpack/cybernetic) if(!silent) to_chat(owner, span_notice("You turn your thrusters set off.")) on = FALSE @@ -194,6 +196,12 @@ SIGNAL_HANDLER ion_trail.oldposition = get_turf(owner) +/obj/item/organ/cyberimp/chest/thrusters/proc/spacemove_react(mob/user, movement_dir) + SIGNAL_HANDLER + + if(on && movement_dir) + return COMSIG_MOVABLE_STOP_SPACEMOVE + /obj/item/organ/cyberimp/chest/thrusters/proc/allow_thrust(num) if(!owner) return FALSE diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index 183906fc949..965b459db88 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -79,6 +79,7 @@ #include "merge_type.dm" #include "metabolizing.dm" #include "mob_spawn.dm" +#include "modsuit.dm" #include "ntnetwork_tests.dm" #include "outfit_sanity.dm" #include "pills.dm" diff --git a/code/modules/unit_tests/modsuit.dm b/code/modules/unit_tests/modsuit.dm new file mode 100644 index 00000000000..42c464e6d6c --- /dev/null +++ b/code/modules/unit_tests/modsuit.dm @@ -0,0 +1,26 @@ +/// Checks all pre-equipped MODsuit paths to see if they have something set wrong. +/datum/unit_test/modsuit_checks + +/datum/unit_test/modsuit_checks/Run() + var/list/paths = typesof(/obj/item/mod/control/pre_equipped) + + for(var/modpath in paths) + var/obj/item/mod/control/mod = new modpath() + TEST_ASSERT(mod.theme, "[modpath] spawned without a theme.") + TEST_ASSERT(mod.helmet, "[modpath] spawned without a helmet.") + TEST_ASSERT(mod.chestplate, "[modpath] spawned without a chestplate.") + TEST_ASSERT(mod.gauntlets, "[modpath] spawned without gauntlets.") + TEST_ASSERT(mod.boots, "[modpath] spawned without boots.") + var/list/modules = list() + var/complexity_max = mod.complexity_max + var/complexity = 0 + for(var/obj/item/mod/module/module as anything in mod.initial_modules) + module = new module() + complexity += module.complexity + TEST_ASSERT(complexity <= complexity_max, "[modpath] starting modules reach above max complexity.") + TEST_ASSERT(!is_type_in_list(module, mod.theme.module_blacklist), "[modpath] starting modules are in [mod.theme.type] blacklist.") + for(var/obj/item/mod/module/module_to_check as anything in modules) + TEST_ASSERT(!is_type_in_list(module, module_to_check.incompatible_modules), "[modpath] initial module [module.type] is incompatible with initial module [module_to_check.type]") + TEST_ASSERT(!is_type_in_list(module_to_check, module.incompatible_modules), "[modpath] initial module [module.type] is incompatible with initial module [module_to_check.type]") + modules += module + diff --git a/code/modules/unit_tests/outfit_sanity.dm b/code/modules/unit_tests/outfit_sanity.dm index f46aec61ae9..1877d946c83 100644 --- a/code/modules/unit_tests/outfit_sanity.dm +++ b/code/modules/unit_tests/outfit_sanity.dm @@ -1,9 +1,11 @@ #define CHECK_OUTFIT_SLOT(outfit_key, slot_name) if (outfit.##outfit_key) { \ H.equip_to_slot_or_del(new outfit.##outfit_key(H), ##slot_name, TRUE); \ /* We don't check the result of equip_to_slot_or_del because it returns false for random jumpsuits, as they delete themselves on init */ \ - if (!H.get_item_by_slot(##slot_name)) { \ + var/obj/item/outfit_item = H.get_item_by_slot(##slot_name); \ + if (!outfit_item) { \ 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); \ } /datum/unit_test/outfit_sanity/Run() @@ -19,7 +21,6 @@ CHECK_OUTFIT_SLOT(uniform, ITEM_SLOT_ICLOTHING) CHECK_OUTFIT_SLOT(suit, ITEM_SLOT_OCLOTHING) - CHECK_OUTFIT_SLOT(back, ITEM_SLOT_BACK) CHECK_OUTFIT_SLOT(belt, ITEM_SLOT_BELT) CHECK_OUTFIT_SLOT(gloves, ITEM_SLOT_GLOVES) CHECK_OUTFIT_SLOT(shoes, ITEM_SLOT_FEET) @@ -28,11 +29,11 @@ CHECK_OUTFIT_SLOT(neck, ITEM_SLOT_NECK) CHECK_OUTFIT_SLOT(ears, ITEM_SLOT_EARS) CHECK_OUTFIT_SLOT(glasses, ITEM_SLOT_EYES) + CHECK_OUTFIT_SLOT(back, ITEM_SLOT_BACK) CHECK_OUTFIT_SLOT(id, ITEM_SLOT_ID) - CHECK_OUTFIT_SLOT(suit_store, ITEM_SLOT_SUITSTORE) CHECK_OUTFIT_SLOT(l_pocket, ITEM_SLOT_LPOCKET) CHECK_OUTFIT_SLOT(r_pocket, ITEM_SLOT_RPOCKET) - + CHECK_OUTFIT_SLOT(suit_store, ITEM_SLOT_SUITSTORE) if (outfit.backpack_contents || outfit.box) var/list/backpack_contents = outfit.backpack_contents?.Copy() if (outfit.box) diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index 7fe8c102ddb..589c50e6fa5 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -183,7 +183,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) /datum/uplink_item/bundles_tc/firestarter name = "Spetsnaz Pyro bundle" - desc = "For systematic suppression of carbon lifeforms in close quarters: Contains a lethal New Russian backpack spray, Elite hardsuit, \ + desc = "For systematic suppression of carbon lifeforms in close quarters: Contains a lethal New Russian backpack spray, Elite MODsuit, \ Stechkin APS machine pistol, two incendiary magazines, a minibomb and a stimulant syringe. \ Order NOW and comrade Boris will throw in an extra tracksuit." item = /obj/item/storage/backpack/duffelbag/syndie/firestarter @@ -1269,7 +1269,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) surplus = 30 illegal_tech = FALSE -//Space Suits and Hardsuits +//Space Suits and MODsuits /datum/uplink_item/suits category = "Space Suits" surplus = 40 @@ -1277,7 +1277,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) /datum/uplink_item/suits/infiltrator_bundle name = "Infiltrator Case" desc = "Developed by Roseus Galactic in conjunction with the Gorlex Marauders to produce a functional suit for urban operations, \ - this suit proves to be cheaper than your standard issue hardsuit, with none of the movement restrictions of the outdated spacesuits employed by the company. \ + this suit proves to be cheaper than your standard issue MODsuit, with none of the movement restrictions of the outdated spacesuits employed by the company. \ Comes with an armor vest, helmet, sneaksuit, sneakboots, specialized combat gloves and a high-tech balaclava. The case is also rather useful as a storage container." item = /obj/item/storage/toolbox/infiltrator cost = 6 @@ -1292,33 +1292,34 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) item = /obj/item/storage/box/syndie_kit/space cost = 4 -/datum/uplink_item/suits/hardsuit - name = "Syndicate Hardsuit" - desc = "The feared suit of a Syndicate nuclear agent. Features slightly better armoring and a built in jetpack \ - that runs off standard atmospheric tanks. Toggling the suit in and out of \ - combat mode will allow you all the mobility of a loose fitting uniform without sacrificing armoring. \ - Additionally the suit is collapsible, making it small enough to fit within a backpack. \ - Nanotrasen crew who spot these suits are known to panic." - item = /obj/item/clothing/suit/space/hardsuit/syndi +/datum/uplink_item/suits/modsuit + name = "Syndicate MODsuit" + desc = "The feared MODsuit of a Syndicate agent. Features armoring and a set of inbuilt modules." + item = /obj/item/mod/control/pre_equipped/traitor cost = 8 - purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) //you can't buy it in nuke, because the elite hardsuit costs the same while being better + purchasable_from = ~(UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS) //you can't buy it in nuke, because the elite modsuit costs the same while being better -/datum/uplink_item/suits/hardsuit/elite - name = "Elite Syndicate Hardsuit" - desc = "An upgraded, elite version of the Syndicate hardsuit. It features fireproofing, and also \ - provides the user with superior armor and mobility compared to the standard Syndicate hardsuit." - item = /obj/item/clothing/suit/space/hardsuit/syndi/elite - cost = 8 +/datum/uplink_item/suits/modsuit/elite + name = "Elite Syndicate MODsuit" + desc = "An upgraded, elite version of the Syndicate MODsuit. It features fireproofing, and also \ + provides the user with superior armor and mobility compared to the standard Syndicate MODsuit." + item = /obj/item/mod/control/pre_equipped/elite purchasable_from = UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS -/datum/uplink_item/suits/hardsuit/shielded - name = "Shielded Syndicate Hardsuit" - desc = "An upgraded version of the standard Syndicate hardsuit. It features a built-in energy shielding system. \ - The shields can handle up to three impacts within a short duration and will rapidly recharge while not under fire." - item = /obj/item/clothing/suit/space/hardsuit/shielded/syndi - cost = 30 +/datum/uplink_item/suits/energy_shield + name = "MODsuit Energy Shield Module" + desc = "An energy shield module for a MODsuit. The shields can handle up to three impacts \ + within a short duration and will rapidly recharge while not under fire." + item = /obj/item/mod/module/energy_shield + cost = 15 purchasable_from = UPLINK_NUKE_OPS | UPLINK_CLOWN_OPS +/datum/uplink_item/device_tools/thermal + name = "Thermal Imaging Glasses" + desc = "A visor for a MODsuit. Lets you see living beings through walls." + item = /obj/item/mod/module/visor/thermal + cost = 4 + // Devices and Tools /datum/uplink_item/device_tools category = "Misc. Gadgets" diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm index b01d17d3803..9cc47a8184a 100644 --- a/code/modules/vehicles/mecha/_mecha.dm +++ b/code/modules/vehicles/mecha/_mecha.dm @@ -846,7 +846,7 @@ mecha_flags &= ~SILICON_PILOT AI.forceMove(card) card.AI = AI - AI.controlled_mech = null + AI.controlled_equipment = null AI.remote_control = null to_chat(AI, span_notice("You have been downloaded to a mobile storage device. Wireless connection offline.")) to_chat(user, "[span_boldnotice("Transfer successful")]: [AI.name] ([rand(1000,9999)].exe) removed from [name] and stored within local memory.") @@ -886,7 +886,7 @@ mecha_flags |= SILICON_PILOT moved_inside(AI) AI.cancel_camera() - AI.controlled_mech = src + AI.controlled_equipment = src AI.remote_control = src to_chat(AI, AI.can_dominate_mechs ? span_greenannounce("Takeover of [name] complete! You are now loaded onto the onboard computer. Do not attempt to leave the station sector!") :\ span_notice("You have been uploaded to a mech's onboard computer.")) @@ -1069,7 +1069,7 @@ return if(!silent) to_chat(AI, span_notice("Returning to core...")) - AI.controlled_mech = null + AI.controlled_equipment = null AI.remote_control = null mob_container = AI newloc = get_turf(AI.linked_core) diff --git a/code/modules/vehicles/mecha/mech_fabricator.dm b/code/modules/vehicles/mecha/mech_fabricator.dm index 81968241cc9..2f36947043e 100644 --- a/code/modules/vehicles/mecha/mech_fabricator.dm +++ b/code/modules/vehicles/mecha/mech_fabricator.dm @@ -60,6 +60,8 @@ "Cybernetics", "Implants", "Control Interfaces", + "MOD Construction", + "MOD Modules", "Misc" ) @@ -170,7 +172,7 @@ var/list/part = list( "name" = D.name, - "desc" = initial(built_item.desc), + "desc" = D.desc == "Desc" ? initial(built_item.desc) : D.desc, "printTime" = get_construction_time_w_coeff(initial(D.construction_time))/10, "cost" = cost, "id" = D.id, diff --git a/code/modules/vehicles/mecha/mecha_wreckage.dm b/code/modules/vehicles/mecha/mecha_wreckage.dm index b46f6549727..aaa4cd3a59f 100644 --- a/code/modules/vehicles/mecha/mecha_wreckage.dm +++ b/code/modules/vehicles/mecha/mecha_wreckage.dm @@ -35,7 +35,7 @@ INVOKE_ASYNC(AI, /mob/living/silicon.proc/death) //The damage is not enough to kill the AI, but to be 'corrupted files' in need of repair. AI.forceMove(src) //Put the dead AI inside the wreckage for recovery add_overlay(mutable_appearance('icons/obj/guns/projectiles.dmi', "green_laser")) //Overlay for the recovery beacon - AI.controlled_mech = null + AI.controlled_equipment = null AI.remote_control = null /obj/structure/mecha_wreckage/Destroy() diff --git a/icons/effects/magic.dmi b/icons/effects/magic.dmi new file mode 100644 index 00000000000..50c16cd7fdd Binary files /dev/null and b/icons/effects/magic.dmi differ diff --git a/icons/mob/actions/actions_mod.dmi b/icons/mob/actions/actions_mod.dmi new file mode 100644 index 00000000000..9c99abc6758 Binary files /dev/null and b/icons/mob/actions/actions_mod.dmi differ diff --git a/icons/mob/clothing/head.dmi b/icons/mob/clothing/head.dmi index 2732488af2c..b83e4c137b1 100644 Binary files a/icons/mob/clothing/head.dmi and b/icons/mob/clothing/head.dmi differ diff --git a/icons/mob/clothing/suit.dmi b/icons/mob/clothing/suit.dmi index 5e4c86b69cd..4a4dcb43d99 100644 Binary files a/icons/mob/clothing/suit.dmi and b/icons/mob/clothing/suit.dmi differ diff --git a/icons/mob/inhands/clothing_lefthand.dmi b/icons/mob/inhands/clothing_lefthand.dmi index 86ccfc7ebe9..056fe28c39e 100644 Binary files a/icons/mob/inhands/clothing_lefthand.dmi and b/icons/mob/inhands/clothing_lefthand.dmi differ diff --git a/icons/mob/inhands/clothing_righthand.dmi b/icons/mob/inhands/clothing_righthand.dmi index a0386eb8a63..d89776e2160 100644 Binary files a/icons/mob/inhands/clothing_righthand.dmi and b/icons/mob/inhands/clothing_righthand.dmi differ diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi index 19a852b1225..a96d0deedb5 100644 Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi index 0c650166de4..4d5b242cd21 100644 Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ diff --git a/icons/mob/mod.dmi b/icons/mob/mod.dmi new file mode 100644 index 00000000000..c8083addffa Binary files /dev/null and b/icons/mob/mod.dmi differ diff --git a/icons/obj/clothing/hats.dmi b/icons/obj/clothing/hats.dmi index c8032121dac..65f036fde7e 100644 Binary files a/icons/obj/clothing/hats.dmi and b/icons/obj/clothing/hats.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index e216e4d16f5..38fabbddaeb 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/machines/mod_installer.dmi b/icons/obj/machines/mod_installer.dmi new file mode 100644 index 00000000000..0b7a6507ec9 Binary files /dev/null and b/icons/obj/machines/mod_installer.dmi differ diff --git a/icons/obj/mod.dmi b/icons/obj/mod.dmi new file mode 100644 index 00000000000..003fb23cf60 Binary files /dev/null and b/icons/obj/mod.dmi differ diff --git a/icons/obj/syringe.dmi b/icons/obj/syringe.dmi index daf727722e0..4119d0a38e7 100644 Binary files a/icons/obj/syringe.dmi and b/icons/obj/syringe.dmi differ diff --git a/strings/tips.txt b/strings/tips.txt index 7eeb9be0646..67a96547a06 100644 --- a/strings/tips.txt +++ b/strings/tips.txt @@ -29,7 +29,7 @@ The P2P chat function found on tablet computers allows for a stealthy way to com Experiment with different setups of the supermatter engine to maximize output, but don't risk the crew's safety to do so! We were all new once, be patient and guide new players in the right direction. On most clothing items that go in the exosuit slot, you can put certain small items into your suit storage, such as a spraycan, your emergency oxygen tank, or a flashlight. -Most job-related exosuit clothing can fit job-related items into it, such as the atmospheric technician's hardsuit/winter coat holding an RPD, or labcoats holding most medicine. +Most job-related exosuit clothing can fit job-related items into it, such as the atmospheric technician's winter coat holding an RPD, or labcoats holding most medicine. If you're using hotkey mode, you can stop pulling things using H. The station's self-destruct terminal is invincible. Go find the disk instead of trying to destroy it. If there's something you need from another department, try asking! This game isn't singleplayer and you'd be surprised what you can get accomplished together! @@ -42,7 +42,6 @@ As the Captain, you have absolute access and control over the station, but this As the Captain, you can purchase a new emergency shuttle using a communications console. Some require cash, while others give you cash in exchange. Keep in mind that purchasing dangerous shuttles may instigate the ire of your crew. As the Chief Medical Officer, your hypospray is like a refillable instant injection syringe that can hold 30 units as opposed to the standard 15. As the Chief Medical Officer, coordinate and communicate with your doctors, chemists, and paramedics during a nuclear emergency, blob infestation, or some other crisis to keep people alive and fighting. -As the Chief Medical Officer, your hardsuit can hold an entire medkit in its suit storage! As a Medical Doctor, you can attempt to drain blood from a husk with a syringe to determine the cause. If you can extract blood, it was caused by extreme temperatures or lasers, if there is no blood to extract, you have confirmed the presence of changelings. As a Medical Doctor, you can surgically implant or extract things from people's chests. This can range from putting in a bomb to pulling out an alien larva. As a Medical Doctor, you must target the correct limb and not be in combat mode when trying to perform surgery on someone. Right clicking your patient will intentionally fail the surgery step. @@ -92,9 +91,7 @@ As an Engineering Cyborg, you can attach air alarm/fire alarm/APC frames to wall As a Medical Cyborg, you can fully perform surgery and even augment people. As a Janitor Cyborg, you are the bane of all slaughter demons and even Bubblegum himself. Cleaning up blood stains will severely gimp them. As the Chief Engineer, you can rename areas or create entirely new ones using your station blueprints. -As the Chief Engineer, your hardsuit is significantly better than everybody else's. It has the best features of both engineering and atmospherics hardsuits - boasting nigh-invulnerability to radiation and all atmospheric conditions. As the Chief Engineer, you can spy on and even forge PDA communications with the message monitor console! The key is in your office. -As the Chief Engineer, your locker contains a jetpack upgrade that can be attached to hardsuits. As the Chief Engineer, the power flow control console in your office will show you APC infos and lets you control them remotely. As an Engineer, the supermatter shard is an extremely dangerous piece of equipment: touching it will disintegrate you. So will touching it with telepathy. As an Engineer, you can electrify grilles by placing powered cables beneath them. @@ -110,7 +107,7 @@ As an Engineer, your RCD can be reloaded with iron, glass or plasteel sheets ins As an Engineer, the Supermatter Monitoring Program on modular computers give you a detailed report on the Supermatter's condition, and the contents of the air inside of the chamber, allowing you to both diagnose and monitor programs from afar! As an Atmospheric Technician, you can unwrench a pipe regardless of the pressures of the gases inside, but if they're too high they can burst out and injure you! As an Atmospheric Technician, look into replacing your gas pumps with volumetric gas pumps, as those move air in flat numerical amounts, rather than percentages which leave trace gases. -As an Atmospheric Technician, you are better suited to fighting fires than anyone else. As such, you have access to better firesuits, backpack firefighter tanks, and a completely heat and fire proof hardsuit. +As an Atmospheric Technician, you are better suited to fighting fires than anyone else. As such, you have access to better firesuits or backpack firefighter tanks. As an Atmospheric Technician, your backpack firefighter tank can launch resin. This resin will extinguish fires and replace any gases with a safe, room-temperature airmix. As an Atmospheric Technician, your ATMOS holofan projector blocks gases while allowing objects to pass through. With it, you can quickly contain gas spills, fires and hull breaches. As an Atmospheric Technician, burning a plasma/oxygen mix inside the incinerator will not only produce power, but also gases such as tritium, water vapor and carbon dioxide. @@ -168,7 +165,7 @@ As the Quartermaster, be sure to check the manifests on crates you receive to ma As the Quartermaster, you can construct an express supply console that instantly delivers crates by drop pod. The impact will cause a small explosion as well. As a Shaft Miner, the northern side of Lavaland has a lot more rare minerals than on the south. As a Shaft Miner, every monster on Lavaland has a pattern you can exploit to minimize damage from the encounters. -As a Shaft Miner, you can harvest goliath plates from goliaths and upgrade your explorer's suit and mining hardsuits, greatly reducing incoming melee damage. +As a Shaft Miner, you can harvest goliath plates from goliaths and upgrade your explorer's suit, greatly reducing incoming melee damage. As a Shaft Miner, always have a GPS on you, so a fellow miner or cyborg can come to save you if you die. As a Shaft Miner, you can craft a variety of equipment from the local fauna. Bone axes, lava boats and ash drake armour are just a few of them! As a Traitor, the cryptographic sequencer (emag) can not only open lockers, crates, APCs and more. It can also do things like hack cyborgs, and even cause bots to go berserk. Use it on the right machines, and you can even contact the Syndicate. Experiment! diff --git a/tgstation.dme b/tgstation.dme index 8d071ac71ab..ddbba99af56 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -104,6 +104,7 @@ #include "code\__DEFINES\misc.dm" #include "code\__DEFINES\mob_spawn.dm" #include "code\__DEFINES\mobs.dm" +#include "code\__DEFINES\mod.dm" #include "code\__DEFINES\monkeys.dm" #include "code\__DEFINES\move_force.dm" #include "code\__DEFINES\movement.dm" @@ -197,6 +198,7 @@ #include "code\__DEFINES\dcs\signals\signals_janitor.dm" #include "code\__DEFINES\dcs\signals\signals_light_eater.dm" #include "code\__DEFINES\dcs\signals\signals_mind.dm" +#include "code\__DEFINES\dcs\signals\signals_mod.dm" #include "code\__DEFINES\dcs\signals\signals_mood.dm" #include "code\__DEFINES\dcs\signals\signals_movetype.dm" #include "code\__DEFINES\dcs\signals\signals_music.dm" @@ -594,6 +596,7 @@ #include "code\datums\ai\movement\ai_movement_basic_avoidance.dm" #include "code\datums\ai\movement\ai_movement_dumb.dm" #include "code\datums\ai\movement\ai_movement_jps.dm" +#include "code\datums\ai\objects\mod.dm" #include "code\datums\ai\objects\vending_machines\vending_machine_behaviors.dm" #include "code\datums\ai\objects\vending_machines\vending_machine_controller.dm" #include "code\datums\ai\oldhostile\hostile_tameable.dm" @@ -1050,6 +1053,7 @@ #include "code\datums\wires\emitter.dm" #include "code\datums\wires\explosive.dm" #include "code\datums\wires\microwave.dm" +#include "code\datums\wires\mod.dm" #include "code\datums\wires\mulebot.dm" #include "code\datums\wires\r_n_d.dm" #include "code\datums\wires\radio.dm" @@ -2248,6 +2252,7 @@ #include "code\modules\client\preferences\hotkeys.dm" #include "code\modules\client\preferences\item_outlines.dm" #include "code\modules\client\preferences\jobless_role.dm" +#include "code\modules\client\preferences\mod_select.dm" #include "code\modules\client\preferences\names.dm" #include "code\modules\client\preferences\ooc.dm" #include "code\modules\client\preferences\parallax.dm" @@ -2372,7 +2377,6 @@ #include "code\modules\clothing\spacesuits\bountyhunter.dm" #include "code\modules\clothing\spacesuits\chronosuit.dm" #include "code\modules\clothing\spacesuits\freedom.dm" -#include "code\modules\clothing\spacesuits\hardsuit.dm" #include "code\modules\clothing\spacesuits\pirate.dm" #include "code\modules\clothing\spacesuits\plasmamen.dm" #include "code\modules\clothing\spacesuits\santa.dm" @@ -3235,6 +3239,17 @@ #include "code\modules\mob_spawn\ghost_roles\space_roles.dm" #include "code\modules\mob_spawn\ghost_roles\spider_roles.dm" #include "code\modules\mob_spawn\ghost_roles\unused_roles.dm" +#include "code\modules\mod\mod_actions.dm" +#include "code\modules\mod\mod_activation.dm" +#include "code\modules\mod\mod_ai.dm" +#include "code\modules\mod\mod_clothes.dm" +#include "code\modules\mod\mod_construction.dm" +#include "code\modules\mod\mod_control.dm" +#include "code\modules\mod\mod_theme.dm" +#include "code\modules\mod\mod_types.dm" +#include "code\modules\mod\mod_ui.dm" +#include "code\modules\mod\modules\_module.dm" +#include "code\modules\mod\modules\modules.dm" #include "code\modules\modular_computers\laptop_vendor.dm" #include "code\modules\modular_computers\computers\_modular_computer_shared.dm" #include "code\modules\modular_computers\computers\item\computer.dm" diff --git a/tgui/packages/tgui/interfaces/MODsuit.js b/tgui/packages/tgui/interfaces/MODsuit.js new file mode 100644 index 00000000000..ebaa3d0ff39 --- /dev/null +++ b/tgui/packages/tgui/interfaces/MODsuit.js @@ -0,0 +1,509 @@ +import { useBackend, useLocalState } from '../backend'; +import { Button, ColorBox, LabeledList, ProgressBar, Section, Collapsible, Box, Icon, Stack, Table, Dimmer, NumberInput, Flex, AnimatedNumber, Dropdown } from '../components'; +import { Window } from '../layouts'; + +const ConfigureNumberEntry = (props, context) => { + const { name, value, module_ref } = props; + const { act } = useBackend(context); + return ( + act('configure', { + "key": name, + "value": value, + "ref": module_ref, + })} /> + ); +}; + +const ConfigureBoolEntry = (props, context) => { + const { name, value, module_ref } = props; + const { act } = useBackend(context); + return ( + act('configure', { + "key": name, + "value": !value, + "ref": module_ref, + })} + /> + ); +}; + +const ConfigureColorEntry = (props, context) => { + const { name, value, module_ref } = props; + const { act } = useBackend(context); + return ( + <> + + + + + + ); +}; + +const displayText = param => { + switch (param) { + case 1: + return "Use"; + case 2: + return "Toggle"; + case 3: + return "Select"; + } +}; + +const ParametersSection = (props, context) => { + const { act, data } = useBackend(context); + const { + active, + malfunctioning, + locked, + open, + selected_module, + complexity, + complexity_max, + wearer_name, + wearer_job, + AI, + } = data; + const status = malfunctioning + ? 'Malfunctioning' : active + ? 'Active' : 'Inactive'; + return ( +
+ + act('activate')} /> + } > + {status} + + act('lock')} /> + } > + {locked ? 'Locked' : 'Unlocked'} + + + {open ? 'Open' : 'Closed'} + + + {selected_module || "None"} + + + {complexity} ({complexity_max}) + + + {wearer_name}, {wearer_job} + + + {AI || 'None'} + + +
+ ); +}; + +const HardwareSection = (props, context) => { + const { act, data } = useBackend(context); + const { + active, + control, + helmet, + chestplate, + gauntlets, + boots, + cell, + charge, + } = data; + return ( +
+ + + + {control} + + + {helmet || "None"} + + + {chestplate || "None"} + + + {gauntlets || "None"} + + + {boots || "None"} + + + + + {cell && ( + + + {cell} + + + + + + ) || ( + No Cell Detected + )} + +
+ ); +}; + +const InfoSection = (props, context) => { + const { act, data } = useBackend(context); + const { + active, + modules, + } = data; + const info_modules = modules.filter(module => !!module.id); + + return ( +
+ + {info_modules.length !== 0 && info_modules.map(module => { + const Module = ID2MODULE[module.id]; + return ( + + {!active && } + + + ); + }) || ( + No Info Modules Detected + )} + +
+ ); +}; + +const ModuleSection = (props, context) => { + const { act, data } = useBackend(context); + const { + complexity_max, + modules, + } = data; + const [configureState, setConfigureState] + = useLocalState(context, "module_configuration", null); + return ( +
+ + {modules.length !== 0 && modules.map(module => { + return ( + + +
+ {configureState === module.ref && ( + setConfigureState(null)} />)} + + + +
+ + {module.description} + +
+
+
+ ); + }) || ( + + No Modules Detected + + )} +
+
+ ); +}; + +export const MODsuit = (props, context) => { + const { act, data } = useBackend(context); + const { + ui_theme, + interface_break, + } = data; + return ( + + + {!!interface_break && ( + + ) || ( + + + + + + + + + + + + + + + )} + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/mod_select.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/mod_select.tsx new file mode 100644 index 00000000000..f3e7f31945a --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/mod_select.tsx @@ -0,0 +1,8 @@ +import { Feature, FeatureDropdownInput } from "../base"; + +export const mod_select: Feature = { + name: "MOD active module key", + category: "GAMEPLAY", + description: "The key you need to use an active MODsuit module.", + component: FeatureDropdownInput, +}; diff --git a/tgui/packages/tgui/interfaces/SDQLSpellMenu.js b/tgui/packages/tgui/interfaces/SDQLSpellMenu.js index fc6b9d402b7..d73cc3c623d 100644 --- a/tgui/packages/tgui/interfaces/SDQLSpellMenu.js +++ b/tgui/packages/tgui/interfaces/SDQLSpellMenu.js @@ -62,7 +62,6 @@ const typevars = (type) => { default_value: '', }, { name: 'clothes_req', type: 'bool', options: null, default_value: false }, - { name: 'cult_req', type: 'bool', options: null, default_value: false }, { name: 'human_req', type: 'bool', options: null, default_value: false }, { name: 'nonabstract_req',